aboutsummaryrefslogtreecommitdiffstats
path: root/1.4.23-rc4/channels
diff options
context:
space:
mode:
Diffstat (limited to '1.4.23-rc4/channels')
-rw-r--r--1.4.23-rc4/channels/DialTone.h252
-rw-r--r--1.4.23-rc4/channels/Makefile123
-rw-r--r--1.4.23-rc4/channels/answer.h237
-rw-r--r--1.4.23-rc4/channels/busy_tone.h55
-rw-r--r--1.4.23-rc4/channels/chan_agent.c2870
-rw-r--r--1.4.23-rc4/channels/chan_alsa.c1391
-rw-r--r--1.4.23-rc4/channels/chan_dahdi.c11992
-rw-r--r--1.4.23-rc4/channels/chan_features.c580
-rw-r--r--1.4.23-rc4/channels/chan_gtalk.c2067
-rw-r--r--1.4.23-rc4/channels/chan_h323.c3274
-rw-r--r--1.4.23-rc4/channels/chan_iax2.c11336
-rw-r--r--1.4.23-rc4/channels/chan_local.c808
-rw-r--r--1.4.23-rc4/channels/chan_mgcp.c4430
-rw-r--r--1.4.23-rc4/channels/chan_misdn.c5775
-rw-r--r--1.4.23-rc4/channels/chan_nbs.c302
-rw-r--r--1.4.23-rc4/channels/chan_oss.c1899
-rw-r--r--1.4.23-rc4/channels/chan_phone.c1433
-rw-r--r--1.4.23-rc4/channels/chan_sip.c18893
-rw-r--r--1.4.23-rc4/channels/chan_skinny.c5016
-rw-r--r--1.4.23-rc4/channels/chan_vpb.cc2905
-rw-r--r--1.4.23-rc4/channels/gentone-ulaw.c157
-rw-r--r--1.4.23-rc4/channels/gentone.c95
-rw-r--r--1.4.23-rc4/channels/h323/ChangeLog43
-rw-r--r--1.4.23-rc4/channels/h323/INSTALL.openh32318
-rw-r--r--1.4.23-rc4/channels/h323/Makefile.in48
-rw-r--r--1.4.23-rc4/channels/h323/README144
-rw-r--r--1.4.23-rc4/channels/h323/TODO9
-rw-r--r--1.4.23-rc4/channels/h323/ast_h323.cxx2487
-rw-r--r--1.4.23-rc4/channels/h323/ast_h323.h166
-rw-r--r--1.4.23-rc4/channels/h323/caps_h323.cxx239
-rw-r--r--1.4.23-rc4/channels/h323/caps_h323.h124
-rw-r--r--1.4.23-rc4/channels/h323/chan_h323.h254
-rw-r--r--1.4.23-rc4/channels/h323/cisco-h225.asn74
-rw-r--r--1.4.23-rc4/channels/h323/cisco-h225.cxx853
-rw-r--r--1.4.23-rc4/channels/h323/cisco-h225.h299
-rw-r--r--1.4.23-rc4/channels/h323/compat_h323.cxx138
-rw-r--r--1.4.23-rc4/channels/h323/compat_h323.h80
-rw-r--r--1.4.23-rc4/channels/h323/noexport.map5
-rw-r--r--1.4.23-rc4/channels/iax2-parser.c1053
-rw-r--r--1.4.23-rc4/channels/iax2-parser.h160
-rw-r--r--1.4.23-rc4/channels/iax2-provision.c540
-rw-r--r--1.4.23-rc4/channels/iax2-provision.h53
-rw-r--r--1.4.23-rc4/channels/iax2.h237
-rw-r--r--1.4.23-rc4/channels/misdn/Makefile17
-rw-r--r--1.4.23-rc4/channels/misdn/chan_misdn_config.h152
-rw-r--r--1.4.23-rc4/channels/misdn/ie.c1422
-rw-r--r--1.4.23-rc4/channels/misdn/isdn_lib.c4661
-rw-r--r--1.4.23-rc4/channels/misdn/isdn_lib.h674
-rw-r--r--1.4.23-rc4/channels/misdn/isdn_lib_intern.h142
-rw-r--r--1.4.23-rc4/channels/misdn/isdn_msg_parser.c1348
-rw-r--r--1.4.23-rc4/channels/misdn/portinfo.c198
-rw-r--r--1.4.23-rc4/channels/misdn_config.c1160
-rw-r--r--1.4.23-rc4/channels/ring10.h1752
-rw-r--r--1.4.23-rc4/channels/ring_tone.h30
54 files changed, 0 insertions, 94470 deletions
diff --git a/1.4.23-rc4/channels/DialTone.h b/1.4.23-rc4/channels/DialTone.h
deleted file mode 100644
index 098ed44d7..000000000
--- a/1.4.23-rc4/channels/DialTone.h
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * 8-bit raw data
- *
- * Source: DialTone.ulaw
- *
- * Copyright (C) 1999, Mark Spencer
- *
- * Distributed under the terms of the GNU General Public License
- *
- */
-
-static unsigned char DialTone[] = {
-0xff, 0xab, 0x9d, 0x96, 0x91, 0x90, 0x91, 0x96, 0x9c, 0xaa,
-0xd9, 0x2f, 0x1f, 0x19, 0x15, 0x14, 0x15, 0x19, 0x1f, 0x2c,
-0x4e, 0xb9, 0xa7, 0x9f, 0x9c, 0x9b, 0x9c, 0x9f, 0xa7, 0xb3,
-0xcf, 0x47, 0x34, 0x2d, 0x2a, 0x2a, 0x2c, 0x31, 0x3a, 0x47,
-0x5f, 0xe4, 0xd8, 0xd9, 0xe9, 0x64, 0x4f, 0x49, 0x46, 0x49,
-0x58, 0xde, 0xc2, 0xb5, 0xad, 0xa8, 0xa6, 0xa6, 0xa9, 0xaf,
-0xbf, 0x56, 0x32, 0x26, 0x1e, 0x1b, 0x19, 0x1a, 0x1d, 0x24,
-0x33, 0xdd, 0xad, 0x9f, 0x98, 0x94, 0x92, 0x93, 0x97, 0x9e,
-0xac, 0xf8, 0x2c, 0x1d, 0x16, 0x11, 0xf, 0x10, 0x15, 0x1b,
-0x29, 0x55, 0xae, 0x9e, 0x97, 0x92, 0x90, 0x91, 0x95, 0x9c,
-0xa8, 0xca, 0x35, 0x22, 0x1a, 0x16, 0x15, 0x16, 0x19, 0x1f,
-0x2b, 0x47, 0xbe, 0xab, 0xa2, 0x9e, 0x9d, 0x9e, 0xa2, 0xa9,
-0xb4, 0xcc, 0x4f, 0x3a, 0x32, 0x2f, 0x2f, 0x32, 0x39, 0x41,
-0x4f, 0x67, 0xf5, 0xf5, 0x67, 0x51, 0x46, 0x3e, 0x3b, 0x3b,
-0x3f, 0x4d, 0xe2, 0xbe, 0xb0, 0xa9, 0xa4, 0xa1, 0xa1, 0xa5,
-0xab, 0xba, 0x64, 0x33, 0x25, 0x1d, 0x19, 0x17, 0x18, 0x1b,
-0x20, 0x2e, 0x72, 0xae, 0x9f, 0x98, 0x94, 0x91, 0x92, 0x96,
-0x9c, 0xa9, 0xd4, 0x2f, 0x1e, 0x17, 0x11, 0xf, 0x10, 0x14,
-0x1a, 0x26, 0x48, 0xb2, 0x9f, 0x98, 0x93, 0x91, 0x92, 0x95,
-0x9b, 0xa7, 0xc1, 0x3a, 0x25, 0x1c, 0x18, 0x16, 0x17, 0x1a,
-0x1f, 0x2b, 0x42, 0xc6, 0xae, 0xa6, 0xa0, 0x9f, 0xa0, 0xa5,
-0xab, 0xb6, 0xcb, 0x5a, 0x40, 0x39, 0x36, 0x37, 0x3b, 0x43,
-0x4e, 0x60, 0x7b, 0x7c, 0x60, 0x4e, 0x41, 0x3a, 0x34, 0x32,
-0x33, 0x39, 0x45, 0xed, 0xbd, 0xae, 0xa6, 0xa0, 0x9e, 0x9e,
-0xa0, 0xa8, 0xb4, 0xef, 0x34, 0x24, 0x1c, 0x18, 0x16, 0x16,
-0x19, 0x1e, 0x2b, 0x54, 0xb1, 0x9f, 0x98, 0x93, 0x91, 0x91,
-0x95, 0x9b, 0xa6, 0xc6, 0x33, 0x1f, 0x17, 0x12, 0xf, 0x10,
-0x13, 0x1a, 0x24, 0x3e, 0xb8, 0xa2, 0x99, 0x94, 0x92, 0x92,
-0x96, 0x9b, 0xa6, 0xbc, 0x40, 0x29, 0x1e, 0x1a, 0x18, 0x19,
-0x1b, 0x20, 0x2b, 0x3f, 0xcf, 0xb3, 0xa9, 0xa5, 0xa3, 0xa4,
-0xa8, 0xae, 0xb9, 0xcc, 0x67, 0x49, 0x40, 0x3f, 0x42, 0x4a,
-0x59, 0x79, 0xe5, 0xe4, 0x7a, 0x54, 0x43, 0x39, 0x31, 0x2d,
-0x2c, 0x2d, 0x32, 0x3e, 0x71, 0xbd, 0xad, 0xa4, 0x9e, 0x9c,
-0x9c, 0x9e, 0xa4, 0xaf, 0xd7, 0x36, 0x24, 0x1c, 0x17, 0x15,
-0x15, 0x17, 0x1d, 0x28, 0x47, 0xb5, 0xa1, 0x98, 0x93, 0x90,
-0x90, 0x93, 0x99, 0xa4, 0xbd, 0x38, 0x21, 0x18, 0x13, 0x10,
-0x10, 0x13, 0x19, 0x22, 0x39, 0xbe, 0xa5, 0x9b, 0x96, 0x93,
-0x93, 0x96, 0x9b, 0xa5, 0xb9, 0x4a, 0x2c, 0x20, 0x1c, 0x1a,
-0x1a, 0x1d, 0x22, 0x2c, 0x3d, 0xdc, 0xb8, 0xad, 0xa9, 0xa8,
-0xa9, 0xac, 0xb2, 0xbd, 0xce, 0x78, 0x54, 0x4d, 0x4f, 0x5a,
-0xff, 0xda, 0xcf, 0xcd, 0xd4, 0xf8, 0x4e, 0x3d, 0x32, 0x2c,
-0x29, 0x28, 0x29, 0x2d, 0x38, 0x5c, 0xbd, 0xac, 0xa2, 0x9d,
-0x9a, 0x9a, 0x9c, 0xa0, 0xac, 0xca, 0x39, 0x25, 0x1b, 0x16,
-0x13, 0x13, 0x16, 0x1b, 0x25, 0x3e, 0xb9, 0xa2, 0x99, 0x93,
-0x90, 0x90, 0x93, 0x98, 0xa1, 0xb8, 0x3d, 0x24, 0x19, 0x13,
-0x10, 0x10, 0x13, 0x18, 0x21, 0x35, 0xc7, 0xa8, 0x9d, 0x97,
-0x95, 0x95, 0x97, 0x9c, 0xa4, 0xb6, 0x57, 0x2f, 0x24, 0x1e,
-0x1c, 0x1c, 0x1e, 0x24, 0x2d, 0x3d, 0xf1, 0xbe, 0xb2, 0xad,
-0xac, 0xad, 0xb1, 0xb9, 0xc3, 0xd4, 0xfa, 0x64, 0x65, 0xf9,
-0xd9, 0xca, 0xc2, 0xbf, 0xc0, 0xc9, 0xe7, 0x4c, 0x39, 0x2e,
-0x28, 0x24, 0x23, 0x25, 0x29, 0x33, 0x4f, 0xbf, 0xab, 0xa0,
-0x9b, 0x99, 0x98, 0x9a, 0x9e, 0xa9, 0xc0, 0x3c, 0x26, 0x1b,
-0x16, 0x12, 0x12, 0x14, 0x19, 0x22, 0x38, 0xbe, 0xa4, 0x9a,
-0x93, 0x90, 0x8f, 0x92, 0x97, 0x9f, 0xb3, 0x46, 0x26, 0x1b,
-0x15, 0x11, 0x11, 0x13, 0x18, 0x1f, 0x31, 0xd4, 0xab, 0x9e,
-0x99, 0x96, 0x96, 0x98, 0x9c, 0xa4, 0xb4, 0x6f, 0x34, 0x28,
-0x20, 0x1e, 0x1e, 0x20, 0x26, 0x2e, 0x3d, 0x6d, 0xc5, 0xb9,
-0xb3, 0xb2, 0xb4, 0xba, 0xc1, 0xcd, 0xe0, 0xfc, 0xfb, 0xe0,
-0xce, 0xc3, 0xbb, 0xb7, 0xb6, 0xb9, 0xc0, 0xda, 0x4b, 0x36,
-0x2b, 0x25, 0x20, 0x1f, 0x20, 0x26, 0x2e, 0x46, 0xc2, 0xab,
-0x9f, 0x9a, 0x97, 0x96, 0x98, 0x9c, 0xa5, 0xba, 0x41, 0x27,
-0x1b, 0x15, 0x12, 0x11, 0x13, 0x18, 0x1f, 0x32, 0xc8, 0xa6,
-0x9a, 0x94, 0x90, 0x8f, 0x91, 0x97, 0x9e, 0xaf, 0x54, 0x29,
-0x1c, 0x16, 0x12, 0x11, 0x14, 0x18, 0x1f, 0x2e, 0xf2, 0xae,
-0xa0, 0x9b, 0x98, 0x97, 0x99, 0x9d, 0xa5, 0xb3, 0xe4, 0x3a,
-0x2b, 0x25, 0x21, 0x21, 0x24, 0x29, 0x30, 0x3e, 0x62, 0xcd,
-0xbf, 0xbb, 0xbb, 0xbe, 0xc6, 0xd1, 0xe7, 0x76, 0x75, 0xe7,
-0xcf, 0xc1, 0xb9, 0xb2, 0xaf, 0xaf, 0xb2, 0xba, 0xcf, 0x4c,
-0x34, 0x29, 0x22, 0x1e, 0x1d, 0x1e, 0x22, 0x2b, 0x3e, 0xc7,
-0xab, 0x9f, 0x99, 0x96, 0x95, 0x96, 0x9a, 0xa2, 0xb5, 0x4a,
-0x28, 0x1c, 0x15, 0x11, 0x10, 0x12, 0x17, 0x1e, 0x2e, 0xd5,
-0xa9, 0x9b, 0x95, 0x90, 0x8f, 0x91, 0x96, 0x9d, 0xac, 0x78,
-0x2c, 0x1e, 0x17, 0x13, 0x12, 0x14, 0x18, 0x1f, 0x2d, 0x5d,
-0xb3, 0xa4, 0x9d, 0x9a, 0x99, 0x9b, 0x9e, 0xa6, 0xb2, 0xd6,
-0x3f, 0x2f, 0x29, 0x26, 0x26, 0x28, 0x2d, 0x35, 0x42, 0x5e,
-0xd8, 0xca, 0xc6, 0xc9, 0xcf, 0xe4, 0x69, 0x59, 0x58, 0x64,
-0xdf, 0xc7, 0xba, 0xb1, 0xac, 0xaa, 0xaa, 0xad, 0xb4, 0xc7,
-0x4f, 0x33, 0x27, 0x1f, 0x1c, 0x1b, 0x1c, 0x1f, 0x27, 0x39,
-0xce, 0xac, 0x9f, 0x99, 0x95, 0x94, 0x95, 0x99, 0x9f, 0xaf,
-0x59, 0x2a, 0x1c, 0x16, 0x11, 0x10, 0x11, 0x16, 0x1d, 0x2b,
-0xff, 0xab, 0x9d, 0x96, 0x91, 0x90, 0x91, 0x96, 0x9c, 0xaa,
-0xd9, 0x2f, 0x1f, 0x19, 0x15, 0x14, 0x15, 0x19, 0x1f, 0x2c,
-0x4e, 0xb9, 0xa7, 0x9f, 0x9c, 0x9b, 0x9c, 0x9f, 0xa7, 0xb3,
-0xcf, 0x47, 0x34, 0x2d, 0x2a, 0x2a, 0x2c, 0x31, 0x3a, 0x47,
-0x5f, 0xe4, 0xd8, 0xd9, 0xe9, 0x64, 0x4f, 0x49, 0x46, 0x49,
-0x58, 0xde, 0xc2, 0xb5, 0xad, 0xa8, 0xa6, 0xa6, 0xa9, 0xaf,
-0xbf, 0x56, 0x32, 0x26, 0x1e, 0x1b, 0x19, 0x1a, 0x1d, 0x24,
-0x33, 0xdd, 0xad, 0x9f, 0x98, 0x94, 0x92, 0x93, 0x97, 0x9e,
-0xac, 0xf8, 0x2c, 0x1d, 0x16, 0x11, 0xf, 0x10, 0x15, 0x1b,
-0x29, 0x55, 0xae, 0x9e, 0x97, 0x92, 0x90, 0x91, 0x95, 0x9c,
-0xa8, 0xca, 0x35, 0x22, 0x1a, 0x16, 0x15, 0x16, 0x19, 0x1f,
-0x2b, 0x47, 0xbe, 0xab, 0xa2, 0x9e, 0x9d, 0x9e, 0xa2, 0xa9,
-0xb4, 0xcc, 0x4f, 0x3a, 0x32, 0x2f, 0x2f, 0x32, 0x39, 0x41,
-0x4f, 0x67, 0xf5, 0xf5, 0x67, 0x51, 0x46, 0x3e, 0x3b, 0x3b,
-0x3f, 0x4d, 0xe2, 0xbe, 0xb0, 0xa9, 0xa4, 0xa1, 0xa1, 0xa5,
-0xab, 0xba, 0x64, 0x33, 0x25, 0x1d, 0x19, 0x17, 0x18, 0x1b,
-0x20, 0x2e, 0x72, 0xae, 0x9f, 0x98, 0x94, 0x91, 0x92, 0x96,
-0x9c, 0xa9, 0xd4, 0x2f, 0x1e, 0x17, 0x11, 0xf, 0x10, 0x14,
-0x1a, 0x26, 0x48, 0xb2, 0x9f, 0x98, 0x93, 0x91, 0x92, 0x95,
-0x9b, 0xa7, 0xc1, 0x3a, 0x25, 0x1c, 0x18, 0x16, 0x17, 0x1a,
-0x1f, 0x2b, 0x42, 0xc6, 0xae, 0xa6, 0xa0, 0x9f, 0xa0, 0xa5,
-0xab, 0xb6, 0xcb, 0x5a, 0x40, 0x39, 0x36, 0x37, 0x3b, 0x43,
-0x4e, 0x60, 0x7b, 0x7c, 0x60, 0x4e, 0x41, 0x3a, 0x34, 0x32,
-0x33, 0x39, 0x45, 0xed, 0xbd, 0xae, 0xa6, 0xa0, 0x9e, 0x9e,
-0xa0, 0xa8, 0xb4, 0xef, 0x34, 0x24, 0x1c, 0x18, 0x16, 0x16,
-0x19, 0x1e, 0x2b, 0x54, 0xb1, 0x9f, 0x98, 0x93, 0x91, 0x91,
-0x95, 0x9b, 0xa6, 0xc6, 0x33, 0x1f, 0x17, 0x12, 0xf, 0x10,
-0x13, 0x1a, 0x24, 0x3e, 0xb8, 0xa2, 0x99, 0x94, 0x92, 0x92,
-0x96, 0x9b, 0xa6, 0xbc, 0x40, 0x29, 0x1e, 0x1a, 0x18, 0x19,
-0x1b, 0x20, 0x2b, 0x3f, 0xcf, 0xb3, 0xa9, 0xa5, 0xa3, 0xa4,
-0xa8, 0xae, 0xb9, 0xcc, 0x67, 0x49, 0x40, 0x3f, 0x42, 0x4a,
-0x59, 0x79, 0xe5, 0xe4, 0x7a, 0x54, 0x43, 0x39, 0x31, 0x2d,
-0x2c, 0x2d, 0x32, 0x3e, 0x71, 0xbd, 0xad, 0xa4, 0x9e, 0x9c,
-0x9c, 0x9e, 0xa4, 0xaf, 0xd7, 0x36, 0x24, 0x1c, 0x17, 0x15,
-0x15, 0x17, 0x1d, 0x28, 0x47, 0xb5, 0xa1, 0x98, 0x93, 0x90,
-0x90, 0x93, 0x99, 0xa4, 0xbd, 0x38, 0x21, 0x18, 0x13, 0x10,
-0x10, 0x13, 0x19, 0x22, 0x39, 0xbe, 0xa5, 0x9b, 0x96, 0x93,
-0x93, 0x96, 0x9b, 0xa5, 0xb9, 0x4a, 0x2c, 0x20, 0x1c, 0x1a,
-0x1a, 0x1d, 0x22, 0x2c, 0x3d, 0xdc, 0xb8, 0xad, 0xa9, 0xa8,
-0xa9, 0xac, 0xb2, 0xbd, 0xce, 0x78, 0x54, 0x4d, 0x4f, 0x5a,
-0xff, 0xda, 0xcf, 0xcd, 0xd4, 0xf8, 0x4e, 0x3d, 0x32, 0x2c,
-0x29, 0x28, 0x29, 0x2d, 0x38, 0x5c, 0xbd, 0xac, 0xa2, 0x9d,
-0x9a, 0x9a, 0x9c, 0xa0, 0xac, 0xca, 0x39, 0x25, 0x1b, 0x16,
-0x13, 0x13, 0x16, 0x1b, 0x25, 0x3e, 0xb9, 0xa2, 0x99, 0x93,
-0x90, 0x90, 0x93, 0x98, 0xa1, 0xb8, 0x3d, 0x24, 0x19, 0x13,
-0x10, 0x10, 0x13, 0x18, 0x21, 0x35, 0xc7, 0xa8, 0x9d, 0x97,
-0x95, 0x95, 0x97, 0x9c, 0xa4, 0xb6, 0x57, 0x2f, 0x24, 0x1e,
-0x1c, 0x1c, 0x1e, 0x24, 0x2d, 0x3d, 0xf1, 0xbe, 0xb2, 0xad,
-0xac, 0xad, 0xb1, 0xb9, 0xc3, 0xd4, 0xfa, 0x64, 0x65, 0xf9,
-0xd9, 0xca, 0xc2, 0xbf, 0xc0, 0xc9, 0xe7, 0x4c, 0x39, 0x2e,
-0x28, 0x24, 0x23, 0x25, 0x29, 0x33, 0x4f, 0xbf, 0xab, 0xa0,
-0x9b, 0x99, 0x98, 0x9a, 0x9e, 0xa9, 0xc0, 0x3c, 0x26, 0x1b,
-0x16, 0x12, 0x12, 0x14, 0x19, 0x22, 0x38, 0xbe, 0xa4, 0x9a,
-0x93, 0x90, 0x8f, 0x92, 0x97, 0x9f, 0xb3, 0x46, 0x26, 0x1b,
-0x15, 0x11, 0x11, 0x13, 0x18, 0x1f, 0x31, 0xd4, 0xab, 0x9e,
-0x99, 0x96, 0x96, 0x98, 0x9c, 0xa4, 0xb4, 0x6f, 0x34, 0x28,
-0x20, 0x1e, 0x1e, 0x20, 0x26, 0x2e, 0x3d, 0x6d, 0xc5, 0xb9,
-0xb3, 0xb2, 0xb4, 0xba, 0xc1, 0xcd, 0xe0, 0xfc, 0xfb, 0xe0,
-0xce, 0xc3, 0xbb, 0xb7, 0xb6, 0xb9, 0xc0, 0xda, 0x4b, 0x36,
-0x2b, 0x25, 0x20, 0x1f, 0x20, 0x26, 0x2e, 0x46, 0xc2, 0xab,
-0x9f, 0x9a, 0x97, 0x96, 0x98, 0x9c, 0xa5, 0xba, 0x41, 0x27,
-0x1b, 0x15, 0x12, 0x11, 0x13, 0x18, 0x1f, 0x32, 0xc8, 0xa6,
-0x9a, 0x94, 0x90, 0x8f, 0x91, 0x97, 0x9e, 0xaf, 0x54, 0x29,
-0x1c, 0x16, 0x12, 0x11, 0x14, 0x18, 0x1f, 0x2e, 0xf2, 0xae,
-0xa0, 0x9b, 0x98, 0x97, 0x99, 0x9d, 0xa5, 0xb3, 0xe4, 0x3a,
-0x2b, 0x25, 0x21, 0x21, 0x24, 0x29, 0x30, 0x3e, 0x62, 0xcd,
-0xbf, 0xbb, 0xbb, 0xbe, 0xc6, 0xd1, 0xe7, 0x76, 0x75, 0xe7,
-0xcf, 0xc1, 0xb9, 0xb2, 0xaf, 0xaf, 0xb2, 0xba, 0xcf, 0x4c,
-0x34, 0x29, 0x22, 0x1e, 0x1d, 0x1e, 0x22, 0x2b, 0x3e, 0xc7,
-0xab, 0x9f, 0x99, 0x96, 0x95, 0x96, 0x9a, 0xa2, 0xb5, 0x4a,
-0x28, 0x1c, 0x15, 0x11, 0x10, 0x12, 0x17, 0x1e, 0x2e, 0xd5,
-0xa9, 0x9b, 0x95, 0x90, 0x8f, 0x91, 0x96, 0x9d, 0xac, 0x78,
-0x2c, 0x1e, 0x17, 0x13, 0x12, 0x14, 0x18, 0x1f, 0x2d, 0x5d,
-0xb3, 0xa4, 0x9d, 0x9a, 0x99, 0x9b, 0x9e, 0xa6, 0xb2, 0xd6,
-0x3f, 0x2f, 0x29, 0x26, 0x26, 0x28, 0x2d, 0x35, 0x42, 0x5e,
-0xd8, 0xca, 0xc6, 0xc9, 0xcf, 0xe4, 0x69, 0x59, 0x58, 0x64,
-0xdf, 0xc7, 0xba, 0xb1, 0xac, 0xaa, 0xaa, 0xad, 0xb4, 0xc7,
-0x4f, 0x33, 0x27, 0x1f, 0x1c, 0x1b, 0x1c, 0x1f, 0x27, 0x39,
-0xce, 0xac, 0x9f, 0x99, 0x95, 0x94, 0x95, 0x99, 0x9f, 0xaf,
-0x59, 0x2a, 0x1c, 0x16, 0x11, 0x10, 0x11, 0x16, 0x1d, 0x2b,
-0xff, 0xab, 0x9d, 0x96, 0x91, 0x90, 0x91, 0x96, 0x9c, 0xaa,
-0xd9, 0x2f, 0x1f, 0x19, 0x15, 0x14, 0x15, 0x19, 0x1f, 0x2c,
-0x4e, 0xb9, 0xa7, 0x9f, 0x9c, 0x9b, 0x9c, 0x9f, 0xa7, 0xb3,
-0xcf, 0x47, 0x34, 0x2d, 0x2a, 0x2a, 0x2c, 0x31, 0x3a, 0x47,
-0x5f, 0xe4, 0xd8, 0xd9, 0xe9, 0x64, 0x4f, 0x49, 0x46, 0x49,
-0x58, 0xde, 0xc2, 0xb5, 0xad, 0xa8, 0xa6, 0xa6, 0xa9, 0xaf,
-0xbf, 0x56, 0x32, 0x26, 0x1e, 0x1b, 0x19, 0x1a, 0x1d, 0x24,
-0x33, 0xdd, 0xad, 0x9f, 0x98, 0x94, 0x92, 0x93, 0x97, 0x9e,
-0xac, 0xf8, 0x2c, 0x1d, 0x16, 0x11, 0xf, 0x10, 0x15, 0x1b,
-0x29, 0x55, 0xae, 0x9e, 0x97, 0x92, 0x90, 0x91, 0x95, 0x9c,
-0xa8, 0xca, 0x35, 0x22, 0x1a, 0x16, 0x15, 0x16, 0x19, 0x1f,
-0x2b, 0x47, 0xbe, 0xab, 0xa2, 0x9e, 0x9d, 0x9e, 0xa2, 0xa9,
-0xb4, 0xcc, 0x4f, 0x3a, 0x32, 0x2f, 0x2f, 0x32, 0x39, 0x41,
-0x4f, 0x67, 0xf5, 0xf5, 0x67, 0x51, 0x46, 0x3e, 0x3b, 0x3b,
-0x3f, 0x4d, 0xe2, 0xbe, 0xb0, 0xa9, 0xa4, 0xa1, 0xa1, 0xa5,
-0xab, 0xba, 0x64, 0x33, 0x25, 0x1d, 0x19, 0x17, 0x18, 0x1b,
-0x20, 0x2e, 0x72, 0xae, 0x9f, 0x98, 0x94, 0x91, 0x92, 0x96,
-0x9c, 0xa9, 0xd4, 0x2f, 0x1e, 0x17, 0x11, 0xf, 0x10, 0x14,
-0x1a, 0x26, 0x48, 0xb2, 0x9f, 0x98, 0x93, 0x91, 0x92, 0x95,
-0x9b, 0xa7, 0xc1, 0x3a, 0x25, 0x1c, 0x18, 0x16, 0x17, 0x1a,
-0x1f, 0x2b, 0x42, 0xc6, 0xae, 0xa6, 0xa0, 0x9f, 0xa0, 0xa5,
-0xab, 0xb6, 0xcb, 0x5a, 0x40, 0x39, 0x36, 0x37, 0x3b, 0x43,
-0x4e, 0x60, 0x7b, 0x7c, 0x60, 0x4e, 0x41, 0x3a, 0x34, 0x32,
-0x33, 0x39, 0x45, 0xed, 0xbd, 0xae, 0xa6, 0xa0, 0x9e, 0x9e,
-0xa0, 0xa8, 0xb4, 0xef, 0x34, 0x24, 0x1c, 0x18, 0x16, 0x16,
-0x19, 0x1e, 0x2b, 0x54, 0xb1, 0x9f, 0x98, 0x93, 0x91, 0x91,
-0x95, 0x9b, 0xa6, 0xc6, 0x33, 0x1f, 0x17, 0x12, 0xf, 0x10,
-0x13, 0x1a, 0x24, 0x3e, 0xb8, 0xa2, 0x99, 0x94, 0x92, 0x92,
-0x96, 0x9b, 0xa6, 0xbc, 0x40, 0x29, 0x1e, 0x1a, 0x18, 0x19,
-0x1b, 0x20, 0x2b, 0x3f, 0xcf, 0xb3, 0xa9, 0xa5, 0xa3, 0xa4,
-0xa8, 0xae, 0xb9, 0xcc, 0x67, 0x49, 0x40, 0x3f, 0x42, 0x4a,
-0x59, 0x79, 0xe5, 0xe4, 0x7a, 0x54, 0x43, 0x39, 0x31, 0x2d,
-0x2c, 0x2d, 0x32, 0x3e, 0x71, 0xbd, 0xad, 0xa4, 0x9e, 0x9c,
-0x9c, 0x9e, 0xa4, 0xaf, 0xd7, 0x36, 0x24, 0x1c, 0x17, 0x15,
-0x15, 0x17, 0x1d, 0x28, 0x47, 0xb5, 0xa1, 0x98, 0x93, 0x90,
-0x90, 0x93, 0x99, 0xa4, 0xbd, 0x38, 0x21, 0x18, 0x13, 0x10,
-0x10, 0x13, 0x19, 0x22, 0x39, 0xbe, 0xa5, 0x9b, 0x96, 0x93,
-0x93, 0x96, 0x9b, 0xa5, 0xb9, 0x4a, 0x2c, 0x20, 0x1c, 0x1a,
-0x1a, 0x1d, 0x22, 0x2c, 0x3d, 0xdc, 0xb8, 0xad, 0xa9, 0xa8,
-0xa9, 0xac, 0xb2, 0xbd, 0xce, 0x78, 0x54, 0x4d, 0x4f, 0x5a,
-0xff, 0xda, 0xcf, 0xcd, 0xd4, 0xf8, 0x4e, 0x3d, 0x32, 0x2c,
-0x29, 0x28, 0x29, 0x2d, 0x38, 0x5c, 0xbd, 0xac, 0xa2, 0x9d,
-0x9a, 0x9a, 0x9c, 0xa0, 0xac, 0xca, 0x39, 0x25, 0x1b, 0x16,
-0x13, 0x13, 0x16, 0x1b, 0x25, 0x3e, 0xb9, 0xa2, 0x99, 0x93,
-0x90, 0x90, 0x93, 0x98, 0xa1, 0xb8, 0x3d, 0x24, 0x19, 0x13,
-0x10, 0x10, 0x13, 0x18, 0x21, 0x35, 0xc7, 0xa8, 0x9d, 0x97,
-0x95, 0x95, 0x97, 0x9c, 0xa4, 0xb6, 0x57, 0x2f, 0x24, 0x1e,
-0x1c, 0x1c, 0x1e, 0x24, 0x2d, 0x3d, 0xf1, 0xbe, 0xb2, 0xad,
-0xac, 0xad, 0xb1, 0xb9, 0xc3, 0xd4, 0xfa, 0x64, 0x65, 0xf9,
-0xd9, 0xca, 0xc2, 0xbf, 0xc0, 0xc9, 0xe7, 0x4c, 0x39, 0x2e,
-0x28, 0x24, 0x23, 0x25, 0x29, 0x33, 0x4f, 0xbf, 0xab, 0xa0,
-0x9b, 0x99, 0x98, 0x9a, 0x9e, 0xa9, 0xc0, 0x3c, 0x26, 0x1b,
-0x16, 0x12, 0x12, 0x14, 0x19, 0x22, 0x38, 0xbe, 0xa4, 0x9a,
-0x93, 0x90, 0x8f, 0x92, 0x97, 0x9f, 0xb3, 0x46, 0x26, 0x1b,
-0x15, 0x11, 0x11, 0x13, 0x18, 0x1f, 0x31, 0xd4, 0xab, 0x9e,
-0x99, 0x96, 0x96, 0x98, 0x9c, 0xa4, 0xb4, 0x6f, 0x34, 0x28,
-0x20, 0x1e, 0x1e, 0x20, 0x26, 0x2e, 0x3d, 0x6d, 0xc5, 0xb9,
-0xb3, 0xb2, 0xb4, 0xba, 0xc1, 0xcd, 0xe0, 0xfc, 0xfb, 0xe0,
-0xce, 0xc3, 0xbb, 0xb7, 0xb6, 0xb9, 0xc0, 0xda, 0x4b, 0x36,
-0x2b, 0x25, 0x20, 0x1f, 0x20, 0x26, 0x2e, 0x46, 0xc2, 0xab,
-0x9f, 0x9a, 0x97, 0x96, 0x98, 0x9c, 0xa5, 0xba, 0x41, 0x27,
-0x1b, 0x15, 0x12, 0x11, 0x13, 0x18, 0x1f, 0x32, 0xc8, 0xa6,
-0x9a, 0x94, 0x90, 0x8f, 0x91, 0x97, 0x9e, 0xaf, 0x54, 0x29,
-0x1c, 0x16, 0x12, 0x11, 0x14, 0x18, 0x1f, 0x2e, 0xf2, 0xae,
-0xa0, 0x9b, 0x98, 0x97, 0x99, 0x9d, 0xa5, 0xb3, 0xe4, 0x3a,
-0x2b, 0x25, 0x21, 0x21, 0x24, 0x29, 0x30, 0x3e, 0x62, 0xcd,
-0xbf, 0xbb, 0xbb, 0xbe, 0xc6, 0xd1, 0xe7, 0x76, 0x75, 0xe7,
-0xcf, 0xc1, 0xb9, 0xb2, 0xaf, 0xaf, 0xb2, 0xba, 0xcf, 0x4c,
-0x34, 0x29, 0x22, 0x1e, 0x1d, 0x1e, 0x22, 0x2b, 0x3e, 0xc7,
-0xab, 0x9f, 0x99, 0x96, 0x95, 0x96, 0x9a, 0xa2, 0xb5, 0x4a,
-0x28, 0x1c, 0x15, 0x11, 0x10, 0x12, 0x17, 0x1e, 0x2e, 0xd5,
-0xa9, 0x9b, 0x95, 0x90, 0x8f, 0x91, 0x96, 0x9d, 0xac, 0x78,
-0x2c, 0x1e, 0x17, 0x13, 0x12, 0x14, 0x18, 0x1f, 0x2d, 0x5d,
-0xb3, 0xa4, 0x9d, 0x9a, 0x99, 0x9b, 0x9e, 0xa6, 0xb2, 0xd6,
-0x3f, 0x2f, 0x29, 0x26, 0x26, 0x28, 0x2d, 0x35, 0x42, 0x5e,
-0xd8, 0xca, 0xc6, 0xc9, 0xcf, 0xe4, 0x69, 0x59, 0x58, 0x64,
-0xdf, 0xc7, 0xba, 0xb1, 0xac, 0xaa, 0xaa, 0xad, 0xb4, 0xc7,
-0x4f, 0x33, 0x27, 0x1f, 0x1c, 0x1b, 0x1c, 0x1f, 0x27, 0x39,
-0xce, 0xac, 0x9f, 0x99, 0x95, 0x94, 0x95, 0x99, 0x9f, 0xaf,
-0x59, 0x2a, 0x1c, 0x16, 0x11, 0x10, 0x11, 0x16, 0x1d, 0x2b };
diff --git a/1.4.23-rc4/channels/Makefile b/1.4.23-rc4/channels/Makefile
deleted file mode 100644
index 8f067f6b0..000000000
--- a/1.4.23-rc4/channels/Makefile
+++ /dev/null
@@ -1,123 +0,0 @@
-#
-# Asterisk -- A telephony toolkit for Linux.
-#
-# Makefile for channel drivers
-#
-# Copyright (C) 1999-2006, Digium, Inc.
-#
-# This program is free software, distributed under the terms of
-# the GNU General Public License
-#
-
--include ../menuselect.makeopts ../menuselect.makedeps
-
-MENUSELECT_CATEGORY=CHANNELS
-MENUSELECT_DESCRIPTION=Channel Drivers
-
-ALL_C_MODS:=$(patsubst %.c,%,$(wildcard chan_*.c))
-ALL_CC_MODS:=$(patsubst %.cc,%,$(wildcard chan_*.cc))
-
-C_MODS:=$(filter-out $(MENUSELECT_CHANNELS),$(ALL_C_MODS))
-CC_MODS:=$(filter-out $(MENUSELECT_CHANNELS),$(ALL_CC_MODS))
-
-ifeq ($(OSARCH),OpenBSD)
- PTLIB=-lpt_OpenBSD_x86_r
- H323LIB=-lh323_OpenBSD_x86_r
-endif
-
-ifeq ($(OSARCH),linux-gnu)
- PTLIB=-lpt_linux_x86_r
- H323LIB=-lh323_linux_x86_r
- CHANH323LIB=-ldl
-endif
-
-ifeq ($(OSARCH),FreeBSD)
- PTLIB=-lpt_FreeBSD_x86_r
- H323LIB=-lh323_FreeBSD_x86_r
- CHANH323LIB=-pthread
-endif
-
-ifeq ($(OSARCH),NetBSD)
- PTLIB=-lpt_NetBSD_x86_r
- H323LIB=-lh323_NetBSD_x86_r
-endif
-
-ifeq ($(wildcard h323/libchanh323.a),)
- CC_MODS:=$(filter-out chan_h323,$(CC_MODS))
-endif
-
-ifndef OPENH323DIR
- OPENH323DIR=$(HOME)/openh323
-endif
-
-ifndef PWLIBDIR
- PWLIBDIR=$(HOME)/pwlib
-endif
-
-LOADABLE_MODS:=$(C_MODS) $(CC_MODS)
-
-ifneq ($(findstring channels,$(MENUSELECT_EMBED)),)
- EMBEDDED_MODS:=$(LOADABLE_MODS)
- LOADABLE_MODS:=
-endif
-
-all: _all
-
-include $(ASTTOPDIR)/Makefile.moddir_rules
-
-clean::
- rm -f gentone
- $(MAKE) -C misdn clean
-
-ifneq ($(wildcard h323/Makefile.ast),)
- include h323/Makefile.ast
-H323LDFLAGS+=-Wl,--version-script=h323/noexport.map
-clean::
- if [ -f h323/Makefile ]; then $(MAKE) -C h323 clean; fi
-else
-h323/libchanh323.a h323/Makefile.ast:
- $(CMD_PREFIX) $(MAKE) -C h323
- $(CMD_PREFIX) rm -f ../main/asterisk
- $(CMD_PREFIX) echo "***************************************************************"
- $(CMD_PREFIX) echo
- $(CMD_PREFIX) echo "********** Re-run 'make' to pick up H.323 parameters **********"
- $(CMD_PREFIX) echo
- $(CMD_PREFIX) echo "***************************************************************"
- $(CMD_PREFIX) exit 1
-endif
-
-dist-clean::
- rm -f h323/Makefile
-
-gentone: gentone.c
- $(ECHO_PREFIX) echo " [LD] $^ -> $@"
- $(CMD_PREFIX) $(HOST_CC) $(STATIC_BUILD) -o $@ $(HOST_CFLAGS) $(HOST_LDFLAGS) $^ $(LIBS)
-gentone: LIBS+=-lm
-
-busy_tone.h:
- ./gentone busy_tone 480 620
-
-ring_tone.h:
- ./gentone ring_tone 440 480
-
-$(if $(filter chan_iax2,$(EMBEDDED_MODS)),modules.link,chan_iax2.so): iax2-parser.o iax2-provision.o
-
-ifeq ($(OSARCH),linux-gnu)
-chan_h323.so: chan_h323.o h323/libchanh323.a h323/Makefile.ast
- $(ECHO_PREFIX) echo " [LD] $^ -> $@"
- $(CMD_PREFIX) $(CXX) $(PTHREAD_CFLAGS) $(ASTLDFLAGS) $(SOLINK) $(H323LDFLAGS) -o $@ $< h323/libchanh323.a $(H323LDLIBS)
-else
-chan_h323.so: chan_h323.o h323/libchanh323.a
- $(ECHO_PREFIX) echo " [LD] $^ -> $@"
- $(CMD_PREFIX) $(CXX) $(PTHREAD_CFLAGS) $(ASTLDFLAGS) $(SOLINK) -o $@ $< h323/libchanh323.a $(CHANH323LIB) -L$(PWLIBDIR)/lib $(PTLIB) -L$(OPENH323DIR)/lib $(H323LIB) -L/usr/lib -lcrypto -lssl -lexpat
-endif
-
-chan_misdn.o: ASTCFLAGS+=-Imisdn
-
-misdn_config.o: ASTCFLAGS+=-Imisdn
-
-misdn/isdn_lib.o: ASTCFLAGS+=-Wno-strict-aliasing
-
-misdn_config.o misdn/isdn_lib.o misdn/isdn_msg_parser.o: ASTCFLAGS+=$(MENUSELECT_OPTS_chan_misdn:%=-D%) $(foreach dep,$(MENUSELECT_DEPENDS_chan_misdn),$(value $(dep)_INCLUDE))
-
-$(if $(filter chan_misdn,$(EMBEDDED_MODS)),modules.link,chan_misdn.so): chan_misdn.o misdn_config.o misdn/isdn_lib.o misdn/isdn_msg_parser.o
diff --git a/1.4.23-rc4/channels/answer.h b/1.4.23-rc4/channels/answer.h
deleted file mode 100644
index 4168c5012..000000000
--- a/1.4.23-rc4/channels/answer.h
+++ /dev/null
@@ -1,237 +0,0 @@
-/*!\file
- * \brief Signed 16-bit audio data
- *
- * Source: answer.raw
- *
- * Copyright (C) 1999-2005, Digium, Inc.
- *
- * Distributed under the terms of the GNU General Public License
- *
- */
-
-static signed short answer[] = {
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 0x19b7, 0x0245, 0xeee5, 0xb875, 0xd9a4, 0x6018, 0x660a, 0xc3c6,
-0x8741, 0xff55, 0x4c2e, 0x2146, 0xfed2, 0xf079, 0xcbd4, 0xe561, 0x3c41, 0x3166,
-0xd425, 0xdc59, 0x2748, 0x087d, 0xc72b, 0xfe3a, 0x4681, 0x14c6, 0xcf45, 0xdd38,
-0xf8dd, 0x0a39, 0x3a5a, 0x32b9, 0xbfec, 0x957f, 0x15a3, 0x70f4, 0x1d95, 0xbfc4,
-0xd367, 0xfda0, 0x0dc0, 0x29eb, 0x1fc2, 0xd684, 0xcab1, 0x19c7, 0x29ef, 0xe679,
-0xe9d0, 0x2b82, 0x151a, 0xca9f, 0xdb68, 0x1f4a, 0x271c, 0x0e2a, 0xfb32, 0xd1b2,
-0xc8ff, 0x2382, 0x6380, 0x0a52, 0xa118, 0xccbf, 0x2ddc, 0x33fd, 0x0964, 0xf2a4,
-0xdd81, 0xe092, 0x1a00, 0x325c, 0xf5e3, 0xd6a1, 0x0b6c, 0x1c75, 0xe4f8, 0xe07c,
-0x2082, 0x2b3e, 0xf445, 0xdaa9, 0xea13, 0xff3c, 0x245c, 0x35c1, 0xf308, 0xab53,
-0xdf59, 0x4698, 0x3f3b, 0xe7f7, 0xca84, 0xed4d, 0x0c3f, 0x1e94, 0x1c2d, 0xf06f,
-0xd4df, 0xff34, 0x23d8, 0x001e, 0xe3f1, 0x0b15, 0x2113, 0xf3fd, 0xd768, 0xf9a0,
-0x1d31, 0x1c6e, 0x0797, 0xe3a0, 0xce6c, 0xfd7b, 0x422a, 0x2c4c, 0xd364, 0xbf42,
-0x0278, 0x303e, 0x1c51, 0xf737, 0xe25a, 0xe75f, 0x0a8f, 0x22ab, 0x05f4, 0xe3f9,
-0xf8c4, 0x1705, 0x0162, 0xe49f, 0xfb8b, 0x1e2b, 0x13ac, 0xf044, 0xe07b, 0xf01a,
-0x1567, 0x2cbf, 0x0b75, 0xd01b, 0xd206, 0x1563, 0x38d7, 0x0f2e, 0xdb32, 0xdc30,
-0x023b, 0x1e44, 0x16eb, 0xf5f7, 0xe425, 0xfa33, 0x14d5, 0x0968, 0xeff2, 0xf762,
-0x1137, 0x0e59, 0xf13a, 0xe651, 0xff41, 0x1d60, 0x18fd, 0xf1e6, 0xd75f, 0xf097,
-0x20ec, 0x27fa, 0xfba4, 0xd5b8, 0xe68e, 0x1657, 0x2518, 0x04f6, 0xe5a3, 0xe976,
-0x0578, 0x18fa, 0x0a92, 0xec0a, 0xef2a, 0x111f, 0x12f4, 0xeec3, 0xe95e, 0x0d3a,
-0x18fd, 0xff72, 0xeefc, 0xf114, 0xfaaa, 0x14ee, 0x21db, 0xf56e, 0xcb49, 0xf621,
-0x3323, 0x1947, 0xe017, 0xe7e9, 0x0819, 0x0707, 0x084c, 0x0f57, 0xf152, 0xdf92,
-0x104a, 0x28eb, 0xedcc, 0xd4ad, 0x1415, 0x296d, 0xed9a, 0xdf57, 0x0cc2, 0x0d95,
-0xf7b5, 0x0deb, 0x0b34, 0xd713, 0xea08, 0x38d6, 0x216d, 0xc727, 0xdc32, 0x2cd2,
-0x1822, 0xe2d5, 0xfeb3, 0x106c, 0xe6e5, 0xf81e, 0x2fe8, 0x01af, 0xc180, 0x037a,
-0x42d8, 0xf88d, 0xc344, 0x0a4f, 0x2c4e, 0xf19d, 0xebeb, 0x162c, 0xf9e9, 0xde93,
-0x1b56, 0x2c60, 0xd8aa, 0xce3e, 0x2a41, 0x2eeb, 0xdab1, 0xde32, 0x1c32, 0x0aba,
-0xeabe, 0x1008, 0x136d, 0xda2f, 0xec3b, 0x31dd, 0x1130, 0xca79, 0xf5b8, 0x3423,
-0x0274, 0xd27d, 0x035e, 0x1e68, 0xf641, 0xf904, 0x1691, 0xef7d, 0xd57a, 0x1c3b,
-0x3c23, 0xe881, 0xc274, 0x0af5, 0x2962, 0xfa34, 0xf676, 0x0f71, 0xefcc, 0xe01f,
-0x19e7, 0x276f, 0xe694, 0xe134, 0x1c3a, 0x0e8b, 0xd8e7, 0xfa81, 0x2f8b, 0x07c5,
-0xd904, 0xf6fa, 0x0ca5, 0xf9a2, 0x0dc7, 0x2623, 0xec54, 0xbe23, 0x02b6, 0x4296,
-0x10cd, 0xda61, 0xf11c, 0x0103, 0xf41c, 0x10b4, 0x2a03, 0xf63c, 0xce1a, 0xfdbd,
-0x1fb4, 0xfc51, 0xf727, 0x1c8a, 0x04ff, 0xcf41, 0xec05, 0x2913, 0x1ce8, 0xf70c,
-0xf744, 0xede8, 0xdd77, 0x0d99, 0x43f1, 0x119c, 0xc14f, 0xd60e, 0x17cb, 0x1e19,
-0x0d4e, 0x0c95, 0xeed1, 0xcdf4, 0xf7a5, 0x331f, 0x1cd0, 0xeb17, 0xf082, 0xfb19,
-0xe899, 0xfdeb, 0x323c, 0x2036, 0xdad3, 0xd134, 0xfd03, 0x1345, 0x1c10, 0x2239,
-0xf656, 0xbc22, 0xdc3f, 0x3392, 0x3d59, 0xfd77, 0xdb4d, 0xe23f, 0xedbe, 0x0f7e,
-0x35cc, 0x1947, 0xd5dc, 0xd1bf, 0x035d, 0x16fc, 0x1174, 0x1675, 0x0249, 0xd2d4,
-0xd851, 0x184d, 0x32fe, 0x0f91, 0xee14, 0xe1e6, 0xdf9b, 0x016b, 0x3668, 0x2b2b,
-0xe20c, 0xc554, 0xf257, 0x1c05, 0x1fc5, 0x14f0, 0xf891, 0xd41c, 0xdf83, 0x1865,
-0x2de1, 0x0b16, 0xed58, 0xea0c, 0xea79, 0xfbd9, 0x22af, 0x2732, 0xf62f, 0xd389,
-0xe7d9, 0x0b39, 0x1cdc, 0x1de3, 0x038a, 0xd809, 0xd5f7, 0x0b55, 0x305e, 0x1910,
-0xf02e, 0xe089, 0xe7c7, 0x0195, 0x2265, 0x21da, 0xf743, 0xd8f2, 0xe978, 0x09a1,
-0x190a, 0x17c5, 0x045a, 0xe46d, 0xdd06, 0xffb2, 0x2293, 0x1cfe, 0xfd4d, 0xe4f9,
-0xe310, 0xfaf1, 0x1d22, 0x2376, 0x0113, 0xde3a, 0xe21b, 0x0204, 0x1ba1, 0x1bd6,
-0x0333, 0xe563, 0xe104, 0xfd51, 0x1bc1, 0x1ccf, 0x0285, 0xe757, 0xe35e, 0xfaf2,
-0x185d, 0x1d46, 0x06b7, 0xec13, 0xe108, 0xef6e, 0x121d, 0x2a17, 0x16a6, 0xe32c,
-0xc9a9, 0xf070, 0x2f48, 0x3788, 0xfa4e, 0xc32a, 0xd9c2, 0x1fa1, 0x36fe, 0x07fa,
-0xd9e4, 0xe577, 0x0e5e, 0x1755, 0xfb53, 0xed71, 0x0540, 0x19e0, 0x0301, 0xdc97,
-0xe391, 0x1937, 0x367c, 0x0bc9, 0xca4c, 0xc96b, 0x105d, 0x461f, 0x2416, 0xd481,
-0xbc97, 0xf8b7, 0x39af, 0x2ec9, 0xecc6, 0xcb50, 0xeee3, 0x1ffe, 0x1e8e, 0xf700,
-0xe66a, 0xff58, 0x149f, 0x02e5, 0xe792, 0xf2d8, 0x1a4d, 0x225a, 0xf642, 0xce7f,
-0xe6a6, 0x25e2, 0x38f5, 0x01d0, 0xc50f, 0xd243, 0x19bd, 0x3fc6, 0x14f0, 0xd2d7,
-0xcdb6, 0x069a, 0x2ffe, 0x1847, 0xe6f8, 0xdf0a, 0x0337, 0x1a90, 0x067a, 0xeb5b,
-0xf541, 0x143b, 0x14f2, 0xf092, 0xdc02, 0xfb91, 0x28a3, 0x2274, 0xeaa8, 0xc9e7,
-0xef48, 0x2d01, 0x322e, 0xf6d2, 0xc7cb, 0xe13b, 0x1fda, 0x3217, 0x0458, 0xd690,
-0xe2bf, 0x11c4, 0x21d5, 0x0291, 0xe5c8, 0xf3a9, 0x12ba, 0x11aa, 0xf22b, 0xe627,
-0x03ec, 0x219a, 0x1036, 0xe2f2, 0xd93f, 0x059c, 0x2ed6, 0x1b75, 0xe227, 0xce55,
-0xfb19, 0x2de0, 0x2477, 0xed08, 0xd148, 0xf307, 0x21d4, 0x2002, 0xf543, 0xdeac,
-0xf7f9, 0x18a9, 0x11d6, 0xf0ef, 0xe8e4, 0x05ea, 0x1ba5, 0x0727, 0xe448, 0xe748,
-0x100e, 0x265e, 0x07fc, 0xdbae, 0xde78, 0x0efa, 0x2ce0, 0x0f94, 0xddf1, 0xd9ea,
-0x0797, 0x28f6, 0x12eb, 0xe60c, 0xdf46, 0x0469, 0x1fbb, 0x0ced, 0xe9f6, 0xe95f,
-0x09fe, 0x1ab9, 0x02cb, 0xe5a4, 0xef2a, 0x1327, 0x1d7b, 0xfd07, 0xde3d, 0xed9c,
-0x17e5, 0x22e7, 0xfe3a, 0xdb38, 0xe9b9, 0x161a, 0x2416, 0x0175, 0xde3d, 0xe9de,
-0x1294, 0x1fc9, 0x00ea, 0xe2a7, 0xeee2, 0x1298, 0x1a7d, 0xfc1d, 0xe3bb, 0xf47a,
-0x1642, 0x185e, 0xf727, 0xe1af, 0xf709, 0x19c3, 0x18e7, 0xf50d, 0xe010, 0xf75b,
-0x1a9c, 0x18d8, 0xf4c5, 0xe0c9, 0xf865, 0x1a1c, 0x16d5, 0xf3a6, 0xe257, 0xfaf2,
-0x1a44, 0x14d5, 0xf34f, 0xe4b6, 0xfc77, 0x17d5, 0x0ff8, 0xf133, 0xe8b7, 0x0344,
-0x1a37, 0x0ad5, 0xe95e, 0xe61a, 0x08a5, 0x227e, 0x0e33, 0xe4a7, 0xdd70, 0x03b0,
-0x25f4, 0x17b2, 0xec0a, 0xdb4e, 0xf898, 0x1ba3, 0x18f6, 0xf973, 0xe87f, 0xf77a,
-0x0b93, 0x096c, 0xfb0e, 0xfb03, 0x0896, 0x0940, 0xf51d, 0xe904, 0xfdc7, 0x1dda,
-0x1bf9, 0xf29b, 0xd37f, 0xea1b, 0x1f37, 0x3175, 0x07eb, 0xd3f7, 0xd46b, 0x077d,
-0x2eeb, 0x1e67, 0xeeae, 0xd8c7, 0xef85, 0x1119, 0x18d3, 0x088e, 0xf953, 0xf5ad,
-0xf556, 0xf63d, 0x0234, 0x167a, 0x19a1, 0xfbf9, 0xd873, 0xdd4b, 0x0f06, 0x3748,
-0x21e6, 0xe181, 0xc032, 0xe79a, 0x2bec, 0x3e76, 0x0b1b, 0xce41, 0xcb23, 0xff96,
-0x2d79, 0x26d1, 0xfcc7, 0xdf8a, 0xe525, 0xfd83, 0x10f1, 0x16d7, 0x0f50, 0xfaea,
-0xe3f1, 0xe20f, 0x0158, 0x27d9, 0x2866, 0xf96f, 0xcb34, 0xd563, 0x11d6, 0x3d25,
-0x2424, 0xe254, 0xc2c9, 0xe7cd, 0x248d, 0x34f5, 0x0c42, 0xdcd0, 0xd827, 0xfa65,
-0x19eb, 0x1b50, 0x0721, 0xf396, 0xeb9c, 0xefde, 0x0016, 0x1594, 0x1cc1, 0x0658,
-0xe22b, 0xd852, 0xfb3e, 0x2923, 0x2c78, 0xfc87, 0xcdb5, 0xd69c, 0x0e3c, 0x3527,
-0x201f, 0xe993, 0xcf9e, 0xeb21, 0x183f, 0x25ea, 0x0c93, 0xed4d, 0xe5f9, 0xf548,
-0x07fb, 0x117c, 0x0ff2, 0x0398, 0xf08c, 0xe628, 0xf489, 0x143b, 0x2419, 0x0ccf,
-0xe2cc, 0xd5a6, 0xf861, 0x2615, 0x2a1b, 0xfeb4, 0xd543, 0xdc53, 0x09b4, 0x2901,
-0x19ff, 0xf24a, 0xde86, 0xeec4, 0x0b7b, 0x1733, 0x0d0a, 0xfc24, 0xf1bb, 0xf110,
-0xfa03, 0x0a0f, 0x15d4, 0x0e21, 0xf435, 0xe17e, 0xee90, 0x1225, 0x2527, 0x0efa,
-0xe61f, 0xd916, 0xf7b8, 0x1f50, 0x2326, 0x0099, 0xe01e, 0xe473, 0x0491, 0x1b37,
-0x1360, 0xfb17, 0xecd9, 0xf20d, 0x0051, 0x0aec, 0x0d4a, 0x073d, 0xfa5a, 0xeeb8,
-0xf165, 0x0516, 0x17dc, 0x12da, 0xf71b, 0xe213, 0xed85, 0x0eef, 0x20c8, 0x0e09,
-0xebcc, 0xe0d4, 0xf848, 0x1637, 0x19d6, 0x026b, 0xec09, 0xed00, 0xff9b, 0x0e5a,
-0x0d6b, 0x026c, 0xf865, 0xf4da, 0xf888, 0x025a, 0x0cbb, 0x0d53, 0xff96, 0xeefa,
-0xee80, 0x021c, 0x15d6, 0x126a, 0xf9c1, 0xe724, 0xf017, 0x0aa1, 0x18b6, 0x0b4e,
-0xf2d7, 0xea91, 0xf957, 0x0cac, 0x1061, 0x03f4, 0xf6ad, 0xf476, 0xfbdf, 0x0489,
-0x08b1, 0x06df, 0xffcf, 0xf766, 0xf537, 0xfddf, 0x0ad4, 0x0e15, 0x01da, 0xf205,
-0xf0a0, 0x0082, 0x1066, 0x0e41, 0xfc71, 0xef1b, 0xf4ad, 0x05cd, 0x0f32, 0x07ed,
-0xf9c8, 0xf401, 0xfa93, 0x04af, 0x088c, 0x04a7, 0xfe15, 0xf9f1, 0xfa64, 0xff1e,
-0x0539, 0x078c, 0x02af, 0xfa1a, 0xf69d, 0xfd09, 0x075b, 0x0a3d, 0x01f2, 0xf761,
-0xf642, 0xffa7, 0x08f3, 0x0830, 0xff05, 0xf7db, 0xf9bc, 0x0174, 0x068b, 0x04b2,
-0xfeff, 0xfb39, 0xfc1a, 000000, 0x0371, 0x03d7, 0x00fe, 0xfd37, 0xfbe0, 0xfe78,
-0x02af, 0x044a, 0x0180, 0xfd43, 0xfc00, 0xfed1, 0x02aa, 0x0346, 0x00dd, 0xfde0,
-0xfbfe, 0x0114, 0x0987, 0x04bc, 0xf49d, 0xf23a, 0x06ab, 0x162e, 0x0544, 0xe76b,
-0xea25, 0x1015, 0x2474, 0x0431, 0xd7d3, 0xe1ec, 0x1923, 0x2df5, 0x01cd, 0xd386,
-0xe3d9, 0x1b9d, 0x2c62, 0xfeb8, 0xd31a, 0xe6ba, 0x1dbd, 0x2abb, 0xfbab, 0xd2ed,
-0xe9ab, 0x1fa7, 0x28ef, 0xf8b3, 0xd2f5, 0xeca5, 0x2160, 0x26fd, 0xf5d7, 0xd334,
-0xefa1, 0x22e5, 0x24ea, 0xf31b, 0xd3a9, 0xf29f, 0x2435, 0x22b6, 0xf07e, 0xd44e,
-0xf59b, 0x2551, 0x2067, 0xee08, 0xd527, 0xf88e, 0x2639, 0x1e00, 0xebb6, 0xd62d,
-0xfb77, 0x26eb, 0x1b85, 0xe98b, 0xd75f, 0xfe51, 0x276b, 0x18f9, 0xe78e, 0xd8b9,
-0x011a, 0x27b6, 0x1660, 0xe5bb, 0xda3a, 0x03cc, 0x27cf, 0x13bd, 0xe415, 0xdbdf,
-0x066a, 0x27b7, 0x1117, 0xe29e, 0xdda5, 0x08ec, 0x276e, 0x0e6d, 0xe154, 0xdf89,
-0x0b52, 0x26f6, 0x0bc7, 0xe039, 0xe185, 0x0d96, 0x2653, 0x0924, 0xdf4e, 0xe399,
-0x0fb9, 0x2584, 0x068b, 0xde93, 0xe5c0, 0x11b8, 0x248e, 0x03fd, 0xde08, 0xe7f8,
-0x1390, 0x2372, 0x0180, 0xddaa, 0xea3c, 0x1544, 0x2231, 0xff12, 0xdd7a, 0xec89,
-0x16cf, 0x20d0, 0xfcb9, 0xdd77, 0xeedb, 0x1831, 0x1f52, 0xfa77, 0xdd9f, 0xf132,
-0x1969, 0x1db7, 0xf850, 0xddf1, 0xf385, 0x1a75, 0x1c06, 0xf645, 0xde6b, 0xf5d7,
-0x1b5b, 0x1a3f, 0xf457, 0xdf0d, 0xf820, 0x1c13, 0x1867, 0xf288, 0xdfd2, 0xfa5f,
-0x1ca1, 0x167f, 0xf0db, 0xe0ba, 0xfc92, 0x1d06, 0x148b, 0xef50, 0xe1c1, 0xfeb5,
-0x1d43, 0x1290, 0xede9, 0xe2e6, 0x00c6, 0x1d58, 0x108e, 0xeca7, 0xe426, 0x02c4,
-0x1d45, 0x0e8a, 0xeb8a, 0xe57f, 0x04a9, 0x1d0e, 0x0c87, 0xea92, 0xe6ec, 0x0677,
-0x1cb2, 0x0a87, 0xe9be, 0xe86e, 0x082a, 0x1c34, 0x088b, 0xe912, 0xe9fe, 0x09c1,
-0x1b95, 0x069c, 0xe88c, 0xeb9c, 0x0b3a, 0x1ad9, 0x04b6, 0xe82a, 0xed43, 0x0c96,
-0x1a00, 0x02df, 0xe7eb, 0xeef3, 0x0dd0, 0x190d, 0x0116, 0xe7d0, 0xf0a8, 0x0eec,
-0x1804, 0xff61, 0xe7d8, 0xf25d, 0x0fe6, 0x16e3, 0xfdc0, 0xe800, 0xf412, 0x10bf,
-0x15b1, 0xfc36, 0xe848, 0xf5c5, 0x1176, 0x146e, 0xfac2, 0xe8ad, 0xf771, 0x120d,
-0x1320, 0xf969, 0xe92e, 0xf913, 0x1282, 0x11c4, 0xf828, 0xe9cb, 0xfaac, 0x12d8,
-0x1062, 0xf703, 0xea7e, 0xfc38, 0x130e, 0x0efa, 0xf5fb, 0xeb49, 0xfdb5, 0x1325,
-0x0d8e, 0xf50e, 0xec26, 0xff20, 0x131e, 0x0c21, 0xf43f, 0xed15, 0x007a, 0x12fa,
-0x0ab6, 0xf38d, 0xee15, 0x01be, 0x12bd, 0x094f, 0xf2f9, 0xef22, 0x02ef, 0x1265,
-0x07f0, 0xf283, 0xf037, 0x0408, 0x11f6, 0x0699, 0xf226, 0xf156, 0x050a, 0x1170,
-0x054b, 0xf1e8, 0xf27a, 0x05f4, 0x10d8, 0x040c, 0xf1c5, 0xf3a3, 0x06c2, 0x102c,
-0x02da, 0xf1bc, 0xf4cc, 0x0779, 0x0f71, 0x01b7, 0xf1cc, 0xf5f5, 0x0815, 0x0ea7,
-0x00a8, 0xf1f4, 0xf719, 0x0899, 0x0dd2, 0xffab, 0xf233, 0xf839, 0x0902, 0x0cf4,
-0xfec0, 0xf288, 0xf950, 0x0952, 0x0c0e, 0xfdec, 0xf2ee, 0xfa5d, 0x0989, 0x0b23,
-0xfd2d, 0xf368, 0xfb62, 0x09a7, 0x0a35, 0xfc85, 0xf3f1, 0xfc58, 0x09af, 0x0946,
-0xfbf2, 0xf488, 0xfd3f, 0x09a1, 0x0859, 0xfb77, 0xf52c, 0xfe17, 0x097d, 0x076f,
-0xfb14, 0xf5d8, 0xfede, 0x0945, 0x068a, 0xfac6, 0xf68d, 0xff93, 0x08fb, 0x05ad,
-0xfa8e, 0xf747, 0x0034, 0x08a1, 0x04da, 0xfa6f, 0xf805, 0x00c2, 0x0836, 0x0410,
-0xfa63, 0xf8c6, 0x013c, 0x07bf, 0x0354, 0xfa6c, 0xf985, 0x01a1, 0x073b, 0x02a4,
-0xfa8a, 0xfa43, 0x01f1, 0x06af, 0x0204, 0xfab9, 0xfafc, 0x022c, 0x0619, 0x0175,
-0xfafa, 0xfbae, 0x0252, 0x057f, 0x00f6, 0xfb4b, 0xfc5a, 0x0263, 0x04e0, 0x008b,
-0xfbaa, 0xfcfa, 0x0262, 0x0440, 0x0032, 0xfc16, 0xfd90, 0x024b, 0x03a0, 0xffec,
-0xfc8c, 0xfe19, 0x0225, 0x0301, 0xffb9, 0xfd0c, 0xfe93, 0x01ea, 0x0267, 0xff9c,
-0xfd95, 0xfefe, 0x01a0, 0x01d3, 0xff90, 0xfe22, 0xff5a, 0x0147, 0x0145, 0xff99,
-0xfeb3, 0xffa1, 0x00e0, 0x00c3, 0xffb6, 0xff46, 0xffd9, 0x006d, 0x004b, 0xffe5,
-0xffda, 0xfffc, 000000, 0xfffe, 000000, 0xffff, 000000, 0xffff, 0xffff, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000 };
diff --git a/1.4.23-rc4/channels/busy_tone.h b/1.4.23-rc4/channels/busy_tone.h
deleted file mode 100644
index 6e5db8e47..000000000
--- a/1.4.23-rc4/channels/busy_tone.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/* busy.h: Generated from frequencies 480 and 620
- by gentone. 400 samples */
-static short busy[400] = {
- 0, 13697, 24766, 31109, 31585, 26222, 16198, 3569,
- -9162, -19575, -25812, -26935, -23069, -15322, -5493, 4339,
- 12277, 16985, 17934, 15440, 10519, 4585, -908, -4827,
- -6592, -6269, -4489, -2220, -467, 30, -983, -3203,
- -5839, -7844, -8215, -6301, -2035, 3975, 10543, 16141,
- 19260, 18787, 14322, 6338, -3845, -14296, -22858, -27611,
- -27309, -21691, -11585, 1213, 14285, 25068, 31388, 31915,
- 26457, 16010, 2568, -11282, -22885, -30054, -31509, -27120,
- -17908, -5805, 6760, 17379, 24147, 26028, 23020, 16094,
- 6931, -2478, -10279, -15136, -16474, -14538, -10253, -4949,
- 0, 3515, 5052, 4688, 3045, 1069, -268, -272,
- 1269, 3996, 7067, 9381, 9889, 7910, 3365, -3123,
- -10320, -16622, -20424, -20510, -16384, -8448, 2006, 13026,
- 22383, 28040, 28613, 23696, 13996, 1232, -12193, -23670,
- -30918, -32459, -27935, -18190, -5103, 8795, 20838, 28764,
- 31164, 27753, 19395, 7893, -4412, -15136, -22342, -24909,
- -22717, -16609, -8143, 780, 8361, 13272, 14909, 13455,
- 9758, 5067, 678, -2387, -3624, -3133, -1538, 224,
- 1209, 751, -1315, -4580, -8145, -10848, -11585, -9628,
- -4878, 2038, 9844, 16867, 21403, 22124, 18429, 10638,
- 0, -11524, -21643, -28211, -29702, -25561, -16364, -3737,
- 9946, 22044, 30180, 32733, 29182, 20210, 7573, -6269,
- -18655, -27259, -30558, -28117, -20645, -9807, 2148, 12878,
- 20426, 23599, 22173, 16865, 9117, 731, -6552, -11426,
- -13269, -12216, -9050, -4941, -1118, 1460, 2335, 1635,
- 0, -1635, -2335, -1460, 1118, 4941, 9050, 12216,
- 13269, 11426, 6552, -731, -9117, -16865, -22173, -23599,
- -20426, -12878, -2148, 9807, 20645, 28117, 30558, 27259,
- 18655, 6269, -7573, -20210, -29182, -32733, -30180, -22044,
- -9946, 3737, 16364, 25561, 29702, 28211, 21643, 11524,
- 0, -10638, -18429, -22124, -21403, -16867, -9844, -2038,
- 4878, 9628, 11585, 10848, 8145, 4580, 1315, -751,
- -1209, -224, 1538, 3133, 3624, 2387, -678, -5067,
- -9758, -13455, -14909, -13272, -8361, -780, 8143, 16609,
- 22717, 24909, 22342, 15136, 4412, -7893, -19395, -27753,
- -31164, -28764, -20838, -8795, 5103, 18190, 27935, 32459,
- 30918, 23670, 12193, -1232, -13996, -23696, -28613, -28040,
- -22383, -13026, -2006, 8448, 16384, 20510, 20424, 16622,
- 10320, 3123, -3365, -7910, -9889, -9381, -7067, -3996,
- -1269, 272, 268, -1069, -3045, -4688, -5052, -3515,
- 0, 4949, 10253, 14538, 16474, 15136, 10279, 2478,
- -6931, -16094, -23020, -26028, -24147, -17379, -6760, 5805,
- 17908, 27120, 31509, 30054, 22885, 11282, -2568, -16010,
- -26457, -31915, -31388, -25068, -14285, -1213, 11585, 21691,
- 27309, 27611, 22858, 14296, 3845, -6338, -14322, -18787,
- -19260, -16141, -10543, -3975, 2035, 6301, 8215, 7844,
- 5839, 3203, 983, -30, 467, 2220, 4489, 6269,
- 6592, 4827, 908, -4585, -10519, -15440, -17934, -16985,
- -12277, -4339, 5493, 15322, 23069, 26935, 25812, 19575,
- 9162, -3569, -16198, -26222, -31585, -31109, -24766, -13697,
-
-};
diff --git a/1.4.23-rc4/channels/chan_agent.c b/1.4.23-rc4/channels/chan_agent.c
deleted file mode 100644
index b12983dfc..000000000
--- a/1.4.23-rc4/channels/chan_agent.c
+++ /dev/null
@@ -1,2870 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 1999 - 2006, Digium, Inc.
- *
- * Mark Spencer <markster@digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-
-/*! \file
- *
- * \brief Implementation of Agents (proxy channel)
- *
- * \author Mark Spencer <markster@digium.com>
- *
- * This file is the implementation of Agents modules.
- * It is a dynamic module that is loaded by Asterisk.
- * \par See also
- * \arg \ref Config_agent
- *
- * \ingroup channel_drivers
- */
-/*** MODULEINFO
- <depend>chan_local</depend>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <unistd.h>
-#include <sys/socket.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <sys/signal.h>
-
-#include "asterisk/lock.h"
-#include "asterisk/channel.h"
-#include "asterisk/config.h"
-#include "asterisk/logger.h"
-#include "asterisk/module.h"
-#include "asterisk/pbx.h"
-#include "asterisk/options.h"
-#include "asterisk/lock.h"
-#include "asterisk/sched.h"
-#include "asterisk/io.h"
-#include "asterisk/rtp.h"
-#include "asterisk/acl.h"
-#include "asterisk/callerid.h"
-#include "asterisk/file.h"
-#include "asterisk/cli.h"
-#include "asterisk/app.h"
-#include "asterisk/musiconhold.h"
-#include "asterisk/manager.h"
-#include "asterisk/features.h"
-#include "asterisk/utils.h"
-#include "asterisk/causes.h"
-#include "asterisk/astdb.h"
-#include "asterisk/devicestate.h"
-#include "asterisk/monitor.h"
-#include "asterisk/stringfields.h"
-
-static const char tdesc[] = "Call Agent Proxy Channel";
-static const char config[] = "agents.conf";
-
-static const char app[] = "AgentLogin";
-static const char app2[] = "AgentCallbackLogin";
-static const char app3[] = "AgentMonitorOutgoing";
-
-static const char synopsis[] = "Call agent login";
-static const char synopsis2[] = "Call agent callback login";
-static const char synopsis3[] = "Record agent's outgoing call";
-
-static const char descrip[] =
-" AgentLogin([AgentNo][|options]):\n"
-"Asks the agent to login to the system. Always returns -1. While\n"
-"logged in, the agent can receive calls and will hear a 'beep'\n"
-"when a new call comes in. The agent can dump the call by pressing\n"
-"the star key.\n"
-"The option string may contain zero or more of the following characters:\n"
-" 's' -- silent login - do not announce the login ok segment after agent logged in/off\n";
-
-static const char descrip2[] =
-" AgentCallbackLogin([AgentNo][|[options][|[exten]@context]]):\n"
-"Asks the agent to login to the system with callback.\n"
-"The agent's callback extension is called (optionally with the specified\n"
-"context).\n"
-"The option string may contain zero or more of the following characters:\n"
-" 's' -- silent login - do not announce the login ok segment agent logged in/off\n";
-
-static const char descrip3[] =
-" AgentMonitorOutgoing([options]):\n"
-"Tries to figure out the id of the agent who is placing outgoing call based on\n"
-"comparison of the callerid of the current interface and the global variable \n"
-"placed by the AgentCallbackLogin application. That's why it should be used only\n"
-"with the AgentCallbackLogin app. Uses the monitoring functions in chan_agent \n"
-"instead of Monitor application. That have to be configured in the agents.conf file.\n"
-"\nReturn value:\n"
-"Normally the app returns 0 unless the options are passed. Also if the callerid or\n"
-"the agentid are not specified it'll look for n+101 priority.\n"
-"\nOptions:\n"
-" 'd' - make the app return -1 if there is an error condition and there is\n"
-" no extension n+101\n"
-" 'c' - change the CDR so that the source of the call is 'Agent/agent_id'\n"
-" 'n' - don't generate the warnings when there is no callerid or the\n"
-" agentid is not known.\n"
-" It's handy if you want to have one context for agent and non-agent calls.\n";
-
-static const char mandescr_agents[] =
-"Description: Will list info about all possible agents.\n"
-"Variables: NONE\n";
-
-static const char mandescr_agent_logoff[] =
-"Description: Sets an agent as no longer logged in.\n"
-"Variables: (Names marked with * are required)\n"
-" *Agent: Agent ID of the agent to log off\n"
-" Soft: Set to 'true' to not hangup existing calls\n";
-
-static const char mandescr_agent_callback_login[] =
-"Description: Sets an agent as logged in with callback.\n"
-"Variables: (Names marked with * are required)\n"
-" *Agent: Agent ID of the agent to login\n"
-" *Exten: Extension to use for callback\n"
-" Context: Context to use for callback\n"
-" AckCall: Set to 'true' to require an acknowledgement by '#' when agent is called back\n"
-" WrapupTime: the minimum amount of time after disconnecting before the caller can receive a new call\n";
-
-static char moh[80] = "default";
-
-#define AST_MAX_AGENT 80 /*!< Agent ID or Password max length */
-#define AST_MAX_BUF 256
-#define AST_MAX_FILENAME_LEN 256
-
-static const char pa_family[] = "Agents"; /*!< Persistent Agents astdb family */
-#define PA_MAX_LEN 2048 /*!< The maximum length of each persistent member agent database entry */
-
-static int persistent_agents = 0; /*!< queues.conf [general] option */
-static void dump_agents(void);
-
-static ast_group_t group;
-static int autologoff;
-static int wrapuptime;
-static int ackcall;
-static int endcall;
-static int multiplelogin = 1;
-static int autologoffunavail = 0;
-
-static int maxlogintries = 3;
-static char agentgoodbye[AST_MAX_FILENAME_LEN] = "vm-goodbye";
-
-static int recordagentcalls = 0;
-static char recordformat[AST_MAX_BUF] = "";
-static char recordformatext[AST_MAX_BUF] = "";
-static char urlprefix[AST_MAX_BUF] = "";
-static char savecallsin[AST_MAX_BUF] = "";
-static int updatecdr = 0;
-static char beep[AST_MAX_BUF] = "beep";
-
-#define GETAGENTBYCALLERID "AGENTBYCALLERID"
-
-/*! \brief Structure representing an agent. */
-struct agent_pvt {
- ast_mutex_t lock; /*!< Channel private lock */
- int dead; /*!< Poised for destruction? */
- int pending; /*!< Not a real agent -- just pending a match */
- int abouttograb; /*!< About to grab */
- int autologoff; /*!< Auto timeout time */
- int ackcall; /*!< ackcall */
- int deferlogoff; /*!< Defer logoff to hangup */
- time_t loginstart; /*!< When agent first logged in (0 when logged off) */
- time_t start; /*!< When call started */
- struct timeval lastdisc; /*!< When last disconnected */
- int wrapuptime; /*!< Wrapup time in ms */
- ast_group_t group; /*!< Group memberships */
- int acknowledged; /*!< Acknowledged */
- char moh[80]; /*!< Which music on hold */
- char agent[AST_MAX_AGENT]; /*!< Agent ID */
- char password[AST_MAX_AGENT]; /*!< Password for Agent login */
- char name[AST_MAX_AGENT];
- int inherited_devicestate; /*!< Does the underlying channel have a devicestate to pass? */
- ast_mutex_t app_lock; /**< Synchronization between owning applications */
- int app_lock_flag;
- ast_cond_t app_complete_cond;
- volatile int app_sleep_cond; /**< Sleep condition for the login app */
- struct ast_channel *owner; /**< Agent */
- char loginchan[80]; /**< channel they logged in from */
- char logincallerid[80]; /**< Caller ID they had when they logged in */
- struct ast_channel *chan; /**< Channel we use */
- AST_LIST_ENTRY(agent_pvt) list; /**< Next Agent in the linked list. */
-};
-
-static AST_LIST_HEAD_STATIC(agents, agent_pvt); /*!< Holds the list of agents (loaded form agents.conf). */
-
-#define CHECK_FORMATS(ast, p) do { \
- if (p->chan) {\
- if (ast->nativeformats != p->chan->nativeformats) { \
- ast_log(LOG_DEBUG, "Native formats changing from %d to %d\n", ast->nativeformats, p->chan->nativeformats); \
- /* Native formats changed, reset things */ \
- ast->nativeformats = p->chan->nativeformats; \
- ast_log(LOG_DEBUG, "Resetting read to %d and write to %d\n", ast->readformat, ast->writeformat);\
- ast_set_read_format(ast, ast->readformat); \
- ast_set_write_format(ast, ast->writeformat); \
- } \
- if (p->chan->readformat != ast->rawreadformat && !p->chan->generator) \
- ast_set_read_format(p->chan, ast->rawreadformat); \
- if (p->chan->writeformat != ast->rawwriteformat && !p->chan->generator) \
- ast_set_write_format(p->chan, ast->rawwriteformat); \
- } \
-} while(0)
-
-/*! \brief Cleanup moves all the relevant FD's from the 2nd to the first, but retains things
- properly for a timingfd XXX This might need more work if agents were logged in as agents or other
- totally impractical combinations XXX */
-
-#define CLEANUP(ast, p) do { \
- int x; \
- if (p->chan) { \
- for (x=0;x<AST_MAX_FDS;x++) {\
- if (x != AST_TIMING_FD) \
- ast->fds[x] = p->chan->fds[x]; \
- } \
- ast->fds[AST_AGENT_FD] = p->chan->fds[AST_TIMING_FD]; \
- } \
-} while(0)
-
-/*--- Forward declarations */
-static struct ast_channel *agent_request(const char *type, int format, void *data, int *cause);
-static int agent_devicestate(void *data);
-static void agent_logoff_maintenance(struct agent_pvt *p, char *loginchan, long logintime, const char *uniqueid, char *logcommand);
-static int agent_digit_begin(struct ast_channel *ast, char digit);
-static int agent_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
-static int agent_call(struct ast_channel *ast, char *dest, int timeout);
-static int agent_hangup(struct ast_channel *ast);
-static int agent_answer(struct ast_channel *ast);
-static struct ast_frame *agent_read(struct ast_channel *ast);
-static int agent_write(struct ast_channel *ast, struct ast_frame *f);
-static int agent_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);
-static int agent_sendtext(struct ast_channel *ast, const char *text);
-static int agent_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
-static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
-static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge);
-static void set_agentbycallerid(const char *callerid, const char *agent);
-static struct ast_channel* agent_get_base_channel(struct ast_channel *chan);
-static int agent_set_base_channel(struct ast_channel *chan, struct ast_channel *base);
-
-/*! \brief Channel interface description for PBX integration */
-static const struct ast_channel_tech agent_tech = {
- .type = "Agent",
- .description = tdesc,
- .capabilities = -1,
- .requester = agent_request,
- .devicestate = agent_devicestate,
- .send_digit_begin = agent_digit_begin,
- .send_digit_end = agent_digit_end,
- .call = agent_call,
- .hangup = agent_hangup,
- .answer = agent_answer,
- .read = agent_read,
- .write = agent_write,
- .write_video = agent_write,
- .send_html = agent_sendhtml,
- .send_text = agent_sendtext,
- .exception = agent_read,
- .indicate = agent_indicate,
- .fixup = agent_fixup,
- .bridged_channel = agent_bridgedchannel,
- .get_base_channel = agent_get_base_channel,
- .set_base_channel = agent_set_base_channel,
-};
-
-static int agent_devicestate_cb(const char *dev, int state, void *data)
-{
- int res, i;
- struct agent_pvt *p;
- char basename[AST_CHANNEL_NAME], *tmp;
-
- /* Skip Agent status */
- if (!strncasecmp(dev, "Agent/", 6)) {
- return 0;
- }
-
- /* Try to be safe, but don't deadlock */
- for (i = 0; i < 10; i++) {
- if ((res = AST_LIST_TRYLOCK(&agents)) == 0) {
- break;
- }
- }
- if (res) {
- return -1;
- }
-
- AST_LIST_TRAVERSE(&agents, p, list) {
- ast_mutex_lock(&p->lock);
- if (p->chan) {
- ast_copy_string(basename, p->chan->name, sizeof(basename));
- if ((tmp = strrchr(basename, '-'))) {
- *tmp = '\0';
- }
- if (strcasecmp(p->chan->name, dev) == 0 || strcasecmp(basename, dev) == 0) {
- p->inherited_devicestate = state;
- ast_device_state_changed("Agent/%s", p->agent);
- }
- }
- ast_mutex_unlock(&p->lock);
- }
- AST_LIST_UNLOCK(&agents);
- return 0;
-}
-
-/*!
- * Adds an agent to the global list of agents.
- *
- * \param agent A string with the username, password and real name of an agent. As defined in agents.conf. Example: "13,169,John Smith"
- * \param pending If it is pending or not.
- * @return The just created agent.
- * \sa agent_pvt, agents.
- */
-static struct agent_pvt *add_agent(char *agent, int pending)
-{
- char *parse;
- AST_DECLARE_APP_ARGS(args,
- AST_APP_ARG(agt);
- AST_APP_ARG(password);
- AST_APP_ARG(name);
- );
- char *password = NULL;
- char *name = NULL;
- char *agt = NULL;
- struct agent_pvt *p;
-
- parse = ast_strdupa(agent);
-
- /* Extract username (agt), password and name from agent (args). */
- AST_NONSTANDARD_APP_ARGS(args, parse, ',');
-
- if(args.argc == 0) {
- ast_log(LOG_WARNING, "A blank agent line!\n");
- return NULL;
- }
-
- if(ast_strlen_zero(args.agt) ) {
- ast_log(LOG_WARNING, "An agent line with no agentid!\n");
- return NULL;
- } else
- agt = args.agt;
-
- if(!ast_strlen_zero(args.password)) {
- password = args.password;
- while (*password && *password < 33) password++;
- }
- if(!ast_strlen_zero(args.name)) {
- name = args.name;
- while (*name && *name < 33) name++;
- }
-
- /* Are we searching for the agent here ? To see if it exists already ? */
- AST_LIST_TRAVERSE(&agents, p, list) {
- if (!pending && !strcmp(p->agent, agt))
- break;
- }
- if (!p) {
- // Build the agent.
- if (!(p = ast_calloc(1, sizeof(*p))))
- return NULL;
- ast_copy_string(p->agent, agt, sizeof(p->agent));
- ast_mutex_init(&p->lock);
- ast_mutex_init(&p->app_lock);
- ast_cond_init(&p->app_complete_cond, NULL);
- p->app_lock_flag = 0;
- p->app_sleep_cond = 1;
- p->group = group;
- p->pending = pending;
- p->inherited_devicestate = -1;
- AST_LIST_INSERT_TAIL(&agents, p, list);
- }
-
- ast_copy_string(p->password, password ? password : "", sizeof(p->password));
- ast_copy_string(p->name, name ? name : "", sizeof(p->name));
- ast_copy_string(p->moh, moh, sizeof(p->moh));
- p->ackcall = ackcall;
- p->autologoff = autologoff;
-
- /* If someone reduces the wrapuptime and reloads, we want it
- * to change the wrapuptime immediately on all calls */
- if (p->wrapuptime > wrapuptime) {
- struct timeval now = ast_tvnow();
- /* XXX check what is this exactly */
-
- /* We won't be pedantic and check the tv_usec val */
- if (p->lastdisc.tv_sec > (now.tv_sec + wrapuptime/1000)) {
- p->lastdisc.tv_sec = now.tv_sec + wrapuptime/1000;
- p->lastdisc.tv_usec = now.tv_usec;
- }
- }
- p->wrapuptime = wrapuptime;
-
- if (pending)
- p->dead = 1;
- else
- p->dead = 0;
- return p;
-}
-
-/*!
- * Deletes an agent after doing some clean up.
- * Further documentation: How safe is this function ? What state should the agent be to be cleaned.
- * \param p Agent to be deleted.
- * \returns Always 0.
- */
-static int agent_cleanup(struct agent_pvt *p)
-{
- struct ast_channel *chan = p->owner;
- p->owner = NULL;
- chan->tech_pvt = NULL;
- p->app_sleep_cond = 1;
- /* Release ownership of the agent to other threads (presumably running the login app). */
- p->app_lock_flag = 0;
- ast_cond_signal(&p->app_complete_cond);
- if (chan)
- ast_channel_free(chan);
- if (p->dead) {
- ast_mutex_destroy(&p->lock);
- ast_mutex_destroy(&p->app_lock);
- ast_cond_destroy(&p->app_complete_cond);
- free(p);
- }
- return 0;
-}
-
-static int check_availability(struct agent_pvt *newlyavailable, int needlock);
-
-static int agent_answer(struct ast_channel *ast)
-{
- ast_log(LOG_WARNING, "Huh? Agent is being asked to answer?\n");
- return -1;
-}
-
-static int __agent_start_monitoring(struct ast_channel *ast, struct agent_pvt *p, int needlock)
-{
- char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer;
- char filename[AST_MAX_BUF];
- int res = -1;
- if (!p)
- return -1;
- if (!ast->monitor) {
- snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast->uniqueid);
- /* substitute . for - */
- if ((pointer = strchr(filename, '.')))
- *pointer = '-';
- snprintf(tmp, sizeof(tmp), "%s%s", savecallsin, filename);
- ast_monitor_start(ast, recordformat, tmp, needlock);
- ast_monitor_setjoinfiles(ast, 1);
- snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix, filename, recordformatext);
-#if 0
- ast_verbose("name is %s, link is %s\n",tmp, tmp2);
-#endif
- if (!ast->cdr)
- ast->cdr = ast_cdr_alloc();
- ast_cdr_setuserfield(ast, tmp2);
- res = 0;
- } else
- ast_log(LOG_ERROR, "Recording already started on that call.\n");
- return res;
-}
-
-static int agent_start_monitoring(struct ast_channel *ast, int needlock)
-{
- return __agent_start_monitoring(ast, ast->tech_pvt, needlock);
-}
-
-static struct ast_frame *agent_read(struct ast_channel *ast)
-{
- struct agent_pvt *p = ast->tech_pvt;
- struct ast_frame *f = NULL;
- static struct ast_frame answer_frame = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
- const char *status;
- ast_mutex_lock(&p->lock);
- CHECK_FORMATS(ast, p);
- if (p->chan) {
- ast_copy_flags(p->chan, ast, AST_FLAG_EXCEPTION);
- p->chan->fdno = (ast->fdno == AST_AGENT_FD) ? AST_TIMING_FD : ast->fdno;
- f = ast_read(p->chan);
- } else
- f = &ast_null_frame;
- if (!f) {
- /* If there's a channel, hang it up (if it's on a callback) make it NULL */
- if (p->chan) {
- p->chan->_bridge = NULL;
- /* Note that we don't hangup if it's not a callback because Asterisk will do it
- for us when the PBX instance that called login finishes */
- if (!ast_strlen_zero(p->loginchan)) {
- if (p->chan)
- ast_log(LOG_DEBUG, "Bridge on '%s' being cleared (2)\n", p->chan->name);
- if (p->owner->_state != AST_STATE_UP) {
- int howlong = time(NULL) - p->start;
- if (p->autologoff && howlong > p->autologoff) {
- long logintime = time(NULL) - p->loginstart;
- p->loginstart = 0;
- ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
- agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Autologoff");
- if (persistent_agents)
- dump_agents();
- }
- }
- status = pbx_builtin_getvar_helper(p->chan, "CHANLOCALSTATUS");
- if (autologoffunavail && status && !strcasecmp(status, "CHANUNAVAIL")) {
- long logintime = time(NULL) - p->loginstart;
- p->loginstart = 0;
- ast_log(LOG_NOTICE, "Agent read: '%s' is not available now, auto logoff\n", p->name);
- agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Chanunavail");
- }
- ast_hangup(p->chan);
- if (p->wrapuptime && p->acknowledged)
- p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
- }
- p->chan = NULL;
- p->inherited_devicestate = -1;
- ast_device_state_changed("Agent/%s", p->agent);
- p->acknowledged = 0;
- }
- } else {
- /* if acknowledgement is not required, and the channel is up, we may have missed
- an AST_CONTROL_ANSWER (if there was one), so mark the call acknowledged anyway */
- if (!p->ackcall && !p->acknowledged && p->chan && (p->chan->_state == AST_STATE_UP))
- p->acknowledged = 1;
- switch (f->frametype) {
- case AST_FRAME_CONTROL:
- if (f->subclass == AST_CONTROL_ANSWER) {
- if (p->ackcall) {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "%s answered, waiting for '#' to acknowledge\n", p->chan->name);
- /* Don't pass answer along */
- ast_frfree(f);
- f = &ast_null_frame;
- } else {
- p->acknowledged = 1;
- /* Use the builtin answer frame for the
- recording start check below. */
- ast_frfree(f);
- f = &answer_frame;
- }
- }
- break;
- case AST_FRAME_DTMF_BEGIN:
- /*ignore DTMF begin's as it can cause issues with queue announce files*/
- if((!p->acknowledged && f->subclass == '#') || (f->subclass == '*' && endcall)){
- ast_frfree(f);
- f = &ast_null_frame;
- }
- break;
- case AST_FRAME_DTMF_END:
- if (!p->acknowledged && (f->subclass == '#')) {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "%s acknowledged\n", p->chan->name);
- p->acknowledged = 1;
- ast_frfree(f);
- f = &answer_frame;
- } else if (f->subclass == '*' && endcall) {
- /* terminates call */
- ast_frfree(f);
- f = NULL;
- }
- break;
- case AST_FRAME_VOICE:
- case AST_FRAME_VIDEO:
- /* don't pass voice or video until the call is acknowledged */
- if (!p->acknowledged) {
- ast_frfree(f);
- f = &ast_null_frame;
- }
- default:
- /* pass everything else on through */
- break;
- }
- }
-
- CLEANUP(ast,p);
- if (p->chan && !p->chan->_bridge) {
- if (strcasecmp(p->chan->tech->type, "Local")) {
- p->chan->_bridge = ast;
- if (p->chan)
- ast_log(LOG_DEBUG, "Bridge on '%s' being set to '%s' (3)\n", p->chan->name, p->chan->_bridge->name);
- }
- }
- ast_mutex_unlock(&p->lock);
- if (recordagentcalls && f == &answer_frame)
- agent_start_monitoring(ast,0);
- return f;
-}
-
-static int agent_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
-{
- struct agent_pvt *p = ast->tech_pvt;
- int res = -1;
- ast_mutex_lock(&p->lock);
- if (p->chan)
- res = ast_channel_sendhtml(p->chan, subclass, data, datalen);
- ast_mutex_unlock(&p->lock);
- return res;
-}
-
-static int agent_sendtext(struct ast_channel *ast, const char *text)
-{
- struct agent_pvt *p = ast->tech_pvt;
- int res = -1;
- ast_mutex_lock(&p->lock);
- if (p->chan)
- res = ast_sendtext(p->chan, text);
- ast_mutex_unlock(&p->lock);
- return res;
-}
-
-static int agent_write(struct ast_channel *ast, struct ast_frame *f)
-{
- struct agent_pvt *p = ast->tech_pvt;
- int res = -1;
- CHECK_FORMATS(ast, p);
- ast_mutex_lock(&p->lock);
- if (!p->chan)
- res = 0;
- else {
- if ((f->frametype != AST_FRAME_VOICE) ||
- (f->frametype != AST_FRAME_VIDEO) ||
- (f->subclass == p->chan->writeformat)) {
- res = ast_write(p->chan, f);
- } else {
- ast_log(LOG_DEBUG, "Dropping one incompatible %s frame on '%s' to '%s'\n",
- f->frametype == AST_FRAME_VOICE ? "audio" : "video",
- ast->name, p->chan->name);
- res = 0;
- }
- }
- CLEANUP(ast, p);
- ast_mutex_unlock(&p->lock);
- return res;
-}
-
-static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
-{
- struct agent_pvt *p = newchan->tech_pvt;
- ast_mutex_lock(&p->lock);
- if (p->owner != oldchan) {
- ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
- ast_mutex_unlock(&p->lock);
- return -1;
- }
- p->owner = newchan;
- ast_mutex_unlock(&p->lock);
- return 0;
-}
-
-static int agent_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
-{
- struct agent_pvt *p = ast->tech_pvt;
- int res = -1;
- ast_mutex_lock(&p->lock);
- if (p->chan && !ast_check_hangup(p->chan)) {
- while (ast_channel_trylock(p->chan)) {
- ast_channel_unlock(ast);
- usleep(1);
- ast_channel_lock(ast);
- }
- res = p->chan->tech->indicate ? p->chan->tech->indicate(p->chan, condition, data, datalen) : -1;
- ast_channel_unlock(p->chan);
- } else
- res = 0;
- ast_mutex_unlock(&p->lock);
- return res;
-}
-
-static int agent_digit_begin(struct ast_channel *ast, char digit)
-{
- struct agent_pvt *p = ast->tech_pvt;
- ast_mutex_lock(&p->lock);
- if (p->chan) {
- ast_senddigit_begin(p->chan, digit);
- }
- ast_mutex_unlock(&p->lock);
- return 0;
-}
-
-static int agent_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
-{
- struct agent_pvt *p = ast->tech_pvt;
- ast_mutex_lock(&p->lock);
- if (p->chan) {
- ast_senddigit_end(p->chan, digit, duration);
- }
- ast_mutex_unlock(&p->lock);
- return 0;
-}
-
-static int agent_call(struct ast_channel *ast, char *dest, int timeout)
-{
- struct agent_pvt *p = ast->tech_pvt;
- int res = -1;
- int newstate=0;
- ast_mutex_lock(&p->lock);
- p->acknowledged = 0;
- if (!p->chan) {
- if (p->pending) {
- ast_log(LOG_DEBUG, "Pretending to dial on pending agent\n");
- newstate = AST_STATE_DIALING;
- res = 0;
- } else {
- ast_log(LOG_NOTICE, "Whoa, they hung up between alloc and call... what are the odds of that?\n");
- res = -1;
- }
- ast_mutex_unlock(&p->lock);
- if (newstate)
- ast_setstate(ast, newstate);
- return res;
- } else if (!ast_strlen_zero(p->loginchan)) {
- time(&p->start);
- /* Call on this agent */
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "outgoing agentcall, to agent '%s', on '%s'\n", p->agent, p->chan->name);
- ast_set_callerid(p->chan,
- ast->cid.cid_num, ast->cid.cid_name, NULL);
- ast_channel_inherit_variables(ast, p->chan);
- res = ast_call(p->chan, p->loginchan, 0);
- CLEANUP(ast,p);
- ast_mutex_unlock(&p->lock);
- return res;
- }
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name);
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Playing beep, lang '%s'\n", p->chan->language);
- res = ast_streamfile(p->chan, beep, p->chan->language);
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Played beep, result '%d'\n", res);
- if (!res) {
- res = ast_waitstream(p->chan, "");
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Waited for stream, result '%d'\n", res);
- }
- if (!res) {
- res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats));
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Set read format, result '%d'\n", res);
- if (res)
- ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
- } else {
- /* Agent hung-up */
- p->chan = NULL;
- p->inherited_devicestate = -1;
- ast_device_state_changed("Agent/%s", p->agent);
- }
-
- if (!res) {
- res = ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats));
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Set write format, result '%d'\n", res);
- if (res)
- ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
- }
- if(!res) {
- /* Call is immediately up, or might need ack */
- if (p->ackcall > 1)
- newstate = AST_STATE_RINGING;
- else {
- newstate = AST_STATE_UP;
- if (recordagentcalls)
- agent_start_monitoring(ast, 0);
- p->acknowledged = 1;
- }
- res = 0;
- }
- CLEANUP(ast, p);
- ast_mutex_unlock(&p->lock);
- if (newstate)
- ast_setstate(ast, newstate);
- return res;
-}
-
-/*! \brief store/clear the global variable that stores agentid based on the callerid */
-static void set_agentbycallerid(const char *callerid, const char *agent)
-{
- char buf[AST_MAX_BUF];
-
- /* if there is no Caller ID, nothing to do */
- if (ast_strlen_zero(callerid))
- return;
-
- snprintf(buf, sizeof(buf), "%s_%s", GETAGENTBYCALLERID, callerid);
- pbx_builtin_setvar_helper(NULL, buf, agent);
-}
-
-/*! \brief return the channel or base channel if one exists. This function assumes the channel it is called on is already locked */
-struct ast_channel* agent_get_base_channel(struct ast_channel *chan)
-{
- struct agent_pvt *p = NULL;
- struct ast_channel *base = chan;
-
- /* chan is locked by the calling function */
- if (!chan || !chan->tech_pvt) {
- ast_log(LOG_ERROR, "whoa, you need a channel (0x%ld) with a tech_pvt (0x%ld) to get a base channel.\n", (long)chan, (chan)?(long)chan->tech_pvt:(long)NULL);
- return NULL;
- }
- p = chan->tech_pvt;
- if (p->chan)
- base = p->chan;
- return base;
-}
-
-int agent_set_base_channel(struct ast_channel *chan, struct ast_channel *base)
-{
- struct agent_pvt *p = NULL;
-
- if (!chan || !base) {
- ast_log(LOG_ERROR, "whoa, you need a channel (0x%ld) and a base channel (0x%ld) for setting.\n", (long)chan, (long)base);
- return -1;
- }
- p = chan->tech_pvt;
- if (!p) {
- ast_log(LOG_ERROR, "whoa, channel %s is missing his tech_pvt structure!!.\n", chan->name);
- return -1;
- }
- p->chan = base;
- return 0;
-}
-
-static int agent_hangup(struct ast_channel *ast)
-{
- struct agent_pvt *p = ast->tech_pvt;
- int howlong = 0;
- const char *status;
- ast_mutex_lock(&p->lock);
- p->owner = NULL;
- ast->tech_pvt = NULL;
- p->app_sleep_cond = 1;
- p->acknowledged = 0;
-
- /* if they really are hung up then set start to 0 so the test
- * later if we're called on an already downed channel
- * doesn't cause an agent to be logged out like when
- * agent_request() is followed immediately by agent_hangup()
- * as in apps/app_chanisavail.c:chanavail_exec()
- */
-
- if (option_debug)
- ast_log(LOG_DEBUG, "Hangup called for state %s\n", ast_state2str(ast->_state));
- if (p->start && (ast->_state != AST_STATE_UP)) {
- howlong = time(NULL) - p->start;
- p->start = 0;
- } else if (ast->_state == AST_STATE_RESERVED)
- howlong = 0;
- else
- p->start = 0;
- if (p->chan) {
- p->chan->_bridge = NULL;
- /* If they're dead, go ahead and hang up on the agent now */
- if (!ast_strlen_zero(p->loginchan)) {
- /* Store last disconnect time */
- if (p->wrapuptime)
- p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
- else
- p->lastdisc = ast_tv(0,0);
- if (p->chan) {
- status = pbx_builtin_getvar_helper(p->chan, "CHANLOCALSTATUS");
- if (autologoffunavail && status && !strcasecmp(status, "CHANUNAVAIL")) {
- long logintime = time(NULL) - p->loginstart;
- p->loginstart = 0;
- ast_log(LOG_NOTICE, "Agent hangup: '%s' is not available now, auto logoff\n", p->name);
- agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Chanunavail");
- }
- /* Recognize the hangup and pass it along immediately */
- ast_hangup(p->chan);
- p->chan = NULL;
- p->inherited_devicestate = -1;
- ast_device_state_changed("Agent/%s", p->agent);
- }
- ast_log(LOG_DEBUG, "Hungup, howlong is %d, autologoff is %d\n", howlong, p->autologoff);
- if ((p->deferlogoff) || (howlong && p->autologoff && (howlong > p->autologoff))) {
- long logintime = time(NULL) - p->loginstart;
- p->loginstart = 0;
- if (!p->deferlogoff)
- ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
- p->deferlogoff = 0;
- agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Autologoff");
- if (persistent_agents)
- dump_agents();
- }
- } else if (p->dead) {
- ast_channel_lock(p->chan);
- ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
- ast_channel_unlock(p->chan);
- } else if (p->loginstart) {
- ast_channel_lock(p->chan);
- ast_indicate_data(p->chan, AST_CONTROL_HOLD,
- S_OR(p->moh, NULL),
- !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0);
- ast_channel_unlock(p->chan);
- }
- }
- ast_mutex_unlock(&p->lock);
-
- /* Only register a device state change if the agent is still logged in */
- if (!p->loginstart) {
- p->loginchan[0] = '\0';
- p->logincallerid[0] = '\0';
- if (persistent_agents)
- dump_agents();
- } else {
- ast_device_state_changed("Agent/%s", p->agent);
- }
-
- if (p->pending) {
- AST_LIST_LOCK(&agents);
- AST_LIST_REMOVE(&agents, p, list);
- AST_LIST_UNLOCK(&agents);
- }
- if (p->abouttograb) {
- /* Let the "about to grab" thread know this isn't valid anymore, and let it
- kill it later */
- p->abouttograb = 0;
- } else if (p->dead) {
- ast_mutex_destroy(&p->lock);
- ast_mutex_destroy(&p->app_lock);
- ast_cond_destroy(&p->app_complete_cond);
- free(p);
- } else {
- if (p->chan) {
- /* Not dead -- check availability now */
- ast_mutex_lock(&p->lock);
- /* Store last disconnect time */
- p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
- ast_mutex_unlock(&p->lock);
- }
- /* Release ownership of the agent to other threads (presumably running the login app). */
- if (ast_strlen_zero(p->loginchan)) {
- p->app_lock_flag = 0;
- ast_cond_signal(&p->app_complete_cond);
- }
- }
- return 0;
-}
-
-static int agent_cont_sleep( void *data )
-{
- struct agent_pvt *p;
- int res;
-
- p = (struct agent_pvt *)data;
-
- ast_mutex_lock(&p->lock);
- res = p->app_sleep_cond;
- if (p->lastdisc.tv_sec) {
- if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0)
- res = 1;
- }
- ast_mutex_unlock(&p->lock);
-
- if(option_debug > 4 && !res )
- ast_log(LOG_DEBUG, "agent_cont_sleep() returning %d\n", res );
-
- return res;
-}
-
-static int agent_ack_sleep(void *data)
-{
- struct agent_pvt *p;
- int res=0;
- int to = 1000;
- struct ast_frame *f;
-
- /* Wait a second and look for something */
-
- p = (struct agent_pvt *) data;
- if (!p->chan)
- return -1;
-
- for(;;) {
- to = ast_waitfor(p->chan, to);
- if (to < 0)
- return -1;
- if (!to)
- return 0;
- f = ast_read(p->chan);
- if (!f)
- return -1;
- if (f->frametype == AST_FRAME_DTMF)
- res = f->subclass;
- else
- res = 0;
- ast_frfree(f);
- ast_mutex_lock(&p->lock);
- if (!p->app_sleep_cond) {
- ast_mutex_unlock(&p->lock);
- return 0;
- } else if (res == '#') {
- ast_mutex_unlock(&p->lock);
- return 1;
- }
- ast_mutex_unlock(&p->lock);
- res = 0;
- }
- return res;
-}
-
-static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge)
-{
- struct agent_pvt *p = bridge->tech_pvt;
- struct ast_channel *ret = NULL;
-
- if (p) {
- if (chan == p->chan)
- ret = bridge->_bridge;
- else if (chan == bridge->_bridge)
- ret = p->chan;
- }
-
- if (option_debug)
- ast_log(LOG_DEBUG, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", chan->name, bridge->name, ret ? ret->name : "<none>");
- return ret;
-}
-
-/*! \brief Create new agent channel */
-static struct ast_channel *agent_new(struct agent_pvt *p, int state)
-{
- struct ast_channel *tmp;
- int alreadylocked;
-#if 0
- if (!p->chan) {
- ast_log(LOG_WARNING, "No channel? :(\n");
- return NULL;
- }
-#endif
- if (p->pending)
- tmp = ast_channel_alloc(0, state, 0, 0, "", p->chan ? p->chan->exten:"", p->chan ? p->chan->context:"", 0, "Agent/P%s-%d", p->agent, (int) ast_random() & 0xffff);
- else
- tmp = ast_channel_alloc(0, state, 0, 0, "", p->chan ? p->chan->exten:"", p->chan ? p->chan->context:"", 0, "Agent/%s", p->agent);
- if (!tmp) {
- ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n");
- return NULL;
- }
-
- tmp->tech = &agent_tech;
- if (p->chan) {
- tmp->nativeformats = p->chan->nativeformats;
- tmp->writeformat = p->chan->writeformat;
- tmp->rawwriteformat = p->chan->writeformat;
- tmp->readformat = p->chan->readformat;
- tmp->rawreadformat = p->chan->readformat;
- ast_string_field_set(tmp, language, p->chan->language);
- ast_copy_string(tmp->context, p->chan->context, sizeof(tmp->context));
- ast_copy_string(tmp->exten, p->chan->exten, sizeof(tmp->exten));
- /* XXX Is this really all we copy form the originating channel?? */
- } else {
- tmp->nativeformats = AST_FORMAT_SLINEAR;
- tmp->writeformat = AST_FORMAT_SLINEAR;
- tmp->rawwriteformat = AST_FORMAT_SLINEAR;
- tmp->readformat = AST_FORMAT_SLINEAR;
- tmp->rawreadformat = AST_FORMAT_SLINEAR;
- }
- /* Safe, agentlock already held */
- tmp->tech_pvt = p;
- p->owner = tmp;
- /* XXX: this needs fixing */
-#if 0
- ast_atomic_fetchadd_int(&__mod_desc->usecnt, +1);
-#endif
- ast_update_use_count();
- tmp->priority = 1;
- /* Wake up and wait for other applications (by definition the login app)
- * to release this channel). Takes ownership of the agent channel
- * to this thread only.
- * For signalling the other thread, ast_queue_frame is used until we
- * can safely use signals for this purpose. The pselect() needs to be
- * implemented in the kernel for this.
- */
- p->app_sleep_cond = 0;
-
- alreadylocked = p->app_lock_flag;
- p->app_lock_flag = 1;
-
- if(ast_strlen_zero(p->loginchan) && alreadylocked) {
- if (p->chan) {
- ast_queue_frame(p->chan, &ast_null_frame);
- ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */
- p->app_lock_flag = 1;
- ast_mutex_lock(&p->lock);
- } else {
- ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
- p->owner = NULL;
- tmp->tech_pvt = NULL;
- p->app_sleep_cond = 1;
- ast_channel_free( tmp );
- ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */
- p->app_lock_flag = 0;
- ast_cond_signal(&p->app_complete_cond);
- return NULL;
- }
- } else if (!ast_strlen_zero(p->loginchan)) {
- if (p->chan)
- ast_queue_frame(p->chan, &ast_null_frame);
- if (!p->chan) {
- ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
- p->owner = NULL;
- tmp->tech_pvt = NULL;
- p->app_sleep_cond = 1;
- ast_channel_free( tmp );
- ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */
- return NULL;
- }
- }
- if (p->chan)
- ast_indicate(p->chan, AST_CONTROL_UNHOLD);
- return tmp;
-}
-
-
-/*!
- * Read configuration data. The file named agents.conf.
- *
- * \returns Always 0, or so it seems.
- */
-static int read_agent_config(void)
-{
- struct ast_config *cfg;
- struct ast_config *ucfg;
- struct ast_variable *v;
- struct agent_pvt *p;
- const char *general_val;
- const char *catname;
- const char *hasagent;
- int genhasagent;
-
- group = 0;
- autologoff = 0;
- wrapuptime = 0;
- ackcall = 0;
- endcall = 1;
- cfg = ast_config_load(config);
- if (!cfg) {
- ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n");
- return 0;
- }
- AST_LIST_LOCK(&agents);
- AST_LIST_TRAVERSE(&agents, p, list) {
- p->dead = 1;
- }
- strcpy(moh, "default");
- /* set the default recording values */
- recordagentcalls = 0;
- strcpy(recordformat, "wav");
- strcpy(recordformatext, "wav");
- urlprefix[0] = '\0';
- savecallsin[0] = '\0';
-
- /* Read in [general] section for persistence */
- if ((general_val = ast_variable_retrieve(cfg, "general", "persistentagents")))
- persistent_agents = ast_true(general_val);
- multiplelogin = ast_true(ast_variable_retrieve(cfg, "general", "multiplelogin"));
-
- /* Read in the [agents] section */
- v = ast_variable_browse(cfg, "agents");
- while(v) {
- /* Create the interface list */
- if (!strcasecmp(v->name, "agent")) {
- add_agent(v->value, 0);
- } else if (!strcasecmp(v->name, "group")) {
- group = ast_get_group(v->value);
- } else if (!strcasecmp(v->name, "autologoff")) {
- autologoff = atoi(v->value);
- if (autologoff < 0)
- autologoff = 0;
- } else if (!strcasecmp(v->name, "ackcall")) {
- if (!strcasecmp(v->value, "always"))
- ackcall = 2;
- else if (ast_true(v->value))
- ackcall = 1;
- else
- ackcall = 0;
- } else if (!strcasecmp(v->name, "endcall")) {
- endcall = ast_true(v->value);
- } else if (!strcasecmp(v->name, "wrapuptime")) {
- wrapuptime = atoi(v->value);
- if (wrapuptime < 0)
- wrapuptime = 0;
- } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) {
- maxlogintries = atoi(v->value);
- if (maxlogintries < 0)
- maxlogintries = 0;
- } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) {
- strcpy(agentgoodbye,v->value);
- } else if (!strcasecmp(v->name, "musiconhold")) {
- ast_copy_string(moh, v->value, sizeof(moh));
- } else if (!strcasecmp(v->name, "updatecdr")) {
- if (ast_true(v->value))
- updatecdr = 1;
- else
- updatecdr = 0;
- } else if (!strcasecmp(v->name, "autologoffunavail")) {
- if (ast_true(v->value))
- autologoffunavail = 1;
- else
- autologoffunavail = 0;
- } else if (!strcasecmp(v->name, "recordagentcalls")) {
- recordagentcalls = ast_true(v->value);
- } else if (!strcasecmp(v->name, "recordformat")) {
- ast_copy_string(recordformat, v->value, sizeof(recordformat));
- if (!strcasecmp(v->value, "wav49"))
- strcpy(recordformatext, "WAV");
- else
- ast_copy_string(recordformatext, v->value, sizeof(recordformatext));
- } else if (!strcasecmp(v->name, "urlprefix")) {
- ast_copy_string(urlprefix, v->value, sizeof(urlprefix));
- if (urlprefix[strlen(urlprefix) - 1] != '/')
- strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1);
- } else if (!strcasecmp(v->name, "savecallsin")) {
- if (v->value[0] == '/')
- ast_copy_string(savecallsin, v->value, sizeof(savecallsin));
- else
- snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value);
- if (savecallsin[strlen(savecallsin) - 1] != '/')
- strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1);
- } else if (!strcasecmp(v->name, "custom_beep")) {
- ast_copy_string(beep, v->value, sizeof(beep));
- }
- v = v->next;
- }
- if ((ucfg = ast_config_load("users.conf"))) {
- genhasagent = ast_true(ast_variable_retrieve(ucfg, "general", "hasagent"));
- catname = ast_category_browse(ucfg, NULL);
- while(catname) {
- if (strcasecmp(catname, "general")) {
- hasagent = ast_variable_retrieve(ucfg, catname, "hasagent");
- if (ast_true(hasagent) || (!hasagent && genhasagent)) {
- char tmp[256];
- const char *fullname = ast_variable_retrieve(ucfg, catname, "fullname");
- const char *secret = ast_variable_retrieve(ucfg, catname, "secret");
- if (!fullname)
- fullname = "";
- if (!secret)
- secret = "";
- snprintf(tmp, sizeof(tmp), "%s,%s,%s", catname, secret,fullname);
- add_agent(tmp, 0);
- }
- }
- catname = ast_category_browse(ucfg, catname);
- }
- ast_config_destroy(ucfg);
- }
- AST_LIST_TRAVERSE_SAFE_BEGIN(&agents, p, list) {
- if (p->dead) {
- AST_LIST_REMOVE_CURRENT(&agents, list);
- /* Destroy if appropriate */
- if (!p->owner) {
- if (!p->chan) {
- ast_mutex_destroy(&p->lock);
- ast_mutex_destroy(&p->app_lock);
- ast_cond_destroy(&p->app_complete_cond);
- free(p);
- } else {
- /* Cause them to hang up */
- ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
- }
- }
- }
- }
- AST_LIST_TRAVERSE_SAFE_END
- AST_LIST_UNLOCK(&agents);
- ast_config_destroy(cfg);
- return 1;
-}
-
-static int check_availability(struct agent_pvt *newlyavailable, int needlock)
-{
- struct ast_channel *chan=NULL, *parent=NULL;
- struct agent_pvt *p;
- int res;
-
- if (option_debug)
- ast_log(LOG_DEBUG, "Checking availability of '%s'\n", newlyavailable->agent);
- if (needlock)
- AST_LIST_LOCK(&agents);
- AST_LIST_TRAVERSE(&agents, p, list) {
- if (p == newlyavailable) {
- continue;
- }
- ast_mutex_lock(&p->lock);
- if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
- /* We found a pending call, time to merge */
- chan = agent_new(newlyavailable, AST_STATE_DOWN);
- parent = p->owner;
- p->abouttograb = 1;
- ast_mutex_unlock(&p->lock);
- break;
- }
- ast_mutex_unlock(&p->lock);
- }
- if (needlock)
- AST_LIST_UNLOCK(&agents);
- if (parent && chan) {
- if (newlyavailable->ackcall > 1) {
- /* Don't do beep here */
- res = 0;
- } else {
- if (option_debug > 2)
- ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
- res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
- if (option_debug > 2)
- ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
- if (!res) {
- res = ast_waitstream(newlyavailable->chan, "");
- ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
- }
- }
- if (!res) {
- /* Note -- parent may have disappeared */
- if (p->abouttograb) {
- newlyavailable->acknowledged = 1;
- /* Safe -- agent lock already held */
- ast_setstate(parent, AST_STATE_UP);
- ast_setstate(chan, AST_STATE_UP);
- ast_copy_string(parent->context, chan->context, sizeof(parent->context));
- /* Go ahead and mark the channel as a zombie so that masquerade will
- destroy it for us, and we need not call ast_hangup */
- ast_mutex_lock(&parent->lock);
- ast_set_flag(chan, AST_FLAG_ZOMBIE);
- ast_channel_masquerade(parent, chan);
- ast_mutex_unlock(&parent->lock);
- p->abouttograb = 0;
- } else {
- if (option_debug)
- ast_log(LOG_DEBUG, "Sneaky, parent disappeared in the mean time...\n");
- agent_cleanup(newlyavailable);
- }
- } else {
- if (option_debug)
- ast_log(LOG_DEBUG, "Ugh... Agent hung up at exactly the wrong time\n");
- agent_cleanup(newlyavailable);
- }
- }
- return 0;
-}
-
-static int check_beep(struct agent_pvt *newlyavailable, int needlock)
-{
- struct agent_pvt *p;
- int res=0;
-
- ast_log(LOG_DEBUG, "Checking beep availability of '%s'\n", newlyavailable->agent);
- if (needlock)
- AST_LIST_LOCK(&agents);
- AST_LIST_TRAVERSE(&agents, p, list) {
- if (p == newlyavailable) {
- continue;
- }
- ast_mutex_lock(&p->lock);
- if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
- ast_mutex_unlock(&p->lock);
- break;
- }
- ast_mutex_unlock(&p->lock);
- }
- if (needlock)
- AST_LIST_UNLOCK(&agents);
- if (p) {
- ast_mutex_unlock(&newlyavailable->lock);
- if (option_debug > 2)
- ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
- res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
- if (option_debug > 2)
- ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
- if (!res) {
- res = ast_waitstream(newlyavailable->chan, "");
- if (option_debug)
- ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
- }
- ast_mutex_lock(&newlyavailable->lock);
- }
- return res;
-}
-
-/* return 1 if multiple login is fine, 0 if it is not and we find a match, -1 if multiplelogin is not allowed and we don't find a match. */
-static int allow_multiple_login(char *chan, char *context)
-{
- struct agent_pvt *p;
- char loginchan[80];
-
- if (multiplelogin) {
- return 1;
- }
- if (!chan) {
- return 0;
- }
-
- snprintf(loginchan, sizeof(loginchan), "%s@%s", chan, S_OR(context, "default"));
-
- AST_LIST_TRAVERSE(&agents, p, list) {
- if(!strcasecmp(loginchan, p->loginchan))
- return 0;
- }
- return -1;
-}
-
-/*! \brief Part of the Asterisk PBX interface */
-static struct ast_channel *agent_request(const char *type, int format, void *data, int *cause)
-{
- struct agent_pvt *p;
- struct ast_channel *chan = NULL;
- char *s;
- ast_group_t groupmatch;
- int groupoff;
- int waitforagent=0;
- int hasagent = 0;
- struct timeval tv;
-
- s = data;
- if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
- groupmatch = (1 << groupoff);
- } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
- groupmatch = (1 << groupoff);
- waitforagent = 1;
- } else
- groupmatch = 0;
-
- /* Check actual logged in agents first */
- AST_LIST_LOCK(&agents);
- AST_LIST_TRAVERSE(&agents, p, list) {
- ast_mutex_lock(&p->lock);
- if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent)) &&
- ast_strlen_zero(p->loginchan)) {
- if (p->chan)
- hasagent++;
- tv = ast_tvnow();
- if (!p->lastdisc.tv_sec || (tv.tv_sec >= p->lastdisc.tv_sec)) {
- p->lastdisc = ast_tv(0, 0);
- /* Agent must be registered, but not have any active call, and not be in a waiting state */
- if (!p->owner && p->chan) {
- /* Fixed agent */
- chan = agent_new(p, AST_STATE_DOWN);
- }
- if (chan) {
- ast_mutex_unlock(&p->lock);
- break;
- }
- }
- }
- ast_mutex_unlock(&p->lock);
- }
- if (!p) {
- AST_LIST_TRAVERSE(&agents, p, list) {
- ast_mutex_lock(&p->lock);
- if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
- if (p->chan || !ast_strlen_zero(p->loginchan))
- hasagent++;
- tv = ast_tvnow();
-#if 0
- ast_log(LOG_NOTICE, "Time now: %ld, Time of lastdisc: %ld\n", tv.tv_sec, p->lastdisc.tv_sec);
-#endif
- if (!p->lastdisc.tv_sec || (tv.tv_sec >= p->lastdisc.tv_sec)) {
- p->lastdisc = ast_tv(0, 0);
- /* Agent must be registered, but not have any active call, and not be in a waiting state */
- if (!p->owner && p->chan) {
- /* Could still get a fixed agent */
- chan = agent_new(p, AST_STATE_DOWN);
- } else if (!p->owner && !ast_strlen_zero(p->loginchan)) {
- /* Adjustable agent */
- p->chan = ast_request("Local", format, p->loginchan, cause);
- if (p->chan)
- chan = agent_new(p, AST_STATE_DOWN);
- }
- if (chan) {
- ast_mutex_unlock(&p->lock);
- break;
- }
- }
- }
- ast_mutex_unlock(&p->lock);
- }
- }
-
- if (!chan && waitforagent) {
- /* No agent available -- but we're requesting to wait for one.
- Allocate a place holder */
- if (hasagent) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Creating place holder for '%s'\n", s);
- p = add_agent(data, 1);
- p->group = groupmatch;
- chan = agent_new(p, AST_STATE_DOWN);
- if (!chan)
- ast_log(LOG_WARNING, "Weird... Fix this to drop the unused pending agent\n");
- } else
- ast_log(LOG_DEBUG, "Not creating place holder for '%s' since nobody logged in\n", s);
- }
- *cause = hasagent ? AST_CAUSE_BUSY : AST_CAUSE_UNREGISTERED;
- AST_LIST_UNLOCK(&agents);
- return chan;
-}
-
-static force_inline int powerof(unsigned int d)
-{
- int x = ffs(d);
-
- if (x)
- return x - 1;
-
- return 0;
-}
-
-/*!
- * Lists agents and their status to the Manager API.
- * It is registered on load_module() and it gets called by the manager backend.
- * \param s
- * \param m
- * \returns
- * \sa action_agent_logoff(), action_agent_callback_login(), load_module().
- */
-static int action_agents(struct mansession *s, const struct message *m)
-{
- const char *id = astman_get_header(m,"ActionID");
- char idText[256] = "";
- char chanbuf[256];
- struct agent_pvt *p;
- char *username = NULL;
- char *loginChan = NULL;
- char *talkingtoChan = NULL;
- char *status = NULL;
-
- if (!ast_strlen_zero(id))
- snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id);
- astman_send_ack(s, m, "Agents will follow");
- AST_LIST_LOCK(&agents);
- AST_LIST_TRAVERSE(&agents, p, list) {
- ast_mutex_lock(&p->lock);
-
- /* Status Values:
- AGENT_LOGGEDOFF - Agent isn't logged in
- AGENT_IDLE - Agent is logged in, and waiting for call
- AGENT_ONCALL - Agent is logged in, and on a call
- AGENT_UNKNOWN - Don't know anything about agent. Shouldn't ever get this. */
-
- username = S_OR(p->name, "None");
-
- /* Set a default status. It 'should' get changed. */
- status = "AGENT_UNKNOWN";
-
- if (!ast_strlen_zero(p->loginchan) && !p->chan) {
- loginChan = p->loginchan;
- talkingtoChan = "n/a";
- status = "AGENT_IDLE";
- if (p->acknowledged) {
- snprintf(chanbuf, sizeof(chanbuf), " %s (Confirmed)", p->loginchan);
- loginChan = chanbuf;
- }
- } else if (p->chan) {
- loginChan = ast_strdupa(p->chan->name);
- if (p->owner && p->owner->_bridge) {
- if (ast_bridged_channel(p->owner)) {
- talkingtoChan = ast_strdupa(S_OR(ast_bridged_channel(p->owner)->cid.cid_num, ""));
- } else {
- talkingtoChan = "n/a";
- }
- status = "AGENT_ONCALL";
- } else {
- talkingtoChan = "n/a";
- status = "AGENT_IDLE";
- }
- } else {
- loginChan = "n/a";
- talkingtoChan = "n/a";
- status = "AGENT_LOGGEDOFF";
- }
-
- astman_append(s, "Event: Agents\r\n"
- "Agent: %s\r\n"
- "Name: %s\r\n"
- "Status: %s\r\n"
- "LoggedInChan: %s\r\n"
- "LoggedInTime: %d\r\n"
- "TalkingTo: %s\r\n"
- "%s"
- "\r\n",
- p->agent, username, status, loginChan, (int)p->loginstart, talkingtoChan, idText);
- ast_mutex_unlock(&p->lock);
- }
- AST_LIST_UNLOCK(&agents);
- astman_append(s, "Event: AgentsComplete\r\n"
- "%s"
- "\r\n",idText);
- return 0;
-}
-
-static void agent_logoff_maintenance(struct agent_pvt *p, char *loginchan, long logintime, const char *uniqueid, char *logcommand)
-{
- char *tmp = NULL;
- char agent[AST_MAX_AGENT];
-
- if (!ast_strlen_zero(logcommand))
- tmp = logcommand;
- else
- tmp = ast_strdupa("");
-
- snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
-
- if (!ast_strlen_zero(uniqueid)) {
- manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
- "Agent: %s\r\n"
- "Reason: %s\r\n"
- "Loginchan: %s\r\n"
- "Logintime: %ld\r\n"
- "Uniqueid: %s\r\n",
- p->agent, tmp, loginchan, logintime, uniqueid);
- } else {
- manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
- "Agent: %s\r\n"
- "Reason: %s\r\n"
- "Loginchan: %s\r\n"
- "Logintime: %ld\r\n",
- p->agent, tmp, loginchan, logintime);
- }
-
- ast_queue_log("NONE", ast_strlen_zero(uniqueid) ? "NONE" : uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", loginchan, logintime, tmp);
- set_agentbycallerid(p->logincallerid, NULL);
- p->loginchan[0] ='\0';
- p->logincallerid[0] = '\0';
- p->inherited_devicestate = -1;
- ast_device_state_changed("Agent/%s", p->agent);
- if (persistent_agents)
- dump_agents();
-
-}
-
-static int agent_logoff(const char *agent, int soft)
-{
- struct agent_pvt *p;
- long logintime;
- int ret = -1; /* Return -1 if no agent if found */
-
- AST_LIST_LOCK(&agents);
- AST_LIST_TRAVERSE(&agents, p, list) {
- if (!strcasecmp(p->agent, agent)) {
- ret = 0;
- if (p->owner || p->chan) {
- if (!soft) {
- ast_mutex_lock(&p->lock);
-
- while (p->owner && ast_channel_trylock(p->owner)) {
- DEADLOCK_AVOIDANCE(&p->lock);
- }
- if (p->owner) {
- ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
- ast_channel_unlock(p->owner);
- }
-
- while (p->chan && ast_channel_trylock(p->chan)) {
- DEADLOCK_AVOIDANCE(&p->lock);
- }
- if (p->chan) {
- ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
- ast_channel_unlock(p->chan);
- }
-
- ast_mutex_unlock(&p->lock);
- } else
- p->deferlogoff = 1;
- } else {
- logintime = time(NULL) - p->loginstart;
- p->loginstart = 0;
- agent_logoff_maintenance(p, p->loginchan, logintime, NULL, "CommandLogoff");
- }
- break;
- }
- }
- AST_LIST_UNLOCK(&agents);
-
- return ret;
-}
-
-static int agent_logoff_cmd(int fd, int argc, char **argv)
-{
- int ret;
- char *agent;
-
- if (argc < 3 || argc > 4)
- return RESULT_SHOWUSAGE;
- if (argc == 4 && strcasecmp(argv[3], "soft"))
- return RESULT_SHOWUSAGE;
-
- agent = argv[2] + 6;
- ret = agent_logoff(agent, argc == 4);
- if (ret == 0)
- ast_cli(fd, "Logging out %s\n", agent);
-
- return RESULT_SUCCESS;
-}
-
-/*!
- * Sets an agent as no longer logged in in the Manager API.
- * It is registered on load_module() and it gets called by the manager backend.
- * \param s
- * \param m
- * \returns
- * \sa action_agents(), action_agent_callback_login(), load_module().
- */
-static int action_agent_logoff(struct mansession *s, const struct message *m)
-{
- const char *agent = astman_get_header(m, "Agent");
- const char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */
- int soft;
- int ret; /* return value of agent_logoff */
-
- if (ast_strlen_zero(agent)) {
- astman_send_error(s, m, "No agent specified");
- return 0;
- }
-
- soft = ast_true(soft_s) ? 1 : 0;
- ret = agent_logoff(agent, soft);
- if (ret == 0)
- astman_send_ack(s, m, "Agent logged out");
- else
- astman_send_error(s, m, "No such agent");
-
- return 0;
-}
-
-static char *complete_agent_logoff_cmd(const char *line, const char *word, int pos, int state)
-{
- char *ret = NULL;
-
- if (pos == 2) {
- struct agent_pvt *p;
- char name[AST_MAX_AGENT];
- int which = 0, len = strlen(word);
-
- AST_LIST_LOCK(&agents);
- AST_LIST_TRAVERSE(&agents, p, list) {
- snprintf(name, sizeof(name), "Agent/%s", p->agent);
- if (!strncasecmp(word, name, len) && ++which > state) {
- ret = ast_strdup(name);
- break;
- }
- }
- AST_LIST_UNLOCK(&agents);
- } else if (pos == 3 && state == 0)
- return ast_strdup("soft");
-
- return ret;
-}
-
-/*!
- * Show agents in cli.
- */
-static int agents_show(int fd, int argc, char **argv)
-{
- struct agent_pvt *p;
- char username[AST_MAX_BUF];
- char location[AST_MAX_BUF] = "";
- char talkingto[AST_MAX_BUF] = "";
- char moh[AST_MAX_BUF];
- int count_agents = 0; /*!< Number of agents configured */
- int online_agents = 0; /*!< Number of online agents */
- int offline_agents = 0; /*!< Number of offline agents */
- if (argc != 2)
- return RESULT_SHOWUSAGE;
- AST_LIST_LOCK(&agents);
- AST_LIST_TRAVERSE(&agents, p, list) {
- ast_mutex_lock(&p->lock);
- if (p->pending) {
- if (p->group)
- ast_cli(fd, "-- Pending call to group %d\n", powerof(p->group));
- else
- ast_cli(fd, "-- Pending call to agent %s\n", p->agent);
- } else {
- if (!ast_strlen_zero(p->name))
- snprintf(username, sizeof(username), "(%s) ", p->name);
- else
- username[0] = '\0';
- if (p->chan) {
- snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
- if (p->owner && ast_bridged_channel(p->owner))
- snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
- else
- strcpy(talkingto, " is idle");
- online_agents++;
- } else if (!ast_strlen_zero(p->loginchan)) {
- if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0 || !(p->lastdisc.tv_sec))
- snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
- else
- snprintf(location, sizeof(location) - 20, "wrapping up at '%s'", p->loginchan);
- talkingto[0] = '\0';
- online_agents++;
- if (p->acknowledged)
- strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
- } else {
- strcpy(location, "not logged in");
- talkingto[0] = '\0';
- offline_agents++;
- }
- if (!ast_strlen_zero(p->moh))
- snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
- ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent,
- username, location, talkingto, moh);
- count_agents++;
- }
- ast_mutex_unlock(&p->lock);
- }
- AST_LIST_UNLOCK(&agents);
- if ( !count_agents )
- ast_cli(fd, "No Agents are configured in %s\n",config);
- else
- ast_cli(fd, "%d agents configured [%d online , %d offline]\n",count_agents, online_agents, offline_agents);
- ast_cli(fd, "\n");
-
- return RESULT_SUCCESS;
-}
-
-
-static int agents_show_online(int fd, int argc, char **argv)
-{
- struct agent_pvt *p;
- char username[AST_MAX_BUF];
- char location[AST_MAX_BUF] = "";
- char talkingto[AST_MAX_BUF] = "";
- char moh[AST_MAX_BUF];
- int count_agents = 0; /* Number of agents configured */
- int online_agents = 0; /* Number of online agents */
- int agent_status = 0; /* 0 means offline, 1 means online */
- if (argc != 3)
- return RESULT_SHOWUSAGE;
- AST_LIST_LOCK(&agents);
- AST_LIST_TRAVERSE(&agents, p, list) {
- agent_status = 0; /* reset it to offline */
- ast_mutex_lock(&p->lock);
- if (!ast_strlen_zero(p->name))
- snprintf(username, sizeof(username), "(%s) ", p->name);
- else
- username[0] = '\0';
- if (p->chan) {
- snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
- if (p->owner && ast_bridged_channel(p->owner))
- snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
- else
- strcpy(talkingto, " is idle");
- agent_status = 1;
- online_agents++;
- } else if (!ast_strlen_zero(p->loginchan)) {
- snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
- talkingto[0] = '\0';
- agent_status = 1;
- online_agents++;
- if (p->acknowledged)
- strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
- }
- if (!ast_strlen_zero(p->moh))
- snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
- if (agent_status)
- ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent, username, location, talkingto, moh);
- count_agents++;
- ast_mutex_unlock(&p->lock);
- }
- AST_LIST_UNLOCK(&agents);
- if (!count_agents)
- ast_cli(fd, "No Agents are configured in %s\n", config);
- else
- ast_cli(fd, "%d agents online\n", online_agents);
- ast_cli(fd, "\n");
- return RESULT_SUCCESS;
-}
-
-
-
-static char show_agents_usage[] =
-"Usage: agent show\n"
-" Provides summary information on agents.\n";
-
-static char show_agents_online_usage[] =
-"Usage: agent show online\n"
-" Provides a list of all online agents.\n";
-
-static char agent_logoff_usage[] =
-"Usage: agent logoff <channel> [soft]\n"
-" Sets an agent as no longer logged in.\n"
-" If 'soft' is specified, do not hangup existing calls.\n";
-
-static struct ast_cli_entry cli_show_agents_deprecated = {
- { "show", "agents", NULL },
- agents_show, NULL,
- NULL, NULL };
-
-static struct ast_cli_entry cli_show_agents_online_deprecated = {
- { "show", "agents", "online" },
- agents_show_online, NULL,
- NULL, NULL };
-
-static struct ast_cli_entry cli_agents[] = {
- { { "agent", "show", NULL },
- agents_show, "Show status of agents",
- show_agents_usage, NULL, &cli_show_agents_deprecated },
-
- { { "agent", "show", "online" },
- agents_show_online, "Show all online agents",
- show_agents_online_usage, NULL, &cli_show_agents_online_deprecated },
-
- { { "agent", "logoff", NULL },
- agent_logoff_cmd, "Sets an agent offline",
- agent_logoff_usage, complete_agent_logoff_cmd },
-};
-
-/*!
- * \brief Log in agent application.
- *
- * \param chan
- * \param data
- * \param callbackmode non-zero for AgentCallbackLogin
- */
-static int __login_exec(struct ast_channel *chan, void *data, int callbackmode)
-{
- int res=0;
- int tries = 0;
- int max_login_tries = maxlogintries;
- struct agent_pvt *p;
- struct ast_module_user *u;
- int login_state = 0;
- char user[AST_MAX_AGENT] = "";
- char pass[AST_MAX_AGENT];
- char agent[AST_MAX_AGENT] = "";
- char xpass[AST_MAX_AGENT] = "";
- char *errmsg;
- char *parse;
- AST_DECLARE_APP_ARGS(args,
- AST_APP_ARG(agent_id);
- AST_APP_ARG(options);
- AST_APP_ARG(extension);
- );
- const char *tmpoptions = NULL;
- char *context = NULL;
- int play_announcement = 1;
- char agent_goodbye[AST_MAX_FILENAME_LEN];
- int update_cdr = updatecdr;
- char *filename = "agent-loginok";
- char tmpchan[AST_MAX_BUF] = "";
-
- u = ast_module_user_add(chan);
-
- parse = ast_strdupa(data);
-
- AST_STANDARD_APP_ARGS(args, parse);
-
- ast_copy_string(agent_goodbye, agentgoodbye, sizeof(agent_goodbye));
-
- ast_channel_lock(chan);
- /* Set Channel Specific Login Overrides */
- if (pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES") && strlen(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) {
- max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"));
- if (max_login_tries < 0)
- max_login_tries = 0;
- tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES");
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTMAXLOGINTRIES=%s, setting max_login_tries to: %d on Channel '%s'.\n",tmpoptions,max_login_tries,chan->name);
- }
- if (pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) {
- if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR")))
- update_cdr = 1;
- else
- update_cdr = 0;
- tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR");
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,chan->name);
- }
- if (pbx_builtin_getvar_helper(chan, "AGENTGOODBYE") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) {
- strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"));
- tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE");
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,chan->name);
- }
- ast_channel_unlock(chan);
- /* End Channel Specific Login Overrides */
-
- if (callbackmode && args.extension) {
- parse = args.extension;
- args.extension = strsep(&parse, "@");
- context = parse;
- }
-
- if (!ast_strlen_zero(args.options)) {
- if (strchr(args.options, 's')) {
- play_announcement = 0;
- }
- }
-
- if (chan->_state != AST_STATE_UP)
- res = ast_answer(chan);
- if (!res) {
- if (!ast_strlen_zero(args.agent_id))
- ast_copy_string(user, args.agent_id, AST_MAX_AGENT);
- else
- res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
- }
- while (!res && (max_login_tries==0 || tries < max_login_tries)) {
- tries++;
- /* Check for password */
- AST_LIST_LOCK(&agents);
- AST_LIST_TRAVERSE(&agents, p, list) {
- if (!strcmp(p->agent, user) && !p->pending)
- ast_copy_string(xpass, p->password, sizeof(xpass));
- }
- AST_LIST_UNLOCK(&agents);
- if (!res) {
- if (!ast_strlen_zero(xpass))
- res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
- else
- pass[0] = '\0';
- }
- errmsg = "agent-incorrect";
-
-#if 0
- ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass);
-#endif
-
- /* Check again for accuracy */
- AST_LIST_LOCK(&agents);
- AST_LIST_TRAVERSE(&agents, p, list) {
- int unlock_channel = 1;
- ast_channel_lock(chan);
- ast_mutex_lock(&p->lock);
- if (!strcmp(p->agent, user) &&
- !strcmp(p->password, pass) && !p->pending) {
- login_state = 1; /* Successful Login */
-
- /* Ensure we can't be gotten until we're done */
- gettimeofday(&p->lastdisc, NULL);
- p->lastdisc.tv_sec++;
-
- /* Set Channel Specific Agent Overrides */
- if (pbx_builtin_getvar_helper(chan, "AGENTACKCALL") && strlen(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
- if (!strcasecmp(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"), "always"))
- p->ackcall = 2;
- else if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL")))
- p->ackcall = 1;
- else
- p->ackcall = 0;
- tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL");
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n",tmpoptions,p->ackcall,p->agent);
- } else {
- p->ackcall = ackcall;
- }
- if (pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF") && strlen(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) {
- p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"));
- if (p->autologoff < 0)
- p->autologoff = 0;
- tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF");
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n",tmpoptions,p->autologoff,p->agent);
- } else {
- p->autologoff = autologoff;
- }
- if (pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME") && strlen(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) {
- p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"));
- if (p->wrapuptime < 0)
- p->wrapuptime = 0;
- tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME");
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n",tmpoptions,p->wrapuptime,p->agent);
- } else {
- p->wrapuptime = wrapuptime;
- }
- ast_channel_unlock(chan);
- unlock_channel = 0;
- /* End Channel Specific Agent Overrides */
- if (!p->chan) {
- char last_loginchan[80] = "";
- long logintime;
- snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
-
- if (callbackmode) {
- int pos = 0;
- /* Retrieve login chan */
- for (;;) {
- if (!ast_strlen_zero(args.extension)) {
- ast_copy_string(tmpchan, args.extension, sizeof(tmpchan));
- res = 0;
- } else
- res = ast_app_getdata(chan, "agent-newlocation", tmpchan+pos, sizeof(tmpchan) - 2, 0);
- if (ast_strlen_zero(tmpchan) )
- break;
- if(ast_exists_extension(chan, S_OR(context,"default"), tmpchan,1, NULL) ) {
- if(!allow_multiple_login(tmpchan,context) ) {
- args.extension = NULL;
- pos = 0;
- } else
- break;
- }
- if (args.extension) {
- ast_log(LOG_WARNING, "Extension '%s' is not valid for automatic login of agent '%s'\n", args.extension, p->agent);
- args.extension = NULL;
- pos = 0;
- } else {
- ast_log(LOG_WARNING, "Extension '%s@%s' is not valid for automatic login of agent '%s'\n", tmpchan, S_OR(context, "default"), p->agent);
- res = ast_streamfile(chan, "invalid", chan->language);
- if (!res)
- res = ast_waitstream(chan, AST_DIGIT_ANY);
- if (res > 0) {
- tmpchan[0] = res;
- tmpchan[1] = '\0';
- pos = 1;
- } else {
- tmpchan[0] = '\0';
- pos = 0;
- }
- }
- }
- args.extension = tmpchan;
- if (!res) {
- set_agentbycallerid(p->logincallerid, NULL);
- if (!ast_strlen_zero(context) && !ast_strlen_zero(tmpchan))
- snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", tmpchan, context);
- else {
- ast_copy_string(last_loginchan, p->loginchan, sizeof(last_loginchan));
- ast_copy_string(p->loginchan, tmpchan, sizeof(p->loginchan));
- }
- p->acknowledged = 0;
- if (ast_strlen_zero(p->loginchan)) {
- login_state = 2;
- filename = "agent-loggedoff";
- } else {
- if (chan->cid.cid_num) {
- ast_copy_string(p->logincallerid, chan->cid.cid_num, sizeof(p->logincallerid));
- set_agentbycallerid(p->logincallerid, p->agent);
- } else
- p->logincallerid[0] = '\0';
- }
-
- if(update_cdr && chan->cdr)
- snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
-
- }
- } else {
- p->loginchan[0] = '\0';
- p->logincallerid[0] = '\0';
- p->acknowledged = 0;
- }
- ast_mutex_unlock(&p->lock);
- AST_LIST_UNLOCK(&agents);
- if( !res && play_announcement==1 )
- res = ast_streamfile(chan, filename, chan->language);
- if (!res)
- ast_waitstream(chan, "");
- AST_LIST_LOCK(&agents);
- ast_mutex_lock(&p->lock);
- if (!res) {
- res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
- if (res)
- ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats));
- }
- if (!res) {
- res = ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
- if (res)
- ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats));
- }
- /* Check once more just in case */
- if (p->chan)
- res = -1;
- if (callbackmode && !res) {
- /* Just say goodbye and be done with it */
- if (!ast_strlen_zero(p->loginchan)) {
- if (p->loginstart == 0)
- time(&p->loginstart);
- manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
- "Agent: %s\r\n"
- "Loginchan: %s\r\n"
- "Uniqueid: %s\r\n",
- p->agent, p->loginchan, chan->uniqueid);
- ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
- if (option_verbose > 1)
- ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
- ast_device_state_changed("Agent/%s", p->agent);
- if (persistent_agents)
- dump_agents();
- } else {
- logintime = time(NULL) - p->loginstart;
- p->loginstart = 0;
-
- agent_logoff_maintenance(p, last_loginchan, logintime, chan->uniqueid, NULL);
- if (option_verbose > 1)
- ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged out\n", p->agent);
- }
- AST_LIST_UNLOCK(&agents);
- if (!res)
- res = ast_safe_sleep(chan, 500);
- ast_mutex_unlock(&p->lock);
- } else if (!res) {
- ast_indicate_data(chan, AST_CONTROL_HOLD,
- S_OR(p->moh, NULL),
- !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0);
- if (p->loginstart == 0)
- time(&p->loginstart);
- manager_event(EVENT_FLAG_AGENT, "Agentlogin",
- "Agent: %s\r\n"
- "Channel: %s\r\n"
- "Uniqueid: %s\r\n",
- p->agent, chan->name, chan->uniqueid);
- if (update_cdr && chan->cdr)
- snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
- ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name);
- if (option_verbose > 1)
- ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged in (format %s/%s)\n", p->agent,
- ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat));
- /* Login this channel and wait for it to go away */
- p->chan = chan;
- if (p->ackcall > 1)
- check_beep(p, 0);
- else
- check_availability(p, 0);
- ast_mutex_unlock(&p->lock);
- AST_LIST_UNLOCK(&agents);
- ast_device_state_changed("Agent/%s", p->agent);
- while (res >= 0) {
- ast_mutex_lock(&p->lock);
- if (p->deferlogoff && p->chan) {
- ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
- p->deferlogoff = 0;
- }
- if (p->chan != chan)
- res = -1;
- ast_mutex_unlock(&p->lock);
- /* Yield here so other interested threads can kick in. */
- sched_yield();
- if (res)
- break;
-
- AST_LIST_LOCK(&agents);
- ast_mutex_lock(&p->lock);
- if (p->lastdisc.tv_sec) {
- if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Wrapup time for %s expired!\n", p->agent);
- p->lastdisc = ast_tv(0, 0);
- ast_device_state_changed("Agent/%s", p->agent);
- if (p->ackcall > 1)
- check_beep(p, 0);
- else
- check_availability(p, 0);
- }
- }
- ast_mutex_unlock(&p->lock);
- AST_LIST_UNLOCK(&agents);
- /* Synchronize channel ownership between call to agent and itself. */
- ast_mutex_lock(&p->app_lock);
- if (p->app_lock_flag == 1) {
- ast_cond_wait(&p->app_complete_cond, &p->app_lock);
- }
- ast_mutex_unlock(&p->app_lock);
- ast_mutex_lock(&p->lock);
- ast_mutex_unlock(&p->lock);
- if (p->ackcall > 1)
- res = agent_ack_sleep(p);
- else
- res = ast_safe_sleep_conditional( chan, 1000, agent_cont_sleep, p );
- if ((p->ackcall > 1) && (res == 1)) {
- AST_LIST_LOCK(&agents);
- ast_mutex_lock(&p->lock);
- check_availability(p, 0);
- ast_mutex_unlock(&p->lock);
- AST_LIST_UNLOCK(&agents);
- res = 0;
- }
- sched_yield();
- }
- ast_mutex_lock(&p->lock);
- if (res && p->owner)
- ast_log(LOG_WARNING, "Huh? We broke out when there was still an owner?\n");
- /* Log us off if appropriate */
- if (p->chan == chan) {
- p->chan = NULL;
- p->inherited_devicestate = -1;
- }
- p->acknowledged = 0;
- logintime = time(NULL) - p->loginstart;
- p->loginstart = 0;
- ast_mutex_unlock(&p->lock);
- manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
- "Agent: %s\r\n"
- "Logintime: %ld\r\n"
- "Uniqueid: %s\r\n",
- p->agent, logintime, chan->uniqueid);
- ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime);
- if (option_verbose > 1)
- ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged out\n", p->agent);
- /* If there is no owner, go ahead and kill it now */
- ast_device_state_changed("Agent/%s", p->agent);
- if (p->dead && !p->owner) {
- ast_mutex_destroy(&p->lock);
- ast_mutex_destroy(&p->app_lock);
- ast_cond_destroy(&p->app_complete_cond);
- free(p);
- }
- }
- else {
- ast_mutex_unlock(&p->lock);
- p = NULL;
- }
- res = -1;
- } else {
- ast_mutex_unlock(&p->lock);
- errmsg = "agent-alreadyon";
- p = NULL;
- }
- break;
- }
- ast_mutex_unlock(&p->lock);
- if (unlock_channel) {
- ast_channel_unlock(chan);
- }
- }
- if (!p)
- AST_LIST_UNLOCK(&agents);
-
- if (!res && (max_login_tries==0 || tries < max_login_tries))
- res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
- }
-
- if (!res)
- res = ast_safe_sleep(chan, 500);
-
- /* AgentLogin() exit */
- if (!callbackmode) {
- ast_module_user_remove(u);
- return -1;
- } else { /* AgentCallbackLogin() exit*/
- /* Set variables */
- if (login_state > 0) {
- pbx_builtin_setvar_helper(chan, "AGENTNUMBER", user);
- if (login_state==1) {
- pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "on");
- pbx_builtin_setvar_helper(chan, "AGENTEXTEN", args.extension);
- } else
- pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "off");
- } else {
- pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "fail");
- }
- if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num)) {
- ast_module_user_remove(u);
- return 0;
- }
- /* Do we need to play agent-goodbye now that we will be hanging up? */
- if (play_announcement) {
- if (!res)
- res = ast_safe_sleep(chan, 1000);
- res = ast_streamfile(chan, agent_goodbye, chan->language);
- if (!res)
- res = ast_waitstream(chan, "");
- if (!res)
- res = ast_safe_sleep(chan, 1000);
- }
- }
-
- ast_module_user_remove(u);
-
- /* We should never get here if next priority exists when in callbackmode */
- return -1;
-}
-
-/*!
- * Called by the AgentLogin application (from the dial plan).
- *
- * \param chan
- * \param data
- * \returns
- * \sa callback_login_exec(), agentmonitoroutgoing_exec(), load_module().
- */
-static int login_exec(struct ast_channel *chan, void *data)
-{
- return __login_exec(chan, data, 0);
-}
-
-static void callback_deprecated(void)
-{
- static int depwarning = 0;
-
- if (!depwarning) {
- depwarning = 1;
-
- ast_log(LOG_WARNING, "AgentCallbackLogin is deprecated and will be removed in a future release.\n");
- ast_log(LOG_WARNING, "See doc/queues-with-callback-members.txt for an example of how to achieve\n");
- ast_log(LOG_WARNING, "the same functionality using only dialplan logic.\n");
- }
-}
-
-/*!
- * Called by the AgentCallbackLogin application (from the dial plan).
- *
- * \param chan
- * \param data
- * \returns
- * \sa login_exec(), agentmonitoroutgoing_exec(), load_module().
- */
-static int callback_exec(struct ast_channel *chan, void *data)
-{
- callback_deprecated();
-
- return __login_exec(chan, data, 1);
-}
-
-/*!
- * Sets an agent as logged in by callback in the Manager API.
- * It is registered on load_module() and it gets called by the manager backend.
- * \param s
- * \param m
- * \returns
- * \sa action_agents(), action_agent_logoff(), load_module().
- */
-static int action_agent_callback_login(struct mansession *s, const struct message *m)
-{
- const char *agent = astman_get_header(m, "Agent");
- const char *exten = astman_get_header(m, "Exten");
- const char *context = astman_get_header(m, "Context");
- const char *wrapuptime_s = astman_get_header(m, "WrapupTime");
- const char *ackcall_s = astman_get_header(m, "AckCall");
- struct agent_pvt *p;
- int login_state = 0;
-
- callback_deprecated();
-
- if (ast_strlen_zero(agent)) {
- astman_send_error(s, m, "No agent specified");
- return 0;
- }
-
- if (ast_strlen_zero(exten)) {
- astman_send_error(s, m, "No extension specified");
- return 0;
- }
-
- AST_LIST_LOCK(&agents);
- AST_LIST_TRAVERSE(&agents, p, list) {
- if (strcmp(p->agent, agent) || p->pending)
- continue;
- if (p->chan) {
- login_state = 2; /* already logged in (and on the phone)*/
- break;
- }
- ast_mutex_lock(&p->lock);
- login_state = 1; /* Successful Login */
-
- if (ast_strlen_zero(context))
- ast_copy_string(p->loginchan, exten, sizeof(p->loginchan));
- else
- snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", exten, context);
-
- if (!ast_strlen_zero(wrapuptime_s)) {
- p->wrapuptime = atoi(wrapuptime_s);
- if (p->wrapuptime < 0)
- p->wrapuptime = 0;
- }
-
- if (!strcasecmp(ackcall_s, "always"))
- p->ackcall = 2;
- else if (ast_true(ackcall_s))
- p->ackcall = 1;
- else
- p->ackcall = 0;
-
- if (p->loginstart == 0)
- time(&p->loginstart);
- manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
- "Agent: %s\r\n"
- "Loginchan: %s\r\n",
- p->agent, p->loginchan);
- ast_queue_log("NONE", "NONE", agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
- if (option_verbose > 1)
- ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
- ast_device_state_changed("Agent/%s", p->agent);
- ast_mutex_unlock(&p->lock);
- if (persistent_agents)
- dump_agents();
- }
- AST_LIST_UNLOCK(&agents);
-
- if (login_state == 1)
- astman_send_ack(s, m, "Agent logged in");
- else if (login_state == 0)
- astman_send_error(s, m, "No such agent");
- else if (login_state == 2)
- astman_send_error(s, m, "Agent already logged in");
-
- return 0;
-}
-
-/*!
- * \brief Called by the AgentMonitorOutgoing application (from the dial plan).
- *
- * \param chan
- * \param data
- * \returns
- * \sa login_exec(), callback_login_exec(), load_module().
- */
-static int agentmonitoroutgoing_exec(struct ast_channel *chan, void *data)
-{
- int exitifnoagentid = 0;
- int nowarnings = 0;
- int changeoutgoing = 0;
- int res = 0;
- char agent[AST_MAX_AGENT];
-
- if (data) {
- if (strchr(data, 'd'))
- exitifnoagentid = 1;
- if (strchr(data, 'n'))
- nowarnings = 1;
- if (strchr(data, 'c'))
- changeoutgoing = 1;
- }
- if (chan->cid.cid_num) {
- const char *tmp;
- char agentvar[AST_MAX_BUF];
- snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num);
- if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
- struct agent_pvt *p;
- ast_copy_string(agent, tmp, sizeof(agent));
- AST_LIST_LOCK(&agents);
- AST_LIST_TRAVERSE(&agents, p, list) {
- if (!strcasecmp(p->agent, tmp)) {
- if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
- __agent_start_monitoring(chan, p, 1);
- break;
- }
- }
- AST_LIST_UNLOCK(&agents);
-
- } else {
- res = -1;
- if (!nowarnings)
- ast_log(LOG_WARNING, "Couldn't find the global variable %s, so I can't figure out which agent (if it's an agent) is placing outgoing call.\n", agentvar);
- }
- } else {
- res = -1;
- if (!nowarnings)
- ast_log(LOG_WARNING, "There is no callerid on that call, so I can't figure out which agent (if it's an agent) is placing outgoing call.\n");
- }
- /* check if there is n + 101 priority */
- /*! \todo XXX Needs to check option priorityjump etc etc */
- if (res) {
- if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
- chan->priority+=100;
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Going to %d priority because there is no callerid or the agentid cannot be found.\n",chan->priority);
- } else if (exitifnoagentid)
- return res;
- }
- return 0;
-}
-
-/*!
- * \brief Dump AgentCallbackLogin agents to the ASTdb database for persistence
- */
-static void dump_agents(void)
-{
- struct agent_pvt *cur_agent = NULL;
- char buf[256];
-
- AST_LIST_TRAVERSE(&agents, cur_agent, list) {
- if (cur_agent->chan)
- continue;
-
- if (!ast_strlen_zero(cur_agent->loginchan)) {
- snprintf(buf, sizeof(buf), "%s;%s", cur_agent->loginchan, cur_agent->logincallerid);
- if (ast_db_put(pa_family, cur_agent->agent, buf))
- ast_log(LOG_WARNING, "failed to create persistent entry in ASTdb for %s!\n", buf);
- else if (option_debug)
- ast_log(LOG_DEBUG, "Saved Agent: %s on %s\n", cur_agent->agent, cur_agent->loginchan);
- } else {
- /* Delete - no agent or there is an error */
- ast_db_del(pa_family, cur_agent->agent);
- }
- }
-}
-
-/*!
- * \brief Reload the persistent agents from astdb.
- */
-static void reload_agents(void)
-{
- char *agent_num;
- struct ast_db_entry *db_tree;
- struct ast_db_entry *entry;
- struct agent_pvt *cur_agent;
- char agent_data[256];
- char *parse;
- char *agent_chan;
- char *agent_callerid;
-
- db_tree = ast_db_gettree(pa_family, NULL);
-
- AST_LIST_LOCK(&agents);
- for (entry = db_tree; entry; entry = entry->next) {
- agent_num = entry->key + strlen(pa_family) + 2;
- AST_LIST_TRAVERSE(&agents, cur_agent, list) {
- ast_mutex_lock(&cur_agent->lock);
- if (strcmp(agent_num, cur_agent->agent) == 0)
- break;
- ast_mutex_unlock(&cur_agent->lock);
- }
- if (!cur_agent) {
- ast_db_del(pa_family, agent_num);
- continue;
- } else
- ast_mutex_unlock(&cur_agent->lock);
- if (!ast_db_get(pa_family, agent_num, agent_data, sizeof(agent_data)-1)) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Reload Agent from AstDB: %s on %s\n", cur_agent->agent, agent_data);
- parse = agent_data;
- agent_chan = strsep(&parse, ";");
- agent_callerid = strsep(&parse, ";");
- ast_copy_string(cur_agent->loginchan, agent_chan, sizeof(cur_agent->loginchan));
- if (agent_callerid) {
- ast_copy_string(cur_agent->logincallerid, agent_callerid, sizeof(cur_agent->logincallerid));
- set_agentbycallerid(cur_agent->logincallerid, cur_agent->agent);
- } else
- cur_agent->logincallerid[0] = '\0';
- if (cur_agent->loginstart == 0)
- time(&cur_agent->loginstart);
- ast_device_state_changed("Agent/%s", cur_agent->agent);
- }
- }
- AST_LIST_UNLOCK(&agents);
- if (db_tree) {
- ast_log(LOG_NOTICE, "Agents successfully reloaded from database.\n");
- ast_db_freetree(db_tree);
- }
-}
-
-/*! \brief Part of PBX channel interface */
-static int agent_devicestate(void *data)
-{
- struct agent_pvt *p;
- char *s;
- ast_group_t groupmatch;
- int groupoff;
- int waitforagent=0;
- int res = AST_DEVICE_INVALID;
-
- s = data;
- if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1))
- groupmatch = (1 << groupoff);
- else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
- groupmatch = (1 << groupoff);
- waitforagent = 1;
- } else
- groupmatch = 0;
-
- /* Check actual logged in agents first */
- AST_LIST_LOCK(&agents);
- AST_LIST_TRAVERSE(&agents, p, list) {
- ast_mutex_lock(&p->lock);
- if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
- if (p->owner) {
- if (res != AST_DEVICE_INUSE)
- res = AST_DEVICE_BUSY;
- } else if (p->inherited_devicestate > -1) {
- res = p->inherited_devicestate;
- } else {
- if (res == AST_DEVICE_BUSY)
- res = AST_DEVICE_INUSE;
- if (p->chan || !ast_strlen_zero(p->loginchan)) {
- if (res == AST_DEVICE_INVALID)
- res = AST_DEVICE_UNKNOWN;
- } else if (res == AST_DEVICE_INVALID)
- res = AST_DEVICE_UNAVAILABLE;
- }
- if (!strcmp(data, p->agent)) {
- ast_mutex_unlock(&p->lock);
- break;
- }
- }
- ast_mutex_unlock(&p->lock);
- }
- AST_LIST_UNLOCK(&agents);
- return res;
-}
-
-/*!
- * \note This function expects the agent list to be locked
- */
-static struct agent_pvt *find_agent(char *agentid)
-{
- struct agent_pvt *cur;
-
- AST_LIST_TRAVERSE(&agents, cur, list) {
- if (!strcmp(cur->agent, agentid))
- break;
- }
-
- return cur;
-}
-
-static int function_agent(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
-{
- char *parse;
- AST_DECLARE_APP_ARGS(args,
- AST_APP_ARG(agentid);
- AST_APP_ARG(item);
- );
- char *tmp;
- struct agent_pvt *agent;
-
- buf[0] = '\0';
-
- if (ast_strlen_zero(data)) {
- ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n");
- return -1;
- }
-
- parse = ast_strdupa(data);
-
- AST_NONSTANDARD_APP_ARGS(args, parse, ':');
- if (!args.item)
- args.item = "status";
-
- AST_LIST_LOCK(&agents);
-
- if (!(agent = find_agent(args.agentid))) {
- AST_LIST_UNLOCK(&agents);
- ast_log(LOG_WARNING, "Agent '%s' not found!\n", args.agentid);
- return -1;
- }
-
- if (!strcasecmp(args.item, "status")) {
- char *status = "LOGGEDOUT";
- if (agent->chan || !ast_strlen_zero(agent->loginchan))
- status = "LOGGEDIN";
- ast_copy_string(buf, status, len);
- } else if (!strcasecmp(args.item, "password"))
- ast_copy_string(buf, agent->password, len);
- else if (!strcasecmp(args.item, "name"))
- ast_copy_string(buf, agent->name, len);
- else if (!strcasecmp(args.item, "mohclass"))
- ast_copy_string(buf, agent->moh, len);
- else if (!strcasecmp(args.item, "channel")) {
- if (agent->chan) {
- ast_copy_string(buf, agent->chan->name, len);
- tmp = strrchr(buf, '-');
- if (tmp)
- *tmp = '\0';
- }
- } else if (!strcasecmp(args.item, "exten"))
- ast_copy_string(buf, agent->loginchan, len);
-
- AST_LIST_UNLOCK(&agents);
-
- return 0;
-}
-
-struct ast_custom_function agent_function = {
- .name = "AGENT",
- .synopsis = "Gets information about an Agent",
- .syntax = "AGENT(<agentid>[:item])",
- .read = function_agent,
- .desc = "The valid items to retrieve are:\n"
- "- status (default) The status of the agent\n"
- " LOGGEDIN | LOGGEDOUT\n"
- "- password The password of the agent\n"
- "- name The name of the agent\n"
- "- mohclass MusicOnHold class\n"
- "- exten The callback extension for the Agent (AgentCallbackLogin)\n"
- "- channel The name of the active channel for the Agent (AgentLogin)\n"
-};
-
-
-/*!
- * \brief Initialize the Agents module.
- * This function is being called by Asterisk when loading the module.
- * Among other things it registers applications, cli commands and reads the cofiguration file.
- *
- * \returns int Always 0.
- */
-static int load_module(void)
-{
- /* Make sure we can register our agent channel type */
- if (ast_channel_register(&agent_tech)) {
- ast_log(LOG_ERROR, "Unable to register channel class 'Agent'\n");
- return -1;
- }
- /* Read in the config */
- if (!read_agent_config())
- return AST_MODULE_LOAD_DECLINE;
- if (persistent_agents)
- reload_agents();
- /* Dialplan applications */
- ast_register_application(app, login_exec, synopsis, descrip);
- ast_register_application(app2, callback_exec, synopsis2, descrip2);
- ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3);
-
- /* Manager commands */
- ast_manager_register2("Agents", EVENT_FLAG_AGENT, action_agents, "Lists agents and their status", mandescr_agents);
- ast_manager_register2("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff, "Sets an agent as no longer logged in", mandescr_agent_logoff);
- ast_manager_register2("AgentCallbackLogin", EVENT_FLAG_AGENT, action_agent_callback_login, "Sets an agent as logged in by callback", mandescr_agent_callback_login);
-
- /* CLI Commands */
- ast_cli_register_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry));
-
- /* Dialplan Functions */
- ast_custom_function_register(&agent_function);
-
- ast_devstate_add(agent_devicestate_cb, NULL);
-
- return 0;
-}
-
-static int reload(void)
-{
- read_agent_config();
- if (persistent_agents)
- reload_agents();
- return 0;
-}
-
-static int unload_module(void)
-{
- struct agent_pvt *p;
- /* First, take us out of the channel loop */
- ast_channel_unregister(&agent_tech);
- /* Delete devicestate subscription */
- ast_devstate_del(agent_devicestate_cb, NULL);
- /* Unregister dialplan functions */
- ast_custom_function_unregister(&agent_function);
- /* Unregister CLI commands */
- ast_cli_unregister_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry));
- /* Unregister dialplan applications */
- ast_unregister_application(app);
- ast_unregister_application(app2);
- ast_unregister_application(app3);
- /* Unregister manager command */
- ast_manager_unregister("Agents");
- ast_manager_unregister("AgentLogoff");
- ast_manager_unregister("AgentCallbackLogin");
- /* Unregister channel */
- AST_LIST_LOCK(&agents);
- /* Hangup all interfaces if they have an owner */
- while ((p = AST_LIST_REMOVE_HEAD(&agents, list))) {
- if (p->owner)
- ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
- free(p);
- }
- AST_LIST_UNLOCK(&agents);
- return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Agent Proxy Channel",
- .load = load_module,
- .unload = unload_module,
- .reload = reload,
- );
diff --git a/1.4.23-rc4/channels/chan_alsa.c b/1.4.23-rc4/channels/chan_alsa.c
deleted file mode 100644
index 03db26b6a..000000000
--- a/1.4.23-rc4/channels/chan_alsa.c
+++ /dev/null
@@ -1,1391 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 1999 - 2005, Digium, Inc.
- *
- * By Matthew Fredrickson <creslin@digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- * \brief ALSA sound card channel driver
- *
- * \author Matthew Fredrickson <creslin@digium.com>
- *
- * \par See also
- * \arg Config_alsa
- *
- * \ingroup channel_drivers
- */
-
-/*** MODULEINFO
- <depend>asound</depend>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <sys/ioctl.h>
-#include <sys/time.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-#define ALSA_PCM_NEW_HW_PARAMS_API
-#define ALSA_PCM_NEW_SW_PARAMS_API
-#include <alsa/asoundlib.h>
-
-#include "asterisk/frame.h"
-#include "asterisk/logger.h"
-#include "asterisk/channel.h"
-#include "asterisk/module.h"
-#include "asterisk/options.h"
-#include "asterisk/pbx.h"
-#include "asterisk/config.h"
-#include "asterisk/cli.h"
-#include "asterisk/utils.h"
-#include "asterisk/causes.h"
-#include "asterisk/endian.h"
-#include "asterisk/stringfields.h"
-#include "asterisk/abstract_jb.h"
-#include "asterisk/musiconhold.h"
-
-#include "busy_tone.h"
-#include "ring_tone.h"
-#include "ring10.h"
-#include "answer.h"
-
-#ifdef ALSA_MONITOR
-#include "alsa-monitor.h"
-#endif
-
-/*! Global jitterbuffer configuration - by default, jb is disabled */
-static struct ast_jb_conf default_jbconf = {
- .flags = 0,
- .max_size = -1,
- .resync_threshold = -1,
- .impl = ""
-};
-static struct ast_jb_conf global_jbconf;
-
-#define DEBUG 0
-/* Which device to use */
-#define ALSA_INDEV "default"
-#define ALSA_OUTDEV "default"
-#define DESIRED_RATE 8000
-
-/* Lets use 160 sample frames, just like GSM. */
-#define FRAME_SIZE 160
-#define PERIOD_FRAMES 80 /* 80 Frames, at 2 bytes each */
-
-/* When you set the frame size, you have to come up with
- the right buffer format as well. */
-/* 5 64-byte frames = one frame */
-#define BUFFER_FMT ((buffersize * 10) << 16) | (0x0006);
-
-/* Don't switch between read/write modes faster than every 300 ms */
-#define MIN_SWITCH_TIME 600
-
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-static snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE;
-#else
-static snd_pcm_format_t format = SND_PCM_FORMAT_S16_BE;
-#endif
-
-static char indevname[50] = ALSA_INDEV;
-static char outdevname[50] = ALSA_OUTDEV;
-
-#if 0
-static struct timeval lasttime;
-#endif
-
-static int silencesuppression = 0;
-static int silencethreshold = 1000;
-
-AST_MUTEX_DEFINE_STATIC(alsalock);
-
-static const char tdesc[] = "ALSA Console Channel Driver";
-static const char config[] = "alsa.conf";
-
-static char context[AST_MAX_CONTEXT] = "default";
-static char language[MAX_LANGUAGE] = "";
-static char exten[AST_MAX_EXTENSION] = "s";
-static char mohinterpret[MAX_MUSICCLASS];
-
-static int hookstate = 0;
-
-static short silence[FRAME_SIZE] = { 0, };
-
-struct sound {
- int ind;
- short *data;
- int datalen;
- int samplen;
- int silencelen;
- int repeat;
-};
-
-static struct sound sounds[] = {
- {AST_CONTROL_RINGING, ringtone, sizeof(ringtone) / 2, 16000, 32000, 1},
- {AST_CONTROL_BUSY, busy, sizeof(busy) / 2, 4000, 4000, 1},
- {AST_CONTROL_CONGESTION, busy, sizeof(busy) / 2, 2000, 2000, 1},
- {AST_CONTROL_RING, ring10, sizeof(ring10) / 2, 16000, 32000, 1},
- {AST_CONTROL_ANSWER, answer, sizeof(answer) / 2, 2200, 0, 0},
-};
-
-/* Sound command pipe */
-static int sndcmd[2];
-
-static struct chan_alsa_pvt {
- /* We only have one ALSA structure -- near sighted perhaps, but it
- keeps this driver as simple as possible -- as it should be. */
- struct ast_channel *owner;
- char exten[AST_MAX_EXTENSION];
- char context[AST_MAX_CONTEXT];
-#if 0
- snd_pcm_t *card;
-#endif
- snd_pcm_t *icard, *ocard;
-
-} alsa;
-
-/* Number of buffers... Each is FRAMESIZE/8 ms long. For example
- with 160 sample frames, and a buffer size of 3, we have a 60ms buffer,
- usually plenty. */
-
-pthread_t sthread;
-
-#define MAX_BUFFER_SIZE 100
-
-/* File descriptors for sound device */
-static int readdev = -1;
-static int writedev = -1;
-
-static int autoanswer = 1;
-
-static int cursound = -1;
-static int sampsent = 0;
-static int silencelen = 0;
-static int offset = 0;
-static int nosound = 0;
-
-/* ZZ */
-static struct ast_channel *alsa_request(const char *type, int format, void *data, int *cause);
-static int alsa_digit(struct ast_channel *c, char digit, unsigned int duration);
-static int alsa_text(struct ast_channel *c, const char *text);
-static int alsa_hangup(struct ast_channel *c);
-static int alsa_answer(struct ast_channel *c);
-static struct ast_frame *alsa_read(struct ast_channel *chan);
-static int alsa_call(struct ast_channel *c, char *dest, int timeout);
-static int alsa_write(struct ast_channel *chan, struct ast_frame *f);
-static int alsa_indicate(struct ast_channel *chan, int cond, const void *data, size_t datalen);
-static int alsa_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
-
-static const struct ast_channel_tech alsa_tech = {
- .type = "Console",
- .description = tdesc,
- .capabilities = AST_FORMAT_SLINEAR,
- .requester = alsa_request,
- .send_digit_end = alsa_digit,
- .send_text = alsa_text,
- .hangup = alsa_hangup,
- .answer = alsa_answer,
- .read = alsa_read,
- .call = alsa_call,
- .write = alsa_write,
- .indicate = alsa_indicate,
- .fixup = alsa_fixup,
-};
-
-static int send_sound(void)
-{
- short myframe[FRAME_SIZE];
- int total = FRAME_SIZE;
- short *frame = NULL;
- int amt = 0, res, myoff;
- snd_pcm_state_t state;
-
- if (cursound == -1)
- return 0;
-
- res = total;
- if (sampsent < sounds[cursound].samplen) {
- myoff = 0;
- while (total) {
- amt = total;
- if (amt > (sounds[cursound].datalen - offset))
- amt = sounds[cursound].datalen - offset;
- memcpy(myframe + myoff, sounds[cursound].data + offset, amt * 2);
- total -= amt;
- offset += amt;
- sampsent += amt;
- myoff += amt;
- if (offset >= sounds[cursound].datalen)
- offset = 0;
- }
- /* Set it up for silence */
- if (sampsent >= sounds[cursound].samplen)
- silencelen = sounds[cursound].silencelen;
- frame = myframe;
- } else {
- if (silencelen > 0) {
- frame = silence;
- silencelen -= res;
- } else {
- if (sounds[cursound].repeat) {
- /* Start over */
- sampsent = 0;
- offset = 0;
- } else {
- cursound = -1;
- nosound = 0;
- }
- return 0;
- }
- }
-
- if (res == 0 || !frame)
- return 0;
-
-#ifdef ALSA_MONITOR
- alsa_monitor_write((char *) frame, res * 2);
-#endif
- state = snd_pcm_state(alsa.ocard);
- if (state == SND_PCM_STATE_XRUN)
- snd_pcm_prepare(alsa.ocard);
- while ((res = snd_pcm_writei(alsa.ocard, frame, res)) == -EAGAIN) {
- usleep(1);
- }
- if (res > 0)
- return 0;
- return 0;
-}
-
-static void *sound_thread(void *unused)
-{
- fd_set rfds;
- fd_set wfds;
- int max, res;
-
- for (;;) {
- FD_ZERO(&rfds);
- FD_ZERO(&wfds);
- max = sndcmd[0];
- FD_SET(sndcmd[0], &rfds);
- if (cursound > -1) {
- FD_SET(writedev, &wfds);
- if (writedev > max)
- max = writedev;
- }
-#ifdef ALSA_MONITOR
- if (!alsa.owner) {
- FD_SET(readdev, &rfds);
- if (readdev > max)
- max = readdev;
- }
-#endif
- res = ast_select(max + 1, &rfds, &wfds, NULL, NULL);
- if (res < 1) {
- ast_log(LOG_WARNING, "select failed: %s\n", strerror(errno));
- continue;
- }
-#ifdef ALSA_MONITOR
- if (FD_ISSET(readdev, &rfds)) {
- /* Keep the pipe going with read audio */
- snd_pcm_state_t state;
- short buf[FRAME_SIZE];
- int r;
-
- state = snd_pcm_state(alsa.ocard);
- if (state == SND_PCM_STATE_XRUN) {
- snd_pcm_prepare(alsa.ocard);
- }
- r = snd_pcm_readi(alsa.icard, buf, FRAME_SIZE);
- if (r == -EPIPE) {
-#if DEBUG
- ast_log(LOG_ERROR, "XRUN read\n");
-#endif
- snd_pcm_prepare(alsa.icard);
- } else if (r == -ESTRPIPE) {
- ast_log(LOG_ERROR, "-ESTRPIPE\n");
- snd_pcm_prepare(alsa.icard);
- } else if (r < 0) {
- ast_log(LOG_ERROR, "Read error: %s\n", snd_strerror(r));
- } else
- alsa_monitor_read((char *) buf, r * 2);
- }
-#endif
- if (FD_ISSET(sndcmd[0], &rfds)) {
- if (read(sndcmd[0], &cursound, sizeof(cursound)) < 0) {
- ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
- }
- silencelen = 0;
- offset = 0;
- sampsent = 0;
- }
- if (FD_ISSET(writedev, &wfds))
- if (send_sound())
- ast_log(LOG_WARNING, "Failed to write sound\n");
- }
- /* Never reached */
- return NULL;
-}
-
-static snd_pcm_t *alsa_card_init(char *dev, snd_pcm_stream_t stream)
-{
- int err;
- int direction;
- snd_pcm_t *handle = NULL;
- snd_pcm_hw_params_t *hwparams = NULL;
- snd_pcm_sw_params_t *swparams = NULL;
- struct pollfd pfd;
- snd_pcm_uframes_t period_size = PERIOD_FRAMES * 4;
- /* int period_bytes = 0; */
- snd_pcm_uframes_t buffer_size = 0;
-
- unsigned int rate = DESIRED_RATE;
-#if 0
- unsigned int per_min = 1;
-#endif
- /* unsigned int per_max = 8; */
- snd_pcm_uframes_t start_threshold, stop_threshold;
-
- err = snd_pcm_open(&handle, dev, stream, SND_PCM_NONBLOCK);
- if (err < 0) {
- ast_log(LOG_ERROR, "snd_pcm_open failed: %s\n", snd_strerror(err));
- return NULL;
- } else
- ast_log(LOG_DEBUG, "Opening device %s in %s mode\n", dev, (stream == SND_PCM_STREAM_CAPTURE) ? "read" : "write");
-
- hwparams = alloca(snd_pcm_hw_params_sizeof());
- memset(hwparams, 0, snd_pcm_hw_params_sizeof());
- snd_pcm_hw_params_any(handle, hwparams);
-
- err = snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
- if (err < 0)
- ast_log(LOG_ERROR, "set_access failed: %s\n", snd_strerror(err));
-
- err = snd_pcm_hw_params_set_format(handle, hwparams, format);
- if (err < 0)
- ast_log(LOG_ERROR, "set_format failed: %s\n", snd_strerror(err));
-
- err = snd_pcm_hw_params_set_channels(handle, hwparams, 1);
- if (err < 0)
- ast_log(LOG_ERROR, "set_channels failed: %s\n", snd_strerror(err));
-
- direction = 0;
- err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &rate, &direction);
- if (rate != DESIRED_RATE)
- ast_log(LOG_WARNING, "Rate not correct, requested %d, got %d\n", DESIRED_RATE, rate);
-
- direction = 0;
- err = snd_pcm_hw_params_set_period_size_near(handle, hwparams, &period_size, &direction);
- if (err < 0)
- ast_log(LOG_ERROR, "period_size(%ld frames) is bad: %s\n", period_size, snd_strerror(err));
- else
- ast_log(LOG_DEBUG, "Period size is %d\n", err);
-
- buffer_size = 4096 * 2; /* period_size * 16; */
- err = snd_pcm_hw_params_set_buffer_size_near(handle, hwparams, &buffer_size);
- if (err < 0)
- ast_log(LOG_WARNING, "Problem setting buffer size of %ld: %s\n", buffer_size, snd_strerror(err));
- else
- ast_log(LOG_DEBUG, "Buffer size is set to %d frames\n", err);
-
-#if 0
- direction = 0;
- err = snd_pcm_hw_params_set_periods_min(handle, hwparams, &per_min, &direction);
- if (err < 0)
- ast_log(LOG_ERROR, "periods_min: %s\n", snd_strerror(err));
-
- err = snd_pcm_hw_params_set_periods_max(handle, hwparams, &per_max, 0);
- if (err < 0)
- ast_log(LOG_ERROR, "periods_max: %s\n", snd_strerror(err));
-#endif
-
- err = snd_pcm_hw_params(handle, hwparams);
- if (err < 0)
- ast_log(LOG_ERROR, "Couldn't set the new hw params: %s\n", snd_strerror(err));
-
- swparams = alloca(snd_pcm_sw_params_sizeof());
- memset(swparams, 0, snd_pcm_sw_params_sizeof());
- snd_pcm_sw_params_current(handle, swparams);
-
-#if 1
- if (stream == SND_PCM_STREAM_PLAYBACK)
- start_threshold = period_size;
- else
- start_threshold = 1;
-
- err = snd_pcm_sw_params_set_start_threshold(handle, swparams, start_threshold);
- if (err < 0)
- ast_log(LOG_ERROR, "start threshold: %s\n", snd_strerror(err));
-#endif
-
-#if 1
- if (stream == SND_PCM_STREAM_PLAYBACK)
- stop_threshold = buffer_size;
- else
- stop_threshold = buffer_size;
-
- err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, stop_threshold);
- if (err < 0)
- ast_log(LOG_ERROR, "stop threshold: %s\n", snd_strerror(err));
-#endif
-#if 0
- err = snd_pcm_sw_params_set_xfer_align(handle, swparams, PERIOD_FRAMES);
- if (err < 0)
- ast_log(LOG_ERROR, "Unable to set xfer alignment: %s\n", snd_strerror(err));
-#endif
-
-#if 0
- err = snd_pcm_sw_params_set_silence_threshold(handle, swparams, silencethreshold);
- if (err < 0)
- ast_log(LOG_ERROR, "Unable to set silence threshold: %s\n", snd_strerror(err));
-#endif
- err = snd_pcm_sw_params(handle, swparams);
- if (err < 0)
- ast_log(LOG_ERROR, "sw_params: %s\n", snd_strerror(err));
-
- err = snd_pcm_poll_descriptors_count(handle);
- if (err <= 0)
- ast_log(LOG_ERROR, "Unable to get a poll descriptors count, error is %s\n", snd_strerror(err));
- if (err != 1)
- ast_log(LOG_DEBUG, "Can't handle more than one device\n");
-
- snd_pcm_poll_descriptors(handle, &pfd, err);
- ast_log(LOG_DEBUG, "Acquired fd %d from the poll descriptor\n", pfd.fd);
-
- if (stream == SND_PCM_STREAM_CAPTURE)
- readdev = pfd.fd;
- else
- writedev = pfd.fd;
-
- return handle;
-}
-
-static int soundcard_init(void)
-{
- alsa.icard = alsa_card_init(indevname, SND_PCM_STREAM_CAPTURE);
- alsa.ocard = alsa_card_init(outdevname, SND_PCM_STREAM_PLAYBACK);
-
- if (!alsa.icard || !alsa.ocard) {
- ast_log(LOG_ERROR, "Problem opening alsa I/O devices\n");
- return -1;
- }
-
- return readdev;
-}
-
-static int alsa_digit(struct ast_channel *c, char digit, unsigned int duration)
-{
- ast_mutex_lock(&alsalock);
- ast_verbose(" << Console Received digit %c of duration %u ms >> \n",
- digit, duration);
- ast_mutex_unlock(&alsalock);
- return 0;
-}
-
-static int alsa_text(struct ast_channel *c, const char *text)
-{
- ast_mutex_lock(&alsalock);
- ast_verbose(" << Console Received text %s >> \n", text);
- ast_mutex_unlock(&alsalock);
- return 0;
-}
-
-static void grab_owner(void)
-{
- while (alsa.owner && ast_mutex_trylock(&alsa.owner->lock)) {
- DEADLOCK_AVOIDANCE(&alsalock);
- }
-}
-
-static int alsa_call(struct ast_channel *c, char *dest, int timeout)
-{
- int res = 3;
- struct ast_frame f = { AST_FRAME_CONTROL };
- ast_mutex_lock(&alsalock);
- ast_verbose(" << Call placed to '%s' on console >> \n", dest);
- if (autoanswer) {
- ast_verbose(" << Auto-answered >> \n");
- grab_owner();
- if (alsa.owner) {
- f.subclass = AST_CONTROL_ANSWER;
- ast_queue_frame(alsa.owner, &f);
- ast_mutex_unlock(&alsa.owner->lock);
- }
- } else {
- ast_verbose(" << Type 'answer' to answer, or use 'autoanswer' for future calls >> \n");
- grab_owner();
- if (alsa.owner) {
- f.subclass = AST_CONTROL_RINGING;
- ast_queue_frame(alsa.owner, &f);
- ast_mutex_unlock(&alsa.owner->lock);
- }
- if (write(sndcmd[1], &res, sizeof(res)) < 0) {
- ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
- }
- }
- snd_pcm_prepare(alsa.icard);
- snd_pcm_start(alsa.icard);
- ast_mutex_unlock(&alsalock);
- return 0;
-}
-
-static void answer_sound(void)
-{
- int res;
-
- nosound = 1;
- res = 4;
- if (write(sndcmd[1], &res, sizeof(res)) < 0) {
- ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
- }
-}
-
-static int alsa_answer(struct ast_channel *c)
-{
- ast_mutex_lock(&alsalock);
- ast_verbose(" << Console call has been answered >> \n");
- answer_sound();
- ast_setstate(c, AST_STATE_UP);
- cursound = -1;
- snd_pcm_prepare(alsa.icard);
- snd_pcm_start(alsa.icard);
- ast_mutex_unlock(&alsalock);
- return 0;
-}
-
-static int alsa_hangup(struct ast_channel *c)
-{
- int res;
- ast_mutex_lock(&alsalock);
- cursound = -1;
- c->tech_pvt = NULL;
- alsa.owner = NULL;
- ast_verbose(" << Hangup on console >> \n");
- ast_module_unref(ast_module_info->self);
- if (hookstate) {
- hookstate = 0;
- if (!autoanswer) {
- /* Congestion noise */
- res = 2;
- if (write(sndcmd[1], &res, sizeof(res)) < 0) {
- ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
- }
- }
- }
- snd_pcm_drop(alsa.icard);
- ast_mutex_unlock(&alsalock);
- return 0;
-}
-
-static int alsa_write(struct ast_channel *chan, struct ast_frame *f)
-{
- static char sizbuf[8000];
- static int sizpos = 0;
- int len = sizpos;
- int pos;
- int res = 0;
- /* size_t frames = 0; */
- snd_pcm_state_t state;
-
- /* Immediately return if no sound is enabled */
- if (nosound)
- return 0;
-
- ast_mutex_lock(&alsalock);
- /* Stop any currently playing sound */
- if (cursound != -1) {
- snd_pcm_drop(alsa.ocard);
- snd_pcm_prepare(alsa.ocard);
- cursound = -1;
- }
-
-
- /* We have to digest the frame in 160-byte portions */
- if (f->datalen > sizeof(sizbuf) - sizpos) {
- ast_log(LOG_WARNING, "Frame too large\n");
- res = -1;
- } else {
- memcpy(sizbuf + sizpos, f->data, f->datalen);
- len += f->datalen;
- pos = 0;
-#ifdef ALSA_MONITOR
- alsa_monitor_write(sizbuf, len);
-#endif
- state = snd_pcm_state(alsa.ocard);
- if (state == SND_PCM_STATE_XRUN)
- snd_pcm_prepare(alsa.ocard);
- while ((res = snd_pcm_writei(alsa.ocard, sizbuf, len / 2)) == -EAGAIN) {
- usleep(1);
- }
- if (res == -EPIPE) {
-#if DEBUG
- ast_log(LOG_DEBUG, "XRUN write\n");
-#endif
- snd_pcm_prepare(alsa.ocard);
- while ((res = snd_pcm_writei(alsa.ocard, sizbuf, len / 2)) == -EAGAIN) {
- usleep(1);
- }
- if (res != len / 2) {
- ast_log(LOG_ERROR, "Write error: %s\n", snd_strerror(res));
- res = -1;
- } else if (res < 0) {
- ast_log(LOG_ERROR, "Write error %s\n", snd_strerror(res));
- res = -1;
- }
- } else {
- if (res == -ESTRPIPE)
- ast_log(LOG_ERROR, "You've got some big problems\n");
- else if (res < 0)
- ast_log(LOG_NOTICE, "Error %d on write\n", res);
- }
- }
- ast_mutex_unlock(&alsalock);
- if (res > 0)
- res = 0;
- return res;
-}
-
-
-static struct ast_frame *alsa_read(struct ast_channel *chan)
-{
- static struct ast_frame f;
- static short __buf[FRAME_SIZE + AST_FRIENDLY_OFFSET / 2];
- short *buf;
- static int readpos = 0;
- static int left = FRAME_SIZE;
- snd_pcm_state_t state;
- int r = 0;
- int off = 0;
-
- ast_mutex_lock(&alsalock);
- /* Acknowledge any pending cmd */
- f.frametype = AST_FRAME_NULL;
- f.subclass = 0;
- f.samples = 0;
- f.datalen = 0;
- f.data = NULL;
- f.offset = 0;
- f.src = "Console";
- f.mallocd = 0;
- f.delivery.tv_sec = 0;
- f.delivery.tv_usec = 0;
-
- state = snd_pcm_state(alsa.icard);
- if ((state != SND_PCM_STATE_PREPARED) && (state != SND_PCM_STATE_RUNNING)) {
- snd_pcm_prepare(alsa.icard);
- }
-
- buf = __buf + AST_FRIENDLY_OFFSET / 2;
-
- r = snd_pcm_readi(alsa.icard, buf + readpos, left);
- if (r == -EPIPE) {
-#if DEBUG
- ast_log(LOG_ERROR, "XRUN read\n");
-#endif
- snd_pcm_prepare(alsa.icard);
- } else if (r == -ESTRPIPE) {
- ast_log(LOG_ERROR, "-ESTRPIPE\n");
- snd_pcm_prepare(alsa.icard);
- } else if (r < 0) {
- ast_log(LOG_ERROR, "Read error: %s\n", snd_strerror(r));
- } else if (r >= 0) {
- off -= r;
- }
- /* Update positions */
- readpos += r;
- left -= r;
-
- if (readpos >= FRAME_SIZE) {
- /* A real frame */
- readpos = 0;
- left = FRAME_SIZE;
- if (chan->_state != AST_STATE_UP) {
- /* Don't transmit unless it's up */
- ast_mutex_unlock(&alsalock);
- return &f;
- }
- f.frametype = AST_FRAME_VOICE;
- f.subclass = AST_FORMAT_SLINEAR;
- f.samples = FRAME_SIZE;
- f.datalen = FRAME_SIZE * 2;
- f.data = buf;
- f.offset = AST_FRIENDLY_OFFSET;
- f.src = "Console";
- f.mallocd = 0;
-#ifdef ALSA_MONITOR
- alsa_monitor_read((char *) buf, FRAME_SIZE * 2);
-#endif
-
- }
- ast_mutex_unlock(&alsalock);
- return &f;
-}
-
-static int alsa_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
-{
- struct chan_alsa_pvt *p = newchan->tech_pvt;
- ast_mutex_lock(&alsalock);
- p->owner = newchan;
- ast_mutex_unlock(&alsalock);
- return 0;
-}
-
-static int alsa_indicate(struct ast_channel *chan, int cond, const void *data, size_t datalen)
-{
- int res = 0;
-
- ast_mutex_lock(&alsalock);
-
- switch (cond) {
- case AST_CONTROL_BUSY:
- res = 1;
- break;
- case AST_CONTROL_CONGESTION:
- res = 2;
- break;
- case AST_CONTROL_RINGING:
- case AST_CONTROL_PROGRESS:
- break;
- case -1:
- res = -1;
- break;
- case AST_CONTROL_VIDUPDATE:
- res = -1;
- break;
- case AST_CONTROL_HOLD:
- ast_verbose(" << Console Has Been Placed on Hold >> \n");
- ast_moh_start(chan, data, mohinterpret);
- break;
- case AST_CONTROL_UNHOLD:
- ast_verbose(" << Console Has Been Retrieved from Hold >> \n");
- ast_moh_stop(chan);
- break;
- case AST_CONTROL_SRCUPDATE:
- break;
- default:
- ast_log(LOG_WARNING, "Don't know how to display condition %d on %s\n", cond, chan->name);
- res = -1;
- }
-
- if (res > -1) {
- if (write(sndcmd[1], &res, sizeof(res)) < 0) {
- ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
- }
- }
-
- ast_mutex_unlock(&alsalock);
-
- return res;
-}
-
-static struct ast_channel *alsa_new(struct chan_alsa_pvt *p, int state)
-{
- struct ast_channel *tmp = NULL;
-
- if (!(tmp = ast_channel_alloc(1, state, 0, 0, "", p->exten, p->context, 0, "ALSA/%s", indevname)))
- return NULL;
-
- tmp->tech = &alsa_tech;
- tmp->fds[0] = readdev;
- tmp->nativeformats = AST_FORMAT_SLINEAR;
- tmp->readformat = AST_FORMAT_SLINEAR;
- tmp->writeformat = AST_FORMAT_SLINEAR;
- tmp->tech_pvt = p;
- if (!ast_strlen_zero(p->context))
- ast_copy_string(tmp->context, p->context, sizeof(tmp->context));
- if (!ast_strlen_zero(p->exten))
- ast_copy_string(tmp->exten, p->exten, sizeof(tmp->exten));
- if (!ast_strlen_zero(language))
- ast_string_field_set(tmp, language, language);
- p->owner = tmp;
- ast_module_ref(ast_module_info->self);
- ast_jb_configure(tmp, &global_jbconf);
- if (state != AST_STATE_DOWN) {
- if (ast_pbx_start(tmp)) {
- ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
- ast_hangup(tmp);
- tmp = NULL;
- }
- }
-
- return tmp;
-}
-
-static struct ast_channel *alsa_request(const char *type, int format, void *data, int *cause)
-{
- int oldformat = format;
- struct ast_channel *tmp = NULL;
-
- format &= AST_FORMAT_SLINEAR;
- if (!format) {
- ast_log(LOG_NOTICE, "Asked to get a channel of format '%d'\n", oldformat);
- return NULL;
- }
-
- ast_mutex_lock(&alsalock);
-
- if (alsa.owner) {
- ast_log(LOG_NOTICE, "Already have a call on the ALSA channel\n");
- *cause = AST_CAUSE_BUSY;
- } else if (!(tmp = alsa_new(&alsa, AST_STATE_DOWN)))
- ast_log(LOG_WARNING, "Unable to create new ALSA channel\n");
-
- ast_mutex_unlock(&alsalock);
-
- return tmp;
-}
-
-static int console_autoanswer_deprecated(int fd, int argc, char *argv[])
-{
- int res = RESULT_SUCCESS;
-
- if ((argc != 1) && (argc != 2))
- return RESULT_SHOWUSAGE;
-
- ast_mutex_lock(&alsalock);
-
- if (argc == 1) {
- ast_cli(fd, "Auto answer is %s.\n", autoanswer ? "on" : "off");
- } else {
- if (!strcasecmp(argv[1], "on"))
- autoanswer = -1;
- else if (!strcasecmp(argv[1], "off"))
- autoanswer = 0;
- else
- res = RESULT_SHOWUSAGE;
- }
-
- ast_mutex_unlock(&alsalock);
-
- return res;
-}
-
-static int console_autoanswer(int fd, int argc, char *argv[])
-{
- int res = RESULT_SUCCESS;;
- if ((argc != 2) && (argc != 3))
- return RESULT_SHOWUSAGE;
- ast_mutex_lock(&alsalock);
- if (argc == 2) {
- ast_cli(fd, "Auto answer is %s.\n", autoanswer ? "on" : "off");
- } else {
- if (!strcasecmp(argv[2], "on"))
- autoanswer = -1;
- else if (!strcasecmp(argv[2], "off"))
- autoanswer = 0;
- else
- res = RESULT_SHOWUSAGE;
- }
- ast_mutex_unlock(&alsalock);
- return res;
-}
-
-static char *autoanswer_complete(const char *line, const char *word, int pos, int state)
-{
-#ifndef MIN
-#define MIN(a,b) ((a) < (b) ? (a) : (b))
-#endif
- switch (state) {
- case 0:
- if (!ast_strlen_zero(word) && !strncasecmp(word, "on", MIN(strlen(word), 2)))
- return ast_strdup("on");
- case 1:
- if (!ast_strlen_zero(word) && !strncasecmp(word, "off", MIN(strlen(word), 3)))
- return ast_strdup("off");
- default:
- return NULL;
- }
- return NULL;
-}
-
-static const char autoanswer_usage[] =
- "Usage: console autoanswer [on|off]\n"
- " Enables or disables autoanswer feature. If used without\n"
- " argument, displays the current on/off status of autoanswer.\n"
- " The default value of autoanswer is in 'alsa.conf'.\n";
-
-static int console_answer_deprecated(int fd, int argc, char *argv[])
-{
- int res = RESULT_SUCCESS;
-
- if (argc != 1)
- return RESULT_SHOWUSAGE;
-
- ast_mutex_lock(&alsalock);
-
- if (!alsa.owner) {
- ast_cli(fd, "No one is calling us\n");
- res = RESULT_FAILURE;
- } else {
- hookstate = 1;
- cursound = -1;
- grab_owner();
- if (alsa.owner) {
- struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
- ast_queue_frame(alsa.owner, &f);
- ast_mutex_unlock(&alsa.owner->lock);
- }
- answer_sound();
- }
-
- snd_pcm_prepare(alsa.icard);
- snd_pcm_start(alsa.icard);
-
- ast_mutex_unlock(&alsalock);
-
- return RESULT_SUCCESS;
-}
-
-static int console_answer(int fd, int argc, char *argv[])
-{
- int res = RESULT_SUCCESS;
-
- if (argc != 2)
- return RESULT_SHOWUSAGE;
-
- ast_mutex_lock(&alsalock);
-
- if (!alsa.owner) {
- ast_cli(fd, "No one is calling us\n");
- res = RESULT_FAILURE;
- } else {
- hookstate = 1;
- cursound = -1;
- grab_owner();
- if (alsa.owner) {
- struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
- ast_queue_frame(alsa.owner, &f);
- ast_mutex_unlock(&alsa.owner->lock);
- }
- answer_sound();
- }
-
- snd_pcm_prepare(alsa.icard);
- snd_pcm_start(alsa.icard);
-
- ast_mutex_unlock(&alsalock);
-
- return RESULT_SUCCESS;
-}
-
-static char sendtext_usage[] =
- "Usage: console send text <message>\n"
- " Sends a text message for display on the remote terminal.\n";
-
-static int console_sendtext_deprecated(int fd, int argc, char *argv[])
-{
- int tmparg = 2;
- int res = RESULT_SUCCESS;
-
- if (argc < 2)
- return RESULT_SHOWUSAGE;
-
- ast_mutex_lock(&alsalock);
-
- if (!alsa.owner) {
- ast_cli(fd, "No one is calling us\n");
- res = RESULT_FAILURE;
- } else {
- struct ast_frame f = { AST_FRAME_TEXT, 0 };
- char text2send[256] = "";
- text2send[0] = '\0';
- while (tmparg < argc) {
- strncat(text2send, argv[tmparg++], sizeof(text2send) - strlen(text2send) - 1);
- strncat(text2send, " ", sizeof(text2send) - strlen(text2send) - 1);
- }
- text2send[strlen(text2send) - 1] = '\n';
- f.data = text2send;
- f.datalen = strlen(text2send) + 1;
- grab_owner();
- if (alsa.owner) {
- ast_queue_frame(alsa.owner, &f);
- f.frametype = AST_FRAME_CONTROL;
- f.subclass = AST_CONTROL_ANSWER;
- f.data = NULL;
- f.datalen = 0;
- ast_queue_frame(alsa.owner, &f);
- ast_mutex_unlock(&alsa.owner->lock);
- }
- }
-
- ast_mutex_unlock(&alsalock);
-
- return res;
-}
-
-static int console_sendtext(int fd, int argc, char *argv[])
-{
- int tmparg = 3;
- int res = RESULT_SUCCESS;
-
- if (argc < 3)
- return RESULT_SHOWUSAGE;
-
- ast_mutex_lock(&alsalock);
-
- if (!alsa.owner) {
- ast_cli(fd, "No one is calling us\n");
- res = RESULT_FAILURE;
- } else {
- struct ast_frame f = { AST_FRAME_TEXT, 0 };
- char text2send[256] = "";
- text2send[0] = '\0';
- while (tmparg < argc) {
- strncat(text2send, argv[tmparg++], sizeof(text2send) - strlen(text2send) - 1);
- strncat(text2send, " ", sizeof(text2send) - strlen(text2send) - 1);
- }
- text2send[strlen(text2send) - 1] = '\n';
- f.data = text2send;
- f.datalen = strlen(text2send) + 1;
- grab_owner();
- if (alsa.owner) {
- ast_queue_frame(alsa.owner, &f);
- f.frametype = AST_FRAME_CONTROL;
- f.subclass = AST_CONTROL_ANSWER;
- f.data = NULL;
- f.datalen = 0;
- ast_queue_frame(alsa.owner, &f);
- ast_mutex_unlock(&alsa.owner->lock);
- }
- }
-
- ast_mutex_unlock(&alsalock);
-
- return res;
-}
-
-static char answer_usage[] =
- "Usage: console answer\n"
- " Answers an incoming call on the console (ALSA) channel.\n";
-
-static int console_hangup_deprecated(int fd, int argc, char *argv[])
-{
- int res = RESULT_SUCCESS;
-
- if (argc != 1)
- return RESULT_SHOWUSAGE;
-
- cursound = -1;
-
- ast_mutex_lock(&alsalock);
-
- if (!alsa.owner && !hookstate) {
- ast_cli(fd, "No call to hangup up\n");
- res = RESULT_FAILURE;
- } else {
- hookstate = 0;
- grab_owner();
- if (alsa.owner) {
- ast_queue_hangup(alsa.owner);
- ast_mutex_unlock(&alsa.owner->lock);
- }
- }
-
- ast_mutex_unlock(&alsalock);
-
- return res;
-}
-
-static int console_hangup(int fd, int argc, char *argv[])
-{
- int res = RESULT_SUCCESS;
-
- if (argc != 2)
- return RESULT_SHOWUSAGE;
-
- cursound = -1;
-
- ast_mutex_lock(&alsalock);
-
- if (!alsa.owner && !hookstate) {
- ast_cli(fd, "No call to hangup up\n");
- res = RESULT_FAILURE;
- } else {
- hookstate = 0;
- grab_owner();
- if (alsa.owner) {
- ast_queue_hangup(alsa.owner);
- ast_mutex_unlock(&alsa.owner->lock);
- }
- }
-
- ast_mutex_unlock(&alsalock);
-
- return res;
-}
-
-static char hangup_usage[] =
- "Usage: console hangup\n"
- " Hangs up any call currently placed on the console.\n";
-
-static int console_dial_deprecated(int fd, int argc, char *argv[])
-{
- char tmp[256], *tmp2;
- char *mye, *myc;
- char *d;
- int res = RESULT_SUCCESS;
-
- if ((argc != 1) && (argc != 2))
- return RESULT_SHOWUSAGE;
-
- ast_mutex_lock(&alsalock);
-
- if (alsa.owner) {
- if (argc == 2) {
- d = argv[1];
- grab_owner();
- if (alsa.owner) {
- struct ast_frame f = { AST_FRAME_DTMF };
- while (*d) {
- f.subclass = *d;
- ast_queue_frame(alsa.owner, &f);
- d++;
- }
- ast_mutex_unlock(&alsa.owner->lock);
- }
- } else {
- ast_cli(fd, "You're already in a call. You can use this only to dial digits until you hangup\n");
- res = RESULT_FAILURE;
- }
- } else {
- mye = exten;
- myc = context;
- if (argc == 2) {
- char *stringp = NULL;
- ast_copy_string(tmp, argv[1], sizeof(tmp));
- stringp = tmp;
- strsep(&stringp, "@");
- tmp2 = strsep(&stringp, "@");
- if (!ast_strlen_zero(tmp))
- mye = tmp;
- if (!ast_strlen_zero(tmp2))
- myc = tmp2;
- }
- if (ast_exists_extension(NULL, myc, mye, 1, NULL)) {
- ast_copy_string(alsa.exten, mye, sizeof(alsa.exten));
- ast_copy_string(alsa.context, myc, sizeof(alsa.context));
- hookstate = 1;
- alsa_new(&alsa, AST_STATE_RINGING);
- } else
- ast_cli(fd, "No such extension '%s' in context '%s'\n", mye, myc);
- }
-
- ast_mutex_unlock(&alsalock);
-
- return res;
-}
-
-static int console_dial(int fd, int argc, char *argv[])
-{
- char tmp[256], *tmp2;
- char *mye, *myc;
- char *d;
- int res = RESULT_SUCCESS;
-
- if ((argc != 2) && (argc != 3))
- return RESULT_SHOWUSAGE;
-
- ast_mutex_lock(&alsalock);
-
- if (alsa.owner) {
- if (argc == 3) {
- d = argv[2];
- grab_owner();
- if (alsa.owner) {
- struct ast_frame f = { AST_FRAME_DTMF };
- while (*d) {
- f.subclass = *d;
- ast_queue_frame(alsa.owner, &f);
- d++;
- }
- ast_mutex_unlock(&alsa.owner->lock);
- }
- } else {
- ast_cli(fd, "You're already in a call. You can use this only to dial digits until you hangup\n");
- res = RESULT_FAILURE;
- }
- } else {
- mye = exten;
- myc = context;
- if (argc == 3) {
- char *stringp = NULL;
- ast_copy_string(tmp, argv[2], sizeof(tmp));
- stringp = tmp;
- strsep(&stringp, "@");
- tmp2 = strsep(&stringp, "@");
- if (!ast_strlen_zero(tmp))
- mye = tmp;
- if (!ast_strlen_zero(tmp2))
- myc = tmp2;
- }
- if (ast_exists_extension(NULL, myc, mye, 1, NULL)) {
- ast_copy_string(alsa.exten, mye, sizeof(alsa.exten));
- ast_copy_string(alsa.context, myc, sizeof(alsa.context));
- hookstate = 1;
- alsa_new(&alsa, AST_STATE_RINGING);
- } else
- ast_cli(fd, "No such extension '%s' in context '%s'\n", mye, myc);
- }
-
- ast_mutex_unlock(&alsalock);
-
- return res;
-}
-
-static char dial_usage[] =
- "Usage: console dial [extension[@context]]\n"
- " Dials a given extension (and context if specified)\n";
-
-static struct ast_cli_entry cli_alsa_answer_deprecated = {
- { "answer", NULL },
- console_answer_deprecated, NULL,
- NULL };
-
-static struct ast_cli_entry cli_alsa_hangup_deprecated = {
- { "hangup", NULL },
- console_hangup_deprecated, NULL,
- NULL };
-
-static struct ast_cli_entry cli_alsa_dial_deprecated = {
- { "dial", NULL },
- console_dial_deprecated, NULL,
- NULL };
-
-static struct ast_cli_entry cli_alsa_send_text_deprecated = {
- { "send", "text", NULL },
- console_sendtext_deprecated, NULL,
- NULL };
-
-static struct ast_cli_entry cli_alsa_autoanswer_deprecated = {
- { "autoanswer", NULL },
- console_autoanswer_deprecated, NULL,
- NULL, autoanswer_complete };
-
-static struct ast_cli_entry cli_alsa[] = {
- { { "console", "answer", NULL },
- console_answer, "Answer an incoming console call",
- answer_usage, NULL, &cli_alsa_answer_deprecated },
-
- { { "console", "hangup", NULL },
- console_hangup, "Hangup a call on the console",
- hangup_usage, NULL, &cli_alsa_hangup_deprecated },
-
- { { "console", "dial", NULL },
- console_dial, "Dial an extension on the console",
- dial_usage, NULL, &cli_alsa_dial_deprecated },
-
- { { "console", "send", "text", NULL },
- console_sendtext, "Send text to the remote device",
- sendtext_usage, NULL, &cli_alsa_send_text_deprecated },
-
- { { "console", "autoanswer", NULL },
- console_autoanswer, "Sets/displays autoanswer",
- autoanswer_usage, autoanswer_complete, &cli_alsa_autoanswer_deprecated },
-};
-
-static int load_module(void)
-{
- int res;
- struct ast_config *cfg;
- struct ast_variable *v;
-
- /* Copy the default jb config over global_jbconf */
- memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
-
- strcpy(mohinterpret, "default");
-
- if ((cfg = ast_config_load(config))) {
- v = ast_variable_browse(cfg, "general");
- for (; v; v = v->next) {
- /* handle jb conf */
- if (!ast_jb_read_conf(&global_jbconf, v->name, v->value))
- continue;
-
- if (!strcasecmp(v->name, "autoanswer"))
- autoanswer = ast_true(v->value);
- else if (!strcasecmp(v->name, "silencesuppression"))
- silencesuppression = ast_true(v->value);
- else if (!strcasecmp(v->name, "silencethreshold"))
- silencethreshold = atoi(v->value);
- else if (!strcasecmp(v->name, "context"))
- ast_copy_string(context, v->value, sizeof(context));
- else if (!strcasecmp(v->name, "language"))
- ast_copy_string(language, v->value, sizeof(language));
- else if (!strcasecmp(v->name, "extension"))
- ast_copy_string(exten, v->value, sizeof(exten));
- else if (!strcasecmp(v->name, "input_device"))
- ast_copy_string(indevname, v->value, sizeof(indevname));
- else if (!strcasecmp(v->name, "output_device"))
- ast_copy_string(outdevname, v->value, sizeof(outdevname));
- else if (!strcasecmp(v->name, "mohinterpret"))
- ast_copy_string(mohinterpret, v->value, sizeof(mohinterpret));
- }
- ast_config_destroy(cfg);
- }
- res = pipe(sndcmd);
- if (res) {
- ast_log(LOG_ERROR, "Unable to create pipe\n");
- return -1;
- }
- res = soundcard_init();
- if (res < 0) {
- if (option_verbose > 1) {
- ast_verbose(VERBOSE_PREFIX_2 "No sound card detected -- console channel will be unavailable\n");
- ast_verbose(VERBOSE_PREFIX_2 "Turn off ALSA support by adding 'noload=chan_alsa.so' in /etc/asterisk/modules.conf\n");
- }
- return 0;
- }
-
- res = ast_channel_register(&alsa_tech);
- if (res < 0) {
- ast_log(LOG_ERROR, "Unable to register channel class 'Console'\n");
- return -1;
- }
- ast_cli_register_multiple(cli_alsa, sizeof(cli_alsa) / sizeof(struct ast_cli_entry));
-
- ast_pthread_create_background(&sthread, NULL, sound_thread, NULL);
-#ifdef ALSA_MONITOR
- if (alsa_monitor_start())
- ast_log(LOG_ERROR, "Problem starting Monitoring\n");
-#endif
- return 0;
-}
-
-static int unload_module(void)
-{
- ast_channel_unregister(&alsa_tech);
- ast_cli_unregister_multiple(cli_alsa, sizeof(cli_alsa) / sizeof(struct ast_cli_entry));
-
- if (alsa.icard)
- snd_pcm_close(alsa.icard);
- if (alsa.ocard)
- snd_pcm_close(alsa.ocard);
- if (sndcmd[0] > 0) {
- close(sndcmd[0]);
- close(sndcmd[1]);
- }
- if (alsa.owner)
- ast_softhangup(alsa.owner, AST_SOFTHANGUP_APPUNLOAD);
- if (alsa.owner)
- return -1;
- return 0;
-}
-
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "ALSA Console Channel Driver");
diff --git a/1.4.23-rc4/channels/chan_dahdi.c b/1.4.23-rc4/channels/chan_dahdi.c
deleted file mode 100644
index 81498b372..000000000
--- a/1.4.23-rc4/channels/chan_dahdi.c
+++ /dev/null
@@ -1,11992 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 1999 - 2006, Digium, Inc.
- *
- * Mark Spencer <markster@digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief DAHDI Pseudo TDM interface
- *
- * \author Mark Spencer <markster@digium.com>
- *
- * Connects to the DAHDI telephony library as well as
- * libpri. Libpri is optional and needed only if you are
- * going to use ISDN connections.
- *
- * You need to install libraries before you attempt to compile
- * and install the DAHDI channel.
- *
- * \par See also
- * \arg \ref Config_dahdi
- *
- * \ingroup channel_drivers
- *
- * \todo Deprecate the "musiconhold" configuration option post 1.4
- */
-
-/*** MODULEINFO
- <depend>res_smdi</depend>
- <depend>dahdi</depend>
- <depend>tonezone</depend>
- <depend>res_features</depend>
- <use>pri</use>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
-#include <stdio.h>
-#include <string.h>
-#ifdef __NetBSD__
-#include <pthread.h>
-#include <signal.h>
-#else
-#include <sys/signal.h>
-#endif
-#include <errno.h>
-#include <stdlib.h>
-#if !defined(SOLARIS) && !defined(__FreeBSD__)
-#include <stdint.h>
-#endif
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <math.h>
-#include <ctype.h>
-
-#ifdef HAVE_PRI
-#include <libpri.h>
-#endif
-
-#include "asterisk/lock.h"
-#include "asterisk/channel.h"
-#include "asterisk/config.h"
-#include "asterisk/logger.h"
-#include "asterisk/module.h"
-#include "asterisk/pbx.h"
-#include "asterisk/options.h"
-#include "asterisk/file.h"
-#include "asterisk/ulaw.h"
-#include "asterisk/alaw.h"
-#include "asterisk/callerid.h"
-#include "asterisk/adsi.h"
-#include "asterisk/cli.h"
-#include "asterisk/cdr.h"
-#include "asterisk/features.h"
-#include "asterisk/musiconhold.h"
-#include "asterisk/say.h"
-#include "asterisk/tdd.h"
-#include "asterisk/app.h"
-#include "asterisk/dsp.h"
-#include "asterisk/astdb.h"
-#include "asterisk/manager.h"
-#include "asterisk/causes.h"
-#include "asterisk/term.h"
-#include "asterisk/utils.h"
-#include "asterisk/transcap.h"
-#include "asterisk/stringfields.h"
-#include "asterisk/abstract_jb.h"
-#include "asterisk/smdi.h"
-#include "asterisk/astobj.h"
-#define SMDI_MD_WAIT_TIMEOUT 1500 /* 1.5 seconds */
-
-#include "asterisk/dahdi_compat.h"
-#include "asterisk/tonezone_compat.h"
-
-/*! Global jitterbuffer configuration - by default, jb is disabled */
-static struct ast_jb_conf default_jbconf =
-{
- .flags = 0,
- .max_size = -1,
- .resync_threshold = -1,
- .impl = ""
-};
-static struct ast_jb_conf global_jbconf;
-
-#ifndef DAHDI_TONEDETECT
-/* Work around older code with no tone detect */
-#define DAHDI_EVENT_DTMFDOWN 0
-#define DAHDI_EVENT_DTMFUP 0
-#endif
-
-/* define this to send PRI user-user information elements */
-#undef SUPPORT_USERUSER
-
-/*!
- * \note Define ZHONE_HACK to cause us to go off hook and then back on hook when
- * the user hangs up to reset the state machine so ring works properly.
- * This is used to be able to support kewlstart by putting the zhone in
- * groundstart mode since their forward disconnect supervision is entirely
- * broken even though their documentation says it isn't and their support
- * is entirely unwilling to provide any assistance with their channel banks
- * even though their web site says they support their products for life.
- */
-/* #define ZHONE_HACK */
-
-/*! \note
- * Define if you want to check the hook state for an FXO (FXS signalled) interface
- * before dialing on it. Certain FXO interfaces always think they're out of
- * service with this method however.
- */
-/* #define DAHDI_CHECK_HOOKSTATE */
-
-/*! \brief Typically, how many rings before we should send Caller*ID */
-#define DEFAULT_CIDRINGS 1
-
-#define CHANNEL_PSEUDO -12
-
-#define AST_LAW(p) (((p)->law == DAHDI_LAW_ALAW) ? AST_FORMAT_ALAW : AST_FORMAT_ULAW)
-
-/*! \brief Signaling types that need to use MF detection should be placed in this macro */
-#define NEED_MFDETECT(p) (((p)->sig == SIG_FEATDMF) || ((p)->sig == SIG_FEATDMF_TA) || ((p)->sig == SIG_E911) || ((p)->sig == SIG_FGC_CAMA) || ((p)->sig == SIG_FGC_CAMAMF) || ((p)->sig == SIG_FEATB))
-
-static const char tdesc[] = "DAHDI Telephony Driver"
-#ifdef HAVE_PRI
- " w/PRI"
-#endif
-;
-
-#define SIG_EM DAHDI_SIG_EM
-#define SIG_EMWINK (0x0100000 | DAHDI_SIG_EM)
-#define SIG_FEATD (0x0200000 | DAHDI_SIG_EM)
-#define SIG_FEATDMF (0x0400000 | DAHDI_SIG_EM)
-#define SIG_FEATB (0x0800000 | DAHDI_SIG_EM)
-#define SIG_E911 (0x1000000 | DAHDI_SIG_EM)
-#define SIG_FEATDMF_TA (0x2000000 | DAHDI_SIG_EM)
-#define SIG_FGC_CAMA (0x4000000 | DAHDI_SIG_EM)
-#define SIG_FGC_CAMAMF (0x8000000 | DAHDI_SIG_EM)
-#define SIG_FXSLS DAHDI_SIG_FXSLS
-#define SIG_FXSGS DAHDI_SIG_FXSGS
-#define SIG_FXSKS DAHDI_SIG_FXSKS
-#define SIG_FXOLS DAHDI_SIG_FXOLS
-#define SIG_FXOGS DAHDI_SIG_FXOGS
-#define SIG_FXOKS DAHDI_SIG_FXOKS
-#define SIG_PRI DAHDI_SIG_CLEAR
-#define SIG_SF DAHDI_SIG_SF
-#define SIG_SFWINK (0x0100000 | DAHDI_SIG_SF)
-#define SIG_SF_FEATD (0x0200000 | DAHDI_SIG_SF)
-#define SIG_SF_FEATDMF (0x0400000 | DAHDI_SIG_SF)
-#define SIG_SF_FEATB (0x0800000 | DAHDI_SIG_SF)
-#define SIG_EM_E1 DAHDI_SIG_EM_E1
-#define SIG_GR303FXOKS (0x0100000 | DAHDI_SIG_FXOKS)
-#define SIG_GR303FXSKS (0x0100000 | DAHDI_SIG_FXSKS)
-
-#define NUM_SPANS 32
-#define NUM_DCHANS 4 /*!< No more than 4 d-channels */
-#define MAX_CHANNELS 672 /*!< No more than a DS3 per trunk group */
-
-#define CHAN_PSEUDO -2
-
-#define DCHAN_PROVISIONED (1 << 0)
-#define DCHAN_NOTINALARM (1 << 1)
-#define DCHAN_UP (1 << 2)
-
-#define DCHAN_AVAILABLE (DCHAN_PROVISIONED | DCHAN_NOTINALARM | DCHAN_UP)
-
-static char defaultcic[64] = "";
-static char defaultozz[64] = "";
-
-static char progzone[10] = "";
-
-static int distinctiveringaftercid = 0;
-
-static int numbufs = 4;
-
-#ifdef HAVE_PRI
-static struct ast_channel inuse;
-#ifdef PRI_GETSET_TIMERS
-static int pritimers[PRI_MAX_TIMERS];
-#endif
-static int pridebugfd = -1;
-static char pridebugfilename[1024] = "";
-#endif
-
-/*! \brief Wait up to 16 seconds for first digit (FXO logic) */
-static int firstdigittimeout = 16000;
-
-/*! \brief How long to wait for following digits (FXO logic) */
-static int gendigittimeout = 8000;
-
-/*! \brief How long to wait for an extra digit, if there is an ambiguous match */
-static int matchdigittimeout = 3000;
-
-/*! \brief Protect the interface list (of dahdi_pvt's) */
-AST_MUTEX_DEFINE_STATIC(iflock);
-
-
-static int ifcount = 0;
-
-#ifdef HAVE_PRI
-AST_MUTEX_DEFINE_STATIC(pridebugfdlock);
-#endif
-
-/*! \brief Protect the monitoring thread, so only one process can kill or start it, and not
- when it's doing something critical. */
-AST_MUTEX_DEFINE_STATIC(monlock);
-
-/*! \brief This is the thread for the monitor which checks for input on the channels
- which are not currently in use. */
-static pthread_t monitor_thread = AST_PTHREADT_NULL;
-static ast_cond_t ss_thread_complete;
-AST_MUTEX_DEFINE_STATIC(ss_thread_lock);
-AST_MUTEX_DEFINE_STATIC(restart_lock);
-static int ss_thread_count = 0;
-static int num_restart_pending = 0;
-
-static int restart_monitor(void);
-
-static enum ast_bridge_result dahdi_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms);
-
-static int dahdi_sendtext(struct ast_channel *c, const char *text);
-
-/*! \brief Avoid the silly dahdi_getevent which ignores a bunch of events */
-static inline int dahdi_get_event(int fd)
-{
- int j;
- if (ioctl(fd, DAHDI_GETEVENT, &j) == -1)
- return -1;
- return j;
-}
-
-/*! \brief Avoid the silly dahdi_waitevent which ignores a bunch of events */
-static inline int dahdi_wait_event(int fd)
-{
- int i, j = 0;
- i = DAHDI_IOMUX_SIGEVENT;
- if (ioctl(fd, DAHDI_IOMUX, &i) == -1)
- return -1;
- if (ioctl(fd, DAHDI_GETEVENT, &j) == -1)
- return -1;
- return j;
-}
-
-/*! Chunk size to read -- we use 20ms chunks to make things happy. */
-#define READ_SIZE 160
-
-#define MASK_AVAIL (1 << 0) /*!< Channel available for PRI use */
-#define MASK_INUSE (1 << 1) /*!< Channel currently in use */
-
-#define CALLWAITING_SILENT_SAMPLES ( (300 * 8) / READ_SIZE) /*!< 300 ms */
-#define CALLWAITING_REPEAT_SAMPLES ( (10000 * 8) / READ_SIZE) /*!< 10,000 ms */
-#define CIDCW_EXPIRE_SAMPLES ( (500 * 8) / READ_SIZE) /*!< 500 ms */
-#define MIN_MS_SINCE_FLASH ( (2000) ) /*!< 2000 ms */
-#define DEFAULT_RINGT ( (8000 * 8) / READ_SIZE) /*!< 8,000 ms */
-
-struct dahdi_pvt;
-
-static int ringt_base = DEFAULT_RINGT;
-
-#ifdef HAVE_PRI
-
-#define PVT_TO_CHANNEL(p) (((p)->prioffset) | ((p)->logicalspan << 8) | (p->pri->mastertrunkgroup ? 0x10000 : 0))
-#define PRI_CHANNEL(p) ((p) & 0xff)
-#define PRI_SPAN(p) (((p) >> 8) & 0xff)
-#define PRI_EXPLICIT(p) (((p) >> 16) & 0x01)
-
-struct dahdi_pri {
- pthread_t master; /*!< Thread of master */
- ast_mutex_t lock; /*!< Mutex */
- char idleext[AST_MAX_EXTENSION]; /*!< Where to idle extra calls */
- char idlecontext[AST_MAX_CONTEXT]; /*!< What context to use for idle */
- char idledial[AST_MAX_EXTENSION]; /*!< What to dial before dumping */
- int minunused; /*!< Min # of channels to keep empty */
- int minidle; /*!< Min # of "idling" calls to keep active */
- int nodetype; /*!< Node type */
- int switchtype; /*!< Type of switch to emulate */
- int nsf; /*!< Network-Specific Facilities */
- int dialplan; /*!< Dialing plan */
- int localdialplan; /*!< Local dialing plan */
- char internationalprefix[10]; /*!< country access code ('00' for european dialplans) */
- char nationalprefix[10]; /*!< area access code ('0' for european dialplans) */
- char localprefix[20]; /*!< area access code + area code ('0'+area code for european dialplans) */
- char privateprefix[20]; /*!< for private dialplans */
- char unknownprefix[20]; /*!< for unknown dialplans */
- int dchannels[NUM_DCHANS]; /*!< What channel are the dchannels on */
- int trunkgroup; /*!< What our trunkgroup is */
- int mastertrunkgroup; /*!< What trunk group is our master */
- int prilogicalspan; /*!< Logical span number within trunk group */
- int numchans; /*!< Num of channels we represent */
- int overlapdial; /*!< In overlap dialing mode */
- int facilityenable; /*!< Enable facility IEs */
- struct pri *dchans[NUM_DCHANS]; /*!< Actual d-channels */
- int dchanavail[NUM_DCHANS]; /*!< Whether each channel is available */
- struct pri *pri; /*!< Currently active D-channel */
- int debug;
- int fds[NUM_DCHANS]; /*!< FD's for d-channels */
- int offset;
- int span;
- int resetting;
- int resetpos;
-#ifdef HAVE_PRI_INBANDDISCONNECT
- unsigned int inbanddisconnect:1; /*!< Should we support inband audio after receiving DISCONNECT? */
-#endif
- time_t lastreset; /*!< time when unused channels were last reset */
- long resetinterval; /*!< Interval (in seconds) for resetting unused channels */
- struct dahdi_pvt *pvts[MAX_CHANNELS]; /*!< Member channel pvt structs */
- struct dahdi_pvt *crvs; /*!< Member CRV structs */
- struct dahdi_pvt *crvend; /*!< Pointer to end of CRV structs */
-};
-
-
-static struct dahdi_pri pris[NUM_SPANS];
-
-#if 0
-#define DEFAULT_PRI_DEBUG (PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q921_DUMP | PRI_DEBUG_Q921_RAW | PRI_DEBUG_Q921_STATE)
-#else
-#define DEFAULT_PRI_DEBUG 0
-#endif
-
-static inline void pri_rel(struct dahdi_pri *pri)
-{
- ast_mutex_unlock(&pri->lock);
-}
-
-#else
-/*! Shut up the compiler */
-struct dahdi_pri;
-#endif
-
-#define SUB_REAL 0 /*!< Active call */
-#define SUB_CALLWAIT 1 /*!< Call-Waiting call on hold */
-#define SUB_THREEWAY 2 /*!< Three-way call */
-
-/* Polarity states */
-#define POLARITY_IDLE 0
-#define POLARITY_REV 1
-
-
-static struct dahdi_distRings drings;
-
-struct distRingData {
- int ring[3];
-};
-struct ringContextData {
- char contextData[AST_MAX_CONTEXT];
-};
-struct dahdi_distRings {
- struct distRingData ringnum[3];
- struct ringContextData ringContext[3];
-};
-
-static char *subnames[] = {
- "Real",
- "Callwait",
- "Threeway"
-};
-
-struct dahdi_subchannel {
- int dfd;
- struct ast_channel *owner;
- int chan;
- short buffer[AST_FRIENDLY_OFFSET/2 + READ_SIZE];
- struct ast_frame f; /*!< One frame for each channel. How did this ever work before? */
- unsigned int needringing:1;
- unsigned int needbusy:1;
- unsigned int needcongestion:1;
- unsigned int needcallerid:1;
- unsigned int needanswer:1;
- unsigned int needflash:1;
- unsigned int needhold:1;
- unsigned int needunhold:1;
- unsigned int linear:1;
- unsigned int inthreeway:1;
- struct dahdi_confinfo curconf;
-};
-
-#define CONF_USER_REAL (1 << 0)
-#define CONF_USER_THIRDCALL (1 << 1)
-
-#define MAX_SLAVES 4
-
-static struct dahdi_pvt {
- ast_mutex_t lock;
- struct ast_channel *owner; /*!< Our current active owner (if applicable) */
- /*!< Up to three channels can be associated with this call */
-
- struct dahdi_subchannel sub_unused; /*!< Just a safety precaution */
- struct dahdi_subchannel subs[3]; /*!< Sub-channels */
- struct dahdi_confinfo saveconf; /*!< Saved conference info */
-
- struct dahdi_pvt *slaves[MAX_SLAVES]; /*!< Slave to us (follows our conferencing) */
- struct dahdi_pvt *master; /*!< Master to us (we follow their conferencing) */
- int inconference; /*!< If our real should be in the conference */
-
- int buf_no; /*!< Number of buffers */
- int buf_policy; /*!< Buffer policy */
- int sig; /*!< Signalling style */
- int radio; /*!< radio type */
- int outsigmod; /*!< Outbound Signalling style (modifier) */
- int oprmode; /*!< "Operator Services" mode */
- struct dahdi_pvt *oprpeer; /*!< "Operator Services" peer tech_pvt ptr */
- float rxgain;
- float txgain;
- int tonezone; /*!< tone zone for this chan, or -1 for default */
- struct dahdi_pvt *next; /*!< Next channel in list */
- struct dahdi_pvt *prev; /*!< Prev channel in list */
-
- /* flags */
- unsigned int adsi:1;
- unsigned int answeronpolarityswitch:1;
- unsigned int busydetect:1;
- unsigned int callreturn:1;
- unsigned int callwaiting:1;
- unsigned int callwaitingcallerid:1;
- unsigned int cancallforward:1;
- unsigned int canpark:1;
- unsigned int confirmanswer:1; /*!< Wait for '#' to confirm answer */
- unsigned int destroy:1;
- unsigned int didtdd:1; /*!< flag to say its done it once */
- unsigned int dialednone:1;
- unsigned int dialing:1;
- unsigned int digital:1;
- unsigned int dnd:1;
- unsigned int echobreak:1;
- unsigned int echocanbridged:1;
- unsigned int echocanon:1;
- unsigned int faxhandled:1; /*!< Has a fax tone already been handled? */
- unsigned int firstradio:1;
- unsigned int hanguponpolarityswitch:1;
- unsigned int hardwaredtmf:1;
- unsigned int hidecallerid:1;
- unsigned int hidecalleridname:1; /*!< Hide just the name not the number for legacy PBX use */
- unsigned int ignoredtmf:1;
- unsigned int immediate:1; /*!< Answer before getting digits? */
- unsigned int inalarm:1;
- unsigned int unknown_alarm:1;
- unsigned int mate:1; /*!< flag to say its in MATE mode */
- unsigned int outgoing:1;
- unsigned int overlapdial:1;
- unsigned int permcallwaiting:1;
- unsigned int permhidecallerid:1; /*!< Whether to hide our outgoing caller ID or not */
- unsigned int priindication_oob:1;
- unsigned int priexclusive:1;
- unsigned int pulse:1;
- unsigned int pulsedial:1; /*!< whether a pulse dial phone is detected */
- unsigned int restartpending:1; /*!< flag to ensure counted only once for restart */
- unsigned int restrictcid:1; /*!< Whether restrict the callerid -> only send ANI */
- unsigned int threewaycalling:1;
- unsigned int transfer:1;
- unsigned int use_callerid:1; /*!< Whether or not to use caller id on this channel */
- unsigned int use_callingpres:1; /*!< Whether to use the callingpres the calling switch sends */
- unsigned int usedistinctiveringdetection:1;
- unsigned int dahditrcallerid:1; /*!< should we use the callerid from incoming call on dahdi transfer or not */
- unsigned int transfertobusy:1; /*!< allow flash-transfers to busy channels */
-#if defined(HAVE_PRI)
- unsigned int alerting:1;
- unsigned int alreadyhungup:1;
- unsigned int isidlecall:1;
- unsigned int proceeding:1;
- unsigned int progress:1;
- unsigned int resetting:1;
- unsigned int setup_ack:1;
-#endif
- unsigned int use_smdi:1; /* Whether to use SMDI on this channel */
- struct ast_smdi_interface *smdi_iface; /* The serial port to listen for SMDI data on */
-
- struct dahdi_distRings drings;
-
- char context[AST_MAX_CONTEXT];
- char defcontext[AST_MAX_CONTEXT];
- char exten[AST_MAX_EXTENSION];
- char language[MAX_LANGUAGE];
- char mohinterpret[MAX_MUSICCLASS];
- char mohsuggest[MAX_MUSICCLASS];
-#ifdef PRI_ANI
- char cid_ani[AST_MAX_EXTENSION];
-#endif
- char cid_num[AST_MAX_EXTENSION];
- int cid_ton; /*!< Type Of Number (TON) */
- char cid_name[AST_MAX_EXTENSION];
- char lastcid_num[AST_MAX_EXTENSION];
- char lastcid_name[AST_MAX_EXTENSION];
- char *origcid_num; /*!< malloced original callerid */
- char *origcid_name; /*!< malloced original callerid */
- char callwait_num[AST_MAX_EXTENSION];
- char callwait_name[AST_MAX_EXTENSION];
- char rdnis[AST_MAX_EXTENSION];
- char dnid[AST_MAX_EXTENSION];
- ast_group_t group;
- int law;
- int confno; /*!< Our conference */
- int confusers; /*!< Who is using our conference */
- int propconfno; /*!< Propagated conference number */
- ast_group_t callgroup;
- ast_group_t pickupgroup;
- int channel; /*!< Channel Number or CRV */
- int span; /*!< Span number */
- time_t guardtime; /*!< Must wait this much time before using for new call */
- int cid_signalling; /*!< CID signalling type bell202 or v23 */
- int cid_start; /*!< CID start indicator, polarity or ring */
- int callingpres; /*!< The value of callling presentation that we're going to use when placing a PRI call */
- int callwaitingrepeat; /*!< How many samples to wait before repeating call waiting */
- int cidcwexpire; /*!< When to expire our muting for CID/CW */
- unsigned char *cidspill;
- int cidpos;
- int cidlen;
- int ringt;
- int ringt_base;
- int stripmsd;
- int callwaitcas;
- int callwaitrings;
- int echocancel;
- int echotraining;
- char echorest[20];
- int busycount;
- int busy_tonelength;
- int busy_quietlength;
- int callprogress;
- struct timeval flashtime; /*!< Last flash-hook time */
- struct ast_dsp *dsp;
- int cref; /*!< Call reference number */
- struct dahdi_dialoperation dop;
- int whichwink; /*!< SIG_FEATDMF_TA Which wink are we on? */
- char finaldial[64];
- char accountcode[AST_MAX_ACCOUNT_CODE]; /*!< Account code */
- int amaflags; /*!< AMA Flags */
- struct tdd_state *tdd; /*!< TDD flag */
- char call_forward[AST_MAX_EXTENSION];
- char mailbox[AST_MAX_EXTENSION];
- char dialdest[256];
- int onhooktime;
- int msgstate;
- int distinctivering; /*!< Which distinctivering to use */
- int cidrings; /*!< Which ring to deliver CID on */
- int dtmfrelax; /*!< whether to run in relaxed DTMF mode */
- int fake_event;
- int polarityonanswerdelay;
- struct timeval polaritydelaytv;
- int sendcalleridafter;
-#ifdef HAVE_PRI
- struct dahdi_pri *pri;
- struct dahdi_pvt *bearer;
- struct dahdi_pvt *realcall;
- q931_call *call;
- int prioffset;
- int logicalspan;
-#endif
- int polarity;
- int dsp_features;
- char begindigit;
-} *iflist = NULL, *ifend = NULL;
-
-/*! \brief Channel configuration from chan_dahdi.conf .
- * This struct is used for parsing the [channels] section of chan_dahdi.conf.
- * Generally there is a field here for every possible configuration item.
- *
- * The state of fields is saved along the parsing and whenever a 'channel'
- * statement is reached, the current dahdi_chan_conf is used to configure the
- * channel (struct dahdi_pvt)
- *
- * @seealso dahdi_chan_init for the default values.
- */
-struct dahdi_chan_conf {
- struct dahdi_pvt chan;
-#ifdef HAVE_PRI
- struct dahdi_pri pri;
-#endif
- struct dahdi_params timing;
-
- char smdi_port[SMDI_MAX_FILENAME_LEN];
-};
-
-/** returns a new dahdi_chan_conf with default values (by-value) */
-static struct dahdi_chan_conf dahdi_chan_conf_default(void) {
- /* recall that if a field is not included here it is initialized
- * to 0 or equivalent
- */
- struct dahdi_chan_conf conf = {
-#ifdef HAVE_PRI
- .pri = {
- .nsf = PRI_NSF_NONE,
- .switchtype = PRI_SWITCH_NI2,
- .dialplan = PRI_NATIONAL_ISDN + 1,
- .localdialplan = PRI_NATIONAL_ISDN + 1,
- .nodetype = PRI_CPE,
-
- .minunused = 2,
- .idleext = "",
- .idledial = "",
- .internationalprefix = "",
- .nationalprefix = "",
- .localprefix = "",
- .privateprefix = "",
- .unknownprefix = "",
-
- .resetinterval = 3600
- },
-#endif
- .chan = {
- .context = "default",
- .cid_num = "",
- .cid_name = "",
- .mohinterpret = "default",
- .mohsuggest = "",
- .transfertobusy = 1,
-
- .cid_signalling = CID_SIG_BELL,
- .cid_start = CID_START_RING,
- .dahditrcallerid = 0,
- .use_callerid = 1,
- .sig = -1,
- .outsigmod = -1,
-
- .tonezone = -1,
-
- .echocancel = 1,
-
- .busycount = 3,
-
- .accountcode = "",
-
- .mailbox = "",
-
-
- .polarityonanswerdelay = 600,
-
- .sendcalleridafter = DEFAULT_CIDRINGS,
-
- .buf_policy = DAHDI_POLICY_IMMEDIATE,
- .buf_no = numbufs
- },
- .timing = {
- .prewinktime = -1,
- .preflashtime = -1,
- .winktime = -1,
- .flashtime = -1,
- .starttime = -1,
- .rxwinktime = -1,
- .rxflashtime = -1,
- .debouncetime = -1
- },
- .smdi_port = "/dev/ttyS0",
- };
-
- return conf;
-}
-
-
-static struct ast_channel *dahdi_request(const char *type, int format, void *data, int *cause);
-static int dahdi_digit_begin(struct ast_channel *ast, char digit);
-static int dahdi_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
-static int dahdi_sendtext(struct ast_channel *c, const char *text);
-static int dahdi_call(struct ast_channel *ast, char *rdest, int timeout);
-static int dahdi_hangup(struct ast_channel *ast);
-static int dahdi_answer(struct ast_channel *ast);
-static struct ast_frame *dahdi_read(struct ast_channel *ast);
-static int dahdi_write(struct ast_channel *ast, struct ast_frame *frame);
-static struct ast_frame *dahdi_exception(struct ast_channel *ast);
-static int dahdi_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen);
-static int dahdi_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
-static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int datalen);
-static int dahdi_func_read(struct ast_channel *chan, char *function, char *data, char *buf, size_t len);
-
-static const struct ast_channel_tech dahdi_tech = {
- .type = "DAHDI",
- .description = tdesc,
- .capabilities = AST_FORMAT_SLINEAR | AST_FORMAT_ULAW | AST_FORMAT_ALAW,
- .requester = dahdi_request,
- .send_digit_begin = dahdi_digit_begin,
- .send_digit_end = dahdi_digit_end,
- .send_text = dahdi_sendtext,
- .call = dahdi_call,
- .hangup = dahdi_hangup,
- .answer = dahdi_answer,
- .read = dahdi_read,
- .write = dahdi_write,
- .bridge = dahdi_bridge,
- .exception = dahdi_exception,
- .indicate = dahdi_indicate,
- .fixup = dahdi_fixup,
- .setoption = dahdi_setoption,
- .func_channel_read = dahdi_func_read,
-};
-
-static const struct ast_channel_tech zap_tech = {
- .type = "Zap",
- .description = tdesc,
- .capabilities = AST_FORMAT_SLINEAR | AST_FORMAT_ULAW | AST_FORMAT_ALAW,
- .requester = dahdi_request,
- .send_digit_begin = dahdi_digit_begin,
- .send_digit_end = dahdi_digit_end,
- .send_text = dahdi_sendtext,
- .call = dahdi_call,
- .hangup = dahdi_hangup,
- .answer = dahdi_answer,
- .read = dahdi_read,
- .write = dahdi_write,
- .bridge = dahdi_bridge,
- .exception = dahdi_exception,
- .indicate = dahdi_indicate,
- .fixup = dahdi_fixup,
- .setoption = dahdi_setoption,
- .func_channel_read = dahdi_func_read,
-};
-
-static const struct ast_channel_tech *chan_tech;
-
-#ifdef HAVE_PRI
-#define GET_CHANNEL(p) ((p)->bearer ? (p)->bearer->channel : p->channel)
-#else
-#define GET_CHANNEL(p) ((p)->channel)
-#endif
-
-struct dahdi_pvt *round_robin[32];
-
-#ifdef HAVE_PRI
-static inline int pri_grab(struct dahdi_pvt *pvt, struct dahdi_pri *pri)
-{
- int res;
- /* Grab the lock first */
- do {
- res = ast_mutex_trylock(&pri->lock);
- if (res) {
- DEADLOCK_AVOIDANCE(&pvt->lock);
- }
- } while (res);
- /* Then break the poll */
- if (pri->master != AST_PTHREADT_NULL)
- pthread_kill(pri->master, SIGURG);
- return 0;
-}
-#endif
-
-#define NUM_CADENCE_MAX 25
-static int num_cadence = 4;
-static int user_has_defined_cadences = 0;
-
-static struct dahdi_ring_cadence cadences[NUM_CADENCE_MAX] = {
- { { 125, 125, 2000, 4000 } }, /*!< Quick chirp followed by normal ring */
- { { 250, 250, 500, 1000, 250, 250, 500, 4000 } }, /*!< British style ring */
- { { 125, 125, 125, 125, 125, 4000 } }, /*!< Three short bursts */
- { { 1000, 500, 2500, 5000 } }, /*!< Long ring */
-};
-
-/*! \brief cidrings says in which pause to transmit the cid information, where the first pause
- * is 1, the second pause is 2 and so on.
- */
-
-static int cidrings[NUM_CADENCE_MAX] = {
- 2, /*!< Right after first long ring */
- 4, /*!< Right after long part */
- 3, /*!< After third chirp */
- 2, /*!< Second spell */
-};
-
-#define ISTRUNK(p) ((p->sig == SIG_FXSLS) || (p->sig == SIG_FXSKS) || \
- (p->sig == SIG_FXSGS) || (p->sig == SIG_PRI))
-
-#define CANBUSYDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_EM_E1 | SIG_SF)) /* || (p->sig & __DAHDI_SIG_FXO) */)
-#define CANPROGRESSDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_EM_E1 | SIG_SF)) /* || (p->sig & __DAHDI_SIG_FXO) */)
-
-static int dahdi_get_index(struct ast_channel *ast, struct dahdi_pvt *p, int nullok)
-{
- int res;
- if (p->subs[SUB_REAL].owner == ast)
- res = 0;
- else if (p->subs[SUB_CALLWAIT].owner == ast)
- res = 1;
- else if (p->subs[SUB_THREEWAY].owner == ast)
- res = 2;
- else {
- res = -1;
- if (!nullok)
- ast_log(LOG_WARNING, "Unable to get index, and nullok is not asserted\n");
- }
- return res;
-}
-
-#ifdef HAVE_PRI
-static void wakeup_sub(struct dahdi_pvt *p, int a, struct dahdi_pri *pri)
-#else
-static void wakeup_sub(struct dahdi_pvt *p, int a, void *pri)
-#endif
-{
-#ifdef HAVE_PRI
- if (pri)
- ast_mutex_unlock(&pri->lock);
-#endif
- for (;;) {
- if (p->subs[a].owner) {
- if (ast_mutex_trylock(&p->subs[a].owner->lock)) {
- DEADLOCK_AVOIDANCE(&p->lock);
- } else {
- ast_queue_frame(p->subs[a].owner, &ast_null_frame);
- ast_mutex_unlock(&p->subs[a].owner->lock);
- break;
- }
- } else
- break;
- }
-#ifdef HAVE_PRI
- if (pri)
- ast_mutex_lock(&pri->lock);
-#endif
-}
-
-#ifdef HAVE_PRI
-static void dahdi_queue_frame(struct dahdi_pvt *p, struct ast_frame *f, struct dahdi_pri *pri)
-#else
-static void dahdi_queue_frame(struct dahdi_pvt *p, struct ast_frame *f, void *pri)
-#endif
-{
- /* We must unlock the PRI to avoid the possibility of a deadlock */
-#ifdef HAVE_PRI
- if (pri)
- ast_mutex_unlock(&pri->lock);
-#endif
- for (;;) {
- if (p->owner) {
- if (ast_mutex_trylock(&p->owner->lock)) {
- DEADLOCK_AVOIDANCE(&p->lock);
- } else {
- ast_queue_frame(p->owner, f);
- ast_mutex_unlock(&p->owner->lock);
- break;
- }
- } else
- break;
- }
-#ifdef HAVE_PRI
- if (pri)
- ast_mutex_lock(&pri->lock);
-#endif
-}
-
-static int restore_gains(struct dahdi_pvt *p);
-
-static void swap_subs(struct dahdi_pvt *p, int a, int b)
-{
- int tchan;
- int tinthreeway;
- struct ast_channel *towner;
-
- ast_log(LOG_DEBUG, "Swapping %d and %d\n", a, b);
-
- tchan = p->subs[a].chan;
- towner = p->subs[a].owner;
- tinthreeway = p->subs[a].inthreeway;
-
- p->subs[a].chan = p->subs[b].chan;
- p->subs[a].owner = p->subs[b].owner;
- p->subs[a].inthreeway = p->subs[b].inthreeway;
-
- p->subs[b].chan = tchan;
- p->subs[b].owner = towner;
- p->subs[b].inthreeway = tinthreeway;
-
- if (p->subs[a].owner)
- p->subs[a].owner->fds[0] = p->subs[a].dfd;
- if (p->subs[b].owner)
- p->subs[b].owner->fds[0] = p->subs[b].dfd;
- wakeup_sub(p, a, NULL);
- wakeup_sub(p, b, NULL);
-}
-
-static int dahdi_open(char *fn)
-{
- int fd;
- int isnum;
- int chan = 0;
- int bs;
- int x;
- isnum = 1;
- for (x = 0; x < strlen(fn); x++) {
- if (!isdigit(fn[x])) {
- isnum = 0;
- break;
- }
- }
- if (isnum) {
- chan = atoi(fn);
- if (chan < 1) {
- ast_log(LOG_WARNING, "Invalid channel number '%s'\n", fn);
- return -1;
- }
- fn = DAHDI_FILE_CHANNEL;
- }
- fd = open(fn, O_RDWR | O_NONBLOCK);
- if (fd < 0) {
- ast_log(LOG_WARNING, "Unable to open '%s': %s\n", fn, strerror(errno));
- return -1;
- }
- if (chan) {
- if (ioctl(fd, DAHDI_SPECIFY, &chan)) {
- x = errno;
- close(fd);
- errno = x;
- ast_log(LOG_WARNING, "Unable to specify channel %d: %s\n", chan, strerror(errno));
- return -1;
- }
- }
- bs = READ_SIZE;
- if (ioctl(fd, DAHDI_SET_BLOCKSIZE, &bs) == -1) {
- ast_log(LOG_WARNING, "Unable to set blocksize '%d': %s\n", bs, strerror(errno));
- x = errno;
- close(fd);
- errno = x;
- return -1;
- }
- return fd;
-}
-
-static void dahdi_close(int fd)
-{
- if (fd > 0)
- close(fd);
-}
-
-static void dahdi_close_sub(struct dahdi_pvt *chan_pvt, int sub_num)
-{
- dahdi_close(chan_pvt->subs[sub_num].dfd);
- chan_pvt->subs[sub_num].dfd = -1;
-}
-
-#ifdef HAVE_PRI
-static void dahdi_close_pri_fd(struct dahdi_pri *pri, int fd_num)
-{
- dahdi_close(pri->fds[fd_num]);
- pri->fds[fd_num] = -1;
-}
-#endif
-
-static int dahdi_setlinear(int dfd, int linear)
-{
- int res;
- res = ioctl(dfd, DAHDI_SETLINEAR, &linear);
- if (res)
- return res;
- return 0;
-}
-
-
-static int alloc_sub(struct dahdi_pvt *p, int x)
-{
- struct dahdi_bufferinfo bi;
- int res;
- if (p->subs[x].dfd < 0) {
- p->subs[x].dfd = dahdi_open(DAHDI_FILE_PSEUDO);
- if (p->subs[x].dfd > -1) {
- res = ioctl(p->subs[x].dfd, DAHDI_GET_BUFINFO, &bi);
- if (!res) {
- bi.txbufpolicy = p->buf_policy;
- bi.rxbufpolicy = p->buf_policy;
- bi.numbufs = p->buf_no;
- res = ioctl(p->subs[x].dfd, DAHDI_SET_BUFINFO, &bi);
- if (res < 0) {
- ast_log(LOG_WARNING, "Unable to set buffer policy on channel %d: %s\n", x, strerror(errno));
- }
- } else
- ast_log(LOG_WARNING, "Unable to check buffer policy on channel %d: %s\n", x, strerror(errno));
- if (ioctl(p->subs[x].dfd, DAHDI_CHANNO, &p->subs[x].chan) == 1) {
- ast_log(LOG_WARNING, "Unable to get channel number for pseudo channel on FD %d: %s\n", p->subs[x].dfd, strerror(errno));
- dahdi_close_sub(p, x);
- return -1;
- }
- if (option_debug)
- ast_log(LOG_DEBUG, "Allocated %s subchannel on FD %d channel %d\n", subnames[x], p->subs[x].dfd, p->subs[x].chan);
- return 0;
- } else
- ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
- return -1;
- }
- ast_log(LOG_WARNING, "%s subchannel of %d already in use\n", subnames[x], p->channel);
- return -1;
-}
-
-static int unalloc_sub(struct dahdi_pvt *p, int x)
-{
- if (!x) {
- ast_log(LOG_WARNING, "Trying to unalloc the real channel %d?!?\n", p->channel);
- return -1;
- }
- ast_log(LOG_DEBUG, "Released sub %d of channel %d\n", x, p->channel);
- dahdi_close_sub(p, x);
- p->subs[x].linear = 0;
- p->subs[x].chan = 0;
- p->subs[x].owner = NULL;
- p->subs[x].inthreeway = 0;
- p->polarity = POLARITY_IDLE;
- memset(&p->subs[x].curconf, 0, sizeof(p->subs[x].curconf));
- return 0;
-}
-
-static int digit_to_dtmfindex(char digit)
-{
- if (isdigit(digit))
- return DAHDI_TONE_DTMF_BASE + (digit - '0');
- else if (digit >= 'A' && digit <= 'D')
- return DAHDI_TONE_DTMF_A + (digit - 'A');
- else if (digit >= 'a' && digit <= 'd')
- return DAHDI_TONE_DTMF_A + (digit - 'a');
- else if (digit == '*')
- return DAHDI_TONE_DTMF_s;
- else if (digit == '#')
- return DAHDI_TONE_DTMF_p;
- else
- return -1;
-}
-
-static int dahdi_digit_begin(struct ast_channel *chan, char digit)
-{
- struct dahdi_pvt *pvt;
- int index;
- int dtmf = -1;
-
- pvt = chan->tech_pvt;
-
- ast_mutex_lock(&pvt->lock);
-
- index = dahdi_get_index(chan, pvt, 0);
-
- if ((index != SUB_REAL) || !pvt->owner)
- goto out;
-
-#ifdef HAVE_PRI
- if ((pvt->sig == SIG_PRI) && (chan->_state == AST_STATE_DIALING) && !pvt->proceeding) {
- if (pvt->setup_ack) {
- if (!pri_grab(pvt, pvt->pri)) {
- pri_information(pvt->pri->pri, pvt->call, digit);
- pri_rel(pvt->pri);
- } else
- ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", pvt->span);
- } else if (strlen(pvt->dialdest) < sizeof(pvt->dialdest) - 1) {
- int res;
- ast_log(LOG_DEBUG, "Queueing digit '%c' since setup_ack not yet received\n", digit);
- res = strlen(pvt->dialdest);
- pvt->dialdest[res++] = digit;
- pvt->dialdest[res] = '\0';
- }
- goto out;
- }
-#endif
- if ((dtmf = digit_to_dtmfindex(digit)) == -1)
- goto out;
-
- if (pvt->pulse || ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_SENDTONE, &dtmf)) {
- int res;
- struct dahdi_dialoperation zo = {
- .op = DAHDI_DIAL_OP_APPEND,
- .dialstr[0] = 'T',
- .dialstr[1] = digit,
- .dialstr[2] = 0,
- };
- if ((res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_DIAL, &zo)))
- ast_log(LOG_WARNING, "Couldn't dial digit %c: %s\n", digit, strerror(errno));
- else
- pvt->dialing = 1;
- } else {
- ast_log(LOG_DEBUG, "Started VLDTMF digit '%c'\n", digit);
- pvt->dialing = 1;
- pvt->begindigit = digit;
- }
-
-out:
- ast_mutex_unlock(&pvt->lock);
-
- return 0;
-}
-
-static int dahdi_digit_end(struct ast_channel *chan, char digit, unsigned int duration)
-{
- struct dahdi_pvt *pvt;
- int res = 0;
- int index;
- int x;
-
- pvt = chan->tech_pvt;
-
- ast_mutex_lock(&pvt->lock);
-
- index = dahdi_get_index(chan, pvt, 0);
-
- if ((index != SUB_REAL) || !pvt->owner || pvt->pulse)
- goto out;
-
-#ifdef HAVE_PRI
- /* This means that the digit was already sent via PRI signalling */
- if (pvt->sig == SIG_PRI && !pvt->begindigit)
- goto out;
-#endif
-
- if (pvt->begindigit) {
- x = -1;
- ast_log(LOG_DEBUG, "Ending VLDTMF digit '%c'\n", digit);
- res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_SENDTONE, &x);
- pvt->dialing = 0;
- pvt->begindigit = 0;
- }
-
-out:
- ast_mutex_unlock(&pvt->lock);
-
- return res;
-}
-
-static char *events[] = {
- "No event",
- "On hook",
- "Ring/Answered",
- "Wink/Flash",
- "Alarm",
- "No more alarm",
- "HDLC Abort",
- "HDLC Overrun",
- "HDLC Bad FCS",
- "Dial Complete",
- "Ringer On",
- "Ringer Off",
- "Hook Transition Complete",
- "Bits Changed",
- "Pulse Start",
- "Timer Expired",
- "Timer Ping",
- "Polarity Reversal",
- "Ring Begin",
-};
-
-static struct {
- int alarm;
- char *name;
-} alarms[] = {
- { DAHDI_ALARM_RED, "Red Alarm" },
- { DAHDI_ALARM_YELLOW, "Yellow Alarm" },
- { DAHDI_ALARM_BLUE, "Blue Alarm" },
- { DAHDI_ALARM_RECOVER, "Recovering" },
- { DAHDI_ALARM_LOOPBACK, "Loopback" },
- { DAHDI_ALARM_NOTOPEN, "Not Open" },
- { DAHDI_ALARM_NONE, "None" },
-};
-
-static char *alarm2str(int alarm)
-{
- int x;
- for (x = 0; x < sizeof(alarms) / sizeof(alarms[0]); x++) {
- if (alarms[x].alarm & alarm)
- return alarms[x].name;
- }
- return alarm ? "Unknown Alarm" : "No Alarm";
-}
-
-static char *event2str(int event)
-{
- static char buf[256];
- if ((event < (sizeof(events) / sizeof(events[0]))) && (event > -1))
- return events[event];
- sprintf(buf, "Event %d", event); /* safe */
- return buf;
-}
-
-#ifdef HAVE_PRI
-static char *dialplan2str(int dialplan)
-{
- if (dialplan == -1) {
- return("Dynamically set dialplan in ISDN");
- }
- return (pri_plan2str(dialplan));
-}
-#endif
-
-static char *dahdi_sig2str(int sig)
-{
- static char buf[256];
- switch (sig) {
- case SIG_EM:
- return "E & M Immediate";
- case SIG_EMWINK:
- return "E & M Wink";
- case SIG_EM_E1:
- return "E & M E1";
- case SIG_FEATD:
- return "Feature Group D (DTMF)";
- case SIG_FEATDMF:
- return "Feature Group D (MF)";
- case SIG_FEATDMF_TA:
- return "Feature Groud D (MF) Tandem Access";
- case SIG_FEATB:
- return "Feature Group B (MF)";
- case SIG_E911:
- return "E911 (MF)";
- case SIG_FGC_CAMA:
- return "FGC/CAMA (Dialpulse)";
- case SIG_FGC_CAMAMF:
- return "FGC/CAMA (MF)";
- case SIG_FXSLS:
- return "FXS Loopstart";
- case SIG_FXSGS:
- return "FXS Groundstart";
- case SIG_FXSKS:
- return "FXS Kewlstart";
- case SIG_FXOLS:
- return "FXO Loopstart";
- case SIG_FXOGS:
- return "FXO Groundstart";
- case SIG_FXOKS:
- return "FXO Kewlstart";
- case SIG_PRI:
- return "ISDN PRI";
- case SIG_SF:
- return "SF (Tone) Immediate";
- case SIG_SFWINK:
- return "SF (Tone) Wink";
- case SIG_SF_FEATD:
- return "SF (Tone) with Feature Group D (DTMF)";
- case SIG_SF_FEATDMF:
- return "SF (Tone) with Feature Group D (MF)";
- case SIG_SF_FEATB:
- return "SF (Tone) with Feature Group B (MF)";
- case SIG_GR303FXOKS:
- return "GR-303 with FXOKS";
- case SIG_GR303FXSKS:
- return "GR-303 with FXSKS";
- case 0:
- return "Pseudo";
- default:
- snprintf(buf, sizeof(buf), "Unknown signalling %d", sig);
- return buf;
- }
-}
-
-#define sig2str dahdi_sig2str
-
-static int conf_add(struct dahdi_pvt *p, struct dahdi_subchannel *c, int index, int slavechannel)
-{
- /* If the conference already exists, and we're already in it
- don't bother doing anything */
- struct dahdi_confinfo zi;
-
- memset(&zi, 0, sizeof(zi));
- zi.chan = 0;
-
- if (slavechannel > 0) {
- /* If we have only one slave, do a digital mon */
- zi.confmode = DAHDI_CONF_DIGITALMON;
- zi.confno = slavechannel;
- } else {
- if (!index) {
- /* Real-side and pseudo-side both participate in conference */
- zi.confmode = DAHDI_CONF_REALANDPSEUDO | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER |
- DAHDI_CONF_PSEUDO_TALKER | DAHDI_CONF_PSEUDO_LISTENER;
- } else
- zi.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
- zi.confno = p->confno;
- }
- if ((zi.confno == c->curconf.confno) && (zi.confmode == c->curconf.confmode))
- return 0;
- if (c->dfd < 0)
- return 0;
- if (ioctl(c->dfd, DAHDI_SETCONF, &zi)) {
- ast_log(LOG_WARNING, "Failed to add %d to conference %d/%d: %s\n", c->dfd, zi.confmode, zi.confno, strerror(errno));
- return -1;
- }
- if (slavechannel < 1) {
- p->confno = zi.confno;
- }
- memcpy(&c->curconf, &zi, sizeof(c->curconf));
- ast_log(LOG_DEBUG, "Added %d to conference %d/%d\n", c->dfd, c->curconf.confmode, c->curconf.confno);
- return 0;
-}
-
-static int isourconf(struct dahdi_pvt *p, struct dahdi_subchannel *c)
-{
- /* If they're listening to our channel, they're ours */
- if ((p->channel == c->curconf.confno) && (c->curconf.confmode == DAHDI_CONF_DIGITALMON))
- return 1;
- /* If they're a talker on our (allocated) conference, they're ours */
- if ((p->confno > 0) && (p->confno == c->curconf.confno) && (c->curconf.confmode & DAHDI_CONF_TALKER))
- return 1;
- return 0;
-}
-
-static int conf_del(struct dahdi_pvt *p, struct dahdi_subchannel *c, int index)
-{
- struct dahdi_confinfo zi;
- if (/* Can't delete if there's no dfd */
- (c->dfd < 0) ||
- /* Don't delete from the conference if it's not our conference */
- !isourconf(p, c)
- /* Don't delete if we don't think it's conferenced at all (implied) */
- ) return 0;
- memset(&zi, 0, sizeof(zi));
- zi.chan = 0;
- zi.confno = 0;
- zi.confmode = 0;
- if (ioctl(c->dfd, DAHDI_SETCONF, &zi)) {
- ast_log(LOG_WARNING, "Failed to drop %d from conference %d/%d: %s\n", c->dfd, c->curconf.confmode, c->curconf.confno, strerror(errno));
- return -1;
- }
- ast_log(LOG_DEBUG, "Removed %d from conference %d/%d\n", c->dfd, c->curconf.confmode, c->curconf.confno);
- memcpy(&c->curconf, &zi, sizeof(c->curconf));
- return 0;
-}
-
-static int isslavenative(struct dahdi_pvt *p, struct dahdi_pvt **out)
-{
- int x;
- int useslavenative;
- struct dahdi_pvt *slave = NULL;
- /* Start out optimistic */
- useslavenative = 1;
- /* Update conference state in a stateless fashion */
- for (x = 0; x < 3; x++) {
- /* Any three-way calling makes slave native mode *definitely* out
- of the question */
- if ((p->subs[x].dfd > -1) && p->subs[x].inthreeway)
- useslavenative = 0;
- }
- /* If we don't have any 3-way calls, check to see if we have
- precisely one slave */
- if (useslavenative) {
- for (x = 0; x < MAX_SLAVES; x++) {
- if (p->slaves[x]) {
- if (slave) {
- /* Whoops already have a slave! No
- slave native and stop right away */
- slave = NULL;
- useslavenative = 0;
- break;
- } else {
- /* We have one slave so far */
- slave = p->slaves[x];
- }
- }
- }
- }
- /* If no slave, slave native definitely out */
- if (!slave)
- useslavenative = 0;
- else if (slave->law != p->law) {
- useslavenative = 0;
- slave = NULL;
- }
- if (out)
- *out = slave;
- return useslavenative;
-}
-
-static int reset_conf(struct dahdi_pvt *p)
-{
- struct dahdi_confinfo zi;
- memset(&zi, 0, sizeof(zi));
- p->confno = -1;
- memset(&p->subs[SUB_REAL].curconf, 0, sizeof(p->subs[SUB_REAL].curconf));
- if (p->subs[SUB_REAL].dfd > -1) {
- if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCONF, &zi))
- ast_log(LOG_WARNING, "Failed to reset conferencing on channel %d: %s\n", p->channel, strerror(errno));
- }
- return 0;
-}
-
-static int update_conf(struct dahdi_pvt *p)
-{
- int needconf = 0;
- int x;
- int useslavenative;
- struct dahdi_pvt *slave = NULL;
-
- useslavenative = isslavenative(p, &slave);
- /* Start with the obvious, general stuff */
- for (x = 0; x < 3; x++) {
- /* Look for three way calls */
- if ((p->subs[x].dfd > -1) && p->subs[x].inthreeway) {
- conf_add(p, &p->subs[x], x, 0);
- needconf++;
- } else {
- conf_del(p, &p->subs[x], x);
- }
- }
- /* If we have a slave, add him to our conference now. or DAX
- if this is slave native */
- for (x = 0; x < MAX_SLAVES; x++) {
- if (p->slaves[x]) {
- if (useslavenative)
- conf_add(p, &p->slaves[x]->subs[SUB_REAL], SUB_REAL, GET_CHANNEL(p));
- else {
- conf_add(p, &p->slaves[x]->subs[SUB_REAL], SUB_REAL, 0);
- needconf++;
- }
- }
- }
- /* If we're supposed to be in there, do so now */
- if (p->inconference && !p->subs[SUB_REAL].inthreeway) {
- if (useslavenative)
- conf_add(p, &p->subs[SUB_REAL], SUB_REAL, GET_CHANNEL(slave));
- else {
- conf_add(p, &p->subs[SUB_REAL], SUB_REAL, 0);
- needconf++;
- }
- }
- /* If we have a master, add ourselves to his conference */
- if (p->master) {
- if (isslavenative(p->master, NULL)) {
- conf_add(p->master, &p->subs[SUB_REAL], SUB_REAL, GET_CHANNEL(p->master));
- } else {
- conf_add(p->master, &p->subs[SUB_REAL], SUB_REAL, 0);
- }
- }
- if (!needconf) {
- /* Nobody is left (or should be left) in our conference.
- Kill it. */
- p->confno = -1;
- }
- if (option_debug)
- ast_log(LOG_DEBUG, "Updated conferencing on %d, with %d conference users\n", p->channel, needconf);
- return 0;
-}
-
-static void dahdi_enable_ec(struct dahdi_pvt *p)
-{
- int x;
- int res;
- if (!p)
- return;
- if (p->echocanon) {
- ast_log(LOG_DEBUG, "Echo cancellation already on\n");
- return;
- }
- if (p->digital) {
- ast_log(LOG_DEBUG, "Echo cancellation isn't required on digital connection\n");
- return;
- }
- if (p->echocancel) {
- if (p->sig == SIG_PRI) {
- x = 1;
- res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &x);
- if (res)
- ast_log(LOG_WARNING, "Unable to enable audio mode on channel %d (%s)\n", p->channel, strerror(errno));
- }
- x = p->echocancel;
- res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_ECHOCANCEL, &x);
- if (res)
- ast_log(LOG_WARNING, "Unable to enable echo cancellation on channel %d (%s)\n", p->channel, strerror(errno));
- else {
- p->echocanon = 1;
- if (option_debug)
- ast_log(LOG_DEBUG, "Enabled echo cancellation on channel %d\n", p->channel);
- }
- } else if (option_debug)
- ast_log(LOG_DEBUG, "No echo cancellation requested\n");
-}
-
-static void dahdi_train_ec(struct dahdi_pvt *p)
-{
- int x;
- int res;
- if (p && p->echocancel && p->echotraining) {
- x = p->echotraining;
- res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_ECHOTRAIN, &x);
- if (res)
- ast_log(LOG_WARNING, "Unable to request echo training on channel %d: %s\n", p->channel, strerror(errno));
- else {
- ast_log(LOG_DEBUG, "Engaged echo training on channel %d\n", p->channel);
- }
- } else
- ast_log(LOG_DEBUG, "No echo training requested\n");
-}
-
-static void dahdi_disable_ec(struct dahdi_pvt *p)
-{
- int x;
- int res;
- if (p->echocancel) {
- x = 0;
- res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_ECHOCANCEL, &x);
- if (res)
- ast_log(LOG_WARNING, "Unable to disable echo cancellation on channel %d: %s\n", p->channel, strerror(errno));
- else if (option_debug)
- ast_log(LOG_DEBUG, "disabled echo cancellation on channel %d\n", p->channel);
- }
- p->echocanon = 0;
-}
-
-static void fill_txgain(struct dahdi_gains *g, float gain, int law)
-{
- int j;
- int k;
- float linear_gain = pow(10.0, gain / 20.0);
-
- switch (law) {
- case DAHDI_LAW_ALAW:
- for (j = 0; j < (sizeof(g->txgain) / sizeof(g->txgain[0])); j++) {
- if (gain) {
- k = (int) (((float) AST_ALAW(j)) * linear_gain);
- if (k > 32767) k = 32767;
- if (k < -32767) k = -32767;
- g->txgain[j] = AST_LIN2A(k);
- } else {
- g->txgain[j] = j;
- }
- }
- break;
- case DAHDI_LAW_MULAW:
- for (j = 0; j < (sizeof(g->txgain) / sizeof(g->txgain[0])); j++) {
- if (gain) {
- k = (int) (((float) AST_MULAW(j)) * linear_gain);
- if (k > 32767) k = 32767;
- if (k < -32767) k = -32767;
- g->txgain[j] = AST_LIN2MU(k);
- } else {
- g->txgain[j] = j;
- }
- }
- break;
- }
-}
-
-static void fill_rxgain(struct dahdi_gains *g, float gain, int law)
-{
- int j;
- int k;
- float linear_gain = pow(10.0, gain / 20.0);
-
- switch (law) {
- case DAHDI_LAW_ALAW:
- for (j = 0; j < (sizeof(g->rxgain) / sizeof(g->rxgain[0])); j++) {
- if (gain) {
- k = (int) (((float) AST_ALAW(j)) * linear_gain);
- if (k > 32767) k = 32767;
- if (k < -32767) k = -32767;
- g->rxgain[j] = AST_LIN2A(k);
- } else {
- g->rxgain[j] = j;
- }
- }
- break;
- case DAHDI_LAW_MULAW:
- for (j = 0; j < (sizeof(g->rxgain) / sizeof(g->rxgain[0])); j++) {
- if (gain) {
- k = (int) (((float) AST_MULAW(j)) * linear_gain);
- if (k > 32767) k = 32767;
- if (k < -32767) k = -32767;
- g->rxgain[j] = AST_LIN2MU(k);
- } else {
- g->rxgain[j] = j;
- }
- }
- break;
- }
-}
-
-static int set_actual_txgain(int fd, int chan, float gain, int law)
-{
- struct dahdi_gains g;
- int res;
-
- memset(&g, 0, sizeof(g));
- g.chan = chan;
- res = ioctl(fd, DAHDI_GETGAINS, &g);
- if (res) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Failed to read gains: %s\n", strerror(errno));
- return res;
- }
-
- fill_txgain(&g, gain, law);
-
- return ioctl(fd, DAHDI_SETGAINS, &g);
-}
-
-static int set_actual_rxgain(int fd, int chan, float gain, int law)
-{
- struct dahdi_gains g;
- int res;
-
- memset(&g, 0, sizeof(g));
- g.chan = chan;
- res = ioctl(fd, DAHDI_GETGAINS, &g);
- if (res) {
- ast_log(LOG_DEBUG, "Failed to read gains: %s\n", strerror(errno));
- return res;
- }
-
- fill_rxgain(&g, gain, law);
-
- return ioctl(fd, DAHDI_SETGAINS, &g);
-}
-
-static int set_actual_gain(int fd, int chan, float rxgain, float txgain, int law)
-{
- return set_actual_txgain(fd, chan, txgain, law) | set_actual_rxgain(fd, chan, rxgain, law);
-}
-
-static int bump_gains(struct dahdi_pvt *p)
-{
- int res;
-
- /* Bump receive gain by 5.0db */
- res = set_actual_gain(p->subs[SUB_REAL].dfd, 0, p->rxgain + 5.0, p->txgain, p->law);
- if (res) {
- ast_log(LOG_WARNING, "Unable to bump gain: %s\n", strerror(errno));
- return -1;
- }
-
- return 0;
-}
-
-static int restore_gains(struct dahdi_pvt *p)
-{
- int res;
-
- res = set_actual_gain(p->subs[SUB_REAL].dfd, 0, p->rxgain, p->txgain, p->law);
- if (res) {
- ast_log(LOG_WARNING, "Unable to restore gains: %s\n", strerror(errno));
- return -1;
- }
-
- return 0;
-}
-
-static inline int dahdi_set_hook(int fd, int hs)
-{
- int x, res;
-
- x = hs;
- res = ioctl(fd, DAHDI_HOOK, &x);
-
- if (res < 0) {
- if (errno == EINPROGRESS)
- return 0;
- ast_log(LOG_WARNING, "DAHDI hook failed returned %d (trying %d): %s\n", res, hs, strerror(errno));
- /* will expectedly fail if phone is off hook during operation, such as during a restart */
- }
-
- return res;
-}
-
-static inline int dahdi_confmute(struct dahdi_pvt *p, int muted)
-{
- int x, y, res;
- x = muted;
- if (p->sig == SIG_PRI) {
- y = 1;
- res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &y);
- if (res)
- ast_log(LOG_WARNING, "Unable to set audio mode on %d: %s\n", p->channel, strerror(errno));
- }
- res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_CONFMUTE, &x);
- if (res < 0)
- ast_log(LOG_WARNING, "dahdi confmute(%d) failed on channel %d: %s\n", muted, p->channel, strerror(errno));
- return res;
-}
-
-static int save_conference(struct dahdi_pvt *p)
-{
- struct dahdi_confinfo c;
- int res;
- if (p->saveconf.confmode) {
- ast_log(LOG_WARNING, "Can't save conference -- already in use\n");
- return -1;
- }
- p->saveconf.chan = 0;
- res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GETCONF, &p->saveconf);
- if (res) {
- ast_log(LOG_WARNING, "Unable to get conference info: %s\n", strerror(errno));
- p->saveconf.confmode = 0;
- return -1;
- }
- c.chan = 0;
- c.confno = 0;
- c.confmode = DAHDI_CONF_NORMAL;
- res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCONF, &c);
- if (res) {
- ast_log(LOG_WARNING, "Unable to set conference info: %s\n", strerror(errno));
- return -1;
- }
- if (option_debug)
- ast_log(LOG_DEBUG, "Disabled conferencing\n");
- return 0;
-}
-
-static int restore_conference(struct dahdi_pvt *p)
-{
- int res;
- if (p->saveconf.confmode) {
- res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCONF, &p->saveconf);
- p->saveconf.confmode = 0;
- if (res) {
- ast_log(LOG_WARNING, "Unable to restore conference info: %s\n", strerror(errno));
- return -1;
- }
- }
- if (option_debug)
- ast_log(LOG_DEBUG, "Restored conferencing\n");
- return 0;
-}
-
-static int send_callerid(struct dahdi_pvt *p);
-
-static int send_cwcidspill(struct dahdi_pvt *p)
-{
- p->callwaitcas = 0;
- p->cidcwexpire = 0;
- if (!(p->cidspill = ast_malloc(MAX_CALLERID_SIZE)))
- return -1;
- p->cidlen = ast_callerid_callwaiting_generate(p->cidspill, p->callwait_name, p->callwait_num, AST_LAW(p));
- /* Make sure we account for the end */
- p->cidlen += READ_SIZE * 4;
- p->cidpos = 0;
- send_callerid(p);
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "CPE supports Call Waiting Caller*ID. Sending '%s/%s'\n", p->callwait_name, p->callwait_num);
- return 0;
-}
-
-static int has_voicemail(struct dahdi_pvt *p)
-{
-
- return ast_app_has_voicemail(p->mailbox, NULL);
-}
-
-static int send_callerid(struct dahdi_pvt *p)
-{
- /* Assumes spill in p->cidspill, p->cidlen in length and we're p->cidpos into it */
- int res;
- /* Take out of linear mode if necessary */
- if (p->subs[SUB_REAL].linear) {
- p->subs[SUB_REAL].linear = 0;
- dahdi_setlinear(p->subs[SUB_REAL].dfd, 0);
- }
- while (p->cidpos < p->cidlen) {
- res = write(p->subs[SUB_REAL].dfd, p->cidspill + p->cidpos, p->cidlen - p->cidpos);
- if (res < 0) {
- if (errno == EAGAIN)
- return 0;
- else {
- ast_log(LOG_WARNING, "write failed: %s\n", strerror(errno));
- return -1;
- }
- }
- if (!res)
- return 0;
- p->cidpos += res;
- }
- free(p->cidspill);
- p->cidspill = NULL;
- if (p->callwaitcas) {
- /* Wait for CID/CW to expire */
- p->cidcwexpire = CIDCW_EXPIRE_SAMPLES;
- } else
- restore_conference(p);
- return 0;
-}
-
-static int dahdi_callwait(struct ast_channel *ast)
-{
- struct dahdi_pvt *p = ast->tech_pvt;
- p->callwaitingrepeat = CALLWAITING_REPEAT_SAMPLES;
- if (p->cidspill) {
- ast_log(LOG_WARNING, "Spill already exists?!?\n");
- free(p->cidspill);
- }
- if (!(p->cidspill = ast_malloc(2400 /* SAS */ + 680 /* CAS */ + READ_SIZE * 4)))
- return -1;
- save_conference(p);
- /* Silence */
- memset(p->cidspill, 0x7f, 2400 + 600 + READ_SIZE * 4);
- if (!p->callwaitrings && p->callwaitingcallerid) {
- ast_gen_cas(p->cidspill, 1, 2400 + 680, AST_LAW(p));
- p->callwaitcas = 1;
- p->cidlen = 2400 + 680 + READ_SIZE * 4;
- } else {
- ast_gen_cas(p->cidspill, 1, 2400, AST_LAW(p));
- p->callwaitcas = 0;
- p->cidlen = 2400 + READ_SIZE * 4;
- }
- p->cidpos = 0;
- send_callerid(p);
-
- return 0;
-}
-
-static int dahdi_call(struct ast_channel *ast, char *rdest, int timeout)
-{
- struct dahdi_pvt *p = ast->tech_pvt;
- int x, res, index,mysig;
- char *c, *n, *l;
-#ifdef HAVE_PRI
- char *s = NULL;
-#endif
- char dest[256]; /* must be same length as p->dialdest */
- ast_mutex_lock(&p->lock);
- ast_copy_string(dest, rdest, sizeof(dest));
- ast_copy_string(p->dialdest, rdest, sizeof(p->dialdest));
- if ((ast->_state == AST_STATE_BUSY)) {
- p->subs[SUB_REAL].needbusy = 1;
- ast_mutex_unlock(&p->lock);
- return 0;
- }
- if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
- ast_log(LOG_WARNING, "dahdi_call called on %s, neither down nor reserved\n", ast->name);
- ast_mutex_unlock(&p->lock);
- return -1;
- }
- p->dialednone = 0;
- if ((p->radio || (p->oprmode < 0))) /* if a radio channel, up immediately */
- {
- /* Special pseudo -- automatically up */
- ast_setstate(ast, AST_STATE_UP);
- ast_mutex_unlock(&p->lock);
- return 0;
- }
- x = DAHDI_FLUSH_READ | DAHDI_FLUSH_WRITE;
- res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_FLUSH, &x);
- if (res)
- ast_log(LOG_WARNING, "Unable to flush input on channel %d: %s\n", p->channel, strerror(errno));
- p->outgoing = 1;
-
- set_actual_gain(p->subs[SUB_REAL].dfd, 0, p->rxgain, p->txgain, p->law);
-
- mysig = p->sig;
- if (p->outsigmod > -1)
- mysig = p->outsigmod;
-
- switch (mysig) {
- case SIG_FXOLS:
- case SIG_FXOGS:
- case SIG_FXOKS:
- if (p->owner == ast) {
- /* Normal ring, on hook */
-
- /* Don't send audio while on hook, until the call is answered */
- p->dialing = 1;
- if (p->use_callerid) {
- /* Generate the Caller-ID spill if desired */
- if (p->cidspill) {
- ast_log(LOG_WARNING, "cidspill already exists??\n");
- free(p->cidspill);
- }
- p->callwaitcas = 0;
- if ((p->cidspill = ast_malloc(MAX_CALLERID_SIZE))) {
- p->cidlen = ast_callerid_generate(p->cidspill, ast->cid.cid_name, ast->cid.cid_num, AST_LAW(p));
- p->cidpos = 0;
- send_callerid(p);
- }
- }
- /* Choose proper cadence */
- if ((p->distinctivering > 0) && (p->distinctivering <= num_cadence)) {
- if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCADENCE, &cadences[p->distinctivering - 1]))
- ast_log(LOG_WARNING, "Unable to set distinctive ring cadence %d on '%s': %s\n", p->distinctivering, ast->name, strerror(errno));
- p->cidrings = cidrings[p->distinctivering - 1];
- } else {
- if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCADENCE, NULL))
- ast_log(LOG_WARNING, "Unable to reset default ring on '%s': %s\n", ast->name, strerror(errno));
- p->cidrings = p->sendcalleridafter;
- }
-
- /* nick@dccinc.com 4/3/03 mods to allow for deferred dialing */
- c = strchr(dest, '/');
- if (c)
- c++;
- if (c && (strlen(c) < p->stripmsd)) {
- ast_log(LOG_WARNING, "Number '%s' is shorter than stripmsd (%d)\n", c, p->stripmsd);
- c = NULL;
- }
- if (c) {
- p->dop.op = DAHDI_DIAL_OP_REPLACE;
- snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "Tw%s", c);
- ast_log(LOG_DEBUG, "FXO: setup deferred dialstring: %s\n", c);
- } else {
- p->dop.dialstr[0] = '\0';
- }
- x = DAHDI_RING;
- if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x) && (errno != EINPROGRESS)) {
- ast_log(LOG_WARNING, "Unable to ring phone: %s\n", strerror(errno));
- ast_mutex_unlock(&p->lock);
- return -1;
- }
- p->dialing = 1;
- } else {
- /* Call waiting call */
- p->callwaitrings = 0;
- if (ast->cid.cid_num)
- ast_copy_string(p->callwait_num, ast->cid.cid_num, sizeof(p->callwait_num));
- else
- p->callwait_num[0] = '\0';
- if (ast->cid.cid_name)
- ast_copy_string(p->callwait_name, ast->cid.cid_name, sizeof(p->callwait_name));
- else
- p->callwait_name[0] = '\0';
- /* Call waiting tone instead */
- if (dahdi_callwait(ast)) {
- ast_mutex_unlock(&p->lock);
- return -1;
- }
- /* Make ring-back */
- if (tone_zone_play_tone(p->subs[SUB_CALLWAIT].dfd, DAHDI_TONE_RINGTONE))
- ast_log(LOG_WARNING, "Unable to generate call-wait ring-back on channel %s\n", ast->name);
-
- }
- n = ast->cid.cid_name;
- l = ast->cid.cid_num;
- if (l)
- ast_copy_string(p->lastcid_num, l, sizeof(p->lastcid_num));
- else
- p->lastcid_num[0] = '\0';
- if (n)
- ast_copy_string(p->lastcid_name, n, sizeof(p->lastcid_name));
- else
- p->lastcid_name[0] = '\0';
- ast_setstate(ast, AST_STATE_RINGING);
- index = dahdi_get_index(ast, p, 0);
- if (index > -1) {
- p->subs[index].needringing = 1;
- }
- break;
- case SIG_FXSLS:
- case SIG_FXSGS:
- case SIG_FXSKS:
- case SIG_EMWINK:
- case SIG_EM:
- case SIG_EM_E1:
- case SIG_FEATD:
- case SIG_FEATDMF:
- case SIG_E911:
- case SIG_FGC_CAMA:
- case SIG_FGC_CAMAMF:
- case SIG_FEATB:
- case SIG_SFWINK:
- case SIG_SF:
- case SIG_SF_FEATD:
- case SIG_SF_FEATDMF:
- case SIG_FEATDMF_TA:
- case SIG_SF_FEATB:
- c = strchr(dest, '/');
- if (c)
- c++;
- else
- c = "";
- if (strlen(c) < p->stripmsd) {
- ast_log(LOG_WARNING, "Number '%s' is shorter than stripmsd (%d)\n", c, p->stripmsd);
- ast_mutex_unlock(&p->lock);
- return -1;
- }
-#ifdef HAVE_PRI
- /* Start the trunk, if not GR-303 */
- if (!p->pri) {
-#endif
- x = DAHDI_START;
- res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
- if (res < 0) {
- if (errno != EINPROGRESS) {
- ast_log(LOG_WARNING, "Unable to start channel: %s\n", strerror(errno));
- ast_mutex_unlock(&p->lock);
- return -1;
- }
- }
-#ifdef HAVE_PRI
- }
-#endif
- ast_log(LOG_DEBUG, "Dialing '%s'\n", c);
- p->dop.op = DAHDI_DIAL_OP_REPLACE;
-
- c += p->stripmsd;
-
- switch (mysig) {
- case SIG_FEATD:
- l = ast->cid.cid_num;
- if (l)
- snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "T*%s*%s*", l, c);
- else
- snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "T**%s*", c);
- break;
- case SIG_FEATDMF:
- l = ast->cid.cid_num;
- if (l)
- snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*00%s#*%s#", l, c);
- else
- snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*02#*%s#", c);
- break;
- case SIG_FEATDMF_TA:
- {
- const char *cic, *ozz;
-
- /* If you have to go through a Tandem Access point you need to use this */
- ozz = pbx_builtin_getvar_helper(p->owner, "FEATDMF_OZZ");
- if (!ozz)
- ozz = defaultozz;
- cic = pbx_builtin_getvar_helper(p->owner, "FEATDMF_CIC");
- if (!cic)
- cic = defaultcic;
- if (!ozz || !cic) {
- ast_log(LOG_WARNING, "Unable to dial channel of type feature group D MF tandem access without CIC or OZZ set\n");
- ast_mutex_unlock(&p->lock);
- return -1;
- }
- snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*%s%s#", ozz, cic);
- snprintf(p->finaldial, sizeof(p->finaldial), "M*%s#", c);
- p->whichwink = 0;
- }
- break;
- case SIG_E911:
- ast_copy_string(p->dop.dialstr, "M*911#", sizeof(p->dop.dialstr));
- break;
- case SIG_FGC_CAMA:
- snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "P%s", c);
- break;
- case SIG_FGC_CAMAMF:
- case SIG_FEATB:
- snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*%s#", c);
- break;
- default:
- if (p->pulse)
- snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "P%sw", c);
- else
- snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "T%sw", c);
- break;
- }
-
- if (p->echotraining && (strlen(p->dop.dialstr) > 4)) {
- memset(p->echorest, 'w', sizeof(p->echorest) - 1);
- strcpy(p->echorest + (p->echotraining / 400) + 1, p->dop.dialstr + strlen(p->dop.dialstr) - 2);
- p->echorest[sizeof(p->echorest) - 1] = '\0';
- p->echobreak = 1;
- p->dop.dialstr[strlen(p->dop.dialstr)-2] = '\0';
- } else
- p->echobreak = 0;
- if (!res) {
- if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop)) {
- int saveerr = errno;
-
- x = DAHDI_ONHOOK;
- ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
- ast_log(LOG_WARNING, "Dialing failed on channel %d: %s\n", p->channel, strerror(saveerr));
- ast_mutex_unlock(&p->lock);
- return -1;
- }
- } else
- ast_log(LOG_DEBUG, "Deferring dialing...\n");
- p->dialing = 1;
- if (ast_strlen_zero(c))
- p->dialednone = 1;
- ast_setstate(ast, AST_STATE_DIALING);
- break;
- case 0:
- /* Special pseudo -- automatically up*/
- ast_setstate(ast, AST_STATE_UP);
- break;
- case SIG_PRI:
- /* We'll get it in a moment -- but use dialdest to store pre-setup_ack digits */
- p->dialdest[0] = '\0';
- break;
- default:
- ast_log(LOG_DEBUG, "not yet implemented\n");
- ast_mutex_unlock(&p->lock);
- return -1;
- }
-#ifdef HAVE_PRI
- if (p->pri) {
- struct pri_sr *sr;
-#ifdef SUPPORT_USERUSER
- const char *useruser;
-#endif
- int pridialplan;
- int dp_strip;
- int prilocaldialplan;
- int ldp_strip;
- int exclusive;
- const char *rr_str;
- int redirect_reason;
-
- c = strchr(dest, '/');
- if (c)
- c++;
- else
- c = dest;
-
- l = NULL;
- n = NULL;
-
- if (!p->hidecallerid) {
- l = ast->cid.cid_num;
- if (!p->hidecalleridname) {
- n = ast->cid.cid_name;
- }
- }
-
-
- if (strlen(c) < p->stripmsd) {
- ast_log(LOG_WARNING, "Number '%s' is shorter than stripmsd (%d)\n", c, p->stripmsd);
- ast_mutex_unlock(&p->lock);
- return -1;
- }
- if (mysig != SIG_FXSKS) {
- p->dop.op = DAHDI_DIAL_OP_REPLACE;
- s = strchr(c + p->stripmsd, 'w');
- if (s) {
- if (strlen(s) > 1)
- snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "T%s", s);
- else
- p->dop.dialstr[0] = '\0';
- *s = '\0';
- } else {
- p->dop.dialstr[0] = '\0';
- }
- }
- if (pri_grab(p, p->pri)) {
- ast_log(LOG_WARNING, "Failed to grab PRI!\n");
- ast_mutex_unlock(&p->lock);
- return -1;
- }
- if (!(p->call = pri_new_call(p->pri->pri))) {
- ast_log(LOG_WARNING, "Unable to create call on channel %d\n", p->channel);
- pri_rel(p->pri);
- ast_mutex_unlock(&p->lock);
- return -1;
- }
- if (!(sr = pri_sr_new())) {
- ast_log(LOG_WARNING, "Failed to allocate setup request channel %d\n", p->channel);
- pri_destroycall(p->pri->pri, p->call);
- p->call = NULL;
- pri_rel(p->pri);
- ast_mutex_unlock(&p->lock);
- return -1;
- }
- if (p->bearer || (mysig == SIG_FXSKS)) {
- if (p->bearer) {
- ast_log(LOG_DEBUG, "Oooh, I have a bearer on %d (%d:%d)\n", PVT_TO_CHANNEL(p->bearer), p->bearer->logicalspan, p->bearer->channel);
- p->bearer->call = p->call;
- } else
- ast_log(LOG_DEBUG, "I'm being setup with no bearer right now...\n");
- pri_set_crv(p->pri->pri, p->call, p->channel, 0);
- }
- p->digital = IS_DIGITAL(ast->transfercapability);
- /* Add support for exclusive override */
- if (p->priexclusive)
- exclusive = 1;
- else {
- /* otherwise, traditional behavior */
- if (p->pri->nodetype == PRI_NETWORK)
- exclusive = 0;
- else
- exclusive = 1;
- }
-
- pri_sr_set_channel(sr, p->bearer ? PVT_TO_CHANNEL(p->bearer) : PVT_TO_CHANNEL(p), exclusive, 1);
- pri_sr_set_bearer(sr, p->digital ? PRI_TRANS_CAP_DIGITAL : ast->transfercapability,
- (p->digital ? -1 :
- ((p->law == DAHDI_LAW_ALAW) ? PRI_LAYER_1_ALAW : PRI_LAYER_1_ULAW)));
- if (p->pri->facilityenable)
- pri_facility_enable(p->pri->pri);
-
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Requested transfer capability: 0x%.2x - %s\n", ast->transfercapability, ast_transfercapability2str(ast->transfercapability));
- dp_strip = 0;
- pridialplan = p->pri->dialplan - 1;
- if (pridialplan == -2) { /* compute dynamically */
- if (strncmp(c + p->stripmsd, p->pri->internationalprefix, strlen(p->pri->internationalprefix)) == 0) {
- dp_strip = strlen(p->pri->internationalprefix);
- pridialplan = PRI_INTERNATIONAL_ISDN;
- } else if (strncmp(c + p->stripmsd, p->pri->nationalprefix, strlen(p->pri->nationalprefix)) == 0) {
- dp_strip = strlen(p->pri->nationalprefix);
- pridialplan = PRI_NATIONAL_ISDN;
- } else {
- pridialplan = PRI_LOCAL_ISDN;
- }
- }
- pri_sr_set_called(sr, c + p->stripmsd + dp_strip, pridialplan, s ? 1 : 0);
-
- ldp_strip = 0;
- prilocaldialplan = p->pri->localdialplan - 1;
- if ((l != NULL) && (prilocaldialplan == -2)) { /* compute dynamically */
- if (strncmp(l, p->pri->internationalprefix, strlen(p->pri->internationalprefix)) == 0) {
- ldp_strip = strlen(p->pri->internationalprefix);
- prilocaldialplan = PRI_INTERNATIONAL_ISDN;
- } else if (strncmp(l, p->pri->nationalprefix, strlen(p->pri->nationalprefix)) == 0) {
- ldp_strip = strlen(p->pri->nationalprefix);
- prilocaldialplan = PRI_NATIONAL_ISDN;
- } else {
- prilocaldialplan = PRI_LOCAL_ISDN;
- }
- }
- pri_sr_set_caller(sr, l ? (l + ldp_strip) : NULL, n, prilocaldialplan,
- p->use_callingpres ? ast->cid.cid_pres : (l ? PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN : PRES_NUMBER_NOT_AVAILABLE));
- if ((rr_str = pbx_builtin_getvar_helper(ast, "PRIREDIRECTREASON"))) {
- if (!strcasecmp(rr_str, "UNKNOWN"))
- redirect_reason = 0;
- else if (!strcasecmp(rr_str, "BUSY"))
- redirect_reason = 1;
- else if (!strcasecmp(rr_str, "NO_REPLY"))
- redirect_reason = 2;
- else if (!strcasecmp(rr_str, "UNCONDITIONAL"))
- redirect_reason = 15;
- else
- redirect_reason = PRI_REDIR_UNCONDITIONAL;
- } else
- redirect_reason = PRI_REDIR_UNCONDITIONAL;
- pri_sr_set_redirecting(sr, ast->cid.cid_rdnis, p->pri->localdialplan - 1, PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN, redirect_reason);
-
-#ifdef SUPPORT_USERUSER
- /* User-user info */
- useruser = pbx_builtin_getvar_helper(p->owner, "USERUSERINFO");
-
- if (useruser)
- pri_sr_set_useruser(sr, useruser);
-#endif
-
- if (pri_setup(p->pri->pri, p->call, sr)) {
- ast_log(LOG_WARNING, "Unable to setup call to %s (using %s)\n",
- c + p->stripmsd + dp_strip, dialplan2str(p->pri->dialplan));
- pri_rel(p->pri);
- ast_mutex_unlock(&p->lock);
- pri_sr_free(sr);
- return -1;
- }
- pri_sr_free(sr);
- ast_setstate(ast, AST_STATE_DIALING);
- pri_rel(p->pri);
- }
-#endif
- ast_mutex_unlock(&p->lock);
- return 0;
-}
-
-static void destroy_dahdi_pvt(struct dahdi_pvt **pvt)
-{
- struct dahdi_pvt *p = *pvt;
- /* Remove channel from the list */
- if (p->prev)
- p->prev->next = p->next;
- if (p->next)
- p->next->prev = p->prev;
- if (p->use_smdi)
- ast_smdi_interface_unref(p->smdi_iface);
- ast_mutex_destroy(&p->lock);
- dahdi_close_sub(p, SUB_REAL);
- if (p->owner)
- p->owner->tech_pvt = NULL;
- free(p);
- *pvt = NULL;
-}
-
-static int destroy_channel(struct dahdi_pvt *prev, struct dahdi_pvt *cur, int now)
-{
- int owned = 0;
- int i = 0;
-
- if (!now) {
- if (cur->owner) {
- owned = 1;
- }
-
- for (i = 0; i < 3; i++) {
- if (cur->subs[i].owner) {
- owned = 1;
- }
- }
- if (!owned) {
- if (prev) {
- prev->next = cur->next;
- if (prev->next)
- prev->next->prev = prev;
- else
- ifend = prev;
- } else {
- iflist = cur->next;
- if (iflist)
- iflist->prev = NULL;
- else
- ifend = NULL;
- }
- destroy_dahdi_pvt(&cur);
- }
- } else {
- if (prev) {
- prev->next = cur->next;
- if (prev->next)
- prev->next->prev = prev;
- else
- ifend = prev;
- } else {
- iflist = cur->next;
- if (iflist)
- iflist->prev = NULL;
- else
- ifend = NULL;
- }
- destroy_dahdi_pvt(&cur);
- }
- return 0;
-}
-
-static void destroy_all_channels(void)
-{
- int x;
- struct dahdi_pvt *p, *pl;
-
- while (num_restart_pending) {
- usleep(1);
- }
-
- ast_mutex_lock(&iflock);
- /* Destroy all the interfaces and free their memory */
- p = iflist;
- while (p) {
- /* Free any callerid */
- if (p->cidspill)
- ast_free(p->cidspill);
- pl = p;
- p = p->next;
- x = pl->channel;
- /* Free associated memory */
- if (pl)
- destroy_dahdi_pvt(&pl);
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_2 "Unregistered channel %d\n", x);
- }
- iflist = NULL;
- ifcount = 0;
- ast_mutex_unlock(&iflock);
-}
-
-#ifdef HAVE_PRI
-static char *dahdi_send_keypad_facility_app = "DAHDISendKeypadFacility";
-static char *zap_send_keypad_facility_app = "ZapSendKeypadFacility";
-
-static char *dahdi_send_keypad_facility_synopsis = "Send digits out of band over a PRI";
-static char *zap_send_keypad_facility_synopsis = "Send digits out of band over a PRI";
-
-static char *dahdi_send_keypad_facility_descrip =
-" DAHDISendKeypadFacility(): This application will send the given string of digits in a Keypad Facility\n"
-" IE over the current channel.\n";
-static char *zap_send_keypad_facility_descrip =
-" ZapSendKeypadFacility(): This application will send the given string of digits in a Keypad Facility\n"
-" IE over the current channel.\n";
-
-static int send_keypad_facility_exec(struct ast_channel *chan, void *data)
-{
- /* Data will be our digit string */
- struct dahdi_pvt *p;
- char *digits = (char *) data;
-
- if (ast_strlen_zero(digits)) {
- ast_log(LOG_DEBUG, "No digit string sent to application!\n");
- return -1;
- }
-
- p = (struct dahdi_pvt *)chan->tech_pvt;
-
- if (!p) {
- ast_log(LOG_DEBUG, "Unable to find technology private\n");
- return -1;
- }
-
- ast_mutex_lock(&p->lock);
-
- if (!p->pri || !p->call) {
- ast_log(LOG_DEBUG, "Unable to find pri or call on channel!\n");
- ast_mutex_unlock(&p->lock);
- return -1;
- }
-
- if (!pri_grab(p, p->pri)) {
- pri_keypad_facility(p->pri->pri, p->call, digits);
- pri_rel(p->pri);
- } else {
- ast_log(LOG_DEBUG, "Unable to grab pri to send keypad facility!\n");
- ast_mutex_unlock(&p->lock);
- return -1;
- }
-
- ast_mutex_unlock(&p->lock);
-
- return 0;
-}
-
-static int dahdi_send_keypad_facility_exec(struct ast_channel *chan, void *data)
-{
- return send_keypad_facility_exec(chan, data);
-}
-
-static int zap_send_keypad_facility_exec(struct ast_channel *chan, void *data)
-{
- ast_log(LOG_WARNING, "Use of the command %s is deprecated, please use %s instead.\n", zap_send_keypad_facility_app, dahdi_send_keypad_facility_app);
- return send_keypad_facility_exec(chan, data);
-}
-
-static int pri_is_up(struct dahdi_pri *pri)
-{
- int x;
- for (x = 0; x < NUM_DCHANS; x++) {
- if (pri->dchanavail[x] == DCHAN_AVAILABLE)
- return 1;
- }
- return 0;
-}
-
-static int pri_assign_bearer(struct dahdi_pvt *crv, struct dahdi_pri *pri, struct dahdi_pvt *bearer)
-{
- bearer->owner = &inuse;
- bearer->realcall = crv;
- crv->subs[SUB_REAL].dfd = bearer->subs[SUB_REAL].dfd;
- if (crv->subs[SUB_REAL].owner)
- crv->subs[SUB_REAL].owner->fds[0] = crv->subs[SUB_REAL].dfd;
- crv->bearer = bearer;
- crv->call = bearer->call;
- crv->pri = pri;
- return 0;
-}
-
-static char *pri_order(int level)
-{
- switch (level) {
- case 0:
- return "Primary";
- case 1:
- return "Secondary";
- case 2:
- return "Tertiary";
- case 3:
- return "Quaternary";
- default:
- return "<Unknown>";
- }
-}
-
-/* Returns fd of the active dchan */
-static int pri_active_dchan_fd(struct dahdi_pri *pri)
-{
- int x = -1;
-
- for (x = 0; x < NUM_DCHANS; x++) {
- if ((pri->dchans[x] == pri->pri))
- break;
- }
-
- return pri->fds[x];
-}
-
-static int pri_find_dchan(struct dahdi_pri *pri)
-{
- int oldslot = -1;
- struct pri *old;
- int newslot = -1;
- int x;
- old = pri->pri;
- for (x = 0; x < NUM_DCHANS; x++) {
- if ((pri->dchanavail[x] == DCHAN_AVAILABLE) && (newslot < 0))
- newslot = x;
- if (pri->dchans[x] == old) {
- oldslot = x;
- }
- }
- if (newslot < 0) {
- newslot = 0;
- ast_log(LOG_WARNING, "No D-channels available! Using Primary channel %d as D-channel anyway!\n",
- pri->dchannels[newslot]);
- }
- if (old && (oldslot != newslot))
- ast_log(LOG_NOTICE, "Switching from from d-channel %d to channel %d!\n",
- pri->dchannels[oldslot], pri->dchannels[newslot]);
- pri->pri = pri->dchans[newslot];
- return 0;
-}
-#endif
-
-static int dahdi_hangup(struct ast_channel *ast)
-{
- int res;
- int index,x, law;
- /*static int restore_gains(struct dahdi_pvt *p);*/
- struct dahdi_pvt *p = ast->tech_pvt;
- struct dahdi_pvt *tmp = NULL;
- struct dahdi_pvt *prev = NULL;
- struct dahdi_params par;
-
- if (option_debug)
- ast_log(LOG_DEBUG, "dahdi_hangup(%s)\n", ast->name);
- if (!ast->tech_pvt) {
- ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
- return 0;
- }
-
- ast_mutex_lock(&p->lock);
-
- index = dahdi_get_index(ast, p, 1);
-
- if (p->sig == SIG_PRI) {
- x = 1;
- ast_channel_setoption(ast,AST_OPTION_AUDIO_MODE,&x,sizeof(char),0);
- }
-
- x = 0;
- dahdi_confmute(p, 0);
- restore_gains(p);
- if (p->origcid_num) {
- ast_copy_string(p->cid_num, p->origcid_num, sizeof(p->cid_num));
- free(p->origcid_num);
- p->origcid_num = NULL;
- }
- if (p->origcid_name) {
- ast_copy_string(p->cid_name, p->origcid_name, sizeof(p->cid_name));
- free(p->origcid_name);
- p->origcid_name = NULL;
- }
- if (p->dsp)
- ast_dsp_digitmode(p->dsp,DSP_DIGITMODE_DTMF | p->dtmfrelax);
- if (p->exten)
- p->exten[0] = '\0';
-
- if (option_debug)
- ast_log(LOG_DEBUG, "Hangup: channel: %d index = %d, normal = %d, callwait = %d, thirdcall = %d\n",
- p->channel, index, p->subs[SUB_REAL].dfd, p->subs[SUB_CALLWAIT].dfd, p->subs[SUB_THREEWAY].dfd);
- p->ignoredtmf = 0;
-
- if (index > -1) {
- /* Real channel, do some fixup */
- p->subs[index].owner = NULL;
- p->subs[index].needanswer = 0;
- p->subs[index].needflash = 0;
- p->subs[index].needringing = 0;
- p->subs[index].needbusy = 0;
- p->subs[index].needcongestion = 0;
- p->subs[index].linear = 0;
- p->subs[index].needcallerid = 0;
- p->polarity = POLARITY_IDLE;
- dahdi_setlinear(p->subs[index].dfd, 0);
- if (index == SUB_REAL) {
- if ((p->subs[SUB_CALLWAIT].dfd > -1) && (p->subs[SUB_THREEWAY].dfd > -1)) {
- ast_log(LOG_DEBUG, "Normal call hung up with both three way call and a call waiting call in place?\n");
- if (p->subs[SUB_CALLWAIT].inthreeway) {
- /* We had flipped over to answer a callwait and now it's gone */
- ast_log(LOG_DEBUG, "We were flipped over to the callwait, moving back and unowning.\n");
- /* Move to the call-wait, but un-own us until they flip back. */
- swap_subs(p, SUB_CALLWAIT, SUB_REAL);
- unalloc_sub(p, SUB_CALLWAIT);
- p->owner = NULL;
- } else {
- /* The three way hung up, but we still have a call wait */
- ast_log(LOG_DEBUG, "We were in the threeway and have a callwait still. Ditching the threeway.\n");
- swap_subs(p, SUB_THREEWAY, SUB_REAL);
- unalloc_sub(p, SUB_THREEWAY);
- if (p->subs[SUB_REAL].inthreeway) {
- /* This was part of a three way call. Immediately make way for
- another call */
- ast_log(LOG_DEBUG, "Call was complete, setting owner to former third call\n");
- p->owner = p->subs[SUB_REAL].owner;
- } else {
- /* This call hasn't been completed yet... Set owner to NULL */
- ast_log(LOG_DEBUG, "Call was incomplete, setting owner to NULL\n");
- p->owner = NULL;
- }
- p->subs[SUB_REAL].inthreeway = 0;
- }
- } else if (p->subs[SUB_CALLWAIT].dfd > -1) {
- /* Move to the call-wait and switch back to them. */
- swap_subs(p, SUB_CALLWAIT, SUB_REAL);
- unalloc_sub(p, SUB_CALLWAIT);
- p->owner = p->subs[SUB_REAL].owner;
- if (p->owner->_state != AST_STATE_UP)
- p->subs[SUB_REAL].needanswer = 1;
- if (ast_bridged_channel(p->subs[SUB_REAL].owner))
- ast_queue_control(p->subs[SUB_REAL].owner, AST_CONTROL_UNHOLD);
- } else if (p->subs[SUB_THREEWAY].dfd > -1) {
- swap_subs(p, SUB_THREEWAY, SUB_REAL);
- unalloc_sub(p, SUB_THREEWAY);
- if (p->subs[SUB_REAL].inthreeway) {
- /* This was part of a three way call. Immediately make way for
- another call */
- ast_log(LOG_DEBUG, "Call was complete, setting owner to former third call\n");
- p->owner = p->subs[SUB_REAL].owner;
- } else {
- /* This call hasn't been completed yet... Set owner to NULL */
- ast_log(LOG_DEBUG, "Call was incomplete, setting owner to NULL\n");
- p->owner = NULL;
- }
- p->subs[SUB_REAL].inthreeway = 0;
- }
- } else if (index == SUB_CALLWAIT) {
- /* Ditch the holding callwait call, and immediately make it availabe */
- if (p->subs[SUB_CALLWAIT].inthreeway) {
- /* This is actually part of a three way, placed on hold. Place the third part
- on music on hold now */
- if (p->subs[SUB_THREEWAY].owner && ast_bridged_channel(p->subs[SUB_THREEWAY].owner)) {
- ast_queue_control_data(p->subs[SUB_THREEWAY].owner, AST_CONTROL_HOLD,
- S_OR(p->mohsuggest, NULL),
- !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
- }
- p->subs[SUB_THREEWAY].inthreeway = 0;
- /* Make it the call wait now */
- swap_subs(p, SUB_CALLWAIT, SUB_THREEWAY);
- unalloc_sub(p, SUB_THREEWAY);
- } else
- unalloc_sub(p, SUB_CALLWAIT);
- } else if (index == SUB_THREEWAY) {
- if (p->subs[SUB_CALLWAIT].inthreeway) {
- /* The other party of the three way call is currently in a call-wait state.
- Start music on hold for them, and take the main guy out of the third call */
- if (p->subs[SUB_CALLWAIT].owner && ast_bridged_channel(p->subs[SUB_CALLWAIT].owner)) {
- ast_queue_control_data(p->subs[SUB_CALLWAIT].owner, AST_CONTROL_HOLD,
- S_OR(p->mohsuggest, NULL),
- !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
- }
- p->subs[SUB_CALLWAIT].inthreeway = 0;
- }
- p->subs[SUB_REAL].inthreeway = 0;
- /* If this was part of a three way call index, let us make
- another three way call */
- unalloc_sub(p, SUB_THREEWAY);
- } else {
- /* This wasn't any sort of call, but how are we an index? */
- ast_log(LOG_WARNING, "Index found but not any type of call?\n");
- }
- }
-
- if (!p->subs[SUB_REAL].owner && !p->subs[SUB_CALLWAIT].owner && !p->subs[SUB_THREEWAY].owner) {
- p->owner = NULL;
- p->ringt = 0;
- p->distinctivering = 0;
- p->confirmanswer = 0;
- p->cidrings = 1;
- p->outgoing = 0;
- p->digital = 0;
- p->faxhandled = 0;
- p->pulsedial = 0;
- p->onhooktime = time(NULL);
-#ifdef HAVE_PRI
- p->proceeding = 0;
- p->progress = 0;
- p->alerting = 0;
- p->setup_ack = 0;
-#endif
- if (p->dsp) {
- ast_dsp_free(p->dsp);
- p->dsp = NULL;
- }
-
- law = DAHDI_LAW_DEFAULT;
- res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETLAW, &law);
- if (res < 0)
- ast_log(LOG_WARNING, "Unable to set law on channel %d to default: %s\n", p->channel, strerror(errno));
- /* Perform low level hangup if no owner left */
-#ifdef HAVE_PRI
- if (p->pri) {
-#ifdef SUPPORT_USERUSER
- const char *useruser = pbx_builtin_getvar_helper(ast,"USERUSERINFO");
-#endif
-
- /* Make sure we have a call (or REALLY have a call in the case of a PRI) */
- if (p->call && (!p->bearer || (p->bearer->call == p->call))) {
- if (!pri_grab(p, p->pri)) {
- if (p->alreadyhungup) {
- ast_log(LOG_DEBUG, "Already hungup... Calling hangup once, and clearing call\n");
-
-#ifdef SUPPORT_USERUSER
- pri_call_set_useruser(p->call, useruser);
-#endif
-
- pri_hangup(p->pri->pri, p->call, -1);
- p->call = NULL;
- if (p->bearer)
- p->bearer->call = NULL;
- } else {
- const char *cause = pbx_builtin_getvar_helper(ast,"PRI_CAUSE");
- int icause = ast->hangupcause ? ast->hangupcause : -1;
- ast_log(LOG_DEBUG, "Not yet hungup... Calling hangup once with icause, and clearing call\n");
-
-#ifdef SUPPORT_USERUSER
- pri_call_set_useruser(p->call, useruser);
-#endif
-
- p->alreadyhungup = 1;
- if (p->bearer)
- p->bearer->alreadyhungup = 1;
- if (cause) {
- if (atoi(cause))
- icause = atoi(cause);
- }
- pri_hangup(p->pri->pri, p->call, icause);
- }
- if (res < 0)
- ast_log(LOG_WARNING, "pri_disconnect failed\n");
- pri_rel(p->pri);
- } else {
- ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
- res = -1;
- }
- } else {
- if (p->bearer)
- ast_log(LOG_DEBUG, "Bearer call is %p, while ours is still %p\n", p->bearer->call, p->call);
- p->call = NULL;
- res = 0;
- }
- }
-#endif
- if (p->sig && (p->sig != SIG_PRI))
- res = dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
- if (res < 0) {
- ast_log(LOG_WARNING, "Unable to hangup line %s\n", ast->name);
- }
- switch (p->sig) {
- case SIG_FXOGS:
- case SIG_FXOLS:
- case SIG_FXOKS:
- res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &par);
- if (!res) {
-#if 0
- ast_log(LOG_DEBUG, "Hanging up channel %d, offhook = %d\n", p->channel, par.rxisoffhook);
-#endif
- /* If they're off hook, try playing congestion */
- if ((par.rxisoffhook) && (!(p->radio || (p->oprmode < 0))))
- tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
- else
- tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
- }
- break;
- case SIG_FXSGS:
- case SIG_FXSLS:
- case SIG_FXSKS:
- /* Make sure we're not made available for at least two seconds assuming
- we were actually used for an inbound or outbound call. */
- if (ast->_state != AST_STATE_RESERVED) {
- time(&p->guardtime);
- p->guardtime += 2;
- }
- break;
- default:
- tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
- }
- if (p->cidspill)
- free(p->cidspill);
- if (p->sig)
- dahdi_disable_ec(p);
- x = 0;
- ast_channel_setoption(ast,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0);
- ast_channel_setoption(ast,AST_OPTION_TDD,&x,sizeof(char),0);
- p->didtdd = 0;
- p->cidspill = NULL;
- p->callwaitcas = 0;
- p->callwaiting = p->permcallwaiting;
- p->hidecallerid = p->permhidecallerid;
- p->dialing = 0;
- p->rdnis[0] = '\0';
- update_conf(p);
- reset_conf(p);
- /* Restore data mode */
- if (p->sig == SIG_PRI) {
- x = 0;
- ast_channel_setoption(ast,AST_OPTION_AUDIO_MODE,&x,sizeof(char),0);
- }
-#ifdef HAVE_PRI
- if (p->bearer) {
- ast_log(LOG_DEBUG, "Freeing up bearer channel %d\n", p->bearer->channel);
- /* Free up the bearer channel as well, and
- don't use its file descriptor anymore */
- update_conf(p->bearer);
- reset_conf(p->bearer);
- p->bearer->owner = NULL;
- p->bearer->realcall = NULL;
- p->bearer = NULL;
- p->subs[SUB_REAL].dfd = -1;
- p->pri = NULL;
- }
-#endif
- if (num_restart_pending == 0)
- restart_monitor();
- }
-
- p->callwaitingrepeat = 0;
- p->cidcwexpire = 0;
- p->oprmode = 0;
- ast->tech_pvt = NULL;
- ast_mutex_unlock(&p->lock);
- ast_module_unref(ast_module_info->self);
- if (option_verbose > 2)
- ast_verbose( VERBOSE_PREFIX_3 "Hungup '%s'\n", ast->name);
-
- ast_mutex_lock(&iflock);
-
- if (p->restartpending) {
- num_restart_pending--;
- }
-
- tmp = iflist;
- prev = NULL;
- if (p->destroy) {
- while (tmp) {
- if (tmp == p) {
- destroy_channel(prev, tmp, 0);
- break;
- } else {
- prev = tmp;
- tmp = tmp->next;
- }
- }
- }
- ast_mutex_unlock(&iflock);
- return 0;
-}
-
-static int dahdi_answer(struct ast_channel *ast)
-{
- struct dahdi_pvt *p = ast->tech_pvt;
- int res = 0;
- int index;
- int oldstate = ast->_state;
- ast_setstate(ast, AST_STATE_UP);
- ast_mutex_lock(&p->lock);
- index = dahdi_get_index(ast, p, 0);
- if (index < 0)
- index = SUB_REAL;
- /* nothing to do if a radio channel */
- if ((p->radio || (p->oprmode < 0))) {
- ast_mutex_unlock(&p->lock);
- return 0;
- }
- switch (p->sig) {
- case SIG_FXSLS:
- case SIG_FXSGS:
- case SIG_FXSKS:
- p->ringt = 0;
- /* Fall through */
- case SIG_EM:
- case SIG_EM_E1:
- case SIG_EMWINK:
- case SIG_FEATD:
- case SIG_FEATDMF:
- case SIG_FEATDMF_TA:
- case SIG_E911:
- case SIG_FGC_CAMA:
- case SIG_FGC_CAMAMF:
- case SIG_FEATB:
- case SIG_SF:
- case SIG_SFWINK:
- case SIG_SF_FEATD:
- case SIG_SF_FEATDMF:
- case SIG_SF_FEATB:
- case SIG_FXOLS:
- case SIG_FXOGS:
- case SIG_FXOKS:
- /* Pick up the line */
- ast_log(LOG_DEBUG, "Took %s off hook\n", ast->name);
- if (p->hanguponpolarityswitch) {
- gettimeofday(&p->polaritydelaytv, NULL);
- }
- res = dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
- tone_zone_play_tone(p->subs[index].dfd, -1);
- p->dialing = 0;
- if ((index == SUB_REAL) && p->subs[SUB_THREEWAY].inthreeway) {
- if (oldstate == AST_STATE_RINGING) {
- ast_log(LOG_DEBUG, "Finally swapping real and threeway\n");
- tone_zone_play_tone(p->subs[SUB_THREEWAY].dfd, -1);
- swap_subs(p, SUB_THREEWAY, SUB_REAL);
- p->owner = p->subs[SUB_REAL].owner;
- }
- }
- if (p->sig & __DAHDI_SIG_FXS) {
- dahdi_enable_ec(p);
- dahdi_train_ec(p);
- }
- break;
-#ifdef HAVE_PRI
- case SIG_PRI:
- /* Send a pri acknowledge */
- if (!pri_grab(p, p->pri)) {
- p->proceeding = 1;
- res = pri_answer(p->pri->pri, p->call, 0, !p->digital);
- pri_rel(p->pri);
- } else {
- ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
- res = -1;
- }
- break;
-#endif
- case 0:
- ast_mutex_unlock(&p->lock);
- return 0;
- default:
- ast_log(LOG_WARNING, "Don't know how to answer signalling %d (channel %d)\n", p->sig, p->channel);
- res = -1;
- }
- ast_mutex_unlock(&p->lock);
- return res;
-}
-
-static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int datalen)
-{
- char *cp;
- signed char *scp;
- int x;
- int index;
- struct dahdi_pvt *p = chan->tech_pvt, *pp;
- struct oprmode *oprmode;
-
-
- /* all supported options require data */
- if (!data || (datalen < 1)) {
- errno = EINVAL;
- return -1;
- }
-
- switch (option) {
- case AST_OPTION_TXGAIN:
- scp = (signed char *) data;
- index = dahdi_get_index(chan, p, 0);
- if (index < 0) {
- ast_log(LOG_WARNING, "No index in TXGAIN?\n");
- return -1;
- }
- if (option_debug)
- ast_log(LOG_DEBUG, "Setting actual tx gain on %s to %f\n", chan->name, p->txgain + (float) *scp);
- return set_actual_txgain(p->subs[index].dfd, 0, p->txgain + (float) *scp, p->law);
- case AST_OPTION_RXGAIN:
- scp = (signed char *) data;
- index = dahdi_get_index(chan, p, 0);
- if (index < 0) {
- ast_log(LOG_WARNING, "No index in RXGAIN?\n");
- return -1;
- }
- if (option_debug)
- ast_log(LOG_DEBUG, "Setting actual rx gain on %s to %f\n", chan->name, p->rxgain + (float) *scp);
- return set_actual_rxgain(p->subs[index].dfd, 0, p->rxgain + (float) *scp, p->law);
- case AST_OPTION_TONE_VERIFY:
- if (!p->dsp)
- break;
- cp = (char *) data;
- switch (*cp) {
- case 1:
- ast_log(LOG_DEBUG, "Set option TONE VERIFY, mode: MUTECONF(1) on %s\n",chan->name);
- ast_dsp_digitmode(p->dsp,DSP_DIGITMODE_MUTECONF | p->dtmfrelax); /* set mute mode if desired */
- break;
- case 2:
- ast_log(LOG_DEBUG, "Set option TONE VERIFY, mode: MUTECONF/MAX(2) on %s\n",chan->name);
- ast_dsp_digitmode(p->dsp,DSP_DIGITMODE_MUTECONF | DSP_DIGITMODE_MUTEMAX | p->dtmfrelax); /* set mute mode if desired */
- break;
- default:
- ast_log(LOG_DEBUG, "Set option TONE VERIFY, mode: OFF(0) on %s\n",chan->name);
- ast_dsp_digitmode(p->dsp,DSP_DIGITMODE_DTMF | p->dtmfrelax); /* set mute mode if desired */
- break;
- }
- break;
- case AST_OPTION_TDD:
- /* turn on or off TDD */
- cp = (char *) data;
- p->mate = 0;
- if (!*cp) { /* turn it off */
- if (option_debug)
- ast_log(LOG_DEBUG, "Set option TDD MODE, value: OFF(0) on %s\n",chan->name);
- if (p->tdd)
- tdd_free(p->tdd);
- p->tdd = 0;
- break;
- }
- ast_log(LOG_DEBUG, "Set option TDD MODE, value: %s(%d) on %s\n",
- (*cp == 2) ? "MATE" : "ON", (int) *cp, chan->name);
- dahdi_disable_ec(p);
- /* otherwise, turn it on */
- if (!p->didtdd) { /* if havent done it yet */
- unsigned char mybuf[41000], *buf;
- int size, res, fd, len;
- struct pollfd fds[1];
-
- buf = mybuf;
- memset(buf, 0x7f, sizeof(mybuf)); /* set to silence */
- ast_tdd_gen_ecdisa(buf + 16000, 16000); /* put in tone */
- len = 40000;
- index = dahdi_get_index(chan, p, 0);
- if (index < 0) {
- ast_log(LOG_WARNING, "No index in TDD?\n");
- return -1;
- }
- fd = p->subs[index].dfd;
- while (len) {
- if (ast_check_hangup(chan))
- return -1;
- size = len;
- if (size > READ_SIZE)
- size = READ_SIZE;
- fds[0].fd = fd;
- fds[0].events = POLLPRI | POLLOUT;
- fds[0].revents = 0;
- res = poll(fds, 1, -1);
- if (!res) {
- ast_log(LOG_DEBUG, "poll (for write) ret. 0 on channel %d\n", p->channel);
- continue;
- }
- /* if got exception */
- if (fds[0].revents & POLLPRI)
- return -1;
- if (!(fds[0].revents & POLLOUT)) {
- ast_log(LOG_DEBUG, "write fd not ready on channel %d\n", p->channel);
- continue;
- }
- res = write(fd, buf, size);
- if (res != size) {
- if (res == -1) return -1;
- ast_log(LOG_DEBUG, "Write returned %d (%s) on channel %d\n", res, strerror(errno), p->channel);
- break;
- }
- len -= size;
- buf += size;
- }
- p->didtdd = 1; /* set to have done it now */
- }
- if (*cp == 2) { /* Mate mode */
- if (p->tdd)
- tdd_free(p->tdd);
- p->tdd = 0;
- p->mate = 1;
- break;
- }
- if (!p->tdd) { /* if we dont have one yet */
- p->tdd = tdd_new(); /* allocate one */
- }
- break;
- case AST_OPTION_RELAXDTMF: /* Relax DTMF decoding (or not) */
- if (!p->dsp)
- break;
- cp = (char *) data;
- ast_log(LOG_DEBUG, "Set option RELAX DTMF, value: %s(%d) on %s\n",
- *cp ? "ON" : "OFF", (int) *cp, chan->name);
- p->dtmfrelax = 0;
- if (*cp) p->dtmfrelax = DSP_DIGITMODE_RELAXDTMF;
- ast_dsp_digitmode(p->dsp, DSP_DIGITMODE_DTMF | p->dtmfrelax);
- break;
- case AST_OPTION_AUDIO_MODE: /* Set AUDIO mode (or not) */
- cp = (char *) data;
- if (!*cp) {
- ast_log(LOG_DEBUG, "Set option AUDIO MODE, value: OFF(0) on %s\n", chan->name);
- x = 0;
- dahdi_disable_ec(p);
- } else {
- ast_log(LOG_DEBUG, "Set option AUDIO MODE, value: ON(1) on %s\n", chan->name);
- x = 1;
- }
- if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &x) == -1)
- ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d: %s\n", p->channel, x, strerror(errno));
- break;
- case AST_OPTION_OPRMODE: /* Operator services mode */
- oprmode = (struct oprmode *) data;
- pp = oprmode->peer->tech_pvt;
- p->oprmode = pp->oprmode = 0;
- /* setup peers */
- p->oprpeer = pp;
- pp->oprpeer = p;
- /* setup modes, if any */
- if (oprmode->mode)
- {
- pp->oprmode = oprmode->mode;
- p->oprmode = -oprmode->mode;
- }
- ast_log(LOG_DEBUG, "Set Operator Services mode, value: %d on %s/%s\n",
- oprmode->mode, chan->name,oprmode->peer->name);;
- break;
- case AST_OPTION_ECHOCAN:
- cp = (char *) data;
- if (*cp) {
- ast_log(LOG_DEBUG, "Enabling echo cancelation on %s\n", chan->name);
- dahdi_enable_ec(p);
- } else {
- ast_log(LOG_DEBUG, "Disabling echo cancelation on %s\n", chan->name);
- dahdi_disable_ec(p);
- }
- break;
- }
- errno = 0;
-
- return 0;
-}
-
-static int dahdi_func_read(struct ast_channel *chan, char *function, char *data, char *buf, size_t len)
-{
- struct dahdi_pvt *p = chan->tech_pvt;
-
- if (!strcasecmp(data, "rxgain")) {
- ast_mutex_lock(&p->lock);
- snprintf(buf, len, "%f", p->rxgain);
- ast_mutex_unlock(&p->lock);
- } else if (!strcasecmp(data, "txgain")) {
- ast_mutex_lock(&p->lock);
- snprintf(buf, len, "%f", p->txgain);
- ast_mutex_unlock(&p->lock);
- } else {
- ast_copy_string(buf, "", len);
- }
- return 0;
-}
-
-
-static void dahdi_unlink(struct dahdi_pvt *slave, struct dahdi_pvt *master, int needlock)
-{
- /* Unlink a specific slave or all slaves/masters from a given master */
- int x;
- int hasslaves;
- if (!master)
- return;
- if (needlock) {
- ast_mutex_lock(&master->lock);
- if (slave) {
- while (ast_mutex_trylock(&slave->lock)) {
- DEADLOCK_AVOIDANCE(&master->lock);
- }
- }
- }
- hasslaves = 0;
- for (x = 0; x < MAX_SLAVES; x++) {
- if (master->slaves[x]) {
- if (!slave || (master->slaves[x] == slave)) {
- /* Take slave out of the conference */
- ast_log(LOG_DEBUG, "Unlinking slave %d from %d\n", master->slaves[x]->channel, master->channel);
- conf_del(master, &master->slaves[x]->subs[SUB_REAL], SUB_REAL);
- conf_del(master->slaves[x], &master->subs[SUB_REAL], SUB_REAL);
- master->slaves[x]->master = NULL;
- master->slaves[x] = NULL;
- } else
- hasslaves = 1;
- }
- if (!hasslaves)
- master->inconference = 0;
- }
- if (!slave) {
- if (master->master) {
- /* Take master out of the conference */
- conf_del(master->master, &master->subs[SUB_REAL], SUB_REAL);
- conf_del(master, &master->master->subs[SUB_REAL], SUB_REAL);
- hasslaves = 0;
- for (x = 0; x < MAX_SLAVES; x++) {
- if (master->master->slaves[x] == master)
- master->master->slaves[x] = NULL;
- else if (master->master->slaves[x])
- hasslaves = 1;
- }
- if (!hasslaves)
- master->master->inconference = 0;
- }
- master->master = NULL;
- }
- update_conf(master);
- if (needlock) {
- if (slave)
- ast_mutex_unlock(&slave->lock);
- ast_mutex_unlock(&master->lock);
- }
-}
-
-static void dahdi_link(struct dahdi_pvt *slave, struct dahdi_pvt *master) {
- int x;
- if (!slave || !master) {
- ast_log(LOG_WARNING, "Tried to link to/from NULL??\n");
- return;
- }
- for (x = 0; x < MAX_SLAVES; x++) {
- if (!master->slaves[x]) {
- master->slaves[x] = slave;
- break;
- }
- }
- if (x >= MAX_SLAVES) {
- ast_log(LOG_WARNING, "Replacing slave %d with new slave, %d\n", master->slaves[MAX_SLAVES - 1]->channel, slave->channel);
- master->slaves[MAX_SLAVES - 1] = slave;
- }
- if (slave->master)
- ast_log(LOG_WARNING, "Replacing master %d with new master, %d\n", slave->master->channel, master->channel);
- slave->master = master;
-
- ast_log(LOG_DEBUG, "Making %d slave to master %d at %d\n", slave->channel, master->channel, x);
-}
-
-static void disable_dtmf_detect(struct dahdi_pvt *p)
-{
-#ifdef DAHDI_TONEDETECT
- int val;
-#endif
-
- p->ignoredtmf = 1;
-
-#ifdef DAHDI_TONEDETECT
- val = 0;
- ioctl(p->subs[SUB_REAL].dfd, DAHDI_TONEDETECT, &val);
-#endif
- if (!p->hardwaredtmf && p->dsp) {
- p->dsp_features &= ~DSP_FEATURE_DTMF_DETECT;
- ast_dsp_set_features(p->dsp, p->dsp_features);
- }
-}
-
-static void enable_dtmf_detect(struct dahdi_pvt *p)
-{
-#ifdef DAHDI_TONEDETECT
- int val;
-#endif
-
- if (p->channel == CHAN_PSEUDO)
- return;
-
- p->ignoredtmf = 0;
-
-#ifdef DAHDI_TONEDETECT
- val = DAHDI_TONEDETECT_ON | DAHDI_TONEDETECT_MUTE;
- ioctl(p->subs[SUB_REAL].dfd, DAHDI_TONEDETECT, &val);
-#endif
- if (!p->hardwaredtmf && p->dsp) {
- p->dsp_features |= DSP_FEATURE_DTMF_DETECT;
- ast_dsp_set_features(p->dsp, p->dsp_features);
- }
-}
-
-static enum ast_bridge_result dahdi_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms)
-{
- struct ast_channel *who;
- struct dahdi_pvt *p0, *p1, *op0, *op1;
- struct dahdi_pvt *master = NULL, *slave = NULL;
- struct ast_frame *f;
- int inconf = 0;
- int nothingok = 1;
- int ofd0, ofd1;
- int oi0, oi1, i0 = -1, i1 = -1, t0, t1;
- int os0 = -1, os1 = -1;
- int priority = 0;
- struct ast_channel *oc0, *oc1;
- enum ast_bridge_result res;
-
-#ifdef PRI_2BCT
- int triedtopribridge = 0;
- q931_call *q931c0 = NULL, *q931c1 = NULL;
-#endif
-
- /* For now, don't attempt to native bridge if either channel needs DTMF detection.
- There is code below to handle it properly until DTMF is actually seen,
- but due to currently unresolved issues it's ignored...
- */
-
- if (flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1))
- return AST_BRIDGE_FAILED_NOWARN;
-
- ast_mutex_lock(&c0->lock);
- while (ast_mutex_trylock(&c1->lock)) {
- DEADLOCK_AVOIDANCE(&c0->lock);
- }
-
- p0 = c0->tech_pvt;
- p1 = c1->tech_pvt;
- /* cant do pseudo-channels here */
- if (!p0 || (!p0->sig) || !p1 || (!p1->sig)) {
- ast_mutex_unlock(&c0->lock);
- ast_mutex_unlock(&c1->lock);
- return AST_BRIDGE_FAILED_NOWARN;
- }
-
- oi0 = dahdi_get_index(c0, p0, 0);
- oi1 = dahdi_get_index(c1, p1, 0);
- if ((oi0 < 0) || (oi1 < 0)) {
- ast_mutex_unlock(&c0->lock);
- ast_mutex_unlock(&c1->lock);
- return AST_BRIDGE_FAILED;
- }
-
- op0 = p0 = c0->tech_pvt;
- op1 = p1 = c1->tech_pvt;
- ofd0 = c0->fds[0];
- ofd1 = c1->fds[0];
- oc0 = p0->owner;
- oc1 = p1->owner;
-
- if (ast_mutex_trylock(&p0->lock)) {
- /* Don't block, due to potential for deadlock */
- ast_mutex_unlock(&c0->lock);
- ast_mutex_unlock(&c1->lock);
- ast_log(LOG_NOTICE, "Avoiding deadlock...\n");
- return AST_BRIDGE_RETRY;
- }
- if (ast_mutex_trylock(&p1->lock)) {
- /* Don't block, due to potential for deadlock */
- ast_mutex_unlock(&p0->lock);
- ast_mutex_unlock(&c0->lock);
- ast_mutex_unlock(&c1->lock);
- ast_log(LOG_NOTICE, "Avoiding deadlock...\n");
- return AST_BRIDGE_RETRY;
- }
-
- if ((oi0 == SUB_REAL) && (oi1 == SUB_REAL)) {
- if (p0->owner && p1->owner) {
- /* If we don't have a call-wait in a 3-way, and we aren't in a 3-way, we can be master */
- if (!p0->subs[SUB_CALLWAIT].inthreeway && !p1->subs[SUB_REAL].inthreeway) {
- master = p0;
- slave = p1;
- inconf = 1;
- } else if (!p1->subs[SUB_CALLWAIT].inthreeway && !p0->subs[SUB_REAL].inthreeway) {
- master = p1;
- slave = p0;
- inconf = 1;
- } else {
- ast_log(LOG_WARNING, "Huh? Both calls are callwaits or 3-ways? That's clever...?\n");
- ast_log(LOG_WARNING, "p0: chan %d/%d/CW%d/3W%d, p1: chan %d/%d/CW%d/3W%d\n",
- p0->channel,
- oi0, (p0->subs[SUB_CALLWAIT].dfd > -1) ? 1 : 0,
- p0->subs[SUB_REAL].inthreeway, p0->channel,
- oi0, (p1->subs[SUB_CALLWAIT].dfd > -1) ? 1 : 0,
- p1->subs[SUB_REAL].inthreeway);
- }
- nothingok = 0;
- }
- } else if ((oi0 == SUB_REAL) && (oi1 == SUB_THREEWAY)) {
- if (p1->subs[SUB_THREEWAY].inthreeway) {
- master = p1;
- slave = p0;
- nothingok = 0;
- }
- } else if ((oi0 == SUB_THREEWAY) && (oi1 == SUB_REAL)) {
- if (p0->subs[SUB_THREEWAY].inthreeway) {
- master = p0;
- slave = p1;
- nothingok = 0;
- }
- } else if ((oi0 == SUB_REAL) && (oi1 == SUB_CALLWAIT)) {
- /* We have a real and a call wait. If we're in a three way call, put us in it, otherwise,
- don't put us in anything */
- if (p1->subs[SUB_CALLWAIT].inthreeway) {
- master = p1;
- slave = p0;
- nothingok = 0;
- }
- } else if ((oi0 == SUB_CALLWAIT) && (oi1 == SUB_REAL)) {
- /* Same as previous */
- if (p0->subs[SUB_CALLWAIT].inthreeway) {
- master = p0;
- slave = p1;
- nothingok = 0;
- }
- }
- ast_log(LOG_DEBUG, "master: %d, slave: %d, nothingok: %d\n",
- master ? master->channel : 0, slave ? slave->channel : 0, nothingok);
- if (master && slave) {
- /* Stop any tones, or play ringtone as appropriate. If they're bridged
- in an active threeway call with a channel that is ringing, we should
- indicate ringing. */
- if ((oi1 == SUB_THREEWAY) &&
- p1->subs[SUB_THREEWAY].inthreeway &&
- p1->subs[SUB_REAL].owner &&
- p1->subs[SUB_REAL].inthreeway &&
- (p1->subs[SUB_REAL].owner->_state == AST_STATE_RINGING)) {
- ast_log(LOG_DEBUG, "Playing ringback on %s since %s is in a ringing three-way\n", c0->name, c1->name);
- tone_zone_play_tone(p0->subs[oi0].dfd, DAHDI_TONE_RINGTONE);
- os1 = p1->subs[SUB_REAL].owner->_state;
- } else {
- ast_log(LOG_DEBUG, "Stopping tones on %d/%d talking to %d/%d\n", p0->channel, oi0, p1->channel, oi1);
- tone_zone_play_tone(p0->subs[oi0].dfd, -1);
- }
- if ((oi0 == SUB_THREEWAY) &&
- p0->subs[SUB_THREEWAY].inthreeway &&
- p0->subs[SUB_REAL].owner &&
- p0->subs[SUB_REAL].inthreeway &&
- (p0->subs[SUB_REAL].owner->_state == AST_STATE_RINGING)) {
- ast_log(LOG_DEBUG, "Playing ringback on %s since %s is in a ringing three-way\n", c1->name, c0->name);
- tone_zone_play_tone(p1->subs[oi1].dfd, DAHDI_TONE_RINGTONE);
- os0 = p0->subs[SUB_REAL].owner->_state;
- } else {
- ast_log(LOG_DEBUG, "Stopping tones on %d/%d talking to %d/%d\n", p1->channel, oi1, p0->channel, oi0);
- tone_zone_play_tone(p1->subs[oi0].dfd, -1);
- }
- if ((oi0 == SUB_REAL) && (oi1 == SUB_REAL)) {
- if (!p0->echocanbridged || !p1->echocanbridged) {
- /* Disable echo cancellation if appropriate */
- dahdi_disable_ec(p0);
- dahdi_disable_ec(p1);
- }
- }
- dahdi_link(slave, master);
- master->inconference = inconf;
- } else if (!nothingok)
- ast_log(LOG_WARNING, "Can't link %d/%s with %d/%s\n", p0->channel, subnames[oi0], p1->channel, subnames[oi1]);
-
- update_conf(p0);
- update_conf(p1);
- t0 = p0->subs[SUB_REAL].inthreeway;
- t1 = p1->subs[SUB_REAL].inthreeway;
-
- ast_mutex_unlock(&p0->lock);
- ast_mutex_unlock(&p1->lock);
-
- ast_mutex_unlock(&c0->lock);
- ast_mutex_unlock(&c1->lock);
-
- /* Native bridge failed */
- if ((!master || !slave) && !nothingok) {
- dahdi_enable_ec(p0);
- dahdi_enable_ec(p1);
- return AST_BRIDGE_FAILED;
- }
-
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Native bridging %s and %s\n", c0->name, c1->name);
-
- if (!(flags & AST_BRIDGE_DTMF_CHANNEL_0) && (oi0 == SUB_REAL))
- disable_dtmf_detect(op0);
-
- if (!(flags & AST_BRIDGE_DTMF_CHANNEL_1) && (oi1 == SUB_REAL))
- disable_dtmf_detect(op1);
-
- for (;;) {
- struct ast_channel *c0_priority[2] = {c0, c1};
- struct ast_channel *c1_priority[2] = {c1, c0};
-
- /* Here's our main loop... Start by locking things, looking for private parts,
- and then balking if anything is wrong */
- ast_mutex_lock(&c0->lock);
- while (ast_mutex_trylock(&c1->lock)) {
- DEADLOCK_AVOIDANCE(&c0->lock);
- }
-
- p0 = c0->tech_pvt;
- p1 = c1->tech_pvt;
-
- if (op0 == p0)
- i0 = dahdi_get_index(c0, p0, 1);
- if (op1 == p1)
- i1 = dahdi_get_index(c1, p1, 1);
- ast_mutex_unlock(&c0->lock);
- ast_mutex_unlock(&c1->lock);
-
- if (!timeoutms ||
- (op0 != p0) ||
- (op1 != p1) ||
- (ofd0 != c0->fds[0]) ||
- (ofd1 != c1->fds[0]) ||
- (p0->subs[SUB_REAL].owner && (os0 > -1) && (os0 != p0->subs[SUB_REAL].owner->_state)) ||
- (p1->subs[SUB_REAL].owner && (os1 > -1) && (os1 != p1->subs[SUB_REAL].owner->_state)) ||
- (oc0 != p0->owner) ||
- (oc1 != p1->owner) ||
- (t0 != p0->subs[SUB_REAL].inthreeway) ||
- (t1 != p1->subs[SUB_REAL].inthreeway) ||
- (oi0 != i0) ||
- (oi1 != i1)) {
- ast_log(LOG_DEBUG, "Something changed out on %d/%d to %d/%d, returning -3 to restart\n",
- op0->channel, oi0, op1->channel, oi1);
- res = AST_BRIDGE_RETRY;
- goto return_from_bridge;
- }
-
-#ifdef PRI_2BCT
- q931c0 = p0->call;
- q931c1 = p1->call;
- if (p0->transfer && p1->transfer
- && q931c0 && q931c1
- && !triedtopribridge) {
- pri_channel_bridge(q931c0, q931c1);
- triedtopribridge = 1;
- }
-#endif
-
- who = ast_waitfor_n(priority ? c0_priority : c1_priority, 2, &timeoutms);
- if (!who) {
- ast_log(LOG_DEBUG, "Ooh, empty read...\n");
- continue;
- }
- f = ast_read(who);
- if (!f || (f->frametype == AST_FRAME_CONTROL)) {
- *fo = f;
- *rc = who;
- res = AST_BRIDGE_COMPLETE;
- goto return_from_bridge;
- }
- if (f->frametype == AST_FRAME_DTMF) {
- if ((who == c0) && p0->pulsedial) {
- ast_write(c1, f);
- } else if ((who == c1) && p1->pulsedial) {
- ast_write(c0, f);
- } else {
- *fo = f;
- *rc = who;
- res = AST_BRIDGE_COMPLETE;
- goto return_from_bridge;
- }
- }
- ast_frfree(f);
-
- /* Swap who gets priority */
- priority = !priority;
- }
-
-return_from_bridge:
- if (op0 == p0)
- dahdi_enable_ec(p0);
-
- if (op1 == p1)
- dahdi_enable_ec(p1);
-
- if (!(flags & AST_BRIDGE_DTMF_CHANNEL_0) && (oi0 == SUB_REAL))
- enable_dtmf_detect(op0);
-
- if (!(flags & AST_BRIDGE_DTMF_CHANNEL_1) && (oi1 == SUB_REAL))
- enable_dtmf_detect(op1);
-
- dahdi_unlink(slave, master, 1);
-
- return res;
-}
-
-static int dahdi_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
-{
- struct dahdi_pvt *p = newchan->tech_pvt;
- int x;
- ast_mutex_lock(&p->lock);
- ast_log(LOG_DEBUG, "New owner for channel %d is %s\n", p->channel, newchan->name);
- if (p->owner == oldchan) {
- p->owner = newchan;
- }
- for (x = 0; x < 3; x++)
- if (p->subs[x].owner == oldchan) {
- if (!x)
- dahdi_unlink(NULL, p, 0);
- p->subs[x].owner = newchan;
- }
- if (newchan->_state == AST_STATE_RINGING)
- dahdi_indicate(newchan, AST_CONTROL_RINGING, NULL, 0);
- update_conf(p);
- ast_mutex_unlock(&p->lock);
- return 0;
-}
-
-static int dahdi_ring_phone(struct dahdi_pvt *p)
-{
- int x;
- int res;
- /* Make sure our transmit state is on hook */
- x = 0;
- x = DAHDI_ONHOOK;
- res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
- do {
- x = DAHDI_RING;
- res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
- if (res) {
- switch (errno) {
- case EBUSY:
- case EINTR:
- /* Wait just in case */
- usleep(10000);
- continue;
- case EINPROGRESS:
- res = 0;
- break;
- default:
- ast_log(LOG_WARNING, "Couldn't ring the phone: %s\n", strerror(errno));
- res = 0;
- }
- }
- } while (res);
- return res;
-}
-
-static void *ss_thread(void *data);
-
-static struct ast_channel *dahdi_new(struct dahdi_pvt *, int, int, int, int, int);
-
-static int attempt_transfer(struct dahdi_pvt *p)
-{
- /* In order to transfer, we need at least one of the channels to
- actually be in a call bridge. We can't conference two applications
- together (but then, why would we want to?) */
- if (ast_bridged_channel(p->subs[SUB_REAL].owner)) {
- /* The three-way person we're about to transfer to could still be in MOH, so
- stop if now if appropriate */
- if (ast_bridged_channel(p->subs[SUB_THREEWAY].owner))
- ast_queue_control(p->subs[SUB_THREEWAY].owner, AST_CONTROL_UNHOLD);
- if (p->subs[SUB_REAL].owner->_state == AST_STATE_RINGING) {
- ast_indicate(ast_bridged_channel(p->subs[SUB_REAL].owner), AST_CONTROL_RINGING);
- }
- if (p->subs[SUB_THREEWAY].owner->_state == AST_STATE_RING) {
- tone_zone_play_tone(p->subs[SUB_THREEWAY].dfd, DAHDI_TONE_RINGTONE);
- }
- if (ast_channel_masquerade(p->subs[SUB_THREEWAY].owner, ast_bridged_channel(p->subs[SUB_REAL].owner))) {
- ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
- ast_bridged_channel(p->subs[SUB_REAL].owner)->name, p->subs[SUB_THREEWAY].owner->name);
- return -1;
- }
- /* Orphan the channel after releasing the lock */
- ast_mutex_unlock(&p->subs[SUB_THREEWAY].owner->lock);
- unalloc_sub(p, SUB_THREEWAY);
- } else if (ast_bridged_channel(p->subs[SUB_THREEWAY].owner)) {
- ast_queue_control(p->subs[SUB_REAL].owner, AST_CONTROL_UNHOLD);
- if (p->subs[SUB_THREEWAY].owner->_state == AST_STATE_RINGING) {
- ast_indicate(ast_bridged_channel(p->subs[SUB_THREEWAY].owner), AST_CONTROL_RINGING);
- }
- if (p->subs[SUB_REAL].owner->_state == AST_STATE_RING) {
- tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
- }
- if (ast_channel_masquerade(p->subs[SUB_REAL].owner, ast_bridged_channel(p->subs[SUB_THREEWAY].owner))) {
- ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
- ast_bridged_channel(p->subs[SUB_THREEWAY].owner)->name, p->subs[SUB_REAL].owner->name);
- return -1;
- }
- /* Three-way is now the REAL */
- swap_subs(p, SUB_THREEWAY, SUB_REAL);
- ast_mutex_unlock(&p->subs[SUB_REAL].owner->lock);
- unalloc_sub(p, SUB_THREEWAY);
- /* Tell the caller not to hangup */
- return 1;
- } else {
- ast_log(LOG_DEBUG, "Neither %s nor %s are in a bridge, nothing to transfer\n",
- p->subs[SUB_REAL].owner->name, p->subs[SUB_THREEWAY].owner->name);
- p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
- return -1;
- }
- return 0;
-}
-
-static int check_for_conference(struct dahdi_pvt *p)
-{
- struct dahdi_confinfo ci;
- /* Fine if we already have a master, etc */
- if (p->master || (p->confno > -1))
- return 0;
- memset(&ci, 0, sizeof(ci));
- if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_GETCONF, &ci)) {
- ast_log(LOG_WARNING, "Failed to get conference info on channel %d: %s\n", p->channel, strerror(errno));
- return 0;
- }
- /* If we have no master and don't have a confno, then
- if we're in a conference, it's probably a MeetMe room or
- some such, so don't let us 3-way out! */
- if ((p->subs[SUB_REAL].curconf.confno != ci.confno) || (p->subs[SUB_REAL].curconf.confmode != ci.confmode)) {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Avoiding 3-way call when in an external conference\n");
- return 1;
- }
- return 0;
-}
-
-static int get_alarms(struct dahdi_pvt *p)
-{
- int res;
- struct dahdi_spaninfo zi;
-#if !defined(HAVE_ZAPTEL) || defined(HAVE_ZAPTEL_CHANALARMS)
- /*
- * The conditional compilation is needed only in asterisk-1.4 for
- * backward compatibility with old zaptel drivers that don't have
- * a DAHDI_PARAMS.chan_alarms field.
- */
- struct dahdi_params params;
-#endif
-
- memset(&zi, 0, sizeof(zi));
- zi.spanno = p->span;
-
- /* First check for span alarms */
- if((res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SPANSTAT, &zi)) < 0) {
- ast_log(LOG_WARNING, "Unable to determine alarm on channel %d: %s\n", p->channel, strerror(errno));
- return 0;
- }
- if (zi.alarms != DAHDI_ALARM_NONE)
- return zi.alarms;
-#if !defined(HAVE_ZAPTEL) || defined(HAVE_ZAPTEL_CHANALARMS)
- /* No alarms on the span. Check for channel alarms. */
- if ((res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &params)) >= 0)
- return params.chan_alarms;
- /* ioctl failed */
- ast_log(LOG_WARNING, "Unable to determine alarm on channel %d\n", p->channel);
-#endif
- return DAHDI_ALARM_NONE;
-}
-
-static void dahdi_handle_dtmfup(struct ast_channel *ast, int index, struct ast_frame **dest)
-{
- struct dahdi_pvt *p = ast->tech_pvt;
- struct ast_frame *f = *dest;
-
- if (option_debug)
- ast_log(LOG_DEBUG, "DTMF digit: %c on %s\n", f->subclass, ast->name);
-
- if (p->confirmanswer) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Confirm answer on %s!\n", ast->name);
- /* Upon receiving a DTMF digit, consider this an answer confirmation instead
- of a DTMF digit */
- p->subs[index].f.frametype = AST_FRAME_CONTROL;
- p->subs[index].f.subclass = AST_CONTROL_ANSWER;
- *dest = &p->subs[index].f;
- /* Reset confirmanswer so DTMF's will behave properly for the duration of the call */
- p->confirmanswer = 0;
- } else if (p->callwaitcas) {
- if ((f->subclass == 'A') || (f->subclass == 'D')) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Got some DTMF, but it's for the CAS\n");
- if (p->cidspill)
- free(p->cidspill);
- send_cwcidspill(p);
- }
- if ((f->subclass != 'm') && (f->subclass != 'u'))
- p->callwaitcas = 0;
- p->subs[index].f.frametype = AST_FRAME_NULL;
- p->subs[index].f.subclass = 0;
- *dest = &p->subs[index].f;
- } else if (f->subclass == 'f') {
- /* Fax tone -- Handle and return NULL */
- if ((p->callprogress & 0x6) && !p->faxhandled) {
- p->faxhandled++;
- if (strcmp(ast->exten, "fax")) {
- const char *target_context = S_OR(ast->macrocontext, ast->context);
-
- /* We need to unlock 'ast' here because ast_exists_extension has the
- * potential to start autoservice on the channel. Such action is prone
- * to deadlock.
- */
- ast_mutex_unlock(&p->lock);
- ast_channel_unlock(ast);
- if (ast_exists_extension(ast, target_context, "fax", 1, ast->cid.cid_num)) {
- ast_channel_lock(ast);
- ast_mutex_lock(&p->lock);
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Redirecting %s to fax extension\n", ast->name);
- /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
- pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast->exten);
- if (ast_async_goto(ast, target_context, "fax", 1))
- ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast->name, target_context);
- } else {
- ast_channel_lock(ast);
- ast_mutex_lock(&p->lock);
- ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n");
- }
- } else if (option_debug)
- ast_log(LOG_DEBUG, "Already in a fax extension, not redirecting\n");
- } else if (option_debug)
- ast_log(LOG_DEBUG, "Fax already handled\n");
- dahdi_confmute(p, 0);
- p->subs[index].f.frametype = AST_FRAME_NULL;
- p->subs[index].f.subclass = 0;
- *dest = &p->subs[index].f;
- } else if (f->subclass == 'm') {
- /* Confmute request */
- dahdi_confmute(p, 1);
- p->subs[index].f.frametype = AST_FRAME_NULL;
- p->subs[index].f.subclass = 0;
- *dest = &p->subs[index].f;
- } else if (f->subclass == 'u') {
- /* Unmute */
- dahdi_confmute(p, 0);
- p->subs[index].f.frametype = AST_FRAME_NULL;
- p->subs[index].f.subclass = 0;
- *dest = &p->subs[index].f;
- } else
- dahdi_confmute(p, 0);
-}
-
-static void handle_alarms(struct dahdi_pvt *p, int alarms)
-{
- const char *alarm_str = alarm2str(alarms);
-
- /* hack alert! Zaptel 1.4 and DAHDI expose FXO battery as an alarm, but this code
- * doesn't know what to do with it. Don't confuse users with log messages. */
- if (!strcasecmp(alarm_str, "No Alarm") || !strcasecmp(alarm_str, "Unknown Alarm")) {
- p->unknown_alarm = 1;
- return;
- } else {
- p->unknown_alarm = 0;
- }
-
- ast_log(LOG_WARNING, "Detected alarm on channel %d: %s\n", p->channel, alarm_str);
- manager_event(EVENT_FLAG_SYSTEM, "Alarm",
- "Alarm: %s\r\n"
- "Channel: %d\r\n",
- alarm_str, p->channel);
-}
-
-static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
-{
- int res, x;
- int index, mysig;
- char *c;
- struct dahdi_pvt *p = ast->tech_pvt;
- pthread_t threadid;
- pthread_attr_t attr;
- struct ast_channel *chan;
- struct ast_frame *f;
-
- index = dahdi_get_index(ast, p, 0);
- mysig = p->sig;
- if (p->outsigmod > -1)
- mysig = p->outsigmod;
- p->subs[index].f.frametype = AST_FRAME_NULL;
- p->subs[index].f.subclass = 0;
- p->subs[index].f.datalen = 0;
- p->subs[index].f.samples = 0;
- p->subs[index].f.mallocd = 0;
- p->subs[index].f.offset = 0;
- p->subs[index].f.src = "dahdi_handle_event";
- p->subs[index].f.data = NULL;
- f = &p->subs[index].f;
-
- if (index < 0)
- return &p->subs[index].f;
- if (p->fake_event) {
- res = p->fake_event;
- p->fake_event = 0;
- } else
- res = dahdi_get_event(p->subs[index].dfd);
-
- if (option_debug)
- ast_log(LOG_DEBUG, "Got event %s(%d) on channel %d (index %d)\n", event2str(res), res, p->channel, index);
-
- if (res & (DAHDI_EVENT_PULSEDIGIT | DAHDI_EVENT_DTMFUP)) {
- p->pulsedial = (res & DAHDI_EVENT_PULSEDIGIT) ? 1 : 0;
-
- ast_log(LOG_DEBUG, "Detected %sdigit '%c'\n", p->pulsedial ? "pulse ": "", res & 0xff);
-#ifdef HAVE_PRI
- if (!p->proceeding && p->sig == SIG_PRI && p->pri && p->pri->overlapdial) {
- /* absorb event */
- } else {
-#endif
- p->subs[index].f.frametype = AST_FRAME_DTMF_END;
- p->subs[index].f.subclass = res & 0xff;
-#ifdef HAVE_PRI
- }
-#endif
- dahdi_handle_dtmfup(ast, index, &f);
- return f;
- }
-
- if (res & DAHDI_EVENT_DTMFDOWN) {
- if (option_debug)
- ast_log(LOG_DEBUG, "DTMF Down '%c'\n", res & 0xff);
- /* Mute conference */
- dahdi_confmute(p, 1);
- p->subs[index].f.frametype = AST_FRAME_DTMF_BEGIN;
- p->subs[index].f.subclass = res & 0xff;
- return &p->subs[index].f;
- }
-
- switch (res) {
-#ifdef DAHDI_EVENT_EC_DISABLED
- case DAHDI_EVENT_EC_DISABLED:
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Channel %d echo canceler disabled due to CED detection\n", p->channel);
- p->echocanon = 0;
- break;
-#endif
- case DAHDI_EVENT_BITSCHANGED:
- ast_log(LOG_WARNING, "Recieved bits changed on %s signalling?\n", sig2str(p->sig));
- case DAHDI_EVENT_PULSE_START:
- /* Stop tone if there's a pulse start and the PBX isn't started */
- if (!ast->pbx)
- tone_zone_play_tone(p->subs[index].dfd, -1);
- break;
- case DAHDI_EVENT_DIALCOMPLETE:
- if (p->inalarm) break;
- if ((p->radio || (p->oprmode < 0))) break;
- if (ioctl(p->subs[index].dfd,DAHDI_DIALING,&x) == -1) {
- ast_log(LOG_DEBUG, "DAHDI_DIALING ioctl failed on %s: %s\n",ast->name, strerror(errno));
- return NULL;
- }
- if (!x) { /* if not still dialing in driver */
- dahdi_enable_ec(p);
- if (p->echobreak) {
- dahdi_train_ec(p);
- ast_copy_string(p->dop.dialstr, p->echorest, sizeof(p->dop.dialstr));
- p->dop.op = DAHDI_DIAL_OP_REPLACE;
- res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop);
- p->echobreak = 0;
- } else {
- p->dialing = 0;
- if ((mysig == SIG_E911) || (mysig == SIG_FGC_CAMA) || (mysig == SIG_FGC_CAMAMF)) {
- /* if thru with dialing after offhook */
- if (ast->_state == AST_STATE_DIALING_OFFHOOK) {
- ast_setstate(ast, AST_STATE_UP);
- p->subs[index].f.frametype = AST_FRAME_CONTROL;
- p->subs[index].f.subclass = AST_CONTROL_ANSWER;
- break;
- } else { /* if to state wait for offhook to dial rest */
- /* we now wait for off hook */
- ast_setstate(ast,AST_STATE_DIALING_OFFHOOK);
- }
- }
- if (ast->_state == AST_STATE_DIALING) {
- if ((p->callprogress & 1) && CANPROGRESSDETECT(p) && p->dsp && p->outgoing) {
- ast_log(LOG_DEBUG, "Done dialing, but waiting for progress detection before doing more...\n");
- } else if (p->confirmanswer || (!p->dialednone && ((mysig == SIG_EM) || (mysig == SIG_EM_E1) || (mysig == SIG_EMWINK) || (mysig == SIG_FEATD) || (mysig == SIG_FEATDMF_TA) || (mysig == SIG_FEATDMF) || (mysig == SIG_E911) || (mysig == SIG_FGC_CAMA) || (mysig == SIG_FGC_CAMAMF) || (mysig == SIG_FEATB) || (mysig == SIG_SF) || (mysig == SIG_SFWINK) || (mysig == SIG_SF_FEATD) || (mysig == SIG_SF_FEATDMF) || (mysig == SIG_SF_FEATB)))) {
- ast_setstate(ast, AST_STATE_RINGING);
- } else if (!p->answeronpolarityswitch) {
- ast_setstate(ast, AST_STATE_UP);
- p->subs[index].f.frametype = AST_FRAME_CONTROL;
- p->subs[index].f.subclass = AST_CONTROL_ANSWER;
- /* If aops=0 and hops=1, this is necessary */
- p->polarity = POLARITY_REV;
- } else {
- /* Start clean, so we can catch the change to REV polarity when party answers */
- p->polarity = POLARITY_IDLE;
- }
- }
- }
- }
- break;
- case DAHDI_EVENT_ALARM:
-#ifdef HAVE_PRI
- if (!p->pri || !p->pri->pri || (pri_get_timer(p->pri->pri, PRI_TIMER_T309) < 0)) {
- /* T309 is not enabled : hangup calls when alarm occurs */
- if (p->call) {
- if (p->pri && p->pri->pri) {
- if (!pri_grab(p, p->pri)) {
- pri_hangup(p->pri->pri, p->call, -1);
- pri_destroycall(p->pri->pri, p->call);
- p->call = NULL;
- pri_rel(p->pri);
- } else
- ast_log(LOG_WARNING, "Failed to grab PRI!\n");
- } else
- ast_log(LOG_WARNING, "The PRI Call has not been destroyed\n");
- }
- if (p->owner)
- p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
- }
- if (p->bearer)
- p->bearer->inalarm = 1;
- else
-#endif
- p->inalarm = 1;
- res = get_alarms(p);
- handle_alarms(p, res);
-#ifdef HAVE_LIBPRI
- if (!p->pri || !p->pri->pri || pri_get_timer(p->pri->pri, PRI_TIMER_T309) < 0) {
- /* fall through intentionally */
- } else {
- break;
- }
-#endif
- case DAHDI_EVENT_ONHOOK:
- if (p->radio) {
- p->subs[index].f.frametype = AST_FRAME_CONTROL;
- p->subs[index].f.subclass = AST_CONTROL_RADIO_UNKEY;
- break;
- }
- if (p->oprmode < 0)
- {
- if (p->oprmode != -1) break;
- if ((p->sig == SIG_FXOLS) || (p->sig == SIG_FXOKS) || (p->sig == SIG_FXOGS))
- {
- /* Make sure it starts ringing */
- dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_RINGOFF);
- dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_RING);
- save_conference(p->oprpeer);
- tone_zone_play_tone(p->oprpeer->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
- }
- break;
- }
- switch (p->sig) {
- case SIG_FXOLS:
- case SIG_FXOGS:
- case SIG_FXOKS:
- p->onhooktime = time(NULL);
- p->msgstate = -1;
- /* Check for some special conditions regarding call waiting */
- if (index == SUB_REAL) {
- /* The normal line was hung up */
- if (p->subs[SUB_CALLWAIT].owner) {
- /* There's a call waiting call, so ring the phone, but make it unowned in the mean time */
- swap_subs(p, SUB_CALLWAIT, SUB_REAL);
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Channel %d still has (callwait) call, ringing phone\n", p->channel);
- unalloc_sub(p, SUB_CALLWAIT);
-#if 0
- p->subs[index].needanswer = 0;
- p->subs[index].needringing = 0;
-#endif
- p->callwaitingrepeat = 0;
- p->cidcwexpire = 0;
- p->owner = NULL;
- /* Don't start streaming audio yet if the incoming call isn't up yet */
- if (p->subs[SUB_REAL].owner->_state != AST_STATE_UP)
- p->dialing = 1;
- dahdi_ring_phone(p);
- } else if (p->subs[SUB_THREEWAY].owner) {
- unsigned int mssinceflash;
- /* Here we have to retain the lock on both the main channel, the 3-way channel, and
- the private structure -- not especially easy or clean */
- while (p->subs[SUB_THREEWAY].owner && ast_mutex_trylock(&p->subs[SUB_THREEWAY].owner->lock)) {
- /* Yuck, didn't get the lock on the 3-way, gotta release everything and re-grab! */
- ast_mutex_unlock(&p->lock);
- DEADLOCK_AVOIDANCE(&ast->lock);
- /* We can grab ast and p in that order, without worry. We should make sure
- nothing seriously bad has happened though like some sort of bizarre double
- masquerade! */
- ast_mutex_lock(&p->lock);
- if (p->owner != ast) {
- ast_log(LOG_WARNING, "This isn't good...\n");
- return NULL;
- }
- }
- if (!p->subs[SUB_THREEWAY].owner) {
- ast_log(LOG_NOTICE, "Whoa, threeway disappeared kinda randomly.\n");
- return NULL;
- }
- mssinceflash = ast_tvdiff_ms(ast_tvnow(), p->flashtime);
- ast_log(LOG_DEBUG, "Last flash was %d ms ago\n", mssinceflash);
- if (mssinceflash < MIN_MS_SINCE_FLASH) {
- /* It hasn't been long enough since the last flashook. This is probably a bounce on
- hanging up. Hangup both channels now */
- if (p->subs[SUB_THREEWAY].owner)
- ast_queue_hangup(p->subs[SUB_THREEWAY].owner);
- p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
- ast_log(LOG_DEBUG, "Looks like a bounced flash, hanging up both calls on %d\n", p->channel);
- ast_mutex_unlock(&p->subs[SUB_THREEWAY].owner->lock);
- } else if ((ast->pbx) || (ast->_state == AST_STATE_UP)) {
- if (p->transfer) {
- /* In any case this isn't a threeway call anymore */
- p->subs[SUB_REAL].inthreeway = 0;
- p->subs[SUB_THREEWAY].inthreeway = 0;
- /* Only attempt transfer if the phone is ringing; why transfer to busy tone eh? */
- if (!p->transfertobusy && ast->_state == AST_STATE_BUSY) {
- ast_mutex_unlock(&p->subs[SUB_THREEWAY].owner->lock);
- /* Swap subs and dis-own channel */
- swap_subs(p, SUB_THREEWAY, SUB_REAL);
- p->owner = NULL;
- /* Ring the phone */
- dahdi_ring_phone(p);
- } else {
- if ((res = attempt_transfer(p)) < 0) {
- p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
- if (p->subs[SUB_THREEWAY].owner)
- ast_mutex_unlock(&p->subs[SUB_THREEWAY].owner->lock);
- } else if (res) {
- /* Don't actually hang up at this point */
- if (p->subs[SUB_THREEWAY].owner)
- ast_mutex_unlock(&p->subs[SUB_THREEWAY].owner->lock);
- break;
- }
- }
- } else {
- p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
- if (p->subs[SUB_THREEWAY].owner)
- ast_mutex_unlock(&p->subs[SUB_THREEWAY].owner->lock);
- }
- } else {
- ast_mutex_unlock(&p->subs[SUB_THREEWAY].owner->lock);
- /* Swap subs and dis-own channel */
- swap_subs(p, SUB_THREEWAY, SUB_REAL);
- p->owner = NULL;
- /* Ring the phone */
- dahdi_ring_phone(p);
- }
- }
- } else {
- ast_log(LOG_WARNING, "Got a hangup and my index is %d?\n", index);
- }
- /* Fall through */
- default:
- dahdi_disable_ec(p);
- return NULL;
- }
- break;
- case DAHDI_EVENT_RINGOFFHOOK:
- if (p->inalarm) break;
- if (p->oprmode < 0)
- {
- if ((p->sig == SIG_FXOLS) || (p->sig == SIG_FXOKS) || (p->sig == SIG_FXOGS))
- {
- /* Make sure it stops ringing */
- dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_RINGOFF);
- tone_zone_play_tone(p->oprpeer->subs[SUB_REAL].dfd, -1);
- restore_conference(p->oprpeer);
- }
- break;
- }
- if (p->radio)
- {
- p->subs[index].f.frametype = AST_FRAME_CONTROL;
- p->subs[index].f.subclass = AST_CONTROL_RADIO_KEY;
- break;
- }
- /* for E911, its supposed to wait for offhook then dial
- the second half of the dial string */
- if (((mysig == SIG_E911) || (mysig == SIG_FGC_CAMA) || (mysig == SIG_FGC_CAMAMF)) && (ast->_state == AST_STATE_DIALING_OFFHOOK)) {
- c = strchr(p->dialdest, '/');
- if (c)
- c++;
- else
- c = p->dialdest;
- if (*c) snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*0%s#", c);
- else ast_copy_string(p->dop.dialstr,"M*2#", sizeof(p->dop.dialstr));
- if (strlen(p->dop.dialstr) > 4) {
- memset(p->echorest, 'w', sizeof(p->echorest) - 1);
- strcpy(p->echorest + (p->echotraining / 401) + 1, p->dop.dialstr + strlen(p->dop.dialstr) - 2);
- p->echorest[sizeof(p->echorest) - 1] = '\0';
- p->echobreak = 1;
- p->dop.dialstr[strlen(p->dop.dialstr)-2] = '\0';
- } else
- p->echobreak = 0;
- if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop)) {
- int saveerr = errno;
-
- x = DAHDI_ONHOOK;
- ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
- ast_log(LOG_WARNING, "Dialing failed on channel %d: %s\n", p->channel, strerror(saveerr));
- return NULL;
- }
- p->dialing = 1;
- return &p->subs[index].f;
- }
- switch (p->sig) {
- case SIG_FXOLS:
- case SIG_FXOGS:
- case SIG_FXOKS:
- switch (ast->_state) {
- case AST_STATE_RINGING:
- dahdi_enable_ec(p);
- dahdi_train_ec(p);
- p->subs[index].f.frametype = AST_FRAME_CONTROL;
- p->subs[index].f.subclass = AST_CONTROL_ANSWER;
- /* Make sure it stops ringing */
- dahdi_set_hook(p->subs[index].dfd, DAHDI_OFFHOOK);
- ast_log(LOG_DEBUG, "channel %d answered\n", p->channel);
- if (p->cidspill) {
- /* Cancel any running CallerID spill */
- free(p->cidspill);
- p->cidspill = NULL;
- }
- p->dialing = 0;
- p->callwaitcas = 0;
- if (p->confirmanswer) {
- /* Ignore answer if "confirm answer" is enabled */
- p->subs[index].f.frametype = AST_FRAME_NULL;
- p->subs[index].f.subclass = 0;
- } else if (!ast_strlen_zero(p->dop.dialstr)) {
- /* nick@dccinc.com 4/3/03 - fxo should be able to do deferred dialing */
- res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop);
- if (res < 0) {
- ast_log(LOG_WARNING, "Unable to initiate dialing on trunk channel %d: %s\n", p->channel, strerror(errno));
- p->dop.dialstr[0] = '\0';
- return NULL;
- } else {
- ast_log(LOG_DEBUG, "Sent FXO deferred digit string: %s\n", p->dop.dialstr);
- p->subs[index].f.frametype = AST_FRAME_NULL;
- p->subs[index].f.subclass = 0;
- p->dialing = 1;
- }
- p->dop.dialstr[0] = '\0';
- ast_setstate(ast, AST_STATE_DIALING);
- } else
- ast_setstate(ast, AST_STATE_UP);
- return &p->subs[index].f;
- case AST_STATE_DOWN:
- ast_setstate(ast, AST_STATE_RING);
- ast->rings = 1;
- p->subs[index].f.frametype = AST_FRAME_CONTROL;
- p->subs[index].f.subclass = AST_CONTROL_OFFHOOK;
- ast_log(LOG_DEBUG, "channel %d picked up\n", p->channel);
- return &p->subs[index].f;
- case AST_STATE_UP:
- /* Make sure it stops ringing */
- dahdi_set_hook(p->subs[index].dfd, DAHDI_OFFHOOK);
- /* Okay -- probably call waiting*/
- if (ast_bridged_channel(p->owner))
- ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
- p->subs[index].needunhold = 1;
- break;
- case AST_STATE_RESERVED:
- /* Start up dialtone */
- if (has_voicemail(p))
- res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_STUTTER);
- else
- res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_DIALTONE);
- break;
- default:
- ast_log(LOG_WARNING, "FXO phone off hook in weird state %d??\n", ast->_state);
- }
- break;
- case SIG_FXSLS:
- case SIG_FXSGS:
- case SIG_FXSKS:
- if (ast->_state == AST_STATE_RING) {
- p->ringt = p->ringt_base;
- }
-
- /* Fall through */
- case SIG_EM:
- case SIG_EM_E1:
- case SIG_EMWINK:
- case SIG_FEATD:
- case SIG_FEATDMF:
- case SIG_FEATDMF_TA:
- case SIG_E911:
- case SIG_FGC_CAMA:
- case SIG_FGC_CAMAMF:
- case SIG_FEATB:
- case SIG_SF:
- case SIG_SFWINK:
- case SIG_SF_FEATD:
- case SIG_SF_FEATDMF:
- case SIG_SF_FEATB:
- if (ast->_state == AST_STATE_PRERING)
- ast_setstate(ast, AST_STATE_RING);
- if ((ast->_state == AST_STATE_DOWN) || (ast->_state == AST_STATE_RING)) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Ring detected\n");
- p->subs[index].f.frametype = AST_FRAME_CONTROL;
- p->subs[index].f.subclass = AST_CONTROL_RING;
- } else if (p->outgoing && ((ast->_state == AST_STATE_RINGING) || (ast->_state == AST_STATE_DIALING))) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Line answered\n");
- if (p->confirmanswer) {
- p->subs[index].f.frametype = AST_FRAME_NULL;
- p->subs[index].f.subclass = 0;
- } else {
- p->subs[index].f.frametype = AST_FRAME_CONTROL;
- p->subs[index].f.subclass = AST_CONTROL_ANSWER;
- ast_setstate(ast, AST_STATE_UP);
- }
- } else if (ast->_state != AST_STATE_RING)
- ast_log(LOG_WARNING, "Ring/Off-hook in strange state %d on channel %d\n", ast->_state, p->channel);
- break;
- default:
- ast_log(LOG_WARNING, "Don't know how to handle ring/off hook for signalling %d\n", p->sig);
- }
- break;
-#ifdef DAHDI_EVENT_RINGBEGIN
- case DAHDI_EVENT_RINGBEGIN:
- switch (p->sig) {
- case SIG_FXSLS:
- case SIG_FXSGS:
- case SIG_FXSKS:
- if (ast->_state == AST_STATE_RING) {
- p->ringt = p->ringt_base;
- }
- break;
- }
- break;
-#endif
- case DAHDI_EVENT_RINGEROFF:
- if (p->inalarm) break;
- if ((p->radio || (p->oprmode < 0))) break;
- ast->rings++;
- if ((ast->rings > p->cidrings) && (p->cidspill)) {
- ast_log(LOG_WARNING, "Didn't finish Caller-ID spill. Cancelling.\n");
- free(p->cidspill);
- p->cidspill = NULL;
- p->callwaitcas = 0;
- }
- p->subs[index].f.frametype = AST_FRAME_CONTROL;
- p->subs[index].f.subclass = AST_CONTROL_RINGING;
- break;
- case DAHDI_EVENT_RINGERON:
- break;
- case DAHDI_EVENT_NOALARM:
- p->inalarm = 0;
-#ifdef HAVE_PRI
- /* Extremely unlikely but just in case */
- if (p->bearer)
- p->bearer->inalarm = 0;
-#endif
- if (!p->unknown_alarm) {
- ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", p->channel);
- manager_event(EVENT_FLAG_SYSTEM, "AlarmClear",
- "Channel: %d\r\n", p->channel);
- } else {
- p->unknown_alarm = 0;
- }
- break;
- case DAHDI_EVENT_WINKFLASH:
- if (p->inalarm) break;
- if (p->radio) break;
- if (p->oprmode < 0) break;
- if (p->oprmode > 1)
- {
- struct dahdi_params par;
-
- if (ioctl(p->oprpeer->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &par) != -1)
- {
- if (!par.rxisoffhook)
- {
- /* Make sure it stops ringing */
- dahdi_set_hook(p->oprpeer->subs[SUB_REAL].dfd, DAHDI_RINGOFF);
- dahdi_set_hook(p->oprpeer->subs[SUB_REAL].dfd, DAHDI_RING);
- save_conference(p);
- tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
- }
- }
- break;
- }
- /* Remember last time we got a flash-hook */
- gettimeofday(&p->flashtime, NULL);
- switch (mysig) {
- case SIG_FXOLS:
- case SIG_FXOGS:
- case SIG_FXOKS:
- ast_log(LOG_DEBUG, "Winkflash, index: %d, normal: %d, callwait: %d, thirdcall: %d\n",
- index, p->subs[SUB_REAL].dfd, p->subs[SUB_CALLWAIT].dfd, p->subs[SUB_THREEWAY].dfd);
- p->callwaitcas = 0;
-
- if (index != SUB_REAL) {
- ast_log(LOG_WARNING, "Got flash hook with index %d on channel %d?!?\n", index, p->channel);
- goto winkflashdone;
- }
-
- if (p->subs[SUB_CALLWAIT].owner) {
- /* Swap to call-wait */
- swap_subs(p, SUB_REAL, SUB_CALLWAIT);
- tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
- p->owner = p->subs[SUB_REAL].owner;
- ast_log(LOG_DEBUG, "Making %s the new owner\n", p->owner->name);
- if (p->owner->_state == AST_STATE_RINGING) {
- ast_setstate(p->owner, AST_STATE_UP);
- p->subs[SUB_REAL].needanswer = 1;
- }
- p->callwaitingrepeat = 0;
- p->cidcwexpire = 0;
- /* Start music on hold if appropriate */
- if (!p->subs[SUB_CALLWAIT].inthreeway && ast_bridged_channel(p->subs[SUB_CALLWAIT].owner)) {
- ast_queue_control_data(p->subs[SUB_CALLWAIT].owner, AST_CONTROL_HOLD,
- S_OR(p->mohsuggest, NULL),
- !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
- }
- p->subs[SUB_CALLWAIT].needhold = 1;
- if (ast_bridged_channel(p->subs[SUB_REAL].owner)) {
- ast_queue_control_data(p->subs[SUB_REAL].owner, AST_CONTROL_HOLD,
- S_OR(p->mohsuggest, NULL),
- !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
- }
- p->subs[SUB_REAL].needunhold = 1;
- } else if (!p->subs[SUB_THREEWAY].owner) {
- char cid_num[256];
- char cid_name[256];
-
- if (!p->threewaycalling) {
- /* Just send a flash if no 3-way calling */
- p->subs[SUB_REAL].needflash = 1;
- goto winkflashdone;
- } else if (!check_for_conference(p)) {
- if (p->dahditrcallerid && p->owner) {
- if (p->owner->cid.cid_num)
- ast_copy_string(cid_num, p->owner->cid.cid_num, sizeof(cid_num));
- if (p->owner->cid.cid_name)
- ast_copy_string(cid_name, p->owner->cid.cid_name, sizeof(cid_name));
- }
- /* XXX This section needs much more error checking!!! XXX */
- /* Start a 3-way call if feasible */
- if (!((ast->pbx) ||
- (ast->_state == AST_STATE_UP) ||
- (ast->_state == AST_STATE_RING))) {
- ast_log(LOG_DEBUG, "Flash when call not up or ringing\n");
- goto winkflashdone;
- }
- if (alloc_sub(p, SUB_THREEWAY)) {
- ast_log(LOG_WARNING, "Unable to allocate three-way subchannel\n");
- goto winkflashdone;
- }
- /* Make new channel */
- chan = dahdi_new(p, AST_STATE_RESERVED, 0, SUB_THREEWAY, 0, 0);
- if (p->dahditrcallerid) {
- if (!p->origcid_num)
- p->origcid_num = ast_strdup(p->cid_num);
- if (!p->origcid_name)
- p->origcid_name = ast_strdup(p->cid_name);
- ast_copy_string(p->cid_num, cid_num, sizeof(p->cid_num));
- ast_copy_string(p->cid_name, cid_name, sizeof(p->cid_name));
- }
- /* Swap things around between the three-way and real call */
- swap_subs(p, SUB_THREEWAY, SUB_REAL);
- /* Disable echo canceller for better dialing */
- dahdi_disable_ec(p);
- res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_DIALRECALL);
- if (res)
- ast_log(LOG_WARNING, "Unable to start dial recall tone on channel %d\n", p->channel);
- p->owner = chan;
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- if (!chan) {
- ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", p->channel);
- } else if (ast_pthread_create(&threadid, &attr, ss_thread, chan)) {
- ast_log(LOG_WARNING, "Unable to start simple switch on channel %d\n", p->channel);
- res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
- dahdi_enable_ec(p);
- ast_hangup(chan);
- } else {
- struct ast_channel *other = ast_bridged_channel(p->subs[SUB_THREEWAY].owner);
- int way3bridge = 0, cdr3way = 0;
-
- if (!other) {
- other = ast_bridged_channel(p->subs[SUB_REAL].owner);
- } else
- way3bridge = 1;
-
- if (p->subs[SUB_THREEWAY].owner->cdr)
- cdr3way = 1;
-
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Started three way call on channel %d\n", p->channel);
- /* Start music on hold if appropriate */
- if (ast_bridged_channel(p->subs[SUB_THREEWAY].owner)) {
- ast_queue_control_data(p->subs[SUB_THREEWAY].owner, AST_CONTROL_HOLD,
- S_OR(p->mohsuggest, NULL),
- !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
- }
- p->subs[SUB_THREEWAY].needhold = 1;
- }
- pthread_attr_destroy(&attr);
- }
- } else {
- /* Already have a 3 way call */
- if (p->subs[SUB_THREEWAY].inthreeway) {
- /* Call is already up, drop the last person */
- if (option_debug)
- ast_log(LOG_DEBUG, "Got flash with three way call up, dropping last call on %d\n", p->channel);
- /* If the primary call isn't answered yet, use it */
- if ((p->subs[SUB_REAL].owner->_state != AST_STATE_UP) && (p->subs[SUB_THREEWAY].owner->_state == AST_STATE_UP)) {
- /* Swap back -- we're dropping the real 3-way that isn't finished yet*/
- swap_subs(p, SUB_THREEWAY, SUB_REAL);
- p->owner = p->subs[SUB_REAL].owner;
- }
- /* Drop the last call and stop the conference */
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Dropping three-way call on %s\n", p->subs[SUB_THREEWAY].owner->name);
- p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
- p->subs[SUB_REAL].inthreeway = 0;
- p->subs[SUB_THREEWAY].inthreeway = 0;
- } else {
- /* Lets see what we're up to */
- if (((ast->pbx) || (ast->_state == AST_STATE_UP)) &&
- (p->transfertobusy || (ast->_state != AST_STATE_BUSY))) {
- int otherindex = SUB_THREEWAY;
- struct ast_channel *other = ast_bridged_channel(p->subs[SUB_THREEWAY].owner);
- int way3bridge = 0, cdr3way = 0;
-
- if (!other) {
- other = ast_bridged_channel(p->subs[SUB_REAL].owner);
- } else
- way3bridge = 1;
-
- if (p->subs[SUB_THREEWAY].owner->cdr)
- cdr3way = 1;
-
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Building conference on call on %s and %s\n", p->subs[SUB_THREEWAY].owner->name, p->subs[SUB_REAL].owner->name);
- /* Put them in the threeway, and flip */
- p->subs[SUB_THREEWAY].inthreeway = 1;
- p->subs[SUB_REAL].inthreeway = 1;
- if (ast->_state == AST_STATE_UP) {
- swap_subs(p, SUB_THREEWAY, SUB_REAL);
- otherindex = SUB_REAL;
- }
- if (p->subs[otherindex].owner && ast_bridged_channel(p->subs[otherindex].owner))
- ast_queue_control(p->subs[otherindex].owner, AST_CONTROL_UNHOLD);
- p->subs[otherindex].needunhold = 1;
- p->owner = p->subs[SUB_REAL].owner;
- if (ast->_state == AST_STATE_RINGING) {
- ast_log(LOG_DEBUG, "Enabling ringtone on real and threeway\n");
- res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
- res = tone_zone_play_tone(p->subs[SUB_THREEWAY].dfd, DAHDI_TONE_RINGTONE);
- }
- } else {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Dumping incomplete call on on %s\n", p->subs[SUB_THREEWAY].owner->name);
- swap_subs(p, SUB_THREEWAY, SUB_REAL);
- p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
- p->owner = p->subs[SUB_REAL].owner;
- if (p->subs[SUB_REAL].owner && ast_bridged_channel(p->subs[SUB_REAL].owner))
- ast_queue_control(p->subs[SUB_REAL].owner, AST_CONTROL_UNHOLD);
- p->subs[SUB_REAL].needunhold = 1;
- dahdi_enable_ec(p);
- }
-
- }
- }
- winkflashdone:
- update_conf(p);
- break;
- case SIG_EM:
- case SIG_EM_E1:
- case SIG_EMWINK:
- case SIG_FEATD:
- case SIG_SF:
- case SIG_SFWINK:
- case SIG_SF_FEATD:
- case SIG_FXSLS:
- case SIG_FXSGS:
- if (p->dialing)
- ast_log(LOG_DEBUG, "Ignoring wink on channel %d\n", p->channel);
- else
- ast_log(LOG_DEBUG, "Got wink in weird state %d on channel %d\n", ast->_state, p->channel);
- break;
- case SIG_FEATDMF_TA:
- switch (p->whichwink) {
- case 0:
- ast_log(LOG_DEBUG, "ANI2 set to '%d' and ANI is '%s'\n", p->owner->cid.cid_ani2, p->owner->cid.cid_ani);
- snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*%d%s#", p->owner->cid.cid_ani2, p->owner->cid.cid_ani);
- break;
- case 1:
- ast_copy_string(p->dop.dialstr, p->finaldial, sizeof(p->dop.dialstr));
- break;
- case 2:
- ast_log(LOG_WARNING, "Received unexpected wink on channel of type SIG_FEATDMF_TA\n");
- return NULL;
- }
- p->whichwink++;
- /* Fall through */
- case SIG_FEATDMF:
- case SIG_E911:
- case SIG_FGC_CAMAMF:
- case SIG_FGC_CAMA:
- case SIG_FEATB:
- case SIG_SF_FEATDMF:
- case SIG_SF_FEATB:
- /* FGD MF *Must* wait for wink */
- if (!ast_strlen_zero(p->dop.dialstr)) {
- res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop);
- if (res < 0) {
- ast_log(LOG_WARNING, "Unable to initiate dialing on trunk channel %d: %s\n", p->channel, strerror(errno));
- p->dop.dialstr[0] = '\0';
- return NULL;
- } else
- ast_log(LOG_DEBUG, "Sent deferred digit string: %s\n", p->dop.dialstr);
- }
- p->dop.dialstr[0] = '\0';
- break;
- default:
- ast_log(LOG_WARNING, "Don't know how to handle ring/off hoook for signalling %d\n", p->sig);
- }
- break;
- case DAHDI_EVENT_HOOKCOMPLETE:
- if (p->inalarm) break;
- if ((p->radio || (p->oprmode < 0))) break;
- switch (mysig) {
- case SIG_FXSLS: /* only interesting for FXS */
- case SIG_FXSGS:
- case SIG_FXSKS:
- case SIG_EM:
- case SIG_EM_E1:
- case SIG_EMWINK:
- case SIG_FEATD:
- case SIG_SF:
- case SIG_SFWINK:
- case SIG_SF_FEATD:
- if (!ast_strlen_zero(p->dop.dialstr)) {
- res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop);
- if (res < 0) {
- ast_log(LOG_WARNING, "Unable to initiate dialing on trunk channel %d: %s\n", p->channel, strerror(errno));
- p->dop.dialstr[0] = '\0';
- return NULL;
- } else
- ast_log(LOG_DEBUG, "Sent deferred digit string: %s\n", p->dop.dialstr);
- }
- p->dop.dialstr[0] = '\0';
- p->dop.op = DAHDI_DIAL_OP_REPLACE;
- break;
- case SIG_FEATDMF:
- case SIG_FEATDMF_TA:
- case SIG_E911:
- case SIG_FGC_CAMA:
- case SIG_FGC_CAMAMF:
- case SIG_FEATB:
- case SIG_SF_FEATDMF:
- case SIG_SF_FEATB:
- ast_log(LOG_DEBUG, "Got hook complete in MF FGD, waiting for wink now on channel %d\n",p->channel);
- break;
- default:
- break;
- }
- break;
- case DAHDI_EVENT_POLARITY:
- /*
- * If we get a Polarity Switch event, check to see
- * if we should change the polarity state and
- * mark the channel as UP or if this is an indication
- * of remote end disconnect.
- */
- if (p->polarity == POLARITY_IDLE) {
- p->polarity = POLARITY_REV;
- if (p->answeronpolarityswitch &&
- ((ast->_state == AST_STATE_DIALING) ||
- (ast->_state == AST_STATE_RINGING))) {
- ast_log(LOG_DEBUG, "Answering on polarity switch!\n");
- ast_setstate(p->owner, AST_STATE_UP);
- if (p->hanguponpolarityswitch) {
- gettimeofday(&p->polaritydelaytv, NULL);
- }
- } else
- ast_log(LOG_DEBUG, "Ignore switch to REVERSED Polarity on channel %d, state %d\n", p->channel, ast->_state);
- }
- /* Removed else statement from here as it was preventing hangups from ever happening*/
- /* Added AST_STATE_RING in if statement below to deal with calling party hangups that take place when ringing */
- if (p->hanguponpolarityswitch &&
- (p->polarityonanswerdelay > 0) &&
- (p->polarity == POLARITY_REV) &&
- ((ast->_state == AST_STATE_UP) || (ast->_state == AST_STATE_RING)) ) {
- /* Added log_debug information below to provide a better indication of what is going on */
- ast_log(LOG_DEBUG, "Polarity Reversal event occured - DEBUG 1: channel %d, state %d, pol= %d, aonp= %d, honp= %d, pdelay= %d, tv= %d\n", p->channel, ast->_state, p->polarity, p->answeronpolarityswitch, p->hanguponpolarityswitch, p->polarityonanswerdelay, ast_tvdiff_ms(ast_tvnow(), p->polaritydelaytv) );
-
- if (ast_tvdiff_ms(ast_tvnow(), p->polaritydelaytv) > p->polarityonanswerdelay) {
- ast_log(LOG_DEBUG, "Polarity Reversal detected and now Hanging up on channel %d\n", p->channel);
- ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
- p->polarity = POLARITY_IDLE;
- } else {
- ast_log(LOG_DEBUG, "Polarity Reversal detected but NOT hanging up (too close to answer event) on channel %d, state %d\n", p->channel, ast->_state);
- }
- } else {
- p->polarity = POLARITY_IDLE;
- ast_log(LOG_DEBUG, "Ignoring Polarity switch to IDLE on channel %d, state %d\n", p->channel, ast->_state);
- }
- /* Added more log_debug information below to provide a better indication of what is going on */
- ast_log(LOG_DEBUG, "Polarity Reversal event occured - DEBUG 2: channel %d, state %d, pol= %d, aonp= %d, honp= %d, pdelay= %d, tv= %d\n", p->channel, ast->_state, p->polarity, p->answeronpolarityswitch, p->hanguponpolarityswitch, p->polarityonanswerdelay, ast_tvdiff_ms(ast_tvnow(), p->polaritydelaytv) );
- break;
- default:
- ast_log(LOG_DEBUG, "Dunno what to do with event %d on channel %d\n", res, p->channel);
- }
- return &p->subs[index].f;
-}
-
-static struct ast_frame *__dahdi_exception(struct ast_channel *ast)
-{
- struct dahdi_pvt *p = ast->tech_pvt;
- int res;
- int usedindex=-1;
- int index;
- struct ast_frame *f;
-
-
- index = dahdi_get_index(ast, p, 1);
-
- p->subs[index].f.frametype = AST_FRAME_NULL;
- p->subs[index].f.datalen = 0;
- p->subs[index].f.samples = 0;
- p->subs[index].f.mallocd = 0;
- p->subs[index].f.offset = 0;
- p->subs[index].f.subclass = 0;
- p->subs[index].f.delivery = ast_tv(0,0);
- p->subs[index].f.src = "dahdi_exception";
- p->subs[index].f.data = NULL;
-
-
- if ((!p->owner) && (!(p->radio || (p->oprmode < 0)))) {
- /* If nobody owns us, absorb the event appropriately, otherwise
- we loop indefinitely. This occurs when, during call waiting, the
- other end hangs up our channel so that it no longer exists, but we
- have neither FLASH'd nor ONHOOK'd to signify our desire to
- change to the other channel. */
- if (p->fake_event) {
- res = p->fake_event;
- p->fake_event = 0;
- } else
- res = dahdi_get_event(p->subs[SUB_REAL].dfd);
- /* Switch to real if there is one and this isn't something really silly... */
- if ((res != DAHDI_EVENT_RINGEROFF) && (res != DAHDI_EVENT_RINGERON) &&
- (res != DAHDI_EVENT_HOOKCOMPLETE)) {
- ast_log(LOG_DEBUG, "Restoring owner of channel %d on event %d\n", p->channel, res);
- p->owner = p->subs[SUB_REAL].owner;
- if (p->owner && ast_bridged_channel(p->owner))
- ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
- p->subs[SUB_REAL].needunhold = 1;
- }
- switch (res) {
- case DAHDI_EVENT_ONHOOK:
- dahdi_disable_ec(p);
- if (p->owner) {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Channel %s still has call, ringing phone\n", p->owner->name);
- dahdi_ring_phone(p);
- p->callwaitingrepeat = 0;
- p->cidcwexpire = 0;
- } else
- ast_log(LOG_WARNING, "Absorbed on hook, but nobody is left!?!?\n");
- update_conf(p);
- break;
- case DAHDI_EVENT_RINGOFFHOOK:
- dahdi_enable_ec(p);
- dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
- if (p->owner && (p->owner->_state == AST_STATE_RINGING)) {
- p->subs[SUB_REAL].needanswer = 1;
- p->dialing = 0;
- }
- break;
- case DAHDI_EVENT_HOOKCOMPLETE:
- case DAHDI_EVENT_RINGERON:
- case DAHDI_EVENT_RINGEROFF:
- /* Do nothing */
- break;
- case DAHDI_EVENT_WINKFLASH:
- gettimeofday(&p->flashtime, NULL);
- if (p->owner) {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Channel %d flashed to other channel %s\n", p->channel, p->owner->name);
- if (p->owner->_state != AST_STATE_UP) {
- /* Answer if necessary */
- usedindex = dahdi_get_index(p->owner, p, 0);
- if (usedindex > -1) {
- p->subs[usedindex].needanswer = 1;
- }
- ast_setstate(p->owner, AST_STATE_UP);
- }
- p->callwaitingrepeat = 0;
- p->cidcwexpire = 0;
- if (ast_bridged_channel(p->owner))
- ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
- p->subs[SUB_REAL].needunhold = 1;
- } else
- ast_log(LOG_WARNING, "Absorbed on hook, but nobody is left!?!?\n");
- update_conf(p);
- break;
- default:
- ast_log(LOG_WARNING, "Don't know how to absorb event %s\n", event2str(res));
- }
- f = &p->subs[index].f;
- return f;
- }
- if (!(p->radio || (p->oprmode < 0)) && option_debug)
- ast_log(LOG_DEBUG, "Exception on %d, channel %d\n", ast->fds[0],p->channel);
- /* If it's not us, return NULL immediately */
- if (ast != p->owner) {
- ast_log(LOG_WARNING, "We're %s, not %s\n", ast->name, p->owner->name);
- f = &p->subs[index].f;
- return f;
- }
- f = dahdi_handle_event(ast);
- return f;
-}
-
-static struct ast_frame *dahdi_exception(struct ast_channel *ast)
-{
- struct dahdi_pvt *p = ast->tech_pvt;
- struct ast_frame *f;
- ast_mutex_lock(&p->lock);
- f = __dahdi_exception(ast);
- ast_mutex_unlock(&p->lock);
- return f;
-}
-
-static struct ast_frame *dahdi_read(struct ast_channel *ast)
-{
- struct dahdi_pvt *p = ast->tech_pvt;
- int res;
- int index;
- void *readbuf;
- struct ast_frame *f;
-
- while (ast_mutex_trylock(&p->lock)) {
- DEADLOCK_AVOIDANCE(&ast->lock);
- }
-
- index = dahdi_get_index(ast, p, 0);
-
- /* Hang up if we don't really exist */
- if (index < 0) {
- ast_log(LOG_WARNING, "We dont exist?\n");
- ast_mutex_unlock(&p->lock);
- return NULL;
- }
-
- if ((p->radio || (p->oprmode < 0)) && p->inalarm) return NULL;
-
- p->subs[index].f.frametype = AST_FRAME_NULL;
- p->subs[index].f.datalen = 0;
- p->subs[index].f.samples = 0;
- p->subs[index].f.mallocd = 0;
- p->subs[index].f.offset = 0;
- p->subs[index].f.subclass = 0;
- p->subs[index].f.delivery = ast_tv(0,0);
- p->subs[index].f.src = "dahdi_read";
- p->subs[index].f.data = NULL;
-
- /* make sure it sends initial key state as first frame */
- if ((p->radio || (p->oprmode < 0)) && (!p->firstradio))
- {
- struct dahdi_params ps;
-
- ps.channo = p->channel;
- if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &ps) < 0) {
- ast_mutex_unlock(&p->lock);
- return NULL;
- }
- p->firstradio = 1;
- p->subs[index].f.frametype = AST_FRAME_CONTROL;
- if (ps.rxisoffhook)
- {
- p->subs[index].f.subclass = AST_CONTROL_RADIO_KEY;
- }
- else
- {
- p->subs[index].f.subclass = AST_CONTROL_RADIO_UNKEY;
- }
- ast_mutex_unlock(&p->lock);
- return &p->subs[index].f;
- }
- if (p->ringt == 1) {
- ast_mutex_unlock(&p->lock);
- return NULL;
- }
- else if (p->ringt > 0)
- p->ringt--;
-
- if (p->subs[index].needringing) {
- /* Send ringing frame if requested */
- p->subs[index].needringing = 0;
- p->subs[index].f.frametype = AST_FRAME_CONTROL;
- p->subs[index].f.subclass = AST_CONTROL_RINGING;
- ast_setstate(ast, AST_STATE_RINGING);
- ast_mutex_unlock(&p->lock);
- return &p->subs[index].f;
- }
-
- if (p->subs[index].needbusy) {
- /* Send busy frame if requested */
- p->subs[index].needbusy = 0;
- p->subs[index].f.frametype = AST_FRAME_CONTROL;
- p->subs[index].f.subclass = AST_CONTROL_BUSY;
- ast_mutex_unlock(&p->lock);
- return &p->subs[index].f;
- }
-
- if (p->subs[index].needcongestion) {
- /* Send congestion frame if requested */
- p->subs[index].needcongestion = 0;
- p->subs[index].f.frametype = AST_FRAME_CONTROL;
- p->subs[index].f.subclass = AST_CONTROL_CONGESTION;
- ast_mutex_unlock(&p->lock);
- return &p->subs[index].f;
- }
-
- if (p->subs[index].needcallerid) {
- ast_set_callerid(ast, S_OR(p->lastcid_num, NULL),
- S_OR(p->lastcid_name, NULL),
- S_OR(p->lastcid_num, NULL)
- );
- p->subs[index].needcallerid = 0;
- }
-
- if (p->subs[index].needanswer) {
- /* Send answer frame if requested */
- p->subs[index].needanswer = 0;
- p->subs[index].f.frametype = AST_FRAME_CONTROL;
- p->subs[index].f.subclass = AST_CONTROL_ANSWER;
- ast_mutex_unlock(&p->lock);
- return &p->subs[index].f;
- }
-
- if (p->subs[index].needflash) {
- /* Send answer frame if requested */
- p->subs[index].needflash = 0;
- p->subs[index].f.frametype = AST_FRAME_CONTROL;
- p->subs[index].f.subclass = AST_CONTROL_FLASH;
- ast_mutex_unlock(&p->lock);
- return &p->subs[index].f;
- }
-
- if (p->subs[index].needhold) {
- /* Send answer frame if requested */
- p->subs[index].needhold = 0;
- p->subs[index].f.frametype = AST_FRAME_CONTROL;
- p->subs[index].f.subclass = AST_CONTROL_HOLD;
- ast_mutex_unlock(&p->lock);
- ast_log(LOG_DEBUG, "Sending hold on '%s'\n", ast->name);
- return &p->subs[index].f;
- }
-
- if (p->subs[index].needunhold) {
- /* Send answer frame if requested */
- p->subs[index].needunhold = 0;
- p->subs[index].f.frametype = AST_FRAME_CONTROL;
- p->subs[index].f.subclass = AST_CONTROL_UNHOLD;
- ast_mutex_unlock(&p->lock);
- ast_log(LOG_DEBUG, "Sending unhold on '%s'\n", ast->name);
- return &p->subs[index].f;
- }
-
- if (ast->rawreadformat == AST_FORMAT_SLINEAR) {
- if (!p->subs[index].linear) {
- p->subs[index].linear = 1;
- res = dahdi_setlinear(p->subs[index].dfd, p->subs[index].linear);
- if (res)
- ast_log(LOG_WARNING, "Unable to set channel %d (index %d) to linear mode.\n", p->channel, index);
- }
- } else if ((ast->rawreadformat == AST_FORMAT_ULAW) ||
- (ast->rawreadformat == AST_FORMAT_ALAW)) {
- if (p->subs[index].linear) {
- p->subs[index].linear = 0;
- res = dahdi_setlinear(p->subs[index].dfd, p->subs[index].linear);
- if (res)
- ast_log(LOG_WARNING, "Unable to set channel %d (index %d) to companded mode.\n", p->channel, index);
- }
- } else {
- ast_log(LOG_WARNING, "Don't know how to read frames in format %s\n", ast_getformatname(ast->rawreadformat));
- ast_mutex_unlock(&p->lock);
- return NULL;
- }
- readbuf = ((unsigned char *)p->subs[index].buffer) + AST_FRIENDLY_OFFSET;
- CHECK_BLOCKING(ast);
- res = read(p->subs[index].dfd, readbuf, p->subs[index].linear ? READ_SIZE * 2 : READ_SIZE);
- ast_clear_flag(ast, AST_FLAG_BLOCKING);
- /* Check for hangup */
- if (res < 0) {
- f = NULL;
- if (res == -1) {
- if (errno == EAGAIN) {
- /* Return "NULL" frame if there is nobody there */
- ast_mutex_unlock(&p->lock);
- return &p->subs[index].f;
- } else if (errno == ELAST) {
- f = __dahdi_exception(ast);
- } else
- ast_log(LOG_WARNING, "dahdi_rec: %s\n", strerror(errno));
- }
- ast_mutex_unlock(&p->lock);
- return f;
- }
- if (res != (p->subs[index].linear ? READ_SIZE * 2 : READ_SIZE)) {
- ast_log(LOG_DEBUG, "Short read (%d/%d), must be an event...\n", res, p->subs[index].linear ? READ_SIZE * 2 : READ_SIZE);
- f = __dahdi_exception(ast);
- ast_mutex_unlock(&p->lock);
- return f;
- }
- if (p->tdd) { /* if in TDD mode, see if we receive that */
- int c;
-
- c = tdd_feed(p->tdd,readbuf,READ_SIZE);
- if (c < 0) {
- ast_log(LOG_DEBUG,"tdd_feed failed\n");
- ast_mutex_unlock(&p->lock);
- return NULL;
- }
- if (c) { /* if a char to return */
- p->subs[index].f.subclass = 0;
- p->subs[index].f.frametype = AST_FRAME_TEXT;
- p->subs[index].f.mallocd = 0;
- p->subs[index].f.offset = AST_FRIENDLY_OFFSET;
- p->subs[index].f.data = p->subs[index].buffer + AST_FRIENDLY_OFFSET;
- p->subs[index].f.datalen = 1;
- *((char *) p->subs[index].f.data) = c;
- ast_mutex_unlock(&p->lock);
- return &p->subs[index].f;
- }
- }
- /* Ensure the CW timer decrements only on a single subchannel */
- if (p->callwaitingrepeat && dahdi_get_index(ast, p, 1) == SUB_REAL) {
- p->callwaitingrepeat--;
- }
- if (p->cidcwexpire)
- p->cidcwexpire--;
- /* Repeat callwaiting */
- if (p->callwaitingrepeat == 1) {
- p->callwaitrings++;
- dahdi_callwait(ast);
- }
- /* Expire CID/CW */
- if (p->cidcwexpire == 1) {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "CPE does not support Call Waiting Caller*ID.\n");
- restore_conference(p);
- }
- if (p->subs[index].linear) {
- p->subs[index].f.datalen = READ_SIZE * 2;
- } else
- p->subs[index].f.datalen = READ_SIZE;
-
- /* Handle CallerID Transmission */
- if ((p->owner == ast) && p->cidspill &&((ast->_state == AST_STATE_UP) || (ast->rings == p->cidrings))) {
- send_callerid(p);
- }
-
- p->subs[index].f.frametype = AST_FRAME_VOICE;
- p->subs[index].f.subclass = ast->rawreadformat;
- p->subs[index].f.samples = READ_SIZE;
- p->subs[index].f.mallocd = 0;
- p->subs[index].f.offset = AST_FRIENDLY_OFFSET;
- p->subs[index].f.data = p->subs[index].buffer + AST_FRIENDLY_OFFSET / sizeof(p->subs[index].buffer[0]);
-#if 0
- ast_log(LOG_DEBUG, "Read %d of voice on %s\n", p->subs[index].f.datalen, ast->name);
-#endif
- if (p->dialing || /* Transmitting something */
- (index && (ast->_state != AST_STATE_UP)) || /* Three-way or callwait that isn't up */
- ((index == SUB_CALLWAIT) && !p->subs[SUB_CALLWAIT].inthreeway) /* Inactive and non-confed call-wait */
- ) {
- /* Whoops, we're still dialing, or in a state where we shouldn't transmit....
- don't send anything */
- p->subs[index].f.frametype = AST_FRAME_NULL;
- p->subs[index].f.subclass = 0;
- p->subs[index].f.samples = 0;
- p->subs[index].f.mallocd = 0;
- p->subs[index].f.offset = 0;
- p->subs[index].f.data = NULL;
- p->subs[index].f.datalen= 0;
- }
- if (p->dsp && (!p->ignoredtmf || p->callwaitcas || p->busydetect || p->callprogress) && !index) {
- /* Perform busy detection. etc on the dahdi line */
- f = ast_dsp_process(ast, p->dsp, &p->subs[index].f);
- if (f) {
- if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_BUSY)) {
- if ((ast->_state == AST_STATE_UP) && !p->outgoing) {
- /* Treat this as a "hangup" instead of a "busy" on the assumption that
- a busy */
- f = NULL;
- }
- } else if (f->frametype == AST_FRAME_DTMF) {
-#ifdef HAVE_PRI
- if (!p->proceeding && p->sig==SIG_PRI && p->pri && p->pri->overlapdial) {
- /* Don't accept in-band DTMF when in overlap dial mode */
- f->frametype = AST_FRAME_NULL;
- f->subclass = 0;
- }
-#endif
- /* DSP clears us of being pulse */
- p->pulsedial = 0;
- }
- }
- } else
- f = &p->subs[index].f;
-
- if (f && (f->frametype == AST_FRAME_DTMF))
- dahdi_handle_dtmfup(ast, index, &f);
-
- /* If we have a fake_event, trigger exception to handle it */
- if (p->fake_event)
- ast_set_flag(ast, AST_FLAG_EXCEPTION);
-
- ast_mutex_unlock(&p->lock);
- return f;
-}
-
-static int my_dahdi_write(struct dahdi_pvt *p, unsigned char *buf, int len, int index, int linear)
-{
- int sent=0;
- int size;
- int res;
- int fd;
- fd = p->subs[index].dfd;
- while (len) {
- size = len;
- if (size > (linear ? READ_SIZE * 2 : READ_SIZE))
- size = (linear ? READ_SIZE * 2 : READ_SIZE);
- res = write(fd, buf, size);
- if (res != size) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Write returned %d (%s) on channel %d\n", res, strerror(errno), p->channel);
- return sent;
- }
- len -= size;
- buf += size;
- }
- return sent;
-}
-
-static int dahdi_write(struct ast_channel *ast, struct ast_frame *frame)
-{
- struct dahdi_pvt *p = ast->tech_pvt;
- int res;
- int index;
- index = dahdi_get_index(ast, p, 0);
- if (index < 0) {
- ast_log(LOG_WARNING, "%s doesn't really exist?\n", ast->name);
- return -1;
- }
-
-#if 0
-#ifdef HAVE_PRI
- ast_mutex_lock(&p->lock);
- if (!p->proceeding && p->sig==SIG_PRI && p->pri && !p->outgoing) {
- if (p->pri->pri) {
- if (!pri_grab(p, p->pri)) {
- pri_progress(p->pri->pri,p->call, PVT_TO_CHANNEL(p), !p->digital);
- pri_rel(p->pri);
- } else
- ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
- }
- p->proceeding=1;
- }
- ast_mutex_unlock(&p->lock);
-#endif
-#endif
- /* Write a frame of (presumably voice) data */
- if (frame->frametype != AST_FRAME_VOICE) {
- if (frame->frametype != AST_FRAME_IMAGE)
- ast_log(LOG_WARNING, "Don't know what to do with frame type '%d'\n", frame->frametype);
- return 0;
- }
- if ((frame->subclass != AST_FORMAT_SLINEAR) &&
- (frame->subclass != AST_FORMAT_ULAW) &&
- (frame->subclass != AST_FORMAT_ALAW)) {
- ast_log(LOG_WARNING, "Cannot handle frames in %d format\n", frame->subclass);
- return -1;
- }
- if (p->dialing) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Dropping frame since I'm still dialing on %s...\n",ast->name);
- return 0;
- }
- if (!p->owner) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Dropping frame since there is no active owner on %s...\n",ast->name);
- return 0;
- }
- if (p->cidspill) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Dropping frame since I've still got a callerid spill\n");
- return 0;
- }
- /* Return if it's not valid data */
- if (!frame->data || !frame->datalen)
- return 0;
-
- if (frame->subclass == AST_FORMAT_SLINEAR) {
- if (!p->subs[index].linear) {
- p->subs[index].linear = 1;
- res = dahdi_setlinear(p->subs[index].dfd, p->subs[index].linear);
- if (res)
- ast_log(LOG_WARNING, "Unable to set linear mode on channel %d\n", p->channel);
- }
- res = my_dahdi_write(p, (unsigned char *)frame->data, frame->datalen, index, 1);
- } else {
- /* x-law already */
- if (p->subs[index].linear) {
- p->subs[index].linear = 0;
- res = dahdi_setlinear(p->subs[index].dfd, p->subs[index].linear);
- if (res)
- ast_log(LOG_WARNING, "Unable to set companded mode on channel %d\n", p->channel);
- }
- res = my_dahdi_write(p, (unsigned char *)frame->data, frame->datalen, index, 0);
- }
- if (res < 0) {
- ast_log(LOG_WARNING, "write failed: %s\n", strerror(errno));
- return -1;
- }
- return 0;
-}
-
-static int dahdi_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen)
-{
- struct dahdi_pvt *p = chan->tech_pvt;
- int res=-1;
- int index;
- int func = DAHDI_FLASH;
- ast_mutex_lock(&p->lock);
- index = dahdi_get_index(chan, p, 0);
- if (option_debug)
- ast_log(LOG_DEBUG, "Requested indication %d on channel %s\n", condition, chan->name);
- if (index == SUB_REAL) {
- switch (condition) {
- case AST_CONTROL_BUSY:
-#ifdef HAVE_PRI
- if (p->priindication_oob && p->sig == SIG_PRI) {
- chan->hangupcause = AST_CAUSE_USER_BUSY;
- chan->_softhangup |= AST_SOFTHANGUP_DEV;
- res = 0;
- } else if (!p->progress && p->sig==SIG_PRI && p->pri && !p->outgoing) {
- if (p->pri->pri) {
- if (!pri_grab(p, p->pri)) {
- pri_progress(p->pri->pri,p->call, PVT_TO_CHANNEL(p), 1);
- pri_rel(p->pri);
- }
- else
- ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
- }
- p->progress = 1;
- res = tone_zone_play_tone(p->subs[index].dfd, DAHDI_TONE_BUSY);
- } else
-#endif
- res = tone_zone_play_tone(p->subs[index].dfd, DAHDI_TONE_BUSY);
- break;
- case AST_CONTROL_RINGING:
-#ifdef HAVE_PRI
- if ((!p->alerting) && p->sig==SIG_PRI && p->pri && !p->outgoing && (chan->_state != AST_STATE_UP)) {
- if (p->pri->pri) {
- if (!pri_grab(p, p->pri)) {
- pri_acknowledge(p->pri->pri,p->call, PVT_TO_CHANNEL(p), !p->digital);
- pri_rel(p->pri);
- }
- else
- ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
- }
- p->alerting = 1;
- }
-#endif
- res = tone_zone_play_tone(p->subs[index].dfd, DAHDI_TONE_RINGTONE);
- if (chan->_state != AST_STATE_UP) {
- if ((chan->_state != AST_STATE_RING) ||
- ((p->sig != SIG_FXSKS) &&
- (p->sig != SIG_FXSLS) &&
- (p->sig != SIG_FXSGS)))
- ast_setstate(chan, AST_STATE_RINGING);
- }
- break;
- case AST_CONTROL_PROCEEDING:
- ast_log(LOG_DEBUG,"Received AST_CONTROL_PROCEEDING on %s\n",chan->name);
-#ifdef HAVE_PRI
- if (!p->proceeding && p->sig==SIG_PRI && p->pri && !p->outgoing) {
- if (p->pri->pri) {
- if (!pri_grab(p, p->pri)) {
- pri_proceeding(p->pri->pri,p->call, PVT_TO_CHANNEL(p), !p->digital);
- pri_rel(p->pri);
- }
- else
- ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
- }
- p->proceeding = 1;
- }
-#endif
- /* don't continue in ast_indicate */
- res = 0;
- break;
- case AST_CONTROL_PROGRESS:
- ast_log(LOG_DEBUG,"Received AST_CONTROL_PROGRESS on %s\n",chan->name);
-#ifdef HAVE_PRI
- p->digital = 0; /* Digital-only calls isn't allows any inband progress messages */
- if (!p->progress && p->sig==SIG_PRI && p->pri && !p->outgoing) {
- if (p->pri->pri) {
- if (!pri_grab(p, p->pri)) {
- pri_progress(p->pri->pri,p->call, PVT_TO_CHANNEL(p), 1);
- pri_rel(p->pri);
- }
- else
- ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
- }
- p->progress = 1;
- }
-#endif
- /* don't continue in ast_indicate */
- res = 0;
- break;
- case AST_CONTROL_CONGESTION:
- chan->hangupcause = AST_CAUSE_CONGESTION;
-#ifdef HAVE_PRI
- if (p->priindication_oob && p->sig == SIG_PRI) {
- chan->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
- chan->_softhangup |= AST_SOFTHANGUP_DEV;
- res = 0;
- } else if (!p->progress && p->sig==SIG_PRI && p->pri && !p->outgoing) {
- if (p->pri) {
- if (!pri_grab(p, p->pri)) {
- pri_progress(p->pri->pri,p->call, PVT_TO_CHANNEL(p), 1);
- pri_rel(p->pri);
- } else
- ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
- }
- p->progress = 1;
- res = tone_zone_play_tone(p->subs[index].dfd, DAHDI_TONE_CONGESTION);
- } else
-#endif
- res = tone_zone_play_tone(p->subs[index].dfd, DAHDI_TONE_CONGESTION);
- break;
- case AST_CONTROL_HOLD:
-#ifdef HAVE_PRI
- if (p->pri && !strcasecmp(p->mohinterpret, "passthrough")) {
- if (!pri_grab(p, p->pri)) {
- res = pri_notify(p->pri->pri, p->call, p->prioffset, PRI_NOTIFY_REMOTE_HOLD);
- pri_rel(p->pri);
- } else
- ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
- } else
-#endif
- ast_moh_start(chan, data, p->mohinterpret);
- break;
- case AST_CONTROL_UNHOLD:
-#ifdef HAVE_PRI
- if (p->pri && !strcasecmp(p->mohinterpret, "passthrough")) {
- if (!pri_grab(p, p->pri)) {
- res = pri_notify(p->pri->pri, p->call, p->prioffset, PRI_NOTIFY_REMOTE_RETRIEVAL);
- pri_rel(p->pri);
- } else
- ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
- } else
-#endif
- ast_moh_stop(chan);
- break;
- case AST_CONTROL_RADIO_KEY:
- if (p->radio)
- res = dahdi_set_hook(p->subs[index].dfd, DAHDI_OFFHOOK);
- res = 0;
- break;
- case AST_CONTROL_RADIO_UNKEY:
- if (p->radio)
- res = dahdi_set_hook(p->subs[index].dfd, DAHDI_RINGOFF);
- res = 0;
- break;
- case AST_CONTROL_FLASH:
- /* flash hookswitch */
- if (ISTRUNK(p) && (p->sig != SIG_PRI)) {
- /* Clear out the dial buffer */
- p->dop.dialstr[0] = '\0';
- if ((ioctl(p->subs[SUB_REAL].dfd,DAHDI_HOOK,&func) == -1) && (errno != EINPROGRESS)) {
- ast_log(LOG_WARNING, "Unable to flash external trunk on channel %s: %s\n",
- chan->name, strerror(errno));
- } else
- res = 0;
- } else
- res = 0;
- break;
- case AST_CONTROL_SRCUPDATE:
- res = 0;
- break;
- case -1:
- res = tone_zone_play_tone(p->subs[index].dfd, -1);
- break;
- }
- } else
- res = 0;
- ast_mutex_unlock(&p->lock);
- return res;
-}
-
-static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpbx, int index, int law, int transfercapability)
-{
- struct ast_channel *tmp;
- int deflaw;
- int res;
- int x,y;
- int features;
- char *b2 = NULL;
- struct dahdi_params ps;
- char chanprefix[*dahdi_chan_name_len + 4];
-
- if (i->subs[index].owner) {
- ast_log(LOG_WARNING, "Channel %d already has a %s call\n", i->channel,subnames[index]);
- return NULL;
- }
- y = 1;
- do {
- if (b2)
- free(b2);
-#ifdef HAVE_PRI
- if (i->bearer || (i->pri && (i->sig == SIG_FXSKS)))
- b2 = ast_safe_string_alloc("%d:%d-%d", i->pri->trunkgroup, i->channel, y);
- else
-#endif
- if (i->channel == CHAN_PSEUDO)
- b2 = ast_safe_string_alloc("pseudo-%ld", ast_random());
- else
- b2 = ast_safe_string_alloc("%d-%d", i->channel, y);
- for (x = 0; x < 3; x++) {
- if ((index != x) && i->subs[x].owner && !strcasecmp(b2, i->subs[x].owner->name + (!strncmp(i->subs[x].owner->name, "Zap", 3) ? 4 : 6)))
- break;
- }
- y++;
- } while (x < 3);
- strcpy(chanprefix, dahdi_chan_name);
- strcat(chanprefix, "/%s");
- tmp = ast_channel_alloc(0, state, i->cid_num, i->cid_name, i->accountcode, i->exten, i->context, i->amaflags, chanprefix, b2);
- if (b2) /*!> b2 can be freed now, it's been copied into the channel structure */
- free(b2);
- if (!tmp)
- return NULL;
- tmp->tech = chan_tech;
- ps.channo = i->channel;
- res = ioctl(i->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &ps);
- if (res) {
- ast_log(LOG_WARNING, "Unable to get parameters, assuming MULAW: %s\n", strerror(errno));
- ps.curlaw = DAHDI_LAW_MULAW;
- }
- if (ps.curlaw == DAHDI_LAW_ALAW)
- deflaw = AST_FORMAT_ALAW;
- else
- deflaw = AST_FORMAT_ULAW;
- if (law) {
- if (law == DAHDI_LAW_ALAW)
- deflaw = AST_FORMAT_ALAW;
- else
- deflaw = AST_FORMAT_ULAW;
- }
- tmp->fds[0] = i->subs[index].dfd;
- tmp->nativeformats = AST_FORMAT_SLINEAR | deflaw;
- /* Start out assuming ulaw since it's smaller :) */
- tmp->rawreadformat = deflaw;
- tmp->readformat = deflaw;
- tmp->rawwriteformat = deflaw;
- tmp->writeformat = deflaw;
- i->subs[index].linear = 0;
- dahdi_setlinear(i->subs[index].dfd, i->subs[index].linear);
- features = 0;
- if (index == SUB_REAL) {
- if (i->busydetect && CANBUSYDETECT(i))
- features |= DSP_FEATURE_BUSY_DETECT;
- if ((i->callprogress & 1) && CANPROGRESSDETECT(i))
- features |= DSP_FEATURE_CALL_PROGRESS;
- if ((!i->outgoing && (i->callprogress & 4)) ||
- (i->outgoing && (i->callprogress & 2))) {
- features |= DSP_FEATURE_FAX_DETECT;
- }
-#ifdef DAHDI_TONEDETECT
- x = DAHDI_TONEDETECT_ON | DAHDI_TONEDETECT_MUTE;
- if (ioctl(i->subs[index].dfd, DAHDI_TONEDETECT, &x)) {
-#endif
- i->hardwaredtmf = 0;
- features |= DSP_FEATURE_DTMF_DETECT;
-#ifdef DAHDI_TONEDETECT
- } else if (NEED_MFDETECT(i)) {
- i->hardwaredtmf = 1;
- features |= DSP_FEATURE_DTMF_DETECT;
- }
-#endif
- }
- if (features) {
- if (i->dsp) {
- ast_log(LOG_DEBUG, "Already have a dsp on %s?\n", tmp->name);
- } else {
- if (i->channel != CHAN_PSEUDO)
- i->dsp = ast_dsp_new();
- else
- i->dsp = NULL;
- if (i->dsp) {
- i->dsp_features = features;
-#ifdef HAVE_PRI
- /* We cannot do progress detection until receives PROGRESS message */
- if (i->outgoing && (i->sig == SIG_PRI)) {
- /* Remember requested DSP features, don't treat
- talking as ANSWER */
- i->dsp_features = features & ~DSP_PROGRESS_TALK;
- features = 0;
- }
-#endif
- ast_dsp_set_features(i->dsp, features);
- ast_dsp_digitmode(i->dsp, DSP_DIGITMODE_DTMF | i->dtmfrelax);
- if (!ast_strlen_zero(progzone))
- ast_dsp_set_call_progress_zone(i->dsp, progzone);
- if (i->busydetect && CANBUSYDETECT(i)) {
- ast_dsp_set_busy_count(i->dsp, i->busycount);
- ast_dsp_set_busy_pattern(i->dsp, i->busy_tonelength, i->busy_quietlength);
- }
- }
- }
- }
-
- if (state == AST_STATE_RING)
- tmp->rings = 1;
- tmp->tech_pvt = i;
- if ((i->sig == SIG_FXOKS) || (i->sig == SIG_FXOGS) || (i->sig == SIG_FXOLS)) {
- /* Only FXO signalled stuff can be picked up */
- tmp->callgroup = i->callgroup;
- tmp->pickupgroup = i->pickupgroup;
- }
- if (!ast_strlen_zero(i->language))
- ast_string_field_set(tmp, language, i->language);
- if (!i->owner)
- i->owner = tmp;
- if (!ast_strlen_zero(i->accountcode))
- ast_string_field_set(tmp, accountcode, i->accountcode);
- if (i->amaflags)
- tmp->amaflags = i->amaflags;
- i->subs[index].owner = tmp;
- ast_copy_string(tmp->context, i->context, sizeof(tmp->context));
- ast_string_field_set(tmp, call_forward, i->call_forward);
- /* If we've been told "no ADSI" then enforce it */
- if (!i->adsi)
- tmp->adsicpe = AST_ADSI_UNAVAILABLE;
- if (!ast_strlen_zero(i->exten))
- ast_copy_string(tmp->exten, i->exten, sizeof(tmp->exten));
- if (!ast_strlen_zero(i->rdnis))
- tmp->cid.cid_rdnis = ast_strdup(i->rdnis);
- if (!ast_strlen_zero(i->dnid))
- tmp->cid.cid_dnid = ast_strdup(i->dnid);
-
- /* Don't use ast_set_callerid() here because it will
- * generate a needless NewCallerID event */
-#ifdef PRI_ANI
- if (!ast_strlen_zero(i->cid_ani))
- tmp->cid.cid_ani = ast_strdup(i->cid_ani);
- else
- tmp->cid.cid_ani = ast_strdup(i->cid_num);
-#else
- tmp->cid.cid_ani = ast_strdup(i->cid_num);
-#endif
- tmp->cid.cid_pres = i->callingpres;
- tmp->cid.cid_ton = i->cid_ton;
-#ifdef HAVE_PRI
- tmp->transfercapability = transfercapability;
- pbx_builtin_setvar_helper(tmp, "TRANSFERCAPABILITY", ast_transfercapability2str(transfercapability));
- if (transfercapability & PRI_TRANS_CAP_DIGITAL)
- i->digital = 1;
- /* Assume calls are not idle calls unless we're told differently */
- i->isidlecall = 0;
- i->alreadyhungup = 0;
-#endif
- /* clear the fake event in case we posted one before we had ast_channel */
- i->fake_event = 0;
- /* Assure there is no confmute on this channel */
- dahdi_confmute(i, 0);
- /* Configure the new channel jb */
- ast_jb_configure(tmp, &global_jbconf);
- if (startpbx) {
- if (ast_pbx_start(tmp)) {
- ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
- ast_hangup(tmp);
- i->owner = NULL;
- return NULL;
- }
- }
-
- ast_module_ref(ast_module_info->self);
-
- return tmp;
-}
-
-
-static int my_getsigstr(struct ast_channel *chan, char *str, const char *term, int ms)
-{
- char c;
-
- *str = 0; /* start with empty output buffer */
- for (;;)
- {
- /* Wait for the first digit (up to specified ms). */
- c = ast_waitfordigit(chan, ms);
- /* if timeout, hangup or error, return as such */
- if (c < 1)
- return c;
- *str++ = c;
- *str = 0;
- if (strchr(term, c))
- return 1;
- }
-}
-
-static int dahdi_wink(struct dahdi_pvt *p, int index)
-{
- int j;
- dahdi_set_hook(p->subs[index].dfd, DAHDI_WINK);
- for (;;)
- {
- /* set bits of interest */
- j = DAHDI_IOMUX_SIGEVENT;
- /* wait for some happening */
- if (ioctl(p->subs[index].dfd,DAHDI_IOMUX,&j) == -1) return(-1);
- /* exit loop if we have it */
- if (j & DAHDI_IOMUX_SIGEVENT) break;
- }
- /* get the event info */
- if (ioctl(p->subs[index].dfd,DAHDI_GETEVENT,&j) == -1) return(-1);
- return 0;
-}
-
-static void *ss_thread(void *data)
-{
- struct ast_channel *chan = data;
- struct dahdi_pvt *p = chan->tech_pvt;
- char exten[AST_MAX_EXTENSION] = "";
- char exten2[AST_MAX_EXTENSION] = "";
- unsigned char buf[256];
- char dtmfcid[300];
- char dtmfbuf[300];
- struct callerid_state *cs = NULL;
- char *name = NULL, *number = NULL;
- int distMatches;
- int curRingData[3];
- int receivedRingT;
- int counter1;
- int counter;
- int samples = 0;
- struct ast_smdi_md_message *smdi_msg = NULL;
- int flags;
- int i;
- int timeout;
- int getforward = 0;
- char *s1, *s2;
- int len = 0;
- int res;
- int index;
-
- ast_mutex_lock(&ss_thread_lock);
- ss_thread_count++;
- ast_mutex_unlock(&ss_thread_lock);
- /* in the bizarre case where the channel has become a zombie before we
- even get started here, abort safely
- */
- if (!p) {
- ast_log(LOG_WARNING, "Channel became a zombie before simple switch could be started (%s)\n", chan->name);
- ast_hangup(chan);
- goto quit;
- }
- if (option_verbose > 2)
- ast_verbose( VERBOSE_PREFIX_3 "Starting simple switch on '%s'\n", chan->name);
- index = dahdi_get_index(chan, p, 1);
- if (index < 0) {
- ast_log(LOG_WARNING, "Huh?\n");
- ast_hangup(chan);
- goto quit;
- }
- if (p->dsp)
- ast_dsp_digitreset(p->dsp);
- switch (p->sig) {
-#ifdef HAVE_PRI
- case SIG_PRI:
- /* Now loop looking for an extension */
- ast_copy_string(exten, p->exten, sizeof(exten));
- len = strlen(exten);
- res = 0;
- while ((len < AST_MAX_EXTENSION-1) && ast_matchmore_extension(chan, chan->context, exten, 1, p->cid_num)) {
- if (len && !ast_ignore_pattern(chan->context, exten))
- tone_zone_play_tone(p->subs[index].dfd, -1);
- else
- tone_zone_play_tone(p->subs[index].dfd, DAHDI_TONE_DIALTONE);
- if (ast_exists_extension(chan, chan->context, exten, 1, p->cid_num))
- timeout = matchdigittimeout;
- else
- timeout = gendigittimeout;
- res = ast_waitfordigit(chan, timeout);
- if (res < 0) {
- ast_log(LOG_DEBUG, "waitfordigit returned < 0...\n");
- ast_hangup(chan);
- goto quit;
- } else if (res) {
- exten[len++] = res;
- exten[len] = '\0';
- } else
- break;
- }
- /* if no extension was received ('unspecified') on overlap call, use the 's' extension */
- if (ast_strlen_zero(exten)) {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Going to extension s|1 because of empty extension received on overlap call\n");
- exten[0] = 's';
- exten[1] = '\0';
- }
- tone_zone_play_tone(p->subs[index].dfd, -1);
- if (ast_exists_extension(chan, chan->context, exten, 1, p->cid_num)) {
- /* Start the real PBX */
- ast_copy_string(chan->exten, exten, sizeof(chan->exten));
- if (p->dsp) ast_dsp_digitreset(p->dsp);
- dahdi_enable_ec(p);
- ast_setstate(chan, AST_STATE_RING);
- res = ast_pbx_run(chan);
- if (res) {
- ast_log(LOG_WARNING, "PBX exited non-zero!\n");
- }
- } else {
- ast_log(LOG_DEBUG, "No such possible extension '%s' in context '%s'\n", exten, chan->context);
- chan->hangupcause = AST_CAUSE_UNALLOCATED;
- ast_hangup(chan);
- p->exten[0] = '\0';
- /* Since we send release complete here, we won't get one */
- p->call = NULL;
- }
- goto quit;
- break;
-#endif
- case SIG_FEATD:
- case SIG_FEATDMF:
- case SIG_FEATDMF_TA:
- case SIG_E911:
- case SIG_FGC_CAMAMF:
- case SIG_FEATB:
- case SIG_EMWINK:
- case SIG_SF_FEATD:
- case SIG_SF_FEATDMF:
- case SIG_SF_FEATB:
- case SIG_SFWINK:
- if (dahdi_wink(p, index))
- goto quit;
- /* Fall through */
- case SIG_EM:
- case SIG_EM_E1:
- case SIG_SF:
- case SIG_FGC_CAMA:
- res = tone_zone_play_tone(p->subs[index].dfd, -1);
- if (p->dsp)
- ast_dsp_digitreset(p->dsp);
- /* set digit mode appropriately */
- if (p->dsp) {
- if (NEED_MFDETECT(p))
- ast_dsp_digitmode(p->dsp,DSP_DIGITMODE_MF | p->dtmfrelax);
- else
- ast_dsp_digitmode(p->dsp,DSP_DIGITMODE_DTMF | p->dtmfrelax);
- }
- memset(dtmfbuf, 0, sizeof(dtmfbuf));
- /* Wait for the first digit only if immediate=no */
- if (!p->immediate)
- /* Wait for the first digit (up to 5 seconds). */
- res = ast_waitfordigit(chan, 5000);
- else
- res = 0;
- if (res > 0) {
- /* save first char */
- dtmfbuf[0] = res;
- switch (p->sig) {
- case SIG_FEATD:
- case SIG_SF_FEATD:
- res = my_getsigstr(chan, dtmfbuf + 1, "*", 3000);
- if (res > 0)
- res = my_getsigstr(chan, dtmfbuf + strlen(dtmfbuf), "*", 3000);
- if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
- break;
- case SIG_FEATDMF_TA:
- res = my_getsigstr(chan, dtmfbuf + 1, "#", 3000);
- if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
- if (dahdi_wink(p, index)) goto quit;
- dtmfbuf[0] = 0;
- /* Wait for the first digit (up to 5 seconds). */
- res = ast_waitfordigit(chan, 5000);
- if (res <= 0) break;
- dtmfbuf[0] = res;
- /* fall through intentionally */
- case SIG_FEATDMF:
- case SIG_E911:
- case SIG_FGC_CAMAMF:
- case SIG_SF_FEATDMF:
- res = my_getsigstr(chan, dtmfbuf + 1, "#", 3000);
- /* if international caca, do it again to get real ANO */
- if ((p->sig == SIG_FEATDMF) && (dtmfbuf[1] != '0') && (strlen(dtmfbuf) != 14))
- {
- if (dahdi_wink(p, index)) goto quit;
- dtmfbuf[0] = 0;
- /* Wait for the first digit (up to 5 seconds). */
- res = ast_waitfordigit(chan, 5000);
- if (res <= 0) break;
- dtmfbuf[0] = res;
- res = my_getsigstr(chan, dtmfbuf + 1, "#", 3000);
- }
- if (res > 0) {
- /* if E911, take off hook */
- if (p->sig == SIG_E911)
- dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
- res = my_getsigstr(chan, dtmfbuf + strlen(dtmfbuf), "#", 3000);
- }
- if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
- break;
- case SIG_FEATB:
- case SIG_SF_FEATB:
- res = my_getsigstr(chan, dtmfbuf + 1, "#", 3000);
- if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
- break;
- case SIG_EMWINK:
- /* if we received a '*', we are actually receiving Feature Group D
- dial syntax, so use that mode; otherwise, fall through to normal
- mode
- */
- if (res == '*') {
- res = my_getsigstr(chan, dtmfbuf + 1, "*", 3000);
- if (res > 0)
- res = my_getsigstr(chan, dtmfbuf + strlen(dtmfbuf), "*", 3000);
- if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
- break;
- }
- default:
- /* If we got the first digit, get the rest */
- len = 1;
- dtmfbuf[len] = '\0';
- while ((len < AST_MAX_EXTENSION-1) && ast_matchmore_extension(chan, chan->context, dtmfbuf, 1, p->cid_num)) {
- if (ast_exists_extension(chan, chan->context, dtmfbuf, 1, p->cid_num)) {
- timeout = matchdigittimeout;
- } else {
- timeout = gendigittimeout;
- }
- res = ast_waitfordigit(chan, timeout);
- if (res < 0) {
- ast_log(LOG_DEBUG, "waitfordigit returned < 0...\n");
- ast_hangup(chan);
- goto quit;
- } else if (res) {
- dtmfbuf[len++] = res;
- dtmfbuf[len] = '\0';
- } else {
- break;
- }
- }
- break;
- }
- }
- if (res == -1) {
- ast_log(LOG_WARNING, "getdtmf on channel %d: %s\n", p->channel, strerror(errno));
- ast_hangup(chan);
- goto quit;
- } else if (res < 0) {
- ast_log(LOG_DEBUG, "Got hung up before digits finished\n");
- ast_hangup(chan);
- goto quit;
- }
-
- if (p->sig == SIG_FGC_CAMA) {
- char anibuf[100];
-
- if (ast_safe_sleep(chan,1000) == -1) {
- ast_hangup(chan);
- goto quit;
- }
- dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
- ast_dsp_digitmode(p->dsp,DSP_DIGITMODE_MF | p->dtmfrelax);
- res = my_getsigstr(chan, anibuf, "#", 10000);
- if ((res > 0) && (strlen(anibuf) > 2)) {
- if (anibuf[strlen(anibuf) - 1] == '#')
- anibuf[strlen(anibuf) - 1] = 0;
- ast_set_callerid(chan, anibuf + 2, NULL, anibuf + 2);
- }
- ast_dsp_digitmode(p->dsp,DSP_DIGITMODE_DTMF | p->dtmfrelax);
- }
-
- ast_copy_string(exten, dtmfbuf, sizeof(exten));
- if (ast_strlen_zero(exten))
- ast_copy_string(exten, "s", sizeof(exten));
- if (p->sig == SIG_FEATD || p->sig == SIG_EMWINK) {
- /* Look for Feature Group D on all E&M Wink and Feature Group D trunks */
- if (exten[0] == '*') {
- char *stringp=NULL;
- ast_copy_string(exten2, exten, sizeof(exten2));
- /* Parse out extension and callerid */
- stringp=exten2 +1;
- s1 = strsep(&stringp, "*");
- s2 = strsep(&stringp, "*");
- if (s2) {
- if (!ast_strlen_zero(p->cid_num))
- ast_set_callerid(chan, p->cid_num, NULL, p->cid_num);
- else
- ast_set_callerid(chan, s1, NULL, s1);
- ast_copy_string(exten, s2, sizeof(exten));
- } else
- ast_copy_string(exten, s1, sizeof(exten));
- } else if (p->sig == SIG_FEATD)
- ast_log(LOG_WARNING, "Got a non-Feature Group D input on channel %d. Assuming E&M Wink instead\n", p->channel);
- }
- if ((p->sig == SIG_FEATDMF) || (p->sig == SIG_FEATDMF_TA)) {
- if (exten[0] == '*') {
- char *stringp=NULL;
- ast_copy_string(exten2, exten, sizeof(exten2));
- /* Parse out extension and callerid */
- stringp=exten2 +1;
- s1 = strsep(&stringp, "#");
- s2 = strsep(&stringp, "#");
- if (s2) {
- if (!ast_strlen_zero(p->cid_num))
- ast_set_callerid(chan, p->cid_num, NULL, p->cid_num);
- else
- if (*(s1 + 2))
- ast_set_callerid(chan, s1 + 2, NULL, s1 + 2);
- ast_copy_string(exten, s2 + 1, sizeof(exten));
- } else
- ast_copy_string(exten, s1 + 2, sizeof(exten));
- } else
- ast_log(LOG_WARNING, "Got a non-Feature Group D input on channel %d. Assuming E&M Wink instead\n", p->channel);
- }
- if ((p->sig == SIG_E911) || (p->sig == SIG_FGC_CAMAMF)) {
- if (exten[0] == '*') {
- char *stringp=NULL;
- ast_copy_string(exten2, exten, sizeof(exten2));
- /* Parse out extension and callerid */
- stringp=exten2 +1;
- s1 = strsep(&stringp, "#");
- s2 = strsep(&stringp, "#");
- if (s2 && (*(s2 + 1) == '0')) {
- if (*(s2 + 2))
- ast_set_callerid(chan, s2 + 2, NULL, s2 + 2);
- }
- if (s1) ast_copy_string(exten, s1, sizeof(exten));
- else ast_copy_string(exten, "911", sizeof(exten));
- } else
- ast_log(LOG_WARNING, "Got a non-E911/FGC CAMA input on channel %d. Assuming E&M Wink instead\n", p->channel);
- }
- if (p->sig == SIG_FEATB) {
- if (exten[0] == '*') {
- char *stringp=NULL;
- ast_copy_string(exten2, exten, sizeof(exten2));
- /* Parse out extension and callerid */
- stringp=exten2 +1;
- s1 = strsep(&stringp, "#");
- ast_copy_string(exten, exten2 + 1, sizeof(exten));
- } else
- ast_log(LOG_WARNING, "Got a non-Feature Group B input on channel %d. Assuming E&M Wink instead\n", p->channel);
- }
- if ((p->sig == SIG_FEATDMF) || (p->sig == SIG_FEATDMF_TA)) {
- dahdi_wink(p, index);
- /* some switches require a minimum guard time between
- the last FGD wink and something that answers
- immediately. This ensures it */
- if (ast_safe_sleep(chan,100)) goto quit;
- }
- dahdi_enable_ec(p);
- if (NEED_MFDETECT(p)) {
- if (p->dsp) {
- if (!p->hardwaredtmf)
- ast_dsp_digitmode(p->dsp,DSP_DIGITMODE_DTMF | p->dtmfrelax);
- else {
- ast_dsp_free(p->dsp);
- p->dsp = NULL;
- }
- }
- }
-
- if (ast_exists_extension(chan, chan->context, exten, 1, chan->cid.cid_num)) {
- ast_copy_string(chan->exten, exten, sizeof(chan->exten));
- if (p->dsp) ast_dsp_digitreset(p->dsp);
- res = ast_pbx_run(chan);
- if (res) {
- ast_log(LOG_WARNING, "PBX exited non-zero\n");
- res = tone_zone_play_tone(p->subs[index].dfd, DAHDI_TONE_CONGESTION);
- }
- goto quit;
- } else {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_2 "Unknown extension '%s' in context '%s' requested\n", exten, chan->context);
- sleep(2);
- res = tone_zone_play_tone(p->subs[index].dfd, DAHDI_TONE_INFO);
- if (res < 0)
- ast_log(LOG_WARNING, "Unable to start special tone on %d\n", p->channel);
- else
- sleep(1);
- res = ast_streamfile(chan, "ss-noservice", chan->language);
- if (res >= 0)
- ast_waitstream(chan, "");
- res = tone_zone_play_tone(p->subs[index].dfd, DAHDI_TONE_CONGESTION);
- ast_hangup(chan);
- goto quit;
- }
- break;
- case SIG_FXOLS:
- case SIG_FXOGS:
- case SIG_FXOKS:
- /* Read the first digit */
- timeout = firstdigittimeout;
- /* If starting a threeway call, never timeout on the first digit so someone
- can use flash-hook as a "hold" feature */
- if (p->subs[SUB_THREEWAY].owner)
- timeout = 999999;
- while (len < AST_MAX_EXTENSION-1) {
- /* Read digit unless it's supposed to be immediate, in which case the
- only answer is 's' */
- if (p->immediate)
- res = 's';
- else
- res = ast_waitfordigit(chan, timeout);
- timeout = 0;
- if (res < 0) {
- ast_log(LOG_DEBUG, "waitfordigit returned < 0...\n");
- res = tone_zone_play_tone(p->subs[index].dfd, -1);
- ast_hangup(chan);
- goto quit;
- } else if (res) {
- exten[len++]=res;
- exten[len] = '\0';
- }
- if (!ast_ignore_pattern(chan->context, exten))
- tone_zone_play_tone(p->subs[index].dfd, -1);
- else
- tone_zone_play_tone(p->subs[index].dfd, DAHDI_TONE_DIALTONE);
- if (ast_exists_extension(chan, chan->context, exten, 1, p->cid_num) && strcmp(exten, ast_parking_ext())) {
- if (!res || !ast_matchmore_extension(chan, chan->context, exten, 1, p->cid_num)) {
- if (getforward) {
- /* Record this as the forwarding extension */
- ast_copy_string(p->call_forward, exten, sizeof(p->call_forward));
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Setting call forward to '%s' on channel %d\n", p->call_forward, p->channel);
- res = tone_zone_play_tone(p->subs[index].dfd, DAHDI_TONE_DIALRECALL);
- if (res)
- break;
- usleep(500000);
- res = tone_zone_play_tone(p->subs[index].dfd, -1);
- sleep(1);
- memset(exten, 0, sizeof(exten));
- res = tone_zone_play_tone(p->subs[index].dfd, DAHDI_TONE_DIALTONE);
- len = 0;
- getforward = 0;
- } else {
- res = tone_zone_play_tone(p->subs[index].dfd, -1);
- ast_copy_string(chan->exten, exten, sizeof(chan->exten));
- if (!ast_strlen_zero(p->cid_num)) {
- if (!p->hidecallerid)
- ast_set_callerid(chan, p->cid_num, NULL, p->cid_num);
- else
- ast_set_callerid(chan, NULL, NULL, p->cid_num);
- }
- if (!ast_strlen_zero(p->cid_name)) {
- if (!p->hidecallerid)
- ast_set_callerid(chan, NULL, p->cid_name, NULL);
- }
- ast_setstate(chan, AST_STATE_RING);
- dahdi_enable_ec(p);
- res = ast_pbx_run(chan);
- if (res) {
- ast_log(LOG_WARNING, "PBX exited non-zero\n");
- res = tone_zone_play_tone(p->subs[index].dfd, DAHDI_TONE_CONGESTION);
- }
- goto quit;
- }
- } else {
- /* It's a match, but they just typed a digit, and there is an ambiguous match,
- so just set the timeout to matchdigittimeout and wait some more */
- timeout = matchdigittimeout;
- }
- } else if (res == 0) {
- ast_log(LOG_DEBUG, "not enough digits (and no ambiguous match)...\n");
- res = tone_zone_play_tone(p->subs[index].dfd, DAHDI_TONE_CONGESTION);
- dahdi_wait_event(p->subs[index].dfd);
- ast_hangup(chan);
- goto quit;
- } else if (p->callwaiting && !strcmp(exten, "*70")) {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Disabling call waiting on %s\n", chan->name);
- /* Disable call waiting if enabled */
- p->callwaiting = 0;
- res = tone_zone_play_tone(p->subs[index].dfd, DAHDI_TONE_DIALRECALL);
- if (res) {
- ast_log(LOG_WARNING, "Unable to do dial recall on channel %s: %s\n",
- chan->name, strerror(errno));
- }
- len = 0;
- ioctl(p->subs[index].dfd,DAHDI_CONFDIAG,&len);
- memset(exten, 0, sizeof(exten));
- timeout = firstdigittimeout;
-
- } else if (!strcmp(exten,ast_pickup_ext())) {
- /* Scan all channels and see if there are any
- * ringing channels that have call groups
- * that equal this channels pickup group
- */
- if (index == SUB_REAL) {
- /* Switch us from Third call to Call Wait */
- if (p->subs[SUB_THREEWAY].owner) {
- /* If you make a threeway call and the *8# a call, it should actually
- look like a callwait */
- alloc_sub(p, SUB_CALLWAIT);
- swap_subs(p, SUB_CALLWAIT, SUB_THREEWAY);
- unalloc_sub(p, SUB_THREEWAY);
- }
- dahdi_enable_ec(p);
- if (ast_pickup_call(chan)) {
- ast_log(LOG_DEBUG, "No call pickup possible...\n");
- res = tone_zone_play_tone(p->subs[index].dfd, DAHDI_TONE_CONGESTION);
- dahdi_wait_event(p->subs[index].dfd);
- }
- ast_hangup(chan);
- goto quit;
- } else {
- ast_log(LOG_WARNING, "Huh? Got *8# on call not on real\n");
- ast_hangup(chan);
- goto quit;
- }
-
- } else if (!p->hidecallerid && !strcmp(exten, "*67")) {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Disabling Caller*ID on %s\n", chan->name);
- /* Disable Caller*ID if enabled */
- p->hidecallerid = 1;
- if (chan->cid.cid_num)
- free(chan->cid.cid_num);
- chan->cid.cid_num = NULL;
- if (chan->cid.cid_name)
- free(chan->cid.cid_name);
- chan->cid.cid_name = NULL;
- res = tone_zone_play_tone(p->subs[index].dfd, DAHDI_TONE_DIALRECALL);
- if (res) {
- ast_log(LOG_WARNING, "Unable to do dial recall on channel %s: %s\n",
- chan->name, strerror(errno));
- }
- len = 0;
- memset(exten, 0, sizeof(exten));
- timeout = firstdigittimeout;
- } else if (p->callreturn && !strcmp(exten, "*69")) {
- res = 0;
- if (!ast_strlen_zero(p->lastcid_num)) {
- res = ast_say_digit_str(chan, p->lastcid_num, "", chan->language);
- }
- if (!res)
- res = tone_zone_play_tone(p->subs[index].dfd, DAHDI_TONE_DIALRECALL);
- break;
- } else if (!strcmp(exten, "*78")) {
- /* Do not disturb */
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Enabled DND on channel %d\n", p->channel);
- manager_event(EVENT_FLAG_SYSTEM, "DNDState",
- "Channel: %s/%d\r\n"
- "Status: enabled\r\n", dahdi_chan_name, p->channel);
- res = tone_zone_play_tone(p->subs[index].dfd, DAHDI_TONE_DIALRECALL);
- p->dnd = 1;
- getforward = 0;
- memset(exten, 0, sizeof(exten));
- len = 0;
- } else if (!strcmp(exten, "*79")) {
- /* Do not disturb */
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Disabled DND on channel %d\n", p->channel);
- manager_event(EVENT_FLAG_SYSTEM, "DNDState",
- "Channel: %s/%d\r\n"
- "Status: disabled\r\n", dahdi_chan_name, p->channel);
- res = tone_zone_play_tone(p->subs[index].dfd, DAHDI_TONE_DIALRECALL);
- p->dnd = 0;
- getforward = 0;
- memset(exten, 0, sizeof(exten));
- len = 0;
- } else if (p->cancallforward && !strcmp(exten, "*72")) {
- res = tone_zone_play_tone(p->subs[index].dfd, DAHDI_TONE_DIALRECALL);
- getforward = 1;
- memset(exten, 0, sizeof(exten));
- len = 0;
- } else if (p->cancallforward && !strcmp(exten, "*73")) {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Cancelling call forwarding on channel %d\n", p->channel);
- res = tone_zone_play_tone(p->subs[index].dfd, DAHDI_TONE_DIALRECALL);
- memset(p->call_forward, 0, sizeof(p->call_forward));
- getforward = 0;
- memset(exten, 0, sizeof(exten));
- len = 0;
- } else if ((p->transfer || p->canpark) && !strcmp(exten, ast_parking_ext()) &&
- p->subs[SUB_THREEWAY].owner &&
- ast_bridged_channel(p->subs[SUB_THREEWAY].owner)) {
- /* This is a three way call, the main call being a real channel,
- and we're parking the first call. */
- ast_masq_park_call(ast_bridged_channel(p->subs[SUB_THREEWAY].owner), chan, 0, NULL);
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Parking call to '%s'\n", chan->name);
- break;
- } else if (!ast_strlen_zero(p->lastcid_num) && !strcmp(exten, "*60")) {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Blacklisting number %s\n", p->lastcid_num);
- res = ast_db_put("blacklist", p->lastcid_num, "1");
- if (!res) {
- res = tone_zone_play_tone(p->subs[index].dfd, DAHDI_TONE_DIALRECALL);
- memset(exten, 0, sizeof(exten));
- len = 0;
- }
- } else if (p->hidecallerid && !strcmp(exten, "*82")) {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Enabling Caller*ID on %s\n", chan->name);
- /* Enable Caller*ID if enabled */
- p->hidecallerid = 0;
- if (chan->cid.cid_num)
- free(chan->cid.cid_num);
- chan->cid.cid_num = NULL;
- if (chan->cid.cid_name)
- free(chan->cid.cid_name);
- chan->cid.cid_name = NULL;
- ast_set_callerid(chan, p->cid_num, p->cid_name, NULL);
- res = tone_zone_play_tone(p->subs[index].dfd, DAHDI_TONE_DIALRECALL);
- if (res) {
- ast_log(LOG_WARNING, "Unable to do dial recall on channel %s: %s\n",
- chan->name, strerror(errno));
- }
- len = 0;
- memset(exten, 0, sizeof(exten));
- timeout = firstdigittimeout;
- } else if (!strcmp(exten, "*0")) {
- struct ast_channel *nbridge =
- p->subs[SUB_THREEWAY].owner;
- struct dahdi_pvt *pbridge = NULL;
- /* set up the private struct of the bridged one, if any */
- if (nbridge && ast_bridged_channel(nbridge))
- pbridge = ast_bridged_channel(nbridge)->tech_pvt;
- if (nbridge && pbridge &&
- (nbridge->tech == chan_tech) &&
- (ast_bridged_channel(nbridge)->tech == chan_tech) &&
- ISTRUNK(pbridge)) {
- int func = DAHDI_FLASH;
- /* Clear out the dial buffer */
- p->dop.dialstr[0] = '\0';
- /* flash hookswitch */
- if ((ioctl(pbridge->subs[SUB_REAL].dfd,DAHDI_HOOK,&func) == -1) && (errno != EINPROGRESS)) {
- ast_log(LOG_WARNING, "Unable to flash external trunk on channel %s: %s\n",
- nbridge->name, strerror(errno));
- }
- swap_subs(p, SUB_REAL, SUB_THREEWAY);
- unalloc_sub(p, SUB_THREEWAY);
- p->owner = p->subs[SUB_REAL].owner;
- if (ast_bridged_channel(p->subs[SUB_REAL].owner))
- ast_queue_control(p->subs[SUB_REAL].owner, AST_CONTROL_UNHOLD);
- ast_hangup(chan);
- goto quit;
- } else {
- tone_zone_play_tone(p->subs[index].dfd, DAHDI_TONE_CONGESTION);
- dahdi_wait_event(p->subs[index].dfd);
- tone_zone_play_tone(p->subs[index].dfd, -1);
- swap_subs(p, SUB_REAL, SUB_THREEWAY);
- unalloc_sub(p, SUB_THREEWAY);
- p->owner = p->subs[SUB_REAL].owner;
- ast_hangup(chan);
- goto quit;
- }
- } else if (!ast_canmatch_extension(chan, chan->context, exten, 1, chan->cid.cid_num) &&
- ((exten[0] != '*') || (strlen(exten) > 2))) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Can't match %s from '%s' in context %s\n", exten, chan->cid.cid_num ? chan->cid.cid_num : "<Unknown Caller>", chan->context);
- break;
- }
- if (!timeout)
- timeout = gendigittimeout;
- if (len && !ast_ignore_pattern(chan->context, exten))
- tone_zone_play_tone(p->subs[index].dfd, -1);
- }
- break;
- case SIG_FXSLS:
- case SIG_FXSGS:
- case SIG_FXSKS:
-#ifdef HAVE_PRI
- if (p->pri) {
- /* This is a GR-303 trunk actually. Wait for the first ring... */
- struct ast_frame *f;
- int res;
- time_t start;
-
- time(&start);
- ast_setstate(chan, AST_STATE_RING);
- while (time(NULL) < start + 3) {
- res = ast_waitfor(chan, 1000);
- if (res) {
- f = ast_read(chan);
- if (!f) {
- ast_log(LOG_WARNING, "Whoa, hangup while waiting for first ring!\n");
- ast_hangup(chan);
- goto quit;
- } else if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_RING)) {
- res = 1;
- } else
- res = 0;
- ast_frfree(f);
- if (res) {
- ast_log(LOG_DEBUG, "Got ring!\n");
- res = 0;
- break;
- }
- }
- }
- }
-#endif
- /* check for SMDI messages */
- if (p->use_smdi && p->smdi_iface) {
- smdi_msg = ast_smdi_md_message_wait(p->smdi_iface, SMDI_MD_WAIT_TIMEOUT);
-
- if (smdi_msg != NULL) {
- ast_copy_string(chan->exten, smdi_msg->fwd_st, sizeof(chan->exten));
-
- if (smdi_msg->type == 'B')
- pbx_builtin_setvar_helper(chan, "_SMDI_VM_TYPE", "b");
- else if (smdi_msg->type == 'N')
- pbx_builtin_setvar_helper(chan, "_SMDI_VM_TYPE", "u");
-
- ast_log(LOG_DEBUG, "Recieved SMDI message on %s\n", chan->name);
- } else {
- ast_log(LOG_WARNING, "SMDI enabled but no SMDI message present\n");
- }
- }
-
- if (p->use_callerid && (p->cid_signalling == CID_SIG_SMDI && smdi_msg)) {
- number = smdi_msg->calling_st;
-
- /* If we want caller id, we're in a prering state due to a polarity reversal
- * and we're set to use a polarity reversal to trigger the start of caller id,
- * grab the caller id and wait for ringing to start... */
- } else if (p->use_callerid && (chan->_state == AST_STATE_PRERING && p->cid_start == CID_START_POLARITY)) {
- /* If set to use DTMF CID signalling, listen for DTMF */
- if (p->cid_signalling == CID_SIG_DTMF) {
- int i = 0;
- cs = NULL;
- ast_log(LOG_DEBUG, "Receiving DTMF cid on "
- "channel %s\n", chan->name);
- dahdi_setlinear(p->subs[index].dfd, 0);
- res = 2000;
- for (;;) {
- struct ast_frame *f;
- res = ast_waitfor(chan, res);
- if (res <= 0) {
- ast_log(LOG_WARNING, "DTMFCID timed out waiting for ring. "
- "Exiting simple switch\n");
- ast_hangup(chan);
- goto quit;
- }
- f = ast_read(chan);
- if (!f)
- break;
- if (f->frametype == AST_FRAME_DTMF) {
- dtmfbuf[i++] = f->subclass;
- ast_log(LOG_DEBUG, "CID got digit '%c'\n", f->subclass);
- res = 2000;
- }
- ast_frfree(f);
- if (chan->_state == AST_STATE_RING ||
- chan->_state == AST_STATE_RINGING)
- break; /* Got ring */
- }
- dtmfbuf[i] = '\0';
- dahdi_setlinear(p->subs[index].dfd, p->subs[index].linear);
- /* Got cid and ring. */
- ast_log(LOG_DEBUG, "CID got string '%s'\n", dtmfbuf);
- callerid_get_dtmf(dtmfbuf, dtmfcid, &flags);
- ast_log(LOG_DEBUG, "CID is '%s', flags %d\n",
- dtmfcid, flags);
- /* If first byte is NULL, we have no cid */
- if (!ast_strlen_zero(dtmfcid))
- number = dtmfcid;
- else
- number = NULL;
- /* If set to use V23 Signalling, launch our FSK gubbins and listen for it */
- } else if ((p->cid_signalling == CID_SIG_V23) || (p->cid_signalling == CID_SIG_V23_JP)) {
- cs = callerid_new(p->cid_signalling);
- if (cs) {
- samples = 0;
-#if 1
- bump_gains(p);
-#endif
- /* Take out of linear mode for Caller*ID processing */
- dahdi_setlinear(p->subs[index].dfd, 0);
-
- /* First we wait and listen for the Caller*ID */
- for (;;) {
- i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
- if ((res = ioctl(p->subs[index].dfd, DAHDI_IOMUX, &i))) {
- ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
- callerid_free(cs);
- ast_hangup(chan);
- goto quit;
- }
- if (i & DAHDI_IOMUX_SIGEVENT) {
- res = dahdi_get_event(p->subs[index].dfd);
- ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
-
- if (p->cid_signalling == CID_SIG_V23_JP) {
-#ifdef DAHDI_EVENT_RINGBEGIN
- if (res == DAHDI_EVENT_RINGBEGIN) {
- res = dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
- usleep(1);
- }
-#endif
- } else {
- res = 0;
- break;
- }
- } else if (i & DAHDI_IOMUX_READ) {
- res = read(p->subs[index].dfd, buf, sizeof(buf));
- if (res < 0) {
- if (errno != ELAST) {
- ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
- callerid_free(cs);
- ast_hangup(chan);
- goto quit;
- }
- break;
- }
- samples += res;
-
- if (p->cid_signalling == CID_SIG_V23_JP) {
- res = callerid_feed_jp(cs, buf, res, AST_LAW(p));
- } else {
- res = callerid_feed(cs, buf, res, AST_LAW(p));
- }
-
- if (res < 0) {
- ast_log(LOG_WARNING, "CallerID feed failed on channel '%s'\n", chan->name);
- break;
- } else if (res)
- break;
- else if (samples > (8000 * 10))
- break;
- }
- }
- if (res == 1) {
- callerid_get(cs, &name, &number, &flags);
- ast_log(LOG_NOTICE, "CallerID number: %s, name: %s, flags=%d\n", number, name, flags);
- }
-
- if (p->cid_signalling == CID_SIG_V23_JP) {
- res = dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
- usleep(1);
- res = 4000;
- } else {
-
- /* Finished with Caller*ID, now wait for a ring to make sure there really is a call coming */
- res = 2000;
- }
-
- for (;;) {
- struct ast_frame *f;
- res = ast_waitfor(chan, res);
- if (res <= 0) {
- ast_log(LOG_WARNING, "CID timed out waiting for ring. "
- "Exiting simple switch\n");
- ast_hangup(chan);
- goto quit;
- }
- if (!(f = ast_read(chan))) {
- ast_log(LOG_WARNING, "Hangup received waiting for ring. Exiting simple switch\n");
- ast_hangup(chan);
- goto quit;
- }
- ast_frfree(f);
- if (chan->_state == AST_STATE_RING ||
- chan->_state == AST_STATE_RINGING)
- break; /* Got ring */
- }
-
- /* We must have a ring by now, so, if configured, lets try to listen for
- * distinctive ringing */
- if (p->usedistinctiveringdetection == 1) {
- len = 0;
- distMatches = 0;
- /* Clear the current ring data array so we dont have old data in it. */
- for (receivedRingT = 0; receivedRingT < (sizeof(curRingData) / sizeof(curRingData[0])); receivedRingT++)
- curRingData[receivedRingT] = 0;
- receivedRingT = 0;
- counter = 0;
- counter1 = 0;
- /* Check to see if context is what it should be, if not set to be. */
- if (strcmp(p->context,p->defcontext) != 0) {
- ast_copy_string(p->context, p->defcontext, sizeof(p->context));
- ast_copy_string(chan->context,p->defcontext,sizeof(chan->context));
- }
-
- for (;;) {
- i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
- if ((res = ioctl(p->subs[index].dfd, DAHDI_IOMUX, &i))) {
- ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
- callerid_free(cs);
- ast_hangup(chan);
- goto quit;
- }
- if (i & DAHDI_IOMUX_SIGEVENT) {
- res = dahdi_get_event(p->subs[index].dfd);
- ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
- res = 0;
- /* Let us detect distinctive ring */
-
- curRingData[receivedRingT] = p->ringt;
-
- if (p->ringt < p->ringt_base/2)
- break;
- /* Increment the ringT counter so we can match it against
- values in chan_dahdi.conf for distinctive ring */
- if (++receivedRingT == (sizeof(curRingData) / sizeof(curRingData[0])))
- break;
- } else if (i & DAHDI_IOMUX_READ) {
- res = read(p->subs[index].dfd, buf, sizeof(buf));
- if (res < 0) {
- if (errno != ELAST) {
- ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
- callerid_free(cs);
- ast_hangup(chan);
- goto quit;
- }
- break;
- }
- if (p->ringt)
- p->ringt--;
- if (p->ringt == 1) {
- res = -1;
- break;
- }
- }
- }
- if (option_verbose > 2)
- /* this only shows up if you have n of the dring patterns filled in */
- ast_verbose( VERBOSE_PREFIX_3 "Detected ring pattern: %d,%d,%d\n",curRingData[0],curRingData[1],curRingData[2]);
-
- for (counter = 0; counter < 3; counter++) {
- /* Check to see if the rings we received match any of the ones in chan_dahdi.conf for this
- channel */
- distMatches = 0;
- for (counter1 = 0; counter1 < 3; counter1++) {
- if (curRingData[counter1] <= (p->drings.ringnum[counter].ring[counter1]+10) && curRingData[counter1] >=
- (p->drings.ringnum[counter].ring[counter1]-10)) {
- distMatches++;
- }
- }
- if (distMatches == 3) {
- /* The ring matches, set the context to whatever is for distinctive ring.. */
- ast_copy_string(p->context, p->drings.ringContext[counter].contextData, sizeof(p->context));
- ast_copy_string(chan->context, p->drings.ringContext[counter].contextData, sizeof(chan->context));
- if (option_verbose > 2)
- ast_verbose( VERBOSE_PREFIX_3 "Distinctive Ring matched context %s\n",p->context);
- break;
- }
- }
- }
- /* Restore linear mode (if appropriate) for Caller*ID processing */
- dahdi_setlinear(p->subs[index].dfd, p->subs[index].linear);
-#if 1
- restore_gains(p);
-#endif
- } else
- ast_log(LOG_WARNING, "Unable to get caller ID space\n");
- } else {
- ast_log(LOG_WARNING, "Channel %s in prering "
- "state, but I have nothing to do. "
- "Terminating simple switch, should be "
- "restarted by the actual ring.\n",
- chan->name);
- ast_hangup(chan);
- goto quit;
- }
- } else if (p->use_callerid && p->cid_start == CID_START_RING) {
- /* FSK Bell202 callerID */
- cs = callerid_new(p->cid_signalling);
- if (cs) {
-#if 1
- bump_gains(p);
-#endif
- samples = 0;
- len = 0;
- distMatches = 0;
- /* Clear the current ring data array so we dont have old data in it. */
- for (receivedRingT = 0; receivedRingT < (sizeof(curRingData) / sizeof(curRingData[0])); receivedRingT++)
- curRingData[receivedRingT] = 0;
- receivedRingT = 0;
- counter = 0;
- counter1 = 0;
- /* Check to see if context is what it should be, if not set to be. */
- if (strcmp(p->context,p->defcontext) != 0) {
- ast_copy_string(p->context, p->defcontext, sizeof(p->context));
- ast_copy_string(chan->context,p->defcontext,sizeof(chan->context));
- }
-
- /* Take out of linear mode for Caller*ID processing */
- dahdi_setlinear(p->subs[index].dfd, 0);
- for (;;) {
- i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
- if ((res = ioctl(p->subs[index].dfd, DAHDI_IOMUX, &i))) {
- ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
- callerid_free(cs);
- ast_hangup(chan);
- goto quit;
- }
- if (i & DAHDI_IOMUX_SIGEVENT) {
- res = dahdi_get_event(p->subs[index].dfd);
- ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
- /* If we get a PR event, they hung up while processing calerid */
- if ( res == DAHDI_EVENT_POLARITY && p->hanguponpolarityswitch && p->polarity == POLARITY_REV) {
- ast_log(LOG_DEBUG, "Hanging up due to polarity reversal on channel %d while detecting callerid\n", p->channel);
- p->polarity = POLARITY_IDLE;
- callerid_free(cs);
- ast_hangup(chan);
- goto quit;
- }
- res = 0;
- /* Let us detect callerid when the telco uses distinctive ring */
-
- curRingData[receivedRingT] = p->ringt;
-
- if (p->ringt < p->ringt_base/2)
- break;
- /* Increment the ringT counter so we can match it against
- values in chan_dahdi.conf for distinctive ring */
- if (++receivedRingT == (sizeof(curRingData) / sizeof(curRingData[0])))
- break;
- } else if (i & DAHDI_IOMUX_READ) {
- res = read(p->subs[index].dfd, buf, sizeof(buf));
- if (res < 0) {
- if (errno != ELAST) {
- ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
- callerid_free(cs);
- ast_hangup(chan);
- goto quit;
- }
- break;
- }
- if (p->ringt)
- p->ringt--;
- if (p->ringt == 1) {
- res = -1;
- break;
- }
- samples += res;
- res = callerid_feed(cs, buf, res, AST_LAW(p));
- if (res < 0) {
- ast_log(LOG_WARNING, "CallerID feed failed: %s\n", strerror(errno));
- break;
- } else if (res)
- break;
- else if (samples > (8000 * 10))
- break;
- }
- }
- if (res == 1) {
- callerid_get(cs, &name, &number, &flags);
- if (option_debug)
- ast_log(LOG_DEBUG, "CallerID number: %s, name: %s, flags=%d\n", number, name, flags);
- }
- if (distinctiveringaftercid == 1) {
- /* Clear the current ring data array so we dont have old data in it. */
- for (receivedRingT = 0; receivedRingT < 3; receivedRingT++) {
- curRingData[receivedRingT] = 0;
- }
- receivedRingT = 0;
- if (option_verbose > 2)
- ast_verbose( VERBOSE_PREFIX_3 "Detecting post-CID distinctive ring\n");
- for (;;) {
- i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
- if ((res = ioctl(p->subs[index].dfd, DAHDI_IOMUX, &i))) {
- ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
- callerid_free(cs);
- ast_hangup(chan);
- goto quit;
- }
- if (i & DAHDI_IOMUX_SIGEVENT) {
- res = dahdi_get_event(p->subs[index].dfd);
- ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
- res = 0;
- /* Let us detect callerid when the telco uses distinctive ring */
-
- curRingData[receivedRingT] = p->ringt;
-
- if (p->ringt < p->ringt_base/2)
- break;
- /* Increment the ringT counter so we can match it against
- values in chan_dahdi.conf for distinctive ring */
- if (++receivedRingT == (sizeof(curRingData) / sizeof(curRingData[0])))
- break;
- } else if (i & DAHDI_IOMUX_READ) {
- res = read(p->subs[index].dfd, buf, sizeof(buf));
- if (res < 0) {
- if (errno != ELAST) {
- ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
- callerid_free(cs);
- ast_hangup(chan);
- goto quit;
- }
- break;
- }
- if (p->ringt)
- p->ringt--;
- if (p->ringt == 1) {
- res = -1;
- break;
- }
- }
- }
- }
- if (p->usedistinctiveringdetection == 1) {
- if (option_verbose > 2)
- /* this only shows up if you have n of the dring patterns filled in */
- ast_verbose( VERBOSE_PREFIX_3 "Detected ring pattern: %d,%d,%d\n",curRingData[0],curRingData[1],curRingData[2]);
-
- for (counter = 0; counter < 3; counter++) {
- /* Check to see if the rings we received match any of the ones in chan_dahdi.conf for this
- channel */
- if (option_verbose > 2)
- /* this only shows up if you have n of the dring patterns filled in */
- ast_verbose( VERBOSE_PREFIX_3 "Checking %d,%d,%d\n",
- p->drings.ringnum[counter].ring[0],
- p->drings.ringnum[counter].ring[1],
- p->drings.ringnum[counter].ring[2]);
- distMatches = 0;
- for (counter1 = 0; counter1 < 3; counter1++) {
- if (curRingData[counter1] <= (p->drings.ringnum[counter].ring[counter1]+10) && curRingData[counter1] >=
- (p->drings.ringnum[counter].ring[counter1]-10)) {
- distMatches++;
- }
- }
- if (distMatches == 3) {
- /* The ring matches, set the context to whatever is for distinctive ring.. */
- ast_copy_string(p->context, p->drings.ringContext[counter].contextData, sizeof(p->context));
- ast_copy_string(chan->context, p->drings.ringContext[counter].contextData, sizeof(chan->context));
- if (option_verbose > 2)
- ast_verbose( VERBOSE_PREFIX_3 "Distinctive Ring matched context %s\n",p->context);
- break;
- }
- }
- }
- /* Restore linear mode (if appropriate) for Caller*ID processing */
- dahdi_setlinear(p->subs[index].dfd, p->subs[index].linear);
-#if 1
- restore_gains(p);
-#endif
- if (res < 0) {
- ast_log(LOG_WARNING, "CallerID returned with error on channel '%s'\n", chan->name);
- }
- } else
- ast_log(LOG_WARNING, "Unable to get caller ID space\n");
- }
- else
- cs = NULL;
-
- if (number)
- ast_shrink_phone_number(number);
- ast_set_callerid(chan, number, name, number);
-
- if (smdi_msg)
- ASTOBJ_UNREF(smdi_msg, ast_smdi_md_message_destroy);
-
- if (cs)
- callerid_free(cs);
-
- ast_setstate(chan, AST_STATE_RING);
- chan->rings = 1;
- p->ringt = p->ringt_base;
- res = ast_pbx_run(chan);
- if (res) {
- ast_hangup(chan);
- ast_log(LOG_WARNING, "PBX exited non-zero\n");
- }
- goto quit;
- default:
- ast_log(LOG_WARNING, "Don't know how to handle simple switch with signalling %s on channel %d\n", sig2str(p->sig), p->channel);
- res = tone_zone_play_tone(p->subs[index].dfd, DAHDI_TONE_CONGESTION);
- if (res < 0)
- ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", p->channel);
- }
- res = tone_zone_play_tone(p->subs[index].dfd, DAHDI_TONE_CONGESTION);
- if (res < 0)
- ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", p->channel);
- ast_hangup(chan);
-quit:
- ast_mutex_lock(&ss_thread_lock);
- ss_thread_count--;
- ast_cond_signal(&ss_thread_complete);
- ast_mutex_unlock(&ss_thread_lock);
- return NULL;
-}
-
-/* destroy a DAHDI channel, identified by its number */
-static int dahdi_destroy_channel_bynum(int channel)
-{
- struct dahdi_pvt *tmp = NULL;
- struct dahdi_pvt *prev = NULL;
-
- tmp = iflist;
- while (tmp) {
- if (tmp->channel == channel) {
- int x = DAHDI_FLASH;
- ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_HOOK, &x); /* important to create an event for dahdi_wait_event to register so that all ss_threads terminate */
- destroy_channel(prev, tmp, 1);
- ast_module_unref(ast_module_info->self);
- return RESULT_SUCCESS;
- }
- prev = tmp;
- tmp = tmp->next;
- }
- return RESULT_FAILURE;
-}
-
-static int handle_init_event(struct dahdi_pvt *i, int event)
-{
- int res;
- pthread_t threadid;
- pthread_attr_t attr;
- struct ast_channel *chan;
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- /* Handle an event on a given channel for the monitor thread. */
- switch (event) {
- case DAHDI_EVENT_NONE:
- case DAHDI_EVENT_BITSCHANGED:
- break;
- case DAHDI_EVENT_WINKFLASH:
- case DAHDI_EVENT_RINGOFFHOOK:
- if (i->inalarm) break;
- if (i->radio) break;
- /* Got a ring/answer. What kind of channel are we? */
- switch (i->sig) {
- case SIG_FXOLS:
- case SIG_FXOGS:
- case SIG_FXOKS:
- res = dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
- if (res && (errno == EBUSY))
- break;
- if (i->cidspill) {
- /* Cancel VMWI spill */
- free(i->cidspill);
- i->cidspill = NULL;
- }
- if (i->immediate) {
- dahdi_enable_ec(i);
- /* The channel is immediately up. Start right away */
- res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
- chan = dahdi_new(i, AST_STATE_RING, 1, SUB_REAL, 0, 0);
- if (!chan) {
- ast_log(LOG_WARNING, "Unable to start PBX on channel %d\n", i->channel);
- res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
- if (res < 0)
- ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
- }
- } else {
- /* Check for callerid, digits, etc */
- chan = dahdi_new(i, AST_STATE_RESERVED, 0, SUB_REAL, 0, 0);
- if (chan) {
- if (has_voicemail(i))
- res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_STUTTER);
- else
- res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_DIALTONE);
- if (res < 0)
- ast_log(LOG_WARNING, "Unable to play dialtone on channel %d, do you have defaultzone and loadzone defined?\n", i->channel);
- if (ast_pthread_create(&threadid, &attr, ss_thread, chan)) {
- ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
- res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
- if (res < 0)
- ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
- ast_hangup(chan);
- }
- } else
- ast_log(LOG_WARNING, "Unable to create channel\n");
- }
- break;
- case SIG_FXSLS:
- case SIG_FXSGS:
- case SIG_FXSKS:
- i->ringt = i->ringt_base;
- /* Fall through */
- case SIG_EMWINK:
- case SIG_FEATD:
- case SIG_FEATDMF:
- case SIG_FEATDMF_TA:
- case SIG_E911:
- case SIG_FGC_CAMA:
- case SIG_FGC_CAMAMF:
- case SIG_FEATB:
- case SIG_EM:
- case SIG_EM_E1:
- case SIG_SFWINK:
- case SIG_SF_FEATD:
- case SIG_SF_FEATDMF:
- case SIG_SF_FEATB:
- case SIG_SF:
- /* Check for callerid, digits, etc */
- chan = dahdi_new(i, AST_STATE_RING, 0, SUB_REAL, 0, 0);
- if (chan && ast_pthread_create(&threadid, &attr, ss_thread, chan)) {
- ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
- res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
- if (res < 0)
- ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
- ast_hangup(chan);
- } else if (!chan) {
- ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", i->channel);
- }
- break;
- default:
- ast_log(LOG_WARNING, "Don't know how to handle ring/answer with signalling %s on channel %d\n", sig2str(i->sig), i->channel);
- res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
- if (res < 0)
- ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
- return -1;
- }
- break;
- case DAHDI_EVENT_NOALARM:
- i->inalarm = 0;
- if (!i->unknown_alarm) {
- ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", i->channel);
- manager_event(EVENT_FLAG_SYSTEM, "AlarmClear",
- "Channel: %d\r\n", i->channel);
- } else {
- i->unknown_alarm = 0;
- }
- break;
- case DAHDI_EVENT_ALARM:
- i->inalarm = 1;
- res = get_alarms(i);
- handle_alarms(i, res);
- /* fall thru intentionally */
- case DAHDI_EVENT_ONHOOK:
- if (i->radio)
- break;
- /* Back on hook. Hang up. */
- switch (i->sig) {
- case SIG_FXOLS:
- case SIG_FXOGS:
- case SIG_FEATD:
- case SIG_FEATDMF:
- case SIG_FEATDMF_TA:
- case SIG_E911:
- case SIG_FGC_CAMA:
- case SIG_FGC_CAMAMF:
- case SIG_FEATB:
- case SIG_EM:
- case SIG_EM_E1:
- case SIG_EMWINK:
- case SIG_SF_FEATD:
- case SIG_SF_FEATDMF:
- case SIG_SF_FEATB:
- case SIG_SF:
- case SIG_SFWINK:
- case SIG_FXSLS:
- case SIG_FXSGS:
- case SIG_FXSKS:
- case SIG_GR303FXSKS:
- dahdi_disable_ec(i);
- res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, -1);
- dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
- break;
- case SIG_GR303FXOKS:
- case SIG_FXOKS:
- dahdi_disable_ec(i);
- /* Diddle the battery for the zhone */
-#ifdef ZHONE_HACK
- dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
- usleep(1);
-#endif
- res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, -1);
- dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
- break;
- case SIG_PRI:
- dahdi_disable_ec(i);
- res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, -1);
- break;
- default:
- ast_log(LOG_WARNING, "Don't know how to handle on hook with signalling %s on channel %d\n", sig2str(i->sig), i->channel);
- res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, -1);
- return -1;
- }
- break;
- case DAHDI_EVENT_POLARITY:
- switch (i->sig) {
- case SIG_FXSLS:
- case SIG_FXSKS:
- case SIG_FXSGS:
- /* We have already got a PR before the channel was
- created, but it wasn't handled. We need polarity
- to be REV for remote hangup detection to work.
- At least in Spain */
- if (i->hanguponpolarityswitch)
- i->polarity = POLARITY_REV;
-
- if (i->cid_start == CID_START_POLARITY) {
- i->polarity = POLARITY_REV;
- ast_verbose(VERBOSE_PREFIX_2 "Starting post polarity "
- "CID detection on channel %d\n",
- i->channel);
- chan = dahdi_new(i, AST_STATE_PRERING, 0, SUB_REAL, 0, 0);
- if (chan && ast_pthread_create(&threadid, &attr, ss_thread, chan)) {
- ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
- }
- }
- break;
- default:
- ast_log(LOG_WARNING, "handle_init_event detected "
- "polarity reversal on non-FXO (SIG_FXS) "
- "interface %d\n", i->channel);
- }
- break;
- case DAHDI_EVENT_REMOVED: /* destroy channel */
- ast_log(LOG_NOTICE,
- "Got DAHDI_EVENT_REMOVED. Destroying channel %d\n",
- i->channel);
- dahdi_destroy_channel_bynum(i->channel);
- break;
- }
- pthread_attr_destroy(&attr);
- return 0;
-}
-
-static void *do_monitor(void *data)
-{
- int count, res, res2, spoint, pollres=0;
- struct dahdi_pvt *i;
- struct dahdi_pvt *last = NULL;
- time_t thispass = 0, lastpass = 0;
- int found;
- char buf[1024];
- struct pollfd *pfds=NULL;
- int lastalloc = -1;
- /* This thread monitors all the frame relay interfaces which are not yet in use
- (and thus do not have a separate thread) indefinitely */
- /* From here on out, we die whenever asked */
-#if 0
- if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)) {
- ast_log(LOG_WARNING, "Unable to set cancel type to asynchronous\n");
- return NULL;
- }
- ast_log(LOG_DEBUG, "Monitor starting...\n");
-#endif
- pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
-
- for (;;) {
- /* Lock the interface list */
- ast_mutex_lock(&iflock);
- if (!pfds || (lastalloc != ifcount)) {
- if (pfds) {
- free(pfds);
- pfds = NULL;
- }
- if (ifcount) {
- if (!(pfds = ast_calloc(1, ifcount * sizeof(*pfds)))) {
- ast_mutex_unlock(&iflock);
- return NULL;
- }
- }
- lastalloc = ifcount;
- }
- /* Build the stuff we're going to poll on, that is the socket of every
- dahdi_pvt that does not have an associated owner channel */
- count = 0;
- i = iflist;
- while (i) {
- if ((i->subs[SUB_REAL].dfd > -1) && i->sig && (!i->radio)) {
- if (!i->owner && !i->subs[SUB_REAL].owner) {
- /* This needs to be watched, as it lacks an owner */
- pfds[count].fd = i->subs[SUB_REAL].dfd;
- pfds[count].events = POLLPRI;
- pfds[count].revents = 0;
- /* Message waiting or r2 channels also get watched for reading */
- if (i->cidspill)
- pfds[count].events |= POLLIN;
- count++;
- }
- }
- i = i->next;
- }
- /* Okay, now that we know what to do, release the interface lock */
- ast_mutex_unlock(&iflock);
-
- pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
- pthread_testcancel();
- /* Wait at least a second for something to happen */
- res = poll(pfds, count, 1000);
- pthread_testcancel();
- pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
-
- /* Okay, poll has finished. Let's see what happened. */
- if (res < 0) {
- if ((errno != EAGAIN) && (errno != EINTR))
- ast_log(LOG_WARNING, "poll return %d: %s\n", res, strerror(errno));
- continue;
- }
- /* Alright, lock the interface list again, and let's look and see what has
- happened */
- ast_mutex_lock(&iflock);
- found = 0;
- spoint = 0;
- lastpass = thispass;
- thispass = time(NULL);
- i = iflist;
- while (i) {
- if (thispass != lastpass) {
- if (!found && ((i == last) || ((i == iflist) && !last))) {
- last = i;
- if (last) {
- if (!last->cidspill && !last->owner && !ast_strlen_zero(last->mailbox) && (thispass - last->onhooktime > 3) &&
- (last->sig & __DAHDI_SIG_FXO)) {
- res = ast_app_has_voicemail(last->mailbox, NULL);
- if (last->msgstate != res) {
- int x;
- ast_log(LOG_DEBUG, "Message status for %s changed from %d to %d on %d\n", last->mailbox, last->msgstate, res, last->channel);
- x = DAHDI_FLUSH_BOTH;
- res2 = ioctl(last->subs[SUB_REAL].dfd, DAHDI_FLUSH, &x);
- if (res2)
- ast_log(LOG_WARNING, "Unable to flush input on channel %d: %s\n", last->channel, strerror(errno));
- if ((last->cidspill = ast_calloc(1, MAX_CALLERID_SIZE))) {
- /* Turn on on hook transfer for 4 seconds */
- x = 4000;
- ioctl(last->subs[SUB_REAL].dfd, DAHDI_ONHOOKTRANSFER, &x);
- last->cidlen = vmwi_generate(last->cidspill, res, 1, AST_LAW(last));
- last->cidpos = 0;
- last->msgstate = res;
- last->onhooktime = thispass;
- }
- found ++;
- }
- }
- last = last->next;
- }
- }
- }
- if ((i->subs[SUB_REAL].dfd > -1) && i->sig) {
- if (i->radio && !i->owner)
- {
- res = dahdi_get_event(i->subs[SUB_REAL].dfd);
- if (res)
- {
- if (option_debug)
- ast_log(LOG_DEBUG, "Monitor doohicky got event %s on radio channel %d\n", event2str(res), i->channel);
- /* Don't hold iflock while handling init events */
- ast_mutex_unlock(&iflock);
- handle_init_event(i, res);
- ast_mutex_lock(&iflock);
- }
- i = i->next;
- continue;
- }
- pollres = ast_fdisset(pfds, i->subs[SUB_REAL].dfd, count, &spoint);
- if (pollres & POLLIN) {
- if (i->owner || i->subs[SUB_REAL].owner) {
-#ifdef HAVE_PRI
- if (!i->pri)
-#endif
- ast_log(LOG_WARNING, "Whoa.... I'm owned but found (%d) in read...\n", i->subs[SUB_REAL].dfd);
- i = i->next;
- continue;
- }
- if (!i->cidspill) {
- ast_log(LOG_WARNING, "Whoa.... I'm reading but have no cidspill (%d)...\n", i->subs[SUB_REAL].dfd);
- i = i->next;
- continue;
- }
- res = read(i->subs[SUB_REAL].dfd, buf, sizeof(buf));
- if (res > 0) {
- /* We read some number of bytes. Write an equal amount of data */
- if (res > i->cidlen - i->cidpos)
- res = i->cidlen - i->cidpos;
- res2 = write(i->subs[SUB_REAL].dfd, i->cidspill + i->cidpos, res);
- if (res2 > 0) {
- i->cidpos += res2;
- if (i->cidpos >= i->cidlen) {
- free(i->cidspill);
- i->cidspill = 0;
- i->cidpos = 0;
- i->cidlen = 0;
- }
- } else {
- ast_log(LOG_WARNING, "Write failed: %s\n", strerror(errno));
- i->msgstate = -1;
- }
- } else {
- ast_log(LOG_WARNING, "Read failed with %d: %s\n", res, strerror(errno));
- }
- }
- if (pollres & POLLPRI) {
- if (i->owner || i->subs[SUB_REAL].owner) {
-#ifdef HAVE_PRI
- if (!i->pri)
-#endif
- ast_log(LOG_WARNING, "Whoa.... I'm owned but found (%d)...\n", i->subs[SUB_REAL].dfd);
- i = i->next;
- continue;
- }
- res = dahdi_get_event(i->subs[SUB_REAL].dfd);
- if (option_debug)
- ast_log(LOG_DEBUG, "Monitor doohicky got event %s on channel %d\n", event2str(res), i->channel);
- /* Don't hold iflock while handling init events */
- ast_mutex_unlock(&iflock);
- handle_init_event(i, res);
- ast_mutex_lock(&iflock);
- }
- }
- i=i->next;
- }
- ast_mutex_unlock(&iflock);
- }
- /* Never reached */
- return NULL;
-
-}
-
-static int restart_monitor(void)
-{
- pthread_attr_t attr;
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- /* If we're supposed to be stopped -- stay stopped */
- if (monitor_thread == AST_PTHREADT_STOP)
- return 0;
- ast_mutex_lock(&monlock);
- if (monitor_thread == pthread_self()) {
- ast_mutex_unlock(&monlock);
- ast_log(LOG_WARNING, "Cannot kill myself\n");
- return -1;
- }
- if (monitor_thread != AST_PTHREADT_NULL) {
- /* Wake up the thread */
- pthread_kill(monitor_thread, SIGURG);
- } else {
- /* Start a new monitor */
- if (ast_pthread_create_background(&monitor_thread, &attr, do_monitor, NULL) < 0) {
- ast_mutex_unlock(&monlock);
- ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
- pthread_attr_destroy(&attr);
- return -1;
- }
- }
- ast_mutex_unlock(&monlock);
- pthread_attr_destroy(&attr);
- return 0;
-}
-
-#ifdef HAVE_PRI
-static int pri_resolve_span(int *span, int channel, int offset, struct dahdi_spaninfo *si)
-{
- int x;
- int trunkgroup;
- /* Get appropriate trunk group if there is one */
- trunkgroup = pris[*span].mastertrunkgroup;
- if (trunkgroup) {
- /* Select a specific trunk group */
- for (x = 0; x < NUM_SPANS; x++) {
- if (pris[x].trunkgroup == trunkgroup) {
- *span = x;
- return 0;
- }
- }
- ast_log(LOG_WARNING, "Channel %d on span %d configured to use nonexistent trunk group %d\n", channel, *span, trunkgroup);
- *span = -1;
- } else {
- if (pris[*span].trunkgroup) {
- ast_log(LOG_WARNING, "Unable to use span %d implicitly since it is trunk group %d (please use spanmap)\n", *span, pris[*span].trunkgroup);
- *span = -1;
- } else if (pris[*span].mastertrunkgroup) {
- ast_log(LOG_WARNING, "Unable to use span %d implicitly since it is already part of trunk group %d\n", *span, pris[*span].mastertrunkgroup);
- *span = -1;
- } else {
- if (si->totalchans == 31) {
- /* E1 */
- pris[*span].dchannels[0] = 16 + offset;
- } else if (si->totalchans == 24) {
- /* T1 or J1 */
- pris[*span].dchannels[0] = 24 + offset;
- } else if (si->totalchans == 3) {
- /* BRI */
- pris[*span].dchannels[0] = 3 + offset;
- } else {
- ast_log(LOG_WARNING, "Unable to use span %d, since the D-channel cannot be located (unexpected span size of %d channels)\n", *span, si->totalchans);
- *span = -1;
- return 0;
- }
- pris[*span].dchanavail[0] |= DCHAN_PROVISIONED;
- pris[*span].offset = offset;
- pris[*span].span = *span + 1;
- }
- }
- return 0;
-}
-
-static int pri_create_trunkgroup(int trunkgroup, int *channels)
-{
- struct dahdi_spaninfo si;
- struct dahdi_params p;
- int fd;
- int span;
- int ospan=0;
- int x,y;
- for (x = 0; x < NUM_SPANS; x++) {
- if (pris[x].trunkgroup == trunkgroup) {
- ast_log(LOG_WARNING, "Trunk group %d already exists on span %d, Primary d-channel %d\n", trunkgroup, x + 1, pris[x].dchannels[0]);
- return -1;
- }
- }
- for (y = 0; y < NUM_DCHANS; y++) {
- if (!channels[y])
- break;
- memset(&si, 0, sizeof(si));
- memset(&p, 0, sizeof(p));
- fd = open(DAHDI_FILE_CHANNEL, O_RDWR);
- if (fd < 0) {
- ast_log(LOG_WARNING, "Failed to open channel: %s\n", strerror(errno));
- return -1;
- }
- x = channels[y];
- if (ioctl(fd, DAHDI_SPECIFY, &x)) {
- ast_log(LOG_WARNING, "Failed to specify channel %d: %s\n", channels[y], strerror(errno));
- close(fd);
- return -1;
- }
- if (ioctl(fd, DAHDI_GET_PARAMS, &p)) {
- ast_log(LOG_WARNING, "Failed to get channel parameters for channel %d: %s\n", channels[y], strerror(errno));
- return -1;
- }
- if (ioctl(fd, DAHDI_SPANSTAT, &si)) {
- ast_log(LOG_WARNING, "Failed go get span information on channel %d (span %d): %s\n", channels[y], p.spanno, strerror(errno));
- close(fd);
- return -1;
- }
- span = p.spanno - 1;
- if (pris[span].trunkgroup) {
- ast_log(LOG_WARNING, "Span %d is already provisioned for trunk group %d\n", span + 1, pris[span].trunkgroup);
- close(fd);
- return -1;
- }
- if (pris[span].pvts[0]) {
- ast_log(LOG_WARNING, "Span %d is already provisioned with channels (implicit PRI maybe?)\n", span + 1);
- close(fd);
- return -1;
- }
- if (!y) {
- pris[span].trunkgroup = trunkgroup;
- pris[span].offset = channels[y] - p.chanpos;
- ospan = span;
- }
- pris[ospan].dchannels[y] = channels[y];
- pris[ospan].dchanavail[y] |= DCHAN_PROVISIONED;
- pris[span].span = span + 1;
- close(fd);
- }
- return 0;
-}
-
-static int pri_create_spanmap(int span, int trunkgroup, int logicalspan)
-{
- if (pris[span].mastertrunkgroup) {
- ast_log(LOG_WARNING, "Span %d is already part of trunk group %d, cannot add to trunk group %d\n", span + 1, pris[span].mastertrunkgroup, trunkgroup);
- return -1;
- }
- pris[span].mastertrunkgroup = trunkgroup;
- pris[span].prilogicalspan = logicalspan;
- return 0;
-}
-
-#endif
-
-static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf, struct dahdi_pri *pri, int reloading)
-{
- /* Make a dahdi_pvt structure for this interface (or CRV if "pri" is specified) */
- struct dahdi_pvt *tmp = NULL, *tmp2, *prev = NULL;
- char fn[80];
-#if 1
- struct dahdi_bufferinfo bi;
-#endif
- int res;
- int span=0;
- int here = 0;
- int x;
- struct dahdi_pvt **wlist;
- struct dahdi_pvt **wend;
- struct dahdi_params p;
-
- wlist = &iflist;
- wend = &ifend;
-
-#ifdef HAVE_PRI
- if (pri) {
- wlist = &pri->crvs;
- wend = &pri->crvend;
- }
-#endif
-
- tmp2 = *wlist;
- prev = NULL;
-
- while (tmp2) {
- if (!tmp2->destroy) {
- if (tmp2->channel == channel) {
- tmp = tmp2;
- here = 1;
- break;
- }
- if (tmp2->channel > channel) {
- break;
- }
- }
- prev = tmp2;
- tmp2 = tmp2->next;
- }
-
- if (!here && reloading != 1) {
- if (!(tmp = ast_calloc(1, sizeof(*tmp)))) {
- if (tmp)
- free(tmp);
- return NULL;
- }
- ast_mutex_init(&tmp->lock);
- ifcount++;
- for (x = 0; x < 3; x++)
- tmp->subs[x].dfd = -1;
- tmp->channel = channel;
- }
-
- if (tmp) {
- int chan_sig = conf->chan.sig;
- if (!here) {
- if ((channel != CHAN_PSEUDO) && !pri) {
- int count = 0;
- snprintf(fn, sizeof(fn), "%d", channel);
- /* Open non-blocking */
- tmp->subs[SUB_REAL].dfd = dahdi_open(fn);
- while (tmp->subs[SUB_REAL].dfd < 0 && reloading == 2 && count < 1000) { /* the kernel may not call dahdi_release fast enough for the open flagbit to be cleared in time */
- usleep(1);
- tmp->subs[SUB_REAL].dfd = dahdi_open(fn);
- count++;
- }
- /* Allocate a DAHDI structure */
- if (tmp->subs[SUB_REAL].dfd < 0) {
- ast_log(LOG_ERROR, "Unable to open channel %d: %s\nhere = %d, tmp->channel = %d, channel = %d\n", channel, strerror(errno), here, tmp->channel, channel);
- destroy_dahdi_pvt(&tmp);
- return NULL;
- }
- memset(&p, 0, sizeof(p));
- res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &p);
- if (res < 0) {
- ast_log(LOG_ERROR, "Unable to get parameters: %s\n", strerror(errno));
- destroy_dahdi_pvt(&tmp);
- return NULL;
- }
- if (p.sigtype != (conf->chan.sig & 0x3ffff)) {
- ast_log(LOG_ERROR, "Signalling requested on channel %d is %s but line is in %s signalling\n", channel, sig2str(conf->chan.sig), sig2str(p.sigtype));
- destroy_dahdi_pvt(&tmp);
- return NULL;
- }
- tmp->law = p.curlaw;
- tmp->span = p.spanno;
- span = p.spanno - 1;
- } else {
- if (channel == CHAN_PSEUDO)
- chan_sig = 0;
- else if ((chan_sig != SIG_FXOKS) && (chan_sig != SIG_FXSKS)) {
- ast_log(LOG_ERROR, "CRV's must use FXO/FXS Kewl Start (fxo_ks/fxs_ks) signalling only.\n");
- return NULL;
- }
- }
-#ifdef HAVE_PRI
- if ((chan_sig == SIG_PRI) || (chan_sig == SIG_GR303FXOKS) || (chan_sig == SIG_GR303FXSKS)) {
- int offset;
- int myswitchtype;
- int matchesdchan;
- int x,y;
- offset = 0;
- if ((chan_sig == SIG_PRI) && ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &offset)) {
- ast_log(LOG_ERROR, "Unable to set clear mode on clear channel %d of span %d: %s\n", channel, p.spanno, strerror(errno));
- destroy_dahdi_pvt(&tmp);
- return NULL;
- }
- if (span >= NUM_SPANS) {
- ast_log(LOG_ERROR, "Channel %d does not lie on a span I know of (%d)\n", channel, span);
- destroy_dahdi_pvt(&tmp);
- return NULL;
- } else {
- struct dahdi_spaninfo si;
- si.spanno = 0;
- if (ioctl(tmp->subs[SUB_REAL].dfd,DAHDI_SPANSTAT,&si) == -1) {
- ast_log(LOG_ERROR, "Unable to get span status: %s\n", strerror(errno));
- destroy_dahdi_pvt(&tmp);
- return NULL;
- }
- /* Store the logical span first based upon the real span */
- tmp->logicalspan = pris[span].prilogicalspan;
- pri_resolve_span(&span, channel, (channel - p.chanpos), &si);
- if (span < 0) {
- ast_log(LOG_WARNING, "Channel %d: Unable to find locate channel/trunk group!\n", channel);
- destroy_dahdi_pvt(&tmp);
- return NULL;
- }
- if (chan_sig == SIG_PRI)
- myswitchtype = conf->pri.switchtype;
- else
- myswitchtype = PRI_SWITCH_GR303_TMC;
- /* Make sure this isn't a d-channel */
- matchesdchan=0;
- for (x = 0; x < NUM_SPANS; x++) {
- for (y = 0; y < NUM_DCHANS; y++) {
- if (pris[x].dchannels[y] == tmp->channel) {
- matchesdchan = 1;
- break;
- }
- }
- }
- offset = p.chanpos;
- if (!matchesdchan) {
- if (pris[span].nodetype && (pris[span].nodetype != conf->pri.nodetype)) {
- ast_log(LOG_ERROR, "Span %d is already a %s node\n", span + 1, pri_node2str(pris[span].nodetype));
- destroy_dahdi_pvt(&tmp);
- return NULL;
- }
- if (pris[span].switchtype && (pris[span].switchtype != myswitchtype)) {
- ast_log(LOG_ERROR, "Span %d is already a %s switch\n", span + 1, pri_switch2str(pris[span].switchtype));
- destroy_dahdi_pvt(&tmp);
- return NULL;
- }
- if ((pris[span].dialplan) && (pris[span].dialplan != conf->pri.dialplan)) {
- ast_log(LOG_ERROR, "Span %d is already a %s dialing plan\n", span + 1, dialplan2str(pris[span].dialplan));
- destroy_dahdi_pvt(&tmp);
- return NULL;
- }
- if (!ast_strlen_zero(pris[span].idledial) && strcmp(pris[span].idledial, conf->pri.idledial)) {
- ast_log(LOG_ERROR, "Span %d already has idledial '%s'.\n", span + 1, conf->pri.idledial);
- destroy_dahdi_pvt(&tmp);
- return NULL;
- }
- if (!ast_strlen_zero(pris[span].idleext) && strcmp(pris[span].idleext, conf->pri.idleext)) {
- ast_log(LOG_ERROR, "Span %d already has idleext '%s'.\n", span + 1, conf->pri.idleext);
- destroy_dahdi_pvt(&tmp);
- return NULL;
- }
- if (pris[span].minunused && (pris[span].minunused != conf->pri.minunused)) {
- ast_log(LOG_ERROR, "Span %d already has minunused of %d.\n", span + 1, conf->pri.minunused);
- destroy_dahdi_pvt(&tmp);
- return NULL;
- }
- if (pris[span].minidle && (pris[span].minidle != conf->pri.minidle)) {
- ast_log(LOG_ERROR, "Span %d already has minidle of %d.\n", span + 1, conf->pri.minidle);
- destroy_dahdi_pvt(&tmp);
- return NULL;
- }
- if (pris[span].numchans >= MAX_CHANNELS) {
- ast_log(LOG_ERROR, "Unable to add channel %d: Too many channels in trunk group %d!\n", channel,
- pris[span].trunkgroup);
- destroy_dahdi_pvt(&tmp);
- return NULL;
- }
- pris[span].nodetype = conf->pri.nodetype;
- pris[span].switchtype = myswitchtype;
- pris[span].nsf = conf->pri.nsf;
- pris[span].dialplan = conf->pri.dialplan;
- pris[span].localdialplan = conf->pri.localdialplan;
- pris[span].pvts[pris[span].numchans++] = tmp;
- pris[span].minunused = conf->pri.minunused;
- pris[span].minidle = conf->pri.minidle;
- pris[span].overlapdial = conf->pri.overlapdial;
-#ifdef HAVE_PRI_INBANDDISCONNECT
- pris[span].inbanddisconnect = conf->pri.inbanddisconnect;
-#endif
- pris[span].facilityenable = conf->pri.facilityenable;
- ast_copy_string(pris[span].idledial, conf->pri.idledial, sizeof(pris[span].idledial));
- ast_copy_string(pris[span].idleext, conf->pri.idleext, sizeof(pris[span].idleext));
- ast_copy_string(pris[span].internationalprefix, conf->pri.internationalprefix, sizeof(pris[span].internationalprefix));
- ast_copy_string(pris[span].nationalprefix, conf->pri.nationalprefix, sizeof(pris[span].nationalprefix));
- ast_copy_string(pris[span].localprefix, conf->pri.localprefix, sizeof(pris[span].localprefix));
- ast_copy_string(pris[span].privateprefix, conf->pri.privateprefix, sizeof(pris[span].privateprefix));
- ast_copy_string(pris[span].unknownprefix, conf->pri.unknownprefix, sizeof(pris[span].unknownprefix));
- pris[span].resetinterval = conf->pri.resetinterval;
-
- tmp->pri = &pris[span];
- tmp->prioffset = offset;
- tmp->call = NULL;
- } else {
- ast_log(LOG_ERROR, "Channel %d is reserved for D-channel.\n", offset);
- destroy_dahdi_pvt(&tmp);
- return NULL;
- }
- }
- } else {
- tmp->prioffset = 0;
- }
-#endif
- } else {
- chan_sig = tmp->sig;
- memset(&p, 0, sizeof(p));
- if (tmp->subs[SUB_REAL].dfd > -1)
- res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &p);
- }
- /* Adjust starttime on loopstart and kewlstart trunks to reasonable values */
- switch (chan_sig) {
- case SIG_FXSKS:
- case SIG_FXSLS:
- case SIG_EM:
- case SIG_EM_E1:
- case SIG_EMWINK:
- case SIG_FEATD:
- case SIG_FEATDMF:
- case SIG_FEATDMF_TA:
- case SIG_FEATB:
- case SIG_E911:
- case SIG_SF:
- case SIG_SFWINK:
- case SIG_FGC_CAMA:
- case SIG_FGC_CAMAMF:
- case SIG_SF_FEATD:
- case SIG_SF_FEATDMF:
- case SIG_SF_FEATB:
- p.starttime = 250;
- break;
- }
-
- if (tmp->radio) {
- /* XXX Waiting to hear back from Jim if these should be adjustable XXX */
- p.channo = channel;
- p.rxwinktime = 1;
- p.rxflashtime = 1;
- p.starttime = 1;
- p.debouncetime = 5;
- }
- if (!tmp->radio) {
- p.channo = channel;
- /* Override timing settings based on config file */
- if (conf->timing.prewinktime >= 0)
- p.prewinktime = conf->timing.prewinktime;
- if (conf->timing.preflashtime >= 0)
- p.preflashtime = conf->timing.preflashtime;
- if (conf->timing.winktime >= 0)
- p.winktime = conf->timing.winktime;
- if (conf->timing.flashtime >= 0)
- p.flashtime = conf->timing.flashtime;
- if (conf->timing.starttime >= 0)
- p.starttime = conf->timing.starttime;
- if (conf->timing.rxwinktime >= 0)
- p.rxwinktime = conf->timing.rxwinktime;
- if (conf->timing.rxflashtime >= 0)
- p.rxflashtime = conf->timing.rxflashtime;
- if (conf->timing.debouncetime >= 0)
- p.debouncetime = conf->timing.debouncetime;
- }
-
- /* dont set parms on a pseudo-channel (or CRV) */
- if (tmp->subs[SUB_REAL].dfd >= 0)
- {
- res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_SET_PARAMS, &p);
- if (res < 0) {
- ast_log(LOG_ERROR, "Unable to set parameters: %s\n", strerror(errno));
- destroy_dahdi_pvt(&tmp);
- return NULL;
- }
- }
-#if 1
- if (!here && (tmp->subs[SUB_REAL].dfd > -1)) {
- memset(&bi, 0, sizeof(bi));
- res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_BUFINFO, &bi);
- if (!res) {
- bi.txbufpolicy = conf->chan.buf_policy;
- bi.rxbufpolicy = conf->chan.buf_policy;
- bi.numbufs = conf->chan.buf_no;
- res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_SET_BUFINFO, &bi);
- if (res < 0) {
- ast_log(LOG_WARNING, "Unable to set buffer policy on channel %d: %s\n", channel, strerror(errno));
- }
- } else
- ast_log(LOG_WARNING, "Unable to check buffer policy on channel %d: %s\n", channel, strerror(errno));
- }
-#endif
- tmp->immediate = conf->chan.immediate;
- tmp->transfertobusy = conf->chan.transfertobusy;
- tmp->sig = chan_sig;
- tmp->outsigmod = conf->chan.outsigmod;
- tmp->ringt_base = ringt_base;
- tmp->firstradio = 0;
- if ((chan_sig == SIG_FXOKS) || (chan_sig == SIG_FXOLS) || (chan_sig == SIG_FXOGS))
- tmp->permcallwaiting = conf->chan.callwaiting;
- else
- tmp->permcallwaiting = 0;
- /* Flag to destroy the channel must be cleared on new mkif. Part of changes for reload to work */
- tmp->destroy = 0;
- tmp->drings = drings;
- tmp->usedistinctiveringdetection = conf->chan.usedistinctiveringdetection;
- tmp->callwaitingcallerid = conf->chan.callwaitingcallerid;
- tmp->threewaycalling = conf->chan.threewaycalling;
- tmp->adsi = conf->chan.adsi;
- tmp->use_smdi = conf->chan.use_smdi;
- tmp->permhidecallerid = conf->chan.hidecallerid;
- tmp->callreturn = conf->chan.callreturn;
- tmp->echocancel = conf->chan.echocancel;
- tmp->echotraining = conf->chan.echotraining;
- tmp->pulse = conf->chan.pulse;
- if (tmp->echocancel)
- tmp->echocanbridged = conf->chan.echocanbridged;
- else {
- if (conf->chan.echocanbridged)
- ast_log(LOG_NOTICE, "echocancelwhenbridged requires echocancel to be enabled; ignoring\n");
- tmp->echocanbridged = 0;
- }
- tmp->busydetect = conf->chan.busydetect;
- tmp->busycount = conf->chan.busycount;
- tmp->busy_tonelength = conf->chan.busy_tonelength;
- tmp->busy_quietlength = conf->chan.busy_quietlength;
- tmp->callprogress = conf->chan.callprogress;
- tmp->cancallforward = conf->chan.cancallforward;
- tmp->dtmfrelax = conf->chan.dtmfrelax;
- tmp->callwaiting = tmp->permcallwaiting;
- tmp->hidecallerid = tmp->permhidecallerid;
- tmp->channel = channel;
- tmp->stripmsd = conf->chan.stripmsd;
- tmp->use_callerid = conf->chan.use_callerid;
- tmp->cid_signalling = conf->chan.cid_signalling;
- tmp->cid_start = conf->chan.cid_start;
- tmp->dahditrcallerid = conf->chan.dahditrcallerid;
- tmp->restrictcid = conf->chan.restrictcid;
- tmp->use_callingpres = conf->chan.use_callingpres;
- tmp->priindication_oob = conf->chan.priindication_oob;
- tmp->priexclusive = conf->chan.priexclusive;
- if (tmp->usedistinctiveringdetection) {
- if (!tmp->use_callerid) {
- ast_log(LOG_NOTICE, "Distinctive Ring detect requires 'usecallerid' be on\n");
- tmp->use_callerid = 1;
- }
- }
-
- if (tmp->cid_signalling == CID_SIG_SMDI) {
- if (!tmp->use_smdi) {
- ast_log(LOG_WARNING, "SMDI callerid requires SMDI to be enabled, enabling...\n");
- tmp->use_smdi = 1;
- }
- }
- if (tmp->use_smdi) {
- tmp->smdi_iface = ast_smdi_interface_find(conf->smdi_port);
- if (!(tmp->smdi_iface)) {
- ast_log(LOG_ERROR, "Invalid SMDI port specfied, disabling SMDI support\n");
- tmp->use_smdi = 0;
- }
- }
-
- ast_copy_string(tmp->accountcode, conf->chan.accountcode, sizeof(tmp->accountcode));
- tmp->amaflags = conf->chan.amaflags;
- if (!here) {
- tmp->confno = -1;
- tmp->propconfno = -1;
- }
- tmp->canpark = conf->chan.canpark;
- tmp->transfer = conf->chan.transfer;
- ast_copy_string(tmp->defcontext,conf->chan.context,sizeof(tmp->defcontext));
- ast_copy_string(tmp->language, conf->chan.language, sizeof(tmp->language));
- ast_copy_string(tmp->mohinterpret, conf->chan.mohinterpret, sizeof(tmp->mohinterpret));
- ast_copy_string(tmp->mohsuggest, conf->chan.mohsuggest, sizeof(tmp->mohsuggest));
- ast_copy_string(tmp->context, conf->chan.context, sizeof(tmp->context));
- ast_copy_string(tmp->cid_num, conf->chan.cid_num, sizeof(tmp->cid_num));
- tmp->cid_ton = 0;
- ast_copy_string(tmp->cid_name, conf->chan.cid_name, sizeof(tmp->cid_name));
- ast_copy_string(tmp->mailbox, conf->chan.mailbox, sizeof(tmp->mailbox));
- tmp->msgstate = -1;
- tmp->group = conf->chan.group;
- tmp->callgroup = conf->chan.callgroup;
- tmp->pickupgroup= conf->chan.pickupgroup;
- tmp->rxgain = conf->chan.rxgain;
- tmp->txgain = conf->chan.txgain;
- tmp->tonezone = conf->chan.tonezone;
- tmp->onhooktime = time(NULL);
- if (tmp->subs[SUB_REAL].dfd > -1) {
- set_actual_gain(tmp->subs[SUB_REAL].dfd, 0, tmp->rxgain, tmp->txgain, tmp->law);
- if (tmp->dsp)
- ast_dsp_digitmode(tmp->dsp, DSP_DIGITMODE_DTMF | tmp->dtmfrelax);
- update_conf(tmp);
- if (!here) {
- if (chan_sig != SIG_PRI)
- /* Hang it up to be sure it's good */
- dahdi_set_hook(tmp->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
- }
- ioctl(tmp->subs[SUB_REAL].dfd,DAHDI_SETTONEZONE,&tmp->tonezone);
-#ifdef HAVE_PRI
- /* the dchannel is down so put the channel in alarm */
- if (tmp->pri && !pri_is_up(tmp->pri)) {
- tmp->inalarm = 1;
- }
-#endif
- if ((res = get_alarms(tmp)) != DAHDI_ALARM_NONE) {
- tmp->inalarm = 1;
- handle_alarms(tmp, res);
- } else {
- /* yes, this looks strange... the unknown_alarm flag is only used to
- control whether an 'alarm cleared' message gets generated when we
- get an indication that the channel is no longer in alarm status.
- however, the channel *could* be in an alarm status that we aren't
- aware of (since get_alarms() only reports span alarms, not channel
- alarms). setting this flag will cause any potential 'alarm cleared'
- message to be suppressed, but if a real alarm occurs before that
- happens, this flag will get cleared by it and the situation will
- be normal.
- */
- tmp->unknown_alarm = 1;
- }
- }
-
- tmp->polarityonanswerdelay = conf->chan.polarityonanswerdelay;
- tmp->answeronpolarityswitch = conf->chan.answeronpolarityswitch;
- tmp->hanguponpolarityswitch = conf->chan.hanguponpolarityswitch;
- tmp->sendcalleridafter = conf->chan.sendcalleridafter;
-
- }
- if (tmp && !here) {
- /* nothing on the iflist */
- if (!*wlist) {
- *wlist = tmp;
- tmp->prev = NULL;
- tmp->next = NULL;
- *wend = tmp;
- } else {
- /* at least one member on the iflist */
- struct dahdi_pvt *working = *wlist;
-
- /* check if we maybe have to put it on the begining */
- if (working->channel > tmp->channel) {
- tmp->next = *wlist;
- tmp->prev = NULL;
- (*wlist)->prev = tmp;
- *wlist = tmp;
- } else {
- /* go through all the members and put the member in the right place */
- while (working) {
- /* in the middle */
- if (working->next) {
- if (working->channel < tmp->channel && working->next->channel > tmp->channel) {
- tmp->next = working->next;
- tmp->prev = working;
- working->next->prev = tmp;
- working->next = tmp;
- break;
- }
- } else {
- /* the last */
- if (working->channel < tmp->channel) {
- working->next = tmp;
- tmp->next = NULL;
- tmp->prev = working;
- *wend = tmp;
- break;
- }
- }
- working = working->next;
- }
- }
- }
- }
- return tmp;
-}
-
-static inline int available(struct dahdi_pvt *p, int channelmatch, ast_group_t groupmatch, int *busy, int *channelmatched, int *groupmatched)
-{
- int res;
- struct dahdi_params par;
-
- /* First, check group matching */
- if (groupmatch) {
- if ((p->group & groupmatch) != groupmatch)
- return 0;
- *groupmatched = 1;
- }
- /* Check to see if we have a channel match */
- if (channelmatch != -1) {
- if (p->channel != channelmatch)
- return 0;
- *channelmatched = 1;
- }
- /* We're at least busy at this point */
- if (busy) {
- if ((p->sig == SIG_FXOKS) || (p->sig == SIG_FXOLS) || (p->sig == SIG_FXOGS))
- *busy = 1;
- }
- /* If do not disturb, definitely not */
- if (p->dnd)
- return 0;
- /* If guard time, definitely not */
- if (p->guardtime && (time(NULL) < p->guardtime))
- return 0;
-
- /* If no owner definitely available */
- if (!p->owner) {
-#ifdef HAVE_PRI
- /* Trust PRI */
- if (p->pri) {
- if (p->resetting || p->call)
- return 0;
- else
- return 1;
- }
-#endif
- if (!(p->radio || (p->oprmode < 0)))
- {
- if (!p->sig || (p->sig == SIG_FXSLS))
- return 1;
- /* Check hook state */
- if (p->subs[SUB_REAL].dfd > -1)
- res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &par);
- else {
- /* Assume not off hook on CVRS */
- res = 0;
- par.rxisoffhook = 0;
- }
- if (res) {
- ast_log(LOG_WARNING, "Unable to check hook state on channel %d: %s\n", p->channel, strerror(errno));
- } else if ((p->sig == SIG_FXSKS) || (p->sig == SIG_FXSGS)) {
- /* When "onhook" that means no battery on the line, and thus
- it is out of service..., if it's on a TDM card... If it's a channel
- bank, there is no telling... */
- if (par.rxbits > -1)
- return 1;
- if (par.rxisoffhook)
- return 1;
- else
-#ifdef DAHDI_CHECK_HOOKSTATE
- return 0;
-#else
- return 1;
-#endif
- } else if (par.rxisoffhook) {
- ast_log(LOG_DEBUG, "Channel %d off hook, can't use\n", p->channel);
- /* Not available when the other end is off hook */
- return 0;
- }
- }
- return 1;
- }
-
- /* If it's not an FXO, forget about call wait */
- if ((p->sig != SIG_FXOKS) && (p->sig != SIG_FXOLS) && (p->sig != SIG_FXOGS))
- return 0;
-
- if (!p->callwaiting) {
- /* If they don't have call waiting enabled, then for sure they're unavailable at this point */
- return 0;
- }
-
- if (p->subs[SUB_CALLWAIT].dfd > -1) {
- /* If there is already a call waiting call, then we can't take a second one */
- return 0;
- }
-
- if ((p->owner->_state != AST_STATE_UP) &&
- ((p->owner->_state != AST_STATE_RINGING) || p->outgoing)) {
- /* If the current call is not up, then don't allow the call */
- return 0;
- }
- if ((p->subs[SUB_THREEWAY].owner) && (!p->subs[SUB_THREEWAY].inthreeway)) {
- /* Can't take a call wait when the three way calling hasn't been merged yet. */
- return 0;
- }
- /* We're cool */
- return 1;
-}
-
-static struct dahdi_pvt *chandup(struct dahdi_pvt *src)
-{
- struct dahdi_pvt *p;
- struct dahdi_bufferinfo bi;
- int res;
-
- if ((p = ast_malloc(sizeof(*p)))) {
- memcpy(p, src, sizeof(struct dahdi_pvt));
- ast_mutex_init(&p->lock);
- p->subs[SUB_REAL].dfd = dahdi_open(DAHDI_FILE_PSEUDO);
- /* Allocate a DAHDI structure */
- if (p->subs[SUB_REAL].dfd < 0) {
- ast_log(LOG_ERROR, "Unable to dup channel: %s\n", strerror(errno));
- destroy_dahdi_pvt(&p);
- return NULL;
- }
- res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_BUFINFO, &bi);
- if (!res) {
- bi.txbufpolicy = p->buf_policy;
- bi.rxbufpolicy = p->buf_policy;
- bi.numbufs = p->buf_no;
- res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SET_BUFINFO, &bi);
- if (res < 0) {
- ast_log(LOG_WARNING, "Unable to set buffer policy on dup channel: %s\n", strerror(errno));
- }
- } else
- ast_log(LOG_WARNING, "Unable to check buffer policy on dup channel: %s\n", strerror(errno));
- }
- p->destroy = 1;
- p->next = iflist;
- p->prev = NULL;
- iflist = p;
- if (iflist->next)
- iflist->next->prev = p;
- return p;
-}
-
-
-#ifdef HAVE_PRI
-static int pri_find_empty_chan(struct dahdi_pri *pri, int backwards)
-{
- int x;
- if (backwards)
- x = pri->numchans;
- else
- x = 0;
- for (;;) {
- if (backwards && (x < 0))
- break;
- if (!backwards && (x >= pri->numchans))
- break;
- if (pri->pvts[x] && !pri->pvts[x]->inalarm && !pri->pvts[x]->owner) {
- ast_log(LOG_DEBUG, "Found empty available channel %d/%d\n",
- pri->pvts[x]->logicalspan, pri->pvts[x]->prioffset);
- return x;
- }
- if (backwards)
- x--;
- else
- x++;
- }
- return -1;
-}
-#endif
-
-static struct ast_channel *dahdi_request(const char *type, int format, void *data, int *cause)
-{
- ast_group_t groupmatch = 0;
- int channelmatch = -1;
- int roundrobin = 0;
- int callwait = 0;
- int busy = 0;
- struct dahdi_pvt *p;
- struct ast_channel *tmp = NULL;
- char *dest=NULL;
- int x;
- char *s;
- char opt=0;
- int res=0, y=0;
- int backwards = 0;
-#ifdef HAVE_PRI
- int crv;
- int bearer = -1;
- int trunkgroup;
- struct dahdi_pri *pri=NULL;
-#endif
- struct dahdi_pvt *exit, *start, *end;
- ast_mutex_t *lock;
- int channelmatched = 0;
- int groupmatched = 0;
-
- /* Assume we're locking the iflock */
- lock = &iflock;
- start = iflist;
- end = ifend;
- if (data) {
- dest = ast_strdupa((char *)data);
- } else {
- ast_log(LOG_WARNING, "Channel requested with no data\n");
- return NULL;
- }
- if (toupper(dest[0]) == 'G' || toupper(dest[0])=='R') {
- /* Retrieve the group number */
- char *stringp=NULL;
- stringp=dest + 1;
- s = strsep(&stringp, "/");
- if ((res = sscanf(s, "%d%c%d", &x, &opt, &y)) < 1) {
- ast_log(LOG_WARNING, "Unable to determine group for data %s\n", (char *)data);
- return NULL;
- }
- groupmatch = ((ast_group_t) 1 << x);
- if (toupper(dest[0]) == 'G') {
- if (dest[0] == 'G') {
- backwards = 1;
- p = ifend;
- } else
- p = iflist;
- } else {
- if (dest[0] == 'R') {
- backwards = 1;
- p = round_robin[x]?round_robin[x]->prev:ifend;
- if (!p)
- p = ifend;
- } else {
- p = round_robin[x]?round_robin[x]->next:iflist;
- if (!p)
- p = iflist;
- }
- roundrobin = 1;
- }
- } else {
- char *stringp=NULL;
- stringp=dest;
- s = strsep(&stringp, "/");
- p = iflist;
- if (!strcasecmp(s, "pseudo")) {
- /* Special case for pseudo */
- x = CHAN_PSEUDO;
- channelmatch = x;
- }
-#ifdef HAVE_PRI
- else if ((res = sscanf(s, "%d:%d%c%d", &trunkgroup, &crv, &opt, &y)) > 1) {
- if ((trunkgroup < 1) || (crv < 1)) {
- ast_log(LOG_WARNING, "Unable to determine trunk group and CRV for data %s\n", (char *)data);
- return NULL;
- }
- res--;
- for (x = 0; x < NUM_SPANS; x++) {
- if (pris[x].trunkgroup == trunkgroup) {
- pri = pris + x;
- lock = &pri->lock;
- start = pri->crvs;
- end = pri->crvend;
- break;
- }
- }
- if (!pri) {
- ast_log(LOG_WARNING, "Unable to find trunk group %d\n", trunkgroup);
- return NULL;
- }
- channelmatch = crv;
- p = pris[x].crvs;
- }
-#endif
- else if ((res = sscanf(s, "%d%c%d", &x, &opt, &y)) < 1) {
- ast_log(LOG_WARNING, "Unable to determine channel for data %s\n", (char *)data);
- return NULL;
- } else {
- channelmatch = x;
- }
- }
- /* Search for an unowned channel */
- ast_mutex_lock(lock);
- exit = p;
- while (p && !tmp) {
- if (roundrobin)
- round_robin[x] = p;
-#if 0
- ast_verbose("name = %s, %d, %d, %d\n",p->owner ? p->owner->name : "<none>", p->channel, channelmatch, groupmatch);
-#endif
-
- if (p && available(p, channelmatch, groupmatch, &busy, &channelmatched, &groupmatched)) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Using channel %d\n", p->channel);
- if (p->inalarm)
- goto next;
-
- callwait = (p->owner != NULL);
-#ifdef HAVE_PRI
- if (pri && (p->subs[SUB_REAL].dfd < 0)) {
- if (p->sig != SIG_FXSKS) {
- /* Gotta find an actual channel to use for this
- CRV if this isn't a callwait */
- bearer = pri_find_empty_chan(pri, 0);
- if (bearer < 0) {
- ast_log(LOG_NOTICE, "Out of bearer channels on span %d for call to CRV %d:%d\n", pri->span, trunkgroup, crv);
- p = NULL;
- break;
- }
- pri_assign_bearer(p, pri, pri->pvts[bearer]);
- } else {
- if (alloc_sub(p, 0)) {
- ast_log(LOG_NOTICE, "Failed to allocate place holder pseudo channel!\n");
- p = NULL;
- break;
- } else
- ast_log(LOG_DEBUG, "Allocated placeholder pseudo channel\n");
- p->pri = pri;
- }
- }
-#endif
- if (p->channel == CHAN_PSEUDO) {
- p = chandup(p);
- if (!p) {
- break;
- }
- }
- if (p->owner) {
- if (alloc_sub(p, SUB_CALLWAIT)) {
- p = NULL;
- break;
- }
- }
- p->outgoing = 1;
- tmp = dahdi_new(p, AST_STATE_RESERVED, 0, p->owner ? SUB_CALLWAIT : SUB_REAL, 0, 0);
-#ifdef HAVE_PRI
- if (p->bearer) {
- /* Log owner to bearer channel, too */
- p->bearer->owner = tmp;
- }
-#endif
- /* Make special notes */
- if (res > 1) {
- if (opt == 'c') {
- /* Confirm answer */
- p->confirmanswer = 1;
- } else if (opt == 'r') {
- /* Distinctive ring */
- if (res < 3)
- ast_log(LOG_WARNING, "Distinctive ring missing identifier in '%s'\n", (char *)data);
- else
- p->distinctivering = y;
- } else if (opt == 'd') {
- /* If this is an ISDN call, make it digital */
- p->digital = 1;
- if (tmp)
- tmp->transfercapability = AST_TRANS_CAP_DIGITAL;
- } else {
- ast_log(LOG_WARNING, "Unknown option '%c' in '%s'\n", opt, (char *)data);
- }
- }
- /* Note if the call is a call waiting call */
- if (tmp && callwait)
- tmp->cdrflags |= AST_CDR_CALLWAIT;
- break;
- }
-next:
- if (backwards) {
- p = p->prev;
- if (!p)
- p = end;
- } else {
- p = p->next;
- if (!p)
- p = start;
- }
- /* stop when you roll to the one that we started from */
- if (p == exit)
- break;
- }
- ast_mutex_unlock(lock);
- restart_monitor();
- if (callwait)
- *cause = AST_CAUSE_BUSY;
- else if (!tmp) {
- if (channelmatched) {
- if (busy)
- *cause = AST_CAUSE_BUSY;
- } else if (groupmatched) {
- *cause = AST_CAUSE_CONGESTION;
- }
- }
-
- return tmp;
-}
-
-
-#ifdef HAVE_PRI
-static struct dahdi_pvt *pri_find_crv(struct dahdi_pri *pri, int crv)
-{
- struct dahdi_pvt *p;
- p = pri->crvs;
- while (p) {
- if (p->channel == crv)
- return p;
- p = p->next;
- }
- return NULL;
-}
-
-
-static int pri_find_principle(struct dahdi_pri *pri, int channel)
-{
- int x;
- int span = PRI_SPAN(channel);
- int spanfd;
- struct dahdi_params param;
- int principle = -1;
- int explicit = PRI_EXPLICIT(channel);
- channel = PRI_CHANNEL(channel);
-
- if (!explicit) {
- spanfd = pri_active_dchan_fd(pri);
- if (ioctl(spanfd, DAHDI_GET_PARAMS, &param))
- return -1;
- span = pris[param.spanno - 1].prilogicalspan;
- }
-
- for (x = 0; x < pri->numchans; x++) {
- if (pri->pvts[x] && (pri->pvts[x]->prioffset == channel) && (pri->pvts[x]->logicalspan == span)) {
- principle = x;
- break;
- }
- }
-
- return principle;
-}
-
-static int pri_fixup_principle(struct dahdi_pri *pri, int principle, q931_call *c)
-{
- int x;
- struct dahdi_pvt *crv;
- if (!c) {
- if (principle < 0)
- return -1;
- return principle;
- }
- if ((principle > -1) &&
- (principle < pri->numchans) &&
- (pri->pvts[principle]) &&
- (pri->pvts[principle]->call == c))
- return principle;
- /* First, check for other bearers */
- for (x = 0; x < pri->numchans; x++) {
- if (!pri->pvts[x])
- continue;
- if (pri->pvts[x]->call == c) {
- /* Found our call */
- if (principle != x) {
- struct dahdi_pvt *new = pri->pvts[principle], *old = pri->pvts[x];
-
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Moving call from channel %d to channel %d\n",
- old->channel, new->channel);
- if (new->owner) {
- ast_log(LOG_WARNING, "Can't fix up channel from %d to %d because %d is already in use\n",
- old->channel, new->channel, new->channel);
- return -1;
- }
- /* Fix it all up now */
- new->owner = old->owner;
- old->owner = NULL;
- if (new->owner) {
- ast_string_field_build(new->owner, name, "%s/%d:%d-%d", dahdi_chan_name, pri->trunkgroup, new->channel, 1);
- new->owner->tech_pvt = new;
- new->owner->fds[0] = new->subs[SUB_REAL].dfd;
- new->subs[SUB_REAL].owner = old->subs[SUB_REAL].owner;
- old->subs[SUB_REAL].owner = NULL;
- } else
- ast_log(LOG_WARNING, "Whoa, there's no owner, and we're having to fix up channel %d to channel %d\n", old->channel, new->channel);
- new->call = old->call;
- old->call = NULL;
-
- /* Copy any DSP that may be present */
- new->dsp = old->dsp;
- new->dsp_features = old->dsp_features;
- old->dsp = NULL;
- old->dsp_features = 0;
- }
- return principle;
- }
- }
- /* Now check for a CRV with no bearer */
- crv = pri->crvs;
- while (crv) {
- if (crv->call == c) {
- /* This is our match... Perform some basic checks */
- if (crv->bearer)
- ast_log(LOG_WARNING, "Trying to fix up call which already has a bearer which isn't the one we think it is\n");
- else if (pri->pvts[principle]->owner)
- ast_log(LOG_WARNING, "Tring to fix up a call to a bearer which already has an owner!\n");
- else {
- /* Looks good. Drop the pseudo channel now, clear up the assignment, and
- wakeup the potential sleeper */
- dahdi_close_sub(crv, SUB_REAL);
- pri->pvts[principle]->call = crv->call;
- pri_assign_bearer(crv, pri, pri->pvts[principle]);
- ast_log(LOG_DEBUG, "Assigning bearer %d/%d to CRV %d:%d\n",
- pri->pvts[principle]->logicalspan, pri->pvts[principle]->prioffset,
- pri->trunkgroup, crv->channel);
- wakeup_sub(crv, SUB_REAL, pri);
- }
- return principle;
- }
- crv = crv->next;
- }
- ast_log(LOG_WARNING, "Call specified, but not found?\n");
- return -1;
-}
-
-static void *do_idle_thread(void *vchan)
-{
- struct ast_channel *chan = vchan;
- struct dahdi_pvt *pvt = chan->tech_pvt;
- struct ast_frame *f;
- char ex[80];
- /* Wait up to 30 seconds for an answer */
- int newms, ms = 30000;
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Initiating idle call on channel %s\n", chan->name);
- snprintf(ex, sizeof(ex), "%d/%s", pvt->channel, pvt->pri->idledial);
- if (ast_call(chan, ex, 0)) {
- ast_log(LOG_WARNING, "Idle dial failed on '%s' to '%s'\n", chan->name, ex);
- ast_hangup(chan);
- return NULL;
- }
- while ((newms = ast_waitfor(chan, ms)) > 0) {
- f = ast_read(chan);
- if (!f) {
- /* Got hangup */
- break;
- }
- if (f->frametype == AST_FRAME_CONTROL) {
- switch (f->subclass) {
- case AST_CONTROL_ANSWER:
- /* Launch the PBX */
- ast_copy_string(chan->exten, pvt->pri->idleext, sizeof(chan->exten));
- ast_copy_string(chan->context, pvt->pri->idlecontext, sizeof(chan->context));
- chan->priority = 1;
- if (option_verbose > 3)
- ast_verbose(VERBOSE_PREFIX_3 "Idle channel '%s' answered, sending to %s@%s\n", chan->name, chan->exten, chan->context);
- ast_pbx_run(chan);
- /* It's already hungup, return immediately */
- return NULL;
- case AST_CONTROL_BUSY:
- if (option_verbose > 3)
- ast_verbose(VERBOSE_PREFIX_3 "Idle channel '%s' busy, waiting...\n", chan->name);
- break;
- case AST_CONTROL_CONGESTION:
- if (option_verbose > 3)
- ast_verbose(VERBOSE_PREFIX_3 "Idle channel '%s' congested, waiting...\n", chan->name);
- break;
- };
- }
- ast_frfree(f);
- ms = newms;
- }
- /* Hangup the channel since nothing happend */
- ast_hangup(chan);
- return NULL;
-}
-
-#ifndef PRI_RESTART
-#error "Upgrade your libpri"
-#endif
-static void dahdi_pri_message(struct pri *pri, char *s)
-{
- int x, y;
- int dchan = -1, span = -1;
- int dchancount = 0;
-
- if (pri) {
- for (x = 0; x < NUM_SPANS; x++) {
- for (y = 0; y < NUM_DCHANS; y++) {
- if (pris[x].dchans[y])
- dchancount++;
-
- if (pris[x].dchans[y] == pri)
- dchan = y;
- }
- if (dchan >= 0) {
- span = x;
- break;
- }
- dchancount = 0;
- }
- if ((dchan >= 0) && (span >= 0)) {
- if (dchancount > 1)
- ast_verbose("[Span %d D-Channel %d]%s", span, dchan, s);
- else
- ast_verbose("%s", s);
- } else
- ast_log(LOG_ERROR, "PRI debug error: could not find pri associated it with debug message output\n");
- } else
- ast_verbose("%s", s);
-
- ast_mutex_lock(&pridebugfdlock);
-
- if (pridebugfd >= 0) {
- if (write(pridebugfd, s, strlen(s)) < 0) {
- ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
- }
- }
-
- ast_mutex_unlock(&pridebugfdlock);
-}
-
-static void dahdi_pri_error(struct pri *pri, char *s)
-{
- int x, y;
- int dchan = -1, span = -1;
- int dchancount = 0;
-
- if (pri) {
- for (x = 0; x < NUM_SPANS; x++) {
- for (y = 0; y < NUM_DCHANS; y++) {
- if (pris[x].dchans[y])
- dchancount++;
-
- if (pris[x].dchans[y] == pri)
- dchan = y;
- }
- if (dchan >= 0) {
- span = x;
- break;
- }
- dchancount = 0;
- }
- if ((dchan >= 0) && (span >= 0)) {
- if (dchancount > 1)
- ast_log(LOG_ERROR, "[Span %d D-Channel %d] PRI: %s", span, dchan, s);
- else
- ast_log(LOG_ERROR, "%s", s);
- } else
- ast_log(LOG_ERROR, "PRI debug error: could not find pri associated it with debug message output\n");
- } else
- ast_log(LOG_ERROR, "%s", s);
-
- ast_mutex_lock(&pridebugfdlock);
-
- if (pridebugfd >= 0) {
- if (write(pridebugfd, s, strlen(s)) < 0) {
- ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
- }
- }
-
- ast_mutex_unlock(&pridebugfdlock);
-}
-
-static int pri_check_restart(struct dahdi_pri *pri)
-{
- do {
- pri->resetpos++;
- } while ((pri->resetpos < pri->numchans) &&
- (!pri->pvts[pri->resetpos] ||
- pri->pvts[pri->resetpos]->call ||
- pri->pvts[pri->resetpos]->resetting));
- if (pri->resetpos < pri->numchans) {
- /* Mark the channel as resetting and restart it */
- pri->pvts[pri->resetpos]->resetting = 1;
- pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[pri->resetpos]));
- } else {
- pri->resetting = 0;
- time(&pri->lastreset);
- }
- return 0;
-}
-
-static int pri_hangup_all(struct dahdi_pvt *p, struct dahdi_pri *pri)
-{
- int x;
- int redo;
- ast_mutex_unlock(&pri->lock);
- ast_mutex_lock(&p->lock);
- do {
- redo = 0;
- for (x = 0; x < 3; x++) {
- while (p->subs[x].owner && ast_mutex_trylock(&p->subs[x].owner->lock)) {
- redo++;
- DEADLOCK_AVOIDANCE(&p->lock);
- }
- if (p->subs[x].owner) {
- ast_queue_hangup(p->subs[x].owner);
- ast_mutex_unlock(&p->subs[x].owner->lock);
- }
- }
- } while (redo);
- ast_mutex_unlock(&p->lock);
- ast_mutex_lock(&pri->lock);
- return 0;
-}
-
-static char * redirectingreason2str(int redirectingreason)
-{
- switch (redirectingreason) {
- case 0:
- return "UNKNOWN";
- case 1:
- return "BUSY";
- case 2:
- return "NO_REPLY";
- case 0xF:
- return "UNCONDITIONAL";
- default:
- return "NOREDIRECT";
- }
-}
-
-static void apply_plan_to_number(char *buf, size_t size, const struct dahdi_pri *pri, const char *number, const int plan)
-{
- switch (plan) {
- case PRI_INTERNATIONAL_ISDN: /* Q.931 dialplan == 0x11 international dialplan => prepend international prefix digits */
- snprintf(buf, size, "%s%s", pri->internationalprefix, number);
- break;
- case PRI_NATIONAL_ISDN: /* Q.931 dialplan == 0x21 national dialplan => prepend national prefix digits */
- snprintf(buf, size, "%s%s", pri->nationalprefix, number);
- break;
- case PRI_LOCAL_ISDN: /* Q.931 dialplan == 0x41 local dialplan => prepend local prefix digits */
- snprintf(buf, size, "%s%s", pri->localprefix, number);
- break;
- case PRI_PRIVATE: /* Q.931 dialplan == 0x49 private dialplan => prepend private prefix digits */
- snprintf(buf, size, "%s%s", pri->privateprefix, number);
- break;
- case PRI_UNKNOWN: /* Q.931 dialplan == 0x00 unknown dialplan => prepend unknown prefix digits */
- snprintf(buf, size, "%s%s", pri->unknownprefix, number);
- break;
- default: /* other Q.931 dialplan => don't twiddle with callingnum */
- snprintf(buf, size, "%s", number);
- break;
- }
-}
-
-static int dahdi_setlaw(int dfd, int law)
-{
- int res;
- res = ioctl(dfd, DAHDI_SETLAW, &law);
- if (res)
- return res;
- return 0;
-}
-
-static void *pri_dchannel(void *vpri)
-{
- struct dahdi_pri *pri = vpri;
- pri_event *e;
- struct pollfd fds[NUM_DCHANS];
- int res;
- int chanpos = 0;
- int x;
- int haveidles;
- int activeidles;
- int nextidle = -1;
- struct ast_channel *c;
- struct timeval tv, lowest, *next;
- struct timeval lastidle = { 0, 0 };
- int doidling=0;
- char *cc;
- char idlen[80];
- struct ast_channel *idle;
- pthread_t p;
- time_t t;
- int i, which=-1;
- int numdchans;
- int cause=0;
- struct dahdi_pvt *crv;
- pthread_t threadid;
- pthread_attr_t attr;
- char ani2str[6];
- char plancallingnum[256];
- char plancallingani[256];
- char calledtonstr[10];
-
- pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
-
- gettimeofday(&lastidle, NULL);
- if (!ast_strlen_zero(pri->idledial) && !ast_strlen_zero(pri->idleext)) {
- /* Need to do idle dialing, check to be sure though */
- cc = strchr(pri->idleext, '@');
- if (cc) {
- *cc = '\0';
- cc++;
- ast_copy_string(pri->idlecontext, cc, sizeof(pri->idlecontext));
-#if 0
- /* Extensions may not be loaded yet */
- if (!ast_exists_extension(NULL, pri->idlecontext, pri->idleext, 1, NULL))
- ast_log(LOG_WARNING, "Extension '%s @ %s' does not exist\n", pri->idleext, pri->idlecontext);
- else
-#endif
- doidling = 1;
- } else
- ast_log(LOG_WARNING, "Idle dial string '%s' lacks '@context'\n", pri->idleext);
- }
- for (;;) {
- for (i = 0; i < NUM_DCHANS; i++) {
- if (!pri->dchannels[i])
- break;
- fds[i].fd = pri->fds[i];
- fds[i].events = POLLIN | POLLPRI;
- fds[i].revents = 0;
- }
- numdchans = i;
- time(&t);
- ast_mutex_lock(&pri->lock);
- if (pri->switchtype != PRI_SWITCH_GR303_TMC && (pri->resetinterval > 0)) {
- if (pri->resetting && pri_is_up(pri)) {
- if (pri->resetpos < 0)
- pri_check_restart(pri);
- } else {
- if (!pri->resetting && (t - pri->lastreset) >= pri->resetinterval) {
- pri->resetting = 1;
- pri->resetpos = -1;
- }
- }
- }
- /* Look for any idle channels if appropriate */
- if (doidling && pri_is_up(pri)) {
- nextidle = -1;
- haveidles = 0;
- activeidles = 0;
- for (x = pri->numchans; x >= 0; x--) {
- if (pri->pvts[x] && !pri->pvts[x]->owner &&
- !pri->pvts[x]->call) {
- if (haveidles < pri->minunused) {
- haveidles++;
- } else if (!pri->pvts[x]->resetting) {
- nextidle = x;
- break;
- }
- } else if (pri->pvts[x] && pri->pvts[x]->owner && pri->pvts[x]->isidlecall)
- activeidles++;
- }
- if (nextidle > -1) {
- if (ast_tvdiff_ms(ast_tvnow(), lastidle) > 1000) {
- /* Don't create a new idle call more than once per second */
- snprintf(idlen, sizeof(idlen), "%d/%s", pri->pvts[nextidle]->channel, pri->idledial);
- idle = dahdi_request(dahdi_chan_name, AST_FORMAT_ULAW, idlen, &cause);
- if (idle) {
- pri->pvts[nextidle]->isidlecall = 1;
- if (ast_pthread_create_background(&p, NULL, do_idle_thread, idle)) {
- ast_log(LOG_WARNING, "Unable to start new thread for idle channel '%s'\n", idle->name);
- dahdi_hangup(idle);
- }
- } else
- ast_log(LOG_WARNING, "Unable to request channel 'DAHDI/%s' for idle call\n", idlen);
- gettimeofday(&lastidle, NULL);
- }
- } else if ((haveidles < pri->minunused) &&
- (activeidles > pri->minidle)) {
- /* Mark something for hangup if there is something
- that can be hungup */
- for (x = pri->numchans; x >= 0; x--) {
- /* find a candidate channel */
- if (pri->pvts[x] && pri->pvts[x]->owner && pri->pvts[x]->isidlecall) {
- pri->pvts[x]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
- haveidles++;
- /* Stop if we have enough idle channels or
- can't spare any more active idle ones */
- if ((haveidles >= pri->minunused) ||
- (activeidles <= pri->minidle))
- break;
- }
- }
- }
- }
- /* Start with reasonable max */
- lowest = ast_tv(60, 0);
- for (i = 0; i < NUM_DCHANS; i++) {
- /* Find lowest available d-channel */
- if (!pri->dchannels[i])
- break;
- if ((next = pri_schedule_next(pri->dchans[i]))) {
- /* We need relative time here */
- tv = ast_tvsub(*next, ast_tvnow());
- if (tv.tv_sec < 0) {
- tv = ast_tv(0,0);
- }
- if (doidling || pri->resetting) {
- if (tv.tv_sec > 1) {
- tv = ast_tv(1, 0);
- }
- } else {
- if (tv.tv_sec > 60) {
- tv = ast_tv(60, 0);
- }
- }
- } else if (doidling || pri->resetting) {
- /* Make sure we stop at least once per second if we're
- monitoring idle channels */
- tv = ast_tv(1,0);
- } else {
- /* Don't poll for more than 60 seconds */
- tv = ast_tv(60, 0);
- }
- if (!i || ast_tvcmp(tv, lowest) < 0) {
- lowest = tv;
- }
- }
- ast_mutex_unlock(&pri->lock);
-
- pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
- pthread_testcancel();
- e = NULL;
- res = poll(fds, numdchans, lowest.tv_sec * 1000 + lowest.tv_usec / 1000);
- pthread_testcancel();
- pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
-
- ast_mutex_lock(&pri->lock);
- if (!res) {
- for (which = 0; which < NUM_DCHANS; which++) {
- if (!pri->dchans[which])
- break;
- /* Just a timeout, run the scheduler */
- e = pri_schedule_run(pri->dchans[which]);
- if (e)
- break;
- }
- } else if (res > -1) {
- for (which = 0; which < NUM_DCHANS; which++) {
- if (!pri->dchans[which])
- break;
- if (fds[which].revents & POLLPRI) {
- /* Check for an event */
- x = 0;
- res = ioctl(pri->fds[which], DAHDI_GETEVENT, &x);
- if (x)
- ast_log(LOG_NOTICE, "PRI got event: %s (%d) on %s D-channel of span %d\n", event2str(x), x, pri_order(which), pri->span);
- /* Keep track of alarm state */
- if (x == DAHDI_EVENT_ALARM) {
- pri->dchanavail[which] &= ~(DCHAN_NOTINALARM | DCHAN_UP);
- pri_find_dchan(pri);
- } else if (x == DAHDI_EVENT_NOALARM) {
- pri->dchanavail[which] |= DCHAN_NOTINALARM;
- pri_restart(pri->dchans[which]);
- }
-
- if (option_debug)
- ast_log(LOG_DEBUG, "Got event %s (%d) on D-channel for span %d\n", event2str(x), x, pri->span);
- } else if (fds[which].revents & POLLIN) {
- e = pri_check_event(pri->dchans[which]);
- }
- if (e)
- break;
- }
- } else if (errno != EINTR)
- ast_log(LOG_WARNING, "pri_event returned error %d (%s)\n", errno, strerror(errno));
-
- if (e) {
- if (pri->debug)
- pri_dump_event(pri->dchans[which], e);
-
- if (e->e != PRI_EVENT_DCHAN_DOWN) {
- if (!(pri->dchanavail[which] & DCHAN_UP)) {
- if (option_verbose > 1)
- ast_verbose(VERBOSE_PREFIX_2 "%s D-Channel on span %d up\n", pri_order(which), pri->span);
- }
- pri->dchanavail[which] |= DCHAN_UP;
- } else {
- if (pri->dchanavail[which] & DCHAN_UP) {
- if (option_verbose > 1)
- ast_verbose(VERBOSE_PREFIX_2 "%s D-Channel on span %d down\n", pri_order(which), pri->span);
- }
- pri->dchanavail[which] &= ~DCHAN_UP;
- }
-
- if ((e->e != PRI_EVENT_DCHAN_UP) && (e->e != PRI_EVENT_DCHAN_DOWN) && (pri->pri != pri->dchans[which]))
- /* Must be an NFAS group that has the secondary dchan active */
- pri->pri = pri->dchans[which];
-
- switch (e->e) {
- case PRI_EVENT_DCHAN_UP:
- if (!pri->pri) pri_find_dchan(pri);
-
- /* Note presense of D-channel */
- time(&pri->lastreset);
-
- /* Restart in 5 seconds */
- if (pri->resetinterval > -1) {
- pri->lastreset -= pri->resetinterval;
- pri->lastreset += 5;
- }
- pri->resetting = 0;
- /* Take the channels from inalarm condition */
- for (i = 0; i < pri->numchans; i++)
- if (pri->pvts[i]) {
- pri->pvts[i]->inalarm = 0;
- }
- break;
- case PRI_EVENT_DCHAN_DOWN:
- pri_find_dchan(pri);
- if (!pri_is_up(pri)) {
- pri->resetting = 0;
- /* Hangup active channels and put them in alarm mode */
- for (i = 0; i < pri->numchans; i++) {
- struct dahdi_pvt *p = pri->pvts[i];
- if (p) {
- if (!p->pri || !p->pri->pri || pri_get_timer(p->pri->pri, PRI_TIMER_T309) < 0) {
- /* T309 is not enabled : hangup calls when alarm occurs */
- if (p->call) {
- if (p->pri && p->pri->pri) {
- pri_hangup(p->pri->pri, p->call, -1);
- pri_destroycall(p->pri->pri, p->call);
- p->call = NULL;
- } else
- ast_log(LOG_WARNING, "The PRI Call have not been destroyed\n");
- }
- if (p->realcall) {
- pri_hangup_all(p->realcall, pri);
- } else if (p->owner)
- p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
- }
- p->inalarm = 1;
- }
- }
- }
- break;
- case PRI_EVENT_RESTART:
- if (e->restart.channel > -1) {
- chanpos = pri_find_principle(pri, e->restart.channel);
- if (chanpos < 0)
- ast_log(LOG_WARNING, "Restart requested on odd/unavailable channel number %d/%d on span %d\n",
- PRI_SPAN(e->restart.channel), PRI_CHANNEL(e->restart.channel), pri->span);
- else {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "B-channel %d/%d restarted on span %d\n",
- PRI_SPAN(e->restart.channel), PRI_CHANNEL(e->restart.channel), pri->span);
- ast_mutex_lock(&pri->pvts[chanpos]->lock);
- if (pri->pvts[chanpos]->call) {
- pri_destroycall(pri->pri, pri->pvts[chanpos]->call);
- pri->pvts[chanpos]->call = NULL;
- }
- /* Force soft hangup if appropriate */
- if (pri->pvts[chanpos]->realcall)
- pri_hangup_all(pri->pvts[chanpos]->realcall, pri);
- else if (pri->pvts[chanpos]->owner)
- pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
- ast_mutex_unlock(&pri->pvts[chanpos]->lock);
- }
- } else {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_2 "Restart on requested on entire span %d\n", pri->span);
- for (x = 0; x < pri->numchans; x++)
- if (pri->pvts[x]) {
- ast_mutex_lock(&pri->pvts[x]->lock);
- if (pri->pvts[x]->call) {
- pri_destroycall(pri->pri, pri->pvts[x]->call);
- pri->pvts[x]->call = NULL;
- }
- if (pri->pvts[chanpos]->realcall)
- pri_hangup_all(pri->pvts[chanpos]->realcall, pri);
- else if (pri->pvts[x]->owner)
- pri->pvts[x]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
- ast_mutex_unlock(&pri->pvts[x]->lock);
- }
- }
- break;
- case PRI_EVENT_KEYPAD_DIGIT:
- chanpos = pri_find_principle(pri, e->digit.channel);
- if (chanpos < 0) {
- ast_log(LOG_WARNING, "KEYPAD_DIGITs received on unconfigured channel %d/%d span %d\n",
- PRI_SPAN(e->digit.channel), PRI_CHANNEL(e->digit.channel), pri->span);
- } else {
- chanpos = pri_fixup_principle(pri, chanpos, e->digit.call);
- if (chanpos > -1) {
- ast_mutex_lock(&pri->pvts[chanpos]->lock);
- /* queue DTMF frame if the PBX for this call was already started (we're forwarding KEYPAD_DIGITs further on */
- if (pri->overlapdial && pri->pvts[chanpos]->call==e->digit.call && pri->pvts[chanpos]->owner) {
- /* how to do that */
- int digitlen = strlen(e->digit.digits);
- char digit;
- int i;
- for (i = 0; i < digitlen; i++) {
- digit = e->digit.digits[i];
- {
- struct ast_frame f = { AST_FRAME_DTMF, digit, };
- dahdi_queue_frame(pri->pvts[chanpos], &f, pri);
- }
- }
- }
- ast_mutex_unlock(&pri->pvts[chanpos]->lock);
- }
- }
- break;
-
- case PRI_EVENT_INFO_RECEIVED:
- chanpos = pri_find_principle(pri, e->ring.channel);
- if (chanpos < 0) {
- ast_log(LOG_WARNING, "INFO received on unconfigured channel %d/%d span %d\n",
- PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
- } else {
- chanpos = pri_fixup_principle(pri, chanpos, e->ring.call);
- if (chanpos > -1) {
- ast_mutex_lock(&pri->pvts[chanpos]->lock);
- /* queue DTMF frame if the PBX for this call was already started (we're forwarding INFORMATION further on */
- if (pri->overlapdial && pri->pvts[chanpos]->call==e->ring.call && pri->pvts[chanpos]->owner) {
- /* how to do that */
- int digitlen = strlen(e->ring.callednum);
- char digit;
- int i;
- for (i = 0; i < digitlen; i++) {
- digit = e->ring.callednum[i];
- {
- struct ast_frame f = { AST_FRAME_DTMF, digit, };
- dahdi_queue_frame(pri->pvts[chanpos], &f, pri);
- }
- }
- }
- ast_mutex_unlock(&pri->pvts[chanpos]->lock);
- }
- }
- break;
- case PRI_EVENT_RING:
- crv = NULL;
- if (e->ring.channel == -1)
- chanpos = pri_find_empty_chan(pri, 1);
- else
- chanpos = pri_find_principle(pri, e->ring.channel);
- /* if no channel specified find one empty */
- if (chanpos < 0) {
- ast_log(LOG_WARNING, "Ring requested on unconfigured channel %d/%d span %d\n",
- PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
- } else {
- ast_mutex_lock(&pri->pvts[chanpos]->lock);
- if (pri->pvts[chanpos]->owner) {
- if (pri->pvts[chanpos]->call == e->ring.call) {
- ast_log(LOG_WARNING, "Duplicate setup requested on channel %d/%d already in use on span %d\n",
- PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
- break;
- } else {
- /* This is where we handle initial glare */
- ast_log(LOG_DEBUG, "Ring requested on channel %d/%d already in use or previously requested on span %d. Attempting to renegotiating channel.\n",
- PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
- ast_mutex_unlock(&pri->pvts[chanpos]->lock);
- chanpos = -1;
- }
- }
- if (chanpos > -1)
- ast_mutex_unlock(&pri->pvts[chanpos]->lock);
- }
- if ((chanpos < 0) && (e->ring.flexible))
- chanpos = pri_find_empty_chan(pri, 1);
- if (chanpos > -1) {
- ast_mutex_lock(&pri->pvts[chanpos]->lock);
- if (pri->switchtype == PRI_SWITCH_GR303_TMC) {
- /* Should be safe to lock CRV AFAIK while bearer is still locked */
- crv = pri_find_crv(pri, pri_get_crv(pri->pri, e->ring.call, NULL));
- if (crv)
- ast_mutex_lock(&crv->lock);
- if (!crv || crv->owner) {
- pri->pvts[chanpos]->call = NULL;
- if (crv) {
- if (crv->owner)
- crv->owner->_softhangup |= AST_SOFTHANGUP_DEV;
- ast_log(LOG_WARNING, "Call received for busy CRV %d on span %d\n", pri_get_crv(pri->pri, e->ring.call, NULL), pri->span);
- } else
- ast_log(LOG_NOTICE, "Call received for unconfigured CRV %d on span %d\n", pri_get_crv(pri->pri, e->ring.call, NULL), pri->span);
- pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_INVALID_CALL_REFERENCE);
- if (crv)
- ast_mutex_unlock(&crv->lock);
- ast_mutex_unlock(&pri->pvts[chanpos]->lock);
- break;
- }
- }
- pri->pvts[chanpos]->call = e->ring.call;
- apply_plan_to_number(plancallingnum, sizeof(plancallingnum), pri, e->ring.callingnum, e->ring.callingplan);
- if (pri->pvts[chanpos]->use_callerid) {
- ast_shrink_phone_number(plancallingnum);
- ast_copy_string(pri->pvts[chanpos]->cid_num, plancallingnum, sizeof(pri->pvts[chanpos]->cid_num));
-#ifdef PRI_ANI
- if (!ast_strlen_zero(e->ring.callingani)) {
- apply_plan_to_number(plancallingani, sizeof(plancallingani), pri, e->ring.callingani, e->ring.callingplanani);
- ast_shrink_phone_number(plancallingani);
- ast_copy_string(pri->pvts[chanpos]->cid_ani, plancallingani, sizeof(pri->pvts[chanpos]->cid_ani));
- } else {
- pri->pvts[chanpos]->cid_ani[0] = '\0';
- }
-#endif
- ast_copy_string(pri->pvts[chanpos]->cid_name, e->ring.callingname, sizeof(pri->pvts[chanpos]->cid_name));
- pri->pvts[chanpos]->cid_ton = e->ring.callingplan; /* this is the callingplan (TON/NPI), e->ring.callingplan>>4 would be the TON */
- } else {
- pri->pvts[chanpos]->cid_num[0] = '\0';
- pri->pvts[chanpos]->cid_ani[0] = '\0';
- pri->pvts[chanpos]->cid_name[0] = '\0';
- pri->pvts[chanpos]->cid_ton = 0;
- }
- apply_plan_to_number(pri->pvts[chanpos]->rdnis, sizeof(pri->pvts[chanpos]->rdnis), pri,
- e->ring.redirectingnum, e->ring.callingplanrdnis);
- /* If immediate=yes go to s|1 */
- if (pri->pvts[chanpos]->immediate) {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Going to extension s|1 because of immediate=yes\n");
- pri->pvts[chanpos]->exten[0] = 's';
- pri->pvts[chanpos]->exten[1] = '\0';
- }
- /* Get called number */
- else if (!ast_strlen_zero(e->ring.callednum)) {
- ast_copy_string(pri->pvts[chanpos]->exten, e->ring.callednum, sizeof(pri->pvts[chanpos]->exten));
- ast_copy_string(pri->pvts[chanpos]->dnid, e->ring.callednum, sizeof(pri->pvts[chanpos]->dnid));
- } else if (pri->overlapdial)
- pri->pvts[chanpos]->exten[0] = '\0';
- else {
- /* Some PRI circuits are set up to send _no_ digits. Handle them as 's'. */
- pri->pvts[chanpos]->exten[0] = 's';
- pri->pvts[chanpos]->exten[1] = '\0';
- }
- /* Set DNID on all incoming calls -- even immediate */
- if (!ast_strlen_zero(e->ring.callednum))
- ast_copy_string(pri->pvts[chanpos]->dnid, e->ring.callednum, sizeof(pri->pvts[chanpos]->dnid));
- /* No number yet, but received "sending complete"? */
- if (e->ring.complete && (ast_strlen_zero(e->ring.callednum))) {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Going to extension s|1 because of Complete received\n");
- pri->pvts[chanpos]->exten[0] = 's';
- pri->pvts[chanpos]->exten[1] = '\0';
- }
- /* Make sure extension exists (or in overlap dial mode, can exist) */
- if ((pri->overlapdial && ast_canmatch_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) ||
- ast_exists_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) {
- /* Setup law */
- int law;
- if (pri->switchtype != PRI_SWITCH_GR303_TMC) {
- /* Set to audio mode at this point */
- law = 1;
- if (ioctl(pri->pvts[chanpos]->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &law) == -1)
- ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d: %s\n", pri->pvts[chanpos]->channel, law, strerror(errno));
- }
- if (e->ring.layer1 == PRI_LAYER_1_ALAW)
- law = DAHDI_LAW_ALAW;
- else
- law = DAHDI_LAW_MULAW;
- res = dahdi_setlaw(pri->pvts[chanpos]->subs[SUB_REAL].dfd, law);
- if (res < 0)
- ast_log(LOG_WARNING, "Unable to set law on channel %d\n", pri->pvts[chanpos]->channel);
- res = set_actual_gain(pri->pvts[chanpos]->subs[SUB_REAL].dfd, 0, pri->pvts[chanpos]->rxgain, pri->pvts[chanpos]->txgain, law);
- if (res < 0)
- ast_log(LOG_WARNING, "Unable to set gains on channel %d\n", pri->pvts[chanpos]->channel);
- if (e->ring.complete || !pri->overlapdial) {
- /* Just announce proceeding */
- pri->pvts[chanpos]->proceeding = 1;
- pri_proceeding(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 0);
- } else {
- if (pri->switchtype != PRI_SWITCH_GR303_TMC)
- pri_need_more_info(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
- else
- pri_answer(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
- }
- /* Get the use_callingpres state */
- pri->pvts[chanpos]->callingpres = e->ring.callingpres;
-
- /* Start PBX */
- if (!e->ring.complete && pri->overlapdial && ast_matchmore_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) {
- /* Release the PRI lock while we create the channel */
- ast_mutex_unlock(&pri->lock);
- if (crv) {
- /* Set bearer and such */
- pri_assign_bearer(crv, pri, pri->pvts[chanpos]);
- c = dahdi_new(crv, AST_STATE_RESERVED, 0, SUB_REAL, law, e->ring.ctype);
- pri->pvts[chanpos]->owner = &inuse;
- ast_log(LOG_DEBUG, "Started up crv %d:%d on bearer channel %d\n", pri->trunkgroup, crv->channel, crv->bearer->channel);
- } else {
- c = dahdi_new(pri->pvts[chanpos], AST_STATE_RESERVED, 0, SUB_REAL, law, e->ring.ctype);
- }
-
- ast_mutex_unlock(&pri->pvts[chanpos]->lock);
-
- if (!ast_strlen_zero(e->ring.callingsubaddr)) {
- pbx_builtin_setvar_helper(c, "CALLINGSUBADDR", e->ring.callingsubaddr);
- }
- if (e->ring.ani2 >= 0) {
- snprintf(ani2str, 5, "%.2d", e->ring.ani2);
- pbx_builtin_setvar_helper(c, "ANI2", ani2str);
- }
-
-#ifdef SUPPORT_USERUSER
- if (!ast_strlen_zero(e->ring.useruserinfo)) {
- pbx_builtin_setvar_helper(c, "USERUSERINFO", e->ring.useruserinfo);
- }
-#endif
-
- snprintf(calledtonstr, sizeof(calledtonstr)-1, "%d", e->ring.calledplan);
- pbx_builtin_setvar_helper(c, "CALLEDTON", calledtonstr);
- if (e->ring.redirectingreason >= 0)
- pbx_builtin_setvar_helper(c, "PRIREDIRECTREASON", redirectingreason2str(e->ring.redirectingreason));
-
- ast_mutex_lock(&pri->pvts[chanpos]->lock);
- ast_mutex_lock(&pri->lock);
-
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- if (c && !ast_pthread_create(&threadid, &attr, ss_thread, c)) {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Accepting overlap call from '%s' to '%s' on channel %d/%d, span %d\n",
- plancallingnum, S_OR(pri->pvts[chanpos]->exten, "<unspecified>"),
- pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
- } else {
- ast_log(LOG_WARNING, "Unable to start PBX on channel %d/%d, span %d\n",
- pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
- if (c)
- ast_hangup(c);
- else {
- pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_SWITCH_CONGESTION);
- pri->pvts[chanpos]->call = NULL;
- }
- }
- pthread_attr_destroy(&attr);
- } else {
- ast_mutex_unlock(&pri->lock);
- /* Release PRI lock while we create the channel */
- c = dahdi_new(pri->pvts[chanpos], AST_STATE_RING, 1, SUB_REAL, law, e->ring.ctype);
- if (c) {
- char calledtonstr[10];
-
- ast_mutex_unlock(&pri->pvts[chanpos]->lock);
-
- if (e->ring.ani2 >= 0) {
- snprintf(ani2str, 5, "%d", e->ring.ani2);
- pbx_builtin_setvar_helper(c, "ANI2", ani2str);
- }
-
-#ifdef SUPPORT_USERUSER
- if (!ast_strlen_zero(e->ring.useruserinfo)) {
- pbx_builtin_setvar_helper(c, "USERUSERINFO", e->ring.useruserinfo);
- }
-#endif
-
- if (e->ring.redirectingreason >= 0)
- pbx_builtin_setvar_helper(c, "PRIREDIRECTREASON", redirectingreason2str(e->ring.redirectingreason));
-
- snprintf(calledtonstr, sizeof(calledtonstr)-1, "%d", e->ring.calledplan);
- pbx_builtin_setvar_helper(c, "CALLEDTON", calledtonstr);
-
- ast_mutex_lock(&pri->pvts[chanpos]->lock);
- ast_mutex_lock(&pri->lock);
-
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Accepting call from '%s' to '%s' on channel %d/%d, span %d\n",
- plancallingnum, pri->pvts[chanpos]->exten,
- pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
- dahdi_enable_ec(pri->pvts[chanpos]);
- } else {
-
- ast_mutex_lock(&pri->lock);
-
- ast_log(LOG_WARNING, "Unable to start PBX on channel %d/%d, span %d\n",
- pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
- pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_SWITCH_CONGESTION);
- pri->pvts[chanpos]->call = NULL;
- }
- }
- } else {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Extension '%s' in context '%s' from '%s' does not exist. Rejecting call on channel %d/%d, span %d\n",
- pri->pvts[chanpos]->exten, pri->pvts[chanpos]->context, pri->pvts[chanpos]->cid_num, pri->pvts[chanpos]->logicalspan,
- pri->pvts[chanpos]->prioffset, pri->span);
- pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_UNALLOCATED);
- pri->pvts[chanpos]->call = NULL;
- pri->pvts[chanpos]->exten[0] = '\0';
- }
- if (crv)
- ast_mutex_unlock(&crv->lock);
- ast_mutex_unlock(&pri->pvts[chanpos]->lock);
- } else {
- if (e->ring.flexible)
- pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION);
- else
- pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_REQUESTED_CHAN_UNAVAIL);
- }
- break;
- case PRI_EVENT_RINGING:
- chanpos = pri_find_principle(pri, e->ringing.channel);
- if (chanpos < 0) {
- ast_log(LOG_WARNING, "Ringing requested on unconfigured channel %d/%d span %d\n",
- PRI_SPAN(e->ringing.channel), PRI_CHANNEL(e->ringing.channel), pri->span);
- } else {
- chanpos = pri_fixup_principle(pri, chanpos, e->ringing.call);
- if (chanpos < 0) {
- ast_log(LOG_WARNING, "Ringing requested on channel %d/%d not in use on span %d\n",
- PRI_SPAN(e->ringing.channel), PRI_CHANNEL(e->ringing.channel), pri->span);
- } else {
- ast_mutex_lock(&pri->pvts[chanpos]->lock);
- if (ast_strlen_zero(pri->pvts[chanpos]->dop.dialstr)) {
- dahdi_enable_ec(pri->pvts[chanpos]);
- pri->pvts[chanpos]->subs[SUB_REAL].needringing = 1;
- pri->pvts[chanpos]->alerting = 1;
- } else
- ast_log(LOG_DEBUG, "Deferring ringing notification because of extra digits to dial...\n");
-#ifdef PRI_PROGRESS_MASK
- if (e->ringing.progressmask & PRI_PROG_INBAND_AVAILABLE) {
-#else
- if (e->ringing.progress == 8) {
-#endif
- /* Now we can do call progress detection */
- if (pri->pvts[chanpos]->dsp && pri->pvts[chanpos]->dsp_features) {
- /* RINGING detection isn't required because we got ALERTING signal */
- ast_dsp_set_features(pri->pvts[chanpos]->dsp, pri->pvts[chanpos]->dsp_features & ~DSP_PROGRESS_RINGING);
- pri->pvts[chanpos]->dsp_features = 0;
- }
- }
-
-#ifdef SUPPORT_USERUSER
- if (!ast_strlen_zero(e->ringing.useruserinfo)) {
- struct ast_channel *owner = pri->pvts[chanpos]->owner;
- ast_mutex_unlock(&pri->pvts[chanpos]->lock);
- pbx_builtin_setvar_helper(owner, "USERUSERINFO", e->ringing.useruserinfo);
- ast_mutex_lock(&pri->pvts[chanpos]->lock);
- }
-#endif
-
- ast_mutex_unlock(&pri->pvts[chanpos]->lock);
- }
- }
- break;
- case PRI_EVENT_PROGRESS:
- /* Get chan value if e->e is not PRI_EVNT_RINGING */
- chanpos = pri_find_principle(pri, e->proceeding.channel);
- if (chanpos > -1) {
-#ifdef PRI_PROGRESS_MASK
- if ((!pri->pvts[chanpos]->progress) || (e->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE)) {
-#else
- if ((!pri->pvts[chanpos]->progress) || (e->proceeding.progress == 8)) {
-#endif
- struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_PROGRESS, };
-
- if (e->proceeding.cause > -1) {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "PROGRESS with cause code %d received\n", e->proceeding.cause);
-
- /* Work around broken, out of spec USER_BUSY cause in a progress message */
- if (e->proceeding.cause == AST_CAUSE_USER_BUSY) {
- if (pri->pvts[chanpos]->owner) {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "PROGRESS with 'user busy' received, signaling AST_CONTROL_BUSY instead of AST_CONTROL_PROGRESS\n");
-
- pri->pvts[chanpos]->owner->hangupcause = e->proceeding.cause;
- f.subclass = AST_CONTROL_BUSY;
- }
- }
- }
-
- ast_mutex_lock(&pri->pvts[chanpos]->lock);
- ast_log(LOG_DEBUG, "Queuing frame from PRI_EVENT_PROGRESS on channel %d/%d span %d\n",
- pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset,pri->span);
- dahdi_queue_frame(pri->pvts[chanpos], &f, pri);
-#ifdef PRI_PROGRESS_MASK
- if (e->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE) {
-#else
- if (e->proceeding.progress == 8) {
-#endif
- /* Now we can do call progress detection */
- if (pri->pvts[chanpos]->dsp && pri->pvts[chanpos]->dsp_features) {
- ast_dsp_set_features(pri->pvts[chanpos]->dsp, pri->pvts[chanpos]->dsp_features);
- pri->pvts[chanpos]->dsp_features = 0;
- }
- }
- pri->pvts[chanpos]->progress = 1;
- ast_mutex_unlock(&pri->pvts[chanpos]->lock);
- }
- }
- break;
- case PRI_EVENT_PROCEEDING:
- chanpos = pri_find_principle(pri, e->proceeding.channel);
- if (chanpos > -1) {
- if (!pri->pvts[chanpos]->proceeding) {
- struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_PROCEEDING, };
-
- ast_mutex_lock(&pri->pvts[chanpos]->lock);
- ast_log(LOG_DEBUG, "Queuing frame from PRI_EVENT_PROCEEDING on channel %d/%d span %d\n",
- pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset,pri->span);
- dahdi_queue_frame(pri->pvts[chanpos], &f, pri);
-#ifdef PRI_PROGRESS_MASK
- if (e->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE) {
-#else
- if (e->proceeding.progress == 8) {
-#endif
- /* Now we can do call progress detection */
- if (pri->pvts[chanpos]->dsp && pri->pvts[chanpos]->dsp_features) {
- ast_dsp_set_features(pri->pvts[chanpos]->dsp, pri->pvts[chanpos]->dsp_features);
- pri->pvts[chanpos]->dsp_features = 0;
- }
- /* Bring voice path up */
- f.subclass = AST_CONTROL_PROGRESS;
- dahdi_queue_frame(pri->pvts[chanpos], &f, pri);
- }
- pri->pvts[chanpos]->proceeding = 1;
- ast_mutex_unlock(&pri->pvts[chanpos]->lock);
- }
- }
- break;
- case PRI_EVENT_FACNAME:
- chanpos = pri_find_principle(pri, e->facname.channel);
- if (chanpos < 0) {
- ast_log(LOG_WARNING, "Facility Name requested on unconfigured channel %d/%d span %d\n",
- PRI_SPAN(e->facname.channel), PRI_CHANNEL(e->facname.channel), pri->span);
- } else {
- chanpos = pri_fixup_principle(pri, chanpos, e->facname.call);
- if (chanpos < 0) {
- ast_log(LOG_WARNING, "Facility Name requested on channel %d/%d not in use on span %d\n",
- PRI_SPAN(e->facname.channel), PRI_CHANNEL(e->facname.channel), pri->span);
- } else {
- /* Re-use *69 field for PRI */
- ast_mutex_lock(&pri->pvts[chanpos]->lock);
- ast_copy_string(pri->pvts[chanpos]->lastcid_num, e->facname.callingnum, sizeof(pri->pvts[chanpos]->lastcid_num));
- ast_copy_string(pri->pvts[chanpos]->lastcid_name, e->facname.callingname, sizeof(pri->pvts[chanpos]->lastcid_name));
- pri->pvts[chanpos]->subs[SUB_REAL].needcallerid =1;
- dahdi_enable_ec(pri->pvts[chanpos]);
- ast_mutex_unlock(&pri->pvts[chanpos]->lock);
- }
- }
- break;
- case PRI_EVENT_ANSWER:
- chanpos = pri_find_principle(pri, e->answer.channel);
- if (chanpos < 0) {
- ast_log(LOG_WARNING, "Answer on unconfigured channel %d/%d span %d\n",
- PRI_SPAN(e->answer.channel), PRI_CHANNEL(e->answer.channel), pri->span);
- } else {
- chanpos = pri_fixup_principle(pri, chanpos, e->answer.call);
- if (chanpos < 0) {
- ast_log(LOG_WARNING, "Answer requested on channel %d/%d not in use on span %d\n",
- PRI_SPAN(e->answer.channel), PRI_CHANNEL(e->answer.channel), pri->span);
- } else {
- ast_mutex_lock(&pri->pvts[chanpos]->lock);
- /* Now we can do call progress detection */
-
- /* We changed this so it turns on the DSP no matter what... progress or no progress.
- * By this time, we need DTMF detection and other features that were previously disabled
- * -- Matt F */
- if (pri->pvts[chanpos]->dsp && pri->pvts[chanpos]->dsp_features) {
- ast_dsp_set_features(pri->pvts[chanpos]->dsp, pri->pvts[chanpos]->dsp_features);
- pri->pvts[chanpos]->dsp_features = 0;
- }
- if (pri->pvts[chanpos]->realcall && (pri->pvts[chanpos]->realcall->sig == SIG_FXSKS)) {
- ast_log(LOG_DEBUG, "Starting up GR-303 trunk now that we got CONNECT...\n");
- x = DAHDI_START;
- res = ioctl(pri->pvts[chanpos]->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
- if (res < 0) {
- if (errno != EINPROGRESS) {
- ast_log(LOG_WARNING, "Unable to start channel: %s\n", strerror(errno));
- }
- }
- } else if (!ast_strlen_zero(pri->pvts[chanpos]->dop.dialstr)) {
- pri->pvts[chanpos]->dialing = 1;
- /* Send any "w" waited stuff */
- res = ioctl(pri->pvts[chanpos]->subs[SUB_REAL].dfd, DAHDI_DIAL, &pri->pvts[chanpos]->dop);
- if (res < 0) {
- ast_log(LOG_WARNING, "Unable to initiate dialing on trunk channel %d: %s\n", pri->pvts[chanpos]->channel, strerror(errno));
- pri->pvts[chanpos]->dop.dialstr[0] = '\0';
- } else
- ast_log(LOG_DEBUG, "Sent deferred digit string: %s\n", pri->pvts[chanpos]->dop.dialstr);
- pri->pvts[chanpos]->dop.dialstr[0] = '\0';
- } else if (pri->pvts[chanpos]->confirmanswer) {
- ast_log(LOG_DEBUG, "Waiting on answer confirmation on channel %d!\n", pri->pvts[chanpos]->channel);
- } else {
- pri->pvts[chanpos]->subs[SUB_REAL].needanswer =1;
- /* Enable echo cancellation if it's not on already */
- dahdi_enable_ec(pri->pvts[chanpos]);
- }
-
-#ifdef SUPPORT_USERUSER
- if (!ast_strlen_zero(e->answer.useruserinfo)) {
- struct ast_channel *owner = pri->pvts[chanpos]->owner;
- ast_mutex_unlock(&pri->pvts[chanpos]->lock);
- pbx_builtin_setvar_helper(owner, "USERUSERINFO", e->answer.useruserinfo);
- ast_mutex_lock(&pri->pvts[chanpos]->lock);
- }
-#endif
-
- ast_mutex_unlock(&pri->pvts[chanpos]->lock);
- }
- }
- break;
- case PRI_EVENT_HANGUP:
- chanpos = pri_find_principle(pri, e->hangup.channel);
- if (chanpos < 0) {
- ast_log(LOG_WARNING, "Hangup requested on unconfigured channel %d/%d span %d\n",
- PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
- } else {
- chanpos = pri_fixup_principle(pri, chanpos, e->hangup.call);
- if (chanpos > -1) {
- ast_mutex_lock(&pri->pvts[chanpos]->lock);
- if (!pri->pvts[chanpos]->alreadyhungup) {
- /* we're calling here dahdi_hangup so once we get there we need to clear p->call after calling pri_hangup */
- pri->pvts[chanpos]->alreadyhungup = 1;
- if (pri->pvts[chanpos]->realcall)
- pri_hangup_all(pri->pvts[chanpos]->realcall, pri);
- else if (pri->pvts[chanpos]->owner) {
- /* Queue a BUSY instead of a hangup if our cause is appropriate */
- pri->pvts[chanpos]->owner->hangupcause = e->hangup.cause;
- if (pri->pvts[chanpos]->owner->_state == AST_STATE_UP)
- pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
- else {
- switch (e->hangup.cause) {
- case PRI_CAUSE_USER_BUSY:
- pri->pvts[chanpos]->subs[SUB_REAL].needbusy =1;
- break;
- case PRI_CAUSE_CALL_REJECTED:
- case PRI_CAUSE_NETWORK_OUT_OF_ORDER:
- case PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION:
- case PRI_CAUSE_SWITCH_CONGESTION:
- case PRI_CAUSE_DESTINATION_OUT_OF_ORDER:
- case PRI_CAUSE_NORMAL_TEMPORARY_FAILURE:
- pri->pvts[chanpos]->subs[SUB_REAL].needcongestion =1;
- break;
- default:
- pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
- }
- }
- }
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Channel %d/%d, span %d got hangup, cause %d\n",
- pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span, e->hangup.cause);
- } else {
- pri_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause);
- pri->pvts[chanpos]->call = NULL;
- }
- if (e->hangup.cause == PRI_CAUSE_REQUESTED_CHAN_UNAVAIL) {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Forcing restart of channel %d/%d on span %d since channel reported in use\n",
- PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
- pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[chanpos]));
- pri->pvts[chanpos]->resetting = 1;
- }
- if (e->hangup.aoc_units > -1)
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Channel %d/%d, span %d received AOC-E charging %d unit%s\n",
- pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span, (int)e->hangup.aoc_units, (e->hangup.aoc_units == 1) ? "" : "s");
-
-#ifdef SUPPORT_USERUSER
- if (pri->pvts[chanpos]->owner && !ast_strlen_zero(e->hangup.useruserinfo)) {
- struct ast_channel *owner = pri->pvts[chanpos]->owner;
- ast_mutex_unlock(&pri->pvts[chanpos]->lock);
- pbx_builtin_setvar_helper(owner, "USERUSERINFO", e->hangup.useruserinfo);
- ast_mutex_lock(&pri->pvts[chanpos]->lock);
- }
-#endif
-
- ast_mutex_unlock(&pri->pvts[chanpos]->lock);
- } else {
- ast_log(LOG_WARNING, "Hangup on bad channel %d/%d on span %d\n",
- PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
- }
- }
- break;
-#ifndef PRI_EVENT_HANGUP_REQ
-#error please update libpri
-#endif
- case PRI_EVENT_HANGUP_REQ:
- chanpos = pri_find_principle(pri, e->hangup.channel);
- if (chanpos < 0) {
- ast_log(LOG_WARNING, "Hangup REQ requested on unconfigured channel %d/%d span %d\n",
- PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
- } else {
- chanpos = pri_fixup_principle(pri, chanpos, e->hangup.call);
- if (chanpos > -1) {
- ast_mutex_lock(&pri->pvts[chanpos]->lock);
- if (pri->pvts[chanpos]->realcall)
- pri_hangup_all(pri->pvts[chanpos]->realcall, pri);
- else if (pri->pvts[chanpos]->owner) {
- pri->pvts[chanpos]->owner->hangupcause = e->hangup.cause;
- if (pri->pvts[chanpos]->owner->_state == AST_STATE_UP)
- pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
- else {
- switch (e->hangup.cause) {
- case PRI_CAUSE_USER_BUSY:
- pri->pvts[chanpos]->subs[SUB_REAL].needbusy =1;
- break;
- case PRI_CAUSE_CALL_REJECTED:
- case PRI_CAUSE_NETWORK_OUT_OF_ORDER:
- case PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION:
- case PRI_CAUSE_SWITCH_CONGESTION:
- case PRI_CAUSE_DESTINATION_OUT_OF_ORDER:
- case PRI_CAUSE_NORMAL_TEMPORARY_FAILURE:
- pri->pvts[chanpos]->subs[SUB_REAL].needcongestion =1;
- break;
- default:
- pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
- }
- }
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Channel %d/%d, span %d got hangup request, cause %d\n", PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span, e->hangup.cause);
- if (e->hangup.aoc_units > -1)
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Channel %d/%d, span %d received AOC-E charging %d unit%s\n",
- pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span, (int)e->hangup.aoc_units, (e->hangup.aoc_units == 1) ? "" : "s");
- } else {
- pri_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause);
- pri->pvts[chanpos]->call = NULL;
- }
- if (e->hangup.cause == PRI_CAUSE_REQUESTED_CHAN_UNAVAIL) {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Forcing restart of channel %d/%d span %d since channel reported in use\n",
- PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
- pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[chanpos]));
- pri->pvts[chanpos]->resetting = 1;
- }
-
-#ifdef SUPPORT_USERUSER
- if (!ast_strlen_zero(e->hangup.useruserinfo)) {
- struct ast_channel *owner = pri->pvts[chanpos]->owner;
- ast_mutex_unlock(&pri->pvts[chanpos]->lock);
- pbx_builtin_setvar_helper(owner, "USERUSERINFO", e->hangup.useruserinfo);
- ast_mutex_lock(&pri->pvts[chanpos]->lock);
- }
-#endif
-
- ast_mutex_unlock(&pri->pvts[chanpos]->lock);
- } else {
- ast_log(LOG_WARNING, "Hangup REQ on bad channel %d/%d on span %d\n", PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
- }
- }
- break;
- case PRI_EVENT_HANGUP_ACK:
- chanpos = pri_find_principle(pri, e->hangup.channel);
- if (chanpos < 0) {
- ast_log(LOG_WARNING, "Hangup ACK requested on unconfigured channel number %d/%d span %d\n",
- PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
- } else {
- chanpos = pri_fixup_principle(pri, chanpos, e->hangup.call);
- if (chanpos > -1) {
- ast_mutex_lock(&pri->pvts[chanpos]->lock);
- pri->pvts[chanpos]->call = NULL;
- pri->pvts[chanpos]->resetting = 0;
- if (pri->pvts[chanpos]->owner) {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Channel %d/%d, span %d got hangup ACK\n", PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
- }
-
-#ifdef SUPPORT_USERUSER
- if (!ast_strlen_zero(e->hangup.useruserinfo)) {
- struct ast_channel *owner = pri->pvts[chanpos]->owner;
- ast_mutex_unlock(&pri->pvts[chanpos]->lock);
- pbx_builtin_setvar_helper(owner, "USERUSERINFO", e->hangup.useruserinfo);
- ast_mutex_lock(&pri->pvts[chanpos]->lock);
- }
-#endif
-
- ast_mutex_unlock(&pri->pvts[chanpos]->lock);
- }
- }
- break;
- case PRI_EVENT_CONFIG_ERR:
- ast_log(LOG_WARNING, "PRI Error on span %d: %s\n", pri->trunkgroup, e->err.err);
- break;
- case PRI_EVENT_RESTART_ACK:
- chanpos = pri_find_principle(pri, e->restartack.channel);
- if (chanpos < 0) {
- /* Sometime switches (e.g. I421 / British Telecom) don't give us the
- channel number, so we have to figure it out... This must be why
- everybody resets exactly a channel at a time. */
- for (x = 0; x < pri->numchans; x++) {
- if (pri->pvts[x] && pri->pvts[x]->resetting) {
- chanpos = x;
- ast_mutex_lock(&pri->pvts[chanpos]->lock);
- ast_log(LOG_DEBUG, "Assuming restart ack is really for channel %d/%d span %d\n", pri->pvts[chanpos]->logicalspan,
- pri->pvts[chanpos]->prioffset, pri->span);
- if (pri->pvts[chanpos]->realcall)
- pri_hangup_all(pri->pvts[chanpos]->realcall, pri);
- else if (pri->pvts[chanpos]->owner) {
- ast_log(LOG_WARNING, "Got restart ack on channel %d/%d with owner on span %d\n", pri->pvts[chanpos]->logicalspan,
- pri->pvts[chanpos]->prioffset, pri->span);
- pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
- }
- pri->pvts[chanpos]->resetting = 0;
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "B-channel %d/%d successfully restarted on span %d\n", pri->pvts[chanpos]->logicalspan,
- pri->pvts[chanpos]->prioffset, pri->span);
- ast_mutex_unlock(&pri->pvts[chanpos]->lock);
- if (pri->resetting)
- pri_check_restart(pri);
- break;
- }
- }
- if (chanpos < 0) {
- ast_log(LOG_WARNING, "Restart ACK requested on strange channel %d/%d span %d\n",
- PRI_SPAN(e->restartack.channel), PRI_CHANNEL(e->restartack.channel), pri->span);
- }
- } else {
- if (pri->pvts[chanpos]) {
- ast_mutex_lock(&pri->pvts[chanpos]->lock);
- if (pri->pvts[chanpos]->realcall)
- pri_hangup_all(pri->pvts[chanpos]->realcall, pri);
- else if (pri->pvts[chanpos]->owner) {
- ast_log(LOG_WARNING, "Got restart ack on channel %d/%d span %d with owner\n",
- PRI_SPAN(e->restartack.channel), PRI_CHANNEL(e->restartack.channel), pri->span);
- pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
- }
- pri->pvts[chanpos]->resetting = 0;
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "B-channel %d/%d successfully restarted on span %d\n", pri->pvts[chanpos]->logicalspan,
- pri->pvts[chanpos]->prioffset, pri->span);
- ast_mutex_unlock(&pri->pvts[chanpos]->lock);
- if (pri->resetting)
- pri_check_restart(pri);
- }
- }
- break;
- case PRI_EVENT_SETUP_ACK:
- chanpos = pri_find_principle(pri, e->setup_ack.channel);
- if (chanpos < 0) {
- ast_log(LOG_WARNING, "Received SETUP_ACKNOWLEDGE on unconfigured channel %d/%d span %d\n",
- PRI_SPAN(e->setup_ack.channel), PRI_CHANNEL(e->setup_ack.channel), pri->span);
- } else {
- chanpos = pri_fixup_principle(pri, chanpos, e->setup_ack.call);
- if (chanpos > -1) {
- ast_mutex_lock(&pri->pvts[chanpos]->lock);
- pri->pvts[chanpos]->setup_ack = 1;
- /* Send any queued digits */
- for (x = 0;x < strlen(pri->pvts[chanpos]->dialdest); x++) {
- ast_log(LOG_DEBUG, "Sending pending digit '%c'\n", pri->pvts[chanpos]->dialdest[x]);
- pri_information(pri->pri, pri->pvts[chanpos]->call,
- pri->pvts[chanpos]->dialdest[x]);
- }
- ast_mutex_unlock(&pri->pvts[chanpos]->lock);
- } else
- ast_log(LOG_WARNING, "Unable to move channel %d!\n", e->setup_ack.channel);
- }
- break;
- case PRI_EVENT_NOTIFY:
- chanpos = pri_find_principle(pri, e->notify.channel);
- if (chanpos < 0) {
- ast_log(LOG_WARNING, "Received NOTIFY on unconfigured channel %d/%d span %d\n",
- PRI_SPAN(e->notify.channel), PRI_CHANNEL(e->notify.channel), pri->span);
- } else {
- struct ast_frame f = { AST_FRAME_CONTROL, };
- ast_mutex_lock(&pri->pvts[chanpos]->lock);
- switch (e->notify.info) {
- case PRI_NOTIFY_REMOTE_HOLD:
- f.subclass = AST_CONTROL_HOLD;
- dahdi_queue_frame(pri->pvts[chanpos], &f, pri);
- break;
- case PRI_NOTIFY_REMOTE_RETRIEVAL:
- f.subclass = AST_CONTROL_UNHOLD;
- dahdi_queue_frame(pri->pvts[chanpos], &f, pri);
- break;
- }
- ast_mutex_unlock(&pri->pvts[chanpos]->lock);
- }
- break;
- default:
- ast_log(LOG_DEBUG, "Event: %d\n", e->e);
- }
- }
- ast_mutex_unlock(&pri->lock);
- }
- /* Never reached */
- return NULL;
-}
-
-static int start_pri(struct dahdi_pri *pri)
-{
- int res, x;
- struct dahdi_params p;
- struct dahdi_bufferinfo bi;
- struct dahdi_spaninfo si;
- int i;
-
- for (i = 0; i < NUM_DCHANS; i++) {
- if (!pri->dchannels[i])
- break;
- pri->fds[i] = open(DAHDI_FILE_CHANNEL, O_RDWR, 0600);
- x = pri->dchannels[i];
- if ((pri->fds[i] < 0) || (ioctl(pri->fds[i],DAHDI_SPECIFY,&x) == -1)) {
- ast_log(LOG_ERROR, "Unable to open D-channel %d (%s)\n", x, strerror(errno));
- return -1;
- }
- res = ioctl(pri->fds[i], DAHDI_GET_PARAMS, &p);
- if (res) {
- dahdi_close_pri_fd(pri, i);
- ast_log(LOG_ERROR, "Unable to get parameters for D-channel %d (%s)\n", x, strerror(errno));
- return -1;
- }
- if ((p.sigtype != DAHDI_SIG_HDLCFCS) && (p.sigtype != DAHDI_SIG_HARDHDLC)) {
- dahdi_close_pri_fd(pri, i);
- ast_log(LOG_ERROR, "D-channel %d is not in HDLC/FCS mode. See /etc/dahdi/system.conf\n", x);
- return -1;
- }
- memset(&si, 0, sizeof(si));
- res = ioctl(pri->fds[i], DAHDI_SPANSTAT, &si);
- if (res) {
- dahdi_close_pri_fd(pri, i);
- ast_log(LOG_ERROR, "Unable to get span state for D-channel %d (%s)\n", x, strerror(errno));
- }
- if (!si.alarms)
- pri->dchanavail[i] |= DCHAN_NOTINALARM;
- else
- pri->dchanavail[i] &= ~DCHAN_NOTINALARM;
- bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
- bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
- bi.numbufs = 32;
- bi.bufsize = 1024;
- if (ioctl(pri->fds[i], DAHDI_SET_BUFINFO, &bi)) {
- ast_log(LOG_ERROR, "Unable to set appropriate buffering on channel %d: %s\n", x, strerror(errno));
- dahdi_close_pri_fd(pri, i);
- return -1;
- }
- pri->dchans[i] = pri_new(pri->fds[i], pri->nodetype, pri->switchtype);
- /* Force overlap dial if we're doing GR-303! */
- if (pri->switchtype == PRI_SWITCH_GR303_TMC)
- pri->overlapdial = 1;
- pri_set_overlapdial(pri->dchans[i],pri->overlapdial);
-#ifdef HAVE_PRI_INBANDDISCONNECT
- pri_set_inbanddisconnect(pri->dchans[i], pri->inbanddisconnect);
-#endif
- /* Enslave to master if appropriate */
- if (i)
- pri_enslave(pri->dchans[0], pri->dchans[i]);
- if (!pri->dchans[i]) {
- dahdi_close_pri_fd(pri, i);
- ast_log(LOG_ERROR, "Unable to create PRI structure\n");
- return -1;
- }
- pri_set_debug(pri->dchans[i], DEFAULT_PRI_DEBUG);
- pri_set_nsf(pri->dchans[i], pri->nsf);
-#ifdef PRI_GETSET_TIMERS
- for (x = 0; x < PRI_MAX_TIMERS; x++) {
- if (pritimers[x] != 0)
- pri_set_timer(pri->dchans[i], x, pritimers[x]);
- }
-#endif
- }
- /* Assume primary is the one we use */
- pri->pri = pri->dchans[0];
- pri->resetpos = -1;
- if (ast_pthread_create_background(&pri->master, NULL, pri_dchannel, pri)) {
- for (i = 0; i < NUM_DCHANS; i++) {
- if (!pri->dchannels[i])
- break;
- dahdi_close_pri_fd(pri, i);
- }
- ast_log(LOG_ERROR, "Unable to spawn D-channel: %s\n", strerror(errno));
- return -1;
- }
- return 0;
-}
-
-static char *complete_span_helper(const char *line, const char *word, int pos, int state, int rpos)
-{
- int which, span;
- char *ret = NULL;
-
- if (pos != rpos)
- return ret;
-
- for (which = span = 0; span < NUM_SPANS; span++) {
- if (pris[span].pri && ++which > state) {
- if (asprintf(&ret, "%d", span + 1) < 0) { /* user indexes start from 1 */
- ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
- }
- break;
- }
- }
- return ret;
-}
-
-static char *complete_span_4(const char *line, const char *word, int pos, int state)
-{
- return complete_span_helper(line,word,pos,state,3);
-}
-
-static char *complete_span_5(const char *line, const char *word, int pos, int state)
-{
- return complete_span_helper(line,word,pos,state,4);
-}
-
-static int handle_pri_set_debug_file(int fd, int argc, char **argv)
-{
- int myfd;
-
- if (!strncasecmp(argv[1], "set", 3)) {
- if (argc < 5)
- return RESULT_SHOWUSAGE;
-
- if (ast_strlen_zero(argv[4]))
- return RESULT_SHOWUSAGE;
-
- myfd = open(argv[4], O_CREAT|O_WRONLY, 0600);
- if (myfd < 0) {
- ast_cli(fd, "Unable to open '%s' for writing\n", argv[4]);
- return RESULT_SUCCESS;
- }
-
- ast_mutex_lock(&pridebugfdlock);
-
- if (pridebugfd >= 0)
- close(pridebugfd);
-
- pridebugfd = myfd;
- ast_copy_string(pridebugfilename,argv[4],sizeof(pridebugfilename));
-
- ast_mutex_unlock(&pridebugfdlock);
-
- ast_cli(fd, "PRI debug output will be sent to '%s'\n", argv[4]);
- } else {
- /* Assume it is unset */
- ast_mutex_lock(&pridebugfdlock);
- close(pridebugfd);
- pridebugfd = -1;
- ast_cli(fd, "PRI debug output to file disabled\n");
- ast_mutex_unlock(&pridebugfdlock);
- }
-
- return RESULT_SUCCESS;
-}
-
-#ifdef HAVE_PRI_VERSION
-static int handle_pri_version(int fd, int agc, char *argv[]) {
- ast_cli(fd, "libpri version: %s\n", pri_get_version());
- return RESULT_SUCCESS;
-}
-#endif
-
-static int handle_pri_debug(int fd, int argc, char *argv[])
-{
- int span;
- int x;
- if (argc < 4) {
- return RESULT_SHOWUSAGE;
- }
- span = atoi(argv[3]);
- if ((span < 1) || (span > NUM_SPANS)) {
- ast_cli(fd, "Invalid span %s. Should be a number %d to %d\n", argv[3], 1, NUM_SPANS);
- return RESULT_SUCCESS;
- }
- if (!pris[span-1].pri) {
- ast_cli(fd, "No PRI running on span %d\n", span);
- return RESULT_SUCCESS;
- }
- for (x = 0; x < NUM_DCHANS; x++) {
- if (pris[span-1].dchans[x])
- pri_set_debug(pris[span-1].dchans[x], PRI_DEBUG_APDU |
- PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q931_STATE |
- PRI_DEBUG_Q921_STATE);
- }
- ast_cli(fd, "Enabled debugging on span %d\n", span);
- return RESULT_SUCCESS;
-}
-
-
-
-static int handle_pri_no_debug(int fd, int argc, char *argv[])
-{
- int span;
- int x;
- if (argc < 5)
- return RESULT_SHOWUSAGE;
- span = atoi(argv[4]);
- if ((span < 1) || (span > NUM_SPANS)) {
- ast_cli(fd, "Invalid span %s. Should be a number %d to %d\n", argv[4], 1, NUM_SPANS);
- return RESULT_SUCCESS;
- }
- if (!pris[span-1].pri) {
- ast_cli(fd, "No PRI running on span %d\n", span);
- return RESULT_SUCCESS;
- }
- for (x = 0; x < NUM_DCHANS; x++) {
- if (pris[span-1].dchans[x])
- pri_set_debug(pris[span-1].dchans[x], 0);
- }
- ast_cli(fd, "Disabled debugging on span %d\n", span);
- return RESULT_SUCCESS;
-}
-
-static int handle_pri_really_debug(int fd, int argc, char *argv[])
-{
- int span;
- int x;
- if (argc < 5)
- return RESULT_SHOWUSAGE;
- span = atoi(argv[4]);
- if ((span < 1) || (span > NUM_SPANS)) {
- ast_cli(fd, "Invalid span %s. Should be a number %d to %d\n", argv[4], 1, NUM_SPANS);
- return RESULT_SUCCESS;
- }
- if (!pris[span-1].pri) {
- ast_cli(fd, "No PRI running on span %d\n", span);
- return RESULT_SUCCESS;
- }
- for (x = 0; x < NUM_DCHANS; x++) {
- if (pris[span-1].dchans[x])
- pri_set_debug(pris[span-1].dchans[x], PRI_DEBUG_APDU |
- PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q931_STATE |
- PRI_DEBUG_Q921_RAW | PRI_DEBUG_Q921_DUMP | PRI_DEBUG_Q921_STATE);
- }
- ast_cli(fd, "Enabled EXTENSIVE debugging on span %d\n", span);
- return RESULT_SUCCESS;
-}
-
-static void build_status(char *s, size_t len, int status, int active)
-{
- if (!s || len < 1) {
- return;
- }
- s[0] = '\0';
- if (status & DCHAN_PROVISIONED)
- strncat(s, "Provisioned, ", len - strlen(s) - 1);
- if (!(status & DCHAN_NOTINALARM))
- strncat(s, "In Alarm, ", len - strlen(s) - 1);
- if (status & DCHAN_UP)
- strncat(s, "Up", len - strlen(s) - 1);
- else
- strncat(s, "Down", len - strlen(s) - 1);
- if (active)
- strncat(s, ", Active", len - strlen(s) - 1);
- else
- strncat(s, ", Standby", len - strlen(s) - 1);
- s[len - 1] = '\0';
-}
-
-static int handle_pri_show_spans(int fd, int argc, char *argv[])
-{
- int span;
- int x;
- char status[256];
- if (argc != 3)
- return RESULT_SHOWUSAGE;
-
- for (span = 0; span < NUM_SPANS; span++) {
- if (pris[span].pri) {
- for (x = 0; x < NUM_DCHANS; x++) {
- if (pris[span].dchannels[x]) {
- build_status(status, sizeof(status), pris[span].dchanavail[x], pris[span].dchans[x] == pris[span].pri);
- ast_cli(fd, "PRI span %d/%d: %s\n", span + 1, x, status);
- }
- }
- }
- }
- return RESULT_SUCCESS;
-}
-
-static int handle_pri_show_span(int fd, int argc, char *argv[])
-{
- int span;
- int x;
- char status[256];
- if (argc < 4)
- return RESULT_SHOWUSAGE;
- span = atoi(argv[3]);
- if ((span < 1) || (span > NUM_SPANS)) {
- ast_cli(fd, "Invalid span '%s'. Should be a number from %d to %d\n", argv[3], 1, NUM_SPANS);
- return RESULT_SUCCESS;
- }
- if (!pris[span-1].pri) {
- ast_cli(fd, "No PRI running on span %d\n", span);
- return RESULT_SUCCESS;
- }
- for (x = 0; x < NUM_DCHANS; x++) {
- if (pris[span-1].dchannels[x]) {
-#ifdef PRI_DUMP_INFO_STR
- char *info_str = NULL;
-#endif
- ast_cli(fd, "%s D-channel: %d\n", pri_order(x), pris[span-1].dchannels[x]);
- build_status(status, sizeof(status), pris[span-1].dchanavail[x], pris[span-1].dchans[x] == pris[span-1].pri);
- ast_cli(fd, "Status: %s\n", status);
-#ifdef PRI_DUMP_INFO_STR
- info_str = pri_dump_info_str(pris[span-1].pri);
- if (info_str) {
- ast_cli(fd, "%s", info_str);
- free(info_str);
- }
-#else
- pri_dump_info(pris[span-1].pri);
-#endif
- ast_cli(fd, "\n");
- }
- }
- return RESULT_SUCCESS;
-}
-
-static int handle_pri_show_debug(int fd, int argc, char *argv[])
-{
- int x;
- int span;
- int count=0;
- int debug=0;
-
- for (span = 0; span < NUM_SPANS; span++) {
- if (pris[span].pri) {
- for (x = 0; x < NUM_DCHANS; x++) {
- debug = 0;
- if (pris[span].dchans[x]) {
- debug = pri_get_debug(pris[span].dchans[x]);
- ast_cli(fd, "Span %d: Debug: %s\tIntense: %s\n", span+1, (debug&PRI_DEBUG_Q931_STATE)? "Yes" : "No" ,(debug&PRI_DEBUG_Q921_RAW)? "Yes" : "No" );
- count++;
- }
- }
- }
-
- }
- ast_mutex_lock(&pridebugfdlock);
- if (pridebugfd >= 0)
- ast_cli(fd, "Logging PRI debug to file %s\n", pridebugfilename);
- ast_mutex_unlock(&pridebugfdlock);
-
- if (!count)
- ast_cli(fd, "No debug set or no PRI running\n");
- return RESULT_SUCCESS;
-}
-
-static const char pri_debug_help[] =
- "Usage: pri debug span <span>\n"
- " Enables debugging on a given PRI span\n";
-
-static const char pri_no_debug_help[] =
- "Usage: pri no debug span <span>\n"
- " Disables debugging on a given PRI span\n";
-
-static const char pri_really_debug_help[] =
- "Usage: pri intensive debug span <span>\n"
- " Enables debugging down to the Q.921 level\n";
-
-static const char pri_show_span_help[] =
- "Usage: pri show span <span>\n"
- " Displays PRI Information on a given PRI span\n";
-
-static const char pri_show_spans_help[] =
- "Usage: pri show spans\n"
- " Displays PRI Information\n";
-
-static struct ast_cli_entry dahdi_pri_cli[] = {
- { { "pri", "debug", "span", NULL },
- handle_pri_debug, "Enables PRI debugging on a span",
- pri_debug_help, complete_span_4 },
-
- { { "pri", "no", "debug", "span", NULL },
- handle_pri_no_debug, "Disables PRI debugging on a span",
- pri_no_debug_help, complete_span_5 },
-
- { { "pri", "intense", "debug", "span", NULL },
- handle_pri_really_debug, "Enables REALLY INTENSE PRI debugging",
- pri_really_debug_help, complete_span_5 },
-
- { { "pri", "show", "spans", NULL },
- handle_pri_show_spans, "Displays PRI Information",
- pri_show_spans_help },
-
- { { "pri", "show", "span", NULL },
- handle_pri_show_span, "Displays PRI Information",
- pri_show_span_help, complete_span_4 },
-
- { { "pri", "show", "debug", NULL },
- handle_pri_show_debug, "Displays current PRI debug settings" },
-
- { { "pri", "set", "debug", "file", NULL },
- handle_pri_set_debug_file, "Sends PRI debug output to the specified file" },
-
- { { "pri", "unset", "debug", "file", NULL },
- handle_pri_set_debug_file, "Ends PRI debug output to file" },
-
-#ifdef HAVE_PRI_VERSION
- { { "pri", "show", "version", NULL },
- handle_pri_version, "Displays version of libpri" },
-#endif
-};
-
-#endif /* HAVE_PRI */
-
-static int dahdi_destroy_channel(int fd, int argc, char **argv)
-{
- int channel;
-
- if (argc != 4)
- return RESULT_SHOWUSAGE;
-
- channel = atoi(argv[3]);
-
- return dahdi_destroy_channel_bynum(channel);
-}
-
-static void dahdi_softhangup_all(void)
-{
- struct dahdi_pvt *p;
-retry:
- ast_mutex_lock(&iflock);
- for (p = iflist; p; p = p->next) {
- ast_mutex_lock(&p->lock);
- if (p->owner && !p->restartpending) {
- if (ast_channel_trylock(p->owner)) {
- if (option_debug > 2)
- ast_verbose("Avoiding deadlock\n");
- /* Avoid deadlock since you're not supposed to lock iflock or pvt before a channel */
- ast_mutex_unlock(&p->lock);
- ast_mutex_unlock(&iflock);
- goto retry;
- }
- if (option_debug > 2)
- ast_verbose("Softhanging up on %s\n", p->owner->name);
- ast_softhangup_nolock(p->owner, AST_SOFTHANGUP_EXPLICIT);
- p->restartpending = 1;
- num_restart_pending++;
- ast_channel_unlock(p->owner);
- }
- ast_mutex_unlock(&p->lock);
- }
- ast_mutex_unlock(&iflock);
-}
-
-static int setup_dahdi(int reload);
-static int dahdi_restart(void)
-{
-#if defined(HAVE_PRI)
- int i, j;
-#endif
- int cancel_code;
- struct dahdi_pvt *p;
-
- ast_mutex_lock(&restart_lock);
-
- if (option_verbose)
- ast_verbose("Destroying channels and reloading DAHDI configuration.\n");
- dahdi_softhangup_all();
- if (option_verbose > 3)
- ast_verbose("Initial softhangup of all DAHDI channels complete.\n");
-
- #if defined(HAVE_PRI)
- for (i = 0; i < NUM_SPANS; i++) {
- if (pris[i].master && (pris[i].master != AST_PTHREADT_NULL)) {
- cancel_code = pthread_cancel(pris[i].master);
- pthread_kill(pris[i].master, SIGURG);
- if (option_debug > 3)
- ast_verbose("Waiting to join thread of span %d with pid=%p, cancel_code=%d\n", i, (void *) pris[i].master, cancel_code);
- pthread_join(pris[i].master, NULL);
- if (option_debug > 3)
- ast_verbose("Joined thread of span %d\n", i);
- }
- }
- #endif
-
- ast_mutex_lock(&monlock);
- if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP) && (monitor_thread != AST_PTHREADT_NULL)) {
- cancel_code = pthread_cancel(monitor_thread);
- pthread_kill(monitor_thread, SIGURG);
- if (option_debug > 3)
- ast_verbose("Waiting to join monitor thread with pid=%p, cancel_code=%d\n", (void *) monitor_thread, cancel_code);
- pthread_join(monitor_thread, NULL);
- if (option_debug > 3)
- ast_verbose("Joined monitor thread\n");
- }
- monitor_thread = AST_PTHREADT_NULL; /* prepare to restart thread in setup_dahdi once channels are reconfigured */
-
- ast_mutex_lock(&ss_thread_lock);
- while (ss_thread_count > 0) { /* let ss_threads finish and run dahdi_hangup before dahvi_pvts are destroyed */
- int x = DAHDI_FLASH;
- if (option_debug > 2)
- ast_verbose("Waiting on %d ss_thread(s) to finish\n", ss_thread_count);
-
- for (p = iflist; p; p = p->next) {
- if (p->owner)
- ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x); /* important to create an event for dahdi_wait_event to register so that all ss_threads terminate */
- }
- ast_cond_wait(&ss_thread_complete, &ss_thread_lock);
- }
-
- /* ensure any created channels before monitor threads were stopped are hungup */
- dahdi_softhangup_all();
- if (option_verbose > 3)
- ast_verbose("Final softhangup of all DAHDI channels complete.\n");
- destroy_all_channels();
- if (option_debug)
- ast_verbose("Channels destroyed. Now re-reading config. %d active channels remaining.\n", ast_active_channels());
-
- ast_mutex_unlock(&monlock);
-
- #ifdef HAVE_PRI
- for (i = 0; i < NUM_SPANS; i++) {
- for (j = 0; j < NUM_DCHANS; j++)
- dahdi_close_pri_fd(&(pris[i]), j);
- }
-
- memset(pris, 0, sizeof(pris));
- for (i = 0; i < NUM_SPANS; i++) {
- ast_mutex_init(&pris[i].lock);
- pris[i].offset = -1;
- pris[i].master = AST_PTHREADT_NULL;
- for (j = 0; j < NUM_DCHANS; j++)
- pris[i].fds[j] = -1;
- }
- pri_set_error(dahdi_pri_error);
- pri_set_message(dahdi_pri_message);
- #endif
-
- if (setup_dahdi(2) != 0) {
- ast_log(LOG_WARNING, "Reload channels from dahdi config failed!\n");
- ast_mutex_unlock(&ss_thread_lock);
- return 1;
- }
- ast_mutex_unlock(&ss_thread_lock);
- ast_mutex_unlock(&restart_lock);
- return 0;
-}
-
-static int dahdi_restart_cmd(int fd, int argc, char **argv)
-{
- if (argc != 2) {
- return RESULT_SHOWUSAGE;
- }
-
- if (dahdi_restart() != 0)
- return RESULT_FAILURE;
- return RESULT_SUCCESS;
-}
-
-static int dahdi_show_channels(int fd, int argc, char **argv)
-{
-#define FORMAT "%7s %-10.10s %-15.15s %-10.10s %-20.20s\n"
-#define FORMAT2 "%7s %-10.10s %-15.15s %-10.10s %-20.20s\n"
- struct dahdi_pvt *tmp = NULL;
- char tmps[20] = "";
- ast_mutex_t *lock;
- struct dahdi_pvt *start;
-#ifdef HAVE_PRI
- int trunkgroup;
- struct dahdi_pri *pri = NULL;
- int x;
-#endif
-
- lock = &iflock;
- start = iflist;
-
-#ifdef HAVE_PRI
- if (argc == 4) {
- if ((trunkgroup = atoi(argv[3])) < 1)
- return RESULT_SHOWUSAGE;
- for (x = 0; x < NUM_SPANS; x++) {
- if (pris[x].trunkgroup == trunkgroup) {
- pri = pris + x;
- break;
- }
- }
- if (pri) {
- start = pri->crvs;
- lock = &pri->lock;
- } else {
- ast_cli(fd, "No such trunk group %d\n", trunkgroup);
- return RESULT_FAILURE;
- }
- } else
-#endif
- if (argc != 3)
- return RESULT_SHOWUSAGE;
-
- ast_mutex_lock(lock);
-#ifdef HAVE_PRI
- ast_cli(fd, FORMAT2, pri ? "CRV" : "Chan", "Extension", "Context", "Language", "MOH Interpret");
-#else
- ast_cli(fd, FORMAT2, "Chan", "Extension", "Context", "Language", "MOH Interpret");
-#endif
-
- tmp = start;
- while (tmp) {
- if (tmp->channel > 0) {
- snprintf(tmps, sizeof(tmps), "%d", tmp->channel);
- } else
- ast_copy_string(tmps, "pseudo", sizeof(tmps));
- ast_cli(fd, FORMAT, tmps, tmp->exten, tmp->context, tmp->language, tmp->mohinterpret);
- tmp = tmp->next;
- }
- ast_mutex_unlock(lock);
- return RESULT_SUCCESS;
-#undef FORMAT
-#undef FORMAT2
-}
-
-static int dahdi_show_channel(int fd, int argc, char **argv)
-{
- int channel;
- struct dahdi_pvt *tmp = NULL;
- struct dahdi_confinfo ci;
- struct dahdi_params ps;
- int x;
- ast_mutex_t *lock;
- struct dahdi_pvt *start;
-#ifdef HAVE_PRI
- char *c;
- int trunkgroup;
- struct dahdi_pri *pri=NULL;
-#endif
-
- lock = &iflock;
- start = iflist;
-
- if (argc != 4)
- return RESULT_SHOWUSAGE;
-#ifdef HAVE_PRI
- if ((c = strchr(argv[3], ':'))) {
- if (sscanf(argv[3], "%d:%d", &trunkgroup, &channel) != 2)
- return RESULT_SHOWUSAGE;
- if ((trunkgroup < 1) || (channel < 1))
- return RESULT_SHOWUSAGE;
- for (x = 0; x < NUM_SPANS; x++) {
- if (pris[x].trunkgroup == trunkgroup) {
- pri = pris + x;
- break;
- }
- }
- if (pri) {
- start = pri->crvs;
- lock = &pri->lock;
- } else {
- ast_cli(fd, "No such trunk group %d\n", trunkgroup);
- return RESULT_FAILURE;
- }
- } else
-#endif
- channel = atoi(argv[3]);
-
- ast_mutex_lock(lock);
- tmp = start;
- while (tmp) {
- if (tmp->channel == channel) {
-#ifdef HAVE_PRI
- if (pri)
- ast_cli(fd, "Trunk/CRV: %d/%d\n", trunkgroup, tmp->channel);
- else
-#endif
- ast_cli(fd, "Channel: %d\n", tmp->channel);
- ast_cli(fd, "File Descriptor: %d\n", tmp->subs[SUB_REAL].dfd);
- ast_cli(fd, "Span: %d\n", tmp->span);
- ast_cli(fd, "Extension: %s\n", tmp->exten);
- ast_cli(fd, "Dialing: %s\n", tmp->dialing ? "yes" : "no");
- ast_cli(fd, "Context: %s\n", tmp->context);
- ast_cli(fd, "Caller ID: %s\n", tmp->cid_num);
- ast_cli(fd, "Calling TON: %d\n", tmp->cid_ton);
- ast_cli(fd, "Caller ID name: %s\n", tmp->cid_name);
- ast_cli(fd, "Destroy: %d\n", tmp->destroy);
- ast_cli(fd, "InAlarm: %d\n", tmp->inalarm);
- ast_cli(fd, "Signalling Type: %s\n", sig2str(tmp->sig));
- ast_cli(fd, "Radio: %d\n", tmp->radio);
- ast_cli(fd, "Owner: %s\n", tmp->owner ? tmp->owner->name : "<None>");
- ast_cli(fd, "Real: %s%s%s\n", tmp->subs[SUB_REAL].owner ? tmp->subs[SUB_REAL].owner->name : "<None>", tmp->subs[SUB_REAL].inthreeway ? " (Confed)" : "", tmp->subs[SUB_REAL].linear ? " (Linear)" : "");
- ast_cli(fd, "Callwait: %s%s%s\n", tmp->subs[SUB_CALLWAIT].owner ? tmp->subs[SUB_CALLWAIT].owner->name : "<None>", tmp->subs[SUB_CALLWAIT].inthreeway ? " (Confed)" : "", tmp->subs[SUB_CALLWAIT].linear ? " (Linear)" : "");
- ast_cli(fd, "Threeway: %s%s%s\n", tmp->subs[SUB_THREEWAY].owner ? tmp->subs[SUB_THREEWAY].owner->name : "<None>", tmp->subs[SUB_THREEWAY].inthreeway ? " (Confed)" : "", tmp->subs[SUB_THREEWAY].linear ? " (Linear)" : "");
- ast_cli(fd, "Confno: %d\n", tmp->confno);
- ast_cli(fd, "Propagated Conference: %d\n", tmp->propconfno);
- ast_cli(fd, "Real in conference: %d\n", tmp->inconference);
- ast_cli(fd, "DSP: %s\n", tmp->dsp ? "yes" : "no");
- ast_cli(fd, "Relax DTMF: %s\n", tmp->dtmfrelax ? "yes" : "no");
- ast_cli(fd, "Dialing/CallwaitCAS: %d/%d\n", tmp->dialing, tmp->callwaitcas);
- ast_cli(fd, "Default law: %s\n", tmp->law == DAHDI_LAW_MULAW ? "ulaw" : tmp->law == DAHDI_LAW_ALAW ? "alaw" : "unknown");
- ast_cli(fd, "Fax Handled: %s\n", tmp->faxhandled ? "yes" : "no");
- ast_cli(fd, "Pulse phone: %s\n", tmp->pulsedial ? "yes" : "no");
- ast_cli(fd, "Echo Cancellation: %d taps%s, currently %s\n", tmp->echocancel, tmp->echocanbridged ? "" : " unless TDM bridged", tmp->echocanon ? "ON" : "OFF");
- if (tmp->master)
- ast_cli(fd, "Master Channel: %d\n", tmp->master->channel);
- for (x = 0; x < MAX_SLAVES; x++) {
- if (tmp->slaves[x])
- ast_cli(fd, "Slave Channel: %d\n", tmp->slaves[x]->channel);
- }
-#ifdef HAVE_PRI
- if (tmp->pri) {
- ast_cli(fd, "PRI Flags: ");
- if (tmp->resetting)
- ast_cli(fd, "Resetting ");
- if (tmp->call)
- ast_cli(fd, "Call ");
- if (tmp->bearer)
- ast_cli(fd, "Bearer ");
- ast_cli(fd, "\n");
- if (tmp->logicalspan)
- ast_cli(fd, "PRI Logical Span: %d\n", tmp->logicalspan);
- else
- ast_cli(fd, "PRI Logical Span: Implicit\n");
- }
-
-#endif
- memset(&ci, 0, sizeof(ci));
- ps.channo = tmp->channel;
- if (tmp->subs[SUB_REAL].dfd > -1) {
- if (!ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GETCONF, &ci)) {
- ast_cli(fd, "Actual Confinfo: Num/%d, Mode/0x%04x\n", ci.confno, ci.confmode);
- }
-#ifdef DAHDI_GETCONFMUTE
- if (!ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GETCONFMUTE, &x)) {
- ast_cli(fd, "Actual Confmute: %s\n", x ? "Yes" : "No");
- }
-#endif
- if (ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &ps) < 0) {
- ast_log(LOG_WARNING, "Failed to get parameters on channel %d: %s\n", tmp->channel, strerror(errno));
- } else {
- ast_cli(fd, "Hookstate (FXS only): %s\n", ps.rxisoffhook ? "Offhook" : "Onhook");
- }
- }
- ast_mutex_unlock(lock);
- return RESULT_SUCCESS;
- }
- tmp = tmp->next;
- }
-
- ast_cli(fd, "Unable to find given channel %d\n", channel);
- ast_mutex_unlock(lock);
- return RESULT_FAILURE;
-}
-
-static char dahdi_show_cadences_usage[] =
-"Usage: dahdi show cadences\n"
-" Shows all cadences currently defined\n";
-
-static int handle_dahdi_show_cadences(int fd, int argc, char *argv[])
-{
- int i, j;
- for (i = 0; i < num_cadence; i++) {
- char output[1024];
- char tmp[16], tmp2[64];
- snprintf(tmp, sizeof(tmp), "r%d: ", i + 1);
- term_color(output, tmp, COLOR_GREEN, COLOR_BLACK, sizeof(output));
-
- for (j = 0; j < 16; j++) {
- if (cadences[i].ringcadence[j] == 0)
- break;
- snprintf(tmp, sizeof(tmp), "%d", cadences[i].ringcadence[j]);
- if (cidrings[i] * 2 - 1 == j)
- term_color(tmp2, tmp, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp2) - 1);
- else
- term_color(tmp2, tmp, COLOR_GREEN, COLOR_BLACK, sizeof(tmp2) - 1);
- if (j != 0)
- strncat(output, ",", sizeof(output) - strlen(output) - 1);
- strncat(output, tmp2, sizeof(output) - strlen(output) - 1);
- }
- ast_cli(fd,"%s\n",output);
- }
- return 0;
-}
-
-/* Based on irqmiss.c */
-static int dahdi_show_status(int fd, int argc, char *argv[]) {
- #define FORMAT "%-40.40s %-10.10s %-10d %-10d %-10d\n"
- #define FORMAT2 "%-40.40s %-10.10s %-10.10s %-10.10s %-10.10s\n"
-
- int span;
- int res;
- char alarms[50];
-
- int ctl;
- struct dahdi_spaninfo s;
-
- if ((ctl = open(DAHDI_FILE_CTL, O_RDWR)) < 0) {
- ast_log(LOG_WARNING, "Unable to open " DAHDI_FILE_CTL ": %s\n", strerror(errno));
- ast_cli(fd, "No " DAHDI_NAME " interface found.\n");
- return RESULT_FAILURE;
- }
- ast_cli(fd, FORMAT2, "Description", "Alarms", "IRQ", "bpviol", "CRC4");
-
- for (span = 1; span < DAHDI_MAX_SPANS; ++span) {
- s.spanno = span;
- res = ioctl(ctl, DAHDI_SPANSTAT, &s);
- if (res) {
- continue;
- }
- alarms[0] = '\0';
- if (s.alarms > 0) {
- if (s.alarms & DAHDI_ALARM_BLUE)
- strcat(alarms, "BLU/");
- if (s.alarms & DAHDI_ALARM_YELLOW)
- strcat(alarms, "YEL/");
- if (s.alarms & DAHDI_ALARM_RED)
- strcat(alarms, "RED/");
- if (s.alarms & DAHDI_ALARM_LOOPBACK)
- strcat(alarms, "LB/");
- if (s.alarms & DAHDI_ALARM_RECOVER)
- strcat(alarms, "REC/");
- if (s.alarms & DAHDI_ALARM_NOTOPEN)
- strcat(alarms, "NOP/");
- if (!strlen(alarms))
- strcat(alarms, "UUU/");
- if (strlen(alarms)) {
- /* Strip trailing / */
- alarms[strlen(alarms) - 1] = '\0';
- }
- } else {
- if (s.numchans)
- strcpy(alarms, "OK");
- else
- strcpy(alarms, "UNCONFIGURED");
- }
-
- ast_cli(fd, FORMAT, s.desc, alarms, s.irqmisses, s.bpvcount, s.crc4count);
- }
- close(ctl);
-
- return RESULT_SUCCESS;
-#undef FORMAT
-#undef FORMAT2
-}
-
-static char show_channels_usage[] =
- "Usage: dahdi show channels\n"
- " Shows a list of available channels\n";
-
-static char show_channel_usage[] =
- "Usage: dahdi show channel <chan num>\n"
- " Detailed information about a given channel\n";
-
-static char dahdi_show_status_usage[] =
- "Usage: dahdi show status\n"
- " Shows a list of DAHDI cards with status\n";
-
-static char destroy_channel_usage[] =
- "Usage: dahdi destroy channel <chan num>\n"
- " DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING. Immediately removes a given channel, whether it is in use or not\n";
-
-static char dahdi_restart_usage[] =
- "Usage: dahdi restart\n"
- " Restarts the DAHDI channels: destroys them all and then\n"
- " re-reads them from chan_dahdi.conf.\n"
- " Note that this will STOP any running CALL on DAHDI channels.\n"
- "";
-
-static struct ast_cli_entry cli_zap_show_cadences_deprecated = {
- { "zap", "show", "cadences", NULL },
- handle_dahdi_show_cadences, NULL,
- NULL };
-
-static struct ast_cli_entry cli_zap_show_channels_deprecated = {
- { "zap", "show", "channels", NULL },
- dahdi_show_channels, NULL,
- NULL };
-
-static struct ast_cli_entry cli_zap_show_channel_deprecated = {
- { "zap", "show", "channel", NULL },
- dahdi_show_channel, NULL,
- NULL };
-
-static struct ast_cli_entry cli_zap_destroy_channel_deprecated = {
- { "zap", "destroy", "channel", NULL },
- dahdi_destroy_channel, NULL,
- NULL };
-
-static struct ast_cli_entry cli_zap_restart_deprecated = {
- { "zap", "restart", NULL },
- dahdi_restart_cmd, NULL,
- NULL };
-
-static struct ast_cli_entry cli_zap_show_status_deprecated = {
- { "zap", "show", "status", NULL },
- dahdi_show_status, NULL,
- NULL };
-
-static struct ast_cli_entry dahdi_cli[] = {
- { { "dahdi", "show", "cadences", NULL },
- handle_dahdi_show_cadences, "List cadences",
- dahdi_show_cadences_usage, NULL, &cli_zap_show_cadences_deprecated },
-
- { { "dahdi", "show", "channels", NULL},
- dahdi_show_channels, "Show active DAHDI channels",
- show_channels_usage, NULL, &cli_zap_show_channels_deprecated },
-
- { { "dahdi", "show", "channel", NULL},
- dahdi_show_channel, "Show information on a channel",
- show_channel_usage, NULL, &cli_zap_show_channel_deprecated },
-
- { { "dahdi", "destroy", "channel", NULL},
- dahdi_destroy_channel, "Destroy a channel",
- destroy_channel_usage, NULL, &cli_zap_destroy_channel_deprecated },
-
- { { "dahdi", "restart", NULL},
- dahdi_restart_cmd, "Fully restart DAHDI channels",
- dahdi_restart_usage, NULL, &cli_zap_restart_deprecated },
-
- { { "dahdi", "show", "status", NULL},
- dahdi_show_status, "Show all DAHDI cards status",
- dahdi_show_status_usage, NULL, &cli_zap_show_status_deprecated },
-};
-
-#define TRANSFER 0
-#define HANGUP 1
-
-static int dahdi_fake_event(struct dahdi_pvt *p, int mode)
-{
- if (p) {
- switch (mode) {
- case TRANSFER:
- p->fake_event = DAHDI_EVENT_WINKFLASH;
- break;
- case HANGUP:
- p->fake_event = DAHDI_EVENT_ONHOOK;
- break;
- default:
- ast_log(LOG_WARNING, "I don't know how to handle transfer event with this: %d on channel %s\n",mode, p->owner->name);
- }
- }
- return 0;
-}
-static struct dahdi_pvt *find_channel(int channel)
-{
- struct dahdi_pvt *p = iflist;
- while (p) {
- if (p->channel == channel) {
- break;
- }
- p = p->next;
- }
- return p;
-}
-
-#define local_astman_ack(s, m, msg, zap) do { if (!zap) astman_send_ack(s, m, "DAHDI" msg); else astman_send_ack(s, m, "Zap" msg); } while (0)
-#define local_astman_header(m, hdr, zap) astman_get_header(m, (!zap) ? "DAHDI" hdr : "Zap" hdr)
-
-static int __action_dnd(struct mansession *s, const struct message *m, int zap_mode, int dnd)
-{
- struct dahdi_pvt *p = NULL;
- const char *channel = local_astman_header(m, "Channel", zap_mode);
-
- if (ast_strlen_zero(channel)) {
- astman_send_error(s, m, "No channel specified");
- return 0;
- }
- if (!(p = find_channel(atoi(channel)))) {
- astman_send_error(s, m, "No such channel");
- return 0;
- }
- p->dnd = dnd;
- local_astman_ack(s, m, "DND", zap_mode);
-
- return 0;
-}
-
-static int zap_action_dndon(struct mansession *s, const struct message *m)
-{
- return __action_dnd(s, m, 1, 1);
-}
-
-static int dahdi_action_dndon(struct mansession *s, const struct message *m)
-{
- return __action_dnd(s, m, 0, 1);
-}
-
-static int zap_action_dndoff(struct mansession *s, const struct message *m)
-{
- return __action_dnd(s, m, 1, 0);
-}
-
-static int dahdi_action_dndoff(struct mansession *s, const struct message *m)
-{
- return __action_dnd(s, m, 0, 0);
-}
-
-static int __action_transfer(struct mansession *s, const struct message *m, int zap_mode)
-{
- struct dahdi_pvt *p = NULL;
- const char *channel = local_astman_header(m, "Channel", zap_mode);
-
- if (ast_strlen_zero(channel)) {
- astman_send_error(s, m, "No channel specified");
- return 0;
- }
- if (!(p = find_channel(atoi(channel)))) {
- astman_send_error(s, m, "No such channel");
- return 0;
- }
- dahdi_fake_event(p,TRANSFER);
- local_astman_ack(s, m, "Transfer", zap_mode);
-
- return 0;
-}
-
-static int zap_action_transfer(struct mansession *s, const struct message *m)
-{
- return __action_transfer(s, m, 1);
-}
-
-static int dahdi_action_transfer(struct mansession *s, const struct message *m)
-{
- return __action_transfer(s, m, 0);
-}
-
-static int __action_transferhangup(struct mansession *s, const struct message *m, int zap_mode)
-{
- struct dahdi_pvt *p = NULL;
- const char *channel = local_astman_header(m, "Channel", zap_mode);
-
- if (ast_strlen_zero(channel)) {
- astman_send_error(s, m, "No channel specified");
- return 0;
- }
- if (!(p = find_channel(atoi(channel)))) {
- astman_send_error(s, m, "No such channel");
- return 0;
- }
- dahdi_fake_event(p, HANGUP);
- local_astman_ack(s, m, "Hangup", zap_mode);
- return 0;
-}
-
-static int zap_action_transferhangup(struct mansession *s, const struct message *m)
-{
- return __action_transferhangup(s, m, 1);
-}
-
-static int dahdi_action_transferhangup(struct mansession *s, const struct message *m)
-{
- return __action_transferhangup(s, m, 0);
-}
-
-static int __action_dialoffhook(struct mansession *s, const struct message *m, int zap_mode)
-{
- struct dahdi_pvt *p = NULL;
- const char *channel = local_astman_header(m, "Channel", zap_mode);
- const char *number = astman_get_header(m, "Number");
- int i;
-
- if (ast_strlen_zero(channel)) {
- astman_send_error(s, m, "No channel specified");
- return 0;
- }
- if (ast_strlen_zero(number)) {
- astman_send_error(s, m, "No number specified");
- return 0;
- }
- if (!(p = find_channel(atoi(channel)))) {
- astman_send_error(s, m, "No such channel");
- return 0;
- }
- if (!p->owner) {
- astman_send_error(s, m, "Channel does not have an owner");
- return 0;
- }
- for (i = 0; i < strlen(number); i++) {
- struct ast_frame f = { AST_FRAME_DTMF, number[i] };
-
- dahdi_queue_frame(p, &f, NULL);
- }
- local_astman_ack(s, m, "DialOffHook", zap_mode);
-
- return 0;
-}
-
-static int zap_action_dialoffhook(struct mansession *s, const struct message *m)
-{
- return __action_dialoffhook(s, m, 1);
-}
-
-static int dahdi_action_dialoffhook(struct mansession *s, const struct message *m)
-{
- return __action_dialoffhook(s, m, 0);
-}
-
-static int __action_showchannels(struct mansession *s, const struct message *m, int zap_mode)
-{
- struct dahdi_pvt *tmp = NULL;
- const char *id = astman_get_header(m, "ActionID");
- char idText[256] = "";
-
- local_astman_ack(s, m, " channel status will follow", zap_mode);
- if (!ast_strlen_zero(id))
- snprintf(idText, sizeof(idText) - 1, "ActionID: %s\r\n", id);
-
- ast_mutex_lock(&iflock);
-
- tmp = iflist;
- while (tmp) {
- if (tmp->channel > 0) {
- int alarm = get_alarms(tmp);
- astman_append(s,
- "Event: %sShowChannels\r\n"
- "Channel: %d\r\n"
- "Signalling: %s\r\n"
- "Context: %s\r\n"
- "DND: %s\r\n"
- "Alarm: %s\r\n"
- "%s"
- "\r\n",
- dahdi_chan_name,
- tmp->channel, sig2str(tmp->sig), tmp->context,
- tmp->dnd ? "Enabled" : "Disabled",
- alarm2str(alarm), idText);
- }
-
- tmp = tmp->next;
- }
-
- ast_mutex_unlock(&iflock);
-
- astman_append(s,
- "Event: %sShowChannelsComplete\r\n"
- "%s"
- "\r\n",
- dahdi_chan_name,
- idText);
- return 0;
-}
-
-static int zap_action_showchannels(struct mansession *s, const struct message *m)
-{
- return __action_showchannels(s, m, 1);
-}
-
-static int dahdi_action_showchannels(struct mansession *s, const struct message *m)
-{
- return __action_showchannels(s, m, 0);
-}
-
-static int __action_restart(struct mansession *s, const struct message *m, int zap_mode)
-{
- if (dahdi_restart() != 0) {
- if (zap_mode) {
- astman_send_error(s, m, "Failed to restart Zap");
- } else {
- astman_send_error(s, m, "Failed to restart DAHDI");
- }
- return 1;
- }
- local_astman_ack(s, m, "Restart: Success", zap_mode);
- return 0;
-}
-
-static int zap_action_restart(struct mansession *s, const struct message *m)
-{
- return __action_restart(s, m, 1);
-}
-
-static int dahdi_action_restart(struct mansession *s, const struct message *m)
-{
- return __action_restart(s, m, 0);
-}
-
-#define local_astman_unregister(a) do { \
- if (*dahdi_chan_mode == CHAN_DAHDI_PLUS_ZAP_MODE) { \
- ast_manager_unregister("DAHDI" a); \
- } \
- ast_manager_unregister("Zap" a); \
- } while (0)
-
-static int __unload_module(void)
-{
- struct dahdi_pvt *p;
-
-#ifdef HAVE_PRI
- int i, j;
- for (i = 0; i < NUM_SPANS; i++) {
- if (pris[i].master != AST_PTHREADT_NULL)
- pthread_cancel(pris[i].master);
- }
- ast_cli_unregister_multiple(dahdi_pri_cli, sizeof(dahdi_pri_cli) / sizeof(struct ast_cli_entry));
-
- if (*dahdi_chan_mode == CHAN_DAHDI_PLUS_ZAP_MODE) {
- ast_unregister_application(dahdi_send_keypad_facility_app);
- }
- ast_unregister_application(zap_send_keypad_facility_app);
-#endif
- ast_cli_unregister_multiple(dahdi_cli, sizeof(dahdi_cli) / sizeof(struct ast_cli_entry));
- local_astman_unregister("DialOffHook");
- local_astman_unregister("Hangup");
- local_astman_unregister("Transfer");
- local_astman_unregister("DNDoff");
- local_astman_unregister("DNDon");
- local_astman_unregister("ShowChannels");
- local_astman_unregister("Restart");
- ast_channel_unregister(chan_tech);
- ast_mutex_lock(&iflock);
- /* Hangup all interfaces if they have an owner */
- p = iflist;
- while (p) {
- if (p->owner)
- ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
- p = p->next;
- }
- ast_mutex_unlock(&iflock);
- ast_mutex_lock(&monlock);
- if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP) && (monitor_thread != AST_PTHREADT_NULL)) {
- pthread_cancel(monitor_thread);
- pthread_kill(monitor_thread, SIGURG);
- pthread_join(monitor_thread, NULL);
- }
- monitor_thread = AST_PTHREADT_STOP;
- ast_mutex_unlock(&monlock);
-
- destroy_all_channels();
-#ifdef HAVE_PRI
- for (i = 0; i < NUM_SPANS; i++) {
- if (pris[i].master && (pris[i].master != AST_PTHREADT_NULL))
- pthread_join(pris[i].master, NULL);
- for (j = 0; j < NUM_DCHANS; j++) {
- dahdi_close_pri_fd(&(pris[i]), j);
- }
- }
-#endif
- ast_cond_destroy(&ss_thread_complete);
- return 0;
-}
-
-static int unload_module(void)
-{
-#ifdef HAVE_PRI
- int y;
- for (y = 0; y < NUM_SPANS; y++)
- ast_mutex_destroy(&pris[y].lock);
-#endif
- return __unload_module();
-}
-
-static int build_channels(struct dahdi_chan_conf *conf, int iscrv, const char *value, int reload, int lineno, int *found_pseudo)
-{
- char *c, *chan;
- int x, start, finish;
- struct dahdi_pvt *tmp;
-#ifdef HAVE_PRI
- struct dahdi_pri *pri;
- int trunkgroup, y;
-#endif
-
- if ((reload == 0) && (conf->chan.sig < 0)) {
- ast_log(LOG_ERROR, "Signalling must be specified before any channels are.\n");
- return -1;
- }
-
- c = ast_strdupa(value);
-
-#ifdef HAVE_PRI
- pri = NULL;
- if (iscrv) {
- if (sscanf(c, "%d:%n", &trunkgroup, &y) != 1) {
- ast_log(LOG_WARNING, "CRV must begin with trunkgroup followed by a colon at line %d\n", lineno);
- return -1;
- }
- if (trunkgroup < 1) {
- ast_log(LOG_WARNING, "CRV trunk group must be a positive number at line %d\n", lineno);
- return -1;
- }
- c += y;
- for (y = 0; y < NUM_SPANS; y++) {
- if (pris[y].trunkgroup == trunkgroup) {
- pri = pris + y;
- break;
- }
- }
- if (!pri) {
- ast_log(LOG_WARNING, "No such trunk group %d at CRV declaration at line %d\n", trunkgroup, lineno);
- return -1;
- }
- }
-#endif
-
- while ((chan = strsep(&c, ","))) {
- if (sscanf(chan, "%d-%d", &start, &finish) == 2) {
- /* Range */
- } else if (sscanf(chan, "%d", &start)) {
- /* Just one */
- finish = start;
- } else if (!strcasecmp(chan, "pseudo")) {
- finish = start = CHAN_PSEUDO;
- if (found_pseudo)
- *found_pseudo = 1;
- } else {
- ast_log(LOG_ERROR, "Syntax error parsing '%s' at '%s'\n", value, chan);
- return -1;
- }
- if (finish < start) {
- ast_log(LOG_WARNING, "Sillyness: %d < %d\n", start, finish);
- x = finish;
- finish = start;
- start = x;
- }
-
- for (x = start; x <= finish; x++) {
-#ifdef HAVE_PRI
- tmp = mkintf(x, conf, pri, reload);
-#else
- tmp = mkintf(x, conf, NULL, reload);
-#endif
-
- if (tmp) {
- if (option_verbose > 2) {
-#ifdef HAVE_PRI
- if (pri)
- ast_verbose(VERBOSE_PREFIX_3 "%s CRV %d:%d, %s signalling\n", reload ? "Reconfigured" : "Registered", trunkgroup, x, sig2str(tmp->sig));
- else
-#endif
- ast_verbose(VERBOSE_PREFIX_3 "%s channel %d, %s signalling\n", reload ? "Reconfigured" : "Registered", x, sig2str(tmp->sig));
- }
- } else {
- ast_log(LOG_ERROR, "Unable to %s channel '%s'\n",
- (reload == 1) ? "reconfigure" : "register", value);
- return -1;
- }
- }
- }
-
- return 0;
-}
-
-/** The length of the parameters list of 'dahdichan'.
- * \todo Move definition of MAX_CHANLIST_LEN to a proper place. */
-#define MAX_CHANLIST_LEN 80
-static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct ast_variable *v, int reload, int skipchannels)
-{
- struct dahdi_pvt *tmp;
- int y;
- int found_pseudo = 0;
- char dahdichan[MAX_CHANLIST_LEN] = {};
-
- for (; v; v = v->next) {
- if (!ast_jb_read_conf(&global_jbconf, v->name, v->value))
- continue;
-
- /* Create the interface list */
- if (!strcasecmp(v->name, "channel")
-#ifdef HAVE_PRI
- || !strcasecmp(v->name, "crv")
-#endif
- ) {
- int iscrv;
- if (skipchannels)
- continue;
- iscrv = !strcasecmp(v->name, "crv");
- if (build_channels(confp, iscrv, v->value, reload, v->lineno, &found_pseudo))
- return -1;
- } else if (!strcasecmp(v->name, "buffers")) {
- int res;
- char policy[21] = "";
-
- res = sscanf(v->value, "%d,%20s", &confp->chan.buf_no, policy);
- if (res != 2) {
- ast_log(LOG_WARNING, "Parsing buffers option data failed, using defaults.\n");
- confp->chan.buf_no = numbufs;
- continue;
- }
- if (confp->chan.buf_no < 0)
- confp->chan.buf_no = numbufs;
- if (!strcasecmp(policy, "full")) {
- confp->chan.buf_policy = DAHDI_POLICY_WHEN_FULL;
- } else if (!strcasecmp(policy, "immediate")) {
- confp->chan.buf_policy = DAHDI_POLICY_IMMEDIATE;
- } else {
- ast_log(LOG_WARNING, "Invalid policy name given (%s).\n", policy);
- }
- } else if (!strcasecmp(v->name, "zapchan") || !strcasecmp(v->name, "dahdichan")) {
- ast_copy_string(dahdichan, v->value, sizeof(dahdichan));
- if (v->name[0] == 'z' || v->name[0] == 'Z') {
- ast_log(LOG_WARNING, "Option zapchan has been deprecated in favor of dahdichan (found in [%s])\n", cat);
- }
- } else if (!strcasecmp(v->name, "usedistinctiveringdetection")) {
- if (ast_true(v->value))
- confp->chan.usedistinctiveringdetection = 1;
- } else if (!strcasecmp(v->name, "distinctiveringaftercid")) {
- if (ast_true(v->value))
- distinctiveringaftercid = 1;
- } else if (!strcasecmp(v->name, "dring1context")) {
- ast_copy_string(drings.ringContext[0].contextData, v->value, sizeof(drings.ringContext[0].contextData));
- } else if (!strcasecmp(v->name, "dring2context")) {
- ast_copy_string(drings.ringContext[1].contextData, v->value, sizeof(drings.ringContext[1].contextData));
- } else if (!strcasecmp(v->name, "dring3context")) {
- ast_copy_string(drings.ringContext[2].contextData, v->value, sizeof(drings.ringContext[2].contextData));
- } else if (!strcasecmp(v->name, "dring1")) {
- sscanf(v->value, "%d,%d,%d", &drings.ringnum[0].ring[0], &drings.ringnum[0].ring[1], &drings.ringnum[0].ring[2]);
- } else if (!strcasecmp(v->name, "dring2")) {
- sscanf(v->value, "%d,%d,%d", &drings.ringnum[1].ring[0], &drings.ringnum[1].ring[1], &drings.ringnum[1].ring[2]);
- } else if (!strcasecmp(v->name, "dring3")) {
- sscanf(v->value, "%d,%d,%d", &drings.ringnum[2].ring[0], &drings.ringnum[2].ring[1], &drings.ringnum[2].ring[2]);
- } else if (!strcasecmp(v->name, "usecallerid")) {
- confp->chan.use_callerid = ast_true(v->value);
- } else if (!strcasecmp(v->name, "cidsignalling")) {
- if (!strcasecmp(v->value, "bell"))
- confp->chan.cid_signalling = CID_SIG_BELL;
- else if (!strcasecmp(v->value, "v23"))
- confp->chan.cid_signalling = CID_SIG_V23;
- else if (!strcasecmp(v->value, "dtmf"))
- confp->chan.cid_signalling = CID_SIG_DTMF;
- else if (!strcasecmp(v->value, "smdi"))
- confp->chan.cid_signalling = CID_SIG_SMDI;
- else if (!strcasecmp(v->value, "v23_jp"))
- confp->chan.cid_signalling = CID_SIG_V23_JP;
- else if (ast_true(v->value))
- confp->chan.cid_signalling = CID_SIG_BELL;
- } else if (!strcasecmp(v->name, "cidstart")) {
- if (!strcasecmp(v->value, "ring"))
- confp->chan.cid_start = CID_START_RING;
- else if (!strcasecmp(v->value, "polarity"))
- confp->chan.cid_start = CID_START_POLARITY;
- else if (ast_true(v->value))
- confp->chan.cid_start = CID_START_RING;
- } else if (!strcasecmp(v->name, "threewaycalling")) {
- confp->chan.threewaycalling = ast_true(v->value);
- } else if (!strcasecmp(v->name, "cancallforward")) {
- confp->chan.cancallforward = ast_true(v->value);
- } else if (!strcasecmp(v->name, "relaxdtmf")) {
- if (ast_true(v->value))
- confp->chan.dtmfrelax = DSP_DIGITMODE_RELAXDTMF;
- else
- confp->chan.dtmfrelax = 0;
- } else if (!strcasecmp(v->name, "mailbox")) {
- ast_copy_string(confp->chan.mailbox, v->value, sizeof(confp->chan.mailbox));
- } else if (!strcasecmp(v->name, "hasvoicemail")) {
- if (ast_true(v->value) && ast_strlen_zero(confp->chan.mailbox)) {
- ast_copy_string(confp->chan.mailbox, cat, sizeof(confp->chan.mailbox));
- }
- } else if (!strcasecmp(v->name, "adsi")) {
- confp->chan.adsi = ast_true(v->value);
- } else if (!strcasecmp(v->name, "usesmdi")) {
- confp->chan.use_smdi = ast_true(v->value);
- } else if (!strcasecmp(v->name, "smdiport")) {
- ast_copy_string(confp->smdi_port, v->value, sizeof(confp->smdi_port));
- } else if (!strcasecmp(v->name, "transfer")) {
- confp->chan.transfer = ast_true(v->value);
- } else if (!strcasecmp(v->name, "canpark")) {
- confp->chan.canpark = ast_true(v->value);
- } else if (!strcasecmp(v->name, "echocancelwhenbridged")) {
- confp->chan.echocanbridged = ast_true(v->value);
- } else if (!strcasecmp(v->name, "busydetect")) {
- confp->chan.busydetect = ast_true(v->value);
- } else if (!strcasecmp(v->name, "busycount")) {
- confp->chan.busycount = atoi(v->value);
- } else if (!strcasecmp(v->name, "busypattern")) {
- if (sscanf(v->value, "%d,%d", &confp->chan.busy_tonelength, &confp->chan.busy_quietlength) != 2) {
- ast_log(LOG_ERROR, "busypattern= expects busypattern=tonelength,quietlength\n");
- }
- } else if (!strcasecmp(v->name, "callprogress")) {
- if (ast_true(v->value))
- confp->chan.callprogress |= 1;
- else
- confp->chan.callprogress &= ~1;
- } else if (!strcasecmp(v->name, "faxdetect")) {
- if (!strcasecmp(v->value, "incoming")) {
- confp->chan.callprogress |= 4;
- confp->chan.callprogress &= ~2;
- } else if (!strcasecmp(v->value, "outgoing")) {
- confp->chan.callprogress &= ~4;
- confp->chan.callprogress |= 2;
- } else if (!strcasecmp(v->value, "both") || ast_true(v->value))
- confp->chan.callprogress |= 6;
- else
- confp->chan.callprogress &= ~6;
- } else if (!strcasecmp(v->name, "echocancel")) {
- if (!ast_strlen_zero(v->value)) {
- y = atoi(v->value);
- } else
- y = 0;
- if ((y == 32) || (y == 64) || (y == 128) || (y == 256) || (y == 512) || (y == 1024))
- confp->chan.echocancel = y;
- else {
- confp->chan.echocancel = ast_true(v->value);
- if (confp->chan.echocancel)
- confp->chan.echocancel=128;
- }
- } else if (!strcasecmp(v->name, "echotraining")) {
- if (sscanf(v->value, "%d", &y) == 1) {
- if ((y < 10) || (y > 4000)) {
- ast_log(LOG_WARNING, "Echo training time must be within the range of 10 to 4000 ms at line %d\n", v->lineno);
- } else {
- confp->chan.echotraining = y;
- }
- } else if (ast_true(v->value)) {
- confp->chan.echotraining = 400;
- } else
- confp->chan.echotraining = 0;
- } else if (!strcasecmp(v->name, "hidecallerid")) {
- confp->chan.hidecallerid = ast_true(v->value);
- } else if (!strcasecmp(v->name, "hidecalleridname")) {
- confp->chan.hidecalleridname = ast_true(v->value);
- } else if (!strcasecmp(v->name, "pulsedial")) {
- confp->chan.pulse = ast_true(v->value);
- } else if (!strcasecmp(v->name, "callreturn")) {
- confp->chan.callreturn = ast_true(v->value);
- } else if (!strcasecmp(v->name, "callwaiting")) {
- confp->chan.callwaiting = ast_true(v->value);
- } else if (!strcasecmp(v->name, "callwaitingcallerid")) {
- confp->chan.callwaitingcallerid = ast_true(v->value);
- } else if (!strcasecmp(v->name, "context")) {
- ast_copy_string(confp->chan.context, v->value, sizeof(confp->chan.context));
- } else if (!strcasecmp(v->name, "language")) {
- ast_copy_string(confp->chan.language, v->value, sizeof(confp->chan.language));
- } else if (!strcasecmp(v->name, "progzone")) {
- ast_copy_string(progzone, v->value, sizeof(progzone));
- } else if (!strcasecmp(v->name, "mohinterpret")
- ||!strcasecmp(v->name, "musiconhold") || !strcasecmp(v->name, "musicclass")) {
- ast_copy_string(confp->chan.mohinterpret, v->value, sizeof(confp->chan.mohinterpret));
- } else if (!strcasecmp(v->name, "mohsuggest")) {
- ast_copy_string(confp->chan.mohsuggest, v->value, sizeof(confp->chan.mohsuggest));
- } else if (!strcasecmp(v->name, "stripmsd")) {
- confp->chan.stripmsd = atoi(v->value);
- } else if (!strcasecmp(v->name, "jitterbuffers")) {
- numbufs = atoi(v->value);
- } else if (!strcasecmp(v->name, "group")) {
- confp->chan.group = ast_get_group(v->value);
- } else if (!strcasecmp(v->name, "callgroup")) {
- confp->chan.callgroup = ast_get_group(v->value);
- } else if (!strcasecmp(v->name, "pickupgroup")) {
- confp->chan.pickupgroup = ast_get_group(v->value);
- } else if (!strcasecmp(v->name, "immediate")) {
- confp->chan.immediate = ast_true(v->value);
- } else if (!strcasecmp(v->name, "transfertobusy")) {
- confp->chan.transfertobusy = ast_true(v->value);
- } else if (!strcasecmp(v->name, "rxgain")) {
- if (sscanf(v->value, "%f", &confp->chan.rxgain) != 1) {
- ast_log(LOG_WARNING, "Invalid rxgain: %s\n", v->value);
- }
- } else if (!strcasecmp(v->name, "txgain")) {
- if (sscanf(v->value, "%f", &confp->chan.txgain) != 1) {
- ast_log(LOG_WARNING, "Invalid txgain: %s\n", v->value);
- }
- } else if (!strcasecmp(v->name, "tonezone")) {
- if (sscanf(v->value, "%d", &confp->chan.tonezone) != 1) {
- ast_log(LOG_WARNING, "Invalid tonezone: %s\n", v->value);
- }
- } else if (!strcasecmp(v->name, "callerid")) {
- if (!strcasecmp(v->value, "asreceived")) {
- confp->chan.cid_num[0] = '\0';
- confp->chan.cid_name[0] = '\0';
- } else {
- ast_callerid_split(v->value, confp->chan.cid_name, sizeof(confp->chan.cid_name), confp->chan.cid_num, sizeof(confp->chan.cid_num));
- }
- } else if (!strcasecmp(v->name, "fullname")) {
- ast_copy_string(confp->chan.cid_name, v->value, sizeof(confp->chan.cid_name));
- } else if (!strcasecmp(v->name, "cid_number")) {
- ast_copy_string(confp->chan.cid_num, v->value, sizeof(confp->chan.cid_num));
- } else if (!strcasecmp(v->name, "useincomingcalleridondahditransfer") || !strcasecmp(v->name, "useincomingcalleridonzaptransfer")) {
- confp->chan.dahditrcallerid = ast_true(v->value);
- if (strstr(v->name, "zap")) {
- ast_log(LOG_WARNING, "Option useincomingcalleridonzaptransfer has been deprecated in favor of useincomingcalleridondahditransfer (in [%s]).\n", cat);
- }
- } else if (!strcasecmp(v->name, "restrictcid")) {
- confp->chan.restrictcid = ast_true(v->value);
- } else if (!strcasecmp(v->name, "usecallingpres")) {
- confp->chan.use_callingpres = ast_true(v->value);
- } else if (!strcasecmp(v->name, "accountcode")) {
- ast_copy_string(confp->chan.accountcode, v->value, sizeof(confp->chan.accountcode));
- } else if (!strcasecmp(v->name, "amaflags")) {
- y = ast_cdr_amaflags2int(v->value);
- if (y < 0)
- ast_log(LOG_WARNING, "Invalid AMA flags: %s at line %d\n", v->value, v->lineno);
- else
- confp->chan.amaflags = y;
- } else if (!strcasecmp(v->name, "polarityonanswerdelay")) {
- confp->chan.polarityonanswerdelay = atoi(v->value);
- } else if (!strcasecmp(v->name, "answeronpolarityswitch")) {
- confp->chan.answeronpolarityswitch = ast_true(v->value);
- } else if (!strcasecmp(v->name, "hanguponpolarityswitch")) {
- confp->chan.hanguponpolarityswitch = ast_true(v->value);
- } else if (!strcasecmp(v->name, "sendcalleridafter")) {
- confp->chan.sendcalleridafter = atoi(v->value);
- } else if (reload != 1){
- if (!strcasecmp(v->name, "signalling")) {
- confp->chan.outsigmod = -1;
- if (!strcasecmp(v->value, "em")) {
- confp->chan.sig = SIG_EM;
- } else if (!strcasecmp(v->value, "em_e1")) {
- confp->chan.sig = SIG_EM_E1;
- } else if (!strcasecmp(v->value, "em_w")) {
- confp->chan.sig = SIG_EMWINK;
- confp->chan.radio = 0;
- } else if (!strcasecmp(v->value, "fxs_ls")) {
- confp->chan.sig = SIG_FXSLS;
- confp->chan.radio = 0;
- } else if (!strcasecmp(v->value, "fxs_gs")) {
- confp->chan.sig = SIG_FXSGS;
- confp->chan.radio = 0;
- } else if (!strcasecmp(v->value, "fxs_ks")) {
- confp->chan.sig = SIG_FXSKS;
- confp->chan.radio = 0;
- } else if (!strcasecmp(v->value, "fxo_ls")) {
- confp->chan.sig = SIG_FXOLS;
- confp->chan.radio = 0;
- } else if (!strcasecmp(v->value, "fxo_gs")) {
- confp->chan.sig = SIG_FXOGS;
- confp->chan.radio = 0;
- } else if (!strcasecmp(v->value, "fxo_ks")) {
- confp->chan.sig = SIG_FXOKS;
- confp->chan.radio = 0;
- } else if (!strcasecmp(v->value, "fxs_rx")) {
- confp->chan.sig = SIG_FXSKS;
- confp->chan.radio = 1;
- } else if (!strcasecmp(v->value, "fxo_rx")) {
- confp->chan.sig = SIG_FXOLS;
- confp->chan.radio = 1;
- } else if (!strcasecmp(v->value, "fxs_tx")) {
- confp->chan.sig = SIG_FXSLS;
- confp->chan.radio = 1;
- } else if (!strcasecmp(v->value, "fxo_tx")) {
- confp->chan.sig = SIG_FXOGS;
- confp->chan.radio = 1;
- } else if (!strcasecmp(v->value, "em_rx")) {
- confp->chan.sig = SIG_EM;
- confp->chan.radio = 1;
- } else if (!strcasecmp(v->value, "em_tx")) {
- confp->chan.sig = SIG_EM;
- confp->chan.radio = 1;
- } else if (!strcasecmp(v->value, "em_rxtx")) {
- confp->chan.sig = SIG_EM;
- confp->chan.radio = 2;
- } else if (!strcasecmp(v->value, "em_txrx")) {
- confp->chan.sig = SIG_EM;
- confp->chan.radio = 2;
- } else if (!strcasecmp(v->value, "sf")) {
- confp->chan.sig = SIG_SF;
- confp->chan.radio = 0;
- } else if (!strcasecmp(v->value, "sf_w")) {
- confp->chan.sig = SIG_SFWINK;
- confp->chan.radio = 0;
- } else if (!strcasecmp(v->value, "sf_featd")) {
- confp->chan.sig = SIG_FEATD;
- confp->chan.radio = 0;
- } else if (!strcasecmp(v->value, "sf_featdmf")) {
- confp->chan.sig = SIG_FEATDMF;
- confp->chan.radio = 0;
- } else if (!strcasecmp(v->value, "sf_featb")) {
- confp->chan.sig = SIG_SF_FEATB;
- confp->chan.radio = 0;
- } else if (!strcasecmp(v->value, "sf")) {
- confp->chan.sig = SIG_SF;
- confp->chan.radio = 0;
- } else if (!strcasecmp(v->value, "sf_rx")) {
- confp->chan.sig = SIG_SF;
- confp->chan.radio = 1;
- } else if (!strcasecmp(v->value, "sf_tx")) {
- confp->chan.sig = SIG_SF;
- confp->chan.radio = 1;
- } else if (!strcasecmp(v->value, "sf_rxtx")) {
- confp->chan.sig = SIG_SF;
- confp->chan.radio = 2;
- } else if (!strcasecmp(v->value, "sf_txrx")) {
- confp->chan.sig = SIG_SF;
- confp->chan.radio = 2;
- } else if (!strcasecmp(v->value, "featd")) {
- confp->chan.sig = SIG_FEATD;
- confp->chan.radio = 0;
- } else if (!strcasecmp(v->value, "featdmf")) {
- confp->chan.sig = SIG_FEATDMF;
- confp->chan.radio = 0;
- } else if (!strcasecmp(v->value, "featdmf_ta")) {
- confp->chan.sig = SIG_FEATDMF_TA;
- confp->chan.radio = 0;
- } else if (!strcasecmp(v->value, "e911")) {
- confp->chan.sig = SIG_E911;
- confp->chan.radio = 0;
- } else if (!strcasecmp(v->value, "fgccama")) {
- confp->chan.sig = SIG_FGC_CAMA;
- confp->chan.radio = 0;
- } else if (!strcasecmp(v->value, "fgccamamf")) {
- confp->chan.sig = SIG_FGC_CAMAMF;
- confp->chan.radio = 0;
- } else if (!strcasecmp(v->value, "featb")) {
- confp->chan.sig = SIG_FEATB;
- confp->chan.radio = 0;
-#ifdef HAVE_PRI
- } else if (!strcasecmp(v->value, "pri_net")) {
- confp->chan.radio = 0;
- confp->chan.sig = SIG_PRI;
- confp->pri.nodetype = PRI_NETWORK;
- } else if (!strcasecmp(v->value, "pri_cpe")) {
- confp->chan.sig = SIG_PRI;
- confp->chan.radio = 0;
- confp->pri.nodetype = PRI_CPE;
- } else if (!strcasecmp(v->value, "gr303fxoks_net")) {
- confp->chan.sig = SIG_GR303FXOKS;
- confp->chan.radio = 0;
- confp->pri.nodetype = PRI_NETWORK;
- } else if (!strcasecmp(v->value, "gr303fxsks_cpe")) {
- confp->chan.sig = SIG_GR303FXSKS;
- confp->chan.radio = 0;
- confp->pri.nodetype = PRI_CPE;
-#endif
- } else {
- ast_log(LOG_ERROR, "Unknown signalling method '%s'\n", v->value);
- }
- } else if (!strcasecmp(v->name, "outsignalling")) {
- if (!strcasecmp(v->value, "em")) {
- confp->chan.outsigmod = SIG_EM;
- } else if (!strcasecmp(v->value, "em_e1")) {
- confp->chan.outsigmod = SIG_EM_E1;
- } else if (!strcasecmp(v->value, "em_w")) {
- confp->chan.outsigmod = SIG_EMWINK;
- } else if (!strcasecmp(v->value, "sf")) {
- confp->chan.outsigmod = SIG_SF;
- } else if (!strcasecmp(v->value, "sf_w")) {
- confp->chan.outsigmod = SIG_SFWINK;
- } else if (!strcasecmp(v->value, "sf_featd")) {
- confp->chan.outsigmod = SIG_FEATD;
- } else if (!strcasecmp(v->value, "sf_featdmf")) {
- confp->chan.outsigmod = SIG_FEATDMF;
- } else if (!strcasecmp(v->value, "sf_featb")) {
- confp->chan.outsigmod = SIG_SF_FEATB;
- } else if (!strcasecmp(v->value, "sf")) {
- confp->chan.outsigmod = SIG_SF;
- } else if (!strcasecmp(v->value, "featd")) {
- confp->chan.outsigmod = SIG_FEATD;
- } else if (!strcasecmp(v->value, "featdmf")) {
- confp->chan.outsigmod = SIG_FEATDMF;
- } else if (!strcasecmp(v->value, "featdmf_ta")) {
- confp->chan.outsigmod = SIG_FEATDMF_TA;
- } else if (!strcasecmp(v->value, "e911")) {
- confp->chan.outsigmod = SIG_E911;
- } else if (!strcasecmp(v->value, "fgccama")) {
- confp->chan.outsigmod = SIG_FGC_CAMA;
- } else if (!strcasecmp(v->value, "fgccamamf")) {
- confp->chan.outsigmod = SIG_FGC_CAMAMF;
- } else if (!strcasecmp(v->value, "featb")) {
- confp->chan.outsigmod = SIG_FEATB;
- } else {
- ast_log(LOG_ERROR, "Unknown signalling method '%s'\n", v->value);
- }
-#ifdef HAVE_PRI
- } else if (!strcasecmp(v->name, "pridialplan")) {
- if (!strcasecmp(v->value, "national")) {
- confp->pri.dialplan = PRI_NATIONAL_ISDN + 1;
- } else if (!strcasecmp(v->value, "unknown")) {
- confp->pri.dialplan = PRI_UNKNOWN + 1;
- } else if (!strcasecmp(v->value, "private")) {
- confp->pri.dialplan = PRI_PRIVATE + 1;
- } else if (!strcasecmp(v->value, "international")) {
- confp->pri.dialplan = PRI_INTERNATIONAL_ISDN + 1;
- } else if (!strcasecmp(v->value, "local")) {
- confp->pri.dialplan = PRI_LOCAL_ISDN + 1;
- } else if (!strcasecmp(v->value, "dynamic")) {
- confp->pri.dialplan = -1;
- } else {
- ast_log(LOG_WARNING, "Unknown PRI dialplan '%s' at line %d.\n", v->value, v->lineno);
- }
- } else if (!strcasecmp(v->name, "prilocaldialplan")) {
- if (!strcasecmp(v->value, "national")) {
- confp->pri.localdialplan = PRI_NATIONAL_ISDN + 1;
- } else if (!strcasecmp(v->value, "unknown")) {
- confp->pri.localdialplan = PRI_UNKNOWN + 1;
- } else if (!strcasecmp(v->value, "private")) {
- confp->pri.localdialplan = PRI_PRIVATE + 1;
- } else if (!strcasecmp(v->value, "international")) {
- confp->pri.localdialplan = PRI_INTERNATIONAL_ISDN + 1;
- } else if (!strcasecmp(v->value, "local")) {
- confp->pri.localdialplan = PRI_LOCAL_ISDN + 1;
- } else if (!strcasecmp(v->value, "dynamic")) {
- confp->pri.localdialplan = -1;
- } else {
- ast_log(LOG_WARNING, "Unknown PRI dialplan '%s' at line %d.\n", v->value, v->lineno);
- }
- } else if (!strcasecmp(v->name, "switchtype")) {
- if (!strcasecmp(v->value, "national"))
- confp->pri.switchtype = PRI_SWITCH_NI2;
- else if (!strcasecmp(v->value, "ni1"))
- confp->pri.switchtype = PRI_SWITCH_NI1;
- else if (!strcasecmp(v->value, "dms100"))
- confp->pri.switchtype = PRI_SWITCH_DMS100;
- else if (!strcasecmp(v->value, "4ess"))
- confp->pri.switchtype = PRI_SWITCH_ATT4ESS;
- else if (!strcasecmp(v->value, "5ess"))
- confp->pri.switchtype = PRI_SWITCH_LUCENT5E;
- else if (!strcasecmp(v->value, "euroisdn"))
- confp->pri.switchtype = PRI_SWITCH_EUROISDN_E1;
- else if (!strcasecmp(v->value, "qsig"))
- confp->pri.switchtype = PRI_SWITCH_QSIG;
- else {
- ast_log(LOG_ERROR, "Unknown switchtype '%s'\n", v->value);
- return -1;
- }
- } else if (!strcasecmp(v->name, "nsf")) {
- if (!strcasecmp(v->value, "sdn"))
- confp->pri.nsf = PRI_NSF_SDN;
- else if (!strcasecmp(v->value, "megacom"))
- confp->pri.nsf = PRI_NSF_MEGACOM;
- else if (!strcasecmp(v->value, "tollfreemegacom"))
- confp->pri.nsf = PRI_NSF_TOLL_FREE_MEGACOM;
- else if (!strcasecmp(v->value, "accunet"))
- confp->pri.nsf = PRI_NSF_ACCUNET;
- else if (!strcasecmp(v->value, "none"))
- confp->pri.nsf = PRI_NSF_NONE;
- else {
- ast_log(LOG_WARNING, "Unknown network-specific facility '%s'\n", v->value);
- confp->pri.nsf = PRI_NSF_NONE;
- }
- } else if (!strcasecmp(v->name, "priindication")) {
- if (!strcasecmp(v->value, "outofband"))
- confp->chan.priindication_oob = 1;
- else if (!strcasecmp(v->value, "inband"))
- confp->chan.priindication_oob = 0;
- else
- ast_log(LOG_WARNING, "'%s' is not a valid pri indication value, should be 'inband' or 'outofband' at line %d\n",
- v->value, v->lineno);
- } else if (!strcasecmp(v->name, "priexclusive")) {
- confp->chan.priexclusive = ast_true(v->value);
- } else if (!strcasecmp(v->name, "internationalprefix")) {
- ast_copy_string(confp->pri.internationalprefix, v->value, sizeof(confp->pri.internationalprefix));
- } else if (!strcasecmp(v->name, "nationalprefix")) {
- ast_copy_string(confp->pri.nationalprefix, v->value, sizeof(confp->pri.nationalprefix));
- } else if (!strcasecmp(v->name, "localprefix")) {
- ast_copy_string(confp->pri.localprefix, v->value, sizeof(confp->pri.localprefix));
- } else if (!strcasecmp(v->name, "privateprefix")) {
- ast_copy_string(confp->pri.privateprefix, v->value, sizeof(confp->pri.privateprefix));
- } else if (!strcasecmp(v->name, "unknownprefix")) {
- ast_copy_string(confp->pri.unknownprefix, v->value, sizeof(confp->pri.unknownprefix));
- } else if (!strcasecmp(v->name, "resetinterval")) {
- if (!strcasecmp(v->value, "never"))
- confp->pri.resetinterval = -1;
- else if (atoi(v->value) >= 60)
- confp->pri.resetinterval = atoi(v->value);
- else
- ast_log(LOG_WARNING, "'%s' is not a valid reset interval, should be >= 60 seconds or 'never' at line %d\n",
- v->value, v->lineno);
- } else if (!strcasecmp(v->name, "minunused")) {
- confp->pri.minunused = atoi(v->value);
- } else if (!strcasecmp(v->name, "minidle")) {
- confp->pri.minidle = atoi(v->value);
- } else if (!strcasecmp(v->name, "idleext")) {
- ast_copy_string(confp->pri.idleext, v->value, sizeof(confp->pri.idleext));
- } else if (!strcasecmp(v->name, "idledial")) {
- ast_copy_string(confp->pri.idledial, v->value, sizeof(confp->pri.idledial));
- } else if (!strcasecmp(v->name, "overlapdial")) {
- confp->pri.overlapdial = ast_true(v->value);
-#ifdef HAVE_PRI_INBANDDISCONNECT
- } else if (!strcasecmp(v->name, "inbanddisconnect")) {
- confp->pri.inbanddisconnect = ast_true(v->value);
-#endif
- } else if (!strcasecmp(v->name, "pritimer")) {
-#ifdef PRI_GETSET_TIMERS
- char *timerc, *c;
- int timer, timeridx;
- c = v->value;
- timerc = strsep(&c, ",");
- if (timerc) {
- timer = atoi(c);
- if (!timer)
- ast_log(LOG_WARNING, "'%s' is not a valid value for an ISDN timer\n", timerc);
- else {
- if ((timeridx = pri_timer2idx(timerc)) >= 0)
- pritimers[timeridx] = timer;
- else
- ast_log(LOG_WARNING, "'%s' is not a valid ISDN timer\n", timerc);
- }
- } else
- ast_log(LOG_WARNING, "'%s' is not a valid ISDN timer configuration string\n", v->value);
-
- } else if (!strcasecmp(v->name, "facilityenable")) {
- confp->pri.facilityenable = ast_true(v->value);
-#endif /* PRI_GETSET_TIMERS */
-#endif /* HAVE_PRI */
- } else if (!strcasecmp(v->name, "cadence")) {
- /* setup to scan our argument */
- int element_count, c[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
- int i;
- struct dahdi_ring_cadence new_cadence;
- int cid_location = -1;
- int firstcadencepos = 0;
- char original_args[80];
- int cadence_is_ok = 1;
-
- ast_copy_string(original_args, v->value, sizeof(original_args));
- /* 16 cadences allowed (8 pairs) */
- element_count = sscanf(v->value, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", &c[0], &c[1], &c[2], &c[3], &c[4], &c[5], &c[6], &c[7], &c[8], &c[9], &c[10], &c[11], &c[12], &c[13], &c[14], &c[15]);
-
- /* Cadence must be even (on/off) */
- if (element_count % 2 == 1) {
- ast_log(LOG_ERROR, "Must be a silence duration for each ring duration: %s\n",original_args);
- cadence_is_ok = 0;
- }
-
- /* Ring cadences cannot be negative */
- for (i = 0; i < element_count; i++) {
- if (c[i] == 0) {
- ast_log(LOG_ERROR, "Ring or silence duration cannot be zero: %s\n", original_args);
- cadence_is_ok = 0;
- break;
- } else if (c[i] < 0) {
- if (i % 2 == 1) {
- /* Silence duration, negative possibly okay */
- if (cid_location == -1) {
- cid_location = i;
- c[i] *= -1;
- } else {
- ast_log(LOG_ERROR, "CID location specified twice: %s\n",original_args);
- cadence_is_ok = 0;
- break;
- }
- } else {
- if (firstcadencepos == 0) {
- firstcadencepos = i; /* only recorded to avoid duplicate specification */
- /* duration will be passed negative to the DAHDI driver */
- } else {
- ast_log(LOG_ERROR, "First cadence position specified twice: %s\n",original_args);
- cadence_is_ok = 0;
- break;
- }
- }
- }
- }
-
- /* Substitute our scanned cadence */
- for (i = 0; i < 16; i++) {
- new_cadence.ringcadence[i] = c[i];
- }
-
- if (cadence_is_ok) {
- /* ---we scanned it without getting annoyed; now some sanity checks--- */
- if (element_count < 2) {
- ast_log(LOG_ERROR, "Minimum cadence is ring,pause: %s\n", original_args);
- } else {
- if (cid_location == -1) {
- /* user didn't say; default to first pause */
- cid_location = 1;
- } else {
- /* convert element_index to cidrings value */
- cid_location = (cid_location + 1) / 2;
- }
- /* ---we like their cadence; try to install it--- */
- if (!user_has_defined_cadences++)
- /* this is the first user-defined cadence; clear the default user cadences */
- num_cadence = 0;
- if ((num_cadence+1) >= NUM_CADENCE_MAX)
- ast_log(LOG_ERROR, "Already %d cadences; can't add another: %s\n", NUM_CADENCE_MAX, original_args);
- else {
- cadences[num_cadence] = new_cadence;
- cidrings[num_cadence++] = cid_location;
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "cadence 'r%d' added: %s\n",num_cadence,original_args);
- }
- }
- }
- } else if (!strcasecmp(v->name, "ringtimeout")) {
- ringt_base = (atoi(v->value) * 8) / READ_SIZE;
- } else if (!strcasecmp(v->name, "prewink")) {
- confp->timing.prewinktime = atoi(v->value);
- } else if (!strcasecmp(v->name, "preflash")) {
- confp->timing.preflashtime = atoi(v->value);
- } else if (!strcasecmp(v->name, "wink")) {
- confp->timing.winktime = atoi(v->value);
- } else if (!strcasecmp(v->name, "flash")) {
- confp->timing.flashtime = atoi(v->value);
- } else if (!strcasecmp(v->name, "start")) {
- confp->timing.starttime = atoi(v->value);
- } else if (!strcasecmp(v->name, "rxwink")) {
- confp->timing.rxwinktime = atoi(v->value);
- } else if (!strcasecmp(v->name, "rxflash")) {
- confp->timing.rxflashtime = atoi(v->value);
- } else if (!strcasecmp(v->name, "debounce")) {
- confp->timing.debouncetime = atoi(v->value);
- } else if (!strcasecmp(v->name, "toneduration")) {
- int toneduration;
- int ctlfd;
- int res;
- struct dahdi_dialparams dps;
-
- ctlfd = open(DAHDI_FILE_CTL, O_RDWR);
-
- if (ctlfd == -1) {
- ast_log(LOG_ERROR, "Unable to open " DAHDI_FILE_CTL " to set toneduration\n");
- return -1;
- }
-
- toneduration = atoi(v->value);
- if (toneduration > -1) {
- memset(&dps, 0, sizeof(dps));
-
- dps.dtmf_tonelen = dps.mfv1_tonelen = toneduration;
- res = ioctl(ctlfd, DAHDI_SET_DIALPARAMS, &dps);
- if (res < 0) {
- ast_log(LOG_ERROR, "Invalid tone duration: %d ms: %s\n", toneduration, strerror(errno));
- return -1;
- }
- }
- close(ctlfd);
- } else if (!strcasecmp(v->name, "defaultcic")) {
- ast_copy_string(defaultcic, v->value, sizeof(defaultcic));
- } else if (!strcasecmp(v->name, "defaultozz")) {
- ast_copy_string(defaultozz, v->value, sizeof(defaultozz));
- }
- } else if (!skipchannels)
- ast_log(LOG_WARNING, "Ignoring %s\n", v->name);
- }
- if (dahdichan[0]) {
- /* The user has set 'dahdichan' */
- /*< \todo pass proper line number instead of 0 */
- if (build_channels(confp, 0, dahdichan, reload, 0, &found_pseudo)) {
- return -1;
- }
- }
- /*< \todo why check for the pseudo in the per-channel section.
- * Any actual use for manual setup of the pseudo channel? */
- if (!found_pseudo && reload == 0) {
- /* use the default configuration for a channel, so
- that any settings from real configured channels
- don't "leak" into the pseudo channel config
- */
- struct dahdi_chan_conf conf = dahdi_chan_conf_default();
-
- tmp = mkintf(CHAN_PSEUDO, &conf, NULL, reload);
-
- if (tmp) {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Automatically generated pseudo channel\n");
- } else {
- ast_log(LOG_WARNING, "Unable to register pseudo channel!\n");
- }
- }
- return 0;
-}
-
-static int setup_dahdi(int reload)
-{
- struct ast_config *cfg;
- struct ast_variable *v;
- struct dahdi_chan_conf conf = dahdi_chan_conf_default();
- int res;
-
-#ifdef HAVE_PRI
- char *c;
- int spanno;
- int i, x;
- int logicalspan;
- int trunkgroup;
- int dchannels[NUM_DCHANS];
-#endif
-
-#ifdef HAVE_ZAPTEL
- int load_from_zapata_conf = 1;
-#else
- int load_from_zapata_conf = (dahdi_chan_mode == CHAN_ZAP_MODE);
-#endif
-
- if (load_from_zapata_conf) {
- if (!(cfg = ast_config_load("zapata.conf"))) {
- ast_log(LOG_ERROR, "Unable to load zapata.conf\n");
- return 0;
- }
- } else {
- if (!(cfg = ast_config_load("chan_dahdi.conf"))) {
- ast_log(LOG_ERROR, "Unable to load chan_dahdi.conf\n");
- return 0;
- }
- }
-
- /* It's a little silly to lock it, but we mind as well just to be sure */
- ast_mutex_lock(&iflock);
-#ifdef HAVE_PRI
- if (reload != 1) {
- /* Process trunkgroups first */
- v = ast_variable_browse(cfg, "trunkgroups");
- while (v) {
- if (!strcasecmp(v->name, "trunkgroup")) {
- trunkgroup = atoi(v->value);
- if (trunkgroup > 0) {
- if ((c = strchr(v->value, ','))) {
- i = 0;
- memset(dchannels, 0, sizeof(dchannels));
- while (c && (i < NUM_DCHANS)) {
- dchannels[i] = atoi(c + 1);
- if (dchannels[i] < 0) {
- ast_log(LOG_WARNING, "D-channel for trunk group %d must be a postiive number at line %d of chan_dahdi.conf\n", trunkgroup, v->lineno);
- } else
- i++;
- c = strchr(c + 1, ',');
- }
- if (i) {
- if (pri_create_trunkgroup(trunkgroup, dchannels)) {
- ast_log(LOG_WARNING, "Unable to create trunk group %d with Primary D-channel %d at line %d of chan_dahdi.conf\n", trunkgroup, dchannels[0], v->lineno);
- } else if (option_verbose > 1)
- ast_verbose(VERBOSE_PREFIX_2 "Created trunk group %d with Primary D-channel %d and %d backup%s\n", trunkgroup, dchannels[0], i - 1, (i == 1) ? "" : "s");
- } else
- ast_log(LOG_WARNING, "Trunk group %d lacks any valid D-channels at line %d of chan_dahdi.conf\n", trunkgroup, v->lineno);
- } else
- ast_log(LOG_WARNING, "Trunk group %d lacks a primary D-channel at line %d of chan_dahdi.conf\n", trunkgroup, v->lineno);
- } else
- ast_log(LOG_WARNING, "Trunk group identifier must be a positive integer at line %d of chan_dahdi.conf\n", v->lineno);
- } else if (!strcasecmp(v->name, "spanmap")) {
- spanno = atoi(v->value);
- if (spanno > 0) {
- if ((c = strchr(v->value, ','))) {
- trunkgroup = atoi(c + 1);
- if (trunkgroup > 0) {
- if ((c = strchr(c + 1, ',')))
- logicalspan = atoi(c + 1);
- else
- logicalspan = 0;
- if (logicalspan >= 0) {
- if (pri_create_spanmap(spanno - 1, trunkgroup, logicalspan)) {
- ast_log(LOG_WARNING, "Failed to map span %d to trunk group %d (logical span %d)\n", spanno, trunkgroup, logicalspan);
- } else if (option_verbose > 1)
- ast_verbose(VERBOSE_PREFIX_2 "Mapped span %d to trunk group %d (logical span %d)\n", spanno, trunkgroup, logicalspan);
- } else
- ast_log(LOG_WARNING, "Logical span must be a postive number, or '0' (for unspecified) at line %d of chan_dahdi.conf\n", v->lineno);
- } else
- ast_log(LOG_WARNING, "Trunk group must be a postive number at line %d of chan_dahdi.conf\n", v->lineno);
- } else
- ast_log(LOG_WARNING, "Missing trunk group for span map at line %d of chan_dahdi.conf\n", v->lineno);
- } else
- ast_log(LOG_WARNING, "Span number must be a postive integer at line %d of chan_dahdi.conf\n", v->lineno);
- } else {
- ast_log(LOG_NOTICE, "Ignoring unknown keyword '%s' in trunkgroups\n", v->name);
- }
- v = v->next;
- }
- }
-#endif
-
- /* Copy the default jb config over global_jbconf */
- memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
-
- v = ast_variable_browse(cfg, "channels");
- res = process_dahdi(&conf, "", v, reload, 0);
- ast_mutex_unlock(&iflock);
- ast_config_destroy(cfg);
- if (res)
- return res;
- cfg = ast_config_load("users.conf");
- if (cfg) {
- char *cat;
- const char *chans;
- process_dahdi(&conf, "", ast_variable_browse(cfg, "general"), 1, 1);
- for (cat = ast_category_browse(cfg, NULL); cat ; cat = ast_category_browse(cfg, cat)) {
- if (!strcasecmp(cat, "general"))
- continue;
- chans = ast_variable_retrieve(cfg, cat, "dahdichan");
- if (!ast_strlen_zero(chans)) {
- struct dahdi_chan_conf sect_conf;
- memcpy(&sect_conf, &conf, sizeof(sect_conf));
-
- process_dahdi(&sect_conf, cat, ast_variable_browse(cfg, cat), reload, 0);
- }
- }
- ast_config_destroy(cfg);
- }
-#ifdef HAVE_PRI
- if (reload != 1) {
- for (x = 0; x < NUM_SPANS; x++) {
- if (pris[x].pvts[0]) {
- if (start_pri(pris + x)) {
- ast_log(LOG_ERROR, "Unable to start D-channel on span %d\n", x + 1);
- return -1;
- } else if (option_verbose > 1)
- ast_verbose(VERBOSE_PREFIX_2 "Starting D-Channel on span %d\n", x + 1);
- }
- }
- }
-#endif
- /* And start the monitor for the first time */
- restart_monitor();
- return 0;
-}
-
-#define local_astman_register(a, b, c, d) do { \
- if (*dahdi_chan_mode == CHAN_DAHDI_PLUS_ZAP_MODE) { \
- ast_manager_register("DAHDI" a, b, dahdi_ ## c, d); \
- } \
- ast_manager_register("Zap" a, b, zap_ ## c, d); \
- } while (0)
-
-static int load_module(void)
-{
- int res;
-
-#ifdef HAVE_PRI
- int y,i;
- memset(pris, 0, sizeof(pris));
- for (y = 0; y < NUM_SPANS; y++) {
- ast_mutex_init(&pris[y].lock);
- pris[y].offset = -1;
- pris[y].master = AST_PTHREADT_NULL;
- for (i = 0; i < NUM_DCHANS; i++)
- pris[y].fds[i] = -1;
- }
- pri_set_error(dahdi_pri_error);
- pri_set_message(dahdi_pri_message);
- if (*dahdi_chan_mode == CHAN_DAHDI_PLUS_ZAP_MODE) {
- ast_register_application(dahdi_send_keypad_facility_app, dahdi_send_keypad_facility_exec,
- dahdi_send_keypad_facility_synopsis, dahdi_send_keypad_facility_descrip);
- }
- ast_register_application(zap_send_keypad_facility_app, zap_send_keypad_facility_exec,
- zap_send_keypad_facility_synopsis, zap_send_keypad_facility_descrip);
-#endif
- if ((res = setup_dahdi(0))) {
- return AST_MODULE_LOAD_DECLINE;
- }
- if (*dahdi_chan_mode == CHAN_DAHDI_PLUS_ZAP_MODE) {
- chan_tech = &dahdi_tech;
- } else {
- chan_tech = &zap_tech;
- }
- if (ast_channel_register(chan_tech)) {
- ast_log(LOG_ERROR, "Unable to register channel class '%s'\n", chan_tech->type);
- __unload_module();
- return -1;
- }
-#ifdef HAVE_PRI
- ast_string_field_init(&inuse, 16);
- ast_string_field_set(&inuse, name, "GR-303InUse");
- ast_cli_register_multiple(dahdi_pri_cli, sizeof(dahdi_pri_cli) / sizeof(struct ast_cli_entry));
-#endif
- ast_cli_register_multiple(dahdi_cli, sizeof(dahdi_cli) / sizeof(struct ast_cli_entry));
-
- memset(round_robin, 0, sizeof(round_robin));
- local_astman_register("Transfer", 0, action_transfer, "Transfer Channel");
- local_astman_register("Hangup", 0, action_transferhangup, "Hangup Channel");
- local_astman_register("DialOffHook", 0, action_dialoffhook, "Dial over channel while offhook");
- local_astman_register("DNDon", 0, action_dndon, "Toggle channel Do Not Disturb status ON");
- local_astman_register("DNDoff", 0, action_dndoff, "Toggle channel Do Not Disturb status OFF");
- local_astman_register("ShowChannels", 0, action_showchannels, "Show status channels");
- local_astman_register("Restart", 0, action_restart, "Fully Restart channels (terminates calls)");
-
- ast_cond_init(&ss_thread_complete, NULL);
-
- return res;
-}
-
-static int dahdi_sendtext(struct ast_channel *c, const char *text)
-{
-#define END_SILENCE_LEN 400
-#define HEADER_MS 50
-#define TRAILER_MS 5
-#define HEADER_LEN ((HEADER_MS + TRAILER_MS) * 8)
-#define ASCII_BYTES_PER_CHAR 80
-
- unsigned char *buf,*mybuf;
- struct dahdi_pvt *p = c->tech_pvt;
- struct pollfd fds[1];
- int size,res,fd,len,x;
- int bytes=0;
- /* Initial carrier (imaginary) */
- float cr = 1.0;
- float ci = 0.0;
- float scont = 0.0;
- int index;
-
- index = dahdi_get_index(c, p, 0);
- if (index < 0) {
- ast_log(LOG_WARNING, "Huh? I don't exist?\n");
- return -1;
- }
- if (!text[0]) return(0); /* if nothing to send, dont */
- if ((!p->tdd) && (!p->mate)) return(0); /* if not in TDD mode, just return */
- if (p->mate)
- buf = ast_malloc(((strlen(text) + 1) * ASCII_BYTES_PER_CHAR) + END_SILENCE_LEN + HEADER_LEN);
- else
- buf = ast_malloc(((strlen(text) + 1) * TDD_BYTES_PER_CHAR) + END_SILENCE_LEN);
- if (!buf)
- return -1;
- mybuf = buf;
- if (p->mate) {
- int codec = AST_LAW(p);
- for (x = 0; x < HEADER_MS; x++) { /* 50 ms of Mark */
- PUT_CLID_MARKMS;
- }
- /* Put actual message */
- for (x = 0; text[x]; x++) {
- PUT_CLID(text[x]);
- }
- for (x = 0; x < TRAILER_MS; x++) { /* 5 ms of Mark */
- PUT_CLID_MARKMS;
- }
- len = bytes;
- buf = mybuf;
- } else {
- len = tdd_generate(p->tdd, buf, text);
- if (len < 1) {
- ast_log(LOG_ERROR, "TDD generate (len %d) failed!!\n", (int)strlen(text));
- free(mybuf);
- return -1;
- }
- }
- memset(buf + len, 0x7f, END_SILENCE_LEN);
- len += END_SILENCE_LEN;
- fd = p->subs[index].dfd;
- while (len) {
- if (ast_check_hangup(c)) {
- free(mybuf);
- return -1;
- }
- size = len;
- if (size > READ_SIZE)
- size = READ_SIZE;
- fds[0].fd = fd;
- fds[0].events = POLLOUT | POLLPRI;
- fds[0].revents = 0;
- res = poll(fds, 1, -1);
- if (!res) {
- ast_log(LOG_DEBUG, "poll (for write) ret. 0 on channel %d\n", p->channel);
- continue;
- }
- /* if got exception */
- if (fds[0].revents & POLLPRI) {
- ast_free(mybuf);
- return -1;
- }
- if (!(fds[0].revents & POLLOUT)) {
- ast_log(LOG_DEBUG, "write fd not ready on channel %d\n", p->channel);
- continue;
- }
- res = write(fd, buf, size);
- if (res != size) {
- if (res == -1) {
- free(mybuf);
- return -1;
- }
- if (option_debug)
- ast_log(LOG_DEBUG, "Write returned %d (%s) on channel %d\n", res, strerror(errno), p->channel);
- break;
- }
- len -= size;
- buf += size;
- }
- free(mybuf);
- return(0);
-}
-
-
-static int reload(void)
-{
- int res = 0;
-
- res = setup_dahdi(1);
- if (res) {
- ast_log(LOG_WARNING, "Reload of chan_dahdi.so is unsuccessful!\n");
- return -1;
- }
- return 0;
-}
-
-/* This is a workaround so that menuselect displays a proper description
- * AST_MODULE_INFO(, , "DAHDI Telephony"
- */
-
-#ifdef HAVE_PRI
-#define tdesc "DAHDI Telephony w/PRI"
-#else
-#define tdesc "DAHDI Telephony"
-#endif
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, tdesc,
- .load = load_module,
- .unload = unload_module,
- .reload = reload,
- );
-
-
diff --git a/1.4.23-rc4/channels/chan_features.c b/1.4.23-rc4/channels/chan_features.c
deleted file mode 100644
index 043576623..000000000
--- a/1.4.23-rc4/channels/chan_features.c
+++ /dev/null
@@ -1,580 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 1999 - 2005, Digium, Inc.
- *
- * Mark Spencer <markster@digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief feature Proxy Channel
- *
- * \author Mark Spencer <markster@digium.com>
- *
- * \note *** Experimental code ****
- *
- * \ingroup channel_drivers
- */
-/*** MODULEINFO
- <defaultenabled>no</defaultenabled>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/socket.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <sys/signal.h>
-
-#include "asterisk/lock.h"
-#include "asterisk/channel.h"
-#include "asterisk/config.h"
-#include "asterisk/logger.h"
-#include "asterisk/module.h"
-#include "asterisk/pbx.h"
-#include "asterisk/options.h"
-#include "asterisk/lock.h"
-#include "asterisk/sched.h"
-#include "asterisk/io.h"
-#include "asterisk/rtp.h"
-#include "asterisk/acl.h"
-#include "asterisk/callerid.h"
-#include "asterisk/file.h"
-#include "asterisk/cli.h"
-#include "asterisk/app.h"
-#include "asterisk/musiconhold.h"
-#include "asterisk/manager.h"
-#include "asterisk/stringfields.h"
-
-static const char tdesc[] = "Feature Proxy Channel Driver";
-
-#define IS_OUTBOUND(a,b) (a == b->chan ? 1 : 0)
-
-struct feature_sub {
- struct ast_channel *owner;
- int inthreeway;
- int pfd;
- int timingfdbackup;
- int alertpipebackup[2];
-};
-
-struct feature_pvt {
- ast_mutex_t lock; /* Channel private lock */
- char tech[AST_MAX_EXTENSION]; /* Technology to abstract */
- char dest[AST_MAX_EXTENSION]; /* Destination to abstract */
- struct ast_channel *subchan;
- struct feature_sub subs[3]; /* Subs */
- struct ast_channel *owner; /* Current Master Channel */
- AST_LIST_ENTRY(feature_pvt) list; /* Next entity */
-};
-
-static AST_LIST_HEAD_STATIC(features, feature_pvt);
-
-#define SUB_REAL 0 /* Active call */
-#define SUB_CALLWAIT 1 /* Call-Waiting call on hold */
-#define SUB_THREEWAY 2 /* Three-way call */
-
-static struct ast_channel *features_request(const char *type, int format, void *data, int *cause);
-static int features_digit_begin(struct ast_channel *ast, char digit);
-static int features_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
-static int features_call(struct ast_channel *ast, char *dest, int timeout);
-static int features_hangup(struct ast_channel *ast);
-static int features_answer(struct ast_channel *ast);
-static struct ast_frame *features_read(struct ast_channel *ast);
-static int features_write(struct ast_channel *ast, struct ast_frame *f);
-static int features_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
-static int features_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
-
-static const struct ast_channel_tech features_tech = {
- .type = "Feature",
- .description = tdesc,
- .capabilities = -1,
- .requester = features_request,
- .send_digit_begin = features_digit_begin,
- .send_digit_end = features_digit_end,
- .call = features_call,
- .hangup = features_hangup,
- .answer = features_answer,
- .read = features_read,
- .write = features_write,
- .exception = features_read,
- .indicate = features_indicate,
- .fixup = features_fixup,
-};
-
-static inline void init_sub(struct feature_sub *sub)
-{
- sub->inthreeway = 0;
- sub->pfd = -1;
- sub->timingfdbackup = -1;
- sub->alertpipebackup[0] = sub->alertpipebackup[1] = -1;
-}
-
-static inline int indexof(struct feature_pvt *p, struct ast_channel *owner, int nullok)
-{
- int x;
- if (!owner) {
- ast_log(LOG_WARNING, "indexof called on NULL owner??\n");
- return -1;
- }
- for (x=0; x<3; x++) {
- if (owner == p->subs[x].owner)
- return x;
- }
- return -1;
-}
-
-#if 0
-static void wakeup_sub(struct feature_pvt *p, int a)
-{
- struct ast_frame null = { AST_FRAME_NULL, };
- for (;;) {
- if (p->subs[a].owner) {
- if (ast_mutex_trylock(&p->subs[a].owner->lock)) {
- ast_mutex_unlock(&p->lock);
- usleep(1);
- ast_mutex_lock(&p->lock);
- } else {
- ast_queue_frame(p->subs[a].owner, &null);
- ast_mutex_unlock(&p->subs[a].owner->lock);
- break;
- }
- } else
- break;
- }
-}
-#endif
-
-static void restore_channel(struct feature_pvt *p, int index)
-{
- /* Restore timing/alertpipe */
- p->subs[index].owner->timingfd = p->subs[index].timingfdbackup;
- p->subs[index].owner->alertpipe[0] = p->subs[index].alertpipebackup[0];
- p->subs[index].owner->alertpipe[1] = p->subs[index].alertpipebackup[1];
- p->subs[index].owner->fds[AST_ALERT_FD] = p->subs[index].alertpipebackup[0];
- p->subs[index].owner->fds[AST_TIMING_FD] = p->subs[index].timingfdbackup;
-}
-
-static void update_features(struct feature_pvt *p, int index)
-{
- int x;
- if (p->subs[index].owner) {
- for (x=0; x<AST_MAX_FDS; x++) {
- if (index)
- p->subs[index].owner->fds[x] = -1;
- else
- p->subs[index].owner->fds[x] = p->subchan->fds[x];
- }
- if (!index) {
- /* Copy timings from master channel */
- p->subs[index].owner->timingfd = p->subchan->timingfd;
- p->subs[index].owner->alertpipe[0] = p->subchan->alertpipe[0];
- p->subs[index].owner->alertpipe[1] = p->subchan->alertpipe[1];
- if (p->subs[index].owner->nativeformats != p->subchan->readformat) {
- p->subs[index].owner->nativeformats = p->subchan->readformat;
- if (p->subs[index].owner->readformat)
- ast_set_read_format(p->subs[index].owner, p->subs[index].owner->readformat);
- if (p->subs[index].owner->writeformat)
- ast_set_write_format(p->subs[index].owner, p->subs[index].owner->writeformat);
- }
- } else{
- restore_channel(p, index);
- }
- }
-}
-
-#if 0
-static void swap_subs(struct feature_pvt *p, int a, int b)
-{
- int tinthreeway;
- struct ast_channel *towner;
-
- ast_log(LOG_DEBUG, "Swapping %d and %d\n", a, b);
-
- towner = p->subs[a].owner;
- tinthreeway = p->subs[a].inthreeway;
-
- p->subs[a].owner = p->subs[b].owner;
- p->subs[a].inthreeway = p->subs[b].inthreeway;
-
- p->subs[b].owner = towner;
- p->subs[b].inthreeway = tinthreeway;
- update_features(p,a);
- update_features(p,b);
- wakeup_sub(p, a);
- wakeup_sub(p, b);
-}
-#endif
-
-static int features_answer(struct ast_channel *ast)
-{
- struct feature_pvt *p = ast->tech_pvt;
- int res = -1;
- int x;
-
- ast_mutex_lock(&p->lock);
- x = indexof(p, ast, 0);
- if (!x && p->subchan)
- res = ast_answer(p->subchan);
- ast_mutex_unlock(&p->lock);
- return res;
-}
-
-static struct ast_frame *features_read(struct ast_channel *ast)
-{
- struct feature_pvt *p = ast->tech_pvt;
- struct ast_frame *f;
- int x;
-
- f = &ast_null_frame;
- ast_mutex_lock(&p->lock);
- x = indexof(p, ast, 0);
- if (!x && p->subchan) {
- update_features(p, x);
- f = ast_read(p->subchan);
- }
- ast_mutex_unlock(&p->lock);
- return f;
-}
-
-static int features_write(struct ast_channel *ast, struct ast_frame *f)
-{
- struct feature_pvt *p = ast->tech_pvt;
- int res = -1;
- int x;
-
- ast_mutex_lock(&p->lock);
- x = indexof(p, ast, 0);
- if (!x && p->subchan)
- res = ast_write(p->subchan, f);
- ast_mutex_unlock(&p->lock);
- return res;
-}
-
-static int features_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
-{
- struct feature_pvt *p = newchan->tech_pvt;
- int x;
-
- ast_mutex_lock(&p->lock);
- if (p->owner == oldchan)
- p->owner = newchan;
- for (x = 0; x < 3; x++) {
- if (p->subs[x].owner == oldchan)
- p->subs[x].owner = newchan;
- }
- ast_mutex_unlock(&p->lock);
- return 0;
-}
-
-static int features_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
-{
- struct feature_pvt *p = ast->tech_pvt;
- int res = -1;
- int x;
-
- /* Queue up a frame representing the indication as a control frame */
- ast_mutex_lock(&p->lock);
- x = indexof(p, ast, 0);
- if (!x && p->subchan)
- res = ast_indicate(p->subchan, condition);
- ast_mutex_unlock(&p->lock);
- return res;
-}
-
-static int features_digit_begin(struct ast_channel *ast, char digit)
-{
- struct feature_pvt *p = ast->tech_pvt;
- int res = -1;
- int x;
-
- /* Queue up a frame representing the indication as a control frame */
- ast_mutex_lock(&p->lock);
- x = indexof(p, ast, 0);
- if (!x && p->subchan)
- res = ast_senddigit_begin(p->subchan, digit);
- ast_mutex_unlock(&p->lock);
-
- return res;
-}
-
-static int features_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
-{
- struct feature_pvt *p = ast->tech_pvt;
- int res = -1;
- int x;
-
- /* Queue up a frame representing the indication as a control frame */
- ast_mutex_lock(&p->lock);
- x = indexof(p, ast, 0);
- if (!x && p->subchan)
- res = ast_senddigit_end(p->subchan, digit, duration);
- ast_mutex_unlock(&p->lock);
- return res;
-}
-
-static int features_call(struct ast_channel *ast, char *dest, int timeout)
-{
- struct feature_pvt *p = ast->tech_pvt;
- int res = -1;
- int x;
- char *dest2;
-
- dest2 = strchr(dest, '/');
- if (dest2) {
- ast_mutex_lock(&p->lock);
- x = indexof(p, ast, 0);
- if (!x && p->subchan) {
- p->subchan->cid.cid_num = ast_strdup(p->owner->cid.cid_num);
- p->subchan->cid.cid_name = ast_strdup(p->owner->cid.cid_name);
- p->subchan->cid.cid_rdnis = ast_strdup(p->owner->cid.cid_rdnis);
- p->subchan->cid.cid_ani = ast_strdup(p->owner->cid.cid_ani);
-
- p->subchan->cid.cid_pres = p->owner->cid.cid_pres;
- ast_string_field_set(p->subchan, language, p->owner->language);
- ast_string_field_set(p->subchan, accountcode, p->owner->accountcode);
- p->subchan->cdrflags = p->owner->cdrflags;
- res = ast_call(p->subchan, dest2, timeout);
- update_features(p, x);
- } else
- ast_log(LOG_NOTICE, "Uhm yah, not quite there with the call waiting...\n");
- ast_mutex_unlock(&p->lock);
- }
- return res;
-}
-
-static int features_hangup(struct ast_channel *ast)
-{
- struct feature_pvt *p = ast->tech_pvt;
- int x;
-
- ast_mutex_lock(&p->lock);
- x = indexof(p, ast, 0);
- if (x > -1) {
- restore_channel(p, x);
- p->subs[x].owner = NULL;
- /* XXX Re-arrange, unconference, etc XXX */
- }
- ast->tech_pvt = NULL;
-
- if (!p->subs[SUB_REAL].owner && !p->subs[SUB_CALLWAIT].owner && !p->subs[SUB_THREEWAY].owner) {
- ast_mutex_unlock(&p->lock);
- /* Remove from list */
- AST_LIST_LOCK(&features);
- AST_LIST_REMOVE(&features, p, list);
- AST_LIST_UNLOCK(&features);
- ast_mutex_lock(&p->lock);
- /* And destroy */
- if (p->subchan)
- ast_hangup(p->subchan);
- ast_mutex_unlock(&p->lock);
- ast_mutex_destroy(&p->lock);
- free(p);
- return 0;
- }
- ast_mutex_unlock(&p->lock);
- return 0;
-}
-
-static struct feature_pvt *features_alloc(char *data, int format)
-{
- struct feature_pvt *tmp;
- char *dest=NULL;
- char *tech;
- int x;
- int status;
- struct ast_channel *chan;
-
- tech = ast_strdupa(data);
- if (tech) {
- dest = strchr(tech, '/');
- if (dest) {
- *dest = '\0';
- dest++;
- }
- }
- if (!tech || !dest) {
- ast_log(LOG_NOTICE, "Format for feature channel is Feature/Tech/Dest ('%s' not valid)!\n",
- data);
- return NULL;
- }
- AST_LIST_LOCK(&features);
- AST_LIST_TRAVERSE(&features, tmp, list) {
- if (!strcasecmp(tmp->tech, tech) && !strcmp(tmp->dest, dest))
- break;
- }
- AST_LIST_UNLOCK(&features);
- if (!tmp) {
- chan = ast_request(tech, format, dest, &status);
- if (!chan) {
- ast_log(LOG_NOTICE, "Unable to allocate subchannel '%s/%s'\n", tech, dest);
- return NULL;
- }
- tmp = malloc(sizeof(struct feature_pvt));
- if (tmp) {
- memset(tmp, 0, sizeof(struct feature_pvt));
- for (x=0;x<3;x++)
- init_sub(tmp->subs + x);
- ast_mutex_init(&tmp->lock);
- ast_copy_string(tmp->tech, tech, sizeof(tmp->tech));
- ast_copy_string(tmp->dest, dest, sizeof(tmp->dest));
- tmp->subchan = chan;
- AST_LIST_LOCK(&features);
- AST_LIST_INSERT_HEAD(&features, tmp, list);
- AST_LIST_UNLOCK(&features);
- }
- }
- return tmp;
-}
-
-static struct ast_channel *features_new(struct feature_pvt *p, int state, int index)
-{
- struct ast_channel *tmp;
- int x,y;
- char *b2 = 0;
- if (!p->subchan) {
- ast_log(LOG_WARNING, "Called upon channel with no subchan:(\n");
- return NULL;
- }
- if (p->subs[index].owner) {
- ast_log(LOG_WARNING, "Called to put index %d already there!\n", index);
- return NULL;
- }
- /* figure out what you want the name to be */
- for (x=1;x<4;x++) {
- if (b2)
- free(b2);
- b2 = ast_safe_string_alloc("%s/%s-%d", p->tech, p->dest, x);
- for (y=0;y<3;y++) {
- if (y == index)
- continue;
- if (p->subs[y].owner && !strcasecmp(p->subs[y].owner->name, b2))
- break;
- }
- if (y >= 3)
- break;
- }
- tmp = ast_channel_alloc(0, state, 0,0, "", "", "", 0, "Feature/%s", b2);
- /* free up the name, it was copied into the channel name */
- if (b2)
- free(b2);
- if (!tmp) {
- ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
- return NULL;
- }
- tmp->tech = &features_tech;
- tmp->writeformat = p->subchan->writeformat;
- tmp->rawwriteformat = p->subchan->rawwriteformat;
- tmp->readformat = p->subchan->readformat;
- tmp->rawreadformat = p->subchan->rawreadformat;
- tmp->nativeformats = p->subchan->readformat;
- tmp->tech_pvt = p;
- p->subs[index].owner = tmp;
- if (!p->owner)
- p->owner = tmp;
- ast_module_ref(ast_module_info->self);
- return tmp;
-}
-
-
-static struct ast_channel *features_request(const char *type, int format, void *data, int *cause)
-{
- struct feature_pvt *p;
- struct ast_channel *chan = NULL;
-
- p = features_alloc(data, format);
- if (p && !p->subs[SUB_REAL].owner)
- chan = features_new(p, AST_STATE_DOWN, SUB_REAL);
- if (chan)
- update_features(p,SUB_REAL);
- return chan;
-}
-
-static int features_show(int fd, int argc, char **argv)
-{
- struct feature_pvt *p;
-
- if (argc != 3)
- return RESULT_SHOWUSAGE;
-
- if (AST_LIST_EMPTY(&features)) {
- ast_cli(fd, "No feature channels in use\n");
- return RESULT_SUCCESS;
- }
-
- AST_LIST_LOCK(&features);
- AST_LIST_TRAVERSE(&features, p, list) {
- ast_mutex_lock(&p->lock);
- ast_cli(fd, "%s -- %s/%s\n", p->owner ? p->owner->name : "<unowned>", p->tech, p->dest);
- ast_mutex_unlock(&p->lock);
- }
- AST_LIST_UNLOCK(&features);
- return RESULT_SUCCESS;
-}
-
-static char show_features_usage[] =
-"Usage: feature show channels\n"
-" Provides summary information on feature channels.\n";
-
-static struct ast_cli_entry cli_features[] = {
- { { "feature", "show", "channels", NULL },
- features_show, "List status of feature channels",
- show_features_usage },
-};
-
-static int load_module(void)
-{
- /* Make sure we can register our sip channel type */
- if (ast_channel_register(&features_tech)) {
- ast_log(LOG_ERROR, "Unable to register channel class 'Feature'\n");
- return -1;
- }
- ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
- return 0;
-}
-
-static int unload_module(void)
-{
- struct feature_pvt *p;
-
- /* First, take us out of the channel loop */
- ast_cli_unregister_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
- ast_channel_unregister(&features_tech);
-
- if (!AST_LIST_LOCK(&features))
- return -1;
- /* Hangup all interfaces if they have an owner */
- AST_LIST_TRAVERSE_SAFE_BEGIN(&features, p, list) {
- if (p->owner)
- ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
- AST_LIST_REMOVE_CURRENT(&features, list);
- free(p);
- }
- AST_LIST_TRAVERSE_SAFE_END
- AST_LIST_UNLOCK(&features);
-
- return 0;
-}
-
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Feature Proxy Channel");
-
diff --git a/1.4.23-rc4/channels/chan_gtalk.c b/1.4.23-rc4/channels/chan_gtalk.c
deleted file mode 100644
index abe0d63b6..000000000
--- a/1.4.23-rc4/channels/chan_gtalk.c
+++ /dev/null
@@ -1,2067 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 1999 - 2005, Digium, Inc.
- *
- * Matt O'Gorman <mogorman@digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \author Matt O'Gorman <mogorman@digium.com>
- *
- * \brief Gtalk Channel Driver, until google/libjingle works with jingle spec
- *
- * \ingroup channel_drivers
- */
-
-/*** MODULEINFO
- <depend>iksemel</depend>
- <depend>res_jabber</depend>
- <use>gnutls</use>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/socket.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <sys/signal.h>
-#include <iksemel.h>
-#include <pthread.h>
-
-#ifdef HAVE_GNUTLS
-#include <gcrypt.h>
-GCRY_THREAD_OPTION_PTHREAD_IMPL;
-#endif /* HAVE_GNUTLS */
-
-#include "asterisk/lock.h"
-#include "asterisk/channel.h"
-#include "asterisk/config.h"
-#include "asterisk/logger.h"
-#include "asterisk/module.h"
-#include "asterisk/pbx.h"
-#include "asterisk/options.h"
-#include "asterisk/lock.h"
-#include "asterisk/sched.h"
-#include "asterisk/io.h"
-#include "asterisk/rtp.h"
-#include "asterisk/acl.h"
-#include "asterisk/callerid.h"
-#include "asterisk/file.h"
-#include "asterisk/cli.h"
-#include "asterisk/app.h"
-#include "asterisk/musiconhold.h"
-#include "asterisk/manager.h"
-#include "asterisk/stringfields.h"
-#include "asterisk/utils.h"
-#include "asterisk/causes.h"
-#include "asterisk/astobj.h"
-#include "asterisk/abstract_jb.h"
-#include "asterisk/jabber.h"
-
-#define GOOGLE_CONFIG "gtalk.conf"
-
-#define GOOGLE_NS "http://www.google.com/session"
-
-
-/*! Global jitterbuffer configuration - by default, jb is disabled */
-static struct ast_jb_conf default_jbconf =
-{
- .flags = 0,
- .max_size = -1,
- .resync_threshold = -1,
- .impl = ""
-};
-static struct ast_jb_conf global_jbconf;
-
-enum gtalk_protocol {
- AJI_PROTOCOL_UDP = 1,
- AJI_PROTOCOL_SSLTCP = 2,
-};
-
-enum gtalk_connect_type {
- AJI_CONNECT_STUN = 1,
- AJI_CONNECT_LOCAL = 2,
- AJI_CONNECT_RELAY = 3,
-};
-
-struct gtalk_pvt {
- ast_mutex_t lock; /*!< Channel private lock */
- time_t laststun;
- struct gtalk *parent; /*!< Parent client */
- char sid[100];
- char us[AJI_MAX_JIDLEN];
- char them[AJI_MAX_JIDLEN];
- char ring[10]; /*!< Message ID of ring */
- iksrule *ringrule; /*!< Rule for matching RING request */
- int initiator; /*!< If we're the initiator */
- int alreadygone;
- int capability;
- struct ast_codec_pref prefs;
- struct gtalk_candidate *theircandidates;
- struct gtalk_candidate *ourcandidates;
- char cid_num[80]; /*!< Caller ID num */
- char cid_name[80]; /*!< Caller ID name */
- char exten[80]; /*!< Called extension */
- struct ast_channel *owner; /*!< Master Channel */
- struct ast_rtp *rtp; /*!< RTP audio session */
- struct ast_rtp *vrtp; /*!< RTP video session */
- int jointcapability; /*!< Supported capability at both ends (codecs ) */
- int peercapability;
- struct gtalk_pvt *next; /* Next entity */
-};
-
-struct gtalk_candidate {
- char name[100];
- enum gtalk_protocol protocol;
- double preference;
- char username[100];
- char password[100];
- enum gtalk_connect_type type;
- char network[6];
- int generation;
- char ip[16];
- int port;
- int receipt;
- struct gtalk_candidate *next;
-};
-
-struct gtalk {
- ASTOBJ_COMPONENTS(struct gtalk);
- struct aji_client *connection;
- struct aji_buddy *buddy;
- struct gtalk_pvt *p;
- struct ast_codec_pref prefs;
- int amaflags; /*!< AMA Flags */
- char user[AJI_MAX_JIDLEN];
- char context[AST_MAX_CONTEXT];
- char accountcode[AST_MAX_ACCOUNT_CODE]; /*!< Account code */
- int capability;
- ast_group_t callgroup; /*!< Call group */
- ast_group_t pickupgroup; /*!< Pickup group */
- int callingpres; /*!< Calling presentation */
- int allowguest;
- char language[MAX_LANGUAGE]; /*!< Default language for prompts */
- char musicclass[MAX_MUSICCLASS]; /*!< Music on Hold class */
-};
-
-struct gtalk_container {
- ASTOBJ_CONTAINER_COMPONENTS(struct gtalk);
-};
-
-static const char desc[] = "Gtalk Channel";
-
-static int global_capability = AST_FORMAT_ULAW | AST_FORMAT_ALAW | AST_FORMAT_GSM | AST_FORMAT_H263;
-
-AST_MUTEX_DEFINE_STATIC(gtalklock); /*!< Protect the interface list (of gtalk_pvt's) */
-
-/* Forward declarations */
-static struct ast_channel *gtalk_request(const char *type, int format, void *data, int *cause);
-static int gtalk_digit(struct ast_channel *ast, char digit, unsigned int duration);
-static int gtalk_digit_begin(struct ast_channel *ast, char digit);
-static int gtalk_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
-static int gtalk_call(struct ast_channel *ast, char *dest, int timeout);
-static int gtalk_hangup(struct ast_channel *ast);
-static int gtalk_answer(struct ast_channel *ast);
-static int gtalk_action(struct gtalk *client, struct gtalk_pvt *p, const char *action);
-static void gtalk_free_pvt(struct gtalk *client, struct gtalk_pvt *p);
-static int gtalk_newcall(struct gtalk *client, ikspak *pak);
-static struct ast_frame *gtalk_read(struct ast_channel *ast);
-static int gtalk_write(struct ast_channel *ast, struct ast_frame *f);
-static int gtalk_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
-static int gtalk_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
-static int gtalk_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);
-static struct gtalk_pvt *gtalk_alloc(struct gtalk *client, const char *us, const char *them, const char *sid);
-static int gtalk_do_reload(int fd, int argc, char **argv);
-static int gtalk_show_channels(int fd, int argc, char **argv);
-/*----- RTP interface functions */
-static int gtalk_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp,
- struct ast_rtp *vrtp, int codecs, int nat_active);
-static enum ast_rtp_get_result gtalk_get_rtp_peer(struct ast_channel *chan, struct ast_rtp **rtp);
-static int gtalk_get_codec(struct ast_channel *chan);
-
-/*! \brief PBX interface structure for channel registration */
-static const struct ast_channel_tech gtalk_tech = {
- .type = "Gtalk",
- .description = "Gtalk Channel Driver",
- .capabilities = ((AST_FORMAT_MAX_AUDIO << 1) - 1),
- .requester = gtalk_request,
- .send_digit_begin = gtalk_digit_begin,
- .send_digit_end = gtalk_digit_end,
- .bridge = ast_rtp_bridge,
- .call = gtalk_call,
- .hangup = gtalk_hangup,
- .answer = gtalk_answer,
- .read = gtalk_read,
- .write = gtalk_write,
- .exception = gtalk_read,
- .indicate = gtalk_indicate,
- .fixup = gtalk_fixup,
- .send_html = gtalk_sendhtml,
- .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER
-};
-
-static struct sockaddr_in bindaddr = { 0, }; /*!< The address we bind to */
-
-static struct sched_context *sched; /*!< The scheduling context */
-static struct io_context *io; /*!< The IO context */
-static struct in_addr __ourip;
-
-
-/*! \brief RTP driver interface */
-static struct ast_rtp_protocol gtalk_rtp = {
- type: "Gtalk",
- get_rtp_info: gtalk_get_rtp_peer,
- set_rtp_peer: gtalk_set_rtp_peer,
- get_codec: gtalk_get_codec,
-};
-
-static char show_channels_usage[] =
-"Usage: gtalk show channels\n"
-" Shows current state of the Gtalk channels.\n";
-
-static char reload_usage[] =
-"Usage: gtalk reload\n"
-" Reload gtalk channel driver.\n";
-
-
-static struct ast_cli_entry gtalk_cli[] = {
- {{ "gtalk", "reload", NULL}, gtalk_do_reload, "Reload GoogleTalk configuration", reload_usage },
- {{ "gtalk", "show", "channels", NULL}, gtalk_show_channels, "Show GoogleTalk channels", show_channels_usage },
- };
-
-
-
-static char externip[16];
-
-static struct gtalk_container gtalk_list;
-
-static void gtalk_member_destroy(struct gtalk *obj)
-{
- free(obj);
-}
-
-static struct gtalk *find_gtalk(char *name, char *connection)
-{
- struct gtalk *gtalk = NULL;
- char *domain = NULL , *s = NULL;
-
- if(strchr(connection, '@')) {
- s = ast_strdupa(connection);
- domain = strsep(&s, "@");
- ast_verbose("OOOOH domain = %s\n", domain);
- }
- gtalk = ASTOBJ_CONTAINER_FIND(&gtalk_list, name);
- if (!gtalk && strchr(name, '@'))
- gtalk = ASTOBJ_CONTAINER_FIND_FULL(&gtalk_list, name, user,,, strcasecmp);
-
- if (!gtalk) {
- /* guest call */
- ASTOBJ_CONTAINER_TRAVERSE(&gtalk_list, 1, {
- ASTOBJ_RDLOCK(iterator);
- if (!strcasecmp(iterator->name, "guest")) {
- gtalk = iterator;
- }
- ASTOBJ_UNLOCK(iterator);
-
- if (gtalk)
- break;
- });
-
- }
- return gtalk;
-}
-
-
-static int add_codec_to_answer(const struct gtalk_pvt *p, int codec, iks *dcodecs)
-{
- int res = 0;
- char *format = ast_getformatname(codec);
-
- if (!strcasecmp("ulaw", format)) {
- iks *payload_eg711u, *payload_pcmu;
- payload_pcmu = iks_new("payload-type");
- payload_eg711u = iks_new("payload-type");
-
- if(!payload_eg711u || !payload_pcmu) {
- if(payload_pcmu)
- iks_delete(payload_pcmu);
- if(payload_eg711u)
- iks_delete(payload_eg711u);
- ast_log(LOG_WARNING,"Failed to allocate iks node");
- return -1;
- }
- iks_insert_attrib(payload_pcmu, "id", "0");
- iks_insert_attrib(payload_pcmu, "name", "PCMU");
- iks_insert_attrib(payload_pcmu, "clockrate","8000");
- iks_insert_attrib(payload_pcmu, "bitrate","64000");
- iks_insert_attrib(payload_eg711u, "id", "100");
- iks_insert_attrib(payload_eg711u, "name", "EG711U");
- iks_insert_attrib(payload_eg711u, "clockrate","8000");
- iks_insert_attrib(payload_eg711u, "bitrate","64000");
- iks_insert_node(dcodecs, payload_pcmu);
- iks_insert_node(dcodecs, payload_eg711u);
- res ++;
- }
- if (!strcasecmp("alaw", format)) {
- iks *payload_eg711a, *payload_pcma;
- payload_pcma = iks_new("payload-type");
- payload_eg711a = iks_new("payload-type");
- if(!payload_eg711a || !payload_pcma) {
- if(payload_eg711a)
- iks_delete(payload_eg711a);
- if(payload_pcma)
- iks_delete(payload_pcma);
- ast_log(LOG_WARNING,"Failed to allocate iks node");
- return -1;
- }
- iks_insert_attrib(payload_pcma, "id", "8");
- iks_insert_attrib(payload_pcma, "name", "PCMA");
- iks_insert_attrib(payload_pcma, "clockrate","8000");
- iks_insert_attrib(payload_pcma, "bitrate","64000");
- payload_eg711a = iks_new("payload-type");
- iks_insert_attrib(payload_eg711a, "id", "101");
- iks_insert_attrib(payload_eg711a, "name", "EG711A");
- iks_insert_attrib(payload_eg711a, "clockrate","8000");
- iks_insert_attrib(payload_eg711a, "bitrate","64000");
- iks_insert_node(dcodecs, payload_pcma);
- iks_insert_node(dcodecs, payload_eg711a);
- res ++;
- }
- if (!strcasecmp("ilbc", format)) {
- iks *payload_ilbc = iks_new("payload-type");
- if(!payload_ilbc) {
- ast_log(LOG_WARNING,"Failed to allocate iks node");
- return -1;
- }
- iks_insert_attrib(payload_ilbc, "id", "97");
- iks_insert_attrib(payload_ilbc, "name", "iLBC");
- iks_insert_attrib(payload_ilbc, "clockrate","8000");
- iks_insert_attrib(payload_ilbc, "bitrate","13300");
- iks_insert_node(dcodecs, payload_ilbc);
- res ++;
- }
- if (!strcasecmp("g723", format)) {
- iks *payload_g723 = iks_new("payload-type");
- if(!payload_g723) {
- ast_log(LOG_WARNING,"Failed to allocate iks node");
- return -1;
- }
- iks_insert_attrib(payload_g723, "id", "4");
- iks_insert_attrib(payload_g723, "name", "G723");
- iks_insert_attrib(payload_g723, "clockrate","8000");
- iks_insert_attrib(payload_g723, "bitrate","6300");
- iks_insert_node(dcodecs, payload_g723);
- res ++;
- }
- if (!strcasecmp("speex", format)) {
- iks *payload_speex = iks_new("payload-type");
- if(!payload_speex) {
- ast_log(LOG_WARNING,"Failed to allocate iks node");
- return -1;
- }
- iks_insert_attrib(payload_speex, "id", "110");
- iks_insert_attrib(payload_speex, "name", "speex");
- iks_insert_attrib(payload_speex, "clockrate","8000");
- iks_insert_attrib(payload_speex, "bitrate","11000");
- iks_insert_node(dcodecs, payload_speex);
- res++;
- }
- if (!strcasecmp("gsm", format)) {
- iks *payload_gsm = iks_new("payload-type");
- if(!payload_gsm) {
- ast_log(LOG_WARNING,"Failed to allocate iks node");
- return -1;
- }
- iks_insert_attrib(payload_gsm, "id", "103");
- iks_insert_attrib(payload_gsm, "name", "gsm");
- iks_insert_node(dcodecs, payload_gsm);
- res++;
- }
- ast_rtp_lookup_code(p->rtp, 1, codec);
- return res;
-}
-
-static int gtalk_invite(struct gtalk_pvt *p, char *to, char *from, char *sid, int initiator)
-{
- struct gtalk *client = p->parent;
- iks *iq, *gtalk, *dcodecs, *payload_telephone, *transport;
- int x;
- int pref_codec = 0;
- int alreadysent = 0;
- int codecs_num = 0;
-
- iq = iks_new("iq");
- gtalk = iks_new("session");
- dcodecs = iks_new("description");
- transport = iks_new("transport");
- payload_telephone = iks_new("payload-type");
- if (!(iq && gtalk && dcodecs && transport && payload_telephone)){
- if(iq)
- iks_delete(iq);
- if(gtalk)
- iks_delete(gtalk);
- if(dcodecs)
- iks_delete(dcodecs);
- if(transport)
- iks_delete(transport);
- if(payload_telephone)
- iks_delete(payload_telephone);
-
- ast_log(LOG_ERROR, "Could not allocate iksemel nodes\n");
- return 0;
- }
- iks_insert_attrib(dcodecs, "xmlns", "http://www.google.com/session/phone");
- iks_insert_attrib(dcodecs, "xml:lang", "en");
-
- for (x = 0; x < 32; x++) {
- if (!(pref_codec = ast_codec_pref_index(&client->prefs, x)))
- break;
- if (!(client->capability & pref_codec))
- continue;
- if (alreadysent & pref_codec)
- continue;
- codecs_num = add_codec_to_answer(p, pref_codec, dcodecs);
- alreadysent |= pref_codec;
- }
-
- if (codecs_num) {
- /* only propose DTMF within an audio session */
- iks_insert_attrib(payload_telephone, "id", "106");
- iks_insert_attrib(payload_telephone, "name", "telephone-event");
- iks_insert_attrib(payload_telephone, "clockrate", "8000");
- }
- iks_insert_attrib(transport,"xmlns","http://www.google.com/transport/p2p");
-
- iks_insert_attrib(iq, "type", "set");
- iks_insert_attrib(iq, "to", to);
- iks_insert_attrib(iq, "from", from);
- iks_insert_attrib(iq, "id", client->connection->mid);
- ast_aji_increment_mid(client->connection->mid);
-
- iks_insert_attrib(gtalk, "xmlns", "http://www.google.com/session");
- iks_insert_attrib(gtalk, "type",initiator ? "initiate": "accept");
- iks_insert_attrib(gtalk, "initiator", initiator ? from : to);
- iks_insert_attrib(gtalk, "id", sid);
- iks_insert_node(iq, gtalk);
- iks_insert_node(gtalk, dcodecs);
- iks_insert_node(gtalk, transport);
- iks_insert_node(dcodecs, payload_telephone);
-
- iks_send(client->connection->p, iq);
- iks_delete(payload_telephone);
- iks_delete(transport);
- iks_delete(dcodecs);
- iks_delete(gtalk);
- iks_delete(iq);
- return 1;
-}
-
-static int gtalk_invite_response(struct gtalk_pvt *p, char *to , char *from, char *sid, int initiator)
-{
- iks *iq, *session, *transport;
- iq = iks_new("iq");
- session = iks_new("session");
- transport = iks_new("transport");
- if(!(iq && session && transport)) {
- if(iq)
- iks_delete(iq);
- if(session)
- iks_delete(session);
- if(transport)
- iks_delete(transport);
- ast_log(LOG_ERROR, " Unable to allocate IKS node\n");
- return -1;
- }
- iks_insert_attrib(iq, "from", from);
- iks_insert_attrib(iq, "to", to);
- iks_insert_attrib(iq, "type", "set");
- iks_insert_attrib(iq, "id",p->parent->connection->mid);
- ast_aji_increment_mid(p->parent->connection->mid);
- iks_insert_attrib(session, "type", "transport-accept");
- iks_insert_attrib(session, "id", sid);
- iks_insert_attrib(session, "initiator", initiator ? from : to);
- iks_insert_attrib(session, "xmlns", "http://www.google.com/session");
- iks_insert_attrib(transport, "xmlns", "http://www.google.com/transport/p2p");
- iks_insert_node(iq,session);
- iks_insert_node(session,transport);
- iks_send(p->parent->connection->p, iq);
- iks_delete(transport);
- iks_delete(session);
- iks_delete(iq);
- return 1;
-
-}
-
-static int gtalk_ringing_ack(void *data, ikspak *pak)
-{
- struct gtalk_pvt *p = data;
-
- if (p->ringrule)
- iks_filter_remove_rule(p->parent->connection->f, p->ringrule);
- p->ringrule = NULL;
- if (p->owner)
- ast_queue_control(p->owner, AST_CONTROL_RINGING);
- return IKS_FILTER_EAT;
-}
-
-static int gtalk_answer(struct ast_channel *ast)
-{
- struct gtalk_pvt *p = ast->tech_pvt;
- int res = 0;
-
- if (option_debug)
- ast_log(LOG_DEBUG, "Answer!\n");
- ast_mutex_lock(&p->lock);
- gtalk_invite(p, p->them, p->us,p->sid, 0);
- ast_mutex_unlock(&p->lock);
- return res;
-}
-
-static enum ast_rtp_get_result gtalk_get_rtp_peer(struct ast_channel *chan, struct ast_rtp **rtp)
-{
- struct gtalk_pvt *p = chan->tech_pvt;
- enum ast_rtp_get_result res = AST_RTP_GET_FAILED;
-
- if (!p)
- return res;
-
- ast_mutex_lock(&p->lock);
- if (p->rtp){
- *rtp = p->rtp;
- res = AST_RTP_TRY_PARTIAL;
- }
- ast_mutex_unlock(&p->lock);
-
- return res;
-}
-
-static int gtalk_get_codec(struct ast_channel *chan)
-{
- struct gtalk_pvt *p = chan->tech_pvt;
- return p->peercapability;
-}
-
-static int gtalk_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs, int nat_active)
-{
- struct gtalk_pvt *p;
-
- p = chan->tech_pvt;
- if (!p)
- return -1;
- ast_mutex_lock(&p->lock);
-
-/* if (rtp)
- ast_rtp_get_peer(rtp, &p->redirip);
- else
- memset(&p->redirip, 0, sizeof(p->redirip));
- p->redircodecs = codecs; */
-
- /* Reset lastrtprx timer */
- ast_mutex_unlock(&p->lock);
- return 0;
-}
-
-static int gtalk_response(struct gtalk *client, char *from, ikspak *pak, const char *reasonstr, const char *reasonstr2)
-{
- iks *response = NULL, *error = NULL, *reason = NULL;
- int res = -1;
-
- response = iks_new("iq");
- if (response) {
- iks_insert_attrib(response, "type", "result");
- iks_insert_attrib(response, "from", from);
- iks_insert_attrib(response, "to", iks_find_attrib(pak->x, "from"));
- iks_insert_attrib(response, "id", iks_find_attrib(pak->x, "id"));
- if (reasonstr) {
- error = iks_new("error");
- if (error) {
- iks_insert_attrib(error, "type", "cancel");
- reason = iks_new(reasonstr);
- if (reason)
- iks_insert_node(error, reason);
- iks_insert_node(response, error);
- }
- }
- iks_send(client->connection->p, response);
- if (reason)
- iks_delete(reason);
- if (error)
- iks_delete(error);
- iks_delete(response);
- res = 0;
- }
- return res;
-}
-
-static int gtalk_is_answered(struct gtalk *client, ikspak *pak)
-{
- struct gtalk_pvt *tmp;
- char *from;
- iks *codec;
- char s1[BUFSIZ], s2[BUFSIZ], s3[BUFSIZ];
- int peernoncodeccapability;
-
- ast_log(LOG_DEBUG, "The client is %s\n", client->name);
- /* Make sure our new call doesn't exist yet */
- for (tmp = client->p; tmp; tmp = tmp->next) {
- if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid))
- break;
- }
-
- /* codec points to the first <payload-type/> tag */
- codec = iks_child(iks_child(iks_child(pak->x)));
- while (codec) {
- ast_rtp_set_m_type(tmp->rtp, atoi(iks_find_attrib(codec, "id")));
- ast_rtp_set_rtpmap_type(tmp->rtp, atoi(iks_find_attrib(codec, "id")), "audio", iks_find_attrib(codec, "name"), 0);
- codec = iks_next(codec);
- }
-
- /* Now gather all of the codecs that we are asked for */
- ast_rtp_get_current_formats(tmp->rtp, &tmp->peercapability, &peernoncodeccapability);
-
- /* at this point, we received an awser from the remote Gtalk client,
- which allows us to compare capabilities */
- tmp->jointcapability = tmp->capability & tmp->peercapability;
- if (!tmp->jointcapability) {
- ast_log(LOG_WARNING, "Capabilities don't match : us - %s, peer - %s, combined - %s \n", ast_getformatname_multiple(s1, BUFSIZ, tmp->capability),
- ast_getformatname_multiple(s2, BUFSIZ, tmp->peercapability),
- ast_getformatname_multiple(s3, BUFSIZ, tmp->jointcapability));
- /* close session if capabilities don't match */
- ast_queue_hangup(tmp->owner);
-
- return -1;
-
- }
-
- from = iks_find_attrib(pak->x, "to");
- if(!from)
- from = client->connection->jid->full;
-
- if (tmp) {
- if (tmp->owner)
- ast_queue_control(tmp->owner, AST_CONTROL_ANSWER);
- } else
- ast_log(LOG_NOTICE, "Whoa, didn't find call!\n");
- gtalk_response(client, from, pak, NULL, NULL);
- return 1;
-}
-
-static int gtalk_is_accepted(struct gtalk *client, ikspak *pak)
-{
- struct gtalk_pvt *tmp;
- char *from;
-
- ast_log(LOG_DEBUG, "The client is %s\n", client->name);
- /* find corresponding call */
- for (tmp = client->p; tmp; tmp = tmp->next) {
- if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid))
- break;
- }
-
- from = iks_find_attrib(pak->x, "to");
- if(!from)
- from = client->connection->jid->full;
-
- if (!tmp)
- ast_log(LOG_NOTICE, "Whoa, didn't find call!\n");
-
- /* answer 'iq' packet to let the remote peer know that we're alive */
- gtalk_response(client, from, pak, NULL, NULL);
- return 1;
-}
-
-static int gtalk_handle_dtmf(struct gtalk *client, ikspak *pak)
-{
- struct gtalk_pvt *tmp;
- iks *dtmfnode = NULL, *dtmfchild = NULL;
- char *dtmf;
- char *from;
- /* Make sure our new call doesn't exist yet */
- for (tmp = client->p; tmp; tmp = tmp->next) {
- if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) || iks_find_with_attrib(pak->x, "gtalk", "sid", tmp->sid))
- break;
- }
- from = iks_find_attrib(pak->x, "to");
- if(!from)
- from = client->connection->jid->full;
-
-
- if (tmp) {
- if(iks_find_with_attrib(pak->x, "dtmf-method", "method", "rtp")) {
- gtalk_response(client, from, pak,
- "feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
- "unsupported-dtmf-method xmlns='http://jabber.org/protocol/gtalk/info/dtmf#errors'");
- return -1;
- }
- if ((dtmfnode = iks_find(pak->x, "dtmf"))) {
- if((dtmf = iks_find_attrib(dtmfnode, "code"))) {
- if(iks_find_with_attrib(pak->x, "dtmf", "action", "button-up")) {
- struct ast_frame f = {AST_FRAME_DTMF_BEGIN, };
- f.subclass = dtmf[0];
- ast_queue_frame(tmp->owner, &f);
- ast_verbose("GOOGLE! DTMF-relay event received: %c\n", f.subclass);
- } else if(iks_find_with_attrib(pak->x, "dtmf", "action", "button-down")) {
- struct ast_frame f = {AST_FRAME_DTMF_END, };
- f.subclass = dtmf[0];
- ast_queue_frame(tmp->owner, &f);
- ast_verbose("GOOGLE! DTMF-relay event received: %c\n", f.subclass);
- } else if(iks_find_attrib(pak->x, "dtmf")) { /* 250 millasecond default */
- struct ast_frame f = {AST_FRAME_DTMF, };
- f.subclass = dtmf[0];
- ast_queue_frame(tmp->owner, &f);
- ast_verbose("GOOGLE! DTMF-relay event received: %c\n", f.subclass);
- }
- }
- } else if ((dtmfnode = iks_find_with_attrib(pak->x, "gtalk", "action", "session-info"))) {
- if((dtmfchild = iks_find(dtmfnode, "dtmf"))) {
- if((dtmf = iks_find_attrib(dtmfchild, "code"))) {
- if(iks_find_with_attrib(dtmfnode, "dtmf", "action", "button-up")) {
- struct ast_frame f = {AST_FRAME_DTMF_END, };
- f.subclass = dtmf[0];
- ast_queue_frame(tmp->owner, &f);
- ast_verbose("GOOGLE! DTMF-relay event received: %c\n", f.subclass);
- } else if(iks_find_with_attrib(dtmfnode, "dtmf", "action", "button-down")) {
- struct ast_frame f = {AST_FRAME_DTMF_BEGIN, };
- f.subclass = dtmf[0];
- ast_queue_frame(tmp->owner, &f);
- ast_verbose("GOOGLE! DTMF-relay event received: %c\n", f.subclass);
- }
- }
- }
- }
- gtalk_response(client, from, pak, NULL, NULL);
- return 1;
- } else
- ast_log(LOG_NOTICE, "Whoa, didn't find call!\n");
-
- gtalk_response(client, from, pak, NULL, NULL);
- return 1;
-}
-
-static int gtalk_hangup_farend(struct gtalk *client, ikspak *pak)
-{
- struct gtalk_pvt *tmp;
- char *from;
-
- ast_log(LOG_DEBUG, "The client is %s\n", client->name);
- /* Make sure our new call doesn't exist yet */
- for (tmp = client->p; tmp; tmp = tmp->next) {
- if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid))
- break;
- }
- from = iks_find_attrib(pak->x, "to");
- if(!from)
- from = client->connection->jid->full;
-
- if (tmp) {
- tmp->alreadygone = 1;
- if (tmp->owner)
- ast_queue_hangup(tmp->owner);
- } else
- ast_log(LOG_NOTICE, "Whoa, didn't find call!\n");
- gtalk_response(client, from, pak, NULL, NULL);
- return 1;
-}
-
-static int gtalk_create_candidates(struct gtalk *client, struct gtalk_pvt *p, char *sid, char *from, char *to)
-{
- struct gtalk_candidate *tmp;
- struct aji_client *c = client->connection;
- struct gtalk_candidate *ours1 = NULL, *ours2 = NULL;
- struct sockaddr_in sin;
- struct sockaddr_in dest;
- struct in_addr us;
- iks *iq, *gtalk, *candidate, *transport;
- char user[17], pass[17], preference[5], port[7];
-
-
- iq = iks_new("iq");
- gtalk = iks_new("session");
- candidate = iks_new("candidate");
- transport = iks_new("transport");
- if (!iq || !gtalk || !candidate || !transport) {
- ast_log(LOG_ERROR, "Memory allocation error\n");
- goto safeout;
- }
- ours1 = ast_calloc(1, sizeof(*ours1));
- ours2 = ast_calloc(1, sizeof(*ours2));
- if (!ours1 || !ours2)
- goto safeout;
-
- iks_insert_attrib(transport, "xmlns","http://www.google.com/transport/p2p");
- iks_insert_node(iq, gtalk);
- iks_insert_node(gtalk,transport);
- iks_insert_node(transport, candidate);
-
- for (; p; p = p->next) {
- if (!strcasecmp(p->sid, sid))
- break;
- }
-
- if (!p) {
- ast_log(LOG_NOTICE, "No matching gtalk session - SID %s!\n", sid);
- goto safeout;
- }
-
- ast_rtp_get_us(p->rtp, &sin);
- ast_find_ourip(&us, bindaddr);
-
- /* Setup our gtalk candidates */
- ast_copy_string(ours1->name, "rtp", sizeof(ours1->name));
- ours1->port = ntohs(sin.sin_port);
- ours1->preference = 1;
- snprintf(user, sizeof(user), "%08lx%08lx", ast_random(), ast_random());
- snprintf(pass, sizeof(pass), "%08lx%08lx", ast_random(), ast_random());
- ast_copy_string(ours1->username, user, sizeof(ours1->username));
- ast_copy_string(ours1->password, pass, sizeof(ours1->password));
- ast_copy_string(ours1->ip, ast_inet_ntoa(us), sizeof(ours1->ip));
- ours1->protocol = AJI_PROTOCOL_UDP;
- ours1->type = AJI_CONNECT_LOCAL;
- ours1->generation = 0;
- p->ourcandidates = ours1;
-
- if (!ast_strlen_zero(externip)) {
- /* XXX We should really stun for this one not just go with externip XXX */
- snprintf(user, sizeof(user), "%08lx%08lx", ast_random(), ast_random());
- snprintf(pass, sizeof(pass), "%08lx%08lx", ast_random(), ast_random());
- ast_copy_string(ours2->username, user, sizeof(ours2->username));
- ast_copy_string(ours2->password, pass, sizeof(ours2->password));
- ast_copy_string(ours2->ip, externip, sizeof(ours2->ip));
- ast_copy_string(ours2->name, "rtp", sizeof(ours1->name));
- ours2->port = ntohs(sin.sin_port);
- ours2->preference = 0.9;
- ours2->protocol = AJI_PROTOCOL_UDP;
- ours2->type = AJI_CONNECT_STUN;
- ours2->generation = 0;
- ours1->next = ours2;
- ours2 = NULL;
- }
- ours1 = NULL;
- dest.sin_addr = __ourip;
- dest.sin_port = sin.sin_port;
-
-
- for (tmp = p->ourcandidates; tmp; tmp = tmp->next) {
- snprintf(port, sizeof(port), "%d", tmp->port);
- snprintf(preference, sizeof(preference), "%.2f", tmp->preference);
- iks_insert_attrib(iq, "from", to);
- iks_insert_attrib(iq, "to", from);
- iks_insert_attrib(iq, "type", "set");
- iks_insert_attrib(iq, "id", c->mid);
- ast_aji_increment_mid(c->mid);
- iks_insert_attrib(gtalk, "type", "transport-info");
- iks_insert_attrib(gtalk, "id", sid);
- iks_insert_attrib(gtalk, "initiator", (p->initiator) ? to : from);
- iks_insert_attrib(gtalk, "xmlns", GOOGLE_NS);
- iks_insert_attrib(candidate, "name", tmp->name);
- iks_insert_attrib(candidate, "address", tmp->ip);
- iks_insert_attrib(candidate, "port", port);
- iks_insert_attrib(candidate, "username", tmp->username);
- iks_insert_attrib(candidate, "password", tmp->password);
- iks_insert_attrib(candidate, "preference", preference);
- if (tmp->protocol == AJI_PROTOCOL_UDP)
- iks_insert_attrib(candidate, "protocol", "udp");
- if (tmp->protocol == AJI_PROTOCOL_SSLTCP)
- iks_insert_attrib(candidate, "protocol", "ssltcp");
- if (tmp->type == AJI_CONNECT_STUN)
- iks_insert_attrib(candidate, "type", "stun");
- if (tmp->type == AJI_CONNECT_LOCAL)
- iks_insert_attrib(candidate, "type", "local");
- if (tmp->type == AJI_CONNECT_RELAY)
- iks_insert_attrib(candidate, "type", "relay");
- iks_insert_attrib(candidate, "network", "0");
- iks_insert_attrib(candidate, "generation", "0");
- iks_send(c->p, iq);
- }
- p->laststun = 0;
-
-safeout:
- if (ours1)
- free(ours1);
- if (ours2)
- free(ours2);
- if (iq)
- iks_delete(iq);
- if (gtalk)
- iks_delete(gtalk);
- if (candidate)
- iks_delete(candidate);
- if(transport)
- iks_delete(transport);
- return 1;
-}
-
-static struct gtalk_pvt *gtalk_alloc(struct gtalk *client, const char *us, const char *them, const char *sid)
-{
- struct gtalk_pvt *tmp = NULL;
- struct aji_resource *resources = NULL;
- struct aji_buddy *buddy;
- char idroster[200];
- char *data, *exten = NULL;
-
- if (option_debug)
- ast_log(LOG_DEBUG, "The client is %s for alloc\n", client->name);
- if (!sid && !strchr(them, '/')) { /* I started call! */
- if (!strcasecmp(client->name, "guest")) {
- buddy = ASTOBJ_CONTAINER_FIND(&client->connection->buddies, them);
- if (buddy)
- resources = buddy->resources;
- } else if (client->buddy)
- resources = client->buddy->resources;
- while (resources) {
- if (resources->cap->jingle) {
- break;
- }
- resources = resources->next;
- }
- if (resources)
- snprintf(idroster, sizeof(idroster), "%s/%s", them, resources->resource);
- else {
- ast_log(LOG_ERROR, "no gtalk capable clients to talk to.\n");
- return NULL;
- }
- }
- if (!(tmp = ast_calloc(1, sizeof(*tmp)))) {
- return NULL;
- }
- if (sid) {
- ast_copy_string(tmp->sid, sid, sizeof(tmp->sid));
- ast_copy_string(tmp->them, them, sizeof(tmp->them));
- ast_copy_string(tmp->us, us, sizeof(tmp->us));
- } else {
- snprintf(tmp->sid, sizeof(tmp->sid), "%08lx%08lx", ast_random(), ast_random());
- ast_copy_string(tmp->them, idroster, sizeof(tmp->them));
- ast_copy_string(tmp->us, us, sizeof(tmp->us));
- tmp->initiator = 1;
- }
- /* clear codecs */
- tmp->rtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr);
- ast_rtp_pt_clear(tmp->rtp);
-
- /* add user configured codec capabilites */
- if (client->capability)
- tmp->capability = client->capability;
- else if (global_capability)
- tmp->capability = global_capability;
-
- tmp->parent = client;
- if (!tmp->rtp) {
- ast_log(LOG_WARNING, "Out of RTP sessions?\n");
- free(tmp);
- return NULL;
- }
-
- /* Set CALLERID(name) to the full JID of the remote peer */
- ast_copy_string(tmp->cid_name, tmp->them, sizeof(tmp->cid_name));
-
- if(strchr(tmp->us, '/')) {
- data = ast_strdupa(tmp->us);
- exten = strsep(&data, "/");
- } else
- exten = tmp->us;
- ast_copy_string(tmp->exten, exten, sizeof(tmp->exten));
- ast_mutex_init(&tmp->lock);
- ast_mutex_lock(&gtalklock);
- tmp->next = client->p;
- client->p = tmp;
- ast_mutex_unlock(&gtalklock);
- return tmp;
-}
-
-/*! \brief Start new gtalk channel */
-static struct ast_channel *gtalk_new(struct gtalk *client, struct gtalk_pvt *i, int state, const char *title)
-{
- struct ast_channel *tmp;
- int fmt;
- int what;
- const char *n2;
-
- if (title)
- n2 = title;
- else
- n2 = i->us;
- tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, client->accountcode, i->exten, client->context, client->amaflags, "Gtalk/%s-%04lx", n2, ast_random() & 0xffff);
- if (!tmp) {
- ast_log(LOG_WARNING, "Unable to allocate Gtalk channel structure!\n");
- return NULL;
- }
- tmp->tech = &gtalk_tech;
-
- /* Select our native format based on codec preference until we receive
- something from another device to the contrary. */
- if (i->jointcapability)
- what = i->jointcapability;
- else if (i->capability)
- what = i->capability;
- else
- what = global_capability;
- tmp->nativeformats = ast_codec_choose(&i->prefs, what, 1) | (i->jointcapability & AST_FORMAT_VIDEO_MASK);
- fmt = ast_best_codec(tmp->nativeformats);
-
- if (i->rtp) {
- ast_rtp_setstun(i->rtp, 1);
- tmp->fds[0] = ast_rtp_fd(i->rtp);
- tmp->fds[1] = ast_rtcp_fd(i->rtp);
- }
- if (i->vrtp) {
- ast_rtp_setstun(i->rtp, 1);
- tmp->fds[2] = ast_rtp_fd(i->vrtp);
- tmp->fds[3] = ast_rtcp_fd(i->vrtp);
- }
- if (state == AST_STATE_RING)
- tmp->rings = 1;
- tmp->adsicpe = AST_ADSI_UNAVAILABLE;
- tmp->writeformat = fmt;
- tmp->rawwriteformat = fmt;
- tmp->readformat = fmt;
- tmp->rawreadformat = fmt;
- tmp->tech_pvt = i;
-
- tmp->callgroup = client->callgroup;
- tmp->pickupgroup = client->pickupgroup;
- tmp->cid.cid_pres = client->callingpres;
- if (!ast_strlen_zero(client->accountcode))
- ast_string_field_set(tmp, accountcode, client->accountcode);
- if (client->amaflags)
- tmp->amaflags = client->amaflags;
- if (!ast_strlen_zero(client->language))
- ast_string_field_set(tmp, language, client->language);
- if (!ast_strlen_zero(client->musicclass))
- ast_string_field_set(tmp, musicclass, client->musicclass);
- i->owner = tmp;
- ast_module_ref(ast_module_info->self);
- ast_copy_string(tmp->context, client->context, sizeof(tmp->context));
- ast_copy_string(tmp->exten, i->exten, sizeof(tmp->exten));
-
- if (!ast_strlen_zero(i->exten) && strcmp(i->exten, "s"))
- tmp->cid.cid_dnid = ast_strdup(i->exten);
- tmp->priority = 1;
- if (i->rtp)
- ast_jb_configure(tmp, &global_jbconf);
- if (state != AST_STATE_DOWN && ast_pbx_start(tmp)) {
- ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
- tmp->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
- ast_hangup(tmp);
- tmp = NULL;
- }
-
- return tmp;
-}
-
-static int gtalk_action(struct gtalk *client, struct gtalk_pvt *p, const char *action)
-{
- iks *request, *session = NULL;
- int res = -1;
-
- request = iks_new("iq");
- if (request) {
- iks_insert_attrib(request, "type", "set");
- iks_insert_attrib(request, "from", p->us);
- iks_insert_attrib(request, "to", p->them);
- iks_insert_attrib(request, "id", client->connection->mid);
- ast_aji_increment_mid(client->connection->mid);
- session = iks_new("session");
- if (session) {
- iks_insert_attrib(session, "type", action);
- iks_insert_attrib(session, "id", p->sid);
- iks_insert_attrib(session, "initiator", p->initiator ? p->us : p->them);
- iks_insert_attrib(session, "xmlns", "http://www.google.com/session");
- iks_insert_node(request, session);
- iks_send(client->connection->p, request);
- iks_delete(session);
- res = 0;
- }
- iks_delete(request);
- }
- return res;
-}
-
-static void gtalk_free_candidates(struct gtalk_candidate *candidate)
-{
- struct gtalk_candidate *last;
- while (candidate) {
- last = candidate;
- candidate = candidate->next;
- free(last);
- }
-}
-
-static void gtalk_free_pvt(struct gtalk *client, struct gtalk_pvt *p)
-{
- struct gtalk_pvt *cur, *prev = NULL;
- cur = client->p;
- while (cur) {
- if (cur == p) {
- if (prev)
- prev->next = p->next;
- else
- client->p = p->next;
- break;
- }
- prev = cur;
- cur = cur->next;
- }
- if (p->ringrule)
- iks_filter_remove_rule(p->parent->connection->f, p->ringrule);
- if (p->owner)
- ast_log(LOG_WARNING, "Uh oh, there's an owner, this is going to be messy.\n");
- if (p->rtp)
- ast_rtp_destroy(p->rtp);
- if (p->vrtp)
- ast_rtp_destroy(p->vrtp);
- gtalk_free_candidates(p->theircandidates);
- free(p);
-}
-
-
-static int gtalk_newcall(struct gtalk *client, ikspak *pak)
-{
- struct gtalk_pvt *p, *tmp = client->p;
- struct ast_channel *chan;
- int res;
- iks *codec;
- char *from = NULL;
- char s1[BUFSIZ], s2[BUFSIZ], s3[BUFSIZ];
- int peernoncodeccapability;
-
- /* Make sure our new call doesn't exist yet */
- from = iks_find_attrib(pak->x,"to");
- if(!from)
- from = client->connection->jid->full;
-
- while (tmp) {
- if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid)) {
- ast_log(LOG_NOTICE, "Ignoring duplicate call setup on SID %s\n", tmp->sid);
- gtalk_response(client, from, pak, "out-of-order", NULL);
- return -1;
- }
- tmp = tmp->next;
- }
-
- if (!strcasecmp(client->name, "guest")){
- /* the guest account is not tied to any configured XMPP client,
- let's set it now */
- client->connection = ast_aji_get_client(from);
- if (!client->connection) {
- ast_log(LOG_ERROR, "No XMPP client to talk to, us (partial JID) : %s\n", from);
- return -1;
- }
- }
-
- p = gtalk_alloc(client, from, pak->from->full, iks_find_attrib(pak->query, "id"));
- if (!p) {
- ast_log(LOG_WARNING, "Unable to allocate gtalk structure!\n");
- return -1;
- }
-
- chan = gtalk_new(client, p, AST_STATE_DOWN, pak->from->user);
- if (!chan) {
- gtalk_free_pvt(client, p);
- return -1;
- }
-
- ast_mutex_lock(&p->lock);
- ast_copy_string(p->them, pak->from->full, sizeof(p->them));
- if (iks_find_attrib(pak->query, "id")) {
- ast_copy_string(p->sid, iks_find_attrib(pak->query, "id"),
- sizeof(p->sid));
- }
-
- /* codec points to the first <payload-type/> tag */
- codec = iks_child(iks_child(iks_child(pak->x)));
-
- while (codec) {
- ast_rtp_set_m_type(p->rtp, atoi(iks_find_attrib(codec, "id")));
- ast_rtp_set_rtpmap_type(p->rtp, atoi(iks_find_attrib(codec, "id")), "audio", iks_find_attrib(codec, "name"), 0);
- codec = iks_next(codec);
- }
-
- /* Now gather all of the codecs that we are asked for */
- ast_rtp_get_current_formats(p->rtp, &p->peercapability, &peernoncodeccapability);
- p->jointcapability = p->capability & p->peercapability;
- ast_mutex_unlock(&p->lock);
-
- ast_setstate(chan, AST_STATE_RING);
- if (!p->jointcapability) {
- ast_log(LOG_WARNING, "Capabilities don't match : us - %s, peer - %s, combined - %s \n", ast_getformatname_multiple(s1, BUFSIZ, p->capability),
- ast_getformatname_multiple(s2, BUFSIZ, p->peercapability),
- ast_getformatname_multiple(s3, BUFSIZ, p->jointcapability));
- /* close session if capabilities don't match */
- gtalk_action(client, p, "reject");
- p->alreadygone = 1;
- gtalk_hangup(chan);
- ast_channel_free(chan);
- return -1;
- }
-
- res = ast_pbx_start(chan);
-
- switch (res) {
- case AST_PBX_FAILED:
- ast_log(LOG_WARNING, "Failed to start PBX :(\n");
- gtalk_response(client, from, pak, "service-unavailable", NULL);
- break;
- case AST_PBX_CALL_LIMIT:
- ast_log(LOG_WARNING, "Failed to start PBX (call limit reached) \n");
- gtalk_response(client, from, pak, "service-unavailable", NULL);
- break;
- case AST_PBX_SUCCESS:
- gtalk_response(client, from, pak, NULL, NULL);
- gtalk_invite_response(p, p->them, p->us,p->sid, 0);
- gtalk_create_candidates(client, p, p->sid, p->them, p->us);
- /* nothing to do */
- break;
- }
-
- return 1;
-}
-
-static int gtalk_update_stun(struct gtalk *client, struct gtalk_pvt *p)
-{
- struct gtalk_candidate *tmp;
- struct hostent *hp;
- struct ast_hostent ahp;
- struct sockaddr_in sin;
- struct sockaddr_in aux;
-
- if (time(NULL) == p->laststun)
- return 0;
-
- tmp = p->theircandidates;
- p->laststun = time(NULL);
- while (tmp) {
- char username[256];
-
- /* Find the IP address of the host */
- hp = ast_gethostbyname(tmp->ip, &ahp);
- sin.sin_family = AF_INET;
- memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
- sin.sin_port = htons(tmp->port);
- snprintf(username, sizeof(username), "%s%s", tmp->username,
- p->ourcandidates->username);
-
- /* Find out the result of the STUN */
- ast_rtp_get_peer(p->rtp, &aux);
-
- /* If the STUN result is different from the IP of the hostname,
- lock on the stun IP of the hostname advertised by the
- remote client */
- if (aux.sin_addr.s_addr &&
- aux.sin_addr.s_addr != sin.sin_addr.s_addr)
- ast_rtp_stun_request(p->rtp, &aux, username);
- else
- ast_rtp_stun_request(p->rtp, &sin, username);
-
- if (aux.sin_addr.s_addr && option_debug > 3) {
- ast_log(LOG_DEBUG, "Receiving RTP traffic from IP %s, matches with remote candidate's IP %s\n", ast_inet_ntoa(aux.sin_addr), tmp->ip);
- ast_log(LOG_DEBUG, "Sending STUN request to %s\n", tmp->ip);
- }
-
- tmp = tmp->next;
- }
- return 1;
-}
-
-static int gtalk_add_candidate(struct gtalk *client, ikspak *pak)
-{
- struct gtalk_pvt *p = NULL, *tmp = NULL;
- struct aji_client *c = client->connection;
- struct gtalk_candidate *newcandidate = NULL;
- iks *traversenodes = NULL, *receipt = NULL;
- char *from;
-
- from = iks_find_attrib(pak->x,"to");
- if(!from)
- from = c->jid->full;
-
- for (tmp = client->p; tmp; tmp = tmp->next) {
- if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid)) {
- p = tmp;
- break;
- }
- }
-
- if (!p)
- return -1;
-
- traversenodes = pak->query;
- while(traversenodes) {
- if(!strcasecmp(iks_name(traversenodes), "session")) {
- traversenodes = iks_child(traversenodes);
- continue;
- }
- if(!strcasecmp(iks_name(traversenodes), "transport")) {
- traversenodes = iks_child(traversenodes);
- continue;
- }
- if(!strcasecmp(iks_name(traversenodes), "candidate")) {
- newcandidate = ast_calloc(1, sizeof(*newcandidate));
- if (!newcandidate)
- return 0;
- ast_copy_string(newcandidate->name, iks_find_attrib(traversenodes, "name"),
- sizeof(newcandidate->name));
- ast_copy_string(newcandidate->ip, iks_find_attrib(traversenodes, "address"),
- sizeof(newcandidate->ip));
- newcandidate->port = atoi(iks_find_attrib(traversenodes, "port"));
- ast_copy_string(newcandidate->username, iks_find_attrib(traversenodes, "username"),
- sizeof(newcandidate->username));
- ast_copy_string(newcandidate->password, iks_find_attrib(traversenodes, "password"),
- sizeof(newcandidate->password));
- newcandidate->preference = atof(iks_find_attrib(traversenodes, "preference"));
- if (!strcasecmp(iks_find_attrib(traversenodes, "protocol"), "udp"))
- newcandidate->protocol = AJI_PROTOCOL_UDP;
- if (!strcasecmp(iks_find_attrib(traversenodes, "protocol"), "ssltcp"))
- newcandidate->protocol = AJI_PROTOCOL_SSLTCP;
-
- if (!strcasecmp(iks_find_attrib(traversenodes, "type"), "stun"))
- newcandidate->type = AJI_CONNECT_STUN;
- if (!strcasecmp(iks_find_attrib(traversenodes, "type"), "local"))
- newcandidate->type = AJI_CONNECT_LOCAL;
- if (!strcasecmp(iks_find_attrib(traversenodes, "type"), "relay"))
- newcandidate->type = AJI_CONNECT_RELAY;
- ast_copy_string(newcandidate->network, iks_find_attrib(traversenodes, "network"),
- sizeof(newcandidate->network));
- newcandidate->generation = atoi(iks_find_attrib(traversenodes, "generation"));
- newcandidate->next = NULL;
-
- newcandidate->next = p->theircandidates;
- p->theircandidates = newcandidate;
- p->laststun = 0;
- gtalk_update_stun(p->parent, p);
- newcandidate = NULL;
- }
- traversenodes = iks_next(traversenodes);
- }
-
- receipt = iks_new("iq");
- iks_insert_attrib(receipt, "type", "result");
- iks_insert_attrib(receipt, "from", from);
- iks_insert_attrib(receipt, "to", iks_find_attrib(pak->x, "from"));
- iks_insert_attrib(receipt, "id", iks_find_attrib(pak->x, "id"));
- iks_send(c->p, receipt);
- iks_delete(receipt);
-
- return 1;
-}
-
-static struct ast_frame *gtalk_rtp_read(struct ast_channel *ast, struct gtalk_pvt *p)
-{
- struct ast_frame *f;
-
- if (!p->rtp)
- return &ast_null_frame;
- f = ast_rtp_read(p->rtp);
- gtalk_update_stun(p->parent, p);
- if (p->owner) {
- /* We already hold the channel lock */
- if (f->frametype == AST_FRAME_VOICE) {
- if (f->subclass != (p->owner->nativeformats & AST_FORMAT_AUDIO_MASK)) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Oooh, format changed to %d\n", f->subclass);
- p->owner->nativeformats =
- (p->owner->nativeformats & AST_FORMAT_VIDEO_MASK) | f->subclass;
- ast_set_read_format(p->owner, p->owner->readformat);
- ast_set_write_format(p->owner, p->owner->writeformat);
- }
-/* if ((ast_test_flag(p, SIP_DTMF) == SIP_DTMF_INBAND) && p->vad) {
- f = ast_dsp_process(p->owner, p->vad, f);
- if (option_debug && f && (f->frametype == AST_FRAME_DTMF))
- ast_log(LOG_DEBUG, "* Detected inband DTMF '%c'\n", f->subclass);
- } */
- }
- }
- return f;
-}
-
-static struct ast_frame *gtalk_read(struct ast_channel *ast)
-{
- struct ast_frame *fr;
- struct gtalk_pvt *p = ast->tech_pvt;
-
- ast_mutex_lock(&p->lock);
- fr = gtalk_rtp_read(ast, p);
- ast_mutex_unlock(&p->lock);
- return fr;
-}
-
-/*! \brief Send frame to media channel (rtp) */
-static int gtalk_write(struct ast_channel *ast, struct ast_frame *frame)
-{
- struct gtalk_pvt *p = ast->tech_pvt;
- int res = 0;
-
- switch (frame->frametype) {
- case AST_FRAME_VOICE:
- if (!(frame->subclass & ast->nativeformats)) {
- ast_log(LOG_WARNING,
- "Asked to transmit frame type %d, while native formats is %d (read/write = %d/%d)\n",
- frame->subclass, ast->nativeformats, ast->readformat,
- ast->writeformat);
- return 0;
- }
- if (p) {
- ast_mutex_lock(&p->lock);
- if (p->rtp) {
- res = ast_rtp_write(p->rtp, frame);
- }
- ast_mutex_unlock(&p->lock);
- }
- break;
- case AST_FRAME_VIDEO:
- if (p) {
- ast_mutex_lock(&p->lock);
- if (p->vrtp) {
- res = ast_rtp_write(p->vrtp, frame);
- }
- ast_mutex_unlock(&p->lock);
- }
- break;
- case AST_FRAME_IMAGE:
- return 0;
- break;
- default:
- ast_log(LOG_WARNING, "Can't send %d type frames with Gtalk write\n",
- frame->frametype);
- return 0;
- }
-
- return res;
-}
-
-static int gtalk_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
-{
- struct gtalk_pvt *p = newchan->tech_pvt;
- ast_mutex_lock(&p->lock);
-
- if ((p->owner != oldchan)) {
- ast_mutex_unlock(&p->lock);
- return -1;
- }
- if (p->owner == oldchan)
- p->owner = newchan;
- ast_mutex_unlock(&p->lock);
- return 0;
-}
-
-static int gtalk_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
-{
- int res = 0;
-
- switch (condition) {
- case AST_CONTROL_HOLD:
- ast_moh_start(ast, data, NULL);
- break;
- case AST_CONTROL_UNHOLD:
- ast_moh_stop(ast);
- break;
- default:
- ast_log(LOG_NOTICE, "Don't know how to indicate condition '%d'\n", condition);
- res = -1;
- }
-
- return res;
-}
-
-static int gtalk_digit_begin(struct ast_channel *chan, char digit)
-{
- return gtalk_digit(chan, digit, 0);
-}
-
-static int gtalk_digit_end(struct ast_channel *chan, char digit, unsigned int duration)
-{
- return gtalk_digit(chan, digit, duration);
-}
-
-static int gtalk_digit(struct ast_channel *ast, char digit, unsigned int duration)
-{
- struct gtalk_pvt *p = ast->tech_pvt;
- struct gtalk *client = p->parent;
- iks *iq, *gtalk, *dtmf;
- char buffer[2] = {digit, '\0'};
- iq = iks_new("iq");
- gtalk = iks_new("gtalk");
- dtmf = iks_new("dtmf");
- if(!iq || !gtalk || !dtmf) {
- if(iq)
- iks_delete(iq);
- if(gtalk)
- iks_delete(gtalk);
- if(dtmf)
- iks_delete(dtmf);
- ast_log(LOG_ERROR, "Did not send dtmf do to memory issue\n");
- return -1;
- }
-
- iks_insert_attrib(iq, "type", "set");
- iks_insert_attrib(iq, "to", p->them);
- iks_insert_attrib(iq, "from", p->us);
- iks_insert_attrib(iq, "id", client->connection->mid);
- ast_aji_increment_mid(client->connection->mid);
- iks_insert_attrib(gtalk, "xmlns", "http://jabber.org/protocol/gtalk");
- iks_insert_attrib(gtalk, "action", "session-info");
- iks_insert_attrib(gtalk, "initiator", p->initiator ? p->us: p->them);
- iks_insert_attrib(gtalk, "sid", p->sid);
- iks_insert_attrib(dtmf, "xmlns", "http://jabber.org/protocol/gtalk/info/dtmf");
- iks_insert_attrib(dtmf, "code", buffer);
- iks_insert_node(iq, gtalk);
- iks_insert_node(gtalk, dtmf);
-
- ast_mutex_lock(&p->lock);
- if (ast->dtmff.frametype == AST_FRAME_DTMF_BEGIN || duration == 0) {
- iks_insert_attrib(dtmf, "action", "button-down");
- } else if (ast->dtmff.frametype == AST_FRAME_DTMF_END || duration != 0) {
- iks_insert_attrib(dtmf, "action", "button-up");
- }
- iks_send(client->connection->p, iq);
- iks_delete(iq);
- iks_delete(gtalk);
- iks_delete(dtmf);
- ast_mutex_unlock(&p->lock);
- return 0;
-}
-
-static int gtalk_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
-{
- ast_log(LOG_NOTICE, "XXX Implement gtalk sendhtml XXX\n");
-
- return -1;
-}
-
-/* Not in use right now.
-static int gtalk_auto_congest(void *nothing)
-{
- struct gtalk_pvt *p = nothing;
-
- ast_mutex_lock(&p->lock);
- if (p->owner) {
- if (!ast_channel_trylock(p->owner)) {
- ast_log(LOG_NOTICE, "Auto-congesting %s\n", p->owner->name);
- ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
- ast_channel_unlock(p->owner);
- }
- }
- ast_mutex_unlock(&p->lock);
- return 0;
-}
-*/
-
-/*! \brief Initiate new call, part of PBX interface
- * dest is the dial string */
-static int gtalk_call(struct ast_channel *ast, char *dest, int timeout)
-{
- struct gtalk_pvt *p = ast->tech_pvt;
-
- if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
- ast_log(LOG_WARNING, "gtalk_call called on %s, neither down nor reserved\n", ast->name);
- return -1;
- }
-
- ast_setstate(ast, AST_STATE_RING);
- if (!p->ringrule) {
- ast_copy_string(p->ring, p->parent->connection->mid, sizeof(p->ring));
- p->ringrule = iks_filter_add_rule(p->parent->connection->f, gtalk_ringing_ack, p,
- IKS_RULE_ID, p->ring, IKS_RULE_DONE);
- } else
- ast_log(LOG_WARNING, "Whoa, already have a ring rule!\n");
-
- gtalk_invite(p, p->them, p->us, p->sid, 1);
- gtalk_create_candidates(p->parent, p, p->sid, p->them, p->us);
-
- return 0;
-}
-
-/*! \brief Hangup a call through the gtalk proxy channel */
-static int gtalk_hangup(struct ast_channel *ast)
-{
- struct gtalk_pvt *p = ast->tech_pvt;
- struct gtalk *client;
-
- ast_mutex_lock(&p->lock);
- client = p->parent;
- p->owner = NULL;
- ast->tech_pvt = NULL;
- if (!p->alreadygone)
- gtalk_action(client, p, "terminate");
- ast_mutex_unlock(&p->lock);
-
- gtalk_free_pvt(client, p);
- ast_module_unref(ast_module_info->self);
-
- return 0;
-}
-
-/*! \brief Part of PBX interface */
-static struct ast_channel *gtalk_request(const char *type, int format, void *data, int *cause)
-{
- struct gtalk_pvt *p = NULL;
- struct gtalk *client = NULL;
- char *sender = NULL, *to = NULL, *s = NULL;
- struct ast_channel *chan = NULL;
-
- if (data) {
- s = ast_strdupa(data);
- if (s) {
- sender = strsep(&s, "/");
- if (sender && (sender[0] != '\0'))
- to = strsep(&s, "/");
- if (!to) {
- ast_log(LOG_ERROR, "Bad arguments in Gtalk Dialstring: %s\n", (char*) data);
- return NULL;
- }
- }
- }
-
- client = find_gtalk(to, sender);
- if (!client) {
- ast_log(LOG_WARNING, "Could not find recipient.\n");
- return NULL;
- }
- if (!strcasecmp(client->name, "guest")){
- /* the guest account is not tied to any configured XMPP client,
- let's set it now */
- client->connection = ast_aji_get_client(sender);
- if (!client->connection) {
- ast_log(LOG_ERROR, "No XMPP client to talk to, us (partial JID) : %s\n", sender);
- ASTOBJ_UNREF(client, gtalk_member_destroy);
- return NULL;
- }
- }
-
- ASTOBJ_WRLOCK(client);
- p = gtalk_alloc(client, strchr(sender, '@') ? sender : client->connection->jid->full, strchr(to, '@') ? to : client->user, NULL);
- if (p)
- chan = gtalk_new(client, p, AST_STATE_DOWN, to);
-
- ASTOBJ_UNLOCK(client);
- return chan;
-}
-
-/*! \brief CLI command "gtalk show channels" */
-static int gtalk_show_channels(int fd, int argc, char **argv)
-{
-#define FORMAT "%-30.30s %-30.30s %-15.15s %-5.5s %-5.5s \n"
- struct gtalk_pvt *p;
- struct ast_channel *chan;
- int numchans = 0;
- char them[AJI_MAX_JIDLEN];
- char *jid = NULL;
- char *resource = NULL;
-
- if (argc != 3)
- return RESULT_SHOWUSAGE;
-
- ast_mutex_lock(&gtalklock);
- ast_cli(fd, FORMAT, "Channel", "Jabber ID", "Resource", "Read", "Write");
- ASTOBJ_CONTAINER_TRAVERSE(&gtalk_list, 1, {
- ASTOBJ_WRLOCK(iterator);
- p = iterator->p;
- while(p) {
- chan = p->owner;
- ast_copy_string(them, p->them, sizeof(them));
- jid = them;
- resource = strchr(them, '/');
- if (!resource)
- resource = "None";
- else {
- *resource = '\0';
- resource ++;
- }
- if (chan)
- ast_cli(fd, FORMAT,
- chan->name,
- jid,
- resource,
- ast_getformatname(chan->readformat),
- ast_getformatname(chan->writeformat)
- );
- else
- ast_log(LOG_WARNING, "No available channel\n");
- numchans ++;
- p = p->next;
- }
- ASTOBJ_UNLOCK(iterator);
- });
-
- ast_mutex_unlock(&gtalklock);
-
- ast_cli(fd, "%d active gtalk channel%s\n", numchans, (numchans != 1) ? "s" : "");
- return RESULT_SUCCESS;
-#undef FORMAT
-}
-
-/*! \brief CLI command "gtalk show channels" */
-static int gtalk_do_reload(int fd, int argc, char **argv)
-{
- ast_verbose("IT DOES WORK!\n");
- return RESULT_SUCCESS;
-}
-
-static int gtalk_parser(void *data, ikspak *pak)
-{
- struct gtalk *client = ASTOBJ_REF((struct gtalk *) data);
-
- if (iks_find_with_attrib(pak->x, "session", "type", "initiate")) {
- /* New call */
- gtalk_newcall(client, pak);
- } else if (iks_find_with_attrib(pak->x, "session", "type", "candidates") || iks_find_with_attrib(pak->x, "session", "type", "transport-info")) {
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "About to add candidate!\n");
- gtalk_add_candidate(client, pak);
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Candidate Added!\n");
- } else if (iks_find_with_attrib(pak->x, "session", "type", "accept")) {
- gtalk_is_answered(client, pak);
- } else if (iks_find_with_attrib(pak->x, "session", "type", "transport-accept")) {
- gtalk_is_accepted(client, pak);
- } else if (iks_find_with_attrib(pak->x, "session", "type", "content-info") || iks_find_with_attrib(pak->x, "gtalk", "action", "session-info")) {
- gtalk_handle_dtmf(client, pak);
- } else if (iks_find_with_attrib(pak->x, "session", "type", "terminate")) {
- gtalk_hangup_farend(client, pak);
- } else if (iks_find_with_attrib(pak->x, "session", "type", "reject")) {
- gtalk_hangup_farend(client, pak);
- }
- ASTOBJ_UNREF(client, gtalk_member_destroy);
- return IKS_FILTER_EAT;
-}
-
-/* Not using this anymore probably take out soon
-static struct gtalk_candidate *gtalk_create_candidate(char *args)
-{
- char *name, *type, *preference, *protocol;
- struct gtalk_candidate *res;
- res = malloc(sizeof(struct gtalk_candidate));
- memset(res, 0, sizeof(struct gtalk_candidate));
- if (args)
- name = args;
- if ((args = strchr(args, ','))) {
- *args = '\0';
- args++;
- preference = args;
- }
- if ((args = strchr(args, ','))) {
- *args = '\0';
- args++;
- protocol = args;
- }
- if ((args = strchr(args, ','))) {
- *args = '\0';
- args++;
- type = args;
- }
- if (name)
- ast_copy_string(res->name, name, sizeof(res->name));
- if (preference) {
- res->preference = atof(preference);
- }
- if (protocol) {
- if (!strcasecmp("udp", protocol))
- res->protocol = AJI_PROTOCOL_UDP;
- if (!strcasecmp("ssltcp", protocol))
- res->protocol = AJI_PROTOCOL_SSLTCP;
- }
- if (type) {
- if (!strcasecmp("stun", type))
- res->type = AJI_CONNECT_STUN;
- if (!strcasecmp("local", type))
- res->type = AJI_CONNECT_LOCAL;
- if (!strcasecmp("relay", type))
- res->type = AJI_CONNECT_RELAY;
- }
-
- return res;
-}
-*/
-
-static int gtalk_create_member(char *label, struct ast_variable *var, int allowguest,
- struct ast_codec_pref prefs, char *context,
- struct gtalk *member)
-{
- struct aji_client *client;
-
- if (!member)
- ast_log(LOG_WARNING, "Out of memory.\n");
-
- ast_copy_string(member->name, label, sizeof(member->name));
- ast_copy_string(member->user, label, sizeof(member->user));
- ast_copy_string(member->context, context, sizeof(member->context));
- member->allowguest = allowguest;
- member->prefs = prefs;
- while (var) {
-#if 0
- struct gtalk_candidate *candidate = NULL;
-#endif
- if (!strcasecmp(var->name, "username"))
- ast_copy_string(member->user, var->value, sizeof(member->user));
- else if (!strcasecmp(var->name, "disallow"))
- ast_parse_allow_disallow(&member->prefs, &member->capability, var->value, 0);
- else if (!strcasecmp(var->name, "allow"))
- ast_parse_allow_disallow(&member->prefs, &member->capability, var->value, 1);
- else if (!strcasecmp(var->name, "context"))
- ast_copy_string(member->context, var->value, sizeof(member->context));
-#if 0
- else if (!strcasecmp(var->name, "candidate")) {
- candidate = gtalk_create_candidate(var->value);
- if (candidate) {
- candidate->next = member->ourcandidates;
- member->ourcandidates = candidate;
- }
- }
-#endif
- else if (!strcasecmp(var->name, "connection")) {
- if ((client = ast_aji_get_client(var->value))) {
- member->connection = client;
- iks_filter_add_rule(client->f, gtalk_parser, member,
- IKS_RULE_TYPE, IKS_PAK_IQ,
- IKS_RULE_FROM_PARTIAL, member->user,
- IKS_RULE_NS, "http://www.google.com/session",
- IKS_RULE_DONE);
-
- } else {
- ast_log(LOG_ERROR, "connection referenced not found!\n");
- return 0;
- }
- }
- var = var->next;
- }
- if (member->connection && member->user)
- member->buddy = ASTOBJ_CONTAINER_FIND(&member->connection->buddies, member->user);
- else {
- ast_log(LOG_ERROR, "No Connection or Username!\n");
- }
- return 1;
-}
-
-static int gtalk_load_config(void)
-{
- char *cat = NULL;
- struct ast_config *cfg = NULL;
- char context[AST_MAX_CONTEXT];
- int allowguest = 1;
- struct ast_variable *var;
- struct gtalk *member;
- struct ast_codec_pref prefs;
- struct aji_client_container *clients;
- struct gtalk_candidate *global_candidates = NULL;
- struct hostent *hp;
- struct ast_hostent ahp;
-
- cfg = ast_config_load(GOOGLE_CONFIG);
- if (!cfg)
- return 0;
-
- /* Copy the default jb config over global_jbconf */
- memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
-
- cat = ast_category_browse(cfg, NULL);
- for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
- /* handle jb conf */
- if (!ast_jb_read_conf(&global_jbconf, var->name, var->value))
- continue;
-
- if (!strcasecmp(var->name, "allowguest"))
- allowguest =
- (ast_true(ast_variable_retrieve(cfg, "general", "allowguest"))) ? 1 : 0;
- else if (!strcasecmp(var->name, "disallow"))
- ast_parse_allow_disallow(&prefs, &global_capability, var->value, 0);
- else if (!strcasecmp(var->name, "allow"))
- ast_parse_allow_disallow(&prefs, &global_capability, var->value, 1);
- else if (!strcasecmp(var->name, "context"))
- ast_copy_string(context, var->value, sizeof(context));
- else if (!strcasecmp(var->name, "bindaddr")) {
- if (!(hp = ast_gethostbyname(var->value, &ahp))) {
- ast_log(LOG_WARNING, "Invalid address: %s\n", var->value);
- } else {
- memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr));
- }
- }
-/* Idea to allow for custom candidates */
-/*
- else if (!strcasecmp(var->name, "candidate")) {
- candidate = gtalk_create_candidate(var->value);
- if (candidate) {
- candidate->next = global_candidates;
- global_candidates = candidate;
- }
- }
-*/
- }
- while (cat) {
- if (strcasecmp(cat, "general")) {
- var = ast_variable_browse(cfg, cat);
- member = (struct gtalk *) malloc(sizeof(struct gtalk));
- memset(member, 0, sizeof(struct gtalk));
- ASTOBJ_INIT(member);
- ASTOBJ_WRLOCK(member);
- if (!strcasecmp(cat, "guest")) {
- ast_copy_string(member->name, "guest", sizeof(member->name));
- ast_copy_string(member->user, "guest", sizeof(member->user));
- ast_copy_string(member->context, context, sizeof(member->context));
- member->allowguest = allowguest;
- member->prefs = prefs;
- while (var) {
- if (!strcasecmp(var->name, "disallow"))
- ast_parse_allow_disallow(&member->prefs, &member->capability,
- var->value, 0);
- else if (!strcasecmp(var->name, "allow"))
- ast_parse_allow_disallow(&member->prefs, &member->capability,
- var->value, 1);
- else if (!strcasecmp(var->name, "context"))
- ast_copy_string(member->context, var->value,
- sizeof(member->context));
-/* Idea to allow for custom candidates */
-/*
- else if (!strcasecmp(var->name, "candidate")) {
- candidate = gtalk_create_candidate(var->value);
- if (candidate) {
- candidate->next = member->ourcandidates;
- member->ourcandidates = candidate;
- }
- }
-*/
- var = var->next;
- }
- ASTOBJ_UNLOCK(member);
- clients = ast_aji_get_clients();
- if (clients) {
- ASTOBJ_CONTAINER_TRAVERSE(clients, 1, {
- ASTOBJ_WRLOCK(iterator);
- ASTOBJ_WRLOCK(member);
- member->connection = NULL;
- iks_filter_add_rule(iterator->f, gtalk_parser, member, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS, "http://www.google.com/session", IKS_RULE_DONE);
- iks_filter_add_rule(iterator->f, gtalk_parser, member, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS, "http://jabber.org/protocol/gtalk", IKS_RULE_DONE);
- ASTOBJ_UNLOCK(member);
- ASTOBJ_UNLOCK(iterator);
- });
- ASTOBJ_CONTAINER_LINK(&gtalk_list, member);
- ASTOBJ_UNREF(member, gtalk_member_destroy);
- } else {
- ASTOBJ_UNLOCK(member);
- ASTOBJ_UNREF(member, gtalk_member_destroy);
- }
- } else {
- ASTOBJ_UNLOCK(member);
- if (gtalk_create_member(cat, var, allowguest, prefs, context, member))
- ASTOBJ_CONTAINER_LINK(&gtalk_list, member);
- ASTOBJ_UNREF(member, gtalk_member_destroy);
- }
- }
- cat = ast_category_browse(cfg, cat);
- }
- gtalk_free_candidates(global_candidates);
- return 1;
-}
-
-/*! \brief Load module into PBX, register channel */
-static int load_module(void)
-{
- char *jabber_loaded = ast_module_helper("", "res_jabber.so", 0, 0, 0, 0);
- free(jabber_loaded);
- if (!jabber_loaded) {
- /* If embedded, check for a different module name */
- jabber_loaded = ast_module_helper("", "res_jabber", 0, 0, 0, 0);
- free(jabber_loaded);
- if (!jabber_loaded) {
- ast_log(LOG_ERROR, "chan_gtalk.so depends upon res_jabber.so\n");
- return AST_MODULE_LOAD_DECLINE;
- }
- }
-
-#ifdef HAVE_GNUTLS
- gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
-#endif /* HAVE_GNUTLS */
-
- ASTOBJ_CONTAINER_INIT(&gtalk_list);
- if (!gtalk_load_config()) {
- ast_log(LOG_ERROR, "Unable to read config file %s. Not loading module.\n", GOOGLE_CONFIG);
- return 0;
- }
-
- sched = sched_context_create();
- if (!sched)
- ast_log(LOG_WARNING, "Unable to create schedule context\n");
-
- io = io_context_create();
- if (!io)
- ast_log(LOG_WARNING, "Unable to create I/O context\n");
-
- if (ast_find_ourip(&__ourip, bindaddr)) {
- ast_log(LOG_WARNING, "Unable to get own IP address, Gtalk disabled\n");
- return 0;
- }
-
- ast_rtp_proto_register(&gtalk_rtp);
- ast_cli_register_multiple(gtalk_cli, sizeof(gtalk_cli) / sizeof(gtalk_cli[0]));
-
- /* Make sure we can register our channel type */
- if (ast_channel_register(&gtalk_tech)) {
- ast_log(LOG_ERROR, "Unable to register channel class %s\n", gtalk_tech.type);
- return -1;
- }
- return 0;
-}
-
-/*! \brief Reload module */
-static int reload(void)
-{
- return 0;
-}
-
-/*! \brief Unload the gtalk channel from Asterisk */
-static int unload_module(void)
-{
- struct gtalk_pvt *privates = NULL;
- ast_cli_unregister_multiple(gtalk_cli, sizeof(gtalk_cli) / sizeof(gtalk_cli[0]));
- /* First, take us out of the channel loop */
- ast_channel_unregister(&gtalk_tech);
- ast_rtp_proto_unregister(&gtalk_rtp);
-
- if (!ast_mutex_lock(&gtalklock)) {
- /* Hangup all interfaces if they have an owner */
- ASTOBJ_CONTAINER_TRAVERSE(&gtalk_list, 1, {
- ASTOBJ_WRLOCK(iterator);
- privates = iterator->p;
- while(privates) {
- if (privates->owner)
- ast_softhangup(privates->owner, AST_SOFTHANGUP_APPUNLOAD);
- privates = privates->next;
- }
- iterator->p = NULL;
- ASTOBJ_UNLOCK(iterator);
- });
- ast_mutex_unlock(&gtalklock);
- } else {
- ast_log(LOG_WARNING, "Unable to lock the monitor\n");
- return -1;
- }
- ASTOBJ_CONTAINER_DESTROYALL(&gtalk_list, gtalk_member_destroy);
- ASTOBJ_CONTAINER_DESTROY(&gtalk_list);
- return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Gtalk Channel Driver",
- .load = load_module,
- .unload = unload_module,
- .reload = reload,
- );
diff --git a/1.4.23-rc4/channels/chan_h323.c b/1.4.23-rc4/channels/chan_h323.c
deleted file mode 100644
index 1199ddda9..000000000
--- a/1.4.23-rc4/channels/chan_h323.c
+++ /dev/null
@@ -1,3274 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 1999 - 2005
- *
- * OpenH323 Channel Driver for ASTERISK PBX.
- * By Jeremy McNamara
- * For The NuFone Network
- *
- * chan_h323 has been derived from code created by
- * Michael Manousos and Mark Spencer
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief This file is part of the chan_h323 driver for Asterisk
- *
- * \author Jeremy McNamara
- *
- * \par See also
- * \arg Config_h323
- *
- * \ingroup channel_drivers
- */
-
-/*** MODULEINFO
- <depend>openh323</depend>
- <defaultenabled>yes</defaultenabled>
- ***/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
-#ifdef __cplusplus
-}
-#endif
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/signal.h>
-#include <sys/param.h>
-#if defined(BSD) || defined(SOLARIS)
-#ifndef IPTOS_MINCOST
-#define IPTOS_MINCOST 0x02
-#endif
-#endif
-#include <arpa/inet.h>
-#include <net/if.h>
-#include <netinet/in.h>
-#include <netinet/in_systm.h>
-#include <netinet/ip.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <netdb.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <fcntl.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "asterisk/lock.h"
-#include "asterisk/logger.h"
-#include "asterisk/channel.h"
-#include "asterisk/config.h"
-#include "asterisk/module.h"
-#include "asterisk/musiconhold.h"
-#include "asterisk/pbx.h"
-#include "asterisk/options.h"
-#include "asterisk/utils.h"
-#include "asterisk/lock.h"
-#include "asterisk/sched.h"
-#include "asterisk/io.h"
-#include "asterisk/rtp.h"
-#include "asterisk/acl.h"
-#include "asterisk/callerid.h"
-#include "asterisk/cli.h"
-#include "asterisk/dsp.h"
-#include "asterisk/causes.h"
-#include "asterisk/stringfields.h"
-#include "asterisk/abstract_jb.h"
-#include "asterisk/astobj.h"
-
-#ifdef __cplusplus
-}
-#endif
-
-#include "h323/chan_h323.h"
-
-receive_digit_cb on_receive_digit;
-on_rtp_cb on_external_rtp_create;
-start_rtp_cb on_start_rtp_channel;
-setup_incoming_cb on_incoming_call;
-setup_outbound_cb on_outgoing_call;
-chan_ringing_cb on_chan_ringing;
-con_established_cb on_connection_established;
-clear_con_cb on_connection_cleared;
-answer_call_cb on_answer_call;
-progress_cb on_progress;
-rfc2833_cb on_set_rfc2833_payload;
-hangup_cb on_hangup;
-setcapabilities_cb on_setcapabilities;
-setpeercapabilities_cb on_setpeercapabilities;
-
-/* global debug flag */
-int h323debug;
-
-/*! Global jitterbuffer configuration - by default, jb is disabled */
-static struct ast_jb_conf default_jbconf =
-{
- .flags = 0,
- .max_size = -1,
- .resync_threshold = -1,
- .impl = ""
-};
-static struct ast_jb_conf global_jbconf;
-
-/** Variables required by Asterisk */
-static const char tdesc[] = "The NuFone Network's Open H.323 Channel Driver";
-static const char config[] = "h323.conf";
-static char default_context[AST_MAX_CONTEXT] = "default";
-static struct sockaddr_in bindaddr;
-
-#define GLOBAL_CAPABILITY (AST_FORMAT_G723_1 | AST_FORMAT_GSM | AST_FORMAT_ULAW | AST_FORMAT_ALAW | AST_FORMAT_G729A | AST_FORMAT_H261)
-
-/** H.323 configuration values */
-static int h323_signalling_port = 1720;
-static char gatekeeper[100];
-static int gatekeeper_disable = 1;
-static int gatekeeper_discover = 0;
-static int gkroute = 0;
-/* Find user by alias (h.323 id) is default, alternative is the incomming call's source IP address*/
-static int userbyalias = 1;
-static int acceptAnonymous = 1;
-static int tos = 0;
-static char secret[50];
-static unsigned int unique = 0;
-
-static call_options_t global_options;
-
-/** Private structure of a OpenH323 channel */
-struct oh323_pvt {
- ast_mutex_t lock; /* Channel private lock */
- call_options_t options; /* Options to be used during call setup */
- int alreadygone; /* Whether or not we've already been destroyed by our peer */
- int needdestroy; /* if we need to be destroyed */
- call_details_t cd; /* Call details */
- struct ast_channel *owner; /* Who owns us */
- struct sockaddr_in sa; /* Our peer */
- struct sockaddr_in redirip; /* Where our RTP should be going if not to us */
- int nonCodecCapability; /* non-audio capability */
- int outgoing; /* Outgoing or incoming call? */
- char exten[AST_MAX_EXTENSION]; /* Requested extension */
- char context[AST_MAX_CONTEXT]; /* Context where to start */
- char accountcode[256]; /* Account code */
- char rdnis[80]; /* Referring DNIS, if available */
- int amaflags; /* AMA Flags */
- struct ast_rtp *rtp; /* RTP Session */
- struct ast_dsp *vad; /* Used for in-band DTMF detection */
- int nativeformats; /* Codec formats supported by a channel */
- int needhangup; /* Send hangup when Asterisk is ready */
- int hangupcause; /* Hangup cause from OpenH323 layer */
- int newstate; /* Pending state change */
- int newcontrol; /* Pending control to send */
- int newdigit; /* Pending DTMF digit to send */
- int newduration; /* Pending DTMF digit duration to send */
- int pref_codec; /* Preferred codec */
- int peercapability; /* Capabilities learned from peer */
- int jointcapability; /* Common capabilities for local and remote side */
- struct ast_codec_pref peer_prefs; /* Preferenced list of codecs which remote side supports */
- int dtmf_pt; /* Payload code used for RFC2833 messages */
- int curDTMF; /* DTMF tone being generated to Asterisk side */
- int DTMFsched; /* Scheduler descriptor for DTMF */
- int update_rtp_info; /* Configuration of fd's array is pending */
- int recvonly; /* Peer isn't wish to receive our voice stream */
- int txDtmfDigit; /* DTMF digit being to send to H.323 side */
- int noInbandDtmf; /* Inband DTMF processing by DSP isn't available */
- int connection_established; /* Call got CONNECT message */
- int got_progress; /* Call got PROGRESS message, pass inband audio */
- struct oh323_pvt *next; /* Next channel in list */
-} *iflist = NULL;
-
-static struct ast_user_list {
- ASTOBJ_CONTAINER_COMPONENTS(struct oh323_user);
-} userl;
-
-static struct ast_peer_list {
- ASTOBJ_CONTAINER_COMPONENTS(struct oh323_peer);
-} peerl;
-
-static struct ast_alias_list {
- ASTOBJ_CONTAINER_COMPONENTS(struct oh323_alias);
-} aliasl;
-
-/** Asterisk RTP stuff */
-static struct sched_context *sched;
-static struct io_context *io;
-
-/** Protect the interface list (oh323_pvt) */
-AST_MUTEX_DEFINE_STATIC(iflock);
-
-/* Protect the monitoring thread, so only one process can kill or start it, and not
- when it's doing something critical. */
-AST_MUTEX_DEFINE_STATIC(monlock);
-
-/* Protect the H.323 capabilities list, to avoid more than one channel to set the capabilities simultaneaously in the h323 stack. */
-AST_MUTEX_DEFINE_STATIC(caplock);
-
-/* Protect the reload process */
-AST_MUTEX_DEFINE_STATIC(h323_reload_lock);
-static int h323_reloading = 0;
-
-/* This is the thread for the monitor which checks for input on the channels
- which are not currently in use. */
-static pthread_t monitor_thread = AST_PTHREADT_NULL;
-static int restart_monitor(void);
-static int h323_do_reload(void);
-
-static struct ast_channel *oh323_request(const char *type, int format, void *data, int *cause);
-static int oh323_digit_begin(struct ast_channel *c, char digit);
-static int oh323_digit_end(struct ast_channel *c, char digit, unsigned int duration);
-static int oh323_call(struct ast_channel *c, char *dest, int timeout);
-static int oh323_hangup(struct ast_channel *c);
-static int oh323_answer(struct ast_channel *c);
-static struct ast_frame *oh323_read(struct ast_channel *c);
-static int oh323_write(struct ast_channel *c, struct ast_frame *frame);
-static int oh323_indicate(struct ast_channel *c, int condition, const void *data, size_t datalen);
-static int oh323_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
-
-static const struct ast_channel_tech oh323_tech = {
- .type = "H323",
- .description = tdesc,
- .capabilities = ((AST_FORMAT_MAX_AUDIO << 1) - 1),
- .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER,
- .requester = oh323_request,
- .send_digit_begin = oh323_digit_begin,
- .send_digit_end = oh323_digit_end,
- .call = oh323_call,
- .hangup = oh323_hangup,
- .answer = oh323_answer,
- .read = oh323_read,
- .write = oh323_write,
- .indicate = oh323_indicate,
- .fixup = oh323_fixup,
- /* disable, for now */
-#if 0
- .bridge = ast_rtp_bridge,
-#endif
-};
-
-static const char* redirectingreason2str(int redirectingreason)
-{
- switch (redirectingreason) {
- case 0:
- return "UNKNOWN";
- case 1:
- return "BUSY";
- case 2:
- return "NO_REPLY";
- case 0xF:
- return "UNCONDITIONAL";
- default:
- return "NOREDIRECT";
- }
-}
-
-static void oh323_destroy_alias(struct oh323_alias *alias)
-{
- if (h323debug)
- ast_log(LOG_DEBUG, "Destroying alias '%s'\n", alias->name);
- free(alias);
-}
-
-static void oh323_destroy_user(struct oh323_user *user)
-{
- if (h323debug)
- ast_log(LOG_DEBUG, "Destroying user '%s'\n", user->name);
- ast_free_ha(user->ha);
- free(user);
-}
-
-static void oh323_destroy_peer(struct oh323_peer *peer)
-{
- if (h323debug)
- ast_log(LOG_DEBUG, "Destroying peer '%s'\n", peer->name);
- ast_free_ha(peer->ha);
- free(peer);
-}
-
-static int oh323_simulate_dtmf_end(const void *data)
-{
- struct oh323_pvt *pvt = (struct oh323_pvt *)data;
-
- if (pvt) {
- ast_mutex_lock(&pvt->lock);
- /* Don't hold pvt lock while trying to lock the channel */
- while(pvt->owner && ast_channel_trylock(pvt->owner)) {
- ast_mutex_unlock(&pvt->lock);
- usleep(1);
- ast_mutex_lock(&pvt->lock);
- }
-
- if (pvt->owner) {
- struct ast_frame f = {
- .frametype = AST_FRAME_DTMF_END,
- .subclass = pvt->curDTMF,
- .samples = 0,
- .src = "SIMULATE_DTMF_END",
- };
- ast_queue_frame(pvt->owner, &f);
- ast_channel_unlock(pvt->owner);
- }
-
- pvt->DTMFsched = -1;
- ast_mutex_unlock(&pvt->lock);
- }
-
- return 0;
-}
-
-/* Channel and private structures should be already locked */
-static void __oh323_update_info(struct ast_channel *c, struct oh323_pvt *pvt)
-{
- if (c->nativeformats != pvt->nativeformats) {
- if (h323debug)
- ast_log(LOG_DEBUG, "Preparing %s for new native format\n", c->name);
- c->nativeformats = pvt->nativeformats;
- ast_set_read_format(c, c->readformat);
- ast_set_write_format(c, c->writeformat);
- }
- if (pvt->needhangup) {
- if (h323debug)
- ast_log(LOG_DEBUG, "Process pending hangup for %s\n", c->name);
- c->_softhangup |= AST_SOFTHANGUP_DEV;
- c->hangupcause = pvt->hangupcause;
- ast_queue_hangup(c);
- pvt->needhangup = 0;
- pvt->newstate = pvt->newcontrol = pvt->newdigit = pvt->DTMFsched = -1;
- }
- if (pvt->newstate >= 0) {
- ast_setstate(c, pvt->newstate);
- pvt->newstate = -1;
- }
- if (pvt->newcontrol >= 0) {
- ast_queue_control(c, pvt->newcontrol);
- pvt->newcontrol = -1;
- }
- if (pvt->newdigit >= 0) {
- struct ast_frame f = {
- .frametype = AST_FRAME_DTMF_END,
- .subclass = pvt->newdigit,
- .samples = pvt->newduration * 8,
- .len = pvt->newduration,
- .src = "UPDATE_INFO",
- };
- if (pvt->newdigit == ' ') { /* signalUpdate message */
- f.subclass = pvt->curDTMF;
- if (pvt->DTMFsched >= 0) {
- AST_SCHED_DEL(sched, pvt->DTMFsched);
- }
- } else { /* Regular input or signal message */
- if (pvt->newduration) { /* This is a signal, signalUpdate follows */
- f.frametype = AST_FRAME_DTMF_BEGIN;
- AST_SCHED_DEL(sched, pvt->DTMFsched);
- pvt->DTMFsched = ast_sched_add(sched, pvt->newduration, oh323_simulate_dtmf_end, pvt);
- if (h323debug)
- ast_log(LOG_DTMF, "Scheduled DTMF END simulation for %d ms, id=%d\n", pvt->newduration, pvt->DTMFsched);
- }
- pvt->curDTMF = pvt->newdigit;
- }
- ast_queue_frame(c, &f);
- pvt->newdigit = -1;
- }
- if (pvt->update_rtp_info > 0) {
- if (pvt->rtp) {
- ast_jb_configure(c, &global_jbconf);
- c->fds[0] = ast_rtp_fd(pvt->rtp);
- c->fds[1] = ast_rtcp_fd(pvt->rtp);
- ast_queue_frame(pvt->owner, &ast_null_frame); /* Tell Asterisk to apply changes */
- }
- pvt->update_rtp_info = -1;
- }
-}
-
-/* Only channel structure should be locked */
-static void oh323_update_info(struct ast_channel *c)
-{
- struct oh323_pvt *pvt = c->tech_pvt;
-
- if (pvt) {
- ast_mutex_lock(&pvt->lock);
- __oh323_update_info(c, pvt);
- ast_mutex_unlock(&pvt->lock);
- }
-}
-
-static void cleanup_call_details(call_details_t *cd)
-{
- if (cd->call_token) {
- free(cd->call_token);
- cd->call_token = NULL;
- }
- if (cd->call_source_aliases) {
- free(cd->call_source_aliases);
- cd->call_source_aliases = NULL;
- }
- if (cd->call_dest_alias) {
- free(cd->call_dest_alias);
- cd->call_dest_alias = NULL;
- }
- if (cd->call_source_name) {
- free(cd->call_source_name);
- cd->call_source_name = NULL;
- }
- if (cd->call_source_e164) {
- free(cd->call_source_e164);
- cd->call_source_e164 = NULL;
- }
- if (cd->call_dest_e164) {
- free(cd->call_dest_e164);
- cd->call_dest_e164 = NULL;
- }
- if (cd->sourceIp) {
- free(cd->sourceIp);
- cd->sourceIp = NULL;
- }
- if (cd->redirect_number) {
- free(cd->redirect_number);
- cd->redirect_number = NULL;
- }
-}
-
-static void __oh323_destroy(struct oh323_pvt *pvt)
-{
- struct oh323_pvt *cur, *prev = NULL;
-
- AST_SCHED_DEL(sched, pvt->DTMFsched);
-
- if (pvt->rtp) {
- ast_rtp_destroy(pvt->rtp);
- }
-
- /* Free dsp used for in-band DTMF detection */
- if (pvt->vad) {
- ast_dsp_free(pvt->vad);
- }
- cleanup_call_details(&pvt->cd);
-
- /* Unlink us from the owner if we have one */
- if (pvt->owner) {
- ast_channel_lock(pvt->owner);
- if (h323debug)
- ast_log(LOG_DEBUG, "Detaching from %s\n", pvt->owner->name);
- pvt->owner->tech_pvt = NULL;
- ast_channel_unlock(pvt->owner);
- }
- cur = iflist;
- while(cur) {
- if (cur == pvt) {
- if (prev)
- prev->next = cur->next;
- else
- iflist = cur->next;
- break;
- }
- prev = cur;
- cur = cur->next;
- }
- if (!cur) {
- ast_log(LOG_WARNING, "%p is not in list?!?! \n", cur);
- } else {
- ast_mutex_unlock(&pvt->lock);
- ast_mutex_destroy(&pvt->lock);
- free(pvt);
- }
-}
-
-static void oh323_destroy(struct oh323_pvt *pvt)
-{
- if (h323debug) {
- ast_log(LOG_DEBUG, "Destroying channel %s\n", (pvt->owner ? pvt->owner->name : "<unknown>"));
- }
- ast_mutex_lock(&iflock);
- ast_mutex_lock(&pvt->lock);
- __oh323_destroy(pvt);
- ast_mutex_unlock(&iflock);
-}
-
-static int oh323_digit_begin(struct ast_channel *c, char digit)
-{
- struct oh323_pvt *pvt = (struct oh323_pvt *) c->tech_pvt;
- char *token;
-
- if (!pvt) {
- ast_log(LOG_ERROR, "No private structure?! This is bad\n");
- return -1;
- }
- ast_mutex_lock(&pvt->lock);
- if (pvt->rtp && (pvt->options.dtmfmode & H323_DTMF_RFC2833) && (pvt->dtmf_pt > 0)) {
- /* out-of-band DTMF */
- if (h323debug) {
- ast_log(LOG_DTMF, "Begin sending out-of-band digit %c on %s\n", digit, c->name);
- }
- ast_rtp_senddigit_begin(pvt->rtp, digit);
- ast_mutex_unlock(&pvt->lock);
- } else if (pvt->txDtmfDigit != digit) {
- /* in-band DTMF */
- if (h323debug) {
- ast_log(LOG_DTMF, "Begin sending inband digit %c on %s\n", digit, c->name);
- }
- pvt->txDtmfDigit = digit;
- token = pvt->cd.call_token ? strdup(pvt->cd.call_token) : NULL;
- ast_mutex_unlock(&pvt->lock);
- h323_send_tone(token, digit);
- if (token) {
- free(token);
- }
- } else
- ast_mutex_unlock(&pvt->lock);
- oh323_update_info(c);
- return 0;
-}
-
-/**
- * Send (play) the specified digit to the channel.
- *
- */
-static int oh323_digit_end(struct ast_channel *c, char digit, unsigned int duration)
-{
- struct oh323_pvt *pvt = (struct oh323_pvt *) c->tech_pvt;
- char *token;
-
- if (!pvt) {
- ast_log(LOG_ERROR, "No private structure?! This is bad\n");
- return -1;
- }
- ast_mutex_lock(&pvt->lock);
- if (pvt->rtp && (pvt->options.dtmfmode & H323_DTMF_RFC2833) && (pvt->dtmf_pt > 0)) {
- /* out-of-band DTMF */
- if (h323debug) {
- ast_log(LOG_DTMF, "End sending out-of-band digit %c on %s, duration %d\n", digit, c->name, duration);
- }
- ast_rtp_senddigit_end(pvt->rtp, digit);
- ast_mutex_unlock(&pvt->lock);
- } else {
- /* in-band DTMF */
- if (h323debug) {
- ast_log(LOG_DTMF, "End sending inband digit %c on %s, duration %d\n", digit, c->name, duration);
- }
- pvt->txDtmfDigit = ' ';
- token = pvt->cd.call_token ? strdup(pvt->cd.call_token) : NULL;
- ast_mutex_unlock(&pvt->lock);
- h323_send_tone(token, ' ');
- if (token) {
- free(token);
- }
- }
- oh323_update_info(c);
- return 0;
-}
-
-/**
- * Make a call over the specified channel to the specified
- * destination.
- * Returns -1 on error, 0 on success.
- */
-static int oh323_call(struct ast_channel *c, char *dest, int timeout)
-{
- int res = 0;
- struct oh323_pvt *pvt = (struct oh323_pvt *)c->tech_pvt;
- const char *addr;
- char called_addr[1024];
-
- if (h323debug) {
- ast_log(LOG_DEBUG, "Calling to %s on %s\n", dest, c->name);
- }
- if ((c->_state != AST_STATE_DOWN) && (c->_state != AST_STATE_RESERVED)) {
- ast_log(LOG_WARNING, "Line is already in use (%s)\n", c->name);
- return -1;
- }
- ast_mutex_lock(&pvt->lock);
- if (!gatekeeper_disable) {
- if (ast_strlen_zero(pvt->exten)) {
- ast_copy_string(called_addr, dest, sizeof(called_addr));
- } else {
- snprintf(called_addr, sizeof(called_addr), "%s@%s", pvt->exten, dest);
- }
- } else {
- res = htons(pvt->sa.sin_port);
- addr = ast_inet_ntoa(pvt->sa.sin_addr);
- if (ast_strlen_zero(pvt->exten)) {
- snprintf(called_addr, sizeof(called_addr), "%s:%d", addr, res);
- } else {
- snprintf(called_addr, sizeof(called_addr), "%s@%s:%d", pvt->exten, addr, res);
- }
- }
- /* make sure null terminated */
- called_addr[sizeof(called_addr) - 1] = '\0';
-
- if (c->cid.cid_num)
- ast_copy_string(pvt->options.cid_num, c->cid.cid_num, sizeof(pvt->options.cid_num));
-
- if (c->cid.cid_name)
- ast_copy_string(pvt->options.cid_name, c->cid.cid_name, sizeof(pvt->options.cid_name));
-
- if (c->cid.cid_rdnis) {
- ast_copy_string(pvt->options.cid_rdnis, c->cid.cid_rdnis, sizeof(pvt->options.cid_rdnis));
- }
-
- pvt->options.presentation = c->cid.cid_pres;
- pvt->options.type_of_number = c->cid.cid_ton;
-
- if ((addr = pbx_builtin_getvar_helper(c, "PRIREDIRECTREASON"))) {
- if (!strcasecmp(addr, "UNKNOWN"))
- pvt->options.redirect_reason = 0;
- else if (!strcasecmp(addr, "BUSY"))
- pvt->options.redirect_reason = 1;
- else if (!strcasecmp(addr, "NO_REPLY"))
- pvt->options.redirect_reason = 2;
- else if (!strcasecmp(addr, "UNCONDITIONAL"))
- pvt->options.redirect_reason = 15;
- else
- pvt->options.redirect_reason = -1;
- } else
- pvt->options.redirect_reason = -1;
-
- pvt->options.transfer_capability = c->transfercapability;
-
- /* indicate that this is an outgoing call */
- pvt->outgoing = 1;
-
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Requested transfer capability: 0x%.2x - %s\n", c->transfercapability, ast_transfercapability2str(c->transfercapability));
- if (h323debug)
- ast_log(LOG_DEBUG, "Placing outgoing call to %s, %d\n", called_addr, pvt->options.dtmfcodec);
- ast_mutex_unlock(&pvt->lock);
- res = h323_make_call(called_addr, &(pvt->cd), &pvt->options);
- if (res) {
- ast_log(LOG_NOTICE, "h323_make_call failed(%s)\n", c->name);
- return -1;
- }
- oh323_update_info(c);
- return 0;
-}
-
-static int oh323_answer(struct ast_channel *c)
-{
- int res;
- struct oh323_pvt *pvt = (struct oh323_pvt *) c->tech_pvt;
- char *token;
-
- if (h323debug)
- ast_log(LOG_DEBUG, "Answering on %s\n", c->name);
-
- ast_mutex_lock(&pvt->lock);
- token = pvt->cd.call_token ? strdup(pvt->cd.call_token) : NULL;
- ast_mutex_unlock(&pvt->lock);
- res = h323_answering_call(token, 0);
- if (token)
- free(token);
-
- oh323_update_info(c);
- if (c->_state != AST_STATE_UP) {
- ast_setstate(c, AST_STATE_UP);
- }
- return res;
-}
-
-static int oh323_hangup(struct ast_channel *c)
-{
- struct oh323_pvt *pvt = (struct oh323_pvt *) c->tech_pvt;
- int q931cause = AST_CAUSE_NORMAL_CLEARING;
- char *call_token;
-
-
- if (h323debug)
- ast_log(LOG_DEBUG, "Hanging up and scheduling destroy of call %s\n", c->name);
-
- if (!c->tech_pvt) {
- ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
- return 0;
- }
- ast_mutex_lock(&pvt->lock);
- /* Determine how to disconnect */
- if (pvt->owner != c) {
- ast_log(LOG_WARNING, "Huh? We aren't the owner?\n");
- ast_mutex_unlock(&pvt->lock);
- return 0;
- }
-
- pvt->owner = NULL;
- c->tech_pvt = NULL;
-
- if (c->hangupcause) {
- q931cause = c->hangupcause;
- } else {
- const char *cause = pbx_builtin_getvar_helper(c, "DIALSTATUS");
- if (cause) {
- if (!strcmp(cause, "CONGESTION")) {
- q931cause = AST_CAUSE_NORMAL_CIRCUIT_CONGESTION;
- } else if (!strcmp(cause, "BUSY")) {
- q931cause = AST_CAUSE_USER_BUSY;
- } else if (!strcmp(cause, "CHANISUNVAIL")) {
- q931cause = AST_CAUSE_REQUESTED_CHAN_UNAVAIL;
- } else if (!strcmp(cause, "NOANSWER")) {
- q931cause = AST_CAUSE_NO_ANSWER;
- } else if (!strcmp(cause, "CANCEL")) {
- q931cause = AST_CAUSE_CALL_REJECTED;
- }
- }
- }
-
- /* Start the process if it's not already started */
- if (!pvt->alreadygone && !pvt->hangupcause) {
- call_token = pvt->cd.call_token ? strdup(pvt->cd.call_token) : NULL;
- if (call_token) {
- /* Release lock to eliminate deadlock */
- ast_mutex_unlock(&pvt->lock);
- if (h323_clear_call(call_token, q931cause)) {
- ast_log(LOG_WARNING, "ClearCall failed.\n");
- }
- free(call_token);
- ast_mutex_lock(&pvt->lock);
- }
- }
- pvt->needdestroy = 1;
- ast_mutex_unlock(&pvt->lock);
-
- /* Update usage counter */
- ast_module_unref(ast_module_info->self);
-
- return 0;
-}
-
-static struct ast_frame *oh323_rtp_read(struct oh323_pvt *pvt)
-{
- /* Retrieve audio/etc from channel. Assumes pvt->lock is already held. */
- struct ast_frame *f;
-
- /* Only apply it for the first packet, we just need the correct ip/port */
- if (pvt->options.nat) {
- ast_rtp_setnat(pvt->rtp, pvt->options.nat);
- pvt->options.nat = 0;
- }
-
- f = ast_rtp_read(pvt->rtp);
- /* Don't send RFC2833 if we're not supposed to */
- if (f && (f->frametype == AST_FRAME_DTMF) && !(pvt->options.dtmfmode & H323_DTMF_RFC2833)) {
- return &ast_null_frame;
- }
- if (pvt->owner) {
- /* We already hold the channel lock */
- if (f->frametype == AST_FRAME_VOICE) {
- if (f->subclass != pvt->owner->nativeformats) {
- /* Try to avoid deadlock */
- if (ast_channel_trylock(pvt->owner)) {
- ast_log(LOG_NOTICE, "Format changed but channel is locked. Ignoring frame...\n");
- return &ast_null_frame;
- }
- if (h323debug)
- ast_log(LOG_DEBUG, "Oooh, format changed to %d\n", f->subclass);
- pvt->owner->nativeformats = f->subclass;
- pvt->nativeformats = f->subclass;
- ast_set_read_format(pvt->owner, pvt->owner->readformat);
- ast_set_write_format(pvt->owner, pvt->owner->writeformat);
- ast_channel_unlock(pvt->owner);
- }
- /* Do in-band DTMF detection */
- if ((pvt->options.dtmfmode & H323_DTMF_INBAND) && pvt->vad) {
- if ((pvt->nativeformats & (AST_FORMAT_SLINEAR | AST_FORMAT_ALAW | AST_FORMAT_ULAW))) {
- if (!ast_channel_trylock(pvt->owner)) {
- f = ast_dsp_process(pvt->owner, pvt->vad, f);
- ast_channel_unlock(pvt->owner);
- }
- else
- ast_log(LOG_NOTICE, "Unable to process inband DTMF while channel is locked\n");
- } else if (pvt->nativeformats && !pvt->noInbandDtmf) {
- ast_log(LOG_NOTICE, "Inband DTMF is not supported on codec %s. Use RFC2833\n", ast_getformatname(f->subclass));
- pvt->noInbandDtmf = 1;
- }
- if (f &&(f->frametype == AST_FRAME_DTMF)) {
- if (h323debug)
- ast_log(LOG_DTMF, "Received in-band digit %c.\n", f->subclass);
- }
- }
- }
- }
- return f;
-}
-
-static struct ast_frame *oh323_read(struct ast_channel *c)
-{
- struct ast_frame *fr;
- struct oh323_pvt *pvt = (struct oh323_pvt *)c->tech_pvt;
- ast_mutex_lock(&pvt->lock);
- __oh323_update_info(c, pvt);
- switch(c->fdno) {
- case 0:
- fr = oh323_rtp_read(pvt);
- break;
- case 1:
- if (pvt->rtp)
- fr = ast_rtcp_read(pvt->rtp);
- else
- fr = &ast_null_frame;
- break;
- default:
- ast_log(LOG_ERROR, "Unable to handle fd %d on channel %s\n", c->fdno, c->name);
- fr = &ast_null_frame;
- break;
- }
- ast_mutex_unlock(&pvt->lock);
- return fr;
-}
-
-static int oh323_write(struct ast_channel *c, struct ast_frame *frame)
-{
- struct oh323_pvt *pvt = (struct oh323_pvt *) c->tech_pvt;
- int res = 0;
- if (frame->frametype != AST_FRAME_VOICE) {
- if (frame->frametype == AST_FRAME_IMAGE) {
- return 0;
- } else {
- ast_log(LOG_WARNING, "Can't send %d type frames with H323 write\n", frame->frametype);
- return 0;
- }
- } else {
- if (!(frame->subclass & c->nativeformats)) {
- ast_log(LOG_WARNING, "Asked to transmit frame type %d, while native formats is %d (read/write = %d/%d)\n",
- frame->subclass, c->nativeformats, c->readformat, c->writeformat);
- return 0;
- }
- }
- if (pvt) {
- ast_mutex_lock(&pvt->lock);
- if (pvt->rtp && !pvt->recvonly)
- res = ast_rtp_write(pvt->rtp, frame);
- __oh323_update_info(c, pvt);
- ast_mutex_unlock(&pvt->lock);
- }
- return res;
-}
-
-static int oh323_indicate(struct ast_channel *c, int condition, const void *data, size_t datalen)
-{
-
- struct oh323_pvt *pvt = (struct oh323_pvt *) c->tech_pvt;
- char *token = (char *)NULL;
- int res = -1;
- int got_progress;
-
- ast_mutex_lock(&pvt->lock);
- token = (pvt->cd.call_token ? strdup(pvt->cd.call_token) : NULL);
- got_progress = pvt->got_progress;
- if (condition == AST_CONTROL_PROGRESS)
- pvt->got_progress = 1;
- else if ((condition == AST_CONTROL_BUSY) || (condition == AST_CONTROL_CONGESTION))
- pvt->alreadygone = 1;
- ast_mutex_unlock(&pvt->lock);
-
- if (h323debug)
- ast_log(LOG_DEBUG, "OH323: Indicating %d on %s\n", condition, token);
-
- switch(condition) {
- case AST_CONTROL_RINGING:
- if (c->_state == AST_STATE_RING || c->_state == AST_STATE_RINGING) {
- h323_send_alerting(token);
- res = (got_progress ? 0 : -1); /* Do not simulate any audio tones if we got PROGRESS message */
- }
- break;
- case AST_CONTROL_PROGRESS:
- if (c->_state != AST_STATE_UP) {
- /* Do not send PROGRESS message more than once */
- if (!got_progress)
- h323_send_progress(token);
- res = 0;
- }
- break;
- case AST_CONTROL_BUSY:
- if (c->_state != AST_STATE_UP) {
- h323_answering_call(token, 1);
- ast_softhangup_nolock(c, AST_SOFTHANGUP_DEV);
- res = 0;
- }
- break;
- case AST_CONTROL_CONGESTION:
- if (c->_state != AST_STATE_UP) {
- h323_answering_call(token, 1);
- ast_softhangup_nolock(c, AST_SOFTHANGUP_DEV);
- res = 0;
- }
- break;
- case AST_CONTROL_HOLD:
- ast_moh_start(c, data, NULL);
- res = 0;
- break;
- case AST_CONTROL_UNHOLD:
- ast_moh_stop(c);
- res = 0;
- break;
- case AST_CONTROL_SRCUPDATE:
- ast_rtp_new_source(pvt->rtp);
- res = 0;
- break;
- case AST_CONTROL_PROCEEDING:
- case -1:
- break;
- default:
- ast_log(LOG_WARNING, "OH323: Don't know how to indicate condition %d on %s\n", condition, token);
- break;
- }
-
- if (h323debug)
- ast_log(LOG_DEBUG, "OH323: Indicated %d on %s, res=%d\n", condition, token, res);
- if (token)
- free(token);
- oh323_update_info(c);
-
- return res;
-}
-
-static int oh323_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
-{
- struct oh323_pvt *pvt = (struct oh323_pvt *) newchan->tech_pvt;
-
- ast_mutex_lock(&pvt->lock);
- if (pvt->owner != oldchan) {
- ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, pvt->owner);
- return -1;
- }
- pvt->owner = newchan;
- ast_mutex_unlock(&pvt->lock);
- return 0;
-}
-
-static int __oh323_rtp_create(struct oh323_pvt *pvt)
-{
- struct in_addr our_addr;
-
- if (pvt->rtp)
- return 0;
-
- if (ast_find_ourip(&our_addr, bindaddr)) {
- ast_mutex_unlock(&pvt->lock);
- ast_log(LOG_ERROR, "Unable to locate local IP address for RTP stream\n");
- return -1;
- }
- pvt->rtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, our_addr);
- if (!pvt->rtp) {
- ast_mutex_unlock(&pvt->lock);
- ast_log(LOG_WARNING, "Unable to create RTP session: %s\n", strerror(errno));
- return -1;
- }
- if (h323debug)
- ast_log(LOG_DEBUG, "Created RTP channel\n");
-
- ast_rtp_settos(pvt->rtp, tos);
-
- if (h323debug)
- ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", pvt->options.nat);
- ast_rtp_setnat(pvt->rtp, pvt->options.nat);
-
- if (pvt->dtmf_pt > 0)
- ast_rtp_set_rtpmap_type(pvt->rtp, pvt->dtmf_pt, "audio", "telephone-event", 0);
-
- if (pvt->peercapability)
- ast_rtp_codec_setpref(pvt->rtp, &pvt->peer_prefs);
-
- if (pvt->owner && !ast_channel_trylock(pvt->owner)) {
- ast_jb_configure(pvt->owner, &global_jbconf);
- pvt->owner->fds[0] = ast_rtp_fd(pvt->rtp);
- pvt->owner->fds[1] = ast_rtcp_fd(pvt->rtp);
- ast_queue_frame(pvt->owner, &ast_null_frame); /* Tell Asterisk to apply changes */
- ast_channel_unlock(pvt->owner);
- } else
- pvt->update_rtp_info = 1;
-
- return 0;
-}
-
-/* Private structure should be locked on a call */
-static struct ast_channel *__oh323_new(struct oh323_pvt *pvt, int state, const char *host)
-{
- struct ast_channel *ch;
- char *cid_num, *cid_name;
- int fmt;
-
- if (!ast_strlen_zero(pvt->options.cid_num))
- cid_num = pvt->options.cid_num;
- else
- cid_num = pvt->cd.call_source_e164;
-
- if (!ast_strlen_zero(pvt->options.cid_name))
- cid_name = pvt->options.cid_name;
- else
- cid_name = pvt->cd.call_source_name;
-
- /* Don't hold a oh323_pvt lock while we allocate a chanel */
- ast_mutex_unlock(&pvt->lock);
- ch = ast_channel_alloc(1, state, cid_num, cid_name, pvt->accountcode, pvt->exten, pvt->context, pvt->amaflags, "H323/%s", host);
- /* Update usage counter */
- ast_module_ref(ast_module_info->self);
- ast_mutex_lock(&pvt->lock);
- if (ch) {
- ch->tech = &oh323_tech;
- if (!(fmt = pvt->jointcapability) && !(fmt = pvt->options.capability))
- fmt = global_options.capability;
- ch->nativeformats = ast_codec_choose(&pvt->options.prefs, fmt, 1)/* | (pvt->jointcapability & AST_FORMAT_VIDEO_MASK)*/;
- pvt->nativeformats = ch->nativeformats;
- fmt = ast_best_codec(ch->nativeformats);
- ch->writeformat = fmt;
- ch->rawwriteformat = fmt;
- ch->readformat = fmt;
- ch->rawreadformat = fmt;
-#if 0
- ch->fds[0] = ast_rtp_fd(pvt->rtp);
- ch->fds[1] = ast_rtcp_fd(pvt->rtp);
-#endif
-#ifdef VIDEO_SUPPORT
- if (pvt->vrtp) {
- ch->fds[2] = ast_rtp_fd(pvt->vrtp);
- ch->fds[3] = ast_rtcp_fd(pvt->vrtp);
- }
-#endif
-#ifdef T38_SUPPORT
- if (pvt->udptl) {
- ch->fds[4] = ast_udptl_fd(pvt->udptl);
- }
-#endif
- if (state == AST_STATE_RING) {
- ch->rings = 1;
- }
- /* Allocate dsp for in-band DTMF support */
- if (pvt->options.dtmfmode & H323_DTMF_INBAND) {
- pvt->vad = ast_dsp_new();
- ast_dsp_set_features(pvt->vad, DSP_FEATURE_DTMF_DETECT);
- }
- /* Register channel functions. */
- ch->tech_pvt = pvt;
- /* Set the owner of this channel */
- pvt->owner = ch;
-
- ast_copy_string(ch->context, pvt->context, sizeof(ch->context));
- ast_copy_string(ch->exten, pvt->exten, sizeof(ch->exten));
- ch->priority = 1;
- if (!ast_strlen_zero(pvt->accountcode)) {
- ast_string_field_set(ch, accountcode, pvt->accountcode);
- }
- if (pvt->amaflags) {
- ch->amaflags = pvt->amaflags;
- }
-
- /* Don't use ast_set_callerid() here because it will
- * generate a needless NewCallerID event */
- ch->cid.cid_ani = ast_strdup(cid_num);
-
- if (pvt->cd.redirect_reason >= 0) {
- ch->cid.cid_rdnis = ast_strdup(pvt->cd.redirect_number);
- pbx_builtin_setvar_helper(ch, "PRIREDIRECTREASON", redirectingreason2str(pvt->cd.redirect_reason));
- }
- ch->cid.cid_pres = pvt->cd.presentation;
- ch->cid.cid_ton = pvt->cd.type_of_number;
-
- if (!ast_strlen_zero(pvt->exten) && strcmp(pvt->exten, "s")) {
- ch->cid.cid_dnid = strdup(pvt->exten);
- }
- if (pvt->cd.transfer_capability >= 0)
- ch->transfercapability = pvt->cd.transfer_capability;
- if (state != AST_STATE_DOWN) {
- if (ast_pbx_start(ch)) {
- ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ch->name);
- ast_hangup(ch);
- ch = NULL;
- }
- }
- } else {
- ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
- }
- return ch;
-}
-
-static struct oh323_pvt *oh323_alloc(int callid)
-{
- struct oh323_pvt *pvt;
-
- pvt = (struct oh323_pvt *) malloc(sizeof(struct oh323_pvt));
- if (!pvt) {
- ast_log(LOG_ERROR, "Couldn't allocate private structure. This is bad\n");
- return NULL;
- }
- memset(pvt, 0, sizeof(struct oh323_pvt));
- pvt->cd.redirect_reason = -1;
- pvt->cd.transfer_capability = -1;
- /* Ensure the call token is allocated for outgoing call */
- if (!callid) {
- if ((pvt->cd).call_token == NULL) {
- (pvt->cd).call_token = (char *)malloc(128);
- }
- if (!pvt->cd.call_token) {
- ast_log(LOG_ERROR, "Not enough memory to alocate call token\n");
- ast_rtp_destroy(pvt->rtp);
- free(pvt);
- return NULL;
- }
- memset((char *)(pvt->cd).call_token, 0, 128);
- pvt->cd.call_reference = callid;
- }
- memcpy(&pvt->options, &global_options, sizeof(pvt->options));
- pvt->jointcapability = pvt->options.capability;
- if (pvt->options.dtmfmode & H323_DTMF_RFC2833) {
- pvt->nonCodecCapability |= AST_RTP_DTMF;
- } else {
- pvt->nonCodecCapability &= ~AST_RTP_DTMF;
- }
- ast_copy_string(pvt->context, default_context, sizeof(pvt->context));
- pvt->newstate = pvt->newcontrol = pvt->newdigit = pvt->update_rtp_info = pvt->DTMFsched = -1;
- ast_mutex_init(&pvt->lock);
- /* Add to interface list */
- ast_mutex_lock(&iflock);
- pvt->next = iflist;
- iflist = pvt;
- ast_mutex_unlock(&iflock);
- return pvt;
-}
-
-static struct oh323_pvt *find_call_locked(int call_reference, const char *token)
-{
- struct oh323_pvt *pvt;
-
- ast_mutex_lock(&iflock);
- pvt = iflist;
- while(pvt) {
- if (!pvt->needdestroy && ((signed int)pvt->cd.call_reference == call_reference)) {
- /* Found the call */
- if ((token != NULL) && (pvt->cd.call_token != NULL) && (!strcmp(pvt->cd.call_token, token))) {
- ast_mutex_lock(&pvt->lock);
- ast_mutex_unlock(&iflock);
- return pvt;
- } else if (token == NULL) {
- ast_log(LOG_WARNING, "Call Token is NULL\n");
- ast_mutex_lock(&pvt->lock);
- ast_mutex_unlock(&iflock);
- return pvt;
- }
- }
- pvt = pvt->next;
- }
- ast_mutex_unlock(&iflock);
- return NULL;
-}
-
-static int update_state(struct oh323_pvt *pvt, int state, int signal)
-{
- if (!pvt)
- return 0;
- if (pvt->owner && !ast_channel_trylock(pvt->owner)) {
- if (state >= 0)
- ast_setstate(pvt->owner, state);
- if (signal >= 0)
- ast_queue_control(pvt->owner, signal);
- ast_channel_unlock(pvt->owner);
- return 1;
- }
- else {
- if (state >= 0)
- pvt->newstate = state;
- if (signal >= 0)
- pvt->newcontrol = signal;
- return 0;
- }
-}
-
-static struct oh323_alias *build_alias(const char *name, struct ast_variable *v, struct ast_variable *alt, int realtime)
-{
- struct oh323_alias *alias;
- int found = 0;
-
- alias = ASTOBJ_CONTAINER_FIND_UNLINK_FULL(&aliasl, name, name, 0, 0, strcasecmp);
-
- if (alias)
- found++;
- else {
- if (!(alias = (struct oh323_alias *)calloc(1, sizeof(*alias))))
- return NULL;
- ASTOBJ_INIT(alias);
- }
- if (!found && name)
- ast_copy_string(alias->name, name, sizeof(alias->name));
- for (; v || ((v = alt) && !(alt = NULL)); v = v->next) {
- if (!strcasecmp(v->name, "e164")) {
- ast_copy_string(alias->e164, v->value, sizeof(alias->e164));
- } else if (!strcasecmp(v->name, "prefix")) {
- ast_copy_string(alias->prefix, v->value, sizeof(alias->prefix));
- } else if (!strcasecmp(v->name, "context")) {
- ast_copy_string(alias->context, v->value, sizeof(alias->context));
- } else if (!strcasecmp(v->name, "secret")) {
- ast_copy_string(alias->secret, v->value, sizeof(alias->secret));
- } else {
- if (strcasecmp(v->value, "h323")) {
- ast_log(LOG_WARNING, "Keyword %s does not make sense in type=h323\n", v->name);
- }
- }
- }
- ASTOBJ_UNMARK(alias);
- return alias;
-}
-
-static struct oh323_alias *realtime_alias(const char *alias)
-{
- struct ast_variable *var, *tmp;
- struct oh323_alias *a;
-
- var = ast_load_realtime("h323", "name", alias, NULL);
-
- if (!var)
- return NULL;
-
- for (tmp = var; tmp; tmp = tmp->next) {
- if (!strcasecmp(tmp->name, "type") &&
- !(!strcasecmp(tmp->value, "alias") || !strcasecmp(tmp->value, "h323"))) {
- ast_variables_destroy(var);
- return NULL;
- }
- }
-
- a = build_alias(alias, var, NULL, 1);
-
- ast_variables_destroy(var);
-
- return a;
-}
-
-#define DEPRECATED(_v, _new_opt) \
- ast_log(LOG_WARNING, "Option %s found at line %d has beed deprecated. Use %s instead.\n", (_v)->name, (_v)->lineno, (_new_opt))
-
-static int update_common_options(struct ast_variable *v, struct call_options *options)
-{
- int tmp;
-
- if (!strcasecmp(v->name, "allow")) {
- ast_parse_allow_disallow(&options->prefs, &options->capability, v->value, 1);
- } else if (!strcasecmp(v->name, "disallow")) {
- ast_parse_allow_disallow(&options->prefs, &options->capability, v->value, 0);
- } else if (!strcasecmp(v->name, "dtmfmode")) {
- if (!strcasecmp(v->value, "inband")) {
- options->dtmfmode = H323_DTMF_INBAND;
- } else if (!strcasecmp(v->value, "rfc2833")) {
- options->dtmfmode = H323_DTMF_RFC2833;
- } else {
- ast_log(LOG_WARNING, "Unknown dtmf mode '%s', using rfc2833\n", v->value);
- options->dtmfmode = H323_DTMF_RFC2833;
- }
- } else if (!strcasecmp(v->name, "dtmfcodec")) {
- tmp = atoi(v->value);
- if (tmp < 96)
- ast_log(LOG_WARNING, "Invalid %s value %s at line %d\n", v->name, v->value, v->lineno);
- else
- options->dtmfcodec = tmp;
- } else if (!strcasecmp(v->name, "bridge")) {
- options->bridge = ast_true(v->value);
- } else if (!strcasecmp(v->name, "nat")) {
- options->nat = ast_true(v->value);
- } else if (!strcasecmp(v->name, "noFastStart")) {
- DEPRECATED(v, "fastStart");
- options->fastStart = !ast_true(v->value);
- } else if (!strcasecmp(v->name, "fastStart")) {
- options->fastStart = ast_true(v->value);
- } else if (!strcasecmp(v->name, "noH245Tunneling")) {
- DEPRECATED(v, "h245Tunneling");
- options->h245Tunneling = !ast_true(v->value);
- } else if (!strcasecmp(v->name, "h245Tunneling")) {
- options->h245Tunneling = ast_true(v->value);
- } else if (!strcasecmp(v->name, "noSilenceSuppression")) {
- DEPRECATED(v, "silenceSuppression");
- options->silenceSuppression = !ast_true(v->value);
- } else if (!strcasecmp(v->name, "silenceSuppression")) {
- options->silenceSuppression = ast_true(v->value);
- } else if (!strcasecmp(v->name, "progress_setup")) {
- tmp = atoi(v->value);
- if ((tmp != 0) && (tmp != 1) && (tmp != 3) && (tmp != 8)) {
- ast_log(LOG_WARNING, "Invalid value %s for %s at line %d, assuming 0\n", v->value, v->name, v->lineno);
- tmp = 0;
- }
- options->progress_setup = tmp;
- } else if (!strcasecmp(v->name, "progress_alert")) {
- tmp = atoi(v->value);
- if ((tmp != 0) && (tmp != 1) && (tmp != 8)) {
- ast_log(LOG_WARNING, "Invalid value %s for %s at line %d, assuming 0\n", v->value, v->name, v->lineno);
- tmp = 0;
- }
- options->progress_alert = tmp;
- } else if (!strcasecmp(v->name, "progress_audio")) {
- options->progress_audio = ast_true(v->value);
- } else if (!strcasecmp(v->name, "callerid")) {
- ast_callerid_split(v->value, options->cid_name, sizeof(options->cid_name), options->cid_num, sizeof(options->cid_num));
- } else if (!strcasecmp(v->name, "fullname")) {
- ast_copy_string(options->cid_name, v->value, sizeof(options->cid_name));
- } else if (!strcasecmp(v->name, "cid_number")) {
- ast_copy_string(options->cid_num, v->value, sizeof(options->cid_num));
- } else if (!strcasecmp(v->name, "tunneling")) {
- if (!strcasecmp(v->value, "none"))
- options->tunnelOptions = 0;
- else if (!strcasecmp(v->value, "cisco"))
- options->tunnelOptions |= H323_TUNNEL_CISCO;
- else if (!strcasecmp(v->value, "qsig"))
- options->tunnelOptions |= H323_TUNNEL_QSIG;
- else
- ast_log(LOG_WARNING, "Invalid value %s for %s at line %d\n", v->value, v->name, v->lineno);
- } else
- return 1;
-
- return 0;
-}
-#undef DEPRECATED
-
-static struct oh323_user *build_user(char *name, struct ast_variable *v, struct ast_variable *alt, int realtime)
-{
- struct oh323_user *user;
- struct ast_ha *oldha;
- int found = 0;
- int format;
-
- user = ASTOBJ_CONTAINER_FIND_UNLINK_FULL(&userl, name, name, 0, 0, strcmp);
-
- if (user)
- found++;
- else {
- if (!(user = (struct oh323_user *)calloc(1, sizeof(*user))))
- return NULL;
- ASTOBJ_INIT(user);
- }
- oldha = user->ha;
- user->ha = (struct ast_ha *)NULL;
- memcpy(&user->options, &global_options, sizeof(user->options));
- /* Set default context */
- ast_copy_string(user->context, default_context, sizeof(user->context));
- if (user && !found)
- ast_copy_string(user->name, name, sizeof(user->name));
-
-#if 0 /* XXX Port channel variables functionality from chan_sip XXX */
- if (user->chanvars) {
- ast_variables_destroy(user->chanvars);
- user->chanvars = NULL;
- }
-#endif
-
- for (; v || ((v = alt) && !(alt = NULL)); v = v->next) {
- if (!update_common_options(v, &user->options))
- continue;
- if (!strcasecmp(v->name, "context")) {
- ast_copy_string(user->context, v->value, sizeof(user->context));
- } else if (!strcasecmp(v->name, "secret")) {
- ast_copy_string(user->secret, v->value, sizeof(user->secret));
- } else if (!strcasecmp(v->name, "accountcode")) {
- ast_copy_string(user->accountcode, v->value, sizeof(user->accountcode));
- } else if (!strcasecmp(v->name, "host")) {
- if (!strcasecmp(v->value, "dynamic")) {
- ast_log(LOG_ERROR, "A dynamic host on a type=user does not make any sense\n");
- ASTOBJ_UNREF(user, oh323_destroy_user);
- return NULL;
- } else if (ast_get_ip(&user->addr, v->value)) {
- ASTOBJ_UNREF(user, oh323_destroy_user);
- return NULL;
- }
- /* Let us know we need to use ip authentication */
- user->host = 1;
- } else if (!strcasecmp(v->name, "amaflags")) {
- format = ast_cdr_amaflags2int(v->value);
- if (format < 0) {
- ast_log(LOG_WARNING, "Invalid AMA Flags: %s at line %d\n", v->value, v->lineno);
- } else {
- user->amaflags = format;
- }
- } else if (!strcasecmp(v->name, "permit") ||
- !strcasecmp(v->name, "deny")) {
- user->ha = ast_append_ha(v->name, v->value, user->ha);
- }
- }
- ASTOBJ_UNMARK(user);
- ast_free_ha(oldha);
- return user;
-}
-
-static struct oh323_user *realtime_user(const call_details_t *cd)
-{
- struct ast_variable *var, *tmp;
- struct oh323_user *user;
- char *username;
-
- if (userbyalias)
- var = ast_load_realtime("h323", "name", username = cd->call_source_aliases, NULL);
- else {
- username = (char *)NULL;
- var = ast_load_realtime("h323", "host", cd->sourceIp, NULL);
- }
-
- if (!var)
- return NULL;
-
- for (tmp = var; tmp; tmp = tmp->next) {
- if (!strcasecmp(tmp->name, "type") &&
- !(!strcasecmp(tmp->value, "user") || !strcasecmp(tmp->value, "friend"))) {
- ast_variables_destroy(var);
- return NULL;
- } else if (!username && !strcasecmp(tmp->name, "name"))
- username = tmp->value;
- }
-
- if (!username) {
- ast_log(LOG_WARNING, "Cannot determine user name for IP address %s\n", cd->sourceIp);
- ast_variables_destroy(var);
- return NULL;
- }
-
- user = build_user(username, var, NULL, 1);
-
- ast_variables_destroy(var);
-
- return user;
-}
-
-static struct oh323_peer *build_peer(const char *name, struct ast_variable *v, struct ast_variable *alt, int realtime)
-{
- struct oh323_peer *peer;
- struct ast_ha *oldha;
- int found = 0;
-
- peer = ASTOBJ_CONTAINER_FIND_UNLINK_FULL(&peerl, name, name, 0, 0, strcmp);
-
- if (peer)
- found++;
- else {
- if (!(peer = (struct oh323_peer*)calloc(1, sizeof(*peer))))
- return NULL;
- ASTOBJ_INIT(peer);
- }
- oldha = peer->ha;
- peer->ha = NULL;
- memcpy(&peer->options, &global_options, sizeof(peer->options));
- peer->addr.sin_port = htons(h323_signalling_port);
- peer->addr.sin_family = AF_INET;
- if (!found && name)
- ast_copy_string(peer->name, name, sizeof(peer->name));
-
-#if 0 /* XXX Port channel variables functionality from chan_sip XXX */
- if (peer->chanvars) {
- ast_variables_destroy(peer->chanvars);
- peer->chanvars = NULL;
- }
-#endif
- /* Default settings for mailbox */
- peer->mailbox[0] = '\0';
-
- for (; v || ((v = alt) && !(alt = NULL)); v = v->next) {
- if (!update_common_options(v, &peer->options))
- continue;
- if (!strcasecmp(v->name, "host")) {
- if (!strcasecmp(v->value, "dynamic")) {
- ast_log(LOG_ERROR, "Dynamic host configuration not implemented.\n");
- ASTOBJ_UNREF(peer, oh323_destroy_peer);
- return NULL;
- }
- if (ast_get_ip(&peer->addr, v->value)) {
- ast_log(LOG_ERROR, "Could not determine IP for %s\n", v->value);
- ASTOBJ_UNREF(peer, oh323_destroy_peer);
- return NULL;
- }
- } else if (!strcasecmp(v->name, "port")) {
- peer->addr.sin_port = htons(atoi(v->value));
- } else if (!strcasecmp(v->name, "permit") ||
- !strcasecmp(v->name, "deny")) {
- peer->ha = ast_append_ha(v->name, v->value, peer->ha);
- } else if (!strcasecmp(v->name, "mailbox")) {
- ast_copy_string(peer->mailbox, v->value, sizeof(peer->mailbox));
- } else if (!strcasecmp(v->name, "hasvoicemail")) {
- if (ast_true(v->value) && ast_strlen_zero(peer->mailbox)) {
- ast_copy_string(peer->mailbox, name, sizeof(peer->mailbox));
- }
- }
- }
- ASTOBJ_UNMARK(peer);
- ast_free_ha(oldha);
- return peer;
-}
-
-static struct oh323_peer *realtime_peer(const char *peername, struct sockaddr_in *sin)
-{
- struct oh323_peer *peer;
- struct ast_variable *var;
- struct ast_variable *tmp;
- const char *addr;
-
- /* First check on peer name */
- if (peername)
- var = ast_load_realtime("h323", "name", peername, addr = NULL);
- else if (sin) /* Then check on IP address for dynamic peers */
- var = ast_load_realtime("h323", "host", addr = ast_inet_ntoa(sin->sin_addr), NULL);
- else
- return NULL;
-
- if (!var)
- return NULL;
-
- for (tmp = var; tmp; tmp = tmp->next) {
- /* If this is type=user, then skip this object. */
- if (!strcasecmp(tmp->name, "type") &&
- !(!strcasecmp(tmp->value, "peer") || !strcasecmp(tmp->value, "friend"))) {
- ast_variables_destroy(var);
- return NULL;
- } else if (!peername && !strcasecmp(tmp->name, "name")) {
- peername = tmp->value;
- }
- }
-
- if (!peername) { /* Did not find peer in realtime */
- ast_log(LOG_WARNING, "Cannot determine peer name for IP address %s\n", addr);
- ast_variables_destroy(var);
- return NULL;
- }
-
- /* Peer found in realtime, now build it in memory */
- peer = build_peer(peername, var, NULL, 1);
-
- ast_variables_destroy(var);
-
- return peer;
-}
-
-static int oh323_addrcmp_str(struct in_addr inaddr, char *addr)
-{
- return strcmp(ast_inet_ntoa(inaddr), addr);
-}
-
-static struct oh323_user *find_user(const call_details_t *cd, int realtime)
-{
- struct oh323_user *u;
-
- if (userbyalias)
- u = ASTOBJ_CONTAINER_FIND(&userl, cd->call_source_aliases);
- else
- u = ASTOBJ_CONTAINER_FIND_FULL(&userl, cd->sourceIp, addr.sin_addr, 0, 0, oh323_addrcmp_str);
-
- if (!u && realtime)
- u = realtime_user(cd);
-
- if (!u && h323debug)
- ast_log(LOG_DEBUG, "Could not find user by name %s or address %s\n", cd->call_source_aliases, cd->sourceIp);
-
- return u;
-}
-
-static int oh323_addrcmp(struct sockaddr_in addr, struct sockaddr_in *sin)
-{
- int res;
-
- if (!sin)
- res = -1;
- else
- res = inaddrcmp(&addr , sin);
-
- return res;
-}
-
-static struct oh323_peer *find_peer(const char *peer, struct sockaddr_in *sin, int realtime)
-{
- struct oh323_peer *p;
-
- if (peer)
- p = ASTOBJ_CONTAINER_FIND(&peerl, peer);
- else
- p = ASTOBJ_CONTAINER_FIND_FULL(&peerl, sin, addr, 0, 0, oh323_addrcmp);
-
- if (!p && realtime)
- p = realtime_peer(peer, sin);
-
- if (!p && h323debug)
- ast_log(LOG_DEBUG, "Could not find peer by name %s or address %s\n", (peer ? peer : "<NONE>"), (sin ? ast_inet_ntoa(sin->sin_addr) : "<NONE>"));
-
- return p;
-}
-
-static int create_addr(struct oh323_pvt *pvt, char *opeer)
-{
- struct hostent *hp;
- struct ast_hostent ahp;
- struct oh323_peer *p;
- int portno;
- int found = 0;
- char *port;
- char *hostn;
- char peer[256] = "";
-
- ast_copy_string(peer, opeer, sizeof(peer));
- port = strchr(peer, ':');
- if (port) {
- *port = '\0';
- port++;
- }
- pvt->sa.sin_family = AF_INET;
- p = find_peer(peer, NULL, 1);
- if (p) {
- found++;
- memcpy(&pvt->options, &p->options, sizeof(pvt->options));
- pvt->jointcapability = pvt->options.capability;
- if (pvt->options.dtmfmode) {
- if (pvt->options.dtmfmode & H323_DTMF_RFC2833) {
- pvt->nonCodecCapability |= AST_RTP_DTMF;
- } else {
- pvt->nonCodecCapability &= ~AST_RTP_DTMF;
- }
- }
- if (p->addr.sin_addr.s_addr) {
- pvt->sa.sin_addr = p->addr.sin_addr;
- pvt->sa.sin_port = p->addr.sin_port;
- }
- ASTOBJ_UNREF(p, oh323_destroy_peer);
- }
- if (!p && !found) {
- hostn = peer;
- if (port) {
- portno = atoi(port);
- } else {
- portno = h323_signalling_port;
- }
- hp = ast_gethostbyname(hostn, &ahp);
- if (hp) {
- memcpy(&pvt->sa.sin_addr, hp->h_addr, sizeof(pvt->sa.sin_addr));
- pvt->sa.sin_port = htons(portno);
- /* Look peer by address */
- p = find_peer(NULL, &pvt->sa, 1);
- memcpy(&pvt->options, (p ? &p->options : &global_options), sizeof(pvt->options));
- pvt->jointcapability = pvt->options.capability;
- if (p) {
- ASTOBJ_UNREF(p, oh323_destroy_peer);
- }
- if (pvt->options.dtmfmode) {
- if (pvt->options.dtmfmode & H323_DTMF_RFC2833) {
- pvt->nonCodecCapability |= AST_RTP_DTMF;
- } else {
- pvt->nonCodecCapability &= ~AST_RTP_DTMF;
- }
- }
- return 0;
- } else {
- ast_log(LOG_WARNING, "No such host: %s\n", peer);
- return -1;
- }
- } else if (!found) {
- return -1;
- } else {
- return 0;
- }
-}
-static struct ast_channel *oh323_request(const char *type, int format, void *data, int *cause)
-{
- int oldformat;
- struct oh323_pvt *pvt;
- struct ast_channel *tmpc = NULL;
- char *dest = (char *)data;
- char *ext, *host;
- char *h323id = NULL;
- char tmp[256], tmp1[256];
-
- if (h323debug)
- ast_log(LOG_DEBUG, "type=%s, format=%d, data=%s.\n", type, format, (char *)data);
-
- pvt = oh323_alloc(0);
- if (!pvt) {
- ast_log(LOG_WARNING, "Unable to build pvt data for '%s'\n", (char *)data);
- return NULL;
- }
- oldformat = format;
- format &= ((AST_FORMAT_MAX_AUDIO << 1) - 1);
- if (!format) {
- ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", format);
- oh323_destroy(pvt);
- if (cause)
- *cause = AST_CAUSE_INCOMPATIBLE_DESTINATION;
- return NULL;
- }
- ast_copy_string(tmp, dest, sizeof(tmp));
- host = strchr(tmp, '@');
- if (host) {
- *host = '\0';
- host++;
- ext = tmp;
- } else {
- ext = strrchr(tmp, '/');
- if (ext)
- *ext++ = '\0';
- host = tmp;
- }
- strtok_r(host, "/", &(h323id));
- if (!ast_strlen_zero(h323id)) {
- h323_set_id(h323id);
- }
- if (ext) {
- ast_copy_string(pvt->exten, ext, sizeof(pvt->exten));
- }
- if (h323debug)
- ast_log(LOG_DEBUG, "Extension: %s Host: %s\n", pvt->exten, host);
-
- if (gatekeeper_disable) {
- if (create_addr(pvt, host)) {
- oh323_destroy(pvt);
- if (cause)
- *cause = AST_CAUSE_DESTINATION_OUT_OF_ORDER;
- return NULL;
- }
- }
- else {
- memcpy(&pvt->options, &global_options, sizeof(pvt->options));
- pvt->jointcapability = pvt->options.capability;
- if (pvt->options.dtmfmode) {
- if (pvt->options.dtmfmode & H323_DTMF_RFC2833) {
- pvt->nonCodecCapability |= AST_RTP_DTMF;
- } else {
- pvt->nonCodecCapability &= ~AST_RTP_DTMF;
- }
- }
- }
-
- ast_mutex_lock(&caplock);
- /* Generate unique channel identifier */
- snprintf(tmp1, sizeof(tmp1)-1, "%s-%u", host, ++unique);
- tmp1[sizeof(tmp1)-1] = '\0';
- ast_mutex_unlock(&caplock);
-
- ast_mutex_lock(&pvt->lock);
- tmpc = __oh323_new(pvt, AST_STATE_DOWN, tmp1);
- ast_mutex_unlock(&pvt->lock);
- if (!tmpc) {
- oh323_destroy(pvt);
- if (cause)
- *cause = AST_CAUSE_NORMAL_TEMPORARY_FAILURE;
- }
- ast_update_use_count();
- restart_monitor();
- return tmpc;
-}
-
-/** Find a call by alias */
-static struct oh323_alias *find_alias(const char *source_aliases, int realtime)
-{
- struct oh323_alias *a;
-
- a = ASTOBJ_CONTAINER_FIND(&aliasl, source_aliases);
-
- if (!a && realtime)
- a = realtime_alias(source_aliases);
-
- return a;
-}
-
-/**
- * Callback for sending digits from H.323 up to asterisk
- *
- */
-static int receive_digit(unsigned call_reference, char digit, const char *token, int duration)
-{
- struct oh323_pvt *pvt;
- int res;
-
- pvt = find_call_locked(call_reference, token);
- if (!pvt) {
- ast_log(LOG_ERROR, "Received digit '%c' (%u ms) for call %s without private structure\n", digit, duration, token);
- return -1;
- }
- if (h323debug)
- ast_log(LOG_DTMF, "Received %s digit '%c' (%u ms) for call %s\n", (digit == ' ' ? "update for" : "new"), (digit == ' ' ? pvt->curDTMF : digit), duration, token);
-
- if (pvt->owner && !ast_channel_trylock(pvt->owner)) {
- if (digit == '!')
- res = ast_queue_control(pvt->owner, AST_CONTROL_FLASH);
- else {
- struct ast_frame f = {
- .frametype = AST_FRAME_DTMF_END,
- .subclass = digit,
- .samples = duration * 8,
- .len = duration,
- .src = "SEND_DIGIT",
- };
- if (digit == ' ') { /* signalUpdate message */
- f.subclass = pvt->curDTMF;
- AST_SCHED_DEL(sched, pvt->DTMFsched);
- } else { /* Regular input or signal message */
- if (pvt->DTMFsched >= 0) {
- /* We still don't send DTMF END from previous event, send it now */
- AST_SCHED_DEL(sched, pvt->DTMFsched);
- f.subclass = pvt->curDTMF;
- f.samples = f.len = 0;
- ast_queue_frame(pvt->owner, &f);
- /* Restore values */
- f.subclass = digit;
- f.samples = duration * 8;
- f.len = duration;
- }
- if (duration) { /* This is a signal, signalUpdate follows */
- f.frametype = AST_FRAME_DTMF_BEGIN;
- pvt->DTMFsched = ast_sched_add(sched, duration, oh323_simulate_dtmf_end, pvt);
- if (h323debug)
- ast_log(LOG_DTMF, "Scheduled DTMF END simulation for %d ms, id=%d\n", duration, pvt->DTMFsched);
- }
- pvt->curDTMF = digit;
- }
- res = ast_queue_frame(pvt->owner, &f);
- }
- ast_channel_unlock(pvt->owner);
- } else {
- if (digit == '!')
- pvt->newcontrol = AST_CONTROL_FLASH;
- else {
- pvt->newduration = duration;
- pvt->newdigit = digit;
- }
- res = 0;
- }
- ast_mutex_unlock(&pvt->lock);
- return res;
-}
-
-/**
- * Callback function used to inform the H.323 stack of the local rtp ip/port details
- *
- * Returns the local RTP information
- */
-static struct rtp_info *external_rtp_create(unsigned call_reference, const char * token)
-{
- struct oh323_pvt *pvt;
- struct sockaddr_in us;
- struct rtp_info *info;
-
- info = (struct rtp_info *)malloc(sizeof(struct rtp_info));
- if (!info) {
- ast_log(LOG_ERROR, "Unable to allocated info structure, this is very bad\n");
- return NULL;
- }
- pvt = find_call_locked(call_reference, token);
- if (!pvt) {
- free(info);
- ast_log(LOG_ERROR, "Unable to find call %s(%d)\n", token, call_reference);
- return NULL;
- }
- if (!pvt->rtp)
- __oh323_rtp_create(pvt);
- if (!pvt->rtp) {
- ast_mutex_unlock(&pvt->lock);
- free(info);
- ast_log(LOG_ERROR, "No RTP stream is available for call %s (%d)", token, call_reference);
- return NULL;
- }
- /* figure out our local RTP port and tell the H.323 stack about it */
- ast_rtp_get_us(pvt->rtp, &us);
- ast_mutex_unlock(&pvt->lock);
-
- ast_copy_string(info->addr, ast_inet_ntoa(us.sin_addr), sizeof(info->addr));
- info->port = ntohs(us.sin_port);
- if (h323debug)
- ast_log(LOG_DEBUG, "Sending RTP 'US' %s:%d\n", info->addr, info->port);
- return info;
-}
-
-/**
- * Definition taken from rtp.c for rtpPayloadType because we need it here.
- */
-struct rtpPayloadType {
- int isAstFormat; /* whether the following code is an AST_FORMAT */
- int code;
-};
-
-/**
- * Call-back function passing remote ip/port information from H.323 to asterisk
- *
- * Returns nothing
- */
-static void setup_rtp_connection(unsigned call_reference, const char *remoteIp, int remotePort, const char *token, int pt)
-{
- struct oh323_pvt *pvt;
- struct sockaddr_in them;
- struct rtpPayloadType rtptype;
- int nativeformats_changed;
- enum { NEED_NONE, NEED_HOLD, NEED_UNHOLD } rtp_change = NEED_NONE;
-
- if (h323debug)
- ast_log(LOG_DEBUG, "Setting up RTP connection for %s\n", token);
-
- /* Find the call or allocate a private structure if call not found */
- pvt = find_call_locked(call_reference, token);
- if (!pvt) {
- ast_log(LOG_ERROR, "Something is wrong: rtp\n");
- return;
- }
- if (pvt->alreadygone) {
- ast_mutex_unlock(&pvt->lock);
- return;
- }
-
- if (!pvt->rtp)
- __oh323_rtp_create(pvt);
-
- them.sin_family = AF_INET;
- /* only works for IPv4 */
- them.sin_addr.s_addr = inet_addr(remoteIp);
- them.sin_port = htons(remotePort);
-
- if (them.sin_addr.s_addr) {
- ast_rtp_set_peer(pvt->rtp, &them);
- if (pvt->recvonly) {
- pvt->recvonly = 0;
- rtp_change = NEED_UNHOLD;
- }
- } else {
- ast_rtp_stop(pvt->rtp);
- if (!pvt->recvonly) {
- pvt->recvonly = 1;
- rtp_change = NEED_HOLD;
- }
- }
-
- /* Change native format to reflect information taken from OLC/OLCAck */
- nativeformats_changed = 0;
- if (pt != 128 && pvt->rtp) { /* Payload type is invalid, so try to use previously decided */
- rtptype = ast_rtp_lookup_pt(pvt->rtp, pt);
- if (h323debug)
- ast_log(LOG_DEBUG, "Native format is set to %d from %d by RTP payload type %d\n", rtptype.code, pvt->nativeformats, pt);
- if (pvt->nativeformats != rtptype.code) {
- pvt->nativeformats = rtptype.code;
- nativeformats_changed = 1;
- }
- } else if (h323debug)
- ast_log(LOG_NOTICE, "Payload type is unknown, formats isn't changed\n");
-
- /* Don't try to lock the channel if nothing changed */
- if (nativeformats_changed || pvt->options.progress_audio || (rtp_change != NEED_NONE)) {
- if (pvt->owner && !ast_channel_trylock(pvt->owner)) {
- /* Re-build translation path only if native format(s) has been changed */
- if (pvt->owner->nativeformats != pvt->nativeformats) {
- if (h323debug)
- ast_log(LOG_DEBUG, "Native format changed to %d from %d, read format is %d, write format is %d\n", pvt->nativeformats, pvt->owner->nativeformats, pvt->owner->readformat, pvt->owner->writeformat);
- pvt->owner->nativeformats = pvt->nativeformats;
- ast_set_read_format(pvt->owner, pvt->owner->readformat);
- ast_set_write_format(pvt->owner, pvt->owner->writeformat);
- }
- if (pvt->options.progress_audio)
- ast_queue_control(pvt->owner, AST_CONTROL_PROGRESS);
- switch (rtp_change) {
- case NEED_HOLD:
- ast_queue_control(pvt->owner, AST_CONTROL_HOLD);
- break;
- case NEED_UNHOLD:
- ast_queue_control(pvt->owner, AST_CONTROL_UNHOLD);
- break;
- default:
- break;
- }
- ast_channel_unlock(pvt->owner);
- }
- else {
- if (pvt->options.progress_audio)
- pvt->newcontrol = AST_CONTROL_PROGRESS;
- else if (rtp_change == NEED_HOLD)
- pvt->newcontrol = AST_CONTROL_HOLD;
- else if (rtp_change == NEED_UNHOLD)
- pvt->newcontrol = AST_CONTROL_UNHOLD;
- if (h323debug)
- ast_log(LOG_DEBUG, "RTP connection preparation for %s is pending...\n", token);
- }
- }
- ast_mutex_unlock(&pvt->lock);
-
- if (h323debug)
- ast_log(LOG_DEBUG, "RTP connection prepared for %s\n", token);
-
- return;
-}
-
-/**
- * Call-back function to signal asterisk that the channel has been answered
- * Returns nothing
- */
-static void connection_made(unsigned call_reference, const char *token)
-{
- struct oh323_pvt *pvt;
-
- if (h323debug)
- ast_log(LOG_DEBUG, "Call %s answered\n", token);
-
- pvt = find_call_locked(call_reference, token);
- if (!pvt) {
- ast_log(LOG_ERROR, "Something is wrong: connection\n");
- return;
- }
-
- /* Inform asterisk about remote party connected only on outgoing calls */
- if (!pvt->outgoing) {
- ast_mutex_unlock(&pvt->lock);
- return;
- }
- /* Do not send ANSWER message more than once */
- if (!pvt->connection_established) {
- pvt->connection_established = 1;
- update_state(pvt, -1, AST_CONTROL_ANSWER);
- }
- ast_mutex_unlock(&pvt->lock);
- return;
-}
-
-static int progress(unsigned call_reference, const char *token, int inband)
-{
- struct oh323_pvt *pvt;
-
- if (h323debug)
- ast_log(LOG_DEBUG, "Received ALERT/PROGRESS message for %s tones\n", (inband ? "inband" : "self-generated"));
-
- pvt = find_call_locked(call_reference, token);
- if (!pvt) {
- ast_log(LOG_ERROR, "Private structure not found in progress.\n");
- return -1;
- }
- if (!pvt->owner) {
- ast_mutex_unlock(&pvt->lock);
- ast_log(LOG_ERROR, "No Asterisk channel associated with private structure.\n");
- return -1;
- }
- update_state(pvt, -1, (inband ? AST_CONTROL_PROGRESS : AST_CONTROL_RINGING));
- ast_mutex_unlock(&pvt->lock);
-
- return 0;
-}
-
-/**
- * Call-back function for incoming calls
- *
- * Returns 1 on success
- */
-static call_options_t *setup_incoming_call(call_details_t *cd)
-{
- struct oh323_pvt *pvt;
- struct oh323_user *user = NULL;
- struct oh323_alias *alias = NULL;
-
- if (h323debug)
- ast_log(LOG_DEBUG, "Setting up incoming call for %s\n", cd->call_token);
-
- /* allocate the call*/
- pvt = oh323_alloc(cd->call_reference);
-
- if (!pvt) {
- ast_log(LOG_ERROR, "Unable to allocate private structure, this is bad.\n");
- cleanup_call_details(cd);
- return NULL;
- }
-
- /* Populate the call details in the private structure */
- memcpy(&pvt->cd, cd, sizeof(pvt->cd));
- memcpy(&pvt->options, &global_options, sizeof(pvt->options));
- pvt->jointcapability = pvt->options.capability;
-
- if (h323debug) {
- ast_verbose(VERBOSE_PREFIX_3 "Setting up Call\n");
- ast_verbose(VERBOSE_PREFIX_3 " \tCall token: [%s]\n", pvt->cd.call_token);
- ast_verbose(VERBOSE_PREFIX_3 " \tCalling party name: [%s]\n", pvt->cd.call_source_name);
- ast_verbose(VERBOSE_PREFIX_3 " \tCalling party number: [%s]\n", pvt->cd.call_source_e164);
- ast_verbose(VERBOSE_PREFIX_3 " \tCalled party name: [%s]\n", pvt->cd.call_dest_alias);
- ast_verbose(VERBOSE_PREFIX_3 " \tCalled party number: [%s]\n", pvt->cd.call_dest_e164);
- if (pvt->cd.redirect_reason >= 0)
- ast_verbose(VERBOSE_PREFIX_3 " \tRedirecting party number: [%s] (reason %d)\n", pvt->cd.redirect_number, pvt->cd.redirect_reason);
- ast_verbose(VERBOSE_PREFIX_3 " \tCalling party IP: [%s]\n", pvt->cd.sourceIp);
- }
-
- /* Decide if we are allowing Gatekeeper routed calls*/
- if ((!strcasecmp(cd->sourceIp, gatekeeper)) && (gkroute == -1) && !gatekeeper_disable) {
- if (!ast_strlen_zero(cd->call_dest_e164)) {
- ast_copy_string(pvt->exten, cd->call_dest_e164, sizeof(pvt->exten));
- ast_copy_string(pvt->context, default_context, sizeof(pvt->context));
- } else {
- alias = find_alias(cd->call_dest_alias, 1);
- if (!alias) {
- ast_log(LOG_ERROR, "Call for %s rejected, alias not found\n", cd->call_dest_alias);
- oh323_destroy(pvt);
- return NULL;
- }
- ast_copy_string(pvt->exten, alias->name, sizeof(pvt->exten));
- ast_copy_string(pvt->context, alias->context, sizeof(pvt->context));
- }
- } else {
- /* Either this call is not from the Gatekeeper
- or we are not allowing gk routed calls */
- user = find_user(cd, 1);
- if (!user) {
- if (!acceptAnonymous) {
- ast_log(LOG_NOTICE, "Anonymous call from '%s@%s' rejected\n", pvt->cd.call_source_aliases, pvt->cd.sourceIp);
- oh323_destroy(pvt);
- return NULL;
- }
- if (ast_strlen_zero(default_context)) {
- ast_log(LOG_ERROR, "Call from '%s@%s' rejected due to no default context\n", pvt->cd.call_source_aliases, pvt->cd.sourceIp);
- oh323_destroy(pvt);
- return NULL;
- }
- ast_copy_string(pvt->context, default_context, sizeof(pvt->context));
- if (!ast_strlen_zero(pvt->cd.call_dest_e164)) {
- ast_copy_string(pvt->exten, cd->call_dest_e164, sizeof(pvt->exten));
- } else {
- ast_copy_string(pvt->exten, cd->call_dest_alias, sizeof(pvt->exten));
- }
- if (h323debug)
- ast_log(LOG_DEBUG, "Sending %s@%s to context [%s] extension %s\n", cd->call_source_aliases, cd->sourceIp, pvt->context, pvt->exten);
- } else {
- if (user->host) {
- if (strcasecmp(cd->sourceIp, ast_inet_ntoa(user->addr.sin_addr))) {
- if (ast_strlen_zero(user->context)) {
- if (ast_strlen_zero(default_context)) {
- ast_log(LOG_ERROR, "Call from '%s' rejected due to non-matching IP address (%s) and no default context\n", user->name, cd->sourceIp);
- oh323_destroy(pvt);
- ASTOBJ_UNREF(user, oh323_destroy_user);
- return NULL;
- }
- ast_copy_string(pvt->context, default_context, sizeof(pvt->context));
- } else {
- ast_copy_string(pvt->context, user->context, sizeof(pvt->context));
- }
- pvt->exten[0] = 'i';
- pvt->exten[1] = '\0';
- ast_log(LOG_ERROR, "Call from '%s' rejected due to non-matching IP address (%s)s\n", user->name, cd->sourceIp);
- oh323_destroy(pvt);
- ASTOBJ_UNREF(user, oh323_destroy_user);
- return NULL; /* XXX: Hmmm... Why to setup context if we drop connection immediately??? */
- }
- }
- ast_copy_string(pvt->context, user->context, sizeof(pvt->context));
- memcpy(&pvt->options, &user->options, sizeof(pvt->options));
- pvt->jointcapability = pvt->options.capability;
- if (!ast_strlen_zero(pvt->cd.call_dest_e164)) {
- ast_copy_string(pvt->exten, cd->call_dest_e164, sizeof(pvt->exten));
- } else {
- ast_copy_string(pvt->exten, cd->call_dest_alias, sizeof(pvt->exten));
- }
- if (!ast_strlen_zero(user->accountcode)) {
- ast_copy_string(pvt->accountcode, user->accountcode, sizeof(pvt->accountcode));
- }
- if (user->amaflags) {
- pvt->amaflags = user->amaflags;
- }
- ASTOBJ_UNREF(user, oh323_destroy_user);
- }
- }
- return &pvt->options;
-}
-
-/**
- * Call-back function to start PBX when OpenH323 ready to serve incoming call
- *
- * Returns 1 on success
- */
-static int answer_call(unsigned call_reference, const char *token)
-{
- struct oh323_pvt *pvt;
- struct ast_channel *c = NULL;
- enum {ext_original, ext_s, ext_i, ext_notexists} try_exten;
- char tmp_exten[sizeof(pvt->exten)];
-
- if (h323debug)
- ast_log(LOG_DEBUG, "Preparing Asterisk to answer for %s\n", token);
-
- /* Find the call or allocate a private structure if call not found */
- pvt = find_call_locked(call_reference, token);
- if (!pvt) {
- ast_log(LOG_ERROR, "Something is wrong: answer_call\n");
- return 0;
- }
- /* Check if requested extension@context pair exists in the dialplan */
- ast_copy_string(tmp_exten, pvt->exten, sizeof(tmp_exten));
-
- /* Try to find best extension in specified context */
- if ((tmp_exten[0] != '\0') && (tmp_exten[1] == '\0')) {
- if (tmp_exten[0] == 's')
- try_exten = ext_s;
- else if (tmp_exten[0] == 'i')
- try_exten = ext_i;
- else
- try_exten = ext_original;
- } else
- try_exten = ext_original;
- do {
- if (ast_exists_extension(NULL, pvt->context, tmp_exten, 1, NULL))
- break;
- switch (try_exten) {
- case ext_original:
- tmp_exten[0] = 's';
- tmp_exten[1] = '\0';
- try_exten = ext_s;
- break;
- case ext_s:
- tmp_exten[0] = 'i';
- try_exten = ext_i;
- break;
- case ext_i:
- try_exten = ext_notexists;
- break;
- default:
- break;
- }
- } while (try_exten != ext_notexists);
-
- /* Drop the call if we don't have <exten>, s and i extensions */
- if (try_exten == ext_notexists) {
- ast_log(LOG_NOTICE, "Dropping call because extensions '%s', 's' and 'i' doesn't exists in context [%s]\n", pvt->exten, pvt->context);
- ast_mutex_unlock(&pvt->lock);
- h323_clear_call(token, AST_CAUSE_UNALLOCATED);
- return 0;
- } else if ((try_exten != ext_original) && (strcmp(pvt->exten, tmp_exten) != 0)) {
- if (h323debug)
- ast_log(LOG_DEBUG, "Going to extension %s@%s because %s@%s isn't exists\n", tmp_exten, pvt->context, pvt->exten, pvt->context);
- ast_copy_string(pvt->exten, tmp_exten, sizeof(pvt->exten));
- }
-
- /* allocate a channel and tell asterisk about it */
- c = __oh323_new(pvt, AST_STATE_RINGING, pvt->cd.call_token);
-
- /* And release when done */
- ast_mutex_unlock(&pvt->lock);
- if (!c) {
- ast_log(LOG_ERROR, "Couldn't create channel. This is bad\n");
- return 0;
- }
- return 1;
-}
-
-/**
- * Call-back function to establish an outgoing H.323 call
- *
- * Returns 1 on success
- */
-static int setup_outgoing_call(call_details_t *cd)
-{
- /* Use argument here or free it immediately */
- cleanup_call_details(cd);
-
- return 1;
-}
-
-/**
- * Call-back function to signal asterisk that the channel is ringing
- * Returns nothing
- */
-static void chan_ringing(unsigned call_reference, const char *token)
-{
- struct oh323_pvt *pvt;
-
- if (h323debug)
- ast_log(LOG_DEBUG, "Ringing on %s\n", token);
-
- pvt = find_call_locked(call_reference, token);
- if (!pvt) {
- ast_log(LOG_ERROR, "Something is wrong: ringing\n");
- return;
- }
- if (!pvt->owner) {
- ast_mutex_unlock(&pvt->lock);
- ast_log(LOG_ERROR, "Channel has no owner\n");
- return;
- }
- update_state(pvt, AST_STATE_RINGING, AST_CONTROL_RINGING);
- ast_mutex_unlock(&pvt->lock);
- return;
-}
-
-/**
- * Call-back function to cleanup communication
- * Returns nothing,
- */
-static void cleanup_connection(unsigned call_reference, const char *call_token)
-{
- struct oh323_pvt *pvt;
-
- if (h323debug)
- ast_log(LOG_DEBUG, "Cleaning connection to %s\n", call_token);
-
- while (1) {
- pvt = find_call_locked(call_reference, call_token);
- if (!pvt) {
- if (h323debug)
- ast_log(LOG_DEBUG, "No connection for %s\n", call_token);
- return;
- }
- if (!pvt->owner || !ast_channel_trylock(pvt->owner))
- break;
-#if 1
-#ifdef DEBUG_THREADS
- ast_log(LOG_NOTICE, "Avoiding H.323 destory deadlock on %s, locked at %ld/%d by %s (%s:%d)\n", call_token, pvt->owner->lock.thread[0], pvt->owner->lock.reentrancy, pvt->owner->lock.func[0], pvt->owner->lock.file[0], pvt->owner->lock.lineno[0]);
-#else
- ast_log(LOG_NOTICE, "Avoiding H.323 destory deadlock on %s\n", call_token);
-#endif
-#endif
- ast_mutex_unlock(&pvt->lock);
- usleep(1);
- }
- if (pvt->rtp) {
- /* Immediately stop RTP */
- ast_rtp_destroy(pvt->rtp);
- pvt->rtp = NULL;
- }
- /* Free dsp used for in-band DTMF detection */
- if (pvt->vad) {
- ast_dsp_free(pvt->vad);
- pvt->vad = NULL;
- }
- cleanup_call_details(&pvt->cd);
- pvt->alreadygone = 1;
- /* Send hangup */
- if (pvt->owner) {
- pvt->owner->_softhangup |= AST_SOFTHANGUP_DEV;
- ast_queue_hangup(pvt->owner);
- ast_channel_unlock(pvt->owner);
- }
- ast_mutex_unlock(&pvt->lock);
- if (h323debug)
- ast_log(LOG_DEBUG, "Connection to %s cleaned\n", call_token);
- return;
-}
-
-static void hangup_connection(unsigned int call_reference, const char *token, int cause)
-{
- struct oh323_pvt *pvt;
-
- if (h323debug) {
- ast_log(LOG_DEBUG, "Hanging up connection to %s with cause %d\n", token, cause);
- }
-
- pvt = find_call_locked(call_reference, token);
- if (!pvt) {
- if (h323debug) {
- ast_log(LOG_DEBUG, "Connection to %s already cleared\n", token);
- }
- return;
- }
- if (pvt->owner && !ast_channel_trylock(pvt->owner)) {
- pvt->owner->_softhangup |= AST_SOFTHANGUP_DEV;
- pvt->owner->hangupcause = pvt->hangupcause = cause;
- ast_queue_hangup(pvt->owner);
- ast_channel_unlock(pvt->owner);
- }
- else {
- pvt->needhangup = 1;
- pvt->hangupcause = cause;
- if (h323debug)
- ast_log(LOG_DEBUG, "Hangup for %s is pending\n", token);
- }
- ast_mutex_unlock(&pvt->lock);
-}
-
-static void set_dtmf_payload(unsigned call_reference, const char *token, int payload)
-{
- struct oh323_pvt *pvt;
-
- if (h323debug)
- ast_log(LOG_DEBUG, "Setting DTMF payload to %d on %s\n", payload, token);
-
- pvt = find_call_locked(call_reference, token);
- if (!pvt) {
- return;
- }
- if (pvt->rtp) {
- ast_rtp_set_rtpmap_type(pvt->rtp, payload, "audio", "telephone-event", 0);
- }
- pvt->dtmf_pt = payload;
- ast_mutex_unlock(&pvt->lock);
- if (h323debug)
- ast_log(LOG_DEBUG, "DTMF payload on %s set to %d\n", token, payload);
-}
-
-static void set_peer_capabilities(unsigned call_reference, const char *token, int capabilities, struct ast_codec_pref *prefs)
-{
- struct oh323_pvt *pvt;
-
- if (h323debug)
- ast_log(LOG_DEBUG, "Got remote capabilities from connection %s\n", token);
-
- pvt = find_call_locked(call_reference, token);
- if (!pvt)
- return;
- pvt->peercapability = capabilities;
- pvt->jointcapability = pvt->options.capability & capabilities;
- if (prefs) {
- memcpy(&pvt->peer_prefs, prefs, sizeof(pvt->peer_prefs));
- if (h323debug) {
- int i;
- for (i = 0; i < 32; ++i) {
- if (!prefs->order[i])
- break;
- ast_log(LOG_DEBUG, "prefs[%d]=%s:%d\n", i, (prefs->order[i] ? ast_getformatname(1 << (prefs->order[i]-1)) : "<none>"), prefs->framing[i]);
- }
- }
- if (pvt->rtp)
- ast_rtp_codec_setpref(pvt->rtp, &pvt->peer_prefs);
- }
- ast_mutex_unlock(&pvt->lock);
-}
-
-static void set_local_capabilities(unsigned call_reference, const char *token)
-{
- struct oh323_pvt *pvt;
- int capability, dtmfmode, pref_codec;
- struct ast_codec_pref prefs;
-
- if (h323debug)
- ast_log(LOG_DEBUG, "Setting capabilities for connection %s\n", token);
-
- pvt = find_call_locked(call_reference, token);
- if (!pvt)
- return;
- capability = (pvt->jointcapability) ? pvt->jointcapability : pvt->options.capability;
- dtmfmode = pvt->options.dtmfmode;
- prefs = pvt->options.prefs;
- pref_codec = pvt->pref_codec;
- ast_mutex_unlock(&pvt->lock);
- h323_set_capabilities(token, capability, dtmfmode, &prefs, pref_codec);
-
- if (h323debug)
- ast_log(LOG_DEBUG, "Capabilities for connection %s is set\n", token);
-}
-
-static void *do_monitor(void *data)
-{
- int res;
- int reloading;
- struct oh323_pvt *oh323 = NULL;
-
- for(;;) {
- /* Check for a reload request */
- ast_mutex_lock(&h323_reload_lock);
- reloading = h323_reloading;
- h323_reloading = 0;
- ast_mutex_unlock(&h323_reload_lock);
- if (reloading) {
- if (option_verbose > 0) {
- ast_verbose(VERBOSE_PREFIX_1 "Reloading H.323\n");
- }
- h323_do_reload();
- }
- /* Check for interfaces needing to be killed */
- if (!ast_mutex_trylock(&iflock)) {
-#if 1
- do {
- for (oh323 = iflist; oh323; oh323 = oh323->next) {
- if (!ast_mutex_trylock(&oh323->lock)) {
- if (oh323->needdestroy) {
- __oh323_destroy(oh323);
- break;
- }
- ast_mutex_unlock(&oh323->lock);
- }
- }
- } while (/*oh323*/ 0);
-#else
-restartsearch:
- oh323 = iflist;
- while(oh323) {
- if (!ast_mutex_trylock(&oh323->lock)) {
- if (oh323->needdestroy) {
- __oh323_destroy(oh323);
- goto restartsearch;
- }
- ast_mutex_unlock(&oh323->lock);
- oh323 = oh323->next;
- }
- }
-#endif
- ast_mutex_unlock(&iflock);
- } else
- oh323 = (struct oh323_pvt *)1; /* Force fast loop */
- pthread_testcancel();
- /* Wait for sched or io */
- res = ast_sched_wait(sched);
- if ((res < 0) || (res > 1000)) {
- res = 1000;
- }
- /* Do not wait if some channel(s) is destroyed, probably, more available too */
- if (oh323)
- res = 1;
- res = ast_io_wait(io, res);
- pthread_testcancel();
- ast_mutex_lock(&monlock);
- if (res >= 0) {
- ast_sched_runq(sched);
- }
- ast_mutex_unlock(&monlock);
- }
- /* Never reached */
- return NULL;
-}
-
-static int restart_monitor(void)
-{
- /* If we're supposed to be stopped -- stay stopped */
- if (ast_mutex_lock(&monlock)) {
- ast_log(LOG_WARNING, "Unable to lock monitor\n");
- return -1;
- }
- if (monitor_thread == AST_PTHREADT_STOP) {
- ast_mutex_unlock(&monlock);
- return 0;
- }
- if (monitor_thread == pthread_self()) {
- ast_mutex_unlock(&monlock);
- ast_log(LOG_WARNING, "Cannot kill myself\n");
- return -1;
- }
- if (monitor_thread && (monitor_thread != AST_PTHREADT_NULL)) {
- /* Wake up the thread */
- pthread_kill(monitor_thread, SIGURG);
- } else {
- /* Start a new monitor */
- if (ast_pthread_create_background(&monitor_thread, NULL, do_monitor, NULL) < 0) {
- monitor_thread = AST_PTHREADT_NULL;
- ast_mutex_unlock(&monlock);
- ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
- return -1;
- }
- }
- ast_mutex_unlock(&monlock);
- return 0;
-}
-
-static int h323_do_trace(int fd, int argc, char *argv[])
-{
- if (argc != 4) {
- return RESULT_SHOWUSAGE;
- }
- h323_debug(1, atoi(argv[3]));
- ast_cli(fd, "H.323 trace set to level %s\n", argv[2]);
- return RESULT_SUCCESS;
-}
-
-static int h323_no_trace(int fd, int argc, char *argv[])
-{
- if (argc < 3 || argc > 4) {
- return RESULT_SHOWUSAGE;
- }
- h323_debug(0,0);
- ast_cli(fd, "H.323 trace disabled\n");
- return RESULT_SUCCESS;
-}
-
-static int h323_do_debug(int fd, int argc, char *argv[])
-{
- if (argc < 2 || argc > 3) {
- return RESULT_SHOWUSAGE;
- }
- h323debug = 1;
- ast_cli(fd, "H.323 debug enabled\n");
- return RESULT_SUCCESS;
-}
-
-static int h323_no_debug(int fd, int argc, char *argv[])
-{
- if (argc < 3 || argc > 4) {
- return RESULT_SHOWUSAGE;
- }
- h323debug = 0;
- ast_cli(fd, "H.323 debug disabled\n");
- return RESULT_SUCCESS;
-}
-
-static int h323_gk_cycle(int fd, int argc, char *argv[])
-{
- if (argc != 3) {
- return RESULT_SHOWUSAGE;
- }
- h323_gk_urq();
-
- /* Possibly register with a GK */
- if (!gatekeeper_disable) {
- if (h323_set_gk(gatekeeper_discover, gatekeeper, secret)) {
- ast_log(LOG_ERROR, "Gatekeeper registration failed.\n");
- }
- }
- return RESULT_SUCCESS;
-}
-
-static int h323_ep_hangup(int fd, int argc, char *argv[])
-{
- if (argc != 3) {
- return RESULT_SHOWUSAGE;
- }
- if (h323_soft_hangup(argv[2])) {
- ast_verbose(VERBOSE_PREFIX_3 "Hangup succeeded on %s\n", argv[2]);
- } else {
- ast_verbose(VERBOSE_PREFIX_3 "Hangup failed for %s\n", argv[2]);
- }
- return RESULT_SUCCESS;
-}
-
-static int h323_tokens_show(int fd, int argc, char *argv[])
-{
- if (argc != 3) {
- return RESULT_SHOWUSAGE;
- }
- h323_show_tokens();
- return RESULT_SUCCESS;
-}
-
-static char trace_usage[] =
-"Usage: h.323 trace <level num>\n"
-" Enables H.323 stack tracing for debugging purposes\n";
-
-static char no_trace_usage[] =
-"Usage: h.323 trace off\n"
-" Disables H.323 stack tracing for debugging purposes\n";
-
-static char debug_usage[] =
-"Usage: h.323 debug\n"
-" Enables H.323 debug output\n";
-
-static char no_debug_usage[] =
-"Usage: h.323 debug off\n"
-" Disables H.323 debug output\n";
-
-static char show_cycle_usage[] =
-"Usage: h.323 gk cycle\n"
-" Manually re-register with the Gatekeper (Currently Disabled)\n";
-
-static char show_hangup_usage[] =
-"Usage: h.323 hangup <token>\n"
-" Manually try to hang up call identified by <token>\n";
-
-static char show_tokens_usage[] =
-"Usage: h.323 show tokens\n"
-" Print out all active call tokens\n";
-
-static char h323_reload_usage[] =
-"Usage: h323 reload\n"
-" Reloads H.323 configuration from h323.conf\n";
-
-static struct ast_cli_entry cli_h323_no_trace_deprecated = {
- { "h.323", "no", "trace", NULL },
- h323_no_trace, "Disable H.323 Stack Tracing",
- no_trace_usage };
-
-static struct ast_cli_entry cli_h323_no_debug_deprecated = {
- { "h.323", "no", "debug", NULL },
- h323_no_debug, "Disable H.323 debug",
- no_debug_usage };
-
-static struct ast_cli_entry cli_h323_debug_deprecated = {
- { "h.323", "debug", NULL },
- h323_do_debug, "Enable H.323 debug",
- debug_usage };
-
-static struct ast_cli_entry cli_h323_trace_deprecated = {
- { "h.323", "trace", NULL },
- h323_do_trace, "Enable H.323 Stack Tracing",
- trace_usage };
-
-static struct ast_cli_entry cli_h323_gk_cycle_deprecated = {
- { "h.323", "gk", "cycle", NULL },
- h323_gk_cycle, "Manually re-register with the Gatekeper",
- show_cycle_usage };
-
-static struct ast_cli_entry cli_h323[] = {
- { { "h323", "set", "trace", NULL },
- h323_do_trace, "Enable H.323 Stack Tracing",
- trace_usage, NULL, &cli_h323_trace_deprecated },
-
- { { "h323", "set", "trace", "off", NULL },
- h323_no_trace, "Disable H.323 Stack Tracing",
- no_trace_usage, NULL, &cli_h323_no_trace_deprecated },
-
- { { "h323", "set", "debug", NULL },
- h323_do_debug, "Enable H.323 debug",
- debug_usage, NULL, &cli_h323_debug_deprecated },
-
- { { "h323", "set", "debug", "off", NULL },
- h323_no_debug, "Disable H.323 debug",
- no_debug_usage, NULL, &cli_h323_no_debug_deprecated },
-
- { { "h323", "cycle", "gk", NULL },
- h323_gk_cycle, "Manually re-register with the Gatekeper",
- show_cycle_usage, NULL, &cli_h323_gk_cycle_deprecated },
-
- { { "h323", "hangup", NULL },
- h323_ep_hangup, "Manually try to hang up a call",
- show_hangup_usage },
-
- { { "h323", "show", "tokens", NULL },
- h323_tokens_show, "Show all active call tokens",
- show_tokens_usage },
-};
-
-static void delete_users(void)
-{
- int pruned = 0;
-
- /* Delete all users */
- ASTOBJ_CONTAINER_WRLOCK(&userl);
- ASTOBJ_CONTAINER_TRAVERSE(&userl, 1, do {
- ASTOBJ_RDLOCK(iterator);
- ASTOBJ_MARK(iterator);
- ++pruned;
- ASTOBJ_UNLOCK(iterator);
- } while (0) );
- if (pruned) {
- ASTOBJ_CONTAINER_PRUNE_MARKED(&userl, oh323_destroy_user);
- }
- ASTOBJ_CONTAINER_UNLOCK(&userl);
-
- ASTOBJ_CONTAINER_WRLOCK(&peerl);
- ASTOBJ_CONTAINER_TRAVERSE(&peerl, 1, do {
- ASTOBJ_RDLOCK(iterator);
- ASTOBJ_MARK(iterator);
- ASTOBJ_UNLOCK(iterator);
- } while (0) );
- ASTOBJ_CONTAINER_UNLOCK(&peerl);
-}
-
-static void delete_aliases(void)
-{
- int pruned = 0;
-
- /* Delete all aliases */
- ASTOBJ_CONTAINER_WRLOCK(&aliasl);
- ASTOBJ_CONTAINER_TRAVERSE(&aliasl, 1, do {
- ASTOBJ_RDLOCK(iterator);
- ASTOBJ_MARK(iterator);
- ++pruned;
- ASTOBJ_UNLOCK(iterator);
- } while (0) );
- if (pruned) {
- ASTOBJ_CONTAINER_PRUNE_MARKED(&aliasl, oh323_destroy_alias);
- }
- ASTOBJ_CONTAINER_UNLOCK(&aliasl);
-}
-
-static void prune_peers(void)
-{
- /* Prune peers who still are supposed to be deleted */
- ASTOBJ_CONTAINER_PRUNE_MARKED(&peerl, oh323_destroy_peer);
-}
-
-static int reload_config(int is_reload)
-{
- int format;
- struct ast_config *cfg, *ucfg;
- struct ast_variable *v;
- struct oh323_peer *peer = NULL;
- struct oh323_user *user = NULL;
- struct oh323_alias *alias = NULL;
- struct ast_hostent ahp; struct hostent *hp;
- char *cat;
- const char *utype;
- int is_user, is_peer, is_alias;
- char _gatekeeper[100];
- int gk_discover, gk_disable, gk_changed;
-
- cfg = ast_config_load(config);
-
- /* We *must* have a config file otherwise stop immediately */
- if (!cfg) {
- ast_log(LOG_NOTICE, "Unable to load config %s, H.323 disabled\n", config);
- return 1;
- }
-
- if (is_reload) {
- delete_users();
- delete_aliases();
- prune_peers();
- }
-
- /* fire up the H.323 Endpoint */
- if (!h323_end_point_exist()) {
- h323_end_point_create();
- }
- ast_copy_string(_gatekeeper, gatekeeper, sizeof(_gatekeeper));
- gk_discover = gatekeeper_discover;
- gk_disable = gatekeeper_disable;
- memset(&bindaddr, 0, sizeof(bindaddr));
- memset(&global_options, 0, sizeof(global_options));
- global_options.fastStart = 1;
- global_options.h245Tunneling = 1;
- global_options.dtmfcodec = 101;
- global_options.dtmfmode = H323_DTMF_RFC2833;
- global_options.capability = GLOBAL_CAPABILITY;
- global_options.bridge = 1; /* Do native bridging by default */
- strcpy(default_context, "default");
- h323_signalling_port = 1720;
- gatekeeper_disable = 1;
- gatekeeper_discover = 0;
- gkroute = 0;
- userbyalias = 1;
- acceptAnonymous = 1;
- tos = 0;
-
- /* Copy the default jb config over global_jbconf */
- memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
-
- /* Load configuration from users.conf */
- ucfg = ast_config_load("users.conf");
- if (ucfg) {
- struct ast_variable *gen;
- int genhas_h323;
- const char *has_h323;
-
- genhas_h323 = ast_true(ast_variable_retrieve(ucfg, "general", "hash323"));
- gen = ast_variable_browse(ucfg, "general");
- for (cat = ast_category_browse(ucfg, NULL); cat; cat = ast_category_browse(ucfg, cat)) {
- if (strcasecmp(cat, "general")) {
- has_h323 = ast_variable_retrieve(ucfg, cat, "hash323");
- if (ast_true(has_h323) || (!has_h323 && genhas_h323)) {
- user = build_user(cat, gen, ast_variable_browse(ucfg, cat), 0);
- if (user) {
- ASTOBJ_CONTAINER_LINK(&userl, user);
- ASTOBJ_UNREF(user, oh323_destroy_user);
- }
- peer = build_peer(cat, gen, ast_variable_browse(ucfg, cat), 0);
- if (peer) {
- ASTOBJ_CONTAINER_LINK(&peerl, peer);
- ASTOBJ_UNREF(peer, oh323_destroy_peer);
- }
- }
- }
- }
- ast_config_destroy(ucfg);
- }
-
- for (v = ast_variable_browse(cfg, "general"); v; v = v->next) {
- /* handle jb conf */
- if (!ast_jb_read_conf(&global_jbconf, v->name, v->value))
- continue;
- /* Create the interface list */
- if (!strcasecmp(v->name, "port")) {
- h323_signalling_port = (int)strtol(v->value, NULL, 10);
- } else if (!strcasecmp(v->name, "bindaddr")) {
- if (!(hp = ast_gethostbyname(v->value, &ahp))) {
- ast_log(LOG_WARNING, "Invalid address: %s\n", v->value);
- } else {
- memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr));
- }
- } else if (!strcasecmp(v->name, "tos")) {
- if (sscanf(v->value, "%d", &format)) {
- tos = format & 0xff;
- } else if (!strcasecmp(v->value, "lowdelay")) {
- tos = IPTOS_LOWDELAY;
- } else if (!strcasecmp(v->value, "throughput")) {
- tos = IPTOS_THROUGHPUT;
- } else if (!strcasecmp(v->value, "reliability")) {
- tos = IPTOS_RELIABILITY;
- } else if (!strcasecmp(v->value, "mincost")) {
- tos = IPTOS_MINCOST;
- } else if (!strcasecmp(v->value, "none")) {
- tos = 0;
- } else {
- ast_log(LOG_WARNING, "Invalid tos value at line %d, should be 'lowdelay', 'throughput', 'reliability', 'mincost', or 'none'\n", v->lineno);
- }
- } else if (!strcasecmp(v->name, "gatekeeper")) {
- if (!strcasecmp(v->value, "DISABLE")) {
- gatekeeper_disable = 1;
- } else if (!strcasecmp(v->value, "DISCOVER")) {
- gatekeeper_disable = 0;
- gatekeeper_discover = 1;
- } else {
- gatekeeper_disable = 0;
- ast_copy_string(gatekeeper, v->value, sizeof(gatekeeper));
- }
- } else if (!strcasecmp(v->name, "secret")) {
- ast_copy_string(secret, v->value, sizeof(secret));
- } else if (!strcasecmp(v->name, "AllowGKRouted")) {
- gkroute = ast_true(v->value);
- } else if (!strcasecmp(v->name, "context")) {
- ast_copy_string(default_context, v->value, sizeof(default_context));
- ast_verbose(VERBOSE_PREFIX_2 "Setting default context to %s\n", default_context);
- } else if (!strcasecmp(v->name, "UserByAlias")) {
- userbyalias = ast_true(v->value);
- } else if (!strcasecmp(v->name, "AcceptAnonymous")) {
- acceptAnonymous = ast_true(v->value);
- } else if (!update_common_options(v, &global_options)) {
- /* dummy */
- }
- }
-
- for (cat = ast_category_browse(cfg, NULL); cat; cat = ast_category_browse(cfg, cat)) {
- if (strcasecmp(cat, "general")) {
- utype = ast_variable_retrieve(cfg, cat, "type");
- if (utype) {
- is_user = is_peer = is_alias = 0;
- if (!strcasecmp(utype, "user"))
- is_user = 1;
- else if (!strcasecmp(utype, "peer"))
- is_peer = 1;
- else if (!strcasecmp(utype, "friend"))
- is_user = is_peer = 1;
- else if (!strcasecmp(utype, "h323") || !strcasecmp(utype, "alias"))
- is_alias = 1;
- else {
- ast_log(LOG_WARNING, "Unknown type '%s' for '%s' in %s\n", utype, cat, config);
- continue;
- }
- if (is_user) {
- user = build_user(cat, ast_variable_browse(cfg, cat), NULL, 0);
- if (user) {
- ASTOBJ_CONTAINER_LINK(&userl, user);
- ASTOBJ_UNREF(user, oh323_destroy_user);
- }
- }
- if (is_peer) {
- peer = build_peer(cat, ast_variable_browse(cfg, cat), NULL, 0);
- if (peer) {
- ASTOBJ_CONTAINER_LINK(&peerl, peer);
- ASTOBJ_UNREF(peer, oh323_destroy_peer);
- }
- }
- if (is_alias) {
- alias = build_alias(cat, ast_variable_browse(cfg, cat), NULL, 0);
- if (alias) {
- ASTOBJ_CONTAINER_LINK(&aliasl, alias);
- ASTOBJ_UNREF(alias, oh323_destroy_alias);
- }
- }
- } else {
- ast_log(LOG_WARNING, "Section '%s' lacks type\n", cat);
- }
- }
- }
- ast_config_destroy(cfg);
-
- /* Register our H.323 aliases if any*/
- ASTOBJ_CONTAINER_WRLOCK(&aliasl);
- ASTOBJ_CONTAINER_TRAVERSE(&aliasl, 1, do {
- ASTOBJ_RDLOCK(iterator);
- if (h323_set_alias(iterator)) {
- ast_log(LOG_ERROR, "Alias %s rejected by endpoint\n", alias->name);
- ASTOBJ_UNLOCK(iterator);
- continue;
- }
- ASTOBJ_UNLOCK(iterator);
- } while (0) );
- ASTOBJ_CONTAINER_UNLOCK(&aliasl);
-
- /* Don't touch GK if nothing changed because URQ will drop all existing calls */
- gk_changed = 0;
- if (gatekeeper_disable != gk_disable)
- gk_changed = is_reload;
- else if(!gatekeeper_disable && (gatekeeper_discover != gk_discover))
- gk_changed = is_reload;
- else if(!gatekeeper_disable && (strncmp(_gatekeeper, gatekeeper, sizeof(_gatekeeper)) != 0))
- gk_changed = is_reload;
- if (gk_changed) {
- if(!gk_disable)
- h323_gk_urq();
- if (!gatekeeper_disable) {
- if (h323_set_gk(gatekeeper_discover, gatekeeper, secret)) {
- ast_log(LOG_ERROR, "Gatekeeper registration failed.\n");
- gatekeeper_disable = 1;
- }
- }
- }
- return 0;
-}
-
-static int h323_reload(int fd, int argc, char *argv[])
-{
- ast_mutex_lock(&h323_reload_lock);
- if (h323_reloading) {
- ast_verbose("Previous H.323 reload not yet done\n");
- } else {
- h323_reloading = 1;
- }
- ast_mutex_unlock(&h323_reload_lock);
- restart_monitor();
- return 0;
-}
-
-static int h323_do_reload(void)
-{
- reload_config(1);
- return 0;
-}
-
-static int reload(void)
-{
- if (!sched || !io) {
- ast_log(LOG_NOTICE, "Unload and load chan_h323.so again in order to receive configuration changes.\n");
- return 0;
- }
- return h323_reload(0, 0, NULL);
-}
-
-static struct ast_cli_entry cli_h323_reload =
- { { "h.323", "reload", NULL },
- h323_reload, "Reload H.323 configuration",
- h323_reload_usage
-};
-
-static enum ast_rtp_get_result oh323_get_rtp_peer(struct ast_channel *chan, struct ast_rtp **rtp)
-{
- struct oh323_pvt *pvt;
- enum ast_rtp_get_result res = AST_RTP_GET_FAILED;
-
- if (!(pvt = (struct oh323_pvt *)chan->tech_pvt))
- return res;
-
- ast_mutex_lock(&pvt->lock);
- if (pvt->rtp && pvt->options.bridge) {
- *rtp = pvt->rtp;
- res = AST_RTP_TRY_NATIVE;
- }
- ast_mutex_unlock(&pvt->lock);
-
- return res;
-}
-
-static enum ast_rtp_get_result oh323_get_vrtp_peer(struct ast_channel *chan, struct ast_rtp **rtp)
-{
- return AST_RTP_GET_FAILED;
-}
-
-static char *convertcap(int cap)
-{
- switch (cap) {
- case AST_FORMAT_G723_1:
- return "G.723";
- case AST_FORMAT_GSM:
- return "GSM";
- case AST_FORMAT_ULAW:
- return "ULAW";
- case AST_FORMAT_ALAW:
- return "ALAW";
- case AST_FORMAT_G722:
- return "G.722";
- case AST_FORMAT_ADPCM:
- return "G.728";
- case AST_FORMAT_G729A:
- return "G.729";
- case AST_FORMAT_SPEEX:
- return "SPEEX";
- case AST_FORMAT_ILBC:
- return "ILBC";
- default:
- ast_log(LOG_NOTICE, "Don't know how to deal with mode %d\n", cap);
- return NULL;
- }
-}
-
-static int oh323_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs, int nat_active)
-{
- /* XXX Deal with Video */
- struct oh323_pvt *pvt;
- struct sockaddr_in them;
- struct sockaddr_in us;
- char *mode;
-
- if (!rtp) {
- return 0;
- }
-
- mode = convertcap(chan->writeformat);
- pvt = (struct oh323_pvt *) chan->tech_pvt;
- if (!pvt) {
- ast_log(LOG_ERROR, "No Private Structure, this is bad\n");
- return -1;
- }
- ast_rtp_get_peer(rtp, &them);
- ast_rtp_get_us(rtp, &us);
-#if 0 /* Native bridge still isn't ready */
- h323_native_bridge(pvt->cd.call_token, ast_inet_ntoa(them.sin_addr), mode);
-#endif
- return 0;
-}
-
-static struct ast_rtp_protocol oh323_rtp = {
- .type = "H323",
- .get_rtp_info = oh323_get_rtp_peer,
- .get_vrtp_info = oh323_get_vrtp_peer,
- .set_rtp_peer = oh323_set_rtp_peer,
-};
-
-static enum ast_module_load_result load_module(void)
-{
- int res;
-
- h323debug = 0;
- sched = sched_context_create();
- if (!sched) {
- ast_log(LOG_WARNING, "Unable to create schedule context\n");
- return AST_MODULE_LOAD_FAILURE;
- }
- io = io_context_create();
- if (!io) {
- ast_log(LOG_WARNING, "Unable to create I/O context\n");
- return AST_MODULE_LOAD_FAILURE;
- }
- ast_cli_register(&cli_h323_reload);
- ASTOBJ_CONTAINER_INIT(&userl);
- ASTOBJ_CONTAINER_INIT(&peerl);
- ASTOBJ_CONTAINER_INIT(&aliasl);
- res = reload_config(0);
- if (res) {
- /* No config entry */
- ast_log(LOG_NOTICE, "Unload and load chan_h323.so again in order to receive configuration changes.\n");
- ast_cli_unregister(&cli_h323_reload);
- io_context_destroy(io);
- io = NULL;
- sched_context_destroy(sched);
- sched = NULL;
- ASTOBJ_CONTAINER_DESTROY(&userl);
- ASTOBJ_CONTAINER_DESTROY(&peerl);
- ASTOBJ_CONTAINER_DESTROY(&aliasl);
- return AST_MODULE_LOAD_DECLINE;
- } else {
- /* Make sure we can register our channel type */
- if (ast_channel_register(&oh323_tech)) {
- ast_log(LOG_ERROR, "Unable to register channel class 'H323'\n");
- ast_cli_unregister(&cli_h323_reload);
- h323_end_process();
- io_context_destroy(io);
- sched_context_destroy(sched);
-
- ASTOBJ_CONTAINER_DESTROYALL(&userl, oh323_destroy_user);
- ASTOBJ_CONTAINER_DESTROY(&userl);
- ASTOBJ_CONTAINER_DESTROYALL(&peerl, oh323_destroy_peer);
- ASTOBJ_CONTAINER_DESTROY(&peerl);
- ASTOBJ_CONTAINER_DESTROYALL(&aliasl, oh323_destroy_alias);
- ASTOBJ_CONTAINER_DESTROY(&aliasl);
-
- return AST_MODULE_LOAD_FAILURE;
- }
- ast_cli_register_multiple(cli_h323, sizeof(cli_h323) / sizeof(struct ast_cli_entry));
-
- ast_rtp_proto_register(&oh323_rtp);
-
- /* Register our callback functions */
- h323_callback_register(setup_incoming_call,
- setup_outgoing_call,
- external_rtp_create,
- setup_rtp_connection,
- cleanup_connection,
- chan_ringing,
- connection_made,
- receive_digit,
- answer_call,
- progress,
- set_dtmf_payload,
- hangup_connection,
- set_local_capabilities,
- set_peer_capabilities);
- /* start the h.323 listener */
- if (h323_start_listener(h323_signalling_port, bindaddr)) {
- ast_log(LOG_ERROR, "Unable to create H323 listener.\n");
- ast_rtp_proto_unregister(&oh323_rtp);
- ast_cli_unregister_multiple(cli_h323, sizeof(cli_h323) / sizeof(struct ast_cli_entry));
- ast_cli_unregister(&cli_h323_reload);
- h323_end_process();
- io_context_destroy(io);
- sched_context_destroy(sched);
-
- ASTOBJ_CONTAINER_DESTROYALL(&userl, oh323_destroy_user);
- ASTOBJ_CONTAINER_DESTROY(&userl);
- ASTOBJ_CONTAINER_DESTROYALL(&peerl, oh323_destroy_peer);
- ASTOBJ_CONTAINER_DESTROY(&peerl);
- ASTOBJ_CONTAINER_DESTROYALL(&aliasl, oh323_destroy_alias);
- ASTOBJ_CONTAINER_DESTROY(&aliasl);
-
- return AST_MODULE_LOAD_FAILURE;
- }
- /* Possibly register with a GK */
- if (!gatekeeper_disable) {
- if (h323_set_gk(gatekeeper_discover, gatekeeper, secret)) {
- ast_log(LOG_ERROR, "Gatekeeper registration failed.\n");
- gatekeeper_disable = 1;
- res = AST_MODULE_LOAD_SUCCESS;
- }
- }
- /* And start the monitor for the first time */
- restart_monitor();
- }
- return res;
-}
-
-static int unload_module(void)
-{
- struct oh323_pvt *p, *pl;
-
- /* unregister commands */
- ast_cli_unregister_multiple(cli_h323, sizeof(cli_h323) / sizeof(struct ast_cli_entry));
- ast_cli_unregister(&cli_h323_reload);
-
- ast_channel_unregister(&oh323_tech);
- ast_rtp_proto_unregister(&oh323_rtp);
-
- if (!ast_mutex_lock(&iflock)) {
- /* hangup all interfaces if they have an owner */
- p = iflist;
- while(p) {
- if (p->owner) {
- ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
- }
- p = p->next;
- }
- iflist = NULL;
- ast_mutex_unlock(&iflock);
- } else {
- ast_log(LOG_WARNING, "Unable to lock the interface list\n");
- return -1;
- }
- if (!ast_mutex_lock(&monlock)) {
- if ((monitor_thread != AST_PTHREADT_STOP) && (monitor_thread != AST_PTHREADT_NULL)) {
- if (monitor_thread != pthread_self()) {
- pthread_cancel(monitor_thread);
- }
- pthread_kill(monitor_thread, SIGURG);
- pthread_join(monitor_thread, NULL);
- }
- monitor_thread = AST_PTHREADT_STOP;
- ast_mutex_unlock(&monlock);
- } else {
- ast_log(LOG_WARNING, "Unable to lock the monitor\n");
- return -1;
- }
- if (!ast_mutex_lock(&iflock)) {
- /* destroy all the interfaces and free their memory */
- p = iflist;
- while(p) {
- pl = p;
- p = p->next;
- /* free associated memory */
- ast_mutex_destroy(&pl->lock);
- free(pl);
- }
- iflist = NULL;
- ast_mutex_unlock(&iflock);
- } else {
- ast_log(LOG_WARNING, "Unable to lock the interface list\n");
- return -1;
- }
- if (!gatekeeper_disable)
- h323_gk_urq();
- h323_end_process();
- if (io)
- io_context_destroy(io);
- if (sched)
- sched_context_destroy(sched);
-
- ASTOBJ_CONTAINER_DESTROYALL(&userl, oh323_destroy_user);
- ASTOBJ_CONTAINER_DESTROY(&userl);
- ASTOBJ_CONTAINER_DESTROYALL(&peerl, oh323_destroy_peer);
- ASTOBJ_CONTAINER_DESTROY(&peerl);
- ASTOBJ_CONTAINER_DESTROYALL(&aliasl, oh323_destroy_alias);
- ASTOBJ_CONTAINER_DESTROY(&aliasl);
-
- return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "The NuFone Network's OpenH323 Channel Driver",
- .load = load_module,
- .unload = unload_module,
- .reload = reload,
-);
diff --git a/1.4.23-rc4/channels/chan_iax2.c b/1.4.23-rc4/channels/chan_iax2.c
deleted file mode 100644
index d03f47c6c..000000000
--- a/1.4.23-rc4/channels/chan_iax2.c
+++ /dev/null
@@ -1,11336 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 1999 - 2006, Digium, Inc.
- *
- * Mark Spencer <markster@digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Implementation of Inter-Asterisk eXchange Version 2
- *
- * \author Mark Spencer <markster@digium.com>
- *
- * \par See also
- * \arg \ref Config_iax
- *
- * \ingroup channel_drivers
- */
-
-/*** MODULEINFO
- <use>dahdi</use>
- <depend>res_features</depend>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/mman.h>
-#include <dirent.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netinet/in_systm.h>
-#include <netinet/ip.h>
-#include <sys/time.h>
-#include <sys/signal.h>
-#include <signal.h>
-#include <string.h>
-#include <strings.h>
-#include <errno.h>
-#include <unistd.h>
-#include <netdb.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <regex.h>
-
-#if defined(HAVE_ZAPTEL) || defined (HAVE_DAHDI)
-#include <sys/ioctl.h>
-#include "asterisk/dahdi_compat.h"
-#endif
-
-#include "asterisk/lock.h"
-#include "asterisk/frame.h"
-#include "asterisk/channel.h"
-#include "asterisk/logger.h"
-#include "asterisk/module.h"
-#include "asterisk/pbx.h"
-#include "asterisk/sched.h"
-#include "asterisk/io.h"
-#include "asterisk/config.h"
-#include "asterisk/options.h"
-#include "asterisk/cli.h"
-#include "asterisk/translate.h"
-#include "asterisk/md5.h"
-#include "asterisk/cdr.h"
-#include "asterisk/crypto.h"
-#include "asterisk/acl.h"
-#include "asterisk/manager.h"
-#include "asterisk/callerid.h"
-#include "asterisk/app.h"
-#include "asterisk/astdb.h"
-#include "asterisk/musiconhold.h"
-#include "asterisk/features.h"
-#include "asterisk/utils.h"
-#include "asterisk/causes.h"
-#include "asterisk/localtime.h"
-#include "asterisk/aes.h"
-#include "asterisk/dnsmgr.h"
-#include "asterisk/devicestate.h"
-#include "asterisk/netsock.h"
-#include "asterisk/stringfields.h"
-#include "asterisk/linkedlists.h"
-#include "asterisk/astobj2.h"
-
-#include "iax2.h"
-#include "iax2-parser.h"
-#include "iax2-provision.h"
-#include "jitterbuf.h"
-
-/* Define SCHED_MULTITHREADED to run the scheduler in a special
- multithreaded mode. */
-#define SCHED_MULTITHREADED
-
-/* Define DEBUG_SCHED_MULTITHREADED to keep track of where each
- thread is actually doing. */
-#define DEBUG_SCHED_MULTITHREAD
-
-#ifndef IPTOS_MINCOST
-#define IPTOS_MINCOST 0x02
-#endif
-
-#ifdef SO_NO_CHECK
-static int nochecksums = 0;
-#endif
-
-
-#define PTR_TO_CALLNO(a) ((unsigned short)(unsigned long)(a))
-#define CALLNO_TO_PTR(a) ((void *)(unsigned long)(a))
-
-#define DEFAULT_THREAD_COUNT 10
-#define DEFAULT_MAX_THREAD_COUNT 100
-#define DEFAULT_RETRY_TIME 1000
-#define MEMORY_SIZE 100
-#define DEFAULT_DROP 3
-
-#define DEBUG_SUPPORT
-
-#define MIN_REUSE_TIME 60 /* Don't reuse a call number within 60 seconds */
-
-/* Sample over last 100 units to determine historic jitter */
-#define GAMMA (0.01)
-
-static struct ast_codec_pref prefs;
-
-static const char tdesc[] = "Inter Asterisk eXchange Driver (Ver 2)";
-
-static char context[80] = "default";
-
-static char language[MAX_LANGUAGE] = "";
-static char regcontext[AST_MAX_CONTEXT] = "";
-
-static int maxauthreq = 3;
-static int max_retries = 4;
-static int ping_time = 21;
-static int lagrq_time = 10;
-static int maxjitterbuffer=1000;
-static int resyncthreshold=1000;
-static int maxjitterinterps=10;
-static int trunkfreq = 20;
-static int authdebug = 1;
-static int autokill = 0;
-static int iaxcompat = 0;
-static int last_authmethod = 0;
-
-static int iaxdefaultdpcache=10 * 60; /* Cache dialplan entries for 10 minutes by default */
-
-static int iaxdefaulttimeout = 5; /* Default to wait no more than 5 seconds for a reply to come back */
-
-static unsigned int tos = 0;
-
-static int min_reg_expire;
-static int max_reg_expire;
-
-static int timingfd = -1; /* Timing file descriptor */
-
-static struct ast_netsock_list *netsock;
-static struct ast_netsock_list *outsock; /*!< used if sourceaddress specified and bindaddr == INADDR_ANY */
-static int defaultsockfd = -1;
-
-int (*iax2_regfunk)(const char *username, int onoff) = NULL;
-
-/* Ethernet, etc */
-#define IAX_CAPABILITY_FULLBANDWIDTH 0xFFFF
-/* T1, maybe ISDN */
-#define IAX_CAPABILITY_MEDBANDWIDTH (IAX_CAPABILITY_FULLBANDWIDTH & \
- ~AST_FORMAT_SLINEAR & \
- ~AST_FORMAT_ULAW & \
- ~AST_FORMAT_ALAW & \
- ~AST_FORMAT_G722)
-/* A modem */
-#define IAX_CAPABILITY_LOWBANDWIDTH (IAX_CAPABILITY_MEDBANDWIDTH & \
- ~AST_FORMAT_G726 & \
- ~AST_FORMAT_G726_AAL2 & \
- ~AST_FORMAT_ADPCM)
-
-#define IAX_CAPABILITY_LOWFREE (IAX_CAPABILITY_LOWBANDWIDTH & \
- ~AST_FORMAT_G723_1)
-
-
-#define DEFAULT_MAXMS 2000 /* Must be faster than 2 seconds by default */
-#define DEFAULT_FREQ_OK 60 * 1000 /* How often to check for the host to be up */
-#define DEFAULT_FREQ_NOTOK 10 * 1000 /* How often to check, if the host is down... */
-
-static struct io_context *io;
-static struct sched_context *sched;
-
-static int iax2_capability = IAX_CAPABILITY_FULLBANDWIDTH;
-
-static int iaxdebug = 0;
-
-static int iaxtrunkdebug = 0;
-
-static int test_losspct = 0;
-#ifdef IAXTESTS
-static int test_late = 0;
-static int test_resync = 0;
-static int test_jit = 0;
-static int test_jitpct = 0;
-#endif /* IAXTESTS */
-
-static char accountcode[AST_MAX_ACCOUNT_CODE];
-static char mohinterpret[MAX_MUSICCLASS];
-static char mohsuggest[MAX_MUSICCLASS];
-static int amaflags = 0;
-static int adsi = 0;
-static int delayreject = 0;
-static int iax2_encryption = 0;
-
-static struct ast_flags globalflags = { 0 };
-
-static pthread_t netthreadid = AST_PTHREADT_NULL;
-static pthread_t schedthreadid = AST_PTHREADT_NULL;
-AST_MUTEX_DEFINE_STATIC(sched_lock);
-static ast_cond_t sched_cond;
-
-enum {
- IAX_STATE_STARTED = (1 << 0),
- IAX_STATE_AUTHENTICATED = (1 << 1),
- IAX_STATE_TBD = (1 << 2),
- IAX_STATE_UNCHANGED = (1 << 3),
-} iax2_state;
-
-struct iax2_context {
- char context[AST_MAX_CONTEXT];
- struct iax2_context *next;
-};
-
-enum {
- IAX_HASCALLERID = (1 << 0), /*!< CallerID has been specified */
- IAX_DELME = (1 << 1), /*!< Needs to be deleted */
- IAX_TEMPONLY = (1 << 2), /*!< Temporary (realtime) */
- IAX_TRUNK = (1 << 3), /*!< Treat as a trunk */
- IAX_NOTRANSFER = (1 << 4), /*!< Don't native bridge */
- IAX_USEJITTERBUF = (1 << 5), /*!< Use jitter buffer */
- IAX_DYNAMIC = (1 << 6), /*!< dynamic peer */
- IAX_SENDANI = (1 << 7), /*!< Send ANI along with CallerID */
- /* (1 << 8) is currently unused due to the deprecation of an old option. Go ahead, take it! */
- IAX_ALREADYGONE = (1 << 9), /*!< Already disconnected */
- IAX_PROVISION = (1 << 10), /*!< This is a provisioning request */
- IAX_QUELCH = (1 << 11), /*!< Whether or not we quelch audio */
- IAX_ENCRYPTED = (1 << 12), /*!< Whether we should assume encrypted tx/rx */
- IAX_KEYPOPULATED = (1 << 13), /*!< Whether we have a key populated */
- IAX_CODEC_USER_FIRST = (1 << 14), /*!< are we willing to let the other guy choose the codec? */
- IAX_CODEC_NOPREFS = (1 << 15), /*!< Force old behaviour by turning off prefs */
- IAX_CODEC_NOCAP = (1 << 16), /*!< only consider requested format and ignore capabilities*/
- IAX_RTCACHEFRIENDS = (1 << 17), /*!< let realtime stay till your reload */
- IAX_RTUPDATE = (1 << 18), /*!< Send a realtime update */
- IAX_RTAUTOCLEAR = (1 << 19), /*!< erase me on expire */
- IAX_FORCEJITTERBUF = (1 << 20), /*!< Force jitterbuffer, even when bridged to a channel that can take jitter */
- IAX_RTIGNOREREGEXPIRE = (1 << 21), /*!< When using realtime, ignore registration expiration */
- IAX_TRUNKTIMESTAMPS = (1 << 22), /*!< Send trunk timestamps */
- IAX_TRANSFERMEDIA = (1 << 23), /*!< When doing IAX2 transfers, transfer media only */
- IAX_MAXAUTHREQ = (1 << 24), /*!< Maximum outstanding AUTHREQ restriction is in place */
- IAX_DELAYPBXSTART = (1 << 25), /*!< Don't start a PBX on the channel until the peer sends us a
- response, so that we've achieved a three-way handshake with
- them before sending voice or anything else*/
- IAX_ALLOWFWDOWNLOAD = (1 << 26), /*!< Allow the FWDOWNL command? */
-} iax2_flags;
-
-static int global_rtautoclear = 120;
-
-static int reload_config(void);
-static int iax2_reload(int fd, int argc, char *argv[]);
-
-
-struct iax2_user {
- AST_DECLARE_STRING_FIELDS(
- AST_STRING_FIELD(name);
- AST_STRING_FIELD(secret);
- AST_STRING_FIELD(dbsecret);
- AST_STRING_FIELD(accountcode);
- AST_STRING_FIELD(mohinterpret);
- AST_STRING_FIELD(mohsuggest);
- AST_STRING_FIELD(inkeys); /*!< Key(s) this user can use to authenticate to us */
- AST_STRING_FIELD(language);
- AST_STRING_FIELD(cid_num);
- AST_STRING_FIELD(cid_name);
- );
-
- int authmethods;
- int encmethods;
- int amaflags;
- int adsi;
- unsigned int flags;
- int capability;
- int maxauthreq; /*!< Maximum allowed outstanding AUTHREQs */
- int curauthreq; /*!< Current number of outstanding AUTHREQs */
- struct ast_codec_pref prefs;
- struct ast_ha *ha;
- struct iax2_context *contexts;
- struct ast_variable *vars;
-};
-
-struct iax2_peer {
- AST_DECLARE_STRING_FIELDS(
- AST_STRING_FIELD(name);
- AST_STRING_FIELD(username);
- AST_STRING_FIELD(secret);
- AST_STRING_FIELD(dbsecret);
- AST_STRING_FIELD(outkey); /*!< What key we use to talk to this peer */
-
- AST_STRING_FIELD(regexten); /*!< Extension to register (if regcontext is used) */
- AST_STRING_FIELD(context); /*!< For transfers only */
- AST_STRING_FIELD(peercontext); /*!< Context to pass to peer */
- AST_STRING_FIELD(mailbox); /*!< Mailbox */
- AST_STRING_FIELD(mohinterpret);
- AST_STRING_FIELD(mohsuggest);
- AST_STRING_FIELD(inkeys); /*!< Key(s) this peer can use to authenticate to us */
- /* Suggested caller id if registering */
- AST_STRING_FIELD(cid_num); /*!< Default context (for transfer really) */
- AST_STRING_FIELD(cid_name); /*!< Default context (for transfer really) */
- AST_STRING_FIELD(zonetag); /*!< Time Zone */
- );
- struct ast_codec_pref prefs;
- struct ast_dnsmgr_entry *dnsmgr; /*!< DNS refresh manager */
- struct sockaddr_in addr;
- int formats;
- int sockfd; /*!< Socket to use for transmission */
- struct in_addr mask;
- int adsi;
- unsigned int flags;
-
- /* Dynamic Registration fields */
- struct sockaddr_in defaddr; /*!< Default address if there is one */
- int authmethods; /*!< Authentication methods (IAX_AUTH_*) */
- int encmethods; /*!< Encryption methods (IAX_ENCRYPT_*) */
-
- int expire; /*!< Schedule entry for expiry */
- int expiry; /*!< How soon to expire */
- int capability; /*!< Capability */
-
- /* Qualification */
- int callno; /*!< Call number of POKE request */
- int pokeexpire; /*!< Scheduled qualification-related task (ie iax2_poke_peer_s or iax2_poke_noanswer) */
- int lastms; /*!< How long last response took (in ms), or -1 for no response */
- int maxms; /*!< Max ms we will accept for the host to be up, 0 to not monitor */
-
- int pokefreqok; /*!< How often to check if the host is up */
- int pokefreqnotok; /*!< How often to check when the host has been determined to be down */
- int historicms; /*!< How long recent average responses took */
- int smoothing; /*!< Sample over how many units to determine historic ms */
-
- struct ast_ha *ha;
-};
-
-#define IAX2_TRUNK_PREFACE (sizeof(struct iax_frame) + sizeof(struct ast_iax2_meta_hdr) + sizeof(struct ast_iax2_meta_trunk_hdr))
-
-static struct iax2_trunk_peer {
- ast_mutex_t lock;
- int sockfd;
- struct sockaddr_in addr;
- struct timeval txtrunktime; /*!< Transmit trunktime */
- struct timeval rxtrunktime; /*!< Receive trunktime */
- struct timeval lasttxtime; /*!< Last transmitted trunktime */
- struct timeval trunkact; /*!< Last trunk activity */
- unsigned int lastsent; /*!< Last sent time */
- /* Trunk data and length */
- unsigned char *trunkdata;
- unsigned int trunkdatalen;
- unsigned int trunkdataalloc;
- struct iax2_trunk_peer *next;
- int trunkerror;
- int calls;
-} *tpeers = NULL;
-
-AST_MUTEX_DEFINE_STATIC(tpeerlock);
-
-struct iax_firmware {
- struct iax_firmware *next;
- int fd;
- int mmaplen;
- int dead;
- struct ast_iax2_firmware_header *fwh;
- unsigned char *buf;
-};
-
-enum iax_reg_state {
- REG_STATE_UNREGISTERED = 0,
- REG_STATE_REGSENT,
- REG_STATE_AUTHSENT,
- REG_STATE_REGISTERED,
- REG_STATE_REJECTED,
- REG_STATE_TIMEOUT,
- REG_STATE_NOAUTH
-};
-
-enum iax_transfer_state {
- TRANSFER_NONE = 0,
- TRANSFER_BEGIN,
- TRANSFER_READY,
- TRANSFER_RELEASED,
- TRANSFER_PASSTHROUGH,
- TRANSFER_MBEGIN,
- TRANSFER_MREADY,
- TRANSFER_MRELEASED,
- TRANSFER_MPASSTHROUGH,
- TRANSFER_MEDIA,
- TRANSFER_MEDIAPASS
-};
-
-struct iax2_registry {
- struct sockaddr_in addr; /*!< Who we connect to for registration purposes */
- char username[80];
- char secret[80]; /*!< Password or key name in []'s */
- char random[80];
- int expire; /*!< Sched ID of expiration */
- int refresh; /*!< How often to refresh */
- enum iax_reg_state regstate;
- int messages; /*!< Message count, low 8 bits = new, high 8 bits = old */
- int callno; /*!< Associated call number if applicable */
- struct sockaddr_in us; /*!< Who the server thinks we are */
- struct ast_dnsmgr_entry *dnsmgr; /*!< DNS refresh manager */
- AST_LIST_ENTRY(iax2_registry) entry;
-};
-
-static AST_LIST_HEAD_STATIC(registrations, iax2_registry);
-
-/* Don't retry more frequently than every 10 ms, or less frequently than every 5 seconds */
-#define MIN_RETRY_TIME 100
-#define MAX_RETRY_TIME 10000
-
-#define MAX_JITTER_BUFFER 50
-#define MIN_JITTER_BUFFER 10
-
-#define DEFAULT_TRUNKDATA 640 * 10 /*!< 40ms, uncompressed linear * 10 channels */
-#define MAX_TRUNKDATA 640 * 200 /*!< 40ms, uncompressed linear * 200 channels */
-
-#define MAX_TIMESTAMP_SKEW 160 /*!< maximum difference between actual and predicted ts for sending */
-
-/* If consecutive voice frame timestamps jump by more than this many milliseconds, then jitter buffer will resync */
-#define TS_GAP_FOR_JB_RESYNC 5000
-
-static int iaxthreadcount = DEFAULT_THREAD_COUNT;
-static int iaxmaxthreadcount = DEFAULT_MAX_THREAD_COUNT;
-static int iaxdynamicthreadcount = 0;
-static int iaxdynamicthreadnum = 0;
-static int iaxactivethreadcount = 0;
-
-struct iax_rr {
- int jitter;
- int losspct;
- int losscnt;
- int packets;
- int delay;
- int dropped;
- int ooo;
-};
-
-struct chan_iax2_pvt {
- /*! Socket to send/receive on for this call */
- int sockfd;
- /*! Last received voice format */
- int voiceformat;
- /*! Last received video format */
- int videoformat;
- /*! Last sent voice format */
- int svoiceformat;
- /*! Last sent video format */
- int svideoformat;
- /*! What we are capable of sending */
- int capability;
- /*! Last received timestamp */
- unsigned int last;
- /*! Last sent timestamp - never send the same timestamp twice in a single call */
- unsigned int lastsent;
- /*! Timestamp of the last video frame sent */
- unsigned int lastvsent;
- /*! Next outgoing timestamp if everything is good */
- unsigned int nextpred;
- /*! True if the last voice we transmitted was not silence/CNG */
- int notsilenttx;
- /*! Ping time */
- unsigned int pingtime;
- /*! Max time for initial response */
- int maxtime;
- /*! Peer Address */
- struct sockaddr_in addr;
- /*! Actual used codec preferences */
- struct ast_codec_pref prefs;
- /*! Requested codec preferences */
- struct ast_codec_pref rprefs;
- /*! Our call number */
- unsigned short callno;
- /*! Peer callno */
- unsigned short peercallno;
- /*! Negotiated format, this is only used to remember what format was
- chosen for an unauthenticated call so that the channel can get
- created later using the right format */
- int chosenformat;
- /*! Peer selected format */
- int peerformat;
- /*! Peer capability */
- int peercapability;
- /*! timeval that we base our transmission on */
- struct timeval offset;
- /*! timeval that we base our delivery on */
- struct timeval rxcore;
- /*! The jitterbuffer */
- jitterbuf *jb;
- /*! active jb read scheduler id */
- int jbid;
- /*! LAG */
- int lag;
- /*! Error, as discovered by the manager */
- int error;
- /*! Owner if we have one */
- struct ast_channel *owner;
- /*! What's our state? */
- struct ast_flags state;
- /*! Expiry (optional) */
- int expiry;
- /*! Next outgoing sequence number */
- unsigned char oseqno;
- /*! Next sequence number they have not yet acknowledged */
- unsigned char rseqno;
- /*! Next incoming sequence number */
- unsigned char iseqno;
- /*! Last incoming sequence number we have acknowledged */
- unsigned char aseqno;
-
- AST_DECLARE_STRING_FIELDS(
- /*! Peer name */
- AST_STRING_FIELD(peer);
- /*! Default Context */
- AST_STRING_FIELD(context);
- /*! Caller ID if available */
- AST_STRING_FIELD(cid_num);
- AST_STRING_FIELD(cid_name);
- /*! Hidden Caller ID (i.e. ANI) if appropriate */
- AST_STRING_FIELD(ani);
- /*! DNID */
- AST_STRING_FIELD(dnid);
- /*! RDNIS */
- AST_STRING_FIELD(rdnis);
- /*! Requested Extension */
- AST_STRING_FIELD(exten);
- /*! Expected Username */
- AST_STRING_FIELD(username);
- /*! Expected Secret */
- AST_STRING_FIELD(secret);
- /*! MD5 challenge */
- AST_STRING_FIELD(challenge);
- /*! Public keys permitted keys for incoming authentication */
- AST_STRING_FIELD(inkeys);
- /*! Private key for outgoing authentication */
- AST_STRING_FIELD(outkey);
- /*! Preferred language */
- AST_STRING_FIELD(language);
- /*! Hostname/peername for naming purposes */
- AST_STRING_FIELD(host);
-
- AST_STRING_FIELD(dproot);
- AST_STRING_FIELD(accountcode);
- AST_STRING_FIELD(mohinterpret);
- AST_STRING_FIELD(mohsuggest);
- );
-
- /*! permitted authentication methods */
- int authmethods;
- /*! permitted encryption methods */
- int encmethods;
- /*! Encryption AES-128 Key */
- aes_encrypt_ctx ecx;
- /*! Decryption AES-128 Key */
- aes_decrypt_ctx dcx;
- /*! 32 bytes of semi-random data */
- unsigned char semirand[32];
- /*! Associated registry */
- struct iax2_registry *reg;
- /*! Associated peer for poking */
- struct iax2_peer *peerpoke;
- /*! IAX_ flags */
- unsigned int flags;
- int adsi;
-
- /*! Transferring status */
- enum iax_transfer_state transferring;
- /*! Transfer identifier */
- int transferid;
- /*! Who we are IAX transfering to */
- struct sockaddr_in transfer;
- /*! What's the new call number for the transfer */
- unsigned short transfercallno;
- /*! Transfer decrypt AES-128 Key */
- aes_encrypt_ctx tdcx;
-
- /*! Status of knowledge of peer ADSI capability */
- int peeradsicpe;
-
- /*! Who we are bridged to */
- unsigned short bridgecallno;
-
- int pingid; /*!< Transmit PING request */
- int lagid; /*!< Retransmit lag request */
- int autoid; /*!< Auto hangup for Dialplan requestor */
- int authid; /*!< Authentication rejection ID */
- int authfail; /*!< Reason to report failure */
- int initid; /*!< Initial peer auto-congest ID (based on qualified peers) */
- int calling_ton;
- int calling_tns;
- int calling_pres;
- int amaflags;
- struct iax2_dpcache *dpentries;
- struct ast_variable *vars;
- /*! last received remote rr */
- struct iax_rr remote_rr;
- /*! Current base time: (just for stats) */
- int min;
- /*! Dropped frame count: (just for stats) */
- int frames_dropped;
- /*! received frame count: (just for stats) */
- int frames_received;
-};
-
-static struct ast_iax2_queue {
- AST_LIST_HEAD(, iax_frame) queue;
- int count;
-} iaxq;
-
-/*!
- * This module will get much higher performance when doing a lot of
- * user and peer lookups if the number of buckets is increased from 1.
- * However, to maintain old behavior for Asterisk 1.4, these are set to
- * 1 by default. When using multiple buckets, search order through these
- * containers is considered random, so you will not be able to depend on
- * the order the entires are specified in iax.conf for matching order. */
-#ifdef LOW_MEMORY
-#define MAX_PEER_BUCKETS 1
-/* #define MAX_PEER_BUCKETS 17 */
-#else
-#define MAX_PEER_BUCKETS 1
-/* #define MAX_PEER_BUCKETS 563 */
-#endif
-static struct ao2_container *peers;
-
-#define MAX_USER_BUCKETS MAX_PEER_BUCKETS
-static struct ao2_container *users;
-
-static struct ast_firmware_list {
- struct iax_firmware *wares;
- ast_mutex_t lock;
-} waresl;
-
-/*! Extension exists */
-#define CACHE_FLAG_EXISTS (1 << 0)
-/*! Extension is nonexistent */
-#define CACHE_FLAG_NONEXISTENT (1 << 1)
-/*! Extension can exist */
-#define CACHE_FLAG_CANEXIST (1 << 2)
-/*! Waiting to hear back response */
-#define CACHE_FLAG_PENDING (1 << 3)
-/*! Timed out */
-#define CACHE_FLAG_TIMEOUT (1 << 4)
-/*! Request transmitted */
-#define CACHE_FLAG_TRANSMITTED (1 << 5)
-/*! Timeout */
-#define CACHE_FLAG_UNKNOWN (1 << 6)
-/*! Matchmore */
-#define CACHE_FLAG_MATCHMORE (1 << 7)
-
-static struct iax2_dpcache {
- char peercontext[AST_MAX_CONTEXT];
- char exten[AST_MAX_EXTENSION];
- struct timeval orig;
- struct timeval expiry;
- int flags;
- unsigned short callno;
- int waiters[256];
- struct iax2_dpcache *next;
- struct iax2_dpcache *peer; /*!< For linking in peers */
-} *dpcache;
-
-AST_MUTEX_DEFINE_STATIC(dpcache_lock);
-
-static void reg_source_db(struct iax2_peer *p);
-static struct iax2_peer *realtime_peer(const char *peername, struct sockaddr_in *sin);
-
-static int ast_cli_netstats(struct mansession *s, int fd, int limit_fmt);
-
-#define IAX_IOSTATE_IDLE 0
-#define IAX_IOSTATE_READY 1
-#define IAX_IOSTATE_PROCESSING 2
-#define IAX_IOSTATE_SCHEDREADY 3
-
-#define IAX_TYPE_POOL 1
-#define IAX_TYPE_DYNAMIC 2
-
-struct iax2_pkt_buf {
- AST_LIST_ENTRY(iax2_pkt_buf) entry;
- size_t len;
- unsigned char buf[1];
-};
-
-struct iax2_thread {
- AST_LIST_ENTRY(iax2_thread) list;
- int type;
- int iostate;
-#ifdef SCHED_MULTITHREADED
- void (*schedfunc)(const void *);
- const void *scheddata;
-#endif
-#ifdef DEBUG_SCHED_MULTITHREAD
- char curfunc[80];
-#endif
- int actions;
- pthread_t threadid;
- int threadnum;
- struct sockaddr_in iosin;
- unsigned char readbuf[4096];
- unsigned char *buf;
- ssize_t buf_len;
- size_t buf_size;
- int iofd;
- time_t checktime;
- ast_mutex_t lock;
- ast_cond_t cond;
- unsigned int ready_for_signal:1;
- /*! if this thread is processing a full frame,
- some information about that frame will be stored
- here, so we can avoid dispatching any more full
- frames for that callno to other threads */
- struct {
- unsigned short callno;
- struct sockaddr_in sin;
- unsigned char type;
- unsigned char csub;
- } ffinfo;
- /*! Queued up full frames for processing. If more full frames arrive for
- * a call which this thread is already processing a full frame for, they
- * are queued up here. */
- AST_LIST_HEAD_NOLOCK(, iax2_pkt_buf) full_frames;
-};
-
-/* Thread lists */
-static AST_LIST_HEAD_STATIC(idle_list, iax2_thread);
-static AST_LIST_HEAD_STATIC(active_list, iax2_thread);
-static AST_LIST_HEAD_STATIC(dynamic_list, iax2_thread);
-
-static void *iax2_process_thread(void *data);
-
-static void signal_condition(ast_mutex_t *lock, ast_cond_t *cond)
-{
- ast_mutex_lock(lock);
- ast_cond_signal(cond);
- ast_mutex_unlock(lock);
-}
-
-static void iax_debug_output(const char *data)
-{
- if (iaxdebug)
- ast_verbose("%s", data);
-}
-
-static void iax_error_output(const char *data)
-{
- ast_log(LOG_WARNING, "%s", data);
-}
-
-static void __attribute__((format(printf, 1, 2))) jb_error_output(const char *fmt, ...)
-{
- va_list args;
- char buf[1024];
-
- va_start(args, fmt);
- vsnprintf(buf, 1024, fmt, args);
- va_end(args);
-
- ast_log(LOG_ERROR, "%s", buf);
-}
-
-static void __attribute__((format(printf, 1, 2))) jb_warning_output(const char *fmt, ...)
-{
- va_list args;
- char buf[1024];
-
- va_start(args, fmt);
- vsnprintf(buf, 1024, fmt, args);
- va_end(args);
-
- ast_log(LOG_WARNING, "%s", buf);
-}
-
-static void __attribute__((format(printf, 1, 2))) jb_debug_output(const char *fmt, ...)
-{
- va_list args;
- char buf[1024];
-
- va_start(args, fmt);
- vsnprintf(buf, 1024, fmt, args);
- va_end(args);
-
- ast_verbose("%s", buf);
-}
-
-/* XXX We probably should use a mutex when working with this XXX */
-static struct chan_iax2_pvt *iaxs[IAX_MAX_CALLS];
-static ast_mutex_t iaxsl[ARRAY_LEN(iaxs)];
-static struct timeval lastused[ARRAY_LEN(iaxs)];
-
-/*!
- * \brief Another container of iax2_pvt structures
- *
- * Active IAX2 pvt structs are also stored in this container, if they are a part
- * of an active call where we know the remote side's call number. The reason
- * for this is that incoming media frames do not contain our call number. So,
- * instead of having to iterate the entire iaxs array, we use this container to
- * look up calls where the remote side is using a given call number.
- */
-static struct ao2_container *iax_peercallno_pvts;
-
-/* Flag to use with trunk calls, keeping these calls high up. It halves our effective use
- but keeps the division between trunked and non-trunked better. */
-#define TRUNK_CALL_START ARRAY_LEN(iaxs) / 2
-
-static int maxtrunkcall = TRUNK_CALL_START;
-static int maxnontrunkcall = 1;
-
-static enum ast_bridge_result iax2_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms);
-static int expire_registry(const void *data);
-static int iax2_answer(struct ast_channel *c);
-static int iax2_call(struct ast_channel *c, char *dest, int timeout);
-static int iax2_devicestate(void *data);
-static int iax2_digit_begin(struct ast_channel *c, char digit);
-static int iax2_digit_end(struct ast_channel *c, char digit, unsigned int duration);
-static int iax2_do_register(struct iax2_registry *reg);
-static int iax2_fixup(struct ast_channel *oldchannel, struct ast_channel *newchan);
-static int iax2_hangup(struct ast_channel *c);
-static int iax2_indicate(struct ast_channel *c, int condition, const void *data, size_t datalen);
-static int iax2_poke_peer(struct iax2_peer *peer, int heldcall);
-static int iax2_provision(struct sockaddr_in *end, int sockfd, char *dest, const char *template, int force);
-static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned int ts, int seqno, int now, int transfer, int final);
-static int iax2_sendhtml(struct ast_channel *c, int subclass, const char *data, int datalen);
-static int iax2_sendimage(struct ast_channel *c, struct ast_frame *img);
-static int iax2_sendtext(struct ast_channel *c, const char *text);
-static int iax2_setoption(struct ast_channel *c, int option, void *data, int datalen);
-static int iax2_transfer(struct ast_channel *c, const char *dest);
-static int iax2_write(struct ast_channel *c, struct ast_frame *f);
-static int send_command(struct chan_iax2_pvt *, char, int, unsigned int, const unsigned char *, int, int);
-static int send_command_final(struct chan_iax2_pvt *, char, int, unsigned int, const unsigned char *, int, int);
-static int send_command_immediate(struct chan_iax2_pvt *, char, int, unsigned int, const unsigned char *, int, int);
-static int send_command_locked(unsigned short callno, char, int, unsigned int, const unsigned char *, int, int);
-static int send_command_transfer(struct chan_iax2_pvt *, char, int, unsigned int, const unsigned char *, int);
-static struct ast_channel *iax2_request(const char *type, int format, void *data, int *cause);
-static struct ast_frame *iax2_read(struct ast_channel *c);
-static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, struct ast_variable *alt, int temponly);
-static struct iax2_user *build_user(const char *name, struct ast_variable *v, struct ast_variable *alt, int temponly);
-static void realtime_update_peer(const char *peername, struct sockaddr_in *sin, time_t regtime);
-static void prune_peers(void);
-
-static const struct ast_channel_tech iax2_tech = {
- .type = "IAX2",
- .description = tdesc,
- .capabilities = IAX_CAPABILITY_FULLBANDWIDTH,
- .properties = AST_CHAN_TP_WANTSJITTER,
- .requester = iax2_request,
- .devicestate = iax2_devicestate,
- .send_digit_begin = iax2_digit_begin,
- .send_digit_end = iax2_digit_end,
- .send_text = iax2_sendtext,
- .send_image = iax2_sendimage,
- .send_html = iax2_sendhtml,
- .call = iax2_call,
- .hangup = iax2_hangup,
- .answer = iax2_answer,
- .read = iax2_read,
- .write = iax2_write,
- .write_video = iax2_write,
- .indicate = iax2_indicate,
- .setoption = iax2_setoption,
- .bridge = iax2_bridge,
- .transfer = iax2_transfer,
- .fixup = iax2_fixup,
-};
-
-/* WARNING: insert_idle_thread should only ever be called within the
- * context of an iax2_process_thread() thread.
- */
-static void insert_idle_thread(struct iax2_thread *thread)
-{
- if (thread->type == IAX_TYPE_DYNAMIC) {
- AST_LIST_LOCK(&dynamic_list);
- AST_LIST_INSERT_TAIL(&dynamic_list, thread, list);
- AST_LIST_UNLOCK(&dynamic_list);
- } else {
- AST_LIST_LOCK(&idle_list);
- AST_LIST_INSERT_TAIL(&idle_list, thread, list);
- AST_LIST_UNLOCK(&idle_list);
- }
-
- return;
-}
-
-static struct iax2_thread *find_idle_thread(void)
-{
- pthread_attr_t attr;
- struct iax2_thread *thread = NULL;
-
- /* Pop the head of the list off */
- AST_LIST_LOCK(&idle_list);
- thread = AST_LIST_REMOVE_HEAD(&idle_list, list);
- AST_LIST_UNLOCK(&idle_list);
-
- /* If no idle thread is available from the regular list, try dynamic */
- if (thread == NULL) {
- AST_LIST_LOCK(&dynamic_list);
- thread = AST_LIST_REMOVE_HEAD(&dynamic_list, list);
- /* Make sure we absolutely have a thread... if not, try to make one if allowed */
- if (thread == NULL && iaxmaxthreadcount > iaxdynamicthreadcount) {
- /* We need to MAKE a thread! */
- if ((thread = ast_calloc(1, sizeof(*thread)))) {
- thread->threadnum = iaxdynamicthreadnum++;
- thread->type = IAX_TYPE_DYNAMIC;
- ast_mutex_init(&thread->lock);
- ast_cond_init(&thread->cond, NULL);
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- if (ast_pthread_create(&thread->threadid, &attr, iax2_process_thread, thread)) {
- free(thread);
- thread = NULL;
- } else {
- /* All went well and the thread is up, so increment our count */
- iaxdynamicthreadcount++;
-
- /* Wait for the thread to be ready before returning it to the caller */
- while (!thread->ready_for_signal)
- usleep(1);
- }
- }
- }
- AST_LIST_UNLOCK(&dynamic_list);
- }
-
- /* this thread is not processing a full frame (since it is idle),
- so ensure that the field for the full frame call number is empty */
- if (thread)
- memset(&thread->ffinfo, 0, sizeof(thread->ffinfo));
-
- return thread;
-}
-
-#ifdef SCHED_MULTITHREADED
-static int __schedule_action(void (*func)(const void *data), const void *data, const char *funcname)
-{
- struct iax2_thread *thread = NULL;
- static time_t lasterror;
- static time_t t;
-
- thread = find_idle_thread();
-
- if (thread != NULL) {
- thread->schedfunc = func;
- thread->scheddata = data;
- thread->iostate = IAX_IOSTATE_SCHEDREADY;
-#ifdef DEBUG_SCHED_MULTITHREAD
- ast_copy_string(thread->curfunc, funcname, sizeof(thread->curfunc));
-#endif
- signal_condition(&thread->lock, &thread->cond);
- return 0;
- }
- time(&t);
- if (t != lasterror && option_debug)
- ast_log(LOG_DEBUG, "Out of idle IAX2 threads for scheduling!\n");
- lasterror = t;
-
- return -1;
-}
-#define schedule_action(func, data) __schedule_action(func, data, __PRETTY_FUNCTION__)
-#endif
-
-static int iax2_sched_add(struct sched_context *con, int when, ast_sched_cb callback, const void *data)
-{
- int res;
-
- res = ast_sched_add(con, when, callback, data);
- signal_condition(&sched_lock, &sched_cond);
-
- return res;
-}
-
-static int send_ping(const void *data);
-
-static void __send_ping(const void *data)
-{
- int callno = (long) data;
-
- ast_mutex_lock(&iaxsl[callno]);
-
- if (iaxs[callno]) {
- if (iaxs[callno]->peercallno) {
- send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_PING, 0, NULL, 0, -1);
- iaxs[callno]->pingid = iax2_sched_add(sched, ping_time * 1000, send_ping, data);
- } else {
- /* I am the schedule, so I'm allowed to do this */
- iaxs[callno]->pingid = -1;
- }
- } else if (option_debug > 0) {
- ast_log(LOG_DEBUG, "I was supposed to send a PING with callno %d, but no such call exists (and I cannot remove pingid, either).\n", callno);
- }
-
- ast_mutex_unlock(&iaxsl[callno]);
-}
-
-static int send_ping(const void *data)
-{
-#ifdef SCHED_MULTITHREADED
- if (schedule_action(__send_ping, data))
-#endif
- __send_ping(data);
-
- return 0;
-}
-
-static int get_encrypt_methods(const char *s)
-{
- int e;
- if (!strcasecmp(s, "aes128"))
- e = IAX_ENCRYPT_AES128;
- else if (ast_true(s))
- e = IAX_ENCRYPT_AES128;
- else
- e = 0;
- return e;
-}
-
-static int send_lagrq(const void *data);
-
-static void __send_lagrq(const void *data)
-{
- int callno = (long) data;
-
- ast_mutex_lock(&iaxsl[callno]);
-
- if (iaxs[callno]) {
- if (iaxs[callno]->peercallno) {
- send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_LAGRQ, 0, NULL, 0, -1);
- iaxs[callno]->lagid = iax2_sched_add(sched, lagrq_time * 1000, send_lagrq, data);
- } else {
- /* I am the schedule, so I'm allowed to do this */
- iaxs[callno]->lagid = -1;
- }
- } else {
- ast_log(LOG_WARNING, "I was supposed to send a LAGRQ with callno %d, but no such call exists (and I cannot remove lagid, either).\n", callno);
- }
-
- ast_mutex_unlock(&iaxsl[callno]);
-}
-
-static int send_lagrq(const void *data)
-{
-#ifdef SCHED_MULTITHREADED
- if (schedule_action(__send_lagrq, data))
-#endif
- __send_lagrq(data);
-
- return 0;
-}
-
-static unsigned char compress_subclass(int subclass)
-{
- int x;
- int power=-1;
- /* If it's 128 or smaller, just return it */
- if (subclass < IAX_FLAG_SC_LOG)
- return subclass;
- /* Otherwise find its power */
- for (x = 0; x < IAX_MAX_SHIFT; x++) {
- if (subclass & (1 << x)) {
- if (power > -1) {
- ast_log(LOG_WARNING, "Can't compress subclass %d\n", subclass);
- return 0;
- } else
- power = x;
- }
- }
- return power | IAX_FLAG_SC_LOG;
-}
-
-static int uncompress_subclass(unsigned char csub)
-{
- /* If the SC_LOG flag is set, return 2^csub otherwise csub */
- if (csub & IAX_FLAG_SC_LOG) {
- /* special case for 'compressed' -1 */
- if (csub == 0xff)
- return -1;
- else
- return 1 << (csub & ~IAX_FLAG_SC_LOG & IAX_MAX_SHIFT);
- }
- else
- return csub;
-}
-
-/*!
- * \note The only member of the peer passed here guaranteed to be set is the name field
- */
-static int peer_hash_cb(const void *obj, const int flags)
-{
- const struct iax2_peer *peer = obj;
-
- return ast_str_hash(peer->name);
-}
-
-/*!
- * \note The only member of the peer passed here guaranteed to be set is the name field
- */
-static int peer_cmp_cb(void *obj, void *arg, int flags)
-{
- struct iax2_peer *peer = obj, *peer2 = arg;
-
- return !strcmp(peer->name, peer2->name) ? CMP_MATCH | CMP_STOP : 0;
-}
-
-/*!
- * \note The only member of the user passed here guaranteed to be set is the name field
- */
-static int user_hash_cb(const void *obj, const int flags)
-{
- const struct iax2_user *user = obj;
-
- return ast_str_hash(user->name);
-}
-
-/*!
- * \note The only member of the user passed here guaranteed to be set is the name field
- */
-static int user_cmp_cb(void *obj, void *arg, int flags)
-{
- struct iax2_user *user = obj, *user2 = arg;
-
- return !strcmp(user->name, user2->name) ? CMP_MATCH | CMP_STOP : 0;
-}
-
-/*!
- * \note This funtion calls realtime_peer -> reg_source_db -> iax2_poke_peer -> find_callno,
- * so do not call it with a pvt lock held.
- */
-static struct iax2_peer *find_peer(const char *name, int realtime)
-{
- struct iax2_peer *peer = NULL;
- struct iax2_peer tmp_peer = {
- .name = name,
- };
-
- peer = ao2_find(peers, &tmp_peer, OBJ_POINTER);
-
- /* Now go for realtime if applicable */
- if(!peer && realtime)
- peer = realtime_peer(name, NULL);
-
- return peer;
-}
-
-static struct iax2_peer *peer_ref(struct iax2_peer *peer)
-{
- ao2_ref(peer, +1);
- return peer;
-}
-
-static inline struct iax2_peer *peer_unref(struct iax2_peer *peer)
-{
- ao2_ref(peer, -1);
- return NULL;
-}
-
-static inline struct iax2_user *user_ref(struct iax2_user *user)
-{
- ao2_ref(user, +1);
- return user;
-}
-
-static inline struct iax2_user *user_unref(struct iax2_user *user)
-{
- ao2_ref(user, -1);
- return NULL;
-}
-
-static int iax2_getpeername(struct sockaddr_in sin, char *host, int len)
-{
- struct iax2_peer *peer = NULL;
- int res = 0;
- struct ao2_iterator i;
-
- i = ao2_iterator_init(peers, 0);
- while ((peer = ao2_iterator_next(&i))) {
- if ((peer->addr.sin_addr.s_addr == sin.sin_addr.s_addr) &&
- (peer->addr.sin_port == sin.sin_port)) {
- ast_copy_string(host, peer->name, len);
- peer_unref(peer);
- res = 1;
- break;
- }
- peer_unref(peer);
- }
-
- if (!peer) {
- peer = realtime_peer(NULL, &sin);
- if (peer) {
- ast_copy_string(host, peer->name, len);
- peer_unref(peer);
- res = 1;
- }
- }
-
- return res;
-}
-
-static void iax2_destroy_helper(struct chan_iax2_pvt *pvt)
-{
- /* Decrement AUTHREQ count if needed */
- if (ast_test_flag(pvt, IAX_MAXAUTHREQ)) {
- struct iax2_user *user;
- struct iax2_user tmp_user = {
- .name = pvt->username,
- };
-
- user = ao2_find(users, &tmp_user, OBJ_POINTER);
- if (user) {
- ast_atomic_fetchadd_int(&user->curauthreq, -1);
- user = user_unref(user);
- }
-
- ast_clear_flag(pvt, IAX_MAXAUTHREQ);
- }
-
- /* No more pings or lagrq's */
- AST_SCHED_DEL(sched, pvt->pingid);
- AST_SCHED_DEL(sched, pvt->lagid);
- AST_SCHED_DEL(sched, pvt->autoid);
- AST_SCHED_DEL(sched, pvt->authid);
- AST_SCHED_DEL(sched, pvt->initid);
- AST_SCHED_DEL(sched, pvt->jbid);
-}
-
-static void store_by_peercallno(struct chan_iax2_pvt *pvt)
-{
- if (!pvt->peercallno) {
- ast_log(LOG_ERROR, "This should not be called without a peer call number.\n");
- return;
- }
-
- ao2_link(iax_peercallno_pvts, pvt);
-}
-
-static void remove_by_peercallno(struct chan_iax2_pvt *pvt)
-{
- if (!pvt->peercallno) {
- ast_log(LOG_ERROR, "This should not be called without a peer call number.\n");
- return;
- }
-
- ao2_unlink(iax_peercallno_pvts, pvt);
-}
-
-static void update_max_trunk(void)
-{
- int max = TRUNK_CALL_START;
- int x;
-
- /* XXX Prolly don't need locks here XXX */
- for (x = TRUNK_CALL_START; x < ARRAY_LEN(iaxs) - 1; x++) {
- if (iaxs[x]) {
- max = x + 1;
- }
- }
-
- maxtrunkcall = max;
- if (option_debug && iaxdebug)
- ast_log(LOG_DEBUG, "New max trunk callno is %d\n", max);
-}
-
-static void iax2_frame_free(struct iax_frame *fr)
-{
- AST_SCHED_DEL(sched, fr->retrans);
- iax_frame_free(fr);
-}
-
-static void iax2_destroy(int callno)
-{
- struct chan_iax2_pvt *pvt;
- struct ast_channel *owner;
-
-retry:
- pvt = iaxs[callno];
- gettimeofday(&lastused[callno], NULL);
-
- owner = pvt ? pvt->owner : NULL;
-
- if (owner) {
- if (ast_mutex_trylock(&owner->lock)) {
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Avoiding IAX destroy deadlock\n");
- DEADLOCK_AVOIDANCE(&iaxsl[callno]);
- goto retry;
- }
- }
- if (!owner && iaxs[callno]) {
- AST_SCHED_DEL_SPINLOCK(sched, iaxs[callno]->lagid, &iaxsl[callno]);
- AST_SCHED_DEL_SPINLOCK(sched, iaxs[callno]->pingid, &iaxsl[callno]);
- iaxs[callno] = NULL;
- }
-
- if (pvt) {
- if (!owner) {
- pvt->owner = NULL;
- } else {
- /* If there's an owner, prod it to give up */
- /* It is ok to use ast_queue_hangup() here instead of iax2_queue_hangup()
- * because we already hold the owner channel lock. */
- ast_queue_hangup(owner);
- }
-
- if (pvt->peercallno) {
- remove_by_peercallno(pvt);
- }
-
- if (!owner) {
- ao2_ref(pvt, -1);
- pvt = NULL;
- }
- }
-
- if (owner) {
- ast_mutex_unlock(&owner->lock);
- }
-
- if (callno & 0x4000) {
- update_max_trunk();
- }
-}
-
-static int scheduled_destroy(const void *vid)
-{
- short callno = PTR_TO_CALLNO(vid);
- ast_mutex_lock(&iaxsl[callno]);
- if (iaxs[callno]) {
- if (option_debug) {
- ast_log(LOG_DEBUG, "Really destroying %d now...\n", callno);
- }
- iax2_destroy(callno);
- }
- ast_mutex_unlock(&iaxsl[callno]);
- return 0;
-}
-
-static void pvt_destructor(void *obj)
-{
- struct chan_iax2_pvt *pvt = obj;
- struct iax_frame *cur = NULL;
-
- iax2_destroy_helper(pvt);
-
- /* Already gone */
- ast_set_flag(pvt, IAX_ALREADYGONE);
-
- AST_LIST_LOCK(&iaxq.queue);
- AST_LIST_TRAVERSE(&iaxq.queue, cur, list) {
- /* Cancel any pending transmissions */
- if (cur->callno == pvt->callno) {
- cur->retries = -1;
- }
- }
- AST_LIST_UNLOCK(&iaxq.queue);
-
- if (pvt->reg) {
- pvt->reg->callno = 0;
- }
-
- if (!pvt->owner) {
- jb_frame frame;
- if (pvt->vars) {
- ast_variables_destroy(pvt->vars);
- pvt->vars = NULL;
- }
-
- while (jb_getall(pvt->jb, &frame) == JB_OK) {
- iax2_frame_free(frame.data);
- }
-
- jb_destroy(pvt->jb);
- ast_string_field_free_memory(pvt);
- }
-}
-
-static struct chan_iax2_pvt *new_iax(struct sockaddr_in *sin, const char *host)
-{
- struct chan_iax2_pvt *tmp;
- jb_conf jbconf;
-
- if (!(tmp = ao2_alloc(sizeof(*tmp), pvt_destructor))) {
- return NULL;
- }
-
- if (ast_string_field_init(tmp, 32)) {
- ao2_ref(tmp, -1);
- tmp = NULL;
- return NULL;
- }
-
- tmp->prefs = prefs;
- tmp->callno = 0;
- tmp->peercallno = 0;
- tmp->transfercallno = 0;
- tmp->bridgecallno = 0;
- tmp->pingid = -1;
- tmp->lagid = -1;
- tmp->autoid = -1;
- tmp->authid = -1;
- tmp->initid = -1;
-
- ast_string_field_set(tmp,exten, "s");
- ast_string_field_set(tmp,host, host);
-
- tmp->jb = jb_new();
- tmp->jbid = -1;
- jbconf.max_jitterbuf = maxjitterbuffer;
- jbconf.resync_threshold = resyncthreshold;
- jbconf.max_contig_interp = maxjitterinterps;
- jb_setconf(tmp->jb,&jbconf);
-
- return tmp;
-}
-
-static struct iax_frame *iaxfrdup2(struct iax_frame *fr)
-{
- struct iax_frame *new = iax_frame_new(DIRECTION_INGRESS, fr->af.datalen, fr->cacheable);
- if (new) {
- size_t afdatalen = new->afdatalen;
- memcpy(new, fr, sizeof(*new));
- iax_frame_wrap(new, &fr->af);
- new->afdatalen = afdatalen;
- new->data = NULL;
- new->datalen = 0;
- new->direction = DIRECTION_INGRESS;
- new->retrans = -1;
- }
- return new;
-}
-
-#define NEW_PREVENT 0
-#define NEW_ALLOW 1
-#define NEW_FORCE 2
-
-static int match(struct sockaddr_in *sin, unsigned short callno, unsigned short dcallno, struct chan_iax2_pvt *cur, int check_dcallno)
-{
- if ((cur->addr.sin_addr.s_addr == sin->sin_addr.s_addr) &&
- (cur->addr.sin_port == sin->sin_port)) {
- /* This is the main host */
- if ( (cur->peercallno == 0 || cur->peercallno == callno) &&
- (check_dcallno ? dcallno == cur->callno : 1) ) {
- /* That's us. Be sure we keep track of the peer call number */
- return 1;
- }
- }
- if ((cur->transfer.sin_addr.s_addr == sin->sin_addr.s_addr) &&
- (cur->transfer.sin_port == sin->sin_port) && (cur->transferring)) {
- /* We're transferring */
- if ((dcallno == cur->callno) || (cur->transferring == TRANSFER_MEDIAPASS && cur->transfercallno == callno))
- return 1;
- }
- return 0;
-}
-
-static void update_max_nontrunk(void)
-{
- int max = 1;
- int x;
- /* XXX Prolly don't need locks here XXX */
- for (x=1;x<TRUNK_CALL_START - 1; x++) {
- if (iaxs[x])
- max = x + 1;
- }
- maxnontrunkcall = max;
- if (option_debug && iaxdebug)
- ast_log(LOG_DEBUG, "New max nontrunk callno is %d\n", max);
-}
-
-static int make_trunk(unsigned short callno, int locked)
-{
- int x;
- int res= 0;
- struct timeval now;
- if (iaxs[callno]->oseqno) {
- ast_log(LOG_WARNING, "Can't make trunk once a call has started!\n");
- return -1;
- }
- if (callno & TRUNK_CALL_START) {
- ast_log(LOG_WARNING, "Call %d is already a trunk\n", callno);
- return -1;
- }
- gettimeofday(&now, NULL);
- for (x = TRUNK_CALL_START; x < ARRAY_LEN(iaxs) - 1; x++) {
- ast_mutex_lock(&iaxsl[x]);
- if (!iaxs[x] && ((now.tv_sec - lastused[x].tv_sec) > MIN_REUSE_TIME)) {
- /* Update the two timers that should have been started */
- /*!
- * \note We delete these before switching the slot, because if
- * they fire in the meantime, they will generate a warning.
- */
- AST_SCHED_DEL(sched, iaxs[callno]->pingid);
- AST_SCHED_DEL(sched, iaxs[callno]->lagid);
- iaxs[x] = iaxs[callno];
- iaxs[x]->callno = x;
- iaxs[callno] = NULL;
- iaxs[x]->pingid = iax2_sched_add(sched, ping_time * 1000, send_ping, (void *)(long)x);
- iaxs[x]->lagid = iax2_sched_add(sched, lagrq_time * 1000, send_lagrq, (void *)(long)x);
- if (locked)
- ast_mutex_unlock(&iaxsl[callno]);
- res = x;
- if (!locked)
- ast_mutex_unlock(&iaxsl[x]);
- break;
- }
- ast_mutex_unlock(&iaxsl[x]);
- }
- if (x >= ARRAY_LEN(iaxs) - 1) {
- ast_log(LOG_WARNING, "Unable to trunk call: Insufficient space\n");
- return -1;
- }
- if (option_debug)
- ast_log(LOG_DEBUG, "Made call %d into trunk call %d\n", callno, x);
- /* We move this call from a non-trunked to a trunked call */
- update_max_trunk();
- update_max_nontrunk();
- return res;
-}
-
-/*!
- * \note Calling this function while holding another pvt lock can cause a deadlock.
- */
-static int __find_callno(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int sockfd, int return_locked, int check_dcallno)
-{
- int res = 0;
- int x;
- struct timeval now;
- char host[80];
-
- if (new <= NEW_ALLOW) {
- if (callno) {
- struct chan_iax2_pvt *pvt;
- struct chan_iax2_pvt tmp_pvt = {
- .callno = dcallno,
- .peercallno = callno,
- /* hack!! */
- .frames_received = check_dcallno,
- };
-
- memcpy(&tmp_pvt.addr, sin, sizeof(tmp_pvt.addr));
-
- if ((pvt = ao2_find(iax_peercallno_pvts, &tmp_pvt, OBJ_POINTER))) {
- if (return_locked) {
- ast_mutex_lock(&iaxsl[pvt->callno]);
- }
- res = pvt->callno;
- ao2_ref(pvt, -1);
- pvt = NULL;
- return res;
- }
- }
-
- /* This will occur on the first response to a message that we initiated,
- * such as a PING. */
- if (dcallno) {
- ast_mutex_lock(&iaxsl[dcallno]);
- }
- if (callno && dcallno && iaxs[dcallno] && !iaxs[dcallno]->peercallno && match(sin, callno, dcallno, iaxs[dcallno], check_dcallno)) {
- iaxs[dcallno]->peercallno = callno;
- res = dcallno;
- store_by_peercallno(iaxs[dcallno]);
- if (!res || !return_locked) {
- ast_mutex_unlock(&iaxsl[dcallno]);
- }
- return res;
- }
- if (dcallno) {
- ast_mutex_unlock(&iaxsl[dcallno]);
- }
-
-#ifdef IAX_OLD_FIND
- /* If we get here, we SHOULD NOT find a call structure for this
- callno; if we do, it means that there is a call structure that
- has a peer callno but did NOT get entered into the hash table,
- which is bad.
-
- If we find a call structure using this old, slow method, output a log
- message so we'll know about it. After a few months of leaving this in
- place, if we don't hear about people seeing these messages, we can
- remove this code for good.
- */
-
- for (x = 1; !res && x < maxnontrunkcall; x++) {
- ast_mutex_lock(&iaxsl[x]);
- if (iaxs[x]) {
- /* Look for an exact match */
- if (match(sin, callno, dcallno, iaxs[x], check_dcallno)) {
- res = x;
- }
- }
- if (!res || !return_locked)
- ast_mutex_unlock(&iaxsl[x]);
- }
-
- for (x = TRUNK_CALL_START; !res && x < maxtrunkcall; x++) {
- ast_mutex_lock(&iaxsl[x]);
- if (iaxs[x]) {
- /* Look for an exact match */
- if (match(sin, callno, dcallno, iaxs[x], check_dcallno)) {
- res = x;
- }
- }
- if (!res || !return_locked)
- ast_mutex_unlock(&iaxsl[x]);
- }
-
- if (res) {
- ast_log(LOG_WARNING, "Old call search code found call number %d that was not in hash table!\n", res);
- }
-#endif
- }
- if (!res && (new >= NEW_ALLOW)) {
- int start, found = 0;
-
- /* It may seem odd that we look through the peer list for a name for
- * this *incoming* call. Well, it is weird. However, users don't
- * have an IP address/port number that we can match against. So,
- * this is just checking for a peer that has that IP/port and
- * assuming that we have a user of the same name. This isn't always
- * correct, but it will be changed if needed after authentication. */
- if (!iax2_getpeername(*sin, host, sizeof(host)))
- snprintf(host, sizeof(host), "%s:%d", ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
-
- now = ast_tvnow();
- start = 2 + (ast_random() % (TRUNK_CALL_START - 1));
- for (x = start; 1; x++) {
- if (x == TRUNK_CALL_START) {
- x = 1;
- continue;
- }
-
- /* Find first unused call number that hasn't been used in a while */
- ast_mutex_lock(&iaxsl[x]);
- if (!iaxs[x] && ((now.tv_sec - lastused[x].tv_sec) > MIN_REUSE_TIME)) {
- found = 1;
- break;
- }
- ast_mutex_unlock(&iaxsl[x]);
-
- if (x == start - 1) {
- break;
- }
- }
- /* We've still got lock held if we found a spot */
- if (x == start - 1 && !found) {
- ast_log(LOG_WARNING, "No more space\n");
- return 0;
- }
- iaxs[x] = new_iax(sin, host);
- update_max_nontrunk();
- if (iaxs[x]) {
- if (option_debug && iaxdebug)
- ast_log(LOG_DEBUG, "Creating new call structure %d\n", x);
- iaxs[x]->sockfd = sockfd;
- iaxs[x]->addr.sin_port = sin->sin_port;
- iaxs[x]->addr.sin_family = sin->sin_family;
- iaxs[x]->addr.sin_addr.s_addr = sin->sin_addr.s_addr;
- iaxs[x]->peercallno = callno;
- iaxs[x]->callno = x;
- iaxs[x]->pingtime = DEFAULT_RETRY_TIME;
- iaxs[x]->expiry = min_reg_expire;
- iaxs[x]->pingid = iax2_sched_add(sched, ping_time * 1000, send_ping, (void *)(long)x);
- iaxs[x]->lagid = iax2_sched_add(sched, lagrq_time * 1000, send_lagrq, (void *)(long)x);
- iaxs[x]->amaflags = amaflags;
- ast_copy_flags(iaxs[x], (&globalflags), IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF);
-
- ast_string_field_set(iaxs[x], accountcode, accountcode);
- ast_string_field_set(iaxs[x], mohinterpret, mohinterpret);
- ast_string_field_set(iaxs[x], mohsuggest, mohsuggest);
-
- if (iaxs[x]->peercallno) {
- store_by_peercallno(iaxs[x]);
- }
- } else {
- ast_log(LOG_WARNING, "Out of resources\n");
- ast_mutex_unlock(&iaxsl[x]);
- return 0;
- }
- if (!return_locked)
- ast_mutex_unlock(&iaxsl[x]);
- res = x;
- }
- return res;
-}
-
-static int find_callno(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int sockfd, int full_frame) {
-
- return __find_callno(callno, dcallno, sin, new, sockfd, 0, full_frame);
-}
-
-static int find_callno_locked(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int sockfd, int full_frame) {
-
- return __find_callno(callno, dcallno, sin, new, sockfd, 1, full_frame);
-}
-
-/*!
- * \brief Queue a frame to a call's owning asterisk channel
- *
- * \pre This function assumes that iaxsl[callno] is locked when called.
- *
- * \note IMPORTANT NOTE!!! Any time this function is used, even if iaxs[callno]
- * was valid before calling it, it may no longer be valid after calling it.
- * This function may unlock and lock the mutex associated with this callno,
- * meaning that another thread may grab it and destroy the call.
- */
-static int iax2_queue_frame(int callno, struct ast_frame *f)
-{
- for (;;) {
- if (iaxs[callno] && iaxs[callno]->owner) {
- if (ast_mutex_trylock(&iaxs[callno]->owner->lock)) {
- /* Avoid deadlock by pausing and trying again */
- DEADLOCK_AVOIDANCE(&iaxsl[callno]);
- } else {
- ast_queue_frame(iaxs[callno]->owner, f);
- ast_mutex_unlock(&iaxs[callno]->owner->lock);
- break;
- }
- } else
- break;
- }
- return 0;
-}
-
-/*!
- * \brief Queue a hangup frame on the ast_channel owner
- *
- * This function queues a hangup frame on the owner of the IAX2 pvt struct that
- * is active for the given call number.
- *
- * \pre Assumes lock for callno is already held.
- *
- * \note IMPORTANT NOTE!!! Any time this function is used, even if iaxs[callno]
- * was valid before calling it, it may no longer be valid after calling it.
- * This function may unlock and lock the mutex associated with this callno,
- * meaning that another thread may grab it and destroy the call.
- */
-static int iax2_queue_hangup(int callno)
-{
- for (;;) {
- if (iaxs[callno] && iaxs[callno]->owner) {
- if (ast_mutex_trylock(&iaxs[callno]->owner->lock)) {
- /* Avoid deadlock by pausing and trying again */
- DEADLOCK_AVOIDANCE(&iaxsl[callno]);
- } else {
- ast_queue_hangup(iaxs[callno]->owner);
- ast_mutex_unlock(&iaxs[callno]->owner->lock);
- break;
- }
- } else
- break;
- }
- return 0;
-}
-
-/*!
- * \brief Queue a control frame on the ast_channel owner
- *
- * This function queues a control frame on the owner of the IAX2 pvt struct that
- * is active for the given call number.
- *
- * \pre Assumes lock for callno is already held.
- *
- * \note IMPORTANT NOTE!!! Any time this function is used, even if iaxs[callno]
- * was valid before calling it, it may no longer be valid after calling it.
- * This function may unlock and lock the mutex associated with this callno,
- * meaning that another thread may grab it and destroy the call.
- */
-static int iax2_queue_control_data(int callno,
- enum ast_control_frame_type control, const void *data, size_t datalen)
-{
- for (;;) {
- if (iaxs[callno] && iaxs[callno]->owner) {
- if (ast_mutex_trylock(&iaxs[callno]->owner->lock)) {
- /* Avoid deadlock by pausing and trying again */
- DEADLOCK_AVOIDANCE(&iaxsl[callno]);
- } else {
- ast_queue_control_data(iaxs[callno]->owner, control, data, datalen);
- ast_mutex_unlock(&iaxs[callno]->owner->lock);
- break;
- }
- } else
- break;
- }
- return 0;
-}
-static void destroy_firmware(struct iax_firmware *cur)
-{
- /* Close firmware */
- if (cur->fwh) {
- munmap((void*)cur->fwh, ntohl(cur->fwh->datalen) + sizeof(*(cur->fwh)));
- }
- close(cur->fd);
- free(cur);
-}
-
-static int try_firmware(char *s)
-{
- struct stat stbuf;
- struct iax_firmware *cur;
- int ifd;
- int fd;
- int res;
-
- struct ast_iax2_firmware_header *fwh, fwh2;
- struct MD5Context md5;
- unsigned char sum[16];
- unsigned char buf[1024];
- int len, chunk;
- char *s2;
- char *last;
- s2 = alloca(strlen(s) + 100);
- if (!s2) {
- ast_log(LOG_WARNING, "Alloca failed!\n");
- return -1;
- }
- last = strrchr(s, '/');
- if (last)
- last++;
- else
- last = s;
- snprintf(s2, strlen(s) + 100, "/var/tmp/%s-%ld", last, (unsigned long)ast_random());
- res = stat(s, &stbuf);
- if (res < 0) {
- ast_log(LOG_WARNING, "Failed to stat '%s': %s\n", s, strerror(errno));
- return -1;
- }
- /* Make sure it's not a directory */
- if (S_ISDIR(stbuf.st_mode))
- return -1;
- ifd = open(s, O_RDONLY);
- if (ifd < 0) {
- ast_log(LOG_WARNING, "Cannot open '%s': %s\n", s, strerror(errno));
- return -1;
- }
- fd = open(s2, O_RDWR | O_CREAT | O_EXCL, 0600);
- if (fd < 0) {
- ast_log(LOG_WARNING, "Cannot open '%s' for writing: %s\n", s2, strerror(errno));
- close(ifd);
- return -1;
- }
- /* Unlink our newly created file */
- unlink(s2);
-
- /* Now copy the firmware into it */
- len = stbuf.st_size;
- while(len) {
- chunk = len;
- if (chunk > sizeof(buf))
- chunk = sizeof(buf);
- res = read(ifd, buf, chunk);
- if (res != chunk) {
- ast_log(LOG_WARNING, "Only read %d of %d bytes of data :(: %s\n", res, chunk, strerror(errno));
- close(ifd);
- close(fd);
- return -1;
- }
- res = write(fd, buf, chunk);
- if (res != chunk) {
- ast_log(LOG_WARNING, "Only write %d of %d bytes of data :(: %s\n", res, chunk, strerror(errno));
- close(ifd);
- close(fd);
- return -1;
- }
- len -= chunk;
- }
- close(ifd);
- /* Return to the beginning */
- lseek(fd, 0, SEEK_SET);
- if ((res = read(fd, &fwh2, sizeof(fwh2))) != sizeof(fwh2)) {
- ast_log(LOG_WARNING, "Unable to read firmware header in '%s'\n", s);
- close(fd);
- return -1;
- }
- if (ntohl(fwh2.magic) != IAX_FIRMWARE_MAGIC) {
- ast_log(LOG_WARNING, "'%s' is not a valid firmware file\n", s);
- close(fd);
- return -1;
- }
- if (ntohl(fwh2.datalen) != (stbuf.st_size - sizeof(fwh2))) {
- ast_log(LOG_WARNING, "Invalid data length in firmware '%s'\n", s);
- close(fd);
- return -1;
- }
- if (fwh2.devname[sizeof(fwh2.devname) - 1] || ast_strlen_zero((char *)fwh2.devname)) {
- ast_log(LOG_WARNING, "No or invalid device type specified for '%s'\n", s);
- close(fd);
- return -1;
- }
- fwh = (struct ast_iax2_firmware_header*)mmap(NULL, stbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
- if (fwh == (void *) -1) {
- ast_log(LOG_WARNING, "mmap failed: %s\n", strerror(errno));
- close(fd);
- return -1;
- }
- MD5Init(&md5);
- MD5Update(&md5, fwh->data, ntohl(fwh->datalen));
- MD5Final(sum, &md5);
- if (memcmp(sum, fwh->chksum, sizeof(sum))) {
- ast_log(LOG_WARNING, "Firmware file '%s' fails checksum\n", s);
- munmap((void*)fwh, stbuf.st_size);
- close(fd);
- return -1;
- }
- cur = waresl.wares;
- while(cur) {
- if (!strcmp((char *)cur->fwh->devname, (char *)fwh->devname)) {
- /* Found a candidate */
- if (cur->dead || (ntohs(cur->fwh->version) < ntohs(fwh->version)))
- /* The version we have on loaded is older, load this one instead */
- break;
- /* This version is no newer than what we have. Don't worry about it.
- We'll consider it a proper load anyhow though */
- munmap((void*)fwh, stbuf.st_size);
- close(fd);
- return 0;
- }
- cur = cur->next;
- }
- if (!cur) {
- /* Allocate a new one and link it */
- if ((cur = ast_calloc(1, sizeof(*cur)))) {
- cur->fd = -1;
- cur->next = waresl.wares;
- waresl.wares = cur;
- }
- }
- if (cur) {
- if (cur->fwh) {
- munmap((void*)cur->fwh, cur->mmaplen);
- }
- if (cur->fd > -1)
- close(cur->fd);
- cur->fwh = fwh;
- cur->fd = fd;
- cur->mmaplen = stbuf.st_size;
- cur->dead = 0;
- }
- return 0;
-}
-
-static int iax_check_version(char *dev)
-{
- int res = 0;
- struct iax_firmware *cur;
- if (!ast_strlen_zero(dev)) {
- ast_mutex_lock(&waresl.lock);
- cur = waresl.wares;
- while(cur) {
- if (!strcmp(dev, (char *)cur->fwh->devname)) {
- res = ntohs(cur->fwh->version);
- break;
- }
- cur = cur->next;
- }
- ast_mutex_unlock(&waresl.lock);
- }
- return res;
-}
-
-static int iax_firmware_append(struct iax_ie_data *ied, const unsigned char *dev, unsigned int desc)
-{
- int res = -1;
- unsigned int bs = desc & 0xff;
- unsigned int start = (desc >> 8) & 0xffffff;
- unsigned int bytes;
- struct iax_firmware *cur;
- if (!ast_strlen_zero((char *)dev) && bs) {
- start *= bs;
- ast_mutex_lock(&waresl.lock);
- cur = waresl.wares;
- while(cur) {
- if (!strcmp((char *)dev, (char *)cur->fwh->devname)) {
- iax_ie_append_int(ied, IAX_IE_FWBLOCKDESC, desc);
- if (start < ntohl(cur->fwh->datalen)) {
- bytes = ntohl(cur->fwh->datalen) - start;
- if (bytes > bs)
- bytes = bs;
- iax_ie_append_raw(ied, IAX_IE_FWBLOCKDATA, cur->fwh->data + start, bytes);
- } else {
- bytes = 0;
- iax_ie_append(ied, IAX_IE_FWBLOCKDATA);
- }
- if (bytes == bs)
- res = 0;
- else
- res = 1;
- break;
- }
- cur = cur->next;
- }
- ast_mutex_unlock(&waresl.lock);
- }
- return res;
-}
-
-
-static void reload_firmware(int unload)
-{
- struct iax_firmware *cur, *curl, *curp;
- DIR *fwd;
- struct dirent *de;
- char dir[256];
- char fn[256];
- /* Mark all as dead */
- ast_mutex_lock(&waresl.lock);
- cur = waresl.wares;
- while(cur) {
- cur->dead = 1;
- cur = cur->next;
- }
-
- /* Now that we've freed them, load the new ones */
- if (!unload) {
- snprintf(dir, sizeof(dir), "%s/firmware/iax", (char *)ast_config_AST_DATA_DIR);
- fwd = opendir(dir);
- if (fwd) {
- while((de = readdir(fwd))) {
- if (de->d_name[0] != '.') {
- snprintf(fn, sizeof(fn), "%s/%s", dir, de->d_name);
- if (!try_firmware(fn)) {
- if (option_verbose > 1)
- ast_verbose(VERBOSE_PREFIX_2 "Loaded firmware '%s'\n", de->d_name);
- }
- }
- }
- closedir(fwd);
- } else
- ast_log(LOG_WARNING, "Error opening firmware directory '%s': %s\n", dir, strerror(errno));
- }
-
- /* Clean up leftovers */
- cur = waresl.wares;
- curp = NULL;
- while(cur) {
- curl = cur;
- cur = cur->next;
- if (curl->dead) {
- if (curp) {
- curp->next = cur;
- } else {
- waresl.wares = cur;
- }
- destroy_firmware(curl);
- } else {
- curp = cur;
- }
- }
- ast_mutex_unlock(&waresl.lock);
-}
-
-/*!
- * \note This function assumes that iaxsl[callno] is locked when called.
- *
- * \note IMPORTANT NOTE!!! Any time this function is used, even if iaxs[callno]
- * was valid before calling it, it may no longer be valid after calling it.
- * This function calls iax2_queue_frame(), which may unlock and lock the mutex
- * associated with this callno, meaning that another thread may grab it and destroy the call.
- */
-static int __do_deliver(void *data)
-{
- /* Just deliver the packet by using queueing. This is called by
- the IAX thread with the iaxsl lock held. */
- struct iax_frame *fr = data;
- fr->retrans = -1;
- ast_clear_flag(&fr->af, AST_FRFLAG_HAS_TIMING_INFO);
- if (iaxs[fr->callno] && !ast_test_flag(iaxs[fr->callno], IAX_ALREADYGONE))
- iax2_queue_frame(fr->callno, &fr->af);
- /* Free our iax frame */
- iax2_frame_free(fr);
- /* And don't run again */
- return 0;
-}
-
-static int handle_error(void)
-{
- /* XXX Ideally we should figure out why an error occured and then abort those
- rather than continuing to try. Unfortunately, the published interface does
- not seem to work XXX */
-#if 0
- struct sockaddr_in *sin;
- int res;
- struct msghdr m;
- struct sock_extended_err e;
- m.msg_name = NULL;
- m.msg_namelen = 0;
- m.msg_iov = NULL;
- m.msg_control = &e;
- m.msg_controllen = sizeof(e);
- m.msg_flags = 0;
- res = recvmsg(netsocket, &m, MSG_ERRQUEUE);
- if (res < 0)
- ast_log(LOG_WARNING, "Error detected, but unable to read error: %s\n", strerror(errno));
- else {
- if (m.msg_controllen) {
- sin = (struct sockaddr_in *)SO_EE_OFFENDER(&e);
- if (sin)
- ast_log(LOG_WARNING, "Receive error from %s\n", ast_inet_ntoa(sin->sin_addr));
- else
- ast_log(LOG_WARNING, "No address detected??\n");
- } else {
- ast_log(LOG_WARNING, "Local error: %s\n", strerror(e.ee_errno));
- }
- }
-#endif
- return 0;
-}
-
-static int transmit_trunk(struct iax_frame *f, struct sockaddr_in *sin, int sockfd)
-{
- int res;
- res = sendto(sockfd, f->data, f->datalen, 0,(struct sockaddr *)sin,
- sizeof(*sin));
- if (res < 0) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Received error: %s\n", strerror(errno));
- handle_error();
- } else
- res = 0;
- return res;
-}
-
-static int send_packet(struct iax_frame *f)
-{
- int res;
- int callno = f->callno;
-
- /* Don't send if there was an error, but return error instead */
- if (!callno || !iaxs[callno] || iaxs[callno]->error)
- return -1;
-
- /* Called with iaxsl held */
- if (option_debug > 2 && iaxdebug)
- ast_log(LOG_DEBUG, "Sending %d on %d/%d to %s:%d\n", f->ts, callno, iaxs[callno]->peercallno, ast_inet_ntoa(iaxs[callno]->addr.sin_addr), ntohs(iaxs[callno]->addr.sin_port));
- if (f->transfer) {
- if (iaxdebug)
- iax_showframe(f, NULL, 0, &iaxs[callno]->transfer, f->datalen - sizeof(struct ast_iax2_full_hdr));
- res = sendto(iaxs[callno]->sockfd, f->data, f->datalen, 0,(struct sockaddr *)&iaxs[callno]->transfer,
- sizeof(iaxs[callno]->transfer));
- } else {
- if (iaxdebug)
- iax_showframe(f, NULL, 0, &iaxs[callno]->addr, f->datalen - sizeof(struct ast_iax2_full_hdr));
- res = sendto(iaxs[callno]->sockfd, f->data, f->datalen, 0,(struct sockaddr *)&iaxs[callno]->addr,
- sizeof(iaxs[callno]->addr));
- }
- if (res < 0) {
- if (option_debug && iaxdebug)
- ast_log(LOG_DEBUG, "Received error: %s\n", strerror(errno));
- handle_error();
- } else
- res = 0;
- return res;
-}
-
-/*!
- * \note Since this function calls iax2_queue_hangup(), the pvt struct
- * for the given call number may disappear during its execution.
- */
-static int iax2_predestroy(int callno)
-{
- struct ast_channel *c;
- struct chan_iax2_pvt *pvt = iaxs[callno];
-
- if (!pvt)
- return -1;
- if (!ast_test_flag(pvt, IAX_ALREADYGONE)) {
- iax2_destroy_helper(pvt);
- ast_set_flag(pvt, IAX_ALREADYGONE);
- }
- c = pvt->owner;
- if (c) {
- c->tech_pvt = NULL;
- iax2_queue_hangup(callno);
- pvt->owner = NULL;
- ast_module_unref(ast_module_info->self);
- }
- return 0;
-}
-
-static int update_packet(struct iax_frame *f)
-{
- /* Called with iaxsl lock held, and iaxs[callno] non-NULL */
- struct ast_iax2_full_hdr *fh = f->data;
- /* Mark this as a retransmission */
- fh->dcallno = ntohs(IAX_FLAG_RETRANS | f->dcallno);
- /* Update iseqno */
- f->iseqno = iaxs[f->callno]->iseqno;
- fh->iseqno = f->iseqno;
- return 0;
-}
-
-static int attempt_transmit(const void *data);
-static void __attempt_transmit(const void *data)
-{
- /* Attempt to transmit the frame to the remote peer...
- Called without iaxsl held. */
- struct iax_frame *f = (struct iax_frame *)data;
- int freeme=0;
- int callno = f->callno;
- /* Make sure this call is still active */
- if (callno)
- ast_mutex_lock(&iaxsl[callno]);
- if (callno && iaxs[callno]) {
- if ((f->retries < 0) /* Already ACK'd */ ||
- (f->retries >= max_retries) /* Too many attempts */) {
- /* Record an error if we've transmitted too many times */
- if (f->retries >= max_retries) {
- if (f->transfer) {
- /* Transfer timeout */
- send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_TXREJ, 0, NULL, 0, -1);
- } else if (f->final) {
- if (f->final)
- iax2_destroy(callno);
- } else {
- if (iaxs[callno]->owner)
- ast_log(LOG_WARNING, "Max retries exceeded to host %s on %s (type = %d, subclass = %d, ts=%d, seqno=%d)\n", ast_inet_ntoa(iaxs[f->callno]->addr.sin_addr),iaxs[f->callno]->owner->name , f->af.frametype, f->af.subclass, f->ts, f->oseqno);
- iaxs[callno]->error = ETIMEDOUT;
- if (iaxs[callno]->owner) {
- struct ast_frame fr = { 0, };
- /* Hangup the fd */
- fr.frametype = AST_FRAME_CONTROL;
- fr.subclass = AST_CONTROL_HANGUP;
- iax2_queue_frame(callno, &fr); // XXX
- /* Remember, owner could disappear */
- if (iaxs[callno] && iaxs[callno]->owner)
- iaxs[callno]->owner->hangupcause = AST_CAUSE_DESTINATION_OUT_OF_ORDER;
- } else {
- if (iaxs[callno]->reg) {
- memset(&iaxs[callno]->reg->us, 0, sizeof(iaxs[callno]->reg->us));
- iaxs[callno]->reg->regstate = REG_STATE_TIMEOUT;
- iaxs[callno]->reg->refresh = IAX_DEFAULT_REG_EXPIRE;
- }
- iax2_destroy(callno);
- }
- }
-
- }
- freeme++;
- } else {
- /* Update it if it needs it */
- update_packet(f);
- /* Attempt transmission */
- send_packet(f);
- f->retries++;
- /* Try again later after 10 times as long */
- f->retrytime *= 10;
- if (f->retrytime > MAX_RETRY_TIME)
- f->retrytime = MAX_RETRY_TIME;
- /* Transfer messages max out at one second */
- if (f->transfer && (f->retrytime > 1000))
- f->retrytime = 1000;
- f->retrans = iax2_sched_add(sched, f->retrytime, attempt_transmit, f);
- }
- } else {
- /* Make sure it gets freed */
- f->retries = -1;
- freeme++;
- }
- if (callno)
- ast_mutex_unlock(&iaxsl[callno]);
- /* Do not try again */
- if (freeme) {
- /* Don't attempt delivery, just remove it from the queue */
- AST_LIST_LOCK(&iaxq.queue);
- AST_LIST_REMOVE(&iaxq.queue, f, list);
- iaxq.count--;
- AST_LIST_UNLOCK(&iaxq.queue);
- f->retrans = -1;
- /* Free the IAX frame */
- iax2_frame_free(f);
- }
-}
-
-static int attempt_transmit(const void *data)
-{
-#ifdef SCHED_MULTITHREADED
- if (schedule_action(__attempt_transmit, data))
-#endif
- __attempt_transmit(data);
- return 0;
-}
-
-static int iax2_prune_realtime(int fd, int argc, char *argv[])
-{
- struct iax2_peer *peer;
-
- if (argc != 4)
- return RESULT_SHOWUSAGE;
- if (!strcmp(argv[3],"all")) {
- reload_config();
- ast_cli(fd, "OK cache is flushed.\n");
- } else if ((peer = find_peer(argv[3], 0))) {
- if(ast_test_flag(peer, IAX_RTCACHEFRIENDS)) {
- ast_set_flag(peer, IAX_RTAUTOCLEAR);
- expire_registry(peer_ref(peer));
- ast_cli(fd, "OK peer %s was removed from the cache.\n", argv[3]);
- } else {
- ast_cli(fd, "SORRY peer %s is not eligible for this operation.\n", argv[3]);
- }
- peer_unref(peer);
- } else {
- ast_cli(fd, "SORRY peer %s was not found in the cache.\n", argv[3]);
- }
-
- return RESULT_SUCCESS;
-}
-
-static int iax2_test_losspct(int fd, int argc, char *argv[])
-{
- if (argc != 4)
- return RESULT_SHOWUSAGE;
-
- test_losspct = atoi(argv[3]);
-
- return RESULT_SUCCESS;
-}
-
-#ifdef IAXTESTS
-static int iax2_test_late(int fd, int argc, char *argv[])
-{
- if (argc != 4)
- return RESULT_SHOWUSAGE;
-
- test_late = atoi(argv[3]);
-
- return RESULT_SUCCESS;
-}
-
-static int iax2_test_resync(int fd, int argc, char *argv[])
-{
- if (argc != 4)
- return RESULT_SHOWUSAGE;
-
- test_resync = atoi(argv[3]);
-
- return RESULT_SUCCESS;
-}
-
-static int iax2_test_jitter(int fd, int argc, char *argv[])
-{
- if (argc < 4 || argc > 5)
- return RESULT_SHOWUSAGE;
-
- test_jit = atoi(argv[3]);
- if (argc == 5)
- test_jitpct = atoi(argv[4]);
-
- return RESULT_SUCCESS;
-}
-#endif /* IAXTESTS */
-
-/*! \brief peer_status: Report Peer status in character string */
-/* returns 1 if peer is online, -1 if unmonitored */
-static int peer_status(struct iax2_peer *peer, char *status, int statuslen)
-{
- int res = 0;
- if (peer->maxms) {
- if (peer->lastms < 0) {
- ast_copy_string(status, "UNREACHABLE", statuslen);
- } else if (peer->lastms > peer->maxms) {
- snprintf(status, statuslen, "LAGGED (%d ms)", peer->lastms);
- res = 1;
- } else if (peer->lastms) {
- snprintf(status, statuslen, "OK (%d ms)", peer->lastms);
- res = 1;
- } else {
- ast_copy_string(status, "UNKNOWN", statuslen);
- }
- } else {
- ast_copy_string(status, "Unmonitored", statuslen);
- res = -1;
- }
- return res;
-}
-
-/*! \brief Show one peer in detail */
-static int iax2_show_peer(int fd, int argc, char *argv[])
-{
- char status[30];
- char cbuf[256];
- struct iax2_peer *peer;
- char codec_buf[512];
- int x = 0, codec = 0, load_realtime = 0;
-
- if (argc < 4)
- return RESULT_SHOWUSAGE;
-
- load_realtime = (argc == 5 && !strcmp(argv[4], "load")) ? 1 : 0;
-
- peer = find_peer(argv[3], load_realtime);
- if (peer) {
- ast_cli(fd,"\n\n");
- ast_cli(fd, " * Name : %s\n", peer->name);
- ast_cli(fd, " Secret : %s\n", ast_strlen_zero(peer->secret)?"<Not set>":"<Set>");
- ast_cli(fd, " Context : %s\n", peer->context);
- ast_cli(fd, " Mailbox : %s\n", peer->mailbox);
- ast_cli(fd, " Dynamic : %s\n", ast_test_flag(peer, IAX_DYNAMIC) ? "Yes":"No");
- ast_cli(fd, " Callerid : %s\n", ast_callerid_merge(cbuf, sizeof(cbuf), peer->cid_name, peer->cid_num, "<unspecified>"));
- ast_cli(fd, " Expire : %d\n", peer->expire);
- ast_cli(fd, " ACL : %s\n", (peer->ha?"Yes":"No"));
- ast_cli(fd, " Addr->IP : %s Port %d\n", peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "(Unspecified)", ntohs(peer->addr.sin_port));
- ast_cli(fd, " Defaddr->IP : %s Port %d\n", ast_inet_ntoa(peer->defaddr.sin_addr), ntohs(peer->defaddr.sin_port));
- ast_cli(fd, " Username : %s\n", peer->username);
- ast_cli(fd, " Codecs : ");
- ast_getformatname_multiple(codec_buf, sizeof(codec_buf) -1, peer->capability);
- ast_cli(fd, "%s\n", codec_buf);
-
- ast_cli(fd, " Codec Order : (");
- for(x = 0; x < 32 ; x++) {
- codec = ast_codec_pref_index(&peer->prefs,x);
- if(!codec)
- break;
- ast_cli(fd, "%s", ast_getformatname(codec));
- if(x < 31 && ast_codec_pref_index(&peer->prefs,x+1))
- ast_cli(fd, "|");
- }
-
- if (!x)
- ast_cli(fd, "none");
- ast_cli(fd, ")\n");
-
- ast_cli(fd, " Status : ");
- peer_status(peer, status, sizeof(status));
- ast_cli(fd, "%s\n",status);
- ast_cli(fd, " Qualify : every %dms when OK, every %dms when UNREACHABLE (sample smoothing %s)\n", peer->pokefreqok, peer->pokefreqnotok, peer->smoothing ? "On" : "Off");
- ast_cli(fd,"\n");
- peer_unref(peer);
- } else {
- ast_cli(fd,"Peer %s not found.\n", argv[3]);
- ast_cli(fd,"\n");
- }
-
- return RESULT_SUCCESS;
-}
-
-static char *complete_iax2_show_peer(const char *line, const char *word, int pos, int state)
-{
- int which = 0;
- struct iax2_peer *peer;
- char *res = NULL;
- int wordlen = strlen(word);
- struct ao2_iterator i;
-
- /* 0 - iax2; 1 - show; 2 - peer; 3 - <peername> */
- if (pos != 3)
- return NULL;
-
- i = ao2_iterator_init(peers, 0);
- while ((peer = ao2_iterator_next(&i))) {
- if (!strncasecmp(peer->name, word, wordlen) && ++which > state) {
- res = ast_strdup(peer->name);
- peer_unref(peer);
- break;
- }
- peer_unref(peer);
- }
-
- return res;
-}
-
-static int iax2_show_stats(int fd, int argc, char *argv[])
-{
- struct iax_frame *cur;
- int cnt = 0, dead=0, final=0;
-
- if (argc != 3)
- return RESULT_SHOWUSAGE;
-
- AST_LIST_LOCK(&iaxq.queue);
- AST_LIST_TRAVERSE(&iaxq.queue, cur, list) {
- if (cur->retries < 0)
- dead++;
- if (cur->final)
- final++;
- cnt++;
- }
- AST_LIST_UNLOCK(&iaxq.queue);
-
- ast_cli(fd, " IAX Statistics\n");
- ast_cli(fd, "---------------------\n");
- ast_cli(fd, "Outstanding frames: %d (%d ingress, %d egress)\n", iax_get_frames(), iax_get_iframes(), iax_get_oframes());
- ast_cli(fd, "Packets in transmit queue: %d dead, %d final, %d total\n\n", dead, final, cnt);
-
- return RESULT_SUCCESS;
-}
-
-static int iax2_show_cache(int fd, int argc, char *argv[])
-{
- struct iax2_dpcache *dp;
- char tmp[1024], *pc;
- int s;
- int x,y;
- struct timeval tv;
- gettimeofday(&tv, NULL);
- ast_mutex_lock(&dpcache_lock);
- dp = dpcache;
- ast_cli(fd, "%-20.20s %-12.12s %-9.9s %-8.8s %s\n", "Peer/Context", "Exten", "Exp.", "Wait.", "Flags");
- while(dp) {
- s = dp->expiry.tv_sec - tv.tv_sec;
- tmp[0] = '\0';
- if (dp->flags & CACHE_FLAG_EXISTS)
- strncat(tmp, "EXISTS|", sizeof(tmp) - strlen(tmp) - 1);
- if (dp->flags & CACHE_FLAG_NONEXISTENT)
- strncat(tmp, "NONEXISTENT|", sizeof(tmp) - strlen(tmp) - 1);
- if (dp->flags & CACHE_FLAG_CANEXIST)
- strncat(tmp, "CANEXIST|", sizeof(tmp) - strlen(tmp) - 1);
- if (dp->flags & CACHE_FLAG_PENDING)
- strncat(tmp, "PENDING|", sizeof(tmp) - strlen(tmp) - 1);
- if (dp->flags & CACHE_FLAG_TIMEOUT)
- strncat(tmp, "TIMEOUT|", sizeof(tmp) - strlen(tmp) - 1);
- if (dp->flags & CACHE_FLAG_TRANSMITTED)
- strncat(tmp, "TRANSMITTED|", sizeof(tmp) - strlen(tmp) - 1);
- if (dp->flags & CACHE_FLAG_MATCHMORE)
- strncat(tmp, "MATCHMORE|", sizeof(tmp) - strlen(tmp) - 1);
- if (dp->flags & CACHE_FLAG_UNKNOWN)
- strncat(tmp, "UNKNOWN|", sizeof(tmp) - strlen(tmp) - 1);
- /* Trim trailing pipe */
- if (!ast_strlen_zero(tmp))
- tmp[strlen(tmp) - 1] = '\0';
- else
- ast_copy_string(tmp, "(none)", sizeof(tmp));
- y=0;
- pc = strchr(dp->peercontext, '@');
- if (!pc)
- pc = dp->peercontext;
- else
- pc++;
- for (x=0;x<sizeof(dp->waiters) / sizeof(dp->waiters[0]); x++)
- if (dp->waiters[x] > -1)
- y++;
- if (s > 0)
- ast_cli(fd, "%-20.20s %-12.12s %-9d %-8d %s\n", pc, dp->exten, s, y, tmp);
- else
- ast_cli(fd, "%-20.20s %-12.12s %-9.9s %-8d %s\n", pc, dp->exten, "(expired)", y, tmp);
- dp = dp->next;
- }
- ast_mutex_unlock(&dpcache_lock);
- return RESULT_SUCCESS;
-}
-
-static unsigned int calc_rxstamp(struct chan_iax2_pvt *p, unsigned int offset);
-
-static void unwrap_timestamp(struct iax_frame *fr)
-{
- /* Video mini frames only encode the lower 15 bits of the session
- * timestamp, but other frame types (e.g. audio) encode 16 bits. */
- const int ts_shift = (fr->af.frametype == AST_FRAME_VIDEO) ? 15 : 16;
- const int lower_mask = (1 << ts_shift) - 1;
- const int upper_mask = ~lower_mask;
- const int last_upper = iaxs[fr->callno]->last & upper_mask;
-
- if ( (fr->ts & upper_mask) == last_upper ) {
- const int x = fr->ts - iaxs[fr->callno]->last;
- const int threshold = (ts_shift == 15) ? 25000 : 50000;
-
- if (x < -threshold) {
- /* Sudden big jump backwards in timestamp:
- What likely happened here is that miniframe timestamp has circled but we haven't
- gotten the update from the main packet. We'll just pretend that we did, and
- update the timestamp appropriately. */
- fr->ts = (last_upper + (1 << ts_shift)) | (fr->ts & lower_mask);
- if (option_debug && iaxdebug)
- ast_log(LOG_DEBUG, "schedule_delivery: pushed forward timestamp\n");
- } else if (x > threshold) {
- /* Sudden apparent big jump forwards in timestamp:
- What's likely happened is this is an old miniframe belonging to the previous
- top 15 or 16-bit timestamp that has turned up out of order.
- Adjust the timestamp appropriately. */
- fr->ts = (last_upper - (1 << ts_shift)) | (fr->ts & lower_mask);
- if (option_debug && iaxdebug)
- ast_log(LOG_DEBUG, "schedule_delivery: pushed back timestamp\n");
- }
- }
-}
-
-static int get_from_jb(const void *p);
-
-static void update_jbsched(struct chan_iax2_pvt *pvt)
-{
- int when;
-
- when = ast_tvdiff_ms(ast_tvnow(), pvt->rxcore);
-
- when = jb_next(pvt->jb) - when;
-
- AST_SCHED_DEL(sched, pvt->jbid);
-
- if(when <= 0) {
- /* XXX should really just empty until when > 0.. */
- when = 1;
- }
-
- pvt->jbid = iax2_sched_add(sched, when, get_from_jb, CALLNO_TO_PTR(pvt->callno));
-}
-
-static void __get_from_jb(const void *p)
-{
- int callno = PTR_TO_CALLNO(p);
- struct chan_iax2_pvt *pvt = NULL;
- struct iax_frame *fr;
- jb_frame frame;
- int ret;
- long now;
- long next;
- struct timeval tv;
-
- /* Make sure we have a valid private structure before going on */
- ast_mutex_lock(&iaxsl[callno]);
- pvt = iaxs[callno];
- if (!pvt) {
- /* No go! */
- ast_mutex_unlock(&iaxsl[callno]);
- return;
- }
-
- pvt->jbid = -1;
-
- gettimeofday(&tv,NULL);
- /* round up a millisecond since ast_sched_runq does; */
- /* prevents us from spinning while waiting for our now */
- /* to catch up with runq's now */
- tv.tv_usec += 1000;
-
- now = ast_tvdiff_ms(tv, pvt->rxcore);
-
- if(now >= (next = jb_next(pvt->jb))) {
- ret = jb_get(pvt->jb,&frame,now,ast_codec_interp_len(pvt->voiceformat));
- switch(ret) {
- case JB_OK:
- fr = frame.data;
- __do_deliver(fr);
- /* __do_deliver() can cause the call to disappear */
- pvt = iaxs[callno];
- break;
- case JB_INTERP:
- {
- struct ast_frame af = { 0, };
-
- /* create an interpolation frame */
- af.frametype = AST_FRAME_VOICE;
- af.subclass = pvt->voiceformat;
- af.samples = frame.ms * 8;
- af.src = "IAX2 JB interpolation";
- af.delivery = ast_tvadd(pvt->rxcore, ast_samp2tv(next, 1000));
- af.offset = AST_FRIENDLY_OFFSET;
-
- /* queue the frame: For consistency, we would call __do_deliver here, but __do_deliver wants an iax_frame,
- * which we'd need to malloc, and then it would free it. That seems like a drag */
- if (!ast_test_flag(iaxs[callno], IAX_ALREADYGONE)) {
- iax2_queue_frame(callno, &af);
- /* iax2_queue_frame() could cause the call to disappear */
- pvt = iaxs[callno];
- }
- }
- break;
- case JB_DROP:
- iax2_frame_free(frame.data);
- break;
- case JB_NOFRAME:
- case JB_EMPTY:
- /* do nothing */
- break;
- default:
- /* shouldn't happen */
- break;
- }
- }
- if (pvt)
- update_jbsched(pvt);
- ast_mutex_unlock(&iaxsl[callno]);
-}
-
-static int get_from_jb(const void *data)
-{
-#ifdef SCHED_MULTITHREADED
- if (schedule_action(__get_from_jb, data))
-#endif
- __get_from_jb(data);
- return 0;
-}
-
-/*!
- * \note This function assumes fr->callno is locked
- *
- * \note IMPORTANT NOTE!!! Any time this function is used, even if iaxs[callno]
- * was valid before calling it, it may no longer be valid after calling it.
- */
-static int schedule_delivery(struct iax_frame *fr, int updatehistory, int fromtrunk, unsigned int *tsout)
-{
- int type, len;
- int ret;
- int needfree = 0;
- struct ast_channel *owner = NULL;
- struct ast_channel *bridge = NULL;
-
- /* Attempt to recover wrapped timestamps */
- unwrap_timestamp(fr);
-
- /* delivery time is sender's sent timestamp converted back into absolute time according to our clock */
- if ( !fromtrunk && !ast_tvzero(iaxs[fr->callno]->rxcore))
- fr->af.delivery = ast_tvadd(iaxs[fr->callno]->rxcore, ast_samp2tv(fr->ts, 1000));
- else {
-#if 0
- if (option_debug)
- ast_log(LOG_DEBUG, "schedule_delivery: set delivery to 0 as we don't have an rxcore yet, or frame is from trunk.\n");
-#endif
- fr->af.delivery = ast_tv(0,0);
- }
-
- type = JB_TYPE_CONTROL;
- len = 0;
-
- if(fr->af.frametype == AST_FRAME_VOICE) {
- type = JB_TYPE_VOICE;
- len = ast_codec_get_samples(&fr->af) / 8;
- } else if(fr->af.frametype == AST_FRAME_CNG) {
- type = JB_TYPE_SILENCE;
- }
-
- if ( (!ast_test_flag(iaxs[fr->callno], IAX_USEJITTERBUF)) ) {
- if (tsout)
- *tsout = fr->ts;
- __do_deliver(fr);
- return -1;
- }
-
- if ((owner = iaxs[fr->callno]->owner))
- bridge = ast_bridged_channel(owner);
-
- /* if the user hasn't requested we force the use of the jitterbuffer, and we're bridged to
- * a channel that can accept jitter, then flush and suspend the jb, and send this frame straight through */
- if ( (!ast_test_flag(iaxs[fr->callno], IAX_FORCEJITTERBUF)) && owner && bridge && (bridge->tech->properties & AST_CHAN_TP_WANTSJITTER) ) {
- jb_frame frame;
-
- /* deliver any frames in the jb */
- while (jb_getall(iaxs[fr->callno]->jb, &frame) == JB_OK) {
- __do_deliver(frame.data);
- /* __do_deliver() can make the call disappear */
- if (!iaxs[fr->callno])
- return -1;
- }
-
- jb_reset(iaxs[fr->callno]->jb);
-
- AST_SCHED_DEL(sched, iaxs[fr->callno]->jbid);
-
- /* deliver this frame now */
- if (tsout)
- *tsout = fr->ts;
- __do_deliver(fr);
- return -1;
- }
-
- /* insert into jitterbuffer */
- /* TODO: Perhaps we could act immediately if it's not droppable and late */
- ret = jb_put(iaxs[fr->callno]->jb, fr, type, len, fr->ts,
- calc_rxstamp(iaxs[fr->callno],fr->ts));
- if (ret == JB_DROP) {
- needfree++;
- } else if (ret == JB_SCHED) {
- update_jbsched(iaxs[fr->callno]);
- }
- if (tsout)
- *tsout = fr->ts;
- if (needfree) {
- /* Free our iax frame */
- iax2_frame_free(fr);
- return -1;
- }
- return 0;
-}
-
-static int iax2_transmit(struct iax_frame *fr)
-{
- /* Lock the queue and place this packet at the end */
- /* By setting this to 0, the network thread will send it for us, and
- queue retransmission if necessary */
- fr->sentyet = 0;
- AST_LIST_LOCK(&iaxq.queue);
- AST_LIST_INSERT_TAIL(&iaxq.queue, fr, list);
- iaxq.count++;
- AST_LIST_UNLOCK(&iaxq.queue);
- /* Wake up the network and scheduler thread */
- if (netthreadid != AST_PTHREADT_NULL)
- pthread_kill(netthreadid, SIGURG);
- signal_condition(&sched_lock, &sched_cond);
- return 0;
-}
-
-
-
-static int iax2_digit_begin(struct ast_channel *c, char digit)
-{
- return send_command_locked(PTR_TO_CALLNO(c->tech_pvt), AST_FRAME_DTMF_BEGIN, digit, 0, NULL, 0, -1);
-}
-
-static int iax2_digit_end(struct ast_channel *c, char digit, unsigned int duration)
-{
- return send_command_locked(PTR_TO_CALLNO(c->tech_pvt), AST_FRAME_DTMF_END, digit, 0, NULL, 0, -1);
-}
-
-static int iax2_sendtext(struct ast_channel *c, const char *text)
-{
-
- return send_command_locked(PTR_TO_CALLNO(c->tech_pvt), AST_FRAME_TEXT,
- 0, 0, (unsigned char *)text, strlen(text) + 1, -1);
-}
-
-static int iax2_sendimage(struct ast_channel *c, struct ast_frame *img)
-{
- return send_command_locked(PTR_TO_CALLNO(c->tech_pvt), AST_FRAME_IMAGE, img->subclass, 0, img->data, img->datalen, -1);
-}
-
-static int iax2_sendhtml(struct ast_channel *c, int subclass, const char *data, int datalen)
-{
- return send_command_locked(PTR_TO_CALLNO(c->tech_pvt), AST_FRAME_HTML, subclass, 0, (unsigned char *)data, datalen, -1);
-}
-
-static int iax2_fixup(struct ast_channel *oldchannel, struct ast_channel *newchan)
-{
- unsigned short callno = PTR_TO_CALLNO(newchan->tech_pvt);
- ast_mutex_lock(&iaxsl[callno]);
- if (iaxs[callno])
- iaxs[callno]->owner = newchan;
- else
- ast_log(LOG_WARNING, "Uh, this isn't a good sign...\n");
- ast_mutex_unlock(&iaxsl[callno]);
- return 0;
-}
-
-/*!
- * \note This function calls reg_source_db -> iax2_poke_peer -> find_callno,
- * so do not call this with a pvt lock held.
- */
-static struct iax2_peer *realtime_peer(const char *peername, struct sockaddr_in *sin)
-{
- struct ast_variable *var = NULL;
- struct ast_variable *tmp;
- struct iax2_peer *peer=NULL;
- time_t regseconds = 0, nowtime;
- int dynamic=0;
-
- if (peername) {
- var = ast_load_realtime("iaxpeers", "name", peername, "host", "dynamic", NULL);
- if (!var && sin)
- var = ast_load_realtime("iaxpeers", "name", peername, "host", ast_inet_ntoa(sin->sin_addr), NULL);
- } else if (sin) {
- char porta[25];
- sprintf(porta, "%d", ntohs(sin->sin_port));
- var = ast_load_realtime("iaxpeers", "ipaddr", ast_inet_ntoa(sin->sin_addr), "port", porta, NULL);
- if (var) {
- /* We'll need the peer name in order to build the structure! */
- for (tmp = var; tmp; tmp = tmp->next) {
- if (!strcasecmp(tmp->name, "name"))
- peername = tmp->value;
- }
- }
- }
- if (!var && peername) { /* Last ditch effort */
- var = ast_load_realtime("iaxpeers", "name", peername, NULL);
- /*!\note
- * If this one loaded something, then we need to ensure that the host
- * field matched. The only reason why we can't have this as a criteria
- * is because we only have the IP address and the host field might be
- * set as a name (and the reverse PTR might not match).
- */
- if (var && sin) {
- for (tmp = var; tmp; tmp = tmp->next) {
- if (!strcasecmp(tmp->name, "host")) {
- struct ast_hostent ahp;
- struct hostent *hp;
- if (!(hp = ast_gethostbyname(tmp->value, &ahp)) || (memcmp(&hp->h_addr, &sin->sin_addr, sizeof(hp->h_addr)))) {
- /* No match */
- ast_variables_destroy(var);
- var = NULL;
- }
- break;
- }
- }
- }
- }
- if (!var)
- return NULL;
-
- peer = build_peer(peername, var, NULL, ast_test_flag((&globalflags), IAX_RTCACHEFRIENDS) ? 0 : 1);
-
- if (!peer) {
- ast_variables_destroy(var);
- return NULL;
- }
-
- for (tmp = var; tmp; tmp = tmp->next) {
- /* Make sure it's not a user only... */
- if (!strcasecmp(tmp->name, "type")) {
- if (strcasecmp(tmp->value, "friend") &&
- strcasecmp(tmp->value, "peer")) {
- /* Whoops, we weren't supposed to exist! */
- peer = peer_unref(peer);
- break;
- }
- } else if (!strcasecmp(tmp->name, "regseconds")) {
- ast_get_time_t(tmp->value, &regseconds, 0, NULL);
- } else if (!strcasecmp(tmp->name, "ipaddr")) {
- inet_aton(tmp->value, &(peer->addr.sin_addr));
- } else if (!strcasecmp(tmp->name, "port")) {
- peer->addr.sin_port = htons(atoi(tmp->value));
- } else if (!strcasecmp(tmp->name, "host")) {
- if (!strcasecmp(tmp->value, "dynamic"))
- dynamic = 1;
- }
- }
-
- ast_variables_destroy(var);
-
- if (!peer)
- return NULL;
-
- if (ast_test_flag((&globalflags), IAX_RTCACHEFRIENDS)) {
- ast_copy_flags(peer, &globalflags, IAX_RTAUTOCLEAR|IAX_RTCACHEFRIENDS);
- if (ast_test_flag(peer, IAX_RTAUTOCLEAR)) {
- if (peer->expire > -1) {
- if (!ast_sched_del(sched, peer->expire)) {
- peer->expire = -1;
- peer_unref(peer);
- }
- }
- peer->expire = iax2_sched_add(sched, (global_rtautoclear) * 1000, expire_registry, peer_ref(peer));
- if (peer->expire == -1)
- peer_unref(peer);
- }
- ao2_link(peers, peer);
- if (ast_test_flag(peer, IAX_DYNAMIC))
- reg_source_db(peer);
- } else {
- ast_set_flag(peer, IAX_TEMPONLY);
- }
-
- if (!ast_test_flag(&globalflags, IAX_RTIGNOREREGEXPIRE) && dynamic) {
- time(&nowtime);
- if ((nowtime - regseconds) > IAX_DEFAULT_REG_EXPIRE) {
- memset(&peer->addr, 0, sizeof(peer->addr));
- realtime_update_peer(peer->name, &peer->addr, 0);
- if (option_debug)
- ast_log(LOG_DEBUG, "realtime_peer: Bah, '%s' is expired (%d/%d/%d)!\n",
- peername, (int)(nowtime - regseconds), (int)regseconds, (int)nowtime);
- }
- else {
- if (option_debug)
- ast_log(LOG_DEBUG, "realtime_peer: Registration for '%s' still active (%d/%d/%d)!\n",
- peername, (int)(nowtime - regseconds), (int)regseconds, (int)nowtime);
- }
- }
-
- return peer;
-}
-
-static struct iax2_user *realtime_user(const char *username, struct sockaddr_in *sin)
-{
- struct ast_variable *var;
- struct ast_variable *tmp;
- struct iax2_user *user=NULL;
-
- var = ast_load_realtime("iaxusers", "name", username, "host", "dynamic", NULL);
- if (!var)
- var = ast_load_realtime("iaxusers", "name", username, "host", ast_inet_ntoa(sin->sin_addr), NULL);
- if (!var && sin) {
- char porta[6];
- snprintf(porta, sizeof(porta), "%d", ntohs(sin->sin_port));
- var = ast_load_realtime("iaxusers", "name", username, "ipaddr", ast_inet_ntoa(sin->sin_addr), "port", porta, NULL);
- if (!var)
- var = ast_load_realtime("iaxusers", "ipaddr", ast_inet_ntoa(sin->sin_addr), "port", porta, NULL);
- }
- if (!var) { /* Last ditch effort */
- var = ast_load_realtime("iaxusers", "name", username, NULL);
- /*!\note
- * If this one loaded something, then we need to ensure that the host
- * field matched. The only reason why we can't have this as a criteria
- * is because we only have the IP address and the host field might be
- * set as a name (and the reverse PTR might not match).
- */
- if (var) {
- for (tmp = var; tmp; tmp = tmp->next) {
- if (!strcasecmp(tmp->name, "host")) {
- struct ast_hostent ahp;
- struct hostent *hp;
- if (!(hp = ast_gethostbyname(tmp->value, &ahp)) || (memcmp(&hp->h_addr, &sin->sin_addr, sizeof(hp->h_addr)))) {
- /* No match */
- ast_variables_destroy(var);
- var = NULL;
- }
- break;
- }
- }
- }
- }
- if (!var)
- return NULL;
-
- tmp = var;
- while(tmp) {
- /* Make sure it's not a peer only... */
- if (!strcasecmp(tmp->name, "type")) {
- if (strcasecmp(tmp->value, "friend") &&
- strcasecmp(tmp->value, "user")) {
- return NULL;
- }
- }
- tmp = tmp->next;
- }
-
- user = build_user(username, var, NULL, !ast_test_flag((&globalflags), IAX_RTCACHEFRIENDS));
-
- ast_variables_destroy(var);
-
- if (!user)
- return NULL;
-
- if (ast_test_flag((&globalflags), IAX_RTCACHEFRIENDS)) {
- ast_set_flag(user, IAX_RTCACHEFRIENDS);
- ao2_link(users, user);
- } else {
- ast_set_flag(user, IAX_TEMPONLY);
- }
-
- return user;
-}
-
-static void realtime_update_peer(const char *peername, struct sockaddr_in *sin, time_t regtime)
-{
- char port[10];
- char regseconds[20];
-
- snprintf(regseconds, sizeof(regseconds), "%d", (int)regtime);
- snprintf(port, sizeof(port), "%d", ntohs(sin->sin_port));
- ast_update_realtime("iaxpeers", "name", peername,
- "ipaddr", ast_inet_ntoa(sin->sin_addr), "port", port,
- "regseconds", regseconds, NULL);
-}
-
-struct create_addr_info {
- int capability;
- unsigned int flags;
- int maxtime;
- int encmethods;
- int found;
- int sockfd;
- int adsi;
- char username[80];
- char secret[80];
- char outkey[80];
- char timezone[80];
- char prefs[32];
- char context[AST_MAX_CONTEXT];
- char peercontext[AST_MAX_CONTEXT];
- char mohinterpret[MAX_MUSICCLASS];
- char mohsuggest[MAX_MUSICCLASS];
-};
-
-static int create_addr(const char *peername, struct ast_channel *c, struct sockaddr_in *sin, struct create_addr_info *cai)
-{
- struct ast_hostent ahp;
- struct hostent *hp;
- struct iax2_peer *peer;
- int res = -1;
- struct ast_codec_pref ourprefs;
-
- ast_clear_flag(cai, IAX_SENDANI | IAX_TRUNK);
- cai->sockfd = defaultsockfd;
- cai->maxtime = 0;
- sin->sin_family = AF_INET;
-
- if (!(peer = find_peer(peername, 1))) {
- cai->found = 0;
-
- hp = ast_gethostbyname(peername, &ahp);
- if (hp) {
- memcpy(&sin->sin_addr, hp->h_addr, sizeof(sin->sin_addr));
- sin->sin_port = htons(IAX_DEFAULT_PORTNO);
- /* use global iax prefs for unknown peer/user */
- /* But move the calling channel's native codec to the top of the preference list */
- memcpy(&ourprefs, &prefs, sizeof(ourprefs));
- if (c)
- ast_codec_pref_prepend(&ourprefs, c->nativeformats, 1);
- ast_codec_pref_convert(&ourprefs, cai->prefs, sizeof(cai->prefs), 1);
- return 0;
- } else {
- ast_log(LOG_WARNING, "No such host: %s\n", peername);
- return -1;
- }
- }
-
- cai->found = 1;
-
- /* if the peer has no address (current or default), return failure */
- if (!(peer->addr.sin_addr.s_addr || peer->defaddr.sin_addr.s_addr))
- goto return_unref;
-
- /* if the peer is being monitored and is currently unreachable, return failure */
- if (peer->maxms && ((peer->lastms > peer->maxms) || (peer->lastms < 0)))
- goto return_unref;
-
- ast_copy_flags(cai, peer, IAX_SENDANI | IAX_TRUNK | IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF);
- cai->maxtime = peer->maxms;
- cai->capability = peer->capability;
- cai->encmethods = peer->encmethods;
- cai->sockfd = peer->sockfd;
- cai->adsi = peer->adsi;
- memcpy(&ourprefs, &peer->prefs, sizeof(ourprefs));
- /* Move the calling channel's native codec to the top of the preference list */
- if (c) {
- ast_log(LOG_DEBUG, "prepending %x to prefs\n", c->nativeformats);
- ast_codec_pref_prepend(&ourprefs, c->nativeformats, 1);
- }
- ast_codec_pref_convert(&ourprefs, cai->prefs, sizeof(cai->prefs), 1);
- ast_copy_string(cai->context, peer->context, sizeof(cai->context));
- ast_copy_string(cai->peercontext, peer->peercontext, sizeof(cai->peercontext));
- ast_copy_string(cai->username, peer->username, sizeof(cai->username));
- ast_copy_string(cai->timezone, peer->zonetag, sizeof(cai->timezone));
- ast_copy_string(cai->outkey, peer->outkey, sizeof(cai->outkey));
- ast_copy_string(cai->mohinterpret, peer->mohinterpret, sizeof(cai->mohinterpret));
- ast_copy_string(cai->mohsuggest, peer->mohsuggest, sizeof(cai->mohsuggest));
- if (ast_strlen_zero(peer->dbsecret)) {
- ast_copy_string(cai->secret, peer->secret, sizeof(cai->secret));
- } else {
- char *family;
- char *key = NULL;
-
- family = ast_strdupa(peer->dbsecret);
- key = strchr(family, '/');
- if (key)
- *key++ = '\0';
- if (!key || ast_db_get(family, key, cai->secret, sizeof(cai->secret))) {
- ast_log(LOG_WARNING, "Unable to retrieve database password for family/key '%s'!\n", peer->dbsecret);
- goto return_unref;
- }
- }
-
- if (peer->addr.sin_addr.s_addr) {
- sin->sin_addr = peer->addr.sin_addr;
- sin->sin_port = peer->addr.sin_port;
- } else {
- sin->sin_addr = peer->defaddr.sin_addr;
- sin->sin_port = peer->defaddr.sin_port;
- }
-
- res = 0;
-
-return_unref:
- peer_unref(peer);
-
- return res;
-}
-
-static void __auto_congest(const void *nothing)
-{
- int callno = PTR_TO_CALLNO(nothing);
- struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_CONGESTION };
- ast_mutex_lock(&iaxsl[callno]);
- if (iaxs[callno]) {
- iaxs[callno]->initid = -1;
- iax2_queue_frame(callno, &f);
- ast_log(LOG_NOTICE, "Auto-congesting call due to slow response\n");
- }
- ast_mutex_unlock(&iaxsl[callno]);
-}
-
-static int auto_congest(const void *data)
-{
-#ifdef SCHED_MULTITHREADED
- if (schedule_action(__auto_congest, data))
-#endif
- __auto_congest(data);
- return 0;
-}
-
-static unsigned int iax2_datetime(const char *tz)
-{
- time_t t;
- struct tm tm;
- unsigned int tmp;
- time(&t);
- if (!ast_strlen_zero(tz))
- ast_localtime(&t, &tm, tz);
- else
- ast_localtime(&t, &tm, NULL);
- tmp = (tm.tm_sec >> 1) & 0x1f; /* 5 bits of seconds */
- tmp |= (tm.tm_min & 0x3f) << 5; /* 6 bits of minutes */
- tmp |= (tm.tm_hour & 0x1f) << 11; /* 5 bits of hours */
- tmp |= (tm.tm_mday & 0x1f) << 16; /* 5 bits of day of month */
- tmp |= ((tm.tm_mon + 1) & 0xf) << 21; /* 4 bits of month */
- tmp |= ((tm.tm_year - 100) & 0x7f) << 25; /* 7 bits of year */
- return tmp;
-}
-
-struct parsed_dial_string {
- char *username;
- char *password;
- char *key;
- char *peer;
- char *port;
- char *exten;
- char *context;
- char *options;
-};
-
-static int send_apathetic_reply(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int command, int ts, unsigned char seqno)
-{
- struct ast_iax2_full_hdr f = { .scallno = htons(0x8000 | callno), .dcallno = htons(dcallno),
- .ts = htonl(ts), .iseqno = seqno, .oseqno = 0, .type = AST_FRAME_IAX,
- .csub = compress_subclass(command) };
-
- return sendto(defaultsockfd, &f, sizeof(f), 0, (struct sockaddr *)sin, sizeof(*sin));
-}
-
-/*!
- * \brief Parses an IAX dial string into its component parts.
- * \param data the string to be parsed
- * \param pds pointer to a \c struct \c parsed_dial_string to be filled in
- * \return nothing
- *
- * This function parses the string and fills the structure
- * with pointers to its component parts. The input string
- * will be modified.
- *
- * \note This function supports both plaintext passwords and RSA
- * key names; if the password string is formatted as '[keyname]',
- * then the keyname will be placed into the key field, and the
- * password field will be set to NULL.
- *
- * \note The dial string format is:
- * [username[:password]@]peer[:port][/exten[@@context]][/options]
- */
-static void parse_dial_string(char *data, struct parsed_dial_string *pds)
-{
- if (ast_strlen_zero(data))
- return;
-
- pds->peer = strsep(&data, "/");
- pds->exten = strsep(&data, "/");
- pds->options = data;
-
- if (pds->exten) {
- data = pds->exten;
- pds->exten = strsep(&data, "@");
- pds->context = data;
- }
-
- if (strchr(pds->peer, '@')) {
- data = pds->peer;
- pds->username = strsep(&data, "@");
- pds->peer = data;
- }
-
- if (pds->username) {
- data = pds->username;
- pds->username = strsep(&data, ":");
- pds->password = data;
- }
-
- data = pds->peer;
- pds->peer = strsep(&data, ":");
- pds->port = data;
-
- /* check for a key name wrapped in [] in the secret position, if found,
- move it to the key field instead
- */
- if (pds->password && (pds->password[0] == '[')) {
- pds->key = ast_strip_quoted(pds->password, "[", "]");
- pds->password = NULL;
- }
-}
-
-static int iax2_call(struct ast_channel *c, char *dest, int timeout)
-{
- struct sockaddr_in sin;
- char *l=NULL, *n=NULL, *tmpstr;
- struct iax_ie_data ied;
- char *defaultrdest = "s";
- unsigned short callno = PTR_TO_CALLNO(c->tech_pvt);
- struct parsed_dial_string pds;
- struct create_addr_info cai;
-
- if ((c->_state != AST_STATE_DOWN) && (c->_state != AST_STATE_RESERVED)) {
- ast_log(LOG_WARNING, "Channel is already in use (%s)?\n", c->name);
- return -1;
- }
-
- memset(&cai, 0, sizeof(cai));
- cai.encmethods = iax2_encryption;
-
- memset(&pds, 0, sizeof(pds));
- tmpstr = ast_strdupa(dest);
- parse_dial_string(tmpstr, &pds);
-
- if (ast_strlen_zero(pds.peer)) {
- ast_log(LOG_WARNING, "No peer provided in the IAX2 dial string '%s'\n", dest);
- return -1;
- }
-
- if (!pds.exten) {
- pds.exten = defaultrdest;
- }
-
- if (create_addr(pds.peer, c, &sin, &cai)) {
- ast_log(LOG_WARNING, "No address associated with '%s'\n", pds.peer);
- return -1;
- }
-
- if (!pds.username && !ast_strlen_zero(cai.username))
- pds.username = cai.username;
- if (!pds.password && !ast_strlen_zero(cai.secret))
- pds.password = cai.secret;
- if (!pds.key && !ast_strlen_zero(cai.outkey))
- pds.key = cai.outkey;
- if (!pds.context && !ast_strlen_zero(cai.peercontext))
- pds.context = cai.peercontext;
-
- /* Keep track of the context for outgoing calls too */
- ast_copy_string(c->context, cai.context, sizeof(c->context));
-
- if (pds.port)
- sin.sin_port = htons(atoi(pds.port));
-
- l = c->cid.cid_num;
- n = c->cid.cid_name;
-
- /* Now build request */
- memset(&ied, 0, sizeof(ied));
-
- /* On new call, first IE MUST be IAX version of caller */
- iax_ie_append_short(&ied, IAX_IE_VERSION, IAX_PROTO_VERSION);
- iax_ie_append_str(&ied, IAX_IE_CALLED_NUMBER, pds.exten);
- if (pds.options && strchr(pds.options, 'a')) {
- /* Request auto answer */
- iax_ie_append(&ied, IAX_IE_AUTOANSWER);
- }
-
- iax_ie_append_str(&ied, IAX_IE_CODEC_PREFS, cai.prefs);
-
- if (l) {
- iax_ie_append_str(&ied, IAX_IE_CALLING_NUMBER, l);
- iax_ie_append_byte(&ied, IAX_IE_CALLINGPRES, c->cid.cid_pres);
- } else {
- if (n)
- iax_ie_append_byte(&ied, IAX_IE_CALLINGPRES, c->cid.cid_pres);
- else
- iax_ie_append_byte(&ied, IAX_IE_CALLINGPRES, AST_PRES_NUMBER_NOT_AVAILABLE);
- }
-
- iax_ie_append_byte(&ied, IAX_IE_CALLINGTON, c->cid.cid_ton);
- iax_ie_append_short(&ied, IAX_IE_CALLINGTNS, c->cid.cid_tns);
-
- if (n)
- iax_ie_append_str(&ied, IAX_IE_CALLING_NAME, n);
- if (ast_test_flag(iaxs[callno], IAX_SENDANI) && c->cid.cid_ani)
- iax_ie_append_str(&ied, IAX_IE_CALLING_ANI, c->cid.cid_ani);
-
- if (!ast_strlen_zero(c->language))
- iax_ie_append_str(&ied, IAX_IE_LANGUAGE, c->language);
- if (!ast_strlen_zero(c->cid.cid_dnid))
- iax_ie_append_str(&ied, IAX_IE_DNID, c->cid.cid_dnid);
- if (!ast_strlen_zero(c->cid.cid_rdnis))
- iax_ie_append_str(&ied, IAX_IE_RDNIS, c->cid.cid_rdnis);
-
- if (pds.context)
- iax_ie_append_str(&ied, IAX_IE_CALLED_CONTEXT, pds.context);
-
- if (pds.username)
- iax_ie_append_str(&ied, IAX_IE_USERNAME, pds.username);
-
- if (cai.encmethods)
- iax_ie_append_short(&ied, IAX_IE_ENCRYPTION, cai.encmethods);
-
- ast_mutex_lock(&iaxsl[callno]);
-
- if (!ast_strlen_zero(c->context))
- ast_string_field_set(iaxs[callno], context, c->context);
-
- if (pds.username)
- ast_string_field_set(iaxs[callno], username, pds.username);
-
- iaxs[callno]->encmethods = cai.encmethods;
-
- iaxs[callno]->adsi = cai.adsi;
-
- ast_string_field_set(iaxs[callno], mohinterpret, cai.mohinterpret);
- ast_string_field_set(iaxs[callno], mohsuggest, cai.mohsuggest);
-
- if (pds.key)
- ast_string_field_set(iaxs[callno], outkey, pds.key);
- if (pds.password)
- ast_string_field_set(iaxs[callno], secret, pds.password);
-
- iax_ie_append_int(&ied, IAX_IE_FORMAT, c->nativeformats);
- iax_ie_append_int(&ied, IAX_IE_CAPABILITY, iaxs[callno]->capability);
- iax_ie_append_short(&ied, IAX_IE_ADSICPE, c->adsicpe);
- iax_ie_append_int(&ied, IAX_IE_DATETIME, iax2_datetime(cai.timezone));
-
- if (iaxs[callno]->maxtime) {
- /* Initialize pingtime and auto-congest time */
- iaxs[callno]->pingtime = iaxs[callno]->maxtime / 2;
- iaxs[callno]->initid = iax2_sched_add(sched, iaxs[callno]->maxtime * 2, auto_congest, CALLNO_TO_PTR(callno));
- } else if (autokill) {
- iaxs[callno]->pingtime = autokill / 2;
- iaxs[callno]->initid = iax2_sched_add(sched, autokill * 2, auto_congest, CALLNO_TO_PTR(callno));
- }
-
- /* send the command using the appropriate socket for this peer */
- iaxs[callno]->sockfd = cai.sockfd;
-
- /* Transmit the string in a "NEW" request */
- send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_NEW, 0, ied.buf, ied.pos, -1);
-
- ast_mutex_unlock(&iaxsl[callno]);
- ast_setstate(c, AST_STATE_RINGING);
-
- return 0;
-}
-
-static int iax2_hangup(struct ast_channel *c)
-{
- unsigned short callno = PTR_TO_CALLNO(c->tech_pvt);
- struct iax_ie_data ied;
- int alreadygone;
- memset(&ied, 0, sizeof(ied));
- ast_mutex_lock(&iaxsl[callno]);
- if (callno && iaxs[callno]) {
- if (option_debug)
- ast_log(LOG_DEBUG, "We're hanging up %s now...\n", c->name);
- alreadygone = ast_test_flag(iaxs[callno], IAX_ALREADYGONE);
- /* Send the hangup unless we have had a transmission error or are already gone */
- iax_ie_append_byte(&ied, IAX_IE_CAUSECODE, (unsigned char)c->hangupcause);
- if (!iaxs[callno]->error && !alreadygone) {
- if (send_command_final(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_HANGUP, 0, ied.buf, ied.pos, -1)) {
- ast_log(LOG_WARNING, "No final packet could be sent for callno %d\n", callno);
- }
- if (!iaxs[callno]) {
- ast_mutex_unlock(&iaxsl[callno]);
- return 0;
- }
- }
- /* Explicitly predestroy it */
- iax2_predestroy(callno);
- /* If we were already gone to begin with, destroy us now */
- if (iaxs[callno] && alreadygone) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Really destroying %s now...\n", c->name);
- iax2_destroy(callno);
- } else if (iaxs[callno]) {
- ast_sched_add(sched, 10000, scheduled_destroy, CALLNO_TO_PTR(callno));
- }
- } else if (c->tech_pvt) {
- /* If this call no longer exists, but the channel still
- * references it we need to set the channel's tech_pvt to null
- * to avoid ast_channel_free() trying to free it.
- */
- c->tech_pvt = NULL;
- }
- ast_mutex_unlock(&iaxsl[callno]);
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Hungup '%s'\n", c->name);
- return 0;
-}
-
-/*!
- * \note expects the pvt to be locked
- */
-static int wait_for_peercallno(struct chan_iax2_pvt *pvt)
-{
- unsigned short callno = pvt->callno;
-
- if (!pvt->peercallno) {
- /* We don't know the remote side's call number, yet. :( */
- int count = 10;
- while (count-- && pvt && !pvt->peercallno) {
- DEADLOCK_AVOIDANCE(&iaxsl[callno]);
- pvt = iaxs[callno];
- }
- if (!pvt->peercallno) {
- return -1;
- }
- }
-
- return 0;
-}
-
-static int iax2_setoption(struct ast_channel *c, int option, void *data, int datalen)
-{
- struct ast_option_header *h;
- int res;
-
- switch (option) {
- case AST_OPTION_TXGAIN:
- case AST_OPTION_RXGAIN:
- /* these two cannot be sent, because they require a result */
- errno = ENOSYS;
- return -1;
- default:
- {
- unsigned short callno = PTR_TO_CALLNO(c->tech_pvt);
- struct chan_iax2_pvt *pvt;
-
- ast_mutex_lock(&iaxsl[callno]);
- pvt = iaxs[callno];
-
- if (wait_for_peercallno(pvt)) {
- ast_mutex_unlock(&iaxsl[callno]);
- return -1;
- }
-
- ast_mutex_unlock(&iaxsl[callno]);
-
- if (!(h = ast_malloc(datalen + sizeof(*h)))) {
- return -1;
- }
-
- h->flag = AST_OPTION_FLAG_REQUEST;
- h->option = htons(option);
- memcpy(h->data, data, datalen);
- res = send_command_locked(PTR_TO_CALLNO(c->tech_pvt), AST_FRAME_CONTROL,
- AST_CONTROL_OPTION, 0, (unsigned char *) h,
- datalen + sizeof(*h), -1);
- free(h);
- return res;
- }
- }
-}
-
-static struct ast_frame *iax2_read(struct ast_channel *c)
-{
- ast_log(LOG_NOTICE, "I should never be called!\n");
- return &ast_null_frame;
-}
-
-static int iax2_start_transfer(unsigned short callno0, unsigned short callno1, int mediaonly)
-{
- int res;
- struct iax_ie_data ied0;
- struct iax_ie_data ied1;
- unsigned int transferid = (unsigned int)ast_random();
- memset(&ied0, 0, sizeof(ied0));
- iax_ie_append_addr(&ied0, IAX_IE_APPARENT_ADDR, &iaxs[callno1]->addr);
- iax_ie_append_short(&ied0, IAX_IE_CALLNO, iaxs[callno1]->peercallno);
- iax_ie_append_int(&ied0, IAX_IE_TRANSFERID, transferid);
-
- memset(&ied1, 0, sizeof(ied1));
- iax_ie_append_addr(&ied1, IAX_IE_APPARENT_ADDR, &iaxs[callno0]->addr);
- iax_ie_append_short(&ied1, IAX_IE_CALLNO, iaxs[callno0]->peercallno);
- iax_ie_append_int(&ied1, IAX_IE_TRANSFERID, transferid);
-
- res = send_command(iaxs[callno0], AST_FRAME_IAX, IAX_COMMAND_TXREQ, 0, ied0.buf, ied0.pos, -1);
- if (res)
- return -1;
- res = send_command(iaxs[callno1], AST_FRAME_IAX, IAX_COMMAND_TXREQ, 0, ied1.buf, ied1.pos, -1);
- if (res)
- return -1;
- iaxs[callno0]->transferring = mediaonly ? TRANSFER_MBEGIN : TRANSFER_BEGIN;
- iaxs[callno1]->transferring = mediaonly ? TRANSFER_MBEGIN : TRANSFER_BEGIN;
- return 0;
-}
-
-static void lock_both(unsigned short callno0, unsigned short callno1)
-{
- ast_mutex_lock(&iaxsl[callno0]);
- while (ast_mutex_trylock(&iaxsl[callno1])) {
- DEADLOCK_AVOIDANCE(&iaxsl[callno0]);
- }
-}
-
-static void unlock_both(unsigned short callno0, unsigned short callno1)
-{
- ast_mutex_unlock(&iaxsl[callno1]);
- ast_mutex_unlock(&iaxsl[callno0]);
-}
-
-static enum ast_bridge_result iax2_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms)
-{
- struct ast_channel *cs[3];
- struct ast_channel *who, *other;
- int to = -1;
- int res = -1;
- int transferstarted=0;
- struct ast_frame *f;
- unsigned short callno0 = PTR_TO_CALLNO(c0->tech_pvt);
- unsigned short callno1 = PTR_TO_CALLNO(c1->tech_pvt);
- struct timeval waittimer = {0, 0}, tv;
-
- lock_both(callno0, callno1);
- if (!iaxs[callno0] || !iaxs[callno1]) {
- unlock_both(callno0, callno1);
- return AST_BRIDGE_FAILED;
- }
- /* Put them in native bridge mode */
- if (!flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1)) {
- iaxs[callno0]->bridgecallno = callno1;
- iaxs[callno1]->bridgecallno = callno0;
- }
- /* If the bridge got retried, don't queue up more packets - the transfer request will be retransmitted as necessary */
- if (iaxs[callno0]->transferring && iaxs[callno1]->transferring) {
- transferstarted = 1;
- }
- unlock_both(callno0, callno1);
-
- /* If not, try to bridge until we can execute a transfer, if we can */
- cs[0] = c0;
- cs[1] = c1;
- for (/* ever */;;) {
- /* Check in case we got masqueraded into */
- if ((c0->tech != &iax2_tech) || (c1->tech != &iax2_tech)) {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Can't masquerade, we're different...\n");
- /* Remove from native mode */
- if (c0->tech == &iax2_tech) {
- ast_mutex_lock(&iaxsl[callno0]);
- iaxs[callno0]->bridgecallno = 0;
- ast_mutex_unlock(&iaxsl[callno0]);
- }
- if (c1->tech == &iax2_tech) {
- ast_mutex_lock(&iaxsl[callno1]);
- iaxs[callno1]->bridgecallno = 0;
- ast_mutex_unlock(&iaxsl[callno1]);
- }
- return AST_BRIDGE_FAILED_NOWARN;
- }
- if (c0->nativeformats != c1->nativeformats) {
- if (option_verbose > 2) {
- char buf0[255];
- char buf1[255];
- ast_getformatname_multiple(buf0, sizeof(buf0) -1, c0->nativeformats);
- ast_getformatname_multiple(buf1, sizeof(buf1) -1, c1->nativeformats);
- ast_verbose(VERBOSE_PREFIX_3 "Operating with different codecs %d[%s] %d[%s] , can't native bridge...\n", c0->nativeformats, buf0, c1->nativeformats, buf1);
- }
- /* Remove from native mode */
- lock_both(callno0, callno1);
- if (iaxs[callno0])
- iaxs[callno0]->bridgecallno = 0;
- if (iaxs[callno1])
- iaxs[callno1]->bridgecallno = 0;
- unlock_both(callno0, callno1);
- return AST_BRIDGE_FAILED_NOWARN;
- }
- /* check if transfered and if we really want native bridging */
- if (!transferstarted && !ast_test_flag(iaxs[callno0], IAX_NOTRANSFER) && !ast_test_flag(iaxs[callno1], IAX_NOTRANSFER)) {
- /* Try the transfer */
- if (iax2_start_transfer(callno0, callno1, (flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1)) ||
- ast_test_flag(iaxs[callno0], IAX_TRANSFERMEDIA) | ast_test_flag(iaxs[callno1], IAX_TRANSFERMEDIA)))
- ast_log(LOG_WARNING, "Unable to start the transfer\n");
- transferstarted = 1;
- }
- if ((iaxs[callno0]->transferring == TRANSFER_RELEASED) && (iaxs[callno1]->transferring == TRANSFER_RELEASED)) {
- /* Call has been transferred. We're no longer involved */
- gettimeofday(&tv, NULL);
- if (ast_tvzero(waittimer)) {
- waittimer = tv;
- } else if (tv.tv_sec - waittimer.tv_sec > IAX_LINGER_TIMEOUT) {
- c0->_softhangup |= AST_SOFTHANGUP_DEV;
- c1->_softhangup |= AST_SOFTHANGUP_DEV;
- *fo = NULL;
- *rc = c0;
- res = AST_BRIDGE_COMPLETE;
- break;
- }
- }
- to = 1000;
- who = ast_waitfor_n(cs, 2, &to);
- if (timeoutms > -1) {
- timeoutms -= (1000 - to);
- if (timeoutms < 0)
- timeoutms = 0;
- }
- if (!who) {
- if (!timeoutms) {
- res = AST_BRIDGE_RETRY;
- break;
- }
- if (ast_check_hangup(c0) || ast_check_hangup(c1)) {
- res = AST_BRIDGE_FAILED;
- break;
- }
- continue;
- }
- f = ast_read(who);
- if (!f) {
- *fo = NULL;
- *rc = who;
- res = AST_BRIDGE_COMPLETE;
- break;
- }
- if ((f->frametype == AST_FRAME_CONTROL) && !(flags & AST_BRIDGE_IGNORE_SIGS)) {
- *fo = f;
- *rc = who;
- res = AST_BRIDGE_COMPLETE;
- break;
- }
- other = (who == c0) ? c1 : c0; /* the 'other' channel */
- if ((f->frametype == AST_FRAME_VOICE) ||
- (f->frametype == AST_FRAME_TEXT) ||
- (f->frametype == AST_FRAME_VIDEO) ||
- (f->frametype == AST_FRAME_IMAGE) ||
- (f->frametype == AST_FRAME_DTMF)) {
- /* monitored dtmf take out of the bridge.
- * check if we monitor the specific source.
- */
- int monitored_source = (who == c0) ? AST_BRIDGE_DTMF_CHANNEL_0 : AST_BRIDGE_DTMF_CHANNEL_1;
- if (f->frametype == AST_FRAME_DTMF && (flags & monitored_source)) {
- *rc = who;
- *fo = f;
- res = AST_BRIDGE_COMPLETE;
- /* Remove from native mode */
- break;
- }
- /* everything else goes to the other side */
- ast_write(other, f);
- }
- ast_frfree(f);
- /* Swap who gets priority */
- cs[2] = cs[0];
- cs[0] = cs[1];
- cs[1] = cs[2];
- }
- lock_both(callno0, callno1);
- if(iaxs[callno0])
- iaxs[callno0]->bridgecallno = 0;
- if(iaxs[callno1])
- iaxs[callno1]->bridgecallno = 0;
- unlock_both(callno0, callno1);
- return res;
-}
-
-static int iax2_answer(struct ast_channel *c)
-{
- unsigned short callno = PTR_TO_CALLNO(c->tech_pvt);
- if (option_debug)
- ast_log(LOG_DEBUG, "Answering IAX2 call\n");
- return send_command_locked(callno, AST_FRAME_CONTROL, AST_CONTROL_ANSWER, 0, NULL, 0, -1);
-}
-
-static int iax2_indicate(struct ast_channel *c, int condition, const void *data, size_t datalen)
-{
- unsigned short callno = PTR_TO_CALLNO(c->tech_pvt);
- struct chan_iax2_pvt *pvt;
- int res = 0;
-
- if (option_debug && iaxdebug)
- ast_log(LOG_DEBUG, "Indicating condition %d\n", condition);
-
- ast_mutex_lock(&iaxsl[callno]);
- pvt = iaxs[callno];
-
- if (wait_for_peercallno(pvt)) {
- res = -1;
- goto done;
- }
-
- switch (condition) {
- case AST_CONTROL_HOLD:
- if (strcasecmp(pvt->mohinterpret, "passthrough")) {
- ast_moh_start(c, data, pvt->mohinterpret);
- goto done;
- }
- break;
- case AST_CONTROL_UNHOLD:
- if (strcasecmp(pvt->mohinterpret, "passthrough")) {
- ast_moh_stop(c);
- goto done;
- }
- }
-
- res = send_command(pvt, AST_FRAME_CONTROL, condition, 0, data, datalen, -1);
-
-done:
- ast_mutex_unlock(&iaxsl[callno]);
-
- return res;
-}
-
-static int iax2_transfer(struct ast_channel *c, const char *dest)
-{
- unsigned short callno = PTR_TO_CALLNO(c->tech_pvt);
- struct iax_ie_data ied;
- char tmp[256], *context;
- ast_copy_string(tmp, dest, sizeof(tmp));
- context = strchr(tmp, '@');
- if (context) {
- *context = '\0';
- context++;
- }
- memset(&ied, 0, sizeof(ied));
- iax_ie_append_str(&ied, IAX_IE_CALLED_NUMBER, tmp);
- if (context)
- iax_ie_append_str(&ied, IAX_IE_CALLED_CONTEXT, context);
- if (option_debug)
- ast_log(LOG_DEBUG, "Transferring '%s' to '%s'\n", c->name, dest);
- return send_command_locked(callno, AST_FRAME_IAX, IAX_COMMAND_TRANSFER, 0, ied.buf, ied.pos, -1);
-}
-
-static int iax2_getpeertrunk(struct sockaddr_in sin)
-{
- struct iax2_peer *peer;
- int res = 0;
- struct ao2_iterator i;
-
- i = ao2_iterator_init(peers, 0);
- while ((peer = ao2_iterator_next(&i))) {
- if ((peer->addr.sin_addr.s_addr == sin.sin_addr.s_addr) &&
- (peer->addr.sin_port == sin.sin_port)) {
- res = ast_test_flag(peer, IAX_TRUNK);
- peer_unref(peer);
- break;
- }
- peer_unref(peer);
- }
-
- return res;
-}
-
-/*! \brief Create new call, interface with the PBX core */
-static struct ast_channel *ast_iax2_new(int callno, int state, int capability)
-{
- struct ast_channel *tmp;
- struct chan_iax2_pvt *i;
- struct ast_variable *v = NULL;
-
- if (!(i = iaxs[callno])) {
- ast_log(LOG_WARNING, "No IAX2 pvt found for callno '%d' !\n", callno);
- return NULL;
- }
-
- /* Don't hold call lock */
- ast_mutex_unlock(&iaxsl[callno]);
- tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, i->accountcode, i->exten, i->context, i->amaflags, "IAX2/%s-%d", i->host, i->callno);
- ast_mutex_lock(&iaxsl[callno]);
- if (i != iaxs[callno]) {
- if (tmp) {
- /* unlock and relock iaxsl[callno] to preserve locking order */
- ast_mutex_unlock(&iaxsl[callno]);
- ast_channel_free(tmp);
- ast_mutex_lock(&iaxsl[callno]);
- }
- return NULL;
- }
-
- if (!tmp)
- return NULL;
- tmp->tech = &iax2_tech;
- /* We can support any format by default, until we get restricted */
- tmp->nativeformats = capability;
- tmp->readformat = tmp->rawreadformat = ast_best_codec(capability);
- tmp->writeformat = tmp->rawwriteformat = ast_best_codec(capability);
- tmp->tech_pvt = CALLNO_TO_PTR(i->callno);
-
- /* Don't use ast_set_callerid() here because it will
- * generate a NewCallerID event before the NewChannel event */
- if (!ast_strlen_zero(i->ani))
- tmp->cid.cid_ani = ast_strdup(i->ani);
- else
- tmp->cid.cid_ani = ast_strdup(i->cid_num);
- tmp->cid.cid_dnid = ast_strdup(i->dnid);
- tmp->cid.cid_rdnis = ast_strdup(i->rdnis);
- tmp->cid.cid_pres = i->calling_pres;
- tmp->cid.cid_ton = i->calling_ton;
- tmp->cid.cid_tns = i->calling_tns;
- if (!ast_strlen_zero(i->language))
- ast_string_field_set(tmp, language, i->language);
- if (!ast_strlen_zero(i->accountcode))
- ast_string_field_set(tmp, accountcode, i->accountcode);
- if (i->amaflags)
- tmp->amaflags = i->amaflags;
- ast_copy_string(tmp->context, i->context, sizeof(tmp->context));
- ast_copy_string(tmp->exten, i->exten, sizeof(tmp->exten));
- if (i->adsi)
- tmp->adsicpe = i->peeradsicpe;
- else
- tmp->adsicpe = AST_ADSI_UNAVAILABLE;
- i->owner = tmp;
- i->capability = capability;
-
- for (v = i->vars ; v ; v = v->next)
- pbx_builtin_setvar_helper(tmp, v->name, v->value);
-
- if (state != AST_STATE_DOWN) {
- if (ast_pbx_start(tmp)) {
- ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
- ast_hangup(tmp);
- i->owner = NULL;
- return NULL;
- }
- }
-
- ast_module_ref(ast_module_info->self);
-
- return tmp;
-}
-
-static unsigned int calc_txpeerstamp(struct iax2_trunk_peer *tpeer, int sampms, struct timeval *tv)
-{
- unsigned long int mssincetx; /* unsigned to handle overflows */
- long int ms, pred;
-
- tpeer->trunkact = *tv;
- mssincetx = ast_tvdiff_ms(*tv, tpeer->lasttxtime);
- if (mssincetx > 5000 || ast_tvzero(tpeer->txtrunktime)) {
- /* If it's been at least 5 seconds since the last time we transmitted on this trunk, reset our timers */
- tpeer->txtrunktime = *tv;
- tpeer->lastsent = 999999;
- }
- /* Update last transmit time now */
- tpeer->lasttxtime = *tv;
-
- /* Calculate ms offset */
- ms = ast_tvdiff_ms(*tv, tpeer->txtrunktime);
- /* Predict from last value */
- pred = tpeer->lastsent + sampms;
- if (abs(ms - pred) < MAX_TIMESTAMP_SKEW)
- ms = pred;
-
- /* We never send the same timestamp twice, so fudge a little if we must */
- if (ms == tpeer->lastsent)
- ms = tpeer->lastsent + 1;
- tpeer->lastsent = ms;
- return ms;
-}
-
-static unsigned int fix_peerts(struct timeval *tv, int callno, unsigned int ts)
-{
- long ms; /* NOT unsigned */
- if (ast_tvzero(iaxs[callno]->rxcore)) {
- /* Initialize rxcore time if appropriate */
- gettimeofday(&iaxs[callno]->rxcore, NULL);
- /* Round to nearest 20ms so traces look pretty */
- iaxs[callno]->rxcore.tv_usec -= iaxs[callno]->rxcore.tv_usec % 20000;
- }
- /* Calculate difference between trunk and channel */
- ms = ast_tvdiff_ms(*tv, iaxs[callno]->rxcore);
- /* Return as the sum of trunk time and the difference between trunk and real time */
- return ms + ts;
-}
-
-static unsigned int calc_timestamp(struct chan_iax2_pvt *p, unsigned int ts, struct ast_frame *f)
-{
- int ms;
- int voice = 0;
- int genuine = 0;
- int adjust;
- struct timeval *delivery = NULL;
-
-
- /* What sort of frame do we have?: voice is self-explanatory
- "genuine" means an IAX frame - things like LAGRQ/RP, PING/PONG, ACK
- non-genuine frames are CONTROL frames [ringing etc], DTMF
- The "genuine" distinction is needed because genuine frames must get a clock-based timestamp,
- the others need a timestamp slaved to the voice frames so that they go in sequence
- */
- if (f) {
- if (f->frametype == AST_FRAME_VOICE) {
- voice = 1;
- delivery = &f->delivery;
- } else if (f->frametype == AST_FRAME_IAX) {
- genuine = 1;
- } else if (f->frametype == AST_FRAME_CNG) {
- p->notsilenttx = 0;
- }
- }
- if (ast_tvzero(p->offset)) {
- gettimeofday(&p->offset, NULL);
- /* Round to nearest 20ms for nice looking traces */
- p->offset.tv_usec -= p->offset.tv_usec % 20000;
- }
- /* If the timestamp is specified, just send it as is */
- if (ts)
- return ts;
- /* If we have a time that the frame arrived, always use it to make our timestamp */
- if (delivery && !ast_tvzero(*delivery)) {
- ms = ast_tvdiff_ms(*delivery, p->offset);
- if (option_debug > 2 && iaxdebug)
- ast_log(LOG_DEBUG, "calc_timestamp: call %d/%d: Timestamp slaved to delivery time\n", p->callno, iaxs[p->callno]->peercallno);
- } else {
- ms = ast_tvdiff_ms(ast_tvnow(), p->offset);
- if (ms < 0)
- ms = 0;
- if (voice) {
- /* On a voice frame, use predicted values if appropriate */
- if (p->notsilenttx && abs(ms - p->nextpred) <= MAX_TIMESTAMP_SKEW) {
- /* Adjust our txcore, keeping voice and non-voice synchronized */
- /* AN EXPLANATION:
- When we send voice, we usually send "calculated" timestamps worked out
- on the basis of the number of samples sent. When we send other frames,
- we usually send timestamps worked out from the real clock.
- The problem is that they can tend to drift out of step because the
- source channel's clock and our clock may not be exactly at the same rate.
- We fix this by continuously "tweaking" p->offset. p->offset is "time zero"
- for this call. Moving it adjusts timestamps for non-voice frames.
- We make the adjustment in the style of a moving average. Each time we
- adjust p->offset by 10% of the difference between our clock-derived
- timestamp and the predicted timestamp. That's why you see "10000"
- below even though IAX2 timestamps are in milliseconds.
- The use of a moving average avoids offset moving too radically.
- Generally, "adjust" roams back and forth around 0, with offset hardly
- changing at all. But if a consistent different starts to develop it
- will be eliminated over the course of 10 frames (200-300msecs)
- */
- adjust = (ms - p->nextpred);
- if (adjust < 0)
- p->offset = ast_tvsub(p->offset, ast_samp2tv(abs(adjust), 10000));
- else if (adjust > 0)
- p->offset = ast_tvadd(p->offset, ast_samp2tv(adjust, 10000));
-
- if (!p->nextpred) {
- p->nextpred = ms; /*f->samples / 8;*/
- if (p->nextpred <= p->lastsent)
- p->nextpred = p->lastsent + 3;
- }
- ms = p->nextpred;
- } else {
- /* in this case, just use the actual
- * time, since we're either way off
- * (shouldn't happen), or we're ending a
- * silent period -- and seed the next
- * predicted time. Also, round ms to the
- * next multiple of frame size (so our
- * silent periods are multiples of
- * frame size too) */
-
- if (option_debug && iaxdebug && abs(ms - p->nextpred) > MAX_TIMESTAMP_SKEW )
- ast_log(LOG_DEBUG, "predicted timestamp skew (%u) > max (%u), using real ts instead.\n",
- abs(ms - p->nextpred), MAX_TIMESTAMP_SKEW);
-
- if (f->samples >= 8) /* check to make sure we dont core dump */
- {
- int diff = ms % (f->samples / 8);
- if (diff)
- ms += f->samples/8 - diff;
- }
-
- p->nextpred = ms;
- p->notsilenttx = 1;
- }
- } else if ( f->frametype == AST_FRAME_VIDEO ) {
- /*
- * IAX2 draft 03 says that timestamps MUST be in order.
- * It does not say anything about several frames having the same timestamp
- * When transporting video, we can have a frame that spans multiple iax packets
- * (so called slices), so it would make sense to use the same timestamp for all of
- * them
- * We do want to make sure that frames don't go backwards though
- */
- if ( (unsigned int)ms < p->lastsent )
- ms = p->lastsent;
- } else {
- /* On a dataframe, use last value + 3 (to accomodate jitter buffer shrinking) if appropriate unless
- it's a genuine frame */
- if (genuine) {
- /* genuine (IAX LAGRQ etc) must keep their clock-based stamps */
- if (ms <= p->lastsent)
- ms = p->lastsent + 3;
- } else if (abs(ms - p->lastsent) <= MAX_TIMESTAMP_SKEW) {
- /* non-genuine frames (!?) (DTMF, CONTROL) should be pulled into the predicted stream stamps */
- ms = p->lastsent + 3;
- }
- }
- }
- p->lastsent = ms;
- if (voice)
- p->nextpred = p->nextpred + f->samples / 8;
- return ms;
-}
-
-static unsigned int calc_rxstamp(struct chan_iax2_pvt *p, unsigned int offset)
-{
- /* Returns where in "receive time" we are. That is, how many ms
- since we received (or would have received) the frame with timestamp 0 */
- int ms;
-#ifdef IAXTESTS
- int jit;
-#endif /* IAXTESTS */
- /* Setup rxcore if necessary */
- if (ast_tvzero(p->rxcore)) {
- p->rxcore = ast_tvnow();
- if (option_debug && iaxdebug)
- ast_log(LOG_DEBUG, "calc_rxstamp: call=%d: rxcore set to %d.%6.6d - %dms\n",
- p->callno, (int)(p->rxcore.tv_sec), (int)(p->rxcore.tv_usec), offset);
- p->rxcore = ast_tvsub(p->rxcore, ast_samp2tv(offset, 1000));
-#if 1
- if (option_debug && iaxdebug)
- ast_log(LOG_DEBUG, "calc_rxstamp: call=%d: works out as %d.%6.6d\n",
- p->callno, (int)(p->rxcore.tv_sec),(int)( p->rxcore.tv_usec));
-#endif
- }
-
- ms = ast_tvdiff_ms(ast_tvnow(), p->rxcore);
-#ifdef IAXTESTS
- if (test_jit) {
- if (!test_jitpct || ((100.0 * ast_random() / (RAND_MAX + 1.0)) < test_jitpct)) {
- jit = (int)((float)test_jit * ast_random() / (RAND_MAX + 1.0));
- if ((int)(2.0 * ast_random() / (RAND_MAX + 1.0)))
- jit = -jit;
- ms += jit;
- }
- }
- if (test_late) {
- ms += test_late;
- test_late = 0;
- }
-#endif /* IAXTESTS */
- return ms;
-}
-
-static struct iax2_trunk_peer *find_tpeer(struct sockaddr_in *sin, int fd)
-{
- struct iax2_trunk_peer *tpeer;
-
- /* Finds and locks trunk peer */
- ast_mutex_lock(&tpeerlock);
- for (tpeer = tpeers; tpeer; tpeer = tpeer->next) {
- /* We don't lock here because tpeer->addr *never* changes */
- if (!inaddrcmp(&tpeer->addr, sin)) {
- ast_mutex_lock(&tpeer->lock);
- break;
- }
- }
- if (!tpeer) {
- if ((tpeer = ast_calloc(1, sizeof(*tpeer)))) {
- ast_mutex_init(&tpeer->lock);
- tpeer->lastsent = 9999;
- memcpy(&tpeer->addr, sin, sizeof(tpeer->addr));
- tpeer->trunkact = ast_tvnow();
- ast_mutex_lock(&tpeer->lock);
- tpeer->next = tpeers;
- tpeer->sockfd = fd;
- tpeers = tpeer;
-#ifdef SO_NO_CHECK
- setsockopt(tpeer->sockfd, SOL_SOCKET, SO_NO_CHECK, &nochecksums, sizeof(nochecksums));
-#endif
- if (option_debug)
- ast_log(LOG_DEBUG, "Created trunk peer for '%s:%d'\n", ast_inet_ntoa(tpeer->addr.sin_addr), ntohs(tpeer->addr.sin_port));
- }
- }
- ast_mutex_unlock(&tpeerlock);
- return tpeer;
-}
-
-static int iax2_trunk_queue(struct chan_iax2_pvt *pvt, struct iax_frame *fr)
-{
- struct ast_frame *f;
- struct iax2_trunk_peer *tpeer;
- void *tmp, *ptr;
- struct ast_iax2_meta_trunk_entry *met;
- struct ast_iax2_meta_trunk_mini *mtm;
-
- f = &fr->af;
- tpeer = find_tpeer(&pvt->addr, pvt->sockfd);
- if (tpeer) {
- if (tpeer->trunkdatalen + f->datalen + 4 >= tpeer->trunkdataalloc) {
- /* Need to reallocate space */
- if (tpeer->trunkdataalloc < MAX_TRUNKDATA) {
- if (!(tmp = ast_realloc(tpeer->trunkdata, tpeer->trunkdataalloc + DEFAULT_TRUNKDATA + IAX2_TRUNK_PREFACE))) {
- ast_mutex_unlock(&tpeer->lock);
- return -1;
- }
-
- tpeer->trunkdataalloc += DEFAULT_TRUNKDATA;
- tpeer->trunkdata = tmp;
- if (option_debug)
- ast_log(LOG_DEBUG, "Expanded trunk '%s:%d' to %d bytes\n", ast_inet_ntoa(tpeer->addr.sin_addr), ntohs(tpeer->addr.sin_port), tpeer->trunkdataalloc);
- } else {
- ast_log(LOG_WARNING, "Maximum trunk data space exceeded to %s:%d\n", ast_inet_ntoa(tpeer->addr.sin_addr), ntohs(tpeer->addr.sin_port));
- ast_mutex_unlock(&tpeer->lock);
- return -1;
- }
- }
-
- /* Append to meta frame */
- ptr = tpeer->trunkdata + IAX2_TRUNK_PREFACE + tpeer->trunkdatalen;
- if (ast_test_flag(&globalflags, IAX_TRUNKTIMESTAMPS)) {
- mtm = (struct ast_iax2_meta_trunk_mini *)ptr;
- mtm->len = htons(f->datalen);
- mtm->mini.callno = htons(pvt->callno);
- mtm->mini.ts = htons(0xffff & fr->ts);
- ptr += sizeof(struct ast_iax2_meta_trunk_mini);
- tpeer->trunkdatalen += sizeof(struct ast_iax2_meta_trunk_mini);
- } else {
- met = (struct ast_iax2_meta_trunk_entry *)ptr;
- /* Store call number and length in meta header */
- met->callno = htons(pvt->callno);
- met->len = htons(f->datalen);
- /* Advance pointers/decrease length past trunk entry header */
- ptr += sizeof(struct ast_iax2_meta_trunk_entry);
- tpeer->trunkdatalen += sizeof(struct ast_iax2_meta_trunk_entry);
- }
- /* Copy actual trunk data */
- memcpy(ptr, f->data, f->datalen);
- tpeer->trunkdatalen += f->datalen;
-
- tpeer->calls++;
- ast_mutex_unlock(&tpeer->lock);
- }
- return 0;
-}
-
-static void build_enc_keys(const unsigned char *digest, aes_encrypt_ctx *ecx, aes_decrypt_ctx *dcx)
-{
- aes_encrypt_key128(digest, ecx);
- aes_decrypt_key128(digest, dcx);
-}
-
-static void memcpy_decrypt(unsigned char *dst, const unsigned char *src, int len, aes_decrypt_ctx *dcx)
-{
-#if 0
- /* Debug with "fake encryption" */
- int x;
- if (len % 16)
- ast_log(LOG_WARNING, "len should be multiple of 16, not %d!\n", len);
- for (x=0;x<len;x++)
- dst[x] = src[x] ^ 0xff;
-#else
- unsigned char lastblock[16] = { 0 };
- int x;
- while(len > 0) {
- aes_decrypt(src, dst, dcx);
- for (x=0;x<16;x++)
- dst[x] ^= lastblock[x];
- memcpy(lastblock, src, sizeof(lastblock));
- dst += 16;
- src += 16;
- len -= 16;
- }
-#endif
-}
-
-static void memcpy_encrypt(unsigned char *dst, const unsigned char *src, int len, aes_encrypt_ctx *ecx)
-{
-#if 0
- /* Debug with "fake encryption" */
- int x;
- if (len % 16)
- ast_log(LOG_WARNING, "len should be multiple of 16, not %d!\n", len);
- for (x=0;x<len;x++)
- dst[x] = src[x] ^ 0xff;
-#else
- unsigned char curblock[16] = { 0 };
- int x;
- while(len > 0) {
- for (x=0;x<16;x++)
- curblock[x] ^= src[x];
- aes_encrypt(curblock, dst, ecx);
- memcpy(curblock, dst, sizeof(curblock));
- dst += 16;
- src += 16;
- len -= 16;
- }
-#endif
-}
-
-static int decode_frame(aes_decrypt_ctx *dcx, struct ast_iax2_full_hdr *fh, struct ast_frame *f, int *datalen)
-{
- int padding;
- unsigned char *workspace;
-
- workspace = alloca(*datalen);
- memset(f, 0, sizeof(*f));
- if (ntohs(fh->scallno) & IAX_FLAG_FULL) {
- struct ast_iax2_full_enc_hdr *efh = (struct ast_iax2_full_enc_hdr *)fh;
- if (*datalen < 16 + sizeof(struct ast_iax2_full_hdr))
- return -1;
- /* Decrypt */
- memcpy_decrypt(workspace, efh->encdata, *datalen - sizeof(struct ast_iax2_full_enc_hdr), dcx);
-
- padding = 16 + (workspace[15] & 0xf);
- if (option_debug && iaxdebug)
- ast_log(LOG_DEBUG, "Decoding full frame with length %d (padding = %d) (15=%02x)\n", *datalen, padding, workspace[15]);
- if (*datalen < padding + sizeof(struct ast_iax2_full_hdr))
- return -1;
-
- *datalen -= padding;
- memcpy(efh->encdata, workspace + padding, *datalen - sizeof(struct ast_iax2_full_enc_hdr));
- f->frametype = fh->type;
- if (f->frametype == AST_FRAME_VIDEO) {
- f->subclass = uncompress_subclass(fh->csub & ~0x40) | ((fh->csub >> 6) & 0x1);
- } else {
- f->subclass = uncompress_subclass(fh->csub);
- }
- } else {
- struct ast_iax2_mini_enc_hdr *efh = (struct ast_iax2_mini_enc_hdr *)fh;
- if (option_debug && iaxdebug)
- ast_log(LOG_DEBUG, "Decoding mini with length %d\n", *datalen);
- if (*datalen < 16 + sizeof(struct ast_iax2_mini_hdr))
- return -1;
- /* Decrypt */
- memcpy_decrypt(workspace, efh->encdata, *datalen - sizeof(struct ast_iax2_mini_enc_hdr), dcx);
- padding = 16 + (workspace[15] & 0x0f);
- if (*datalen < padding + sizeof(struct ast_iax2_mini_hdr))
- return -1;
- *datalen -= padding;
- memcpy(efh->encdata, workspace + padding, *datalen - sizeof(struct ast_iax2_mini_enc_hdr));
- }
- return 0;
-}
-
-static int encrypt_frame(aes_encrypt_ctx *ecx, struct ast_iax2_full_hdr *fh, unsigned char *poo, int *datalen)
-{
- int padding;
- unsigned char *workspace;
- workspace = alloca(*datalen + 32);
- if (!workspace)
- return -1;
- if (ntohs(fh->scallno) & IAX_FLAG_FULL) {
- struct ast_iax2_full_enc_hdr *efh = (struct ast_iax2_full_enc_hdr *)fh;
- if (option_debug && iaxdebug)
- ast_log(LOG_DEBUG, "Encoding full frame %d/%d with length %d\n", fh->type, fh->csub, *datalen);
- padding = 16 - ((*datalen - sizeof(struct ast_iax2_full_enc_hdr)) % 16);
- padding = 16 + (padding & 0xf);
- memcpy(workspace, poo, padding);
- memcpy(workspace + padding, efh->encdata, *datalen - sizeof(struct ast_iax2_full_enc_hdr));
- workspace[15] &= 0xf0;
- workspace[15] |= (padding & 0xf);
- if (option_debug && iaxdebug)
- ast_log(LOG_DEBUG, "Encoding full frame %d/%d with length %d + %d padding (15=%02x)\n", fh->type, fh->csub, *datalen, padding, workspace[15]);
- *datalen += padding;
- memcpy_encrypt(efh->encdata, workspace, *datalen - sizeof(struct ast_iax2_full_enc_hdr), ecx);
- if (*datalen >= 32 + sizeof(struct ast_iax2_full_enc_hdr))
- memcpy(poo, workspace + *datalen - 32, 32);
- } else {
- struct ast_iax2_mini_enc_hdr *efh = (struct ast_iax2_mini_enc_hdr *)fh;
- if (option_debug && iaxdebug)
- ast_log(LOG_DEBUG, "Encoding mini frame with length %d\n", *datalen);
- padding = 16 - ((*datalen - sizeof(struct ast_iax2_mini_enc_hdr)) % 16);
- padding = 16 + (padding & 0xf);
- memcpy(workspace, poo, padding);
- memcpy(workspace + padding, efh->encdata, *datalen - sizeof(struct ast_iax2_mini_enc_hdr));
- workspace[15] &= 0xf0;
- workspace[15] |= (padding & 0x0f);
- *datalen += padding;
- memcpy_encrypt(efh->encdata, workspace, *datalen - sizeof(struct ast_iax2_mini_enc_hdr), ecx);
- if (*datalen >= 32 + sizeof(struct ast_iax2_mini_enc_hdr))
- memcpy(poo, workspace + *datalen - 32, 32);
- }
- return 0;
-}
-
-static int decrypt_frame(int callno, struct ast_iax2_full_hdr *fh, struct ast_frame *f, int *datalen)
-{
- int res=-1;
- if (!ast_test_flag(iaxs[callno], IAX_KEYPOPULATED)) {
- /* Search for possible keys, given secrets */
- struct MD5Context md5;
- unsigned char digest[16];
- char *tmppw, *stringp;
-
- tmppw = ast_strdupa(iaxs[callno]->secret);
- stringp = tmppw;
- while ((tmppw = strsep(&stringp, ";"))) {
- MD5Init(&md5);
- MD5Update(&md5, (unsigned char *)iaxs[callno]->challenge, strlen(iaxs[callno]->challenge));
- MD5Update(&md5, (unsigned char *)tmppw, strlen(tmppw));
- MD5Final(digest, &md5);
- build_enc_keys(digest, &iaxs[callno]->ecx, &iaxs[callno]->dcx);
- res = decode_frame(&iaxs[callno]->dcx, fh, f, datalen);
- if (!res) {
- ast_set_flag(iaxs[callno], IAX_KEYPOPULATED);
- break;
- }
- }
- } else
- res = decode_frame(&iaxs[callno]->dcx, fh, f, datalen);
- return res;
-}
-
-static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned int ts, int seqno, int now, int transfer, int final)
-{
- /* Queue a packet for delivery on a given private structure. Use "ts" for
- timestamp, or calculate if ts is 0. Send immediately without retransmission
- or delayed, with retransmission */
- struct ast_iax2_full_hdr *fh;
- struct ast_iax2_mini_hdr *mh;
- struct ast_iax2_video_hdr *vh;
- struct {
- struct iax_frame fr2;
- unsigned char buffer[4096];
- } frb;
- struct iax_frame *fr;
- int res;
- int sendmini=0;
- unsigned int lastsent;
- unsigned int fts;
-
- frb.fr2.afdatalen = sizeof(frb.buffer);
-
- if (!pvt) {
- ast_log(LOG_WARNING, "No private structure for packet?\n");
- return -1;
- }
-
- lastsent = pvt->lastsent;
-
- /* Calculate actual timestamp */
- fts = calc_timestamp(pvt, ts, f);
-
- /* Bail here if this is an "interp" frame; we don't want or need to send these placeholders out
- * (the endpoint should detect the lost packet itself). But, we want to do this here, so that we
- * increment the "predicted timestamps" for voice, if we're predecting */
- if(f->frametype == AST_FRAME_VOICE && f->datalen == 0)
- return 0;
-
-
- if ((ast_test_flag(pvt, IAX_TRUNK) ||
- (((fts & 0xFFFF0000L) == (lastsent & 0xFFFF0000L)) ||
- ((fts & 0xFFFF0000L) == ((lastsent + 0x10000) & 0xFFFF0000L))))
- /* High two bytes are the same on timestamp, or sending on a trunk */ &&
- (f->frametype == AST_FRAME_VOICE)
- /* is a voice frame */ &&
- (f->subclass == pvt->svoiceformat)
- /* is the same type */ ) {
- /* Force immediate rather than delayed transmission */
- now = 1;
- /* Mark that mini-style frame is appropriate */
- sendmini = 1;
- }
- if ( f->frametype == AST_FRAME_VIDEO ) {
- /*
- * If the lower 15 bits of the timestamp roll over, or if
- * the video format changed then send a full frame.
- * Otherwise send a mini video frame
- */
- if (((fts & 0xFFFF8000L) == (pvt->lastvsent & 0xFFFF8000L)) &&
- ((f->subclass & ~0x1) == pvt->svideoformat)
- ) {
- now = 1;
- sendmini = 1;
- } else {
- now = 0;
- sendmini = 0;
- }
- pvt->lastvsent = fts;
- }
- /* Allocate an iax_frame */
- if (now) {
- fr = &frb.fr2;
- } else
- fr = iax_frame_new(DIRECTION_OUTGRESS, ast_test_flag(pvt, IAX_ENCRYPTED) ? f->datalen + 32 : f->datalen, (f->frametype == AST_FRAME_VOICE) || (f->frametype == AST_FRAME_VIDEO));
- if (!fr) {
- ast_log(LOG_WARNING, "Out of memory\n");
- return -1;
- }
- /* Copy our prospective frame into our immediate or retransmitted wrapper */
- iax_frame_wrap(fr, f);
-
- fr->ts = fts;
- fr->callno = pvt->callno;
- fr->transfer = transfer;
- fr->final = final;
- if (!sendmini) {
- /* We need a full frame */
- if (seqno > -1)
- fr->oseqno = seqno;
- else
- fr->oseqno = pvt->oseqno++;
- fr->iseqno = pvt->iseqno;
- fh = (struct ast_iax2_full_hdr *)(fr->af.data - sizeof(struct ast_iax2_full_hdr));
- fh->scallno = htons(fr->callno | IAX_FLAG_FULL);
- fh->ts = htonl(fr->ts);
- fh->oseqno = fr->oseqno;
- if (transfer) {
- fh->iseqno = 0;
- } else
- fh->iseqno = fr->iseqno;
- /* Keep track of the last thing we've acknowledged */
- if (!transfer)
- pvt->aseqno = fr->iseqno;
- fh->type = fr->af.frametype & 0xFF;
- if (fr->af.frametype == AST_FRAME_VIDEO)
- fh->csub = compress_subclass(fr->af.subclass & ~0x1) | ((fr->af.subclass & 0x1) << 6);
- else
- fh->csub = compress_subclass(fr->af.subclass);
- if (transfer) {
- fr->dcallno = pvt->transfercallno;
- } else
- fr->dcallno = pvt->peercallno;
- fh->dcallno = htons(fr->dcallno);
- fr->datalen = fr->af.datalen + sizeof(struct ast_iax2_full_hdr);
- fr->data = fh;
- fr->retries = 0;
- /* Retry after 2x the ping time has passed */
- fr->retrytime = pvt->pingtime * 2;
- if (fr->retrytime < MIN_RETRY_TIME)
- fr->retrytime = MIN_RETRY_TIME;
- if (fr->retrytime > MAX_RETRY_TIME)
- fr->retrytime = MAX_RETRY_TIME;
- /* Acks' don't get retried */
- if ((f->frametype == AST_FRAME_IAX) && (f->subclass == IAX_COMMAND_ACK))
- fr->retries = -1;
- else if (f->frametype == AST_FRAME_VOICE)
- pvt->svoiceformat = f->subclass;
- else if (f->frametype == AST_FRAME_VIDEO)
- pvt->svideoformat = f->subclass & ~0x1;
- if (ast_test_flag(pvt, IAX_ENCRYPTED)) {
- if (ast_test_flag(pvt, IAX_KEYPOPULATED)) {
- if (iaxdebug) {
- if (fr->transfer)
- iax_showframe(fr, NULL, 2, &pvt->transfer, fr->datalen - sizeof(struct ast_iax2_full_hdr));
- else
- iax_showframe(fr, NULL, 2, &pvt->addr, fr->datalen - sizeof(struct ast_iax2_full_hdr));
- }
- encrypt_frame(&pvt->ecx, fh, pvt->semirand, &fr->datalen);
- } else
- ast_log(LOG_WARNING, "Supposed to send packet encrypted, but no key?\n");
- }
-
- if (now) {
- res = send_packet(fr);
- } else
- res = iax2_transmit(fr);
- } else {
- if (ast_test_flag(pvt, IAX_TRUNK)) {
- iax2_trunk_queue(pvt, fr);
- res = 0;
- } else if (fr->af.frametype == AST_FRAME_VIDEO) {
- /* Video frame have no sequence number */
- fr->oseqno = -1;
- fr->iseqno = -1;
- vh = (struct ast_iax2_video_hdr *)(fr->af.data - sizeof(struct ast_iax2_video_hdr));
- vh->zeros = 0;
- vh->callno = htons(0x8000 | fr->callno);
- vh->ts = htons((fr->ts & 0x7FFF) | (fr->af.subclass & 0x1 ? 0x8000 : 0));
- fr->datalen = fr->af.datalen + sizeof(struct ast_iax2_video_hdr);
- fr->data = vh;
- fr->retries = -1;
- res = send_packet(fr);
- } else {
- /* Mini-frames have no sequence number */
- fr->oseqno = -1;
- fr->iseqno = -1;
- /* Mini frame will do */
- mh = (struct ast_iax2_mini_hdr *)(fr->af.data - sizeof(struct ast_iax2_mini_hdr));
- mh->callno = htons(fr->callno);
- mh->ts = htons(fr->ts & 0xFFFF);
- fr->datalen = fr->af.datalen + sizeof(struct ast_iax2_mini_hdr);
- fr->data = mh;
- fr->retries = -1;
- if (pvt->transferring == TRANSFER_MEDIAPASS)
- fr->transfer = 1;
- if (ast_test_flag(pvt, IAX_ENCRYPTED)) {
- if (ast_test_flag(pvt, IAX_KEYPOPULATED)) {
- encrypt_frame(&pvt->ecx, (struct ast_iax2_full_hdr *)mh, pvt->semirand, &fr->datalen);
- } else
- ast_log(LOG_WARNING, "Supposed to send packet encrypted, but no key?\n");
- }
- res = send_packet(fr);
- }
- }
- return res;
-}
-
-static int iax2_show_users(int fd, int argc, char *argv[])
-{
- regex_t regexbuf;
- int havepattern = 0;
-
-#define FORMAT "%-15.15s %-20.20s %-15.15s %-15.15s %-5.5s %-5.10s\n"
-#define FORMAT2 "%-15.15s %-20.20s %-15.15d %-15.15s %-5.5s %-5.10s\n"
-
- struct iax2_user *user = NULL;
- char auth[90];
- char *pstr = "";
- struct ao2_iterator i;
-
- switch (argc) {
- case 5:
- if (!strcasecmp(argv[3], "like")) {
- if (regcomp(&regexbuf, argv[4], REG_EXTENDED | REG_NOSUB))
- return RESULT_SHOWUSAGE;
- havepattern = 1;
- } else
- return RESULT_SHOWUSAGE;
- case 3:
- break;
- default:
- return RESULT_SHOWUSAGE;
- }
-
- ast_cli(fd, FORMAT, "Username", "Secret", "Authen", "Def.Context", "A/C","Codec Pref");
- i = ao2_iterator_init(users, 0);
- for (user = ao2_iterator_next(&i); user;
- user_unref(user), user = ao2_iterator_next(&i)) {
- if (havepattern && regexec(&regexbuf, user->name, 0, NULL, 0))
- continue;
-
- if (!ast_strlen_zero(user->secret)) {
- ast_copy_string(auth,user->secret,sizeof(auth));
- } else if (!ast_strlen_zero(user->inkeys)) {
- snprintf(auth, sizeof(auth), "Key: %-15.15s ", user->inkeys);
- } else
- ast_copy_string(auth, "-no secret-", sizeof(auth));
-
- if(ast_test_flag(user,IAX_CODEC_NOCAP))
- pstr = "REQ Only";
- else if(ast_test_flag(user,IAX_CODEC_NOPREFS))
- pstr = "Disabled";
- else
- pstr = ast_test_flag(user,IAX_CODEC_USER_FIRST) ? "Caller" : "Host";
-
- ast_cli(fd, FORMAT2, user->name, auth, user->authmethods,
- user->contexts ? user->contexts->context : context,
- user->ha ? "Yes" : "No", pstr);
- }
-
- if (havepattern)
- regfree(&regexbuf);
-
- return RESULT_SUCCESS;
-#undef FORMAT
-#undef FORMAT2
-}
-
-static int __iax2_show_peers(int manager, int fd, struct mansession *s, int argc, char *argv[])
-{
- regex_t regexbuf;
- int havepattern = 0;
- int total_peers = 0;
- int online_peers = 0;
- int offline_peers = 0;
- int unmonitored_peers = 0;
- struct ao2_iterator i;
-
-#define FORMAT2 "%-15.15s %-15.15s %s %-15.15s %-8s %s %-10s%s"
-#define FORMAT "%-15.15s %-15.15s %s %-15.15s %-5d%s %s %-10s%s"
-
- struct iax2_peer *peer = NULL;
- char name[256];
- int registeredonly=0;
- char *term = manager ? "\r\n" : "\n";
-
- switch (argc) {
- case 6:
- if (!strcasecmp(argv[3], "registered"))
- registeredonly = 1;
- else
- return RESULT_SHOWUSAGE;
- if (!strcasecmp(argv[4], "like")) {
- if (regcomp(&regexbuf, argv[5], REG_EXTENDED | REG_NOSUB))
- return RESULT_SHOWUSAGE;
- havepattern = 1;
- } else
- return RESULT_SHOWUSAGE;
- break;
- case 5:
- if (!strcasecmp(argv[3], "like")) {
- if (regcomp(&regexbuf, argv[4], REG_EXTENDED | REG_NOSUB))
- return RESULT_SHOWUSAGE;
- havepattern = 1;
- } else
- return RESULT_SHOWUSAGE;
- break;
- case 4:
- if (!strcasecmp(argv[3], "registered"))
- registeredonly = 1;
- else
- return RESULT_SHOWUSAGE;
- break;
- case 3:
- break;
- default:
- return RESULT_SHOWUSAGE;
- }
-
-
- if (s)
- astman_append(s, FORMAT2, "Name/Username", "Host", " ", "Mask", "Port", " ", "Status", term);
- else
- ast_cli(fd, FORMAT2, "Name/Username", "Host", " ", "Mask", "Port", " ", "Status", term);
-
- i = ao2_iterator_init(peers, 0);
- for (peer = ao2_iterator_next(&i); peer;
- peer_unref(peer), peer = ao2_iterator_next(&i)) {
- char nm[20];
- char status[20];
- char srch[2000];
- int retstatus;
-
- if (registeredonly && !peer->addr.sin_addr.s_addr)
- continue;
- if (havepattern && regexec(&regexbuf, peer->name, 0, NULL, 0))
- continue;
-
- if (!ast_strlen_zero(peer->username))
- snprintf(name, sizeof(name), "%s/%s", peer->name, peer->username);
- else
- ast_copy_string(name, peer->name, sizeof(name));
-
- retstatus = peer_status(peer, status, sizeof(status));
- if (retstatus > 0)
- online_peers++;
- else if (!retstatus)
- offline_peers++;
- else
- unmonitored_peers++;
-
- ast_copy_string(nm, ast_inet_ntoa(peer->mask), sizeof(nm));
-
- snprintf(srch, sizeof(srch), FORMAT, name,
- peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "(Unspecified)",
- ast_test_flag(peer, IAX_DYNAMIC) ? "(D)" : "(S)",
- nm,
- ntohs(peer->addr.sin_port), ast_test_flag(peer, IAX_TRUNK) ? "(T)" : " ",
- peer->encmethods ? "(E)" : " ", status, term);
-
- if (s)
- astman_append(s, FORMAT, name,
- peer->addr.sin_addr.s_addr ? ast_inet_ntoa( peer->addr.sin_addr) : "(Unspecified)",
- ast_test_flag(peer, IAX_DYNAMIC) ? "(D)" : "(S)",
- nm,
- ntohs(peer->addr.sin_port), ast_test_flag(peer, IAX_TRUNK) ? "(T)" : " ",
- peer->encmethods ? "(E)" : " ", status, term);
- else
- ast_cli(fd, FORMAT, name,
- peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "(Unspecified)",
- ast_test_flag(peer, IAX_DYNAMIC) ? "(D)" : "(S)",
- nm,
- ntohs(peer->addr.sin_port), ast_test_flag(peer, IAX_TRUNK) ? "(T)" : " ",
- peer->encmethods ? "(E)" : " ", status, term);
- total_peers++;
- }
-
- if (s)
- astman_append(s,"%d iax2 peers [%d online, %d offline, %d unmonitored]%s", total_peers, online_peers, offline_peers, unmonitored_peers, term);
- else
- ast_cli(fd,"%d iax2 peers [%d online, %d offline, %d unmonitored]%s", total_peers, online_peers, offline_peers, unmonitored_peers, term);
-
- if (havepattern)
- regfree(&regexbuf);
-
- return RESULT_SUCCESS;
-#undef FORMAT
-#undef FORMAT2
-}
-
-static int iax2_show_threads(int fd, int argc, char *argv[])
-{
- struct iax2_thread *thread = NULL;
- time_t t;
- int threadcount = 0, dynamiccount = 0;
- char type;
-
- if (argc != 3)
- return RESULT_SHOWUSAGE;
-
- ast_cli(fd, "IAX2 Thread Information\n");
- time(&t);
- ast_cli(fd, "Idle Threads:\n");
- AST_LIST_LOCK(&idle_list);
- AST_LIST_TRAVERSE(&idle_list, thread, list) {
-#ifdef DEBUG_SCHED_MULTITHREAD
- ast_cli(fd, "Thread %d: state=%d, update=%d, actions=%d, func ='%s'\n",
- thread->threadnum, thread->iostate, (int)(t - thread->checktime), thread->actions, thread->curfunc);
-#else
- ast_cli(fd, "Thread %d: state=%d, update=%d, actions=%d\n",
- thread->threadnum, thread->iostate, (int)(t - thread->checktime), thread->actions);
-#endif
- threadcount++;
- }
- AST_LIST_UNLOCK(&idle_list);
- ast_cli(fd, "Active Threads:\n");
- AST_LIST_LOCK(&active_list);
- AST_LIST_TRAVERSE(&active_list, thread, list) {
- if (thread->type == IAX_TYPE_DYNAMIC)
- type = 'D';
- else
- type = 'P';
-#ifdef DEBUG_SCHED_MULTITHREAD
- ast_cli(fd, "Thread %c%d: state=%d, update=%d, actions=%d, func ='%s'\n",
- type, thread->threadnum, thread->iostate, (int)(t - thread->checktime), thread->actions, thread->curfunc);
-#else
- ast_cli(fd, "Thread %c%d: state=%d, update=%d, actions=%d\n",
- type, thread->threadnum, thread->iostate, (int)(t - thread->checktime), thread->actions);
-#endif
- threadcount++;
- }
- AST_LIST_UNLOCK(&active_list);
- ast_cli(fd, "Dynamic Threads:\n");
- AST_LIST_LOCK(&dynamic_list);
- AST_LIST_TRAVERSE(&dynamic_list, thread, list) {
-#ifdef DEBUG_SCHED_MULTITHREAD
- ast_cli(fd, "Thread %d: state=%d, update=%d, actions=%d, func ='%s'\n",
- thread->threadnum, thread->iostate, (int)(t - thread->checktime), thread->actions, thread->curfunc);
-#else
- ast_cli(fd, "Thread %d: state=%d, update=%d, actions=%d\n",
- thread->threadnum, thread->iostate, (int)(t - thread->checktime), thread->actions);
-#endif
- dynamiccount++;
- }
- AST_LIST_UNLOCK(&dynamic_list);
- ast_cli(fd, "%d of %d threads accounted for with %d dynamic threads\n", threadcount, iaxthreadcount, dynamiccount);
- return RESULT_SUCCESS;
-}
-
-static int iax2_show_peers(int fd, int argc, char *argv[])
-{
- return __iax2_show_peers(0, fd, NULL, argc, argv);
-}
-static int manager_iax2_show_netstats(struct mansession *s, const struct message *m)
-{
- ast_cli_netstats(s, -1, 0);
- astman_append(s, "\r\n");
- return RESULT_SUCCESS;
-}
-
-static int iax2_show_firmware(int fd, int argc, char *argv[])
-{
-#define FORMAT2 "%-15.15s %-15.15s %-15.15s\n"
-#if !defined(__FreeBSD__)
-#define FORMAT "%-15.15s %-15d %-15d\n"
-#else /* __FreeBSD__ */
-#define FORMAT "%-15.15s %-15d %-15d\n" /* XXX 2.95 ? */
-#endif /* __FreeBSD__ */
- struct iax_firmware *cur;
- if ((argc != 3) && (argc != 4))
- return RESULT_SHOWUSAGE;
- ast_mutex_lock(&waresl.lock);
-
- ast_cli(fd, FORMAT2, "Device", "Version", "Size");
- for (cur = waresl.wares;cur;cur = cur->next) {
- if ((argc == 3) || (!strcasecmp(argv[3], (char *)cur->fwh->devname)))
- ast_cli(fd, FORMAT, cur->fwh->devname, ntohs(cur->fwh->version),
- (int)ntohl(cur->fwh->datalen));
- }
- ast_mutex_unlock(&waresl.lock);
- return RESULT_SUCCESS;
-#undef FORMAT
-#undef FORMAT2
-}
-
-/* JDG: callback to display iax peers in manager */
-static int manager_iax2_show_peers(struct mansession *s, const struct message *m)
-{
- char *a[] = { "iax2", "show", "users" };
- int ret;
- const char *id = astman_get_header(m,"ActionID");
-
- if (!ast_strlen_zero(id))
- astman_append(s, "ActionID: %s\r\n",id);
- ret = __iax2_show_peers(1, -1, s, 3, a );
- astman_append(s, "\r\n\r\n" );
- return ret;
-} /* /JDG */
-
-static char *regstate2str(int regstate)
-{
- switch(regstate) {
- case REG_STATE_UNREGISTERED:
- return "Unregistered";
- case REG_STATE_REGSENT:
- return "Request Sent";
- case REG_STATE_AUTHSENT:
- return "Auth. Sent";
- case REG_STATE_REGISTERED:
- return "Registered";
- case REG_STATE_REJECTED:
- return "Rejected";
- case REG_STATE_TIMEOUT:
- return "Timeout";
- case REG_STATE_NOAUTH:
- return "No Authentication";
- default:
- return "Unknown";
- }
-}
-
-static int iax2_show_registry(int fd, int argc, char *argv[])
-{
-#define FORMAT2 "%-20.20s %-6.6s %-10.10s %-20.20s %8.8s %s\n"
-#define FORMAT "%-20.20s %-6.6s %-10.10s %-20.20s %8d %s\n"
- struct iax2_registry *reg = NULL;
-
- char host[80];
- char perceived[80];
- if (argc != 3)
- return RESULT_SHOWUSAGE;
- ast_cli(fd, FORMAT2, "Host", "dnsmgr", "Username", "Perceived", "Refresh", "State");
- AST_LIST_LOCK(&registrations);
- AST_LIST_TRAVERSE(&registrations, reg, entry) {
- snprintf(host, sizeof(host), "%s:%d", ast_inet_ntoa(reg->addr.sin_addr), ntohs(reg->addr.sin_port));
- if (reg->us.sin_addr.s_addr)
- snprintf(perceived, sizeof(perceived), "%s:%d", ast_inet_ntoa(reg->us.sin_addr), ntohs(reg->us.sin_port));
- else
- ast_copy_string(perceived, "<Unregistered>", sizeof(perceived));
- ast_cli(fd, FORMAT, host,
- (reg->dnsmgr) ? "Y" : "N",
- reg->username, perceived, reg->refresh, regstate2str(reg->regstate));
- }
- AST_LIST_UNLOCK(&registrations);
- return RESULT_SUCCESS;
-#undef FORMAT
-#undef FORMAT2
-}
-
-static int iax2_show_channels(int fd, int argc, char *argv[])
-{
-#define FORMAT2 "%-20.20s %-15.15s %-10.10s %-11.11s %-11.11s %-7.7s %-6.6s %-6.6s %s\n"
-#define FORMAT "%-20.20s %-15.15s %-10.10s %5.5d/%5.5d %5.5d/%5.5d %-5.5dms %-4.4dms %-4.4dms %-6.6s\n"
-#define FORMATB "%-20.20s %-15.15s %-10.10s %5.5d/%5.5d %5.5d/%5.5d [Native Bridged to ID=%5.5d]\n"
- int x;
- int numchans = 0;
-
- if (argc != 3)
- return RESULT_SHOWUSAGE;
- ast_cli(fd, FORMAT2, "Channel", "Peer", "Username", "ID (Lo/Rem)", "Seq (Tx/Rx)", "Lag", "Jitter", "JitBuf", "Format");
- for (x = 0; x < ARRAY_LEN(iaxs); x++) {
- ast_mutex_lock(&iaxsl[x]);
- if (iaxs[x]) {
- int lag, jitter, localdelay;
- jb_info jbinfo;
-
- if(ast_test_flag(iaxs[x], IAX_USEJITTERBUF)) {
- jb_getinfo(iaxs[x]->jb, &jbinfo);
- jitter = jbinfo.jitter;
- localdelay = jbinfo.current - jbinfo.min;
- } else {
- jitter = -1;
- localdelay = 0;
- }
- lag = iaxs[x]->remote_rr.delay;
- ast_cli(fd, FORMAT,
- iaxs[x]->owner ? iaxs[x]->owner->name : "(None)",
- ast_inet_ntoa(iaxs[x]->addr.sin_addr),
- S_OR(iaxs[x]->username, "(None)"),
- iaxs[x]->callno, iaxs[x]->peercallno,
- iaxs[x]->oseqno, iaxs[x]->iseqno,
- lag,
- jitter,
- localdelay,
- ast_getformatname(iaxs[x]->voiceformat) );
- numchans++;
- }
- ast_mutex_unlock(&iaxsl[x]);
- }
- ast_cli(fd, "%d active IAX channel%s\n", numchans, (numchans != 1) ? "s" : "");
- return RESULT_SUCCESS;
-#undef FORMAT
-#undef FORMAT2
-#undef FORMATB
-}
-
-static int ast_cli_netstats(struct mansession *s, int fd, int limit_fmt)
-{
- int x;
- int numchans = 0;
- for (x = 0; x < ARRAY_LEN(iaxs); x++) {
- ast_mutex_lock(&iaxsl[x]);
- if (iaxs[x]) {
- int localjitter, localdelay, locallost, locallosspct, localdropped, localooo;
- char *fmt;
- jb_info jbinfo;
-
- if(ast_test_flag(iaxs[x], IAX_USEJITTERBUF)) {
- jb_getinfo(iaxs[x]->jb, &jbinfo);
- localjitter = jbinfo.jitter;
- localdelay = jbinfo.current - jbinfo.min;
- locallost = jbinfo.frames_lost;
- locallosspct = jbinfo.losspct/1000;
- localdropped = jbinfo.frames_dropped;
- localooo = jbinfo.frames_ooo;
- } else {
- localjitter = -1;
- localdelay = 0;
- locallost = -1;
- locallosspct = -1;
- localdropped = 0;
- localooo = -1;
- }
- if (limit_fmt)
- fmt = "%-25.25s %4d %4d %4d %5d %3d %5d %4d %6d %4d %4d %5d %3d %5d %4d %6d\n";
- else
- fmt = "%s %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n";
- if (s)
-
- astman_append(s, fmt,
- iaxs[x]->owner ? iaxs[x]->owner->name : "(None)",
- iaxs[x]->pingtime,
- localjitter,
- localdelay,
- locallost,
- locallosspct,
- localdropped,
- localooo,
- iaxs[x]->frames_received/1000,
- iaxs[x]->remote_rr.jitter,
- iaxs[x]->remote_rr.delay,
- iaxs[x]->remote_rr.losscnt,
- iaxs[x]->remote_rr.losspct,
- iaxs[x]->remote_rr.dropped,
- iaxs[x]->remote_rr.ooo,
- iaxs[x]->remote_rr.packets/1000);
- else
- ast_cli(fd, fmt,
- iaxs[x]->owner ? iaxs[x]->owner->name : "(None)",
- iaxs[x]->pingtime,
- localjitter,
- localdelay,
- locallost,
- locallosspct,
- localdropped,
- localooo,
- iaxs[x]->frames_received/1000,
- iaxs[x]->remote_rr.jitter,
- iaxs[x]->remote_rr.delay,
- iaxs[x]->remote_rr.losscnt,
- iaxs[x]->remote_rr.losspct,
- iaxs[x]->remote_rr.dropped,
- iaxs[x]->remote_rr.ooo,
- iaxs[x]->remote_rr.packets/1000
- );
- numchans++;
- }
- ast_mutex_unlock(&iaxsl[x]);
- }
- return numchans;
-}
-
-static int iax2_show_netstats(int fd, int argc, char *argv[])
-{
- int numchans = 0;
- if (argc != 3)
- return RESULT_SHOWUSAGE;
- ast_cli(fd, " -------- LOCAL --------------------- -------- REMOTE --------------------\n");
- ast_cli(fd, "Channel RTT Jit Del Lost %% Drop OOO Kpkts Jit Del Lost %% Drop OOO Kpkts\n");
- numchans = ast_cli_netstats(NULL, fd, 1);
- ast_cli(fd, "%d active IAX channel%s\n", numchans, (numchans != 1) ? "s" : "");
- return RESULT_SUCCESS;
-}
-
-static int iax2_do_debug(int fd, int argc, char *argv[])
-{
- if (argc < 2 || argc > 3)
- return RESULT_SHOWUSAGE;
- iaxdebug = 1;
- ast_cli(fd, "IAX2 Debugging Enabled\n");
- return RESULT_SUCCESS;
-}
-
-static int iax2_do_trunk_debug(int fd, int argc, char *argv[])
-{
- if (argc < 3 || argc > 4)
- return RESULT_SHOWUSAGE;
- iaxtrunkdebug = 1;
- ast_cli(fd, "IAX2 Trunk Debug Requested\n");
- return RESULT_SUCCESS;
-}
-
-static int iax2_do_jb_debug(int fd, int argc, char *argv[])
-{
- if (argc < 3 || argc > 4)
- return RESULT_SHOWUSAGE;
- jb_setoutput(jb_error_output, jb_warning_output, jb_debug_output);
- ast_cli(fd, "IAX2 Jitterbuffer Debugging Enabled\n");
- return RESULT_SUCCESS;
-}
-
-static int iax2_no_debug(int fd, int argc, char *argv[])
-{
- if (argc < 3 || argc > 4)
- return RESULT_SHOWUSAGE;
- iaxdebug = 0;
- ast_cli(fd, "IAX2 Debugging Disabled\n");
- return RESULT_SUCCESS;
-}
-
-static int iax2_no_trunk_debug(int fd, int argc, char *argv[])
-{
- if (argc < 4 || argc > 5)
- return RESULT_SHOWUSAGE;
- iaxtrunkdebug = 0;
- ast_cli(fd, "IAX2 Trunk Debugging Disabled\n");
- return RESULT_SUCCESS;
-}
-
-static int iax2_no_jb_debug(int fd, int argc, char *argv[])
-{
- if (argc < 4 || argc > 5)
- return RESULT_SHOWUSAGE;
- jb_setoutput(jb_error_output, jb_warning_output, NULL);
- jb_debug_output("\n");
- ast_cli(fd, "IAX2 Jitterbuffer Debugging Disabled\n");
- return RESULT_SUCCESS;
-}
-
-static int iax2_write(struct ast_channel *c, struct ast_frame *f)
-{
- unsigned short callno = PTR_TO_CALLNO(c->tech_pvt);
- int res = -1;
- ast_mutex_lock(&iaxsl[callno]);
- if (iaxs[callno]) {
- /* If there's an outstanding error, return failure now */
- if (!iaxs[callno]->error) {
- if (ast_test_flag(iaxs[callno], IAX_ALREADYGONE))
- res = 0;
- /* Don't waste bandwidth sending null frames */
- else if (f->frametype == AST_FRAME_NULL)
- res = 0;
- else if ((f->frametype == AST_FRAME_VOICE) && ast_test_flag(iaxs[callno], IAX_QUELCH))
- res = 0;
- else if (!ast_test_flag(&iaxs[callno]->state, IAX_STATE_STARTED))
- res = 0;
- else
- /* Simple, just queue for transmission */
- res = iax2_send(iaxs[callno], f, 0, -1, 0, 0, 0);
- } else {
- if (option_debug)
- ast_log(LOG_DEBUG, "Write error: %s\n", strerror(errno));
- }
- }
- /* If it's already gone, just return */
- ast_mutex_unlock(&iaxsl[callno]);
- return res;
-}
-
-static int __send_command(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, const unsigned char *data, int datalen, int seqno,
- int now, int transfer, int final)
-{
- struct ast_frame f = { 0, };
-
- f.frametype = type;
- f.subclass = command;
- f.datalen = datalen;
- f.src = __FUNCTION__;
- f.data = (void *) data;
-
- return iax2_send(i, &f, ts, seqno, now, transfer, final);
-}
-
-static int send_command(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, const unsigned char *data, int datalen, int seqno)
-{
- return __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 0);
-}
-
-static int send_command_locked(unsigned short callno, char type, int command, unsigned int ts, const unsigned char *data, int datalen, int seqno)
-{
- int res;
- ast_mutex_lock(&iaxsl[callno]);
- res = send_command(iaxs[callno], type, command, ts, data, datalen, seqno);
- ast_mutex_unlock(&iaxsl[callno]);
- return res;
-}
-
-/*!
- * \note Since this function calls iax2_predestroy() -> iax2_queue_hangup(),
- * the pvt struct for the given call number may disappear during its
- * execution.
- */
-static int send_command_final(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, const unsigned char *data, int datalen, int seqno)
-{
- int call_num = i->callno;
- /* It is assumed that the callno has already been locked */
- iax2_predestroy(i->callno);
- if (!iaxs[call_num])
- return -1;
- return __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 1);
-}
-
-static int send_command_immediate(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, const unsigned char *data, int datalen, int seqno)
-{
- return __send_command(i, type, command, ts, data, datalen, seqno, 1, 0, 0);
-}
-
-static int send_command_transfer(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, const unsigned char *data, int datalen)
-{
- return __send_command(i, type, command, ts, data, datalen, 0, 0, 1, 0);
-}
-
-static int apply_context(struct iax2_context *con, const char *context)
-{
- while(con) {
- if (!strcmp(con->context, context) || !strcmp(con->context, "*"))
- return -1;
- con = con->next;
- }
- return 0;
-}
-
-
-static int check_access(int callno, struct sockaddr_in *sin, struct iax_ies *ies)
-{
- /* Start pessimistic */
- int res = -1;
- int version = 2;
- struct iax2_user *user = NULL, *best = NULL;
- int bestscore = 0;
- int gotcapability = 0;
- struct ast_variable *v = NULL, *tmpvar = NULL;
- struct ao2_iterator i;
-
- if (!iaxs[callno])
- return res;
- if (ies->called_number)
- ast_string_field_set(iaxs[callno], exten, ies->called_number);
- if (ies->calling_number) {
- ast_shrink_phone_number(ies->calling_number);
- ast_string_field_set(iaxs[callno], cid_num, ies->calling_number);
- }
- if (ies->calling_name)
- ast_string_field_set(iaxs[callno], cid_name, ies->calling_name);
- if (ies->calling_ani)
- ast_string_field_set(iaxs[callno], ani, ies->calling_ani);
- if (ies->dnid)
- ast_string_field_set(iaxs[callno], dnid, ies->dnid);
- if (ies->rdnis)
- ast_string_field_set(iaxs[callno], rdnis, ies->rdnis);
- if (ies->called_context)
- ast_string_field_set(iaxs[callno], context, ies->called_context);
- if (ies->language)
- ast_string_field_set(iaxs[callno], language, ies->language);
- if (ies->username)
- ast_string_field_set(iaxs[callno], username, ies->username);
- if (ies->calling_ton > -1)
- iaxs[callno]->calling_ton = ies->calling_ton;
- if (ies->calling_tns > -1)
- iaxs[callno]->calling_tns = ies->calling_tns;
- if (ies->calling_pres > -1)
- iaxs[callno]->calling_pres = ies->calling_pres;
- if (ies->format)
- iaxs[callno]->peerformat = ies->format;
- if (ies->adsicpe)
- iaxs[callno]->peeradsicpe = ies->adsicpe;
- if (ies->capability) {
- gotcapability = 1;
- iaxs[callno]->peercapability = ies->capability;
- }
- if (ies->version)
- version = ies->version;
-
- /* Use provided preferences until told otherwise for actual preferences */
- if(ies->codec_prefs) {
- ast_codec_pref_convert(&iaxs[callno]->rprefs, ies->codec_prefs, 32, 0);
- ast_codec_pref_convert(&iaxs[callno]->prefs, ies->codec_prefs, 32, 0);
- }
-
- if (!gotcapability)
- iaxs[callno]->peercapability = iaxs[callno]->peerformat;
- if (version > IAX_PROTO_VERSION) {
- ast_log(LOG_WARNING, "Peer '%s' has too new a protocol version (%d) for me\n",
- ast_inet_ntoa(sin->sin_addr), version);
- return res;
- }
- /* Search the userlist for a compatible entry, and fill in the rest */
- i = ao2_iterator_init(users, 0);
- while ((user = ao2_iterator_next(&i))) {
- if ((ast_strlen_zero(iaxs[callno]->username) || /* No username specified */
- !strcmp(iaxs[callno]->username, user->name)) /* Or this username specified */
- && ast_apply_ha(user->ha, sin) /* Access is permitted from this IP */
- && (ast_strlen_zero(iaxs[callno]->context) || /* No context specified */
- apply_context(user->contexts, iaxs[callno]->context))) { /* Context is permitted */
- if (!ast_strlen_zero(iaxs[callno]->username)) {
- /* Exact match, stop right now. */
- if (best)
- user_unref(best);
- best = user;
- break;
- } else if (ast_strlen_zero(user->secret) && ast_strlen_zero(user->dbsecret) && ast_strlen_zero(user->inkeys)) {
- /* No required authentication */
- if (user->ha) {
- /* There was host authentication and we passed, bonus! */
- if (bestscore < 4) {
- bestscore = 4;
- if (best)
- user_unref(best);
- best = user;
- continue;
- }
- } else {
- /* No host access, but no secret, either, not bad */
- if (bestscore < 3) {
- bestscore = 3;
- if (best)
- user_unref(best);
- best = user;
- continue;
- }
- }
- } else {
- if (user->ha) {
- /* Authentication, but host access too, eh, it's something.. */
- if (bestscore < 2) {
- bestscore = 2;
- if (best)
- user_unref(best);
- best = user;
- continue;
- }
- } else {
- /* Authentication and no host access... This is our baseline */
- if (bestscore < 1) {
- bestscore = 1;
- if (best)
- user_unref(best);
- best = user;
- continue;
- }
- }
- }
- }
- user_unref(user);
- }
- user = best;
- if (!user && !ast_strlen_zero(iaxs[callno]->username)) {
- user = realtime_user(iaxs[callno]->username, sin);
- if (user && !ast_strlen_zero(iaxs[callno]->context) && /* No context specified */
- !apply_context(user->contexts, iaxs[callno]->context)) { /* Context is permitted */
- user = user_unref(user);
- }
- }
- if (user) {
- /* We found our match (use the first) */
- /* copy vars */
- for (v = user->vars ; v ; v = v->next) {
- if((tmpvar = ast_variable_new(v->name, v->value))) {
- tmpvar->next = iaxs[callno]->vars;
- iaxs[callno]->vars = tmpvar;
- }
- }
- /* If a max AUTHREQ restriction is in place, activate it */
- if (user->maxauthreq > 0)
- ast_set_flag(iaxs[callno], IAX_MAXAUTHREQ);
- iaxs[callno]->prefs = user->prefs;
- ast_copy_flags(iaxs[callno], user, IAX_CODEC_USER_FIRST);
- ast_copy_flags(iaxs[callno], user, IAX_CODEC_NOPREFS);
- ast_copy_flags(iaxs[callno], user, IAX_CODEC_NOCAP);
- iaxs[callno]->encmethods = user->encmethods;
- /* Store the requested username if not specified */
- if (ast_strlen_zero(iaxs[callno]->username))
- ast_string_field_set(iaxs[callno], username, user->name);
- /* Store whether this is a trunked call, too, of course, and move if appropriate */
- ast_copy_flags(iaxs[callno], user, IAX_TRUNK);
- iaxs[callno]->capability = user->capability;
- /* And use the default context */
- if (ast_strlen_zero(iaxs[callno]->context)) {
- if (user->contexts)
- ast_string_field_set(iaxs[callno], context, user->contexts->context);
- else
- ast_string_field_set(iaxs[callno], context, context);
- }
- /* And any input keys */
- ast_string_field_set(iaxs[callno], inkeys, user->inkeys);
- /* And the permitted authentication methods */
- iaxs[callno]->authmethods = user->authmethods;
- iaxs[callno]->adsi = user->adsi;
- /* If the user has callerid, override the remote caller id. */
- if (ast_test_flag(user, IAX_HASCALLERID)) {
- iaxs[callno]->calling_tns = 0;
- iaxs[callno]->calling_ton = 0;
- ast_string_field_set(iaxs[callno], cid_num, user->cid_num);
- ast_string_field_set(iaxs[callno], cid_name, user->cid_name);
- ast_string_field_set(iaxs[callno], ani, user->cid_num);
- iaxs[callno]->calling_pres = AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN;
- } else if (ast_strlen_zero(iaxs[callno]->cid_num) && ast_strlen_zero(iaxs[callno]->cid_name)) {
- iaxs[callno]->calling_pres = AST_PRES_NUMBER_NOT_AVAILABLE;
- } /* else user is allowed to set their own CID settings */
- if (!ast_strlen_zero(user->accountcode))
- ast_string_field_set(iaxs[callno], accountcode, user->accountcode);
- if (!ast_strlen_zero(user->mohinterpret))
- ast_string_field_set(iaxs[callno], mohinterpret, user->mohinterpret);
- if (!ast_strlen_zero(user->mohsuggest))
- ast_string_field_set(iaxs[callno], mohsuggest, user->mohsuggest);
- if (user->amaflags)
- iaxs[callno]->amaflags = user->amaflags;
- if (!ast_strlen_zero(user->language))
- ast_string_field_set(iaxs[callno], language, user->language);
- ast_copy_flags(iaxs[callno], user, IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF);
- /* Keep this check last */
- if (!ast_strlen_zero(user->dbsecret)) {
- char *family, *key=NULL;
- char buf[80];
- family = ast_strdupa(user->dbsecret);
- key = strchr(family, '/');
- if (key) {
- *key = '\0';
- key++;
- }
- if (!key || ast_db_get(family, key, buf, sizeof(buf)))
- ast_log(LOG_WARNING, "Unable to retrieve database password for family/key '%s'!\n", user->dbsecret);
- else
- ast_string_field_set(iaxs[callno], secret, buf);
- } else
- ast_string_field_set(iaxs[callno], secret, user->secret);
- res = 0;
- user = user_unref(user);
- }
- ast_set2_flag(iaxs[callno], iax2_getpeertrunk(*sin), IAX_TRUNK);
- return res;
-}
-
-static int raw_hangup(struct sockaddr_in *sin, unsigned short src, unsigned short dst, int sockfd)
-{
- struct ast_iax2_full_hdr fh;
- fh.scallno = htons(src | IAX_FLAG_FULL);
- fh.dcallno = htons(dst);
- fh.ts = 0;
- fh.oseqno = 0;
- fh.iseqno = 0;
- fh.type = AST_FRAME_IAX;
- fh.csub = compress_subclass(IAX_COMMAND_INVAL);
- if (iaxdebug)
- iax_showframe(NULL, &fh, 0, sin, 0);
- if (option_debug)
- ast_log(LOG_DEBUG, "Raw Hangup %s:%d, src=%d, dst=%d\n",
- ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port), src, dst);
- return sendto(sockfd, &fh, sizeof(fh), 0, (struct sockaddr *)sin, sizeof(*sin));
-}
-
-static void merge_encryption(struct chan_iax2_pvt *p, unsigned int enc)
-{
- /* Select exactly one common encryption if there are any */
- p->encmethods &= enc;
- if (p->encmethods) {
- if (p->encmethods & IAX_ENCRYPT_AES128)
- p->encmethods = IAX_ENCRYPT_AES128;
- else
- p->encmethods = 0;
- }
-}
-
-/*!
- * \pre iaxsl[call_num] is locked
- *
- * \note Since this function calls send_command_final(), the pvt struct for the given
- * call number may disappear while executing this function.
- */
-static int authenticate_request(int call_num)
-{
- struct iax_ie_data ied;
- int res = -1, authreq_restrict = 0;
- char challenge[10];
- struct chan_iax2_pvt *p = iaxs[call_num];
-
- memset(&ied, 0, sizeof(ied));
-
- /* If an AUTHREQ restriction is in place, make sure we can send an AUTHREQ back */
- if (ast_test_flag(p, IAX_MAXAUTHREQ)) {
- struct iax2_user *user, tmp_user = {
- .name = p->username,
- };
-
- user = ao2_find(users, &tmp_user, OBJ_POINTER);
- if (user) {
- if (user->curauthreq == user->maxauthreq)
- authreq_restrict = 1;
- else
- user->curauthreq++;
- user = user_unref(user);
- }
- }
-
- /* If the AUTHREQ limit test failed, send back an error */
- if (authreq_restrict) {
- iax_ie_append_str(&ied, IAX_IE_CAUSE, "Unauthenticated call limit reached");
- iax_ie_append_byte(&ied, IAX_IE_CAUSECODE, AST_CAUSE_CALL_REJECTED);
- send_command_final(p, AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied.buf, ied.pos, -1);
- return 0;
- }
-
- iax_ie_append_short(&ied, IAX_IE_AUTHMETHODS, p->authmethods);
- if (p->authmethods & (IAX_AUTH_MD5 | IAX_AUTH_RSA)) {
- snprintf(challenge, sizeof(challenge), "%d", (int)ast_random());
- ast_string_field_set(p, challenge, challenge);
- /* snprintf(p->challenge, sizeof(p->challenge), "%d", (int)ast_random()); */
- iax_ie_append_str(&ied, IAX_IE_CHALLENGE, p->challenge);
- }
- if (p->encmethods)
- iax_ie_append_short(&ied, IAX_IE_ENCRYPTION, p->encmethods);
-
- iax_ie_append_str(&ied,IAX_IE_USERNAME, p->username);
-
- res = send_command(p, AST_FRAME_IAX, IAX_COMMAND_AUTHREQ, 0, ied.buf, ied.pos, -1);
-
- if (p->encmethods)
- ast_set_flag(p, IAX_ENCRYPTED);
-
- return res;
-}
-
-static int authenticate_verify(struct chan_iax2_pvt *p, struct iax_ies *ies)
-{
- char requeststr[256];
- char md5secret[256] = "";
- char secret[256] = "";
- char rsasecret[256] = "";
- int res = -1;
- int x;
- struct iax2_user *user, tmp_user = {
- .name = p->username,
- };
-
- user = ao2_find(users, &tmp_user, OBJ_POINTER);
- if (user) {
- if (ast_test_flag(p, IAX_MAXAUTHREQ)) {
- ast_atomic_fetchadd_int(&user->curauthreq, -1);
- ast_clear_flag(p, IAX_MAXAUTHREQ);
- }
- ast_string_field_set(p, host, user->name);
- user = user_unref(user);
- }
-
- if (!ast_test_flag(&p->state, IAX_STATE_AUTHENTICATED))
- return res;
- if (ies->password)
- ast_copy_string(secret, ies->password, sizeof(secret));
- if (ies->md5_result)
- ast_copy_string(md5secret, ies->md5_result, sizeof(md5secret));
- if (ies->rsa_result)
- ast_copy_string(rsasecret, ies->rsa_result, sizeof(rsasecret));
- if ((p->authmethods & IAX_AUTH_RSA) && !ast_strlen_zero(rsasecret) && !ast_strlen_zero(p->inkeys)) {
- struct ast_key *key;
- char *keyn;
- char tmpkey[256];
- char *stringp=NULL;
- ast_copy_string(tmpkey, p->inkeys, sizeof(tmpkey));
- stringp=tmpkey;
- keyn = strsep(&stringp, ":");
- while(keyn) {
- key = ast_key_get(keyn, AST_KEY_PUBLIC);
- if (key && !ast_check_signature(key, p->challenge, rsasecret)) {
- res = 0;
- break;
- } else if (!key)
- ast_log(LOG_WARNING, "requested inkey '%s' for RSA authentication does not exist\n", keyn);
- keyn = strsep(&stringp, ":");
- }
- } else if (p->authmethods & IAX_AUTH_MD5) {
- struct MD5Context md5;
- unsigned char digest[16];
- char *tmppw, *stringp;
-
- tmppw = ast_strdupa(p->secret);
- stringp = tmppw;
- while((tmppw = strsep(&stringp, ";"))) {
- MD5Init(&md5);
- MD5Update(&md5, (unsigned char *)p->challenge, strlen(p->challenge));
- MD5Update(&md5, (unsigned char *)tmppw, strlen(tmppw));
- MD5Final(digest, &md5);
- /* If they support md5, authenticate with it. */
- for (x=0;x<16;x++)
- sprintf(requeststr + (x << 1), "%2.2x", digest[x]); /* safe */
- if (!strcasecmp(requeststr, md5secret)) {
- res = 0;
- break;
- }
- }
- } else if (p->authmethods & IAX_AUTH_PLAINTEXT) {
- if (!strcmp(secret, p->secret))
- res = 0;
- }
- return res;
-}
-
-/*! \brief Verify inbound registration */
-static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies *ies)
-{
- char requeststr[256] = "";
- char peer[256] = "";
- char md5secret[256] = "";
- char rsasecret[256] = "";
- char secret[256] = "";
- struct iax2_peer *p = NULL;
- struct ast_key *key;
- char *keyn;
- int x;
- int expire = 0;
- int res = -1;
-
- ast_clear_flag(&iaxs[callno]->state, IAX_STATE_AUTHENTICATED | IAX_STATE_UNCHANGED);
- /* iaxs[callno]->peer[0] = '\0'; not necc. any more-- stringfield is pre-inited to null string */
- if (ies->username)
- ast_copy_string(peer, ies->username, sizeof(peer));
- if (ies->password)
- ast_copy_string(secret, ies->password, sizeof(secret));
- if (ies->md5_result)
- ast_copy_string(md5secret, ies->md5_result, sizeof(md5secret));
- if (ies->rsa_result)
- ast_copy_string(rsasecret, ies->rsa_result, sizeof(rsasecret));
- if (ies->refresh)
- expire = ies->refresh;
-
- if (ast_strlen_zero(peer)) {
- ast_log(LOG_NOTICE, "Empty registration from %s\n", ast_inet_ntoa(sin->sin_addr));
- return -1;
- }
-
- /* SLD: first call to lookup peer during registration */
- ast_mutex_unlock(&iaxsl[callno]);
- p = find_peer(peer, 1);
- ast_mutex_lock(&iaxsl[callno]);
- if (!p || !iaxs[callno]) {
- if (authdebug && !p)
- ast_log(LOG_NOTICE, "No registration for peer '%s' (from %s)\n", peer, ast_inet_ntoa(sin->sin_addr));
- goto return_unref;
- }
-
- if (!ast_test_flag(p, IAX_DYNAMIC)) {
- if (authdebug)
- ast_log(LOG_NOTICE, "Peer '%s' is not dynamic (from %s)\n", peer, ast_inet_ntoa(sin->sin_addr));
- goto return_unref;
- }
-
- if (!ast_apply_ha(p->ha, sin)) {
- if (authdebug)
- ast_log(LOG_NOTICE, "Host %s denied access to register peer '%s'\n", ast_inet_ntoa(sin->sin_addr), p->name);
- goto return_unref;
- }
- if (!inaddrcmp(&p->addr, sin))
- ast_set_flag(&iaxs[callno]->state, IAX_STATE_UNCHANGED);
- ast_string_field_set(iaxs[callno], secret, p->secret);
- ast_string_field_set(iaxs[callno], inkeys, p->inkeys);
- /* Check secret against what we have on file */
- if (!ast_strlen_zero(rsasecret) && (p->authmethods & IAX_AUTH_RSA) && !ast_strlen_zero(iaxs[callno]->challenge)) {
- if (!ast_strlen_zero(p->inkeys)) {
- char tmpkeys[256];
- char *stringp=NULL;
- ast_copy_string(tmpkeys, p->inkeys, sizeof(tmpkeys));
- stringp=tmpkeys;
- keyn = strsep(&stringp, ":");
- while(keyn) {
- key = ast_key_get(keyn, AST_KEY_PUBLIC);
- if (key && !ast_check_signature(key, iaxs[callno]->challenge, rsasecret)) {
- ast_set_flag(&iaxs[callno]->state, IAX_STATE_AUTHENTICATED);
- break;
- } else if (!key)
- ast_log(LOG_WARNING, "requested inkey '%s' does not exist\n", keyn);
- keyn = strsep(&stringp, ":");
- }
- if (!keyn) {
- if (authdebug)
- ast_log(LOG_NOTICE, "Host %s failed RSA authentication with inkeys '%s'\n", peer, p->inkeys);
- goto return_unref;
- }
- } else {
- if (authdebug)
- ast_log(LOG_NOTICE, "Host '%s' trying to do RSA authentication, but we have no inkeys\n", peer);
- goto return_unref;
- }
- } else if (!ast_strlen_zero(md5secret) && (p->authmethods & IAX_AUTH_MD5) && !ast_strlen_zero(iaxs[callno]->challenge)) {
- struct MD5Context md5;
- unsigned char digest[16];
- char *tmppw, *stringp;
-
- tmppw = ast_strdupa(p->secret);
- stringp = tmppw;
- while((tmppw = strsep(&stringp, ";"))) {
- MD5Init(&md5);
- MD5Update(&md5, (unsigned char *)iaxs[callno]->challenge, strlen(iaxs[callno]->challenge));
- MD5Update(&md5, (unsigned char *)tmppw, strlen(tmppw));
- MD5Final(digest, &md5);
- for (x=0;x<16;x++)
- sprintf(requeststr + (x << 1), "%2.2x", digest[x]); /* safe */
- if (!strcasecmp(requeststr, md5secret))
- break;
- }
- if (tmppw) {
- ast_set_flag(&iaxs[callno]->state, IAX_STATE_AUTHENTICATED);
- } else {
- if (authdebug)
- ast_log(LOG_NOTICE, "Host %s failed MD5 authentication for '%s' (%s != %s)\n", ast_inet_ntoa(sin->sin_addr), p->name, requeststr, md5secret);
- goto return_unref;
- }
- } else if (!ast_strlen_zero(secret) && (p->authmethods & IAX_AUTH_PLAINTEXT)) {
- /* They've provided a plain text password and we support that */
- if (strcmp(secret, p->secret)) {
- if (authdebug)
- ast_log(LOG_NOTICE, "Host %s did not provide proper plaintext password for '%s'\n", ast_inet_ntoa(sin->sin_addr), p->name);
- goto return_unref;
- } else
- ast_set_flag(&iaxs[callno]->state, IAX_STATE_AUTHENTICATED);
- } else if (!ast_strlen_zero(md5secret) || !ast_strlen_zero(secret)) {
- if (authdebug)
- ast_log(LOG_NOTICE, "Inappropriate authentication received\n");
- goto return_unref;
- }
- ast_string_field_set(iaxs[callno], peer, peer);
- /* Choose lowest expiry number */
- if (expire && (expire < iaxs[callno]->expiry))
- iaxs[callno]->expiry = expire;
-
- ast_device_state_changed("IAX2/%s", p->name); /* Activate notification */
-
- res = 0;
-
-return_unref:
- if (p)
- peer_unref(p);
-
- return res;
-}
-
-static int authenticate(const char *challenge, const char *secret, const char *keyn, int authmethods, struct iax_ie_data *ied, struct sockaddr_in *sin, aes_encrypt_ctx *ecx, aes_decrypt_ctx *dcx)
-{
- int res = -1;
- int x;
- if (!ast_strlen_zero(keyn)) {
- if (!(authmethods & IAX_AUTH_RSA)) {
- if (ast_strlen_zero(secret))
- ast_log(LOG_NOTICE, "Asked to authenticate to %s with an RSA key, but they don't allow RSA authentication\n", ast_inet_ntoa(sin->sin_addr));
- } else if (ast_strlen_zero(challenge)) {
- ast_log(LOG_NOTICE, "No challenge provided for RSA authentication to %s\n", ast_inet_ntoa(sin->sin_addr));
- } else {
- char sig[256];
- struct ast_key *key;
- key = ast_key_get(keyn, AST_KEY_PRIVATE);
- if (!key) {
- ast_log(LOG_NOTICE, "Unable to find private key '%s'\n", keyn);
- } else {
- if (ast_sign(key, (char*)challenge, sig)) {
- ast_log(LOG_NOTICE, "Unable to sign challenge with key\n");
- res = -1;
- } else {
- iax_ie_append_str(ied, IAX_IE_RSA_RESULT, sig);
- res = 0;
- }
- }
- }
- }
- /* Fall back */
- if (res && !ast_strlen_zero(secret)) {
- if ((authmethods & IAX_AUTH_MD5) && !ast_strlen_zero(challenge)) {
- struct MD5Context md5;
- unsigned char digest[16];
- char digres[128];
- MD5Init(&md5);
- MD5Update(&md5, (unsigned char *)challenge, strlen(challenge));
- MD5Update(&md5, (unsigned char *)secret, strlen(secret));
- MD5Final(digest, &md5);
- /* If they support md5, authenticate with it. */
- for (x=0;x<16;x++)
- sprintf(digres + (x << 1), "%2.2x", digest[x]); /* safe */
- if (ecx && dcx)
- build_enc_keys(digest, ecx, dcx);
- iax_ie_append_str(ied, IAX_IE_MD5_RESULT, digres);
- res = 0;
- } else if (authmethods & IAX_AUTH_PLAINTEXT) {
- iax_ie_append_str(ied, IAX_IE_PASSWORD, secret);
- res = 0;
- } else
- ast_log(LOG_NOTICE, "No way to send secret to peer '%s' (their methods: %d)\n", ast_inet_ntoa(sin->sin_addr), authmethods);
- }
- return res;
-}
-
-/*!
- * \note This function calls realtime_peer -> reg_source_db -> iax2_poke_peer -> find_callno,
- * so do not call this function with a pvt lock held.
- */
-static int authenticate_reply(struct chan_iax2_pvt *p, struct sockaddr_in *sin, struct iax_ies *ies, const char *override, const char *okey)
-{
- struct iax2_peer *peer = NULL;
- /* Start pessimistic */
- int res = -1;
- int authmethods = 0;
- struct iax_ie_data ied;
- uint16_t callno = p->callno;
-
- memset(&ied, 0, sizeof(ied));
-
- if (ies->username)
- ast_string_field_set(p, username, ies->username);
- if (ies->challenge)
- ast_string_field_set(p, challenge, ies->challenge);
- if (ies->authmethods)
- authmethods = ies->authmethods;
- if (authmethods & IAX_AUTH_MD5)
- merge_encryption(p, ies->encmethods);
- else
- p->encmethods = 0;
-
- /* Check for override RSA authentication first */
- if (!ast_strlen_zero(override) || !ast_strlen_zero(okey)) {
- /* Normal password authentication */
- res = authenticate(p->challenge, override, okey, authmethods, &ied, sin, &p->ecx, &p->dcx);
- } else {
- struct ao2_iterator i = ao2_iterator_init(peers, 0);
- while ((peer = ao2_iterator_next(&i))) {
- if ((ast_strlen_zero(p->peer) || !strcmp(p->peer, peer->name))
- /* No peer specified at our end, or this is the peer */
- && (ast_strlen_zero(peer->username) || (!strcmp(peer->username, p->username)))
- /* No username specified in peer rule, or this is the right username */
- && (!peer->addr.sin_addr.s_addr || ((sin->sin_addr.s_addr & peer->mask.s_addr) == (peer->addr.sin_addr.s_addr & peer->mask.s_addr)))
- /* No specified host, or this is our host */
- ) {
- res = authenticate(p->challenge, peer->secret, peer->outkey, authmethods, &ied, sin, &p->ecx, &p->dcx);
- if (!res) {
- peer_unref(peer);
- break;
- }
- }
- peer_unref(peer);
- }
- if (!peer) {
- /* We checked our list and didn't find one. It's unlikely, but possible,
- that we're trying to authenticate *to* a realtime peer */
- const char *peer_name = ast_strdupa(p->peer);
- ast_mutex_unlock(&iaxsl[callno]);
- if ((peer = realtime_peer(peer_name, NULL))) {
- ast_mutex_lock(&iaxsl[callno]);
- if (!(p = iaxs[callno])) {
- peer_unref(peer);
- return -1;
- }
- res = authenticate(p->challenge, peer->secret,peer->outkey, authmethods, &ied, sin, &p->ecx, &p->dcx);
- peer_unref(peer);
- }
- if (!peer) {
- ast_mutex_lock(&iaxsl[callno]);
- if (!(p = iaxs[callno]))
- return -1;
- }
- }
- }
- if (ies->encmethods)
- ast_set_flag(p, IAX_ENCRYPTED | IAX_KEYPOPULATED);
- if (!res)
- res = send_command(p, AST_FRAME_IAX, IAX_COMMAND_AUTHREP, 0, ied.buf, ied.pos, -1);
- return res;
-}
-
-static int iax2_do_register(struct iax2_registry *reg);
-
-static void __iax2_do_register_s(const void *data)
-{
- struct iax2_registry *reg = (struct iax2_registry *)data;
- reg->expire = -1;
- iax2_do_register(reg);
-}
-
-static int iax2_do_register_s(const void *data)
-{
-#ifdef SCHED_MULTITHREADED
- if (schedule_action(__iax2_do_register_s, data))
-#endif
- __iax2_do_register_s(data);
- return 0;
-}
-
-static int try_transfer(struct chan_iax2_pvt *pvt, struct iax_ies *ies)
-{
- int newcall = 0;
- char newip[256];
- struct iax_ie_data ied;
- struct sockaddr_in new;
-
-
- memset(&ied, 0, sizeof(ied));
- if (ies->apparent_addr)
- bcopy(ies->apparent_addr, &new, sizeof(new));
- if (ies->callno)
- newcall = ies->callno;
- if (!newcall || !new.sin_addr.s_addr || !new.sin_port) {
- ast_log(LOG_WARNING, "Invalid transfer request\n");
- return -1;
- }
- pvt->transfercallno = newcall;
- memcpy(&pvt->transfer, &new, sizeof(pvt->transfer));
- inet_aton(newip, &pvt->transfer.sin_addr);
- pvt->transfer.sin_family = AF_INET;
- pvt->transferring = TRANSFER_BEGIN;
- pvt->transferid = ies->transferid;
- if (ies->transferid)
- iax_ie_append_int(&ied, IAX_IE_TRANSFERID, ies->transferid);
- send_command_transfer(pvt, AST_FRAME_IAX, IAX_COMMAND_TXCNT, 0, ied.buf, ied.pos);
- return 0;
-}
-
-static int complete_dpreply(struct chan_iax2_pvt *pvt, struct iax_ies *ies)
-{
- char exten[256] = "";
- int status = CACHE_FLAG_UNKNOWN;
- int expiry = iaxdefaultdpcache;
- int x;
- int matchmore = 0;
- struct iax2_dpcache *dp, *prev;
-
- if (ies->called_number)
- ast_copy_string(exten, ies->called_number, sizeof(exten));
-
- if (ies->dpstatus & IAX_DPSTATUS_EXISTS)
- status = CACHE_FLAG_EXISTS;
- else if (ies->dpstatus & IAX_DPSTATUS_CANEXIST)
- status = CACHE_FLAG_CANEXIST;
- else if (ies->dpstatus & IAX_DPSTATUS_NONEXISTENT)
- status = CACHE_FLAG_NONEXISTENT;
-
- if (ies->dpstatus & IAX_DPSTATUS_IGNOREPAT) {
- /* Don't really do anything with this */
- }
- if (ies->refresh)
- expiry = ies->refresh;
- if (ies->dpstatus & IAX_DPSTATUS_MATCHMORE)
- matchmore = CACHE_FLAG_MATCHMORE;
- ast_mutex_lock(&dpcache_lock);
- prev = NULL;
- dp = pvt->dpentries;
- while(dp) {
- if (!strcmp(dp->exten, exten)) {
- /* Let them go */
- if (prev)
- prev->peer = dp->peer;
- else
- pvt->dpentries = dp->peer;
- dp->peer = NULL;
- dp->callno = 0;
- dp->expiry.tv_sec = dp->orig.tv_sec + expiry;
- if (dp->flags & CACHE_FLAG_PENDING) {
- dp->flags &= ~CACHE_FLAG_PENDING;
- dp->flags |= status;
- dp->flags |= matchmore;
- }
- /* Wake up waiters */
- for (x = 0; x < ARRAY_LEN(dp->waiters); x++) {
- if (dp->waiters[x] > -1) {
- if (write(dp->waiters[x], "asdf", 4) < 0) {
- ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
- }
- }
- }
- }
- prev = dp;
- dp = dp->peer;
- }
- ast_mutex_unlock(&dpcache_lock);
- return 0;
-}
-
-static int complete_transfer(int callno, struct iax_ies *ies)
-{
- int peercallno = 0;
- struct chan_iax2_pvt *pvt = iaxs[callno];
- struct iax_frame *cur;
- jb_frame frame;
-
- if (ies->callno)
- peercallno = ies->callno;
-
- if (peercallno < 1) {
- ast_log(LOG_WARNING, "Invalid transfer request\n");
- return -1;
- }
- memcpy(&pvt->addr, &pvt->transfer, sizeof(pvt->addr));
- memset(&pvt->transfer, 0, sizeof(pvt->transfer));
- /* Reset sequence numbers */
- pvt->oseqno = 0;
- pvt->rseqno = 0;
- pvt->iseqno = 0;
- pvt->aseqno = 0;
-
- if (pvt->peercallno) {
- remove_by_peercallno(pvt);
- }
- pvt->peercallno = peercallno;
- store_by_peercallno(pvt);
-
- pvt->transferring = TRANSFER_NONE;
- pvt->svoiceformat = -1;
- pvt->voiceformat = 0;
- pvt->svideoformat = -1;
- pvt->videoformat = 0;
- pvt->transfercallno = -1;
- memset(&pvt->rxcore, 0, sizeof(pvt->rxcore));
- memset(&pvt->offset, 0, sizeof(pvt->offset));
- /* reset jitterbuffer */
- while(jb_getall(pvt->jb,&frame) == JB_OK)
- iax2_frame_free(frame.data);
- jb_reset(pvt->jb);
- pvt->lag = 0;
- pvt->last = 0;
- pvt->lastsent = 0;
- pvt->nextpred = 0;
- pvt->pingtime = DEFAULT_RETRY_TIME;
- AST_LIST_LOCK(&iaxq.queue);
- AST_LIST_TRAVERSE(&iaxq.queue, cur, list) {
- /* We must cancel any packets that would have been transmitted
- because now we're talking to someone new. It's okay, they
- were transmitted to someone that didn't care anyway. */
- if (callno == cur->callno)
- cur->retries = -1;
- }
- AST_LIST_UNLOCK(&iaxq.queue);
- return 0;
-}
-
-/*! \brief Acknowledgment received for OUR registration */
-static int iax2_ack_registry(struct iax_ies *ies, struct sockaddr_in *sin, int callno)
-{
- struct iax2_registry *reg;
- /* Start pessimistic */
- char peer[256] = "";
- char msgstatus[60];
- int refresh = 60;
- char ourip[256] = "<Unspecified>";
- struct sockaddr_in oldus;
- struct sockaddr_in us;
- int oldmsgs;
-
- memset(&us, 0, sizeof(us));
- if (ies->apparent_addr)
- bcopy(ies->apparent_addr, &us, sizeof(us));
- if (ies->username)
- ast_copy_string(peer, ies->username, sizeof(peer));
- if (ies->refresh)
- refresh = ies->refresh;
- if (ies->calling_number) {
- /* We don't do anything with it really, but maybe we should */
- }
- reg = iaxs[callno]->reg;
- if (!reg) {
- ast_log(LOG_WARNING, "Registry acknowledge on unknown registry '%s'\n", peer);
- return -1;
- }
- memcpy(&oldus, &reg->us, sizeof(oldus));
- oldmsgs = reg->messages;
- if (inaddrcmp(&reg->addr, sin)) {
- ast_log(LOG_WARNING, "Received unsolicited registry ack from '%s'\n", ast_inet_ntoa(sin->sin_addr));
- return -1;
- }
- memcpy(&reg->us, &us, sizeof(reg->us));
- if (ies->msgcount >= 0)
- reg->messages = ies->msgcount & 0xffff; /* only low 16 bits are used in the transmission of the IE */
- /* always refresh the registration at the interval requested by the server
- we are registering to
- */
- reg->refresh = refresh;
- AST_SCHED_DEL(sched, reg->expire);
- reg->expire = iax2_sched_add(sched, (5 * reg->refresh / 6) * 1000, iax2_do_register_s, reg);
- if (inaddrcmp(&oldus, &reg->us) || (reg->messages != oldmsgs)) {
- if (option_verbose > 2) {
- if (reg->messages > 255)
- snprintf(msgstatus, sizeof(msgstatus), " with %d new and %d old messages waiting", reg->messages & 0xff, reg->messages >> 8);
- else if (reg->messages > 1)
- snprintf(msgstatus, sizeof(msgstatus), " with %d new messages waiting\n", reg->messages);
- else if (reg->messages > 0)
- snprintf(msgstatus, sizeof(msgstatus), " with 1 new message waiting\n");
- else
- snprintf(msgstatus, sizeof(msgstatus), " with no messages waiting\n");
- snprintf(ourip, sizeof(ourip), "%s:%d", ast_inet_ntoa(reg->us.sin_addr), ntohs(reg->us.sin_port));
- ast_verbose(VERBOSE_PREFIX_3 "Registered IAX2 to '%s', who sees us as %s%s\n", ast_inet_ntoa(sin->sin_addr), ourip, msgstatus);
- }
- manager_event(EVENT_FLAG_SYSTEM, "Registry", "ChannelDriver: IAX2\r\nDomain: %s\r\nStatus: Registered\r\n", ast_inet_ntoa(sin->sin_addr));
- }
- reg->regstate = REG_STATE_REGISTERED;
- return 0;
-}
-
-static int iax2_register(char *value, int lineno)
-{
- struct iax2_registry *reg;
- char copy[256];
- char *username, *hostname, *secret;
- char *porta;
- char *stringp=NULL;
-
- if (!value)
- return -1;
- ast_copy_string(copy, value, sizeof(copy));
- stringp=copy;
- username = strsep(&stringp, "@");
- hostname = strsep(&stringp, "@");
- if (!hostname) {
- ast_log(LOG_WARNING, "Format for registration is user[:secret]@host[:port] at line %d\n", lineno);
- return -1;
- }
- stringp=username;
- username = strsep(&stringp, ":");
- secret = strsep(&stringp, ":");
- stringp=hostname;
- hostname = strsep(&stringp, ":");
- porta = strsep(&stringp, ":");
-
- if (porta && !atoi(porta)) {
- ast_log(LOG_WARNING, "%s is not a valid port number at line %d\n", porta, lineno);
- return -1;
- }
- if (!(reg = ast_calloc(1, sizeof(*reg))))
- return -1;
- if (ast_dnsmgr_lookup(hostname, &reg->addr.sin_addr, &reg->dnsmgr) < 0) {
- free(reg);
- return -1;
- }
- ast_copy_string(reg->username, username, sizeof(reg->username));
- if (secret)
- ast_copy_string(reg->secret, secret, sizeof(reg->secret));
- reg->expire = -1;
- reg->refresh = IAX_DEFAULT_REG_EXPIRE;
- reg->addr.sin_family = AF_INET;
- reg->addr.sin_port = porta ? htons(atoi(porta)) : htons(IAX_DEFAULT_PORTNO);
- AST_LIST_LOCK(&registrations);
- AST_LIST_INSERT_HEAD(&registrations, reg, entry);
- AST_LIST_UNLOCK(&registrations);
-
- return 0;
-}
-
-static void register_peer_exten(struct iax2_peer *peer, int onoff)
-{
- char multi[256];
- char *stringp, *ext;
- if (!ast_strlen_zero(regcontext)) {
- ast_copy_string(multi, S_OR(peer->regexten, peer->name), sizeof(multi));
- stringp = multi;
- while((ext = strsep(&stringp, "&"))) {
- if (onoff) {
- if (!ast_exists_extension(NULL, regcontext, ext, 1, NULL))
- ast_add_extension(regcontext, 1, ext, 1, NULL, NULL,
- "Noop", ast_strdup(peer->name), ast_free, "IAX2");
- } else
- ast_context_remove_extension(regcontext, ext, 1, NULL);
- }
- }
-}
-static void prune_peers(void);
-
-static void unlink_peer(struct iax2_peer *peer)
-{
- if (peer->expire > -1) {
- if (!ast_sched_del(sched, peer->expire)) {
- peer->expire = -1;
- peer_unref(peer);
- }
- }
-
- if (peer->pokeexpire > -1) {
- if (!ast_sched_del(sched, peer->pokeexpire)) {
- peer->pokeexpire = -1;
- peer_unref(peer);
- }
- }
-
- ao2_unlink(peers, peer);
-}
-
-static void __expire_registry(const void *data)
-{
- struct iax2_peer *peer = (struct iax2_peer *) data;
-
- if (!peer)
- return;
-
- peer->expire = -1;
-
- if (option_debug)
- ast_log(LOG_DEBUG, "Expiring registration for peer '%s'\n", peer->name);
- if (ast_test_flag((&globalflags), IAX_RTUPDATE) && (ast_test_flag(peer, IAX_TEMPONLY|IAX_RTCACHEFRIENDS)))
- realtime_update_peer(peer->name, &peer->addr, 0);
- manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "Peer: IAX2/%s\r\nPeerStatus: Unregistered\r\nCause: Expired\r\n", peer->name);
- /* Reset the address */
- memset(&peer->addr, 0, sizeof(peer->addr));
- /* Reset expiry value */
- peer->expiry = min_reg_expire;
- if (!ast_test_flag(peer, IAX_TEMPONLY))
- ast_db_del("IAX/Registry", peer->name);
- register_peer_exten(peer, 0);
- ast_device_state_changed("IAX2/%s", peer->name); /* Activate notification */
- if (iax2_regfunk)
- iax2_regfunk(peer->name, 0);
-
- if (ast_test_flag(peer, IAX_RTAUTOCLEAR))
- unlink_peer(peer);
-
- peer_unref(peer);
-}
-
-static int expire_registry(const void *data)
-{
-#ifdef SCHED_MULTITHREADED
- if (schedule_action(__expire_registry, data))
-#endif
- __expire_registry(data);
- return 0;
-}
-
-static int iax2_poke_peer(struct iax2_peer *peer, int heldcall);
-
-static void reg_source_db(struct iax2_peer *p)
-{
- char data[80];
- struct in_addr in;
- char *c, *d;
- if (!ast_test_flag(p, IAX_TEMPONLY) && (!ast_db_get("IAX/Registry", p->name, data, sizeof(data)))) {
- c = strchr(data, ':');
- if (c) {
- *c = '\0';
- c++;
- if (inet_aton(data, &in)) {
- d = strchr(c, ':');
- if (d) {
- *d = '\0';
- d++;
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Seeding '%s' at %s:%d for %d\n", p->name,
- ast_inet_ntoa(in), atoi(c), atoi(d));
- iax2_poke_peer(p, 0);
- p->expiry = atoi(d);
- memset(&p->addr, 0, sizeof(p->addr));
- p->addr.sin_family = AF_INET;
- p->addr.sin_addr = in;
- p->addr.sin_port = htons(atoi(c));
- if (p->expire > -1) {
- if (!ast_sched_del(sched, p->expire)) {
- p->expire = -1;
- peer_unref(p);
- }
- }
- ast_device_state_changed("IAX2/%s", p->name); /* Activate notification */
- p->expire = iax2_sched_add(sched, (p->expiry + 10) * 1000, expire_registry, peer_ref(p));
- if (p->expire == -1)
- peer_unref(p);
- if (iax2_regfunk)
- iax2_regfunk(p->name, 1);
- register_peer_exten(p, 1);
- }
-
- }
- }
- }
-}
-
-/*!
- * \pre iaxsl[callno] is locked
- *
- * \note Since this function calls send_command_final(), the pvt struct for
- * the given call number may disappear while executing this function.
- */
-static int update_registry(struct sockaddr_in *sin, int callno, char *devtype, int fd, unsigned short refresh)
-{
- /* Called from IAX thread only, with proper iaxsl lock */
- struct iax_ie_data ied;
- struct iax2_peer *p;
- int msgcount;
- char data[80];
- int version;
- const char *peer_name;
- int res = -1;
-
- memset(&ied, 0, sizeof(ied));
-
- peer_name = ast_strdupa(iaxs[callno]->peer);
-
- /* SLD: Another find_peer call during registration - this time when we are really updating our registration */
- ast_mutex_unlock(&iaxsl[callno]);
- if (!(p = find_peer(peer_name, 1))) {
- ast_mutex_lock(&iaxsl[callno]);
- ast_log(LOG_WARNING, "No such peer '%s'\n", peer_name);
- return -1;
- }
- ast_mutex_lock(&iaxsl[callno]);
- if (!iaxs[callno])
- goto return_unref;
-
- if (ast_test_flag((&globalflags), IAX_RTUPDATE) && (ast_test_flag(p, IAX_TEMPONLY|IAX_RTCACHEFRIENDS))) {
- if (sin->sin_addr.s_addr) {
- time_t nowtime;
- time(&nowtime);
- realtime_update_peer(peer_name, sin, nowtime);
- } else {
- realtime_update_peer(peer_name, sin, 0);
- }
- }
- if (inaddrcmp(&p->addr, sin)) {
- if (iax2_regfunk)
- iax2_regfunk(p->name, 1);
- /* Stash the IP address from which they registered */
- memcpy(&p->addr, sin, sizeof(p->addr));
- snprintf(data, sizeof(data), "%s:%d:%d", ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port), p->expiry);
- if (!ast_test_flag(p, IAX_TEMPONLY) && sin->sin_addr.s_addr) {
- ast_db_put("IAX/Registry", p->name, data);
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Registered IAX2 '%s' (%s) at %s:%d\n", p->name,
- ast_test_flag(&iaxs[callno]->state, IAX_STATE_AUTHENTICATED) ? "AUTHENTICATED" : "UNAUTHENTICATED", ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
- manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "Peer: IAX2/%s\r\nPeerStatus: Registered\r\n", p->name);
- register_peer_exten(p, 1);
- ast_device_state_changed("IAX2/%s", p->name); /* Activate notification */
- } else if (!ast_test_flag(p, IAX_TEMPONLY)) {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Unregistered IAX2 '%s' (%s)\n", p->name,
- ast_test_flag(&iaxs[callno]->state, IAX_STATE_AUTHENTICATED) ? "AUTHENTICATED" : "UNAUTHENTICATED");
- manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "Peer: IAX2/%s\r\nPeerStatus: Unregistered\r\n", p->name);
- register_peer_exten(p, 0);
- ast_db_del("IAX/Registry", p->name);
- ast_device_state_changed("IAX2/%s", p->name); /* Activate notification */
- }
- /* Update the host */
- /* Verify that the host is really there */
- iax2_poke_peer(p, callno);
- }
-
- /* Make sure our call still exists, an INVAL at the right point may make it go away */
- if (!iaxs[callno]) {
- res = -1;
- goto return_unref;
- }
-
- /* Store socket fd */
- p->sockfd = fd;
- /* Setup the expiry */
- if (p->expire > -1) {
- if (!ast_sched_del(sched, p->expire)) {
- p->expire = -1;
- peer_unref(p);
- }
- }
- /* treat an unspecified refresh interval as the minimum */
- if (!refresh)
- refresh = min_reg_expire;
- if (refresh > max_reg_expire) {
- ast_log(LOG_NOTICE, "Restricting registration for peer '%s' to %d seconds (requested %d)\n",
- p->name, max_reg_expire, refresh);
- p->expiry = max_reg_expire;
- } else if (refresh < min_reg_expire) {
- ast_log(LOG_NOTICE, "Restricting registration for peer '%s' to %d seconds (requested %d)\n",
- p->name, min_reg_expire, refresh);
- p->expiry = min_reg_expire;
- } else {
- p->expiry = refresh;
- }
- if (p->expiry && sin->sin_addr.s_addr) {
- p->expire = iax2_sched_add(sched, (p->expiry + 10) * 1000, expire_registry, peer_ref(p));
- if (p->expire == -1)
- peer_unref(p);
- }
- iax_ie_append_str(&ied, IAX_IE_USERNAME, p->name);
- iax_ie_append_int(&ied, IAX_IE_DATETIME, iax2_datetime(p->zonetag));
- if (sin->sin_addr.s_addr) {
- iax_ie_append_short(&ied, IAX_IE_REFRESH, p->expiry);
- iax_ie_append_addr(&ied, IAX_IE_APPARENT_ADDR, &p->addr);
- if (!ast_strlen_zero(p->mailbox)) {
- int new, old;
- ast_app_inboxcount(p->mailbox, &new, &old);
- if (new > 255)
- new = 255;
- if (old > 255)
- old = 255;
- msgcount = (old << 8) | new;
- iax_ie_append_short(&ied, IAX_IE_MSGCOUNT, msgcount);
- }
- if (ast_test_flag(p, IAX_HASCALLERID)) {
- iax_ie_append_str(&ied, IAX_IE_CALLING_NUMBER, p->cid_num);
- iax_ie_append_str(&ied, IAX_IE_CALLING_NAME, p->cid_name);
- }
- }
- version = iax_check_version(devtype);
- if (version)
- iax_ie_append_short(&ied, IAX_IE_FIRMWAREVER, version);
-
- res = 0;
-
-return_unref:
- peer_unref(p);
-
- return res ? res : send_command_final(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_REGACK, 0, ied.buf, ied.pos, -1);
-}
-
-static int registry_authrequest(int callno)
-{
- struct iax_ie_data ied;
- struct iax2_peer *p;
- char challenge[10];
- const char *peer_name;
- int res = -1;
- int sentauthmethod;
-
- peer_name = ast_strdupa(iaxs[callno]->peer);
-
- /* SLD: third call to find_peer in registration */
- ast_mutex_unlock(&iaxsl[callno]);
- if ((p = find_peer(peer_name, 1))) {
- last_authmethod = p->authmethods;
- }
-
- ast_mutex_lock(&iaxsl[callno]);
- if (!iaxs[callno])
- goto return_unref;
- if (!p && !delayreject) {
- ast_log(LOG_WARNING, "No such peer '%s'\n", peer_name);
- goto return_unref;
- }
-
- memset(&ied, 0, sizeof(ied));
- /* The selection of which delayed reject is sent may leak information,
- * if it sets a static response. For example, if a host is known to only
- * use MD5 authentication, then an RSA response would indicate that the
- * peer does not exist, and vice-versa.
- * Therefore, we use whatever the last peer used (which may vary over the
- * course of a server, which should leak minimal information). */
- sentauthmethod = p ? p->authmethods : last_authmethod ? last_authmethod : (IAX_AUTH_MD5 | IAX_AUTH_PLAINTEXT);
- iax_ie_append_short(&ied, IAX_IE_AUTHMETHODS, sentauthmethod);
- if (sentauthmethod & (IAX_AUTH_RSA | IAX_AUTH_MD5)) {
- /* Build the challenge */
- snprintf(challenge, sizeof(challenge), "%d", (int)ast_random());
- ast_string_field_set(iaxs[callno], challenge, challenge);
- iax_ie_append_str(&ied, IAX_IE_CHALLENGE, iaxs[callno]->challenge);
- }
- iax_ie_append_str(&ied, IAX_IE_USERNAME, peer_name);
-
- res = 0;
-
-return_unref:
- peer_unref(p);
-
- return res ? res : send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_REGAUTH, 0, ied.buf, ied.pos, -1);;
-}
-
-static int registry_rerequest(struct iax_ies *ies, int callno, struct sockaddr_in *sin)
-{
- struct iax2_registry *reg;
- /* Start pessimistic */
- struct iax_ie_data ied;
- char peer[256] = "";
- char challenge[256] = "";
- int res;
- int authmethods = 0;
- if (ies->authmethods)
- authmethods = ies->authmethods;
- if (ies->username)
- ast_copy_string(peer, ies->username, sizeof(peer));
- if (ies->challenge)
- ast_copy_string(challenge, ies->challenge, sizeof(challenge));
- memset(&ied, 0, sizeof(ied));
- reg = iaxs[callno]->reg;
- if (reg) {
- if (inaddrcmp(&reg->addr, sin)) {
- ast_log(LOG_WARNING, "Received unsolicited registry authenticate request from '%s'\n", ast_inet_ntoa(sin->sin_addr));
- return -1;
- }
- if (ast_strlen_zero(reg->secret)) {
- ast_log(LOG_NOTICE, "No secret associated with peer '%s'\n", reg->username);
- reg->regstate = REG_STATE_NOAUTH;
- return -1;
- }
- iax_ie_append_str(&ied, IAX_IE_USERNAME, reg->username);
- iax_ie_append_short(&ied, IAX_IE_REFRESH, reg->refresh);
- if (reg->secret[0] == '[') {
- char tmpkey[256];
- ast_copy_string(tmpkey, reg->secret + 1, sizeof(tmpkey));
- tmpkey[strlen(tmpkey) - 1] = '\0';
- res = authenticate(challenge, NULL, tmpkey, authmethods, &ied, sin, NULL, NULL);
- } else
- res = authenticate(challenge, reg->secret, NULL, authmethods, &ied, sin, NULL, NULL);
- if (!res) {
- reg->regstate = REG_STATE_AUTHSENT;
- return send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_REGREQ, 0, ied.buf, ied.pos, -1);
- } else
- return -1;
- ast_log(LOG_WARNING, "Registry acknowledge on unknown registery '%s'\n", peer);
- } else
- ast_log(LOG_NOTICE, "Can't reregister without a reg\n");
- return -1;
-}
-
-static void stop_stuff(int callno)
-{
- iax2_destroy_helper(iaxs[callno]);
-}
-
-static void __auth_reject(const void *nothing)
-{
- /* Called from IAX thread only, without iaxs lock */
- int callno = (int)(long)(nothing);
- struct iax_ie_data ied;
- ast_mutex_lock(&iaxsl[callno]);
- if (iaxs[callno]) {
- memset(&ied, 0, sizeof(ied));
- if (iaxs[callno]->authfail == IAX_COMMAND_REGREJ) {
- iax_ie_append_str(&ied, IAX_IE_CAUSE, "Registration Refused");
- iax_ie_append_byte(&ied, IAX_IE_CAUSECODE, AST_CAUSE_FACILITY_REJECTED);
- } else if (iaxs[callno]->authfail == IAX_COMMAND_REJECT) {
- iax_ie_append_str(&ied, IAX_IE_CAUSE, "No authority found");
- iax_ie_append_byte(&ied, IAX_IE_CAUSECODE, AST_CAUSE_FACILITY_NOT_SUBSCRIBED);
- }
- send_command_final(iaxs[callno], AST_FRAME_IAX, iaxs[callno]->authfail, 0, ied.buf, ied.pos, -1);
- }
- ast_mutex_unlock(&iaxsl[callno]);
-}
-
-static int auth_reject(const void *data)
-{
- int callno = (int)(long)(data);
- ast_mutex_lock(&iaxsl[callno]);
- if (iaxs[callno])
- iaxs[callno]->authid = -1;
- ast_mutex_unlock(&iaxsl[callno]);
-#ifdef SCHED_MULTITHREADED
- if (schedule_action(__auth_reject, data))
-#endif
- __auth_reject(data);
- return 0;
-}
-
-static int auth_fail(int callno, int failcode)
-{
- /* Schedule sending the authentication failure in one second, to prevent
- guessing */
- if (iaxs[callno]) {
- iaxs[callno]->authfail = failcode;
- if (delayreject) {
- AST_SCHED_DEL(sched, iaxs[callno]->authid);
- iaxs[callno]->authid = iax2_sched_add(sched, 1000, auth_reject, (void *)(long)callno);
- } else
- auth_reject((void *)(long)callno);
- }
- return 0;
-}
-
-static void __auto_hangup(const void *nothing)
-{
- /* Called from IAX thread only, without iaxs lock */
- int callno = (int)(long)(nothing);
- struct iax_ie_data ied;
- ast_mutex_lock(&iaxsl[callno]);
- if (iaxs[callno]) {
- memset(&ied, 0, sizeof(ied));
- iax_ie_append_str(&ied, IAX_IE_CAUSE, "Timeout");
- iax_ie_append_byte(&ied, IAX_IE_CAUSECODE, AST_CAUSE_NO_USER_RESPONSE);
- send_command_final(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_HANGUP, 0, ied.buf, ied.pos, -1);
- }
- ast_mutex_unlock(&iaxsl[callno]);
-}
-
-static int auto_hangup(const void *data)
-{
- int callno = (int)(long)(data);
- ast_mutex_lock(&iaxsl[callno]);
- if (iaxs[callno]) {
- iaxs[callno]->autoid = -1;
- }
- ast_mutex_unlock(&iaxsl[callno]);
-#ifdef SCHED_MULTITHREADED
- if (schedule_action(__auto_hangup, data))
-#endif
- __auto_hangup(data);
- return 0;
-}
-
-static void iax2_dprequest(struct iax2_dpcache *dp, int callno)
-{
- struct iax_ie_data ied;
- /* Auto-hangup with 30 seconds of inactivity */
- AST_SCHED_DEL(sched, iaxs[callno]->autoid);
- iaxs[callno]->autoid = iax2_sched_add(sched, 30000, auto_hangup, (void *)(long)callno);
- memset(&ied, 0, sizeof(ied));
- iax_ie_append_str(&ied, IAX_IE_CALLED_NUMBER, dp->exten);
- send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_DPREQ, 0, ied.buf, ied.pos, -1);
- dp->flags |= CACHE_FLAG_TRANSMITTED;
-}
-
-static int iax2_vnak(int callno)
-{
- return send_command_immediate(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_VNAK, 0, NULL, 0, iaxs[callno]->iseqno);
-}
-
-static void vnak_retransmit(int callno, int last)
-{
- struct iax_frame *f;
-
- AST_LIST_LOCK(&iaxq.queue);
- AST_LIST_TRAVERSE(&iaxq.queue, f, list) {
- /* Send a copy immediately */
- if ((f->callno == callno) && iaxs[f->callno] &&
- ((unsigned char ) (f->oseqno - last) < 128) &&
- (f->retries >= 0)) {
- send_packet(f);
- }
- }
- AST_LIST_UNLOCK(&iaxq.queue);
-}
-
-static void __iax2_poke_peer_s(const void *data)
-{
- struct iax2_peer *peer = (struct iax2_peer *)data;
- iax2_poke_peer(peer, 0);
- peer_unref(peer);
-}
-
-static int iax2_poke_peer_s(const void *data)
-{
- struct iax2_peer *peer = (struct iax2_peer *)data;
- peer->pokeexpire = -1;
-#ifdef SCHED_MULTITHREADED
- if (schedule_action(__iax2_poke_peer_s, data))
-#endif
- __iax2_poke_peer_s(data);
- return 0;
-}
-
-static int send_trunk(struct iax2_trunk_peer *tpeer, struct timeval *now)
-{
- int res = 0;
- struct iax_frame *fr;
- struct ast_iax2_meta_hdr *meta;
- struct ast_iax2_meta_trunk_hdr *mth;
- int calls = 0;
-
- /* Point to frame */
- fr = (struct iax_frame *)tpeer->trunkdata;
- /* Point to meta data */
- meta = (struct ast_iax2_meta_hdr *)fr->afdata;
- mth = (struct ast_iax2_meta_trunk_hdr *)meta->data;
- if (tpeer->trunkdatalen) {
- /* We're actually sending a frame, so fill the meta trunk header and meta header */
- meta->zeros = 0;
- meta->metacmd = IAX_META_TRUNK;
- if (ast_test_flag(&globalflags, IAX_TRUNKTIMESTAMPS))
- meta->cmddata = IAX_META_TRUNK_MINI;
- else
- meta->cmddata = IAX_META_TRUNK_SUPERMINI;
- mth->ts = htonl(calc_txpeerstamp(tpeer, trunkfreq, now));
- /* And the rest of the ast_iax2 header */
- fr->direction = DIRECTION_OUTGRESS;
- fr->retrans = -1;
- fr->transfer = 0;
- /* Any appropriate call will do */
- fr->data = fr->afdata;
- fr->datalen = tpeer->trunkdatalen + sizeof(struct ast_iax2_meta_hdr) + sizeof(struct ast_iax2_meta_trunk_hdr);
- res = transmit_trunk(fr, &tpeer->addr, tpeer->sockfd);
- calls = tpeer->calls;
-#if 0
- if (option_debug)
- ast_log(LOG_DEBUG, "Trunking %d call chunks in %d bytes to %s:%d, ts=%d\n", calls, fr->datalen, ast_inet_ntoa(tpeer->addr.sin_addr), ntohs(tpeer->addr.sin_port), ntohl(mth->ts));
-#endif
- /* Reset transmit trunk side data */
- tpeer->trunkdatalen = 0;
- tpeer->calls = 0;
- }
- if (res < 0)
- return res;
- return calls;
-}
-
-static inline int iax2_trunk_expired(struct iax2_trunk_peer *tpeer, struct timeval *now)
-{
- /* Drop when trunk is about 5 seconds idle */
- if (now->tv_sec > tpeer->trunkact.tv_sec + 5)
- return 1;
- return 0;
-}
-
-static int timing_read(int *id, int fd, short events, void *cbdata)
-{
- char buf[1024];
- int res;
- struct iax2_trunk_peer *tpeer, *prev = NULL, *drop=NULL;
- int processed = 0;
- int totalcalls = 0;
-#ifdef DAHDI_TIMERACK
- int x = 1;
-#endif
- struct timeval now;
- if (iaxtrunkdebug)
- ast_verbose("Beginning trunk processing. Trunk queue ceiling is %d bytes per host\n", MAX_TRUNKDATA);
- gettimeofday(&now, NULL);
- if (events & AST_IO_PRI) {
-#ifdef DAHDI_TIMERACK
- /* Great, this is a timing interface, just call the ioctl */
- if (ioctl(fd, DAHDI_TIMERACK, &x)) {
- ast_log(LOG_WARNING, "Unable to acknowledge timer. IAX trunking will fail!\n");
- usleep(1);
- return -1;
- }
-#endif
- } else {
- /* Read and ignore from the pseudo channel for timing */
- res = read(fd, buf, sizeof(buf));
- if (res < 1) {
- ast_log(LOG_WARNING, "Unable to read from timing fd\n");
- return 1;
- }
- }
- /* For each peer that supports trunking... */
- ast_mutex_lock(&tpeerlock);
- tpeer = tpeers;
- while(tpeer) {
- processed++;
- res = 0;
- ast_mutex_lock(&tpeer->lock);
- /* We can drop a single tpeer per pass. That makes all this logic
- substantially easier */
- if (!drop && iax2_trunk_expired(tpeer, &now)) {
- /* Take it out of the list, but don't free it yet, because it
- could be in use */
- if (prev)
- prev->next = tpeer->next;
- else
- tpeers = tpeer->next;
- drop = tpeer;
- } else {
- res = send_trunk(tpeer, &now);
- if (iaxtrunkdebug)
- ast_verbose(" - Trunk peer (%s:%d) has %d call chunk%s in transit, %d bytes backloged and has hit a high water mark of %d bytes\n", ast_inet_ntoa(tpeer->addr.sin_addr), ntohs(tpeer->addr.sin_port), res, (res != 1) ? "s" : "", tpeer->trunkdatalen, tpeer->trunkdataalloc);
- }
- totalcalls += res;
- res = 0;
- ast_mutex_unlock(&tpeer->lock);
- prev = tpeer;
- tpeer = tpeer->next;
- }
- ast_mutex_unlock(&tpeerlock);
- if (drop) {
- ast_mutex_lock(&drop->lock);
- /* Once we have this lock, we're sure nobody else is using it or could use it once we release it,
- because by the time they could get tpeerlock, we've already grabbed it */
- if (option_debug)
- ast_log(LOG_DEBUG, "Dropping unused iax2 trunk peer '%s:%d'\n", ast_inet_ntoa(drop->addr.sin_addr), ntohs(drop->addr.sin_port));
- if (drop->trunkdata) {
- free(drop->trunkdata);
- drop->trunkdata = NULL;
- }
- ast_mutex_unlock(&drop->lock);
- ast_mutex_destroy(&drop->lock);
- free(drop);
-
- }
- if (iaxtrunkdebug)
- ast_verbose("Ending trunk processing with %d peers and %d call chunks processed\n", processed, totalcalls);
- iaxtrunkdebug =0;
- return 1;
-}
-
-struct dpreq_data {
- int callno;
- char context[AST_MAX_EXTENSION];
- char callednum[AST_MAX_EXTENSION];
- char *callerid;
-};
-
-static void dp_lookup(int callno, const char *context, const char *callednum, const char *callerid, int skiplock)
-{
- unsigned short dpstatus = 0;
- struct iax_ie_data ied1;
- int mm;
-
- memset(&ied1, 0, sizeof(ied1));
- mm = ast_matchmore_extension(NULL, context, callednum, 1, callerid);
- /* Must be started */
- if (!strcmp(callednum, ast_parking_ext()) || ast_exists_extension(NULL, context, callednum, 1, callerid)) {
- dpstatus = IAX_DPSTATUS_EXISTS;
- } else if (ast_canmatch_extension(NULL, context, callednum, 1, callerid)) {
- dpstatus = IAX_DPSTATUS_CANEXIST;
- } else {
- dpstatus = IAX_DPSTATUS_NONEXISTENT;
- }
- if (ast_ignore_pattern(context, callednum))
- dpstatus |= IAX_DPSTATUS_IGNOREPAT;
- if (mm)
- dpstatus |= IAX_DPSTATUS_MATCHMORE;
- if (!skiplock)
- ast_mutex_lock(&iaxsl[callno]);
- if (iaxs[callno]) {
- iax_ie_append_str(&ied1, IAX_IE_CALLED_NUMBER, callednum);
- iax_ie_append_short(&ied1, IAX_IE_DPSTATUS, dpstatus);
- iax_ie_append_short(&ied1, IAX_IE_REFRESH, iaxdefaultdpcache);
- send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_DPREP, 0, ied1.buf, ied1.pos, -1);
- }
- if (!skiplock)
- ast_mutex_unlock(&iaxsl[callno]);
-}
-
-static void *dp_lookup_thread(void *data)
-{
- /* Look up for dpreq */
- struct dpreq_data *dpr = data;
- dp_lookup(dpr->callno, dpr->context, dpr->callednum, dpr->callerid, 0);
- if (dpr->callerid)
- free(dpr->callerid);
- free(dpr);
- return NULL;
-}
-
-static void spawn_dp_lookup(int callno, const char *context, const char *callednum, const char *callerid)
-{
- pthread_t newthread;
- struct dpreq_data *dpr;
- pthread_attr_t attr;
-
- if (!(dpr = ast_calloc(1, sizeof(*dpr))))
- return;
-
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-
- dpr->callno = callno;
- ast_copy_string(dpr->context, context, sizeof(dpr->context));
- ast_copy_string(dpr->callednum, callednum, sizeof(dpr->callednum));
- if (callerid)
- dpr->callerid = ast_strdup(callerid);
- if (ast_pthread_create(&newthread, &attr, dp_lookup_thread, dpr)) {
- ast_log(LOG_WARNING, "Unable to start lookup thread!\n");
- }
-
- pthread_attr_destroy(&attr);
-}
-
-struct iax_dual {
- struct ast_channel *chan1;
- struct ast_channel *chan2;
-};
-
-static void *iax_park_thread(void *stuff)
-{
- struct ast_channel *chan1, *chan2;
- struct iax_dual *d;
- struct ast_frame *f;
- int ext;
- int res;
- d = stuff;
- chan1 = d->chan1;
- chan2 = d->chan2;
- free(d);
- f = ast_read(chan1);
- if (f)
- ast_frfree(f);
- res = ast_park_call(chan1, chan2, 0, &ext);
- ast_hangup(chan2);
- ast_log(LOG_NOTICE, "Parked on extension '%d'\n", ext);
- return NULL;
-}
-
-static int iax_park(struct ast_channel *chan1, struct ast_channel *chan2)
-{
- struct iax_dual *d;
- struct ast_channel *chan1m, *chan2m;
- pthread_t th;
- chan1m = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, chan2->accountcode, chan1->exten, chan1->context, chan1->amaflags, "Parking/%s", chan1->name);
- chan2m = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, chan2->accountcode, chan2->exten, chan2->context, chan2->amaflags, "IAXPeer/%s",chan2->name);
- if (chan2m && chan1m) {
- /* Make formats okay */
- chan1m->readformat = chan1->readformat;
- chan1m->writeformat = chan1->writeformat;
- ast_channel_masquerade(chan1m, chan1);
- /* Setup the extensions and such */
- ast_copy_string(chan1m->context, chan1->context, sizeof(chan1m->context));
- ast_copy_string(chan1m->exten, chan1->exten, sizeof(chan1m->exten));
- chan1m->priority = chan1->priority;
-
- /* We make a clone of the peer channel too, so we can play
- back the announcement */
- /* Make formats okay */
- chan2m->readformat = chan2->readformat;
- chan2m->writeformat = chan2->writeformat;
- ast_channel_masquerade(chan2m, chan2);
- /* Setup the extensions and such */
- ast_copy_string(chan2m->context, chan2->context, sizeof(chan2m->context));
- ast_copy_string(chan2m->exten, chan2->exten, sizeof(chan2m->exten));
- chan2m->priority = chan2->priority;
- if (ast_do_masquerade(chan2m)) {
- ast_log(LOG_WARNING, "Masquerade failed :(\n");
- ast_hangup(chan2m);
- return -1;
- }
- } else {
- if (chan1m)
- ast_hangup(chan1m);
- if (chan2m)
- ast_hangup(chan2m);
- return -1;
- }
- if ((d = ast_calloc(1, sizeof(*d)))) {
- pthread_attr_t attr;
-
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-
- d->chan1 = chan1m;
- d->chan2 = chan2m;
- if (!ast_pthread_create_background(&th, &attr, iax_park_thread, d)) {
- pthread_attr_destroy(&attr);
- return 0;
- }
- pthread_attr_destroy(&attr);
- free(d);
- }
- return -1;
-}
-
-
-static int iax2_provision(struct sockaddr_in *end, int sockfd, char *dest, const char *template, int force);
-
-static int check_provisioning(struct sockaddr_in *sin, int sockfd, char *si, unsigned int ver)
-{
- unsigned int ourver;
- char rsi[80];
- snprintf(rsi, sizeof(rsi), "si-%s", si);
- if (iax_provision_version(&ourver, rsi, 1))
- return 0;
- if (option_debug)
- ast_log(LOG_DEBUG, "Service identifier '%s', we think '%08x', they think '%08x'\n", si, ourver, ver);
- if (ourver != ver)
- iax2_provision(sin, sockfd, NULL, rsi, 1);
- return 0;
-}
-
-static void construct_rr(struct chan_iax2_pvt *pvt, struct iax_ie_data *iep)
-{
- jb_info stats;
- jb_getinfo(pvt->jb, &stats);
-
- memset(iep, 0, sizeof(*iep));
-
- iax_ie_append_int(iep,IAX_IE_RR_JITTER, stats.jitter);
- if(stats.frames_in == 0) stats.frames_in = 1;
- iax_ie_append_int(iep,IAX_IE_RR_LOSS, ((0xff & (stats.losspct/1000)) << 24 | (stats.frames_lost & 0x00ffffff)));
- iax_ie_append_int(iep,IAX_IE_RR_PKTS, stats.frames_in);
- iax_ie_append_short(iep,IAX_IE_RR_DELAY, stats.current - stats.min);
- iax_ie_append_int(iep,IAX_IE_RR_DROPPED, stats.frames_dropped);
- iax_ie_append_int(iep,IAX_IE_RR_OOO, stats.frames_ooo);
-}
-
-static void save_rr(struct iax_frame *fr, struct iax_ies *ies)
-{
- iaxs[fr->callno]->remote_rr.jitter = ies->rr_jitter;
- iaxs[fr->callno]->remote_rr.losspct = ies->rr_loss >> 24;
- iaxs[fr->callno]->remote_rr.losscnt = ies->rr_loss & 0xffffff;
- iaxs[fr->callno]->remote_rr.packets = ies->rr_pkts;
- iaxs[fr->callno]->remote_rr.delay = ies->rr_delay;
- iaxs[fr->callno]->remote_rr.dropped = ies->rr_dropped;
- iaxs[fr->callno]->remote_rr.ooo = ies->rr_ooo;
-}
-
-static int socket_process(struct iax2_thread *thread);
-
-/*!
- * \brief Handle any deferred full frames for this thread
- */
-static void handle_deferred_full_frames(struct iax2_thread *thread)
-{
- struct iax2_pkt_buf *pkt_buf;
-
- ast_mutex_lock(&thread->lock);
-
- while ((pkt_buf = AST_LIST_REMOVE_HEAD(&thread->full_frames, entry))) {
- ast_mutex_unlock(&thread->lock);
-
- thread->buf = pkt_buf->buf;
- thread->buf_len = pkt_buf->len;
- thread->buf_size = pkt_buf->len + 1;
-
- socket_process(thread);
-
- thread->buf = NULL;
- ast_free(pkt_buf);
-
- ast_mutex_lock(&thread->lock);
- }
-
- ast_mutex_unlock(&thread->lock);
-}
-
-/*!
- * \brief Queue the last read full frame for processing by a certain thread
- *
- * If there are already any full frames queued, they are sorted
- * by sequence number.
- */
-static void defer_full_frame(struct iax2_thread *from_here, struct iax2_thread *to_here)
-{
- struct iax2_pkt_buf *pkt_buf, *cur_pkt_buf;
- struct ast_iax2_full_hdr *fh, *cur_fh;
-
- if (!(pkt_buf = ast_calloc(1, sizeof(*pkt_buf) + from_here->buf_len)))
- return;
-
- pkt_buf->len = from_here->buf_len;
- memcpy(pkt_buf->buf, from_here->buf, pkt_buf->len);
-
- fh = (struct ast_iax2_full_hdr *) pkt_buf->buf;
- ast_mutex_lock(&to_here->lock);
- AST_LIST_TRAVERSE_SAFE_BEGIN(&to_here->full_frames, cur_pkt_buf, entry) {
- cur_fh = (struct ast_iax2_full_hdr *) cur_pkt_buf->buf;
- if (fh->oseqno < cur_fh->oseqno) {
- AST_LIST_INSERT_BEFORE_CURRENT(&to_here->full_frames, pkt_buf, entry);
- break;
- }
- }
- AST_LIST_TRAVERSE_SAFE_END
-
- if (!cur_pkt_buf)
- AST_LIST_INSERT_TAIL(&to_here->full_frames, pkt_buf, entry);
-
- ast_mutex_unlock(&to_here->lock);
-}
-
-static int socket_read(int *id, int fd, short events, void *cbdata)
-{
- struct iax2_thread *thread;
- socklen_t len;
- time_t t;
- static time_t last_errtime = 0;
- struct ast_iax2_full_hdr *fh;
-
- if (!(thread = find_idle_thread())) {
- time(&t);
- if (t != last_errtime && option_debug)
- ast_log(LOG_DEBUG, "Out of idle IAX2 threads for I/O, pausing!\n");
- last_errtime = t;
- usleep(1);
- return 1;
- }
-
- len = sizeof(thread->iosin);
- thread->iofd = fd;
- thread->buf_len = recvfrom(fd, thread->readbuf, sizeof(thread->readbuf), 0, (struct sockaddr *) &thread->iosin, &len);
- thread->buf_size = sizeof(thread->readbuf);
- thread->buf = thread->readbuf;
- if (thread->buf_len < 0) {
- if (errno != ECONNREFUSED && errno != EAGAIN)
- ast_log(LOG_WARNING, "Error: %s\n", strerror(errno));
- handle_error();
- thread->iostate = IAX_IOSTATE_IDLE;
- signal_condition(&thread->lock, &thread->cond);
- return 1;
- }
- if (test_losspct && ((100.0 * ast_random() / (RAND_MAX + 1.0)) < test_losspct)) { /* simulate random loss condition */
- thread->iostate = IAX_IOSTATE_IDLE;
- signal_condition(&thread->lock, &thread->cond);
- return 1;
- }
-
- /* Determine if this frame is a full frame; if so, and any thread is currently
- processing a full frame for the same callno from this peer, then drop this
- frame (and the peer will retransmit it) */
- fh = (struct ast_iax2_full_hdr *) thread->buf;
- if (ntohs(fh->scallno) & IAX_FLAG_FULL) {
- struct iax2_thread *cur = NULL;
- uint16_t callno = ntohs(fh->scallno) & ~IAX_FLAG_FULL;
-
- AST_LIST_LOCK(&active_list);
- AST_LIST_TRAVERSE(&active_list, cur, list) {
- if ((cur->ffinfo.callno == callno) &&
- !inaddrcmp(&cur->ffinfo.sin, &thread->iosin))
- break;
- }
- if (cur) {
- /* we found another thread processing a full frame for this call,
- so queue it up for processing later. */
- defer_full_frame(thread, cur);
- AST_LIST_UNLOCK(&active_list);
- thread->iostate = IAX_IOSTATE_IDLE;
- signal_condition(&thread->lock, &thread->cond);
- return 1;
- } else {
- /* this thread is going to process this frame, so mark it */
- thread->ffinfo.callno = callno;
- memcpy(&thread->ffinfo.sin, &thread->iosin, sizeof(thread->ffinfo.sin));
- thread->ffinfo.type = fh->type;
- thread->ffinfo.csub = fh->csub;
- }
- AST_LIST_UNLOCK(&active_list);
- }
-
- /* Mark as ready and send on its way */
- thread->iostate = IAX_IOSTATE_READY;
-#ifdef DEBUG_SCHED_MULTITHREAD
- ast_copy_string(thread->curfunc, "socket_process", sizeof(thread->curfunc));
-#endif
- signal_condition(&thread->lock, &thread->cond);
-
- return 1;
-}
-
-static int socket_process(struct iax2_thread *thread)
-{
- struct sockaddr_in sin;
- int res;
- int updatehistory=1;
- int new = NEW_PREVENT;
- void *ptr;
- int dcallno = 0;
- struct ast_iax2_full_hdr *fh = (struct ast_iax2_full_hdr *)thread->buf;
- struct ast_iax2_mini_hdr *mh = (struct ast_iax2_mini_hdr *)thread->buf;
- struct ast_iax2_meta_hdr *meta = (struct ast_iax2_meta_hdr *)thread->buf;
- struct ast_iax2_video_hdr *vh = (struct ast_iax2_video_hdr *)thread->buf;
- struct ast_iax2_meta_trunk_hdr *mth;
- struct ast_iax2_meta_trunk_entry *mte;
- struct ast_iax2_meta_trunk_mini *mtm;
- struct iax_frame *fr;
- struct iax_frame *cur;
- struct ast_frame f = { 0, };
- struct ast_channel *c;
- struct iax2_dpcache *dp;
- struct iax2_peer *peer;
- struct iax2_trunk_peer *tpeer;
- struct timeval rxtrunktime;
- struct iax_ies ies;
- struct iax_ie_data ied0, ied1;
- int format;
- int fd;
- int exists;
- int minivid = 0;
- unsigned int ts;
- char empty[32]=""; /* Safety measure */
- struct iax_frame *duped_fr;
- char host_pref_buf[128];
- char caller_pref_buf[128];
- struct ast_codec_pref pref;
- char *using_prefs = "mine";
-
- /* allocate an iax_frame with 4096 bytes of data buffer */
- fr = alloca(sizeof(*fr) + 4096);
- memset(fr, 0, sizeof(*fr));
- fr->afdatalen = 4096; /* From alloca() above */
-
- /* Copy frequently used parameters to the stack */
- res = thread->buf_len;
- fd = thread->iofd;
- memcpy(&sin, &thread->iosin, sizeof(sin));
-
- if (res < sizeof(*mh)) {
- ast_log(LOG_WARNING, "midget packet received (%d of %zd min)\n", res, sizeof(*mh));
- return 1;
- }
- if ((vh->zeros == 0) && (ntohs(vh->callno) & 0x8000)) {
- if (res < sizeof(*vh)) {
- ast_log(LOG_WARNING, "Rejecting packet from '%s.%d' that is flagged as a video frame but is too short\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
- return 1;
- }
-
- /* This is a video frame, get call number */
- fr->callno = find_callno(ntohs(vh->callno) & ~0x8000, dcallno, &sin, new, fd, 0);
- minivid = 1;
- } else if ((meta->zeros == 0) && !(ntohs(meta->metacmd) & 0x8000)) {
- unsigned char metatype;
-
- if (res < sizeof(*meta)) {
- ast_log(LOG_WARNING, "Rejecting packet from '%s.%d' that is flagged as a meta frame but is too short\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
- return 1;
- }
-
- /* This is a meta header */
- switch(meta->metacmd) {
- case IAX_META_TRUNK:
- if (res < (sizeof(*meta) + sizeof(*mth))) {
- ast_log(LOG_WARNING, "midget meta trunk packet received (%d of %zd min)\n", res,
- sizeof(*meta) + sizeof(*mth));
- return 1;
- }
- mth = (struct ast_iax2_meta_trunk_hdr *)(meta->data);
- ts = ntohl(mth->ts);
- metatype = meta->cmddata;
- res -= (sizeof(*meta) + sizeof(*mth));
- ptr = mth->data;
- tpeer = find_tpeer(&sin, fd);
- if (!tpeer) {
- ast_log(LOG_WARNING, "Unable to accept trunked packet from '%s:%d': No matching peer\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
- return 1;
- }
- tpeer->trunkact = ast_tvnow();
- if (!ts || ast_tvzero(tpeer->rxtrunktime))
- tpeer->rxtrunktime = tpeer->trunkact;
- rxtrunktime = tpeer->rxtrunktime;
- ast_mutex_unlock(&tpeer->lock);
- while(res >= sizeof(*mte)) {
- /* Process channels */
- unsigned short callno, trunked_ts, len;
-
- if (metatype == IAX_META_TRUNK_MINI) {
- mtm = (struct ast_iax2_meta_trunk_mini *)ptr;
- ptr += sizeof(*mtm);
- res -= sizeof(*mtm);
- len = ntohs(mtm->len);
- callno = ntohs(mtm->mini.callno);
- trunked_ts = ntohs(mtm->mini.ts);
- } else if (metatype == IAX_META_TRUNK_SUPERMINI) {
- mte = (struct ast_iax2_meta_trunk_entry *)ptr;
- ptr += sizeof(*mte);
- res -= sizeof(*mte);
- len = ntohs(mte->len);
- callno = ntohs(mte->callno);
- trunked_ts = 0;
- } else {
- ast_log(LOG_WARNING, "Unknown meta trunk cmd from '%s:%d': dropping\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
- break;
- }
- /* Stop if we don't have enough data */
- if (len > res)
- break;
- fr->callno = find_callno_locked(callno & ~IAX_FLAG_FULL, 0, &sin, NEW_PREVENT, fd, 0);
- if (fr->callno) {
- /* If it's a valid call, deliver the contents. If not, we
- drop it, since we don't have a scallno to use for an INVAL */
- /* Process as a mini frame */
- memset(&f, 0, sizeof(f));
- f.frametype = AST_FRAME_VOICE;
- if (iaxs[fr->callno]) {
- if (iaxs[fr->callno]->voiceformat > 0) {
- f.subclass = iaxs[fr->callno]->voiceformat;
- f.datalen = len;
- if (f.datalen >= 0) {
- if (f.datalen)
- f.data = ptr;
- if(trunked_ts) {
- fr->ts = (iaxs[fr->callno]->last & 0xFFFF0000L) | (trunked_ts & 0xffff);
- } else
- fr->ts = fix_peerts(&rxtrunktime, fr->callno, ts);
- /* Don't pass any packets until we're started */
- if (ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED)) {
- /* Common things */
- f.src = "IAX2";
- if (f.datalen && (f.frametype == AST_FRAME_VOICE))
- f.samples = ast_codec_get_samples(&f);
- iax_frame_wrap(fr, &f);
- duped_fr = iaxfrdup2(fr);
- if (duped_fr) {
- schedule_delivery(duped_fr, updatehistory, 1, &fr->ts);
- }
- /* It is possible for the pvt structure to go away after we call schedule_delivery */
- if (iaxs[fr->callno] && iaxs[fr->callno]->last < fr->ts) {
- iaxs[fr->callno]->last = fr->ts;
-#if 1
- if (option_debug && iaxdebug)
- ast_log(LOG_DEBUG, "For call=%d, set last=%d\n", fr->callno, fr->ts);
-#endif
- }
- }
- } else {
- ast_log(LOG_WARNING, "Datalen < 0?\n");
- }
- } else {
- ast_log(LOG_WARNING, "Received trunked frame before first full voice frame\n");
- iax2_vnak(fr->callno);
- }
- }
- ast_mutex_unlock(&iaxsl[fr->callno]);
- }
- ptr += len;
- res -= len;
- }
-
- }
- return 1;
- }
-
-#ifdef DEBUG_SUPPORT
- if (iaxdebug && (res >= sizeof(*fh)))
- iax_showframe(NULL, fh, 1, &sin, res - sizeof(*fh));
-#endif
- if (ntohs(mh->callno) & IAX_FLAG_FULL) {
- if (res < sizeof(*fh)) {
- ast_log(LOG_WARNING, "Rejecting packet from '%s.%d' that is flagged as a full frame but is too short\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
- return 1;
- }
-
- /* Get the destination call number */
- dcallno = ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS;
- /* Retrieve the type and subclass */
- f.frametype = fh->type;
- if (f.frametype == AST_FRAME_VIDEO) {
- f.subclass = uncompress_subclass(fh->csub & ~0x40) | ((fh->csub >> 6) & 0x1);
- } else {
- f.subclass = uncompress_subclass(fh->csub);
- }
-
- /* Deal with POKE/PONG without allocating a callno */
- if (f.frametype == AST_FRAME_IAX && f.subclass == IAX_COMMAND_POKE) {
- /* Reply back with a PONG, but don't care about the result. */
- send_apathetic_reply(1, ntohs(fh->scallno), &sin, IAX_COMMAND_PONG, ntohs(fh->ts), fh->iseqno + 1);
- return 1;
- } else if (f.frametype == AST_FRAME_IAX && f.subclass == IAX_COMMAND_ACK && dcallno == 1) {
- /* Ignore */
- return 1;
- }
-
- if ((f.frametype == AST_FRAME_IAX) && ((f.subclass == IAX_COMMAND_NEW) || (f.subclass == IAX_COMMAND_REGREQ) ||
- (f.subclass == IAX_COMMAND_POKE) || (f.subclass == IAX_COMMAND_FWDOWNL) ||
- (f.subclass == IAX_COMMAND_REGREL)))
- new = NEW_ALLOW;
- } else {
- /* Don't know anything about it yet */
- f.frametype = AST_FRAME_NULL;
- f.subclass = 0;
- }
-
- if (!fr->callno) {
- int check_dcallno = 0;
-
- /*
- * We enforce accurate destination call numbers for all full frames except
- * LAGRQ and PING commands. This is because older versions of Asterisk
- * schedule these commands to get sent very quickly, and they will sometimes
- * be sent before they receive the first frame from the other side. When
- * that happens, it doesn't contain the destination call number. However,
- * not checking it for these frames is safe.
- *
- * Discussed in the following thread:
- * http://lists.digium.com/pipermail/asterisk-dev/2008-May/033217.html
- */
-
- if (ntohs(mh->callno) & IAX_FLAG_FULL) {
- check_dcallno = f.frametype == AST_FRAME_IAX ? (f.subclass != IAX_COMMAND_PING && f.subclass != IAX_COMMAND_LAGRQ) : 1;
- }
-
- fr->callno = find_callno(ntohs(mh->callno) & ~IAX_FLAG_FULL, dcallno, &sin, new, fd, check_dcallno);
- }
-
- if (fr->callno > 0)
- ast_mutex_lock(&iaxsl[fr->callno]);
-
- if (!fr->callno || !iaxs[fr->callno]) {
- /* A call arrived for a nonexistent destination. Unless it's an "inval"
- frame, reply with an inval */
- if (ntohs(mh->callno) & IAX_FLAG_FULL) {
- /* We can only raw hangup control frames */
- if (((f.subclass != IAX_COMMAND_INVAL) &&
- (f.subclass != IAX_COMMAND_TXCNT) &&
- (f.subclass != IAX_COMMAND_TXACC) &&
- (f.subclass != IAX_COMMAND_FWDOWNL))||
- (f.frametype != AST_FRAME_IAX))
- raw_hangup(&sin, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS, ntohs(mh->callno) & ~IAX_FLAG_FULL,
- fd);
- }
- if (fr->callno > 0)
- ast_mutex_unlock(&iaxsl[fr->callno]);
- return 1;
- }
- if (ast_test_flag(iaxs[fr->callno], IAX_ENCRYPTED)) {
- if (decrypt_frame(fr->callno, fh, &f, &res)) {
- ast_log(LOG_NOTICE, "Packet Decrypt Failed!\n");
- ast_mutex_unlock(&iaxsl[fr->callno]);
- return 1;
- }
-#ifdef DEBUG_SUPPORT
- else if (iaxdebug)
- iax_showframe(NULL, fh, 3, &sin, res - sizeof(*fh));
-#endif
- }
-
- /* count this frame */
- iaxs[fr->callno]->frames_received++;
-
- if (!inaddrcmp(&sin, &iaxs[fr->callno]->addr) && !minivid &&
- f.subclass != IAX_COMMAND_TXCNT && /* for attended transfer */
- f.subclass != IAX_COMMAND_TXACC) { /* for attended transfer */
- unsigned short new_peercallno;
-
- new_peercallno = (unsigned short) (ntohs(mh->callno) & ~IAX_FLAG_FULL);
- if (new_peercallno && new_peercallno != iaxs[fr->callno]->peercallno) {
- if (iaxs[fr->callno]->peercallno) {
- remove_by_peercallno(iaxs[fr->callno]);
- }
- iaxs[fr->callno]->peercallno = new_peercallno;
- store_by_peercallno(iaxs[fr->callno]);
- }
- }
- if (ntohs(mh->callno) & IAX_FLAG_FULL) {
- if (option_debug && iaxdebug)
- ast_log(LOG_DEBUG, "Received packet %d, (%d, %d)\n", fh->oseqno, f.frametype, f.subclass);
- /* Check if it's out of order (and not an ACK or INVAL) */
- fr->oseqno = fh->oseqno;
- fr->iseqno = fh->iseqno;
- fr->ts = ntohl(fh->ts);
-#ifdef IAXTESTS
- if (test_resync) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Simulating frame ts resync, was %u now %u\n", fr->ts, fr->ts + test_resync);
- fr->ts += test_resync;
- }
-#endif /* IAXTESTS */
-#if 0
- if ( (ntohs(fh->dcallno) & IAX_FLAG_RETRANS) ||
- ( (f.frametype != AST_FRAME_VOICE) && ! (f.frametype == AST_FRAME_IAX &&
- (f.subclass == IAX_COMMAND_NEW ||
- f.subclass == IAX_COMMAND_AUTHREQ ||
- f.subclass == IAX_COMMAND_ACCEPT ||
- f.subclass == IAX_COMMAND_REJECT)) ) )
-#endif
- if ((ntohs(fh->dcallno) & IAX_FLAG_RETRANS) || (f.frametype != AST_FRAME_VOICE))
- updatehistory = 0;
- if ((iaxs[fr->callno]->iseqno != fr->oseqno) &&
- (iaxs[fr->callno]->iseqno ||
- ((f.subclass != IAX_COMMAND_TXCNT) &&
- (f.subclass != IAX_COMMAND_TXREADY) && /* for attended transfer */
- (f.subclass != IAX_COMMAND_TXREL) && /* for attended transfer */
- (f.subclass != IAX_COMMAND_UNQUELCH ) && /* for attended transfer */
- (f.subclass != IAX_COMMAND_TXACC)) ||
- (f.frametype != AST_FRAME_IAX))) {
- if (
- ((f.subclass != IAX_COMMAND_ACK) &&
- (f.subclass != IAX_COMMAND_INVAL) &&
- (f.subclass != IAX_COMMAND_TXCNT) &&
- (f.subclass != IAX_COMMAND_TXREADY) && /* for attended transfer */
- (f.subclass != IAX_COMMAND_TXREL) && /* for attended transfer */
- (f.subclass != IAX_COMMAND_UNQUELCH ) && /* for attended transfer */
- (f.subclass != IAX_COMMAND_TXACC) &&
- (f.subclass != IAX_COMMAND_VNAK)) ||
- (f.frametype != AST_FRAME_IAX)) {
- /* If it's not an ACK packet, it's out of order. */
- if (option_debug)
- ast_log(LOG_DEBUG, "Packet arrived out of order (expecting %d, got %d) (frametype = %d, subclass = %d)\n",
- iaxs[fr->callno]->iseqno, fr->oseqno, f.frametype, f.subclass);
- /* Check to see if we need to request retransmission,
- * and take sequence number wraparound into account */
- if ((unsigned char) (iaxs[fr->callno]->iseqno - fr->oseqno) < 128) {
- /* If we've already seen it, ack it XXX There's a border condition here XXX */
- if ((f.frametype != AST_FRAME_IAX) ||
- ((f.subclass != IAX_COMMAND_ACK) && (f.subclass != IAX_COMMAND_INVAL))) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Acking anyway\n");
- /* XXX Maybe we should handle its ack to us, but then again, it's probably outdated anyway, and if
- we have anything to send, we'll retransmit and get an ACK back anyway XXX */
- send_command_immediate(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr->ts, NULL, 0,fr->iseqno);
- }
- } else {
- /* Send a VNAK requesting retransmission */
- iax2_vnak(fr->callno);
- }
- ast_mutex_unlock(&iaxsl[fr->callno]);
- return 1;
- }
- } else {
- /* Increment unless it's an ACK or VNAK */
- if (((f.subclass != IAX_COMMAND_ACK) &&
- (f.subclass != IAX_COMMAND_INVAL) &&
- (f.subclass != IAX_COMMAND_TXCNT) &&
- (f.subclass != IAX_COMMAND_TXACC) &&
- (f.subclass != IAX_COMMAND_VNAK)) ||
- (f.frametype != AST_FRAME_IAX))
- iaxs[fr->callno]->iseqno++;
- }
- /* A full frame */
- if (res < sizeof(*fh)) {
- ast_log(LOG_WARNING, "midget packet received (%d of %zd min)\n", res, sizeof(*fh));
- ast_mutex_unlock(&iaxsl[fr->callno]);
- return 1;
- }
- /* Ensure text frames are NULL-terminated */
- if (f.frametype == AST_FRAME_TEXT && thread->buf[res - 1] != '\0') {
- if (res < thread->buf_size)
- thread->buf[res++] = '\0';
- else /* Trims one character from the text message, but that's better than overwriting the end of the buffer. */
- thread->buf[res - 1] = '\0';
- }
- f.datalen = res - sizeof(*fh);
-
- /* Handle implicit ACKing unless this is an INVAL, and only if this is
- from the real peer, not the transfer peer */
- if (!inaddrcmp(&sin, &iaxs[fr->callno]->addr) &&
- ((f.subclass != IAX_COMMAND_INVAL) ||
- (f.frametype != AST_FRAME_IAX))) {
- unsigned char x;
- int call_to_destroy;
- /* XXX This code is not very efficient. Surely there is a better way which still
- properly handles boundary conditions? XXX */
- /* First we have to qualify that the ACKed value is within our window */
- for (x=iaxs[fr->callno]->rseqno; x != iaxs[fr->callno]->oseqno; x++)
- if (fr->iseqno == x)
- break;
- if ((x != iaxs[fr->callno]->oseqno) || (iaxs[fr->callno]->oseqno == fr->iseqno)) {
- /* The acknowledgement is within our window. Time to acknowledge everything
- that it says to */
- for (x=iaxs[fr->callno]->rseqno; x != fr->iseqno; x++) {
- /* Ack the packet with the given timestamp */
- if (option_debug && iaxdebug)
- ast_log(LOG_DEBUG, "Cancelling transmission of packet %d\n", x);
- call_to_destroy = 0;
- AST_LIST_LOCK(&iaxq.queue);
- AST_LIST_TRAVERSE(&iaxq.queue, cur, list) {
- /* If it's our call, and our timestamp, mark -1 retries */
- if ((fr->callno == cur->callno) && (x == cur->oseqno)) {
- cur->retries = -1;
- /* Destroy call if this is the end */
- if (cur->final)
- call_to_destroy = fr->callno;
- }
- }
- AST_LIST_UNLOCK(&iaxq.queue);
- if (call_to_destroy) {
- if (iaxdebug && option_debug)
- ast_log(LOG_DEBUG, "Really destroying %d, having been acked on final message\n", call_to_destroy);
- ast_mutex_lock(&iaxsl[call_to_destroy]);
- iax2_destroy(call_to_destroy);
- ast_mutex_unlock(&iaxsl[call_to_destroy]);
- }
- }
- /* Note how much we've received acknowledgement for */
- if (iaxs[fr->callno])
- iaxs[fr->callno]->rseqno = fr->iseqno;
- else {
- /* Stop processing now */
- ast_mutex_unlock(&iaxsl[fr->callno]);
- return 1;
- }
- } else if (option_debug)
- ast_log(LOG_DEBUG, "Received iseqno %d not within window %d->%d\n", fr->iseqno, iaxs[fr->callno]->rseqno, iaxs[fr->callno]->oseqno);
- }
- if (inaddrcmp(&sin, &iaxs[fr->callno]->addr) &&
- ((f.frametype != AST_FRAME_IAX) ||
- ((f.subclass != IAX_COMMAND_TXACC) &&
- (f.subclass != IAX_COMMAND_TXCNT)))) {
- /* Only messages we accept from a transfer host are TXACC and TXCNT */
- ast_mutex_unlock(&iaxsl[fr->callno]);
- return 1;
- }
-
- if (f.datalen) {
- if (f.frametype == AST_FRAME_IAX) {
- if (iax_parse_ies(&ies, thread->buf + sizeof(*fh), f.datalen)) {
- ast_log(LOG_WARNING, "Undecodable frame received from '%s'\n", ast_inet_ntoa(sin.sin_addr));
- ast_mutex_unlock(&iaxsl[fr->callno]);
- return 1;
- }
- f.data = NULL;
- f.datalen = 0;
- } else
- f.data = thread->buf + sizeof(*fh);
- } else {
- if (f.frametype == AST_FRAME_IAX)
- f.data = NULL;
- else
- f.data = empty;
- memset(&ies, 0, sizeof(ies));
- }
-
- /* when we receive the first full frame for a new incoming channel,
- it is safe to start the PBX on the channel because we have now
- completed a 3-way handshake with the peer */
- if ((f.frametype == AST_FRAME_VOICE) ||
- (f.frametype == AST_FRAME_VIDEO) ||
- (f.frametype == AST_FRAME_IAX)) {
- if (ast_test_flag(iaxs[fr->callno], IAX_DELAYPBXSTART)) {
- ast_clear_flag(iaxs[fr->callno], IAX_DELAYPBXSTART);
- if (!ast_iax2_new(fr->callno, AST_STATE_RING, iaxs[fr->callno]->chosenformat)) {
- ast_mutex_unlock(&iaxsl[fr->callno]);
- return 1;
- }
- }
- }
-
- if (f.frametype == AST_FRAME_VOICE) {
- if (f.subclass != iaxs[fr->callno]->voiceformat) {
- iaxs[fr->callno]->voiceformat = f.subclass;
- if (option_debug)
- ast_log(LOG_DEBUG, "Ooh, voice format changed to %d\n", f.subclass);
- if (iaxs[fr->callno]->owner) {
- int orignative;
-retryowner:
- if (ast_mutex_trylock(&iaxs[fr->callno]->owner->lock)) {
- DEADLOCK_AVOIDANCE(&iaxsl[fr->callno]);
- if (iaxs[fr->callno] && iaxs[fr->callno]->owner) goto retryowner;
- }
- if (iaxs[fr->callno]) {
- if (iaxs[fr->callno]->owner) {
- orignative = iaxs[fr->callno]->owner->nativeformats;
- iaxs[fr->callno]->owner->nativeformats = f.subclass;
- if (iaxs[fr->callno]->owner->readformat)
- ast_set_read_format(iaxs[fr->callno]->owner, iaxs[fr->callno]->owner->readformat);
- iaxs[fr->callno]->owner->nativeformats = orignative;
- ast_mutex_unlock(&iaxs[fr->callno]->owner->lock);
- }
- } else {
- if (option_debug)
- ast_log(LOG_DEBUG, "Neat, somebody took away the channel at a magical time but i found it!\n");
- ast_mutex_unlock(&iaxsl[fr->callno]);
- return 1;
- }
- }
- }
- }
- if (f.frametype == AST_FRAME_VIDEO) {
- if (f.subclass != iaxs[fr->callno]->videoformat) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Ooh, video format changed to %d\n", f.subclass & ~0x1);
- iaxs[fr->callno]->videoformat = f.subclass & ~0x1;
- }
- }
- if (f.frametype == AST_FRAME_CONTROL && iaxs[fr->callno]->owner) {
- if (f.subclass == AST_CONTROL_BUSY) {
- iaxs[fr->callno]->owner->hangupcause = AST_CAUSE_BUSY;
- } else if (f.subclass == AST_CONTROL_CONGESTION) {
- iaxs[fr->callno]->owner->hangupcause = AST_CAUSE_CONGESTION;
- }
- }
- if (f.frametype == AST_FRAME_IAX) {
- AST_SCHED_DEL(sched, iaxs[fr->callno]->initid);
- /* Handle the IAX pseudo frame itself */
- if (option_debug && iaxdebug)
- ast_log(LOG_DEBUG, "IAX subclass %d received\n", f.subclass);
-
- /* Update last ts unless the frame's timestamp originated with us. */
- if (iaxs[fr->callno]->last < fr->ts &&
- f.subclass != IAX_COMMAND_ACK &&
- f.subclass != IAX_COMMAND_PONG &&
- f.subclass != IAX_COMMAND_LAGRP) {
- iaxs[fr->callno]->last = fr->ts;
- if (option_debug && iaxdebug)
- ast_log(LOG_DEBUG, "For call=%d, set last=%d\n", fr->callno, fr->ts);
- }
-
- switch(f.subclass) {
- case IAX_COMMAND_ACK:
- /* Do nothing */
- break;
- case IAX_COMMAND_QUELCH:
- if (ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED)) {
- /* Generate Manager Hold event, if necessary*/
- if (iaxs[fr->callno]->owner) {
- manager_event(EVENT_FLAG_CALL, "Hold",
- "Channel: %s\r\n"
- "Uniqueid: %s\r\n",
- iaxs[fr->callno]->owner->name,
- iaxs[fr->callno]->owner->uniqueid);
- }
-
- ast_set_flag(iaxs[fr->callno], IAX_QUELCH);
- if (ies.musiconhold) {
- if (iaxs[fr->callno]->owner && ast_bridged_channel(iaxs[fr->callno]->owner)) {
- const char *mohsuggest = iaxs[fr->callno]->mohsuggest;
- iax2_queue_control_data(fr->callno, AST_CONTROL_HOLD,
- S_OR(mohsuggest, NULL),
- !ast_strlen_zero(mohsuggest) ? strlen(mohsuggest) + 1 : 0);
- if (!iaxs[fr->callno]) {
- ast_mutex_unlock(&iaxsl[fr->callno]);
- return 1;
- }
- }
- }
- }
- break;
- case IAX_COMMAND_UNQUELCH:
- if (ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED)) {
- /* Generate Manager Unhold event, if necessary*/
- if (iaxs[fr->callno]->owner && ast_test_flag(iaxs[fr->callno], IAX_QUELCH)) {
- manager_event(EVENT_FLAG_CALL, "Unhold",
- "Channel: %s\r\n"
- "Uniqueid: %s\r\n",
- iaxs[fr->callno]->owner->name,
- iaxs[fr->callno]->owner->uniqueid);
- }
-
- ast_clear_flag(iaxs[fr->callno], IAX_QUELCH);
- if (iaxs[fr->callno]->owner && ast_bridged_channel(iaxs[fr->callno]->owner)) {
- iax2_queue_control_data(fr->callno, AST_CONTROL_UNHOLD, NULL, 0);
- if (!iaxs[fr->callno]) {
- ast_mutex_unlock(&iaxsl[fr->callno]);
- return 1;
- }
- }
- }
- break;
- case IAX_COMMAND_TXACC:
- if (iaxs[fr->callno]->transferring == TRANSFER_BEGIN) {
- /* Ack the packet with the given timestamp */
- AST_LIST_LOCK(&iaxq.queue);
- AST_LIST_TRAVERSE(&iaxq.queue, cur, list) {
- /* Cancel any outstanding txcnt's */
- if ((fr->callno == cur->callno) && (cur->transfer))
- cur->retries = -1;
- }
- AST_LIST_UNLOCK(&iaxq.queue);
- memset(&ied1, 0, sizeof(ied1));
- iax_ie_append_short(&ied1, IAX_IE_CALLNO, iaxs[fr->callno]->callno);
- send_command(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_TXREADY, 0, ied1.buf, ied1.pos, -1);
- iaxs[fr->callno]->transferring = TRANSFER_READY;
- }
- break;
- case IAX_COMMAND_NEW:
- /* Ignore if it's already up */
- if (ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED | IAX_STATE_TBD))
- break;
- if (ies.provverpres && ies.serviceident && sin.sin_addr.s_addr) {
- ast_mutex_unlock(&iaxsl[fr->callno]);
- check_provisioning(&sin, fd, ies.serviceident, ies.provver);
- ast_mutex_lock(&iaxsl[fr->callno]);
- if (!iaxs[fr->callno]) {
- ast_mutex_unlock(&iaxsl[fr->callno]);
- return 1;
- }
- }
- /* If we're in trunk mode, do it now, and update the trunk number in our frame before continuing */
- if (ast_test_flag(iaxs[fr->callno], IAX_TRUNK)) {
- int new_callno;
- if ((new_callno = make_trunk(fr->callno, 1)) != -1)
- fr->callno = new_callno;
- }
- /* For security, always ack immediately */
- if (delayreject)
- send_command_immediate(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr->ts, NULL, 0,fr->iseqno);
- if (check_access(fr->callno, &sin, &ies)) {
- /* They're not allowed on */
- auth_fail(fr->callno, IAX_COMMAND_REJECT);
- if (authdebug)
- ast_log(LOG_NOTICE, "Rejected connect attempt from %s, who was trying to reach '%s@%s'\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->exten, iaxs[fr->callno]->context);
- break;
- }
- if (strcasecmp(iaxs[fr->callno]->exten, "TBD")) {
- const char *context, *exten, *cid_num;
-
- context = ast_strdupa(iaxs[fr->callno]->context);
- exten = ast_strdupa(iaxs[fr->callno]->exten);
- cid_num = ast_strdupa(iaxs[fr->callno]->cid_num);
-
- /* This might re-enter the IAX code and need the lock */
- ast_mutex_unlock(&iaxsl[fr->callno]);
- exists = ast_exists_extension(NULL, context, exten, 1, cid_num);
- ast_mutex_lock(&iaxsl[fr->callno]);
-
- if (!iaxs[fr->callno]) {
- ast_mutex_unlock(&iaxsl[fr->callno]);
- return 1;
- }
- } else
- exists = 0;
- if (ast_strlen_zero(iaxs[fr->callno]->secret) && ast_strlen_zero(iaxs[fr->callno]->inkeys)) {
- if (strcmp(iaxs[fr->callno]->exten, "TBD") && !exists) {
- memset(&ied0, 0, sizeof(ied0));
- iax_ie_append_str(&ied0, IAX_IE_CAUSE, "No such context/extension");
- iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_NO_ROUTE_DESTINATION);
- send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
- if (!iaxs[fr->callno]) {
- ast_mutex_unlock(&iaxsl[fr->callno]);
- return 1;
- }
- if (authdebug)
- ast_log(LOG_NOTICE, "Rejected connect attempt from %s, request '%s@%s' does not exist\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->exten, iaxs[fr->callno]->context);
- } else {
- /* Select an appropriate format */
-
- if(ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOPREFS)) {
- if(ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOCAP)) {
- using_prefs = "reqonly";
- } else {
- using_prefs = "disabled";
- }
- format = iaxs[fr->callno]->peerformat & iaxs[fr->callno]->capability;
- memset(&pref, 0, sizeof(pref));
- strcpy(caller_pref_buf, "disabled");
- strcpy(host_pref_buf, "disabled");
- } else {
- using_prefs = "mine";
- /* If the information elements are in here... use them */
- if (ies.codec_prefs)
- ast_codec_pref_convert(&iaxs[fr->callno]->rprefs, ies.codec_prefs, 32, 0);
- if (ast_codec_pref_index(&iaxs[fr->callno]->rprefs, 0)) {
- /* If we are codec_first_choice we let the caller have the 1st shot at picking the codec.*/
- if (ast_test_flag(iaxs[fr->callno], IAX_CODEC_USER_FIRST)) {
- pref = iaxs[fr->callno]->rprefs;
- using_prefs = "caller";
- } else {
- pref = iaxs[fr->callno]->prefs;
- }
- } else
- pref = iaxs[fr->callno]->prefs;
-
- format = ast_codec_choose(&pref, iaxs[fr->callno]->capability & iaxs[fr->callno]->peercapability, 0);
- ast_codec_pref_string(&iaxs[fr->callno]->rprefs, caller_pref_buf, sizeof(caller_pref_buf) - 1);
- ast_codec_pref_string(&iaxs[fr->callno]->prefs, host_pref_buf, sizeof(host_pref_buf) - 1);
- }
- if (!format) {
- if(!ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOCAP))
- format = iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability;
- if (!format) {
- memset(&ied0, 0, sizeof(ied0));
- iax_ie_append_str(&ied0, IAX_IE_CAUSE, "Unable to negotiate codec");
- iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
- send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
- if (!iaxs[fr->callno]) {
- ast_mutex_unlock(&iaxsl[fr->callno]);
- return 1;
- }
- if (authdebug) {
- if(ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOCAP))
- ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested 0x%x incompatible with our capability 0x%x.\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->peerformat, iaxs[fr->callno]->capability);
- else
- ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability 0x%x/0x%x incompatible with our capability 0x%x.\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->peerformat, iaxs[fr->callno]->peercapability, iaxs[fr->callno]->capability);
- }
- } else {
- /* Pick one... */
- if(ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOCAP)) {
- if(!(iaxs[fr->callno]->peerformat & iaxs[fr->callno]->capability))
- format = 0;
- } else {
- if(ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOPREFS)) {
- using_prefs = ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOCAP) ? "reqonly" : "disabled";
- memset(&pref, 0, sizeof(pref));
- format = ast_best_codec(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
- strcpy(caller_pref_buf,"disabled");
- strcpy(host_pref_buf,"disabled");
- } else {
- using_prefs = "mine";
- if (ast_codec_pref_index(&iaxs[fr->callno]->rprefs, 0)) {
- /* Do the opposite of what we tried above. */
- if (ast_test_flag(iaxs[fr->callno], IAX_CODEC_USER_FIRST)) {
- pref = iaxs[fr->callno]->prefs;
- } else {
- pref = iaxs[fr->callno]->rprefs;
- using_prefs = "caller";
- }
- format = ast_codec_choose(&pref, iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability, 1);
-
- } else /* if no codec_prefs IE do it the old way */
- format = ast_best_codec(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
- }
- }
-
- if (!format) {
- memset(&ied0, 0, sizeof(ied0));
- iax_ie_append_str(&ied0, IAX_IE_CAUSE, "Unable to negotiate codec");
- iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
- ast_log(LOG_ERROR, "No best format in 0x%x???\n", iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
- send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
- if (!iaxs[fr->callno]) {
- ast_mutex_unlock(&iaxsl[fr->callno]);
- return 1;
- }
- if (authdebug)
- ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability 0x%x/0x%x incompatible with our capability 0x%x.\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->peerformat, iaxs[fr->callno]->peercapability, iaxs[fr->callno]->capability);
- ast_set_flag(iaxs[fr->callno], IAX_ALREADYGONE);
- break;
- }
- }
- }
- if (format) {
- /* No authentication required, let them in */
- memset(&ied1, 0, sizeof(ied1));
- iax_ie_append_int(&ied1, IAX_IE_FORMAT, format);
- send_command(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACCEPT, 0, ied1.buf, ied1.pos, -1);
- if (strcmp(iaxs[fr->callno]->exten, "TBD")) {
- ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED);
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Accepting UNAUTHENTICATED call from %s:\n"
- "%srequested format = %s,\n"
- "%srequested prefs = %s,\n"
- "%sactual format = %s,\n"
- "%shost prefs = %s,\n"
- "%spriority = %s\n",
- ast_inet_ntoa(sin.sin_addr),
- VERBOSE_PREFIX_4,
- ast_getformatname(iaxs[fr->callno]->peerformat),
- VERBOSE_PREFIX_4,
- caller_pref_buf,
- VERBOSE_PREFIX_4,
- ast_getformatname(format),
- VERBOSE_PREFIX_4,
- host_pref_buf,
- VERBOSE_PREFIX_4,
- using_prefs);
-
- iaxs[fr->callno]->chosenformat = format;
- ast_set_flag(iaxs[fr->callno], IAX_DELAYPBXSTART);
- } else {
- ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_TBD);
- /* If this is a TBD call, we're ready but now what... */
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Accepted unauthenticated TBD call from %s\n", ast_inet_ntoa(sin.sin_addr));
- }
- }
- }
- break;
- }
- if (iaxs[fr->callno]->authmethods & IAX_AUTH_MD5)
- merge_encryption(iaxs[fr->callno],ies.encmethods);
- else
- iaxs[fr->callno]->encmethods = 0;
- if (!authenticate_request(fr->callno) && iaxs[fr->callno])
- ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_AUTHENTICATED);
- if (!iaxs[fr->callno]) {
- ast_mutex_unlock(&iaxsl[fr->callno]);
- return 1;
- }
- break;
- case IAX_COMMAND_DPREQ:
- /* Request status in the dialplan */
- if (ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_TBD) &&
- !ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED) && ies.called_number) {
- if (iaxcompat) {
- /* Spawn a thread for the lookup */
- spawn_dp_lookup(fr->callno, iaxs[fr->callno]->context, ies.called_number, iaxs[fr->callno]->cid_num);
- } else {
- /* Just look it up */
- dp_lookup(fr->callno, iaxs[fr->callno]->context, ies.called_number, iaxs[fr->callno]->cid_num, 1);
- }
- }
- break;
- case IAX_COMMAND_HANGUP:
- ast_set_flag(iaxs[fr->callno], IAX_ALREADYGONE);
- if (option_debug)
- ast_log(LOG_DEBUG, "Immediately destroying %d, having received hangup\n", fr->callno);
- /* Set hangup cause according to remote */
- if (ies.causecode && iaxs[fr->callno]->owner)
- iaxs[fr->callno]->owner->hangupcause = ies.causecode;
- /* Send ack immediately, before we destroy */
- send_command_immediate(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr->ts, NULL, 0,fr->iseqno);
- iax2_destroy(fr->callno);
- break;
- case IAX_COMMAND_REJECT:
- /* Set hangup cause according to remote */
- if (ies.causecode && iaxs[fr->callno]->owner)
- iaxs[fr->callno]->owner->hangupcause = ies.causecode;
-
- if (!ast_test_flag(iaxs[fr->callno], IAX_PROVISION)) {
- if (iaxs[fr->callno]->owner && authdebug)
- ast_log(LOG_WARNING, "Call rejected by %s: %s\n",
- ast_inet_ntoa(iaxs[fr->callno]->addr.sin_addr),
- ies.cause ? ies.cause : "<Unknown>");
- if (option_debug)
- ast_log(LOG_DEBUG, "Immediately destroying %d, having received reject\n",
- fr->callno);
- }
- /* Send ack immediately, before we destroy */
- send_command_immediate(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACK,
- fr->ts, NULL, 0, fr->iseqno);
- if (!ast_test_flag(iaxs[fr->callno], IAX_PROVISION))
- iaxs[fr->callno]->error = EPERM;
- iax2_destroy(fr->callno);
- break;
- case IAX_COMMAND_TRANSFER:
- {
- struct ast_channel *bridged_chan;
-
- if (iaxs[fr->callno]->owner && (bridged_chan = ast_bridged_channel(iaxs[fr->callno]->owner)) && ies.called_number) {
- /* Set BLINDTRANSFER channel variables */
-
- ast_mutex_unlock(&iaxsl[fr->callno]);
- pbx_builtin_setvar_helper(iaxs[fr->callno]->owner, "BLINDTRANSFER", bridged_chan->name);
- ast_mutex_lock(&iaxsl[fr->callno]);
- if (!iaxs[fr->callno]) {
- ast_mutex_unlock(&iaxsl[fr->callno]);
- return 1;
- }
-
- pbx_builtin_setvar_helper(bridged_chan, "BLINDTRANSFER", iaxs[fr->callno]->owner->name);
- if (!strcmp(ies.called_number, ast_parking_ext())) {
- struct ast_channel *saved_channel = iaxs[fr->callno]->owner;
- ast_mutex_unlock(&iaxsl[fr->callno]);
- if (iax_park(bridged_chan, saved_channel)) {
- ast_log(LOG_WARNING, "Failed to park call on '%s'\n", bridged_chan->name);
- } else {
- ast_log(LOG_DEBUG, "Parked call on '%s'\n", bridged_chan->name);
- }
- ast_mutex_lock(&iaxsl[fr->callno]);
- } else {
- if (ast_async_goto(bridged_chan, iaxs[fr->callno]->context, ies.called_number, 1))
- ast_log(LOG_WARNING, "Async goto of '%s' to '%s@%s' failed\n", bridged_chan->name,
- ies.called_number, iaxs[fr->callno]->context);
- else
- ast_log(LOG_DEBUG, "Async goto of '%s' to '%s@%s' started\n", bridged_chan->name,
- ies.called_number, iaxs[fr->callno]->context);
- }
- } else
- ast_log(LOG_DEBUG, "Async goto not applicable on call %d\n", fr->callno);
-
- break;
- }
- case IAX_COMMAND_ACCEPT:
- /* Ignore if call is already up or needs authentication or is a TBD */
- if (ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED | IAX_STATE_TBD | IAX_STATE_AUTHENTICATED))
- break;
- if (ast_test_flag(iaxs[fr->callno], IAX_PROVISION)) {
- /* Send ack immediately, before we destroy */
- send_command_immediate(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr->ts, NULL, 0,fr->iseqno);
- iax2_destroy(fr->callno);
- break;
- }
- if (ies.format) {
- iaxs[fr->callno]->peerformat = ies.format;
- } else {
- if (iaxs[fr->callno]->owner)
- iaxs[fr->callno]->peerformat = iaxs[fr->callno]->owner->nativeformats;
- else
- iaxs[fr->callno]->peerformat = iaxs[fr->callno]->capability;
- }
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Call accepted by %s (format %s)\n", ast_inet_ntoa(iaxs[fr->callno]->addr.sin_addr), ast_getformatname(iaxs[fr->callno]->peerformat));
- if (!(iaxs[fr->callno]->peerformat & iaxs[fr->callno]->capability)) {
- memset(&ied0, 0, sizeof(ied0));
- iax_ie_append_str(&ied0, IAX_IE_CAUSE, "Unable to negotiate codec");
- iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
- send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
- if (!iaxs[fr->callno]) {
- ast_mutex_unlock(&iaxsl[fr->callno]);
- return 1;
- }
- if (authdebug)
- ast_log(LOG_NOTICE, "Rejected call to %s, format 0x%x incompatible with our capability 0x%x.\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->peerformat, iaxs[fr->callno]->capability);
- } else {
- ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED);
- if (iaxs[fr->callno]->owner) {
- /* Switch us to use a compatible format */
- iaxs[fr->callno]->owner->nativeformats = iaxs[fr->callno]->peerformat;
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Format for call is %s\n", ast_getformatname(iaxs[fr->callno]->owner->nativeformats));
-retryowner2:
- if (ast_mutex_trylock(&iaxs[fr->callno]->owner->lock)) {
- DEADLOCK_AVOIDANCE(&iaxsl[fr->callno]);
- if (iaxs[fr->callno] && iaxs[fr->callno]->owner) goto retryowner2;
- }
-
- if (iaxs[fr->callno] && iaxs[fr->callno]->owner) {
- /* Setup read/write formats properly. */
- if (iaxs[fr->callno]->owner->writeformat)
- ast_set_write_format(iaxs[fr->callno]->owner, iaxs[fr->callno]->owner->writeformat);
- if (iaxs[fr->callno]->owner->readformat)
- ast_set_read_format(iaxs[fr->callno]->owner, iaxs[fr->callno]->owner->readformat);
- ast_mutex_unlock(&iaxs[fr->callno]->owner->lock);
- }
- }
- }
- if (iaxs[fr->callno]) {
- ast_mutex_lock(&dpcache_lock);
- dp = iaxs[fr->callno]->dpentries;
- while(dp) {
- if (!(dp->flags & CACHE_FLAG_TRANSMITTED)) {
- iax2_dprequest(dp, fr->callno);
- }
- dp = dp->peer;
- }
- ast_mutex_unlock(&dpcache_lock);
- }
- break;
- case IAX_COMMAND_POKE:
- /* Send back a pong packet with the original timestamp */
- send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_PONG, fr->ts, NULL, 0, -1);
- if (!iaxs[fr->callno]) {
- ast_mutex_unlock(&iaxsl[fr->callno]);
- return 1;
- }
- break;
- case IAX_COMMAND_PING:
- {
- struct iax_ie_data pingied;
- construct_rr(iaxs[fr->callno], &pingied);
- /* Send back a pong packet with the original timestamp */
- send_command(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_PONG, fr->ts, pingied.buf, pingied.pos, -1);
- }
- break;
- case IAX_COMMAND_PONG:
- /* Calculate ping time */
- iaxs[fr->callno]->pingtime = calc_timestamp(iaxs[fr->callno], 0, &f) - fr->ts;
- /* save RR info */
- save_rr(fr, &ies);
-
- if (iaxs[fr->callno]->peerpoke) {
- peer = iaxs[fr->callno]->peerpoke;
- if ((peer->lastms < 0) || (peer->historicms > peer->maxms)) {
- if (iaxs[fr->callno]->pingtime <= peer->maxms) {
- ast_log(LOG_NOTICE, "Peer '%s' is now REACHABLE! Time: %d\n", peer->name, iaxs[fr->callno]->pingtime);
- manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "Peer: IAX2/%s\r\nPeerStatus: Reachable\r\nTime: %d\r\n", peer->name, iaxs[fr->callno]->pingtime);
- ast_device_state_changed("IAX2/%s", peer->name); /* Activate notification */
- }
- } else if ((peer->historicms > 0) && (peer->historicms <= peer->maxms)) {
- if (iaxs[fr->callno]->pingtime > peer->maxms) {
- ast_log(LOG_NOTICE, "Peer '%s' is now TOO LAGGED (%d ms)!\n", peer->name, iaxs[fr->callno]->pingtime);
- manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "Peer: IAX2/%s\r\nPeerStatus: Lagged\r\nTime: %d\r\n", peer->name, iaxs[fr->callno]->pingtime);
- ast_device_state_changed("IAX2/%s", peer->name); /* Activate notification */
- }
- }
- peer->lastms = iaxs[fr->callno]->pingtime;
- if (peer->smoothing && (peer->lastms > -1))
- peer->historicms = (iaxs[fr->callno]->pingtime + peer->historicms) / 2;
- else if (peer->smoothing && peer->lastms < 0)
- peer->historicms = (0 + peer->historicms) / 2;
- else
- peer->historicms = iaxs[fr->callno]->pingtime;
-
- /* Remove scheduled iax2_poke_noanswer */
- if (peer->pokeexpire > -1) {
- if (!ast_sched_del(sched, peer->pokeexpire)) {
- peer_unref(peer);
- peer->pokeexpire = -1;
- }
- }
- /* Schedule the next cycle */
- if ((peer->lastms < 0) || (peer->historicms > peer->maxms))
- peer->pokeexpire = iax2_sched_add(sched, peer->pokefreqnotok, iax2_poke_peer_s, peer_ref(peer));
- else
- peer->pokeexpire = iax2_sched_add(sched, peer->pokefreqok, iax2_poke_peer_s, peer_ref(peer));
- if (peer->pokeexpire == -1)
- peer_unref(peer);
- /* and finally send the ack */
- send_command_immediate(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr->ts, NULL, 0,fr->iseqno);
- /* And wrap up the qualify call */
- iax2_destroy(fr->callno);
- peer->callno = 0;
- if (option_debug)
- ast_log(LOG_DEBUG, "Peer %s: got pong, lastms %d, historicms %d, maxms %d\n", peer->name, peer->lastms, peer->historicms, peer->maxms);
- }
- break;
- case IAX_COMMAND_LAGRQ:
- case IAX_COMMAND_LAGRP:
- f.src = "LAGRQ";
- f.mallocd = 0;
- f.offset = 0;
- f.samples = 0;
- iax_frame_wrap(fr, &f);
- if(f.subclass == IAX_COMMAND_LAGRQ) {
- /* Received a LAGRQ - echo back a LAGRP */
- fr->af.subclass = IAX_COMMAND_LAGRP;
- iax2_send(iaxs[fr->callno], &fr->af, fr->ts, -1, 0, 0, 0);
- } else {
- /* Received LAGRP in response to our LAGRQ */
- unsigned int ts;
- /* This is a reply we've been given, actually measure the difference */
- ts = calc_timestamp(iaxs[fr->callno], 0, &fr->af);
- iaxs[fr->callno]->lag = ts - fr->ts;
- if (option_debug && iaxdebug)
- ast_log(LOG_DEBUG, "Peer %s lag measured as %dms\n",
- ast_inet_ntoa(iaxs[fr->callno]->addr.sin_addr), iaxs[fr->callno]->lag);
- }
- break;
- case IAX_COMMAND_AUTHREQ:
- if (ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED | IAX_STATE_TBD)) {
- ast_log(LOG_WARNING, "Call on %s is already up, can't start on it\n", iaxs[fr->callno]->owner ? iaxs[fr->callno]->owner->name : "<Unknown>");
- break;
- }
- if (authenticate_reply(iaxs[fr->callno], &iaxs[fr->callno]->addr, &ies, iaxs[fr->callno]->secret, iaxs[fr->callno]->outkey)) {
- struct ast_frame hangup_fr = { .frametype = AST_FRAME_CONTROL,
- .subclass = AST_CONTROL_HANGUP,
- };
- ast_log(LOG_WARNING,
- "I don't know how to authenticate %s to %s\n",
- ies.username ? ies.username : "<unknown>", ast_inet_ntoa(iaxs[fr->callno]->addr.sin_addr));
- iax2_queue_frame(fr->callno, &hangup_fr);
- }
- if (!iaxs[fr->callno]) {
- ast_mutex_unlock(&iaxsl[fr->callno]);
- return 1;
- }
- break;
- case IAX_COMMAND_AUTHREP:
- /* For security, always ack immediately */
- if (delayreject)
- send_command_immediate(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr->ts, NULL, 0,fr->iseqno);
- /* Ignore once we've started */
- if (ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED | IAX_STATE_TBD)) {
- ast_log(LOG_WARNING, "Call on %s is already up, can't start on it\n", iaxs[fr->callno]->owner ? iaxs[fr->callno]->owner->name : "<Unknown>");
- break;
- }
- if (authenticate_verify(iaxs[fr->callno], &ies)) {
- if (authdebug)
- ast_log(LOG_NOTICE, "Host %s failed to authenticate as %s\n", ast_inet_ntoa(iaxs[fr->callno]->addr.sin_addr), iaxs[fr->callno]->username);
- memset(&ied0, 0, sizeof(ied0));
- auth_fail(fr->callno, IAX_COMMAND_REJECT);
- break;
- }
- if (strcasecmp(iaxs[fr->callno]->exten, "TBD")) {
- /* This might re-enter the IAX code and need the lock */
- exists = ast_exists_extension(NULL, iaxs[fr->callno]->context, iaxs[fr->callno]->exten, 1, iaxs[fr->callno]->cid_num);
- } else
- exists = 0;
- if (strcmp(iaxs[fr->callno]->exten, "TBD") && !exists) {
- if (authdebug)
- ast_log(LOG_NOTICE, "Rejected connect attempt from %s, request '%s@%s' does not exist\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->exten, iaxs[fr->callno]->context);
- memset(&ied0, 0, sizeof(ied0));
- iax_ie_append_str(&ied0, IAX_IE_CAUSE, "No such context/extension");
- iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_NO_ROUTE_DESTINATION);
- send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
- if (!iaxs[fr->callno]) {
- ast_mutex_unlock(&iaxsl[fr->callno]);
- return 1;
- }
- } else {
- /* Select an appropriate format */
- if(ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOPREFS)) {
- if(ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOCAP)) {
- using_prefs = "reqonly";
- } else {
- using_prefs = "disabled";
- }
- format = iaxs[fr->callno]->peerformat & iaxs[fr->callno]->capability;
- memset(&pref, 0, sizeof(pref));
- strcpy(caller_pref_buf, "disabled");
- strcpy(host_pref_buf, "disabled");
- } else {
- using_prefs = "mine";
- if (ies.codec_prefs)
- ast_codec_pref_convert(&iaxs[fr->callno]->rprefs, ies.codec_prefs, 32, 0);
- if (ast_codec_pref_index(&iaxs[fr->callno]->rprefs, 0)) {
- if (ast_test_flag(iaxs[fr->callno], IAX_CODEC_USER_FIRST)) {
- pref = iaxs[fr->callno]->rprefs;
- using_prefs = "caller";
- } else {
- pref = iaxs[fr->callno]->prefs;
- }
- } else /* if no codec_prefs IE do it the old way */
- pref = iaxs[fr->callno]->prefs;
-
- format = ast_codec_choose(&pref, iaxs[fr->callno]->capability & iaxs[fr->callno]->peercapability, 0);
- ast_codec_pref_string(&iaxs[fr->callno]->rprefs, caller_pref_buf, sizeof(caller_pref_buf) - 1);
- ast_codec_pref_string(&iaxs[fr->callno]->prefs, host_pref_buf, sizeof(host_pref_buf) - 1);
- }
- if (!format) {
- if(!ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOCAP)) {
- if (option_debug)
- ast_log(LOG_DEBUG, "We don't do requested format %s, falling back to peer capability %d\n", ast_getformatname(iaxs[fr->callno]->peerformat), iaxs[fr->callno]->peercapability);
- format = iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability;
- }
- if (!format) {
- if (authdebug) {
- if(ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOCAP))
- ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested 0x%x incompatible with our capability 0x%x.\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->peerformat, iaxs[fr->callno]->capability);
- else
- ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability 0x%x/0x%x incompatible with our capability 0x%x.\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->peerformat, iaxs[fr->callno]->peercapability, iaxs[fr->callno]->capability);
- }
- memset(&ied0, 0, sizeof(ied0));
- iax_ie_append_str(&ied0, IAX_IE_CAUSE, "Unable to negotiate codec");
- iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
- send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
- if (!iaxs[fr->callno]) {
- ast_mutex_unlock(&iaxsl[fr->callno]);
- return 1;
- }
- } else {
- /* Pick one... */
- if(ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOCAP)) {
- if(!(iaxs[fr->callno]->peerformat & iaxs[fr->callno]->capability))
- format = 0;
- } else {
- if(ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOPREFS)) {
- using_prefs = ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOCAP) ? "reqonly" : "disabled";
- memset(&pref, 0, sizeof(pref));
- format = ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOCAP) ?
- iaxs[fr->callno]->peerformat : ast_best_codec(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
- strcpy(caller_pref_buf,"disabled");
- strcpy(host_pref_buf,"disabled");
- } else {
- using_prefs = "mine";
- if (ast_codec_pref_index(&iaxs[fr->callno]->rprefs, 0)) {
- /* Do the opposite of what we tried above. */
- if (ast_test_flag(iaxs[fr->callno], IAX_CODEC_USER_FIRST)) {
- pref = iaxs[fr->callno]->prefs;
- } else {
- pref = iaxs[fr->callno]->rprefs;
- using_prefs = "caller";
- }
- format = ast_codec_choose(&pref, iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability, 1);
- } else /* if no codec_prefs IE do it the old way */
- format = ast_best_codec(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
- }
- }
- if (!format) {
- ast_log(LOG_ERROR, "No best format in 0x%x???\n", iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
- if (authdebug) {
- if(ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOCAP))
- ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested 0x%x incompatible with our capability 0x%x.\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->peerformat, iaxs[fr->callno]->capability);
- else
- ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability 0x%x/0x%x incompatible with our capability 0x%x.\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->peerformat, iaxs[fr->callno]->peercapability, iaxs[fr->callno]->capability);
- }
- memset(&ied0, 0, sizeof(ied0));
- iax_ie_append_str(&ied0, IAX_IE_CAUSE, "Unable to negotiate codec");
- iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
- send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
- if (!iaxs[fr->callno]) {
- ast_mutex_unlock(&iaxsl[fr->callno]);
- return 1;
- }
- }
- }
- }
- if (format) {
- /* Authentication received */
- memset(&ied1, 0, sizeof(ied1));
- iax_ie_append_int(&ied1, IAX_IE_FORMAT, format);
- send_command(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACCEPT, 0, ied1.buf, ied1.pos, -1);
- if (strcmp(iaxs[fr->callno]->exten, "TBD")) {
- ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED);
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Accepting AUTHENTICATED call from %s:\n"
- "%srequested format = %s,\n"
- "%srequested prefs = %s,\n"
- "%sactual format = %s,\n"
- "%shost prefs = %s,\n"
- "%spriority = %s\n",
- ast_inet_ntoa(sin.sin_addr),
- VERBOSE_PREFIX_4,
- ast_getformatname(iaxs[fr->callno]->peerformat),
- VERBOSE_PREFIX_4,
- caller_pref_buf,
- VERBOSE_PREFIX_4,
- ast_getformatname(format),
- VERBOSE_PREFIX_4,
- host_pref_buf,
- VERBOSE_PREFIX_4,
- using_prefs);
-
- ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED);
- if(!(c = ast_iax2_new(fr->callno, AST_STATE_RING, format)))
- iax2_destroy(fr->callno);
- } else {
- ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_TBD);
- /* If this is a TBD call, we're ready but now what... */
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Accepted AUTHENTICATED TBD call from %s\n", ast_inet_ntoa(sin.sin_addr));
- }
- }
- }
- break;
- case IAX_COMMAND_DIAL:
- if (ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_TBD)) {
- ast_clear_flag(&iaxs[fr->callno]->state, IAX_STATE_TBD);
- ast_string_field_set(iaxs[fr->callno], exten, ies.called_number ? ies.called_number : "s");
- if (!ast_exists_extension(NULL, iaxs[fr->callno]->context, iaxs[fr->callno]->exten, 1, iaxs[fr->callno]->cid_num)) {
- if (authdebug)
- ast_log(LOG_NOTICE, "Rejected dial attempt from %s, request '%s@%s' does not exist\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->exten, iaxs[fr->callno]->context);
- memset(&ied0, 0, sizeof(ied0));
- iax_ie_append_str(&ied0, IAX_IE_CAUSE, "No such context/extension");
- iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_NO_ROUTE_DESTINATION);
- send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
- if (!iaxs[fr->callno]) {
- ast_mutex_unlock(&iaxsl[fr->callno]);
- return 1;
- }
- } else {
- ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED);
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Accepting DIAL from %s, formats = 0x%x\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->peerformat);
- ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED);
- send_command(iaxs[fr->callno], AST_FRAME_CONTROL, AST_CONTROL_PROGRESS, 0, NULL, 0, -1);
- if(!(c = ast_iax2_new(fr->callno, AST_STATE_RING, iaxs[fr->callno]->peerformat)))
- iax2_destroy(fr->callno);
- }
- }
- break;
- case IAX_COMMAND_INVAL:
- iaxs[fr->callno]->error = ENOTCONN;
- if (option_debug)
- ast_log(LOG_DEBUG, "Immediately destroying %d, having received INVAL\n", fr->callno);
- iax2_destroy(fr->callno);
- if (option_debug)
- ast_log(LOG_DEBUG, "Destroying call %d\n", fr->callno);
- break;
- case IAX_COMMAND_VNAK:
- if (option_debug)
- ast_log(LOG_DEBUG, "Received VNAK: resending outstanding frames\n");
- /* Force retransmission */
- vnak_retransmit(fr->callno, fr->iseqno);
- break;
- case IAX_COMMAND_REGREQ:
- case IAX_COMMAND_REGREL:
- /* For security, always ack immediately */
- if (delayreject)
- send_command_immediate(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr->ts, NULL, 0,fr->iseqno);
- if (register_verify(fr->callno, &sin, &ies)) {
- if (!iaxs[fr->callno]) {
- ast_mutex_unlock(&iaxsl[fr->callno]);
- return 1;
- }
- /* Send delayed failure */
- auth_fail(fr->callno, IAX_COMMAND_REGREJ);
- break;
- }
- if (!iaxs[fr->callno]) {
- ast_mutex_unlock(&iaxsl[fr->callno]);
- return 1;
- }
- if ((ast_strlen_zero(iaxs[fr->callno]->secret) && ast_strlen_zero(iaxs[fr->callno]->inkeys)) ||
- ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_AUTHENTICATED | IAX_STATE_UNCHANGED)) {
- if (f.subclass == IAX_COMMAND_REGREL)
- memset(&sin, 0, sizeof(sin));
- if (update_registry(&sin, fr->callno, ies.devicetype, fd, ies.refresh))
- ast_log(LOG_WARNING, "Registry error\n");
- if (!iaxs[fr->callno]) {
- ast_mutex_unlock(&iaxsl[fr->callno]);
- return 1;
- }
- if (ies.provverpres && ies.serviceident && sin.sin_addr.s_addr) {
- ast_mutex_unlock(&iaxsl[fr->callno]);
- check_provisioning(&sin, fd, ies.serviceident, ies.provver);
- ast_mutex_lock(&iaxsl[fr->callno]);
- if (!iaxs[fr->callno]) {
- ast_mutex_unlock(&iaxsl[fr->callno]);
- return 1;
- }
- }
- break;
- }
- registry_authrequest(fr->callno);
- if (!iaxs[fr->callno]) {
- ast_mutex_unlock(&iaxsl[fr->callno]);
- return 1;
- }
- break;
- case IAX_COMMAND_REGACK:
- if (iax2_ack_registry(&ies, &sin, fr->callno))
- ast_log(LOG_WARNING, "Registration failure\n");
- /* Send ack immediately, before we destroy */
- send_command_immediate(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr->ts, NULL, 0,fr->iseqno);
- iax2_destroy(fr->callno);
- break;
- case IAX_COMMAND_REGREJ:
- if (iaxs[fr->callno]->reg) {
- if (authdebug) {
- ast_log(LOG_NOTICE, "Registration of '%s' rejected: '%s' from: '%s'\n", iaxs[fr->callno]->reg->username, ies.cause ? ies.cause : "<unknown>", ast_inet_ntoa(sin.sin_addr));
- manager_event(EVENT_FLAG_SYSTEM, "Registry", "ChannelDriver: IAX2\r\nUsername: %s\r\nStatus: Rejected\r\nCause: %s\r\n", iaxs[fr->callno]->reg->username, ies.cause ? ies.cause : "<unknown>");
- }
- iaxs[fr->callno]->reg->regstate = REG_STATE_REJECTED;
- }
- /* Send ack immediately, before we destroy */
- send_command_immediate(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr->ts, NULL, 0,fr->iseqno);
- iax2_destroy(fr->callno);
- break;
- case IAX_COMMAND_REGAUTH:
- /* Authentication request */
- if (registry_rerequest(&ies, fr->callno, &sin)) {
- memset(&ied0, 0, sizeof(ied0));
- iax_ie_append_str(&ied0, IAX_IE_CAUSE, "No authority found");
- iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_FACILITY_NOT_SUBSCRIBED);
- send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
- if (!iaxs[fr->callno]) {
- ast_mutex_unlock(&iaxsl[fr->callno]);
- return 1;
- }
- }
- break;
- case IAX_COMMAND_TXREJ:
- iaxs[fr->callno]->transferring = 0;
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Channel '%s' unable to transfer\n", iaxs[fr->callno]->owner ? iaxs[fr->callno]->owner->name : "<Unknown>");
- memset(&iaxs[fr->callno]->transfer, 0, sizeof(iaxs[fr->callno]->transfer));
- if (iaxs[fr->callno]->bridgecallno) {
- if (iaxs[iaxs[fr->callno]->bridgecallno]->transferring) {
- iaxs[iaxs[fr->callno]->bridgecallno]->transferring = 0;
- send_command(iaxs[iaxs[fr->callno]->bridgecallno], AST_FRAME_IAX, IAX_COMMAND_TXREJ, 0, NULL, 0, -1);
- }
- }
- break;
- case IAX_COMMAND_TXREADY:
- if ((iaxs[fr->callno]->transferring == TRANSFER_BEGIN) ||
- (iaxs[fr->callno]->transferring == TRANSFER_MBEGIN)) {
- if (iaxs[fr->callno]->transferring == TRANSFER_MBEGIN)
- iaxs[fr->callno]->transferring = TRANSFER_MREADY;
- else
- iaxs[fr->callno]->transferring = TRANSFER_READY;
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Channel '%s' ready to transfer\n", iaxs[fr->callno]->owner ? iaxs[fr->callno]->owner->name : "<Unknown>");
- if (iaxs[fr->callno]->bridgecallno) {
- if ((iaxs[iaxs[fr->callno]->bridgecallno]->transferring == TRANSFER_READY) ||
- (iaxs[iaxs[fr->callno]->bridgecallno]->transferring == TRANSFER_MREADY)) {
- /* They're both ready, now release them. */
- if (iaxs[fr->callno]->transferring == TRANSFER_MREADY) {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Attempting media bridge of %s and %s\n", iaxs[fr->callno]->owner ? iaxs[fr->callno]->owner->name : "<Unknown>",
- iaxs[iaxs[fr->callno]->bridgecallno]->owner ? iaxs[iaxs[fr->callno]->bridgecallno]->owner->name : "<Unknown>");
-
- iaxs[iaxs[fr->callno]->bridgecallno]->transferring = TRANSFER_MEDIA;
- iaxs[fr->callno]->transferring = TRANSFER_MEDIA;
-
- memset(&ied0, 0, sizeof(ied0));
- memset(&ied1, 0, sizeof(ied1));
- iax_ie_append_short(&ied0, IAX_IE_CALLNO, iaxs[iaxs[fr->callno]->bridgecallno]->peercallno);
- iax_ie_append_short(&ied1, IAX_IE_CALLNO, iaxs[fr->callno]->peercallno);
- send_command(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_TXMEDIA, 0, ied0.buf, ied0.pos, -1);
- send_command(iaxs[iaxs[fr->callno]->bridgecallno], AST_FRAME_IAX, IAX_COMMAND_TXMEDIA, 0, ied1.buf, ied1.pos, -1);
- } else {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Releasing %s and %s\n", iaxs[fr->callno]->owner ? iaxs[fr->callno]->owner->name : "<Unknown>",
- iaxs[iaxs[fr->callno]->bridgecallno]->owner ? iaxs[iaxs[fr->callno]->bridgecallno]->owner->name : "<Unknown>");
-
- iaxs[iaxs[fr->callno]->bridgecallno]->transferring = TRANSFER_RELEASED;
- iaxs[fr->callno]->transferring = TRANSFER_RELEASED;
- ast_set_flag(iaxs[iaxs[fr->callno]->bridgecallno], IAX_ALREADYGONE);
- ast_set_flag(iaxs[fr->callno], IAX_ALREADYGONE);
-
- /* Stop doing lag & ping requests */
- stop_stuff(fr->callno);
- stop_stuff(iaxs[fr->callno]->bridgecallno);
-
- memset(&ied0, 0, sizeof(ied0));
- memset(&ied1, 0, sizeof(ied1));
- iax_ie_append_short(&ied0, IAX_IE_CALLNO, iaxs[iaxs[fr->callno]->bridgecallno]->peercallno);
- iax_ie_append_short(&ied1, IAX_IE_CALLNO, iaxs[fr->callno]->peercallno);
- send_command(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_TXREL, 0, ied0.buf, ied0.pos, -1);
- send_command(iaxs[iaxs[fr->callno]->bridgecallno], AST_FRAME_IAX, IAX_COMMAND_TXREL, 0, ied1.buf, ied1.pos, -1);
- }
-
- }
- }
- }
- break;
- case IAX_COMMAND_TXREQ:
- try_transfer(iaxs[fr->callno], &ies);
- break;
- case IAX_COMMAND_TXCNT:
- if (iaxs[fr->callno]->transferring)
- send_command_transfer(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_TXACC, 0, NULL, 0);
- break;
- case IAX_COMMAND_TXREL:
- /* Send ack immediately, rather than waiting until we've changed addresses */
- send_command_immediate(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr->ts, NULL, 0,fr->iseqno);
- complete_transfer(fr->callno, &ies);
- stop_stuff(fr->callno); /* for attended transfer to work with libiax */
- break;
- case IAX_COMMAND_TXMEDIA:
- if (iaxs[fr->callno]->transferring == TRANSFER_READY) {
- AST_LIST_LOCK(&iaxq.queue);
- AST_LIST_TRAVERSE(&iaxq.queue, cur, list) {
- /* Cancel any outstanding frames and start anew */
- if ((fr->callno == cur->callno) && (cur->transfer)) {
- cur->retries = -1;
- }
- }
- AST_LIST_UNLOCK(&iaxq.queue);
- /* Start sending our media to the transfer address, but otherwise leave the call as-is */
- iaxs[fr->callno]->transferring = TRANSFER_MEDIAPASS;
- }
- break;
- case IAX_COMMAND_DPREP:
- complete_dpreply(iaxs[fr->callno], &ies);
- break;
- case IAX_COMMAND_UNSUPPORT:
- ast_log(LOG_NOTICE, "Peer did not understand our iax command '%d'\n", ies.iax_unknown);
- break;
- case IAX_COMMAND_FWDOWNL:
- /* Firmware download */
- if (!ast_test_flag(&globalflags, IAX_ALLOWFWDOWNLOAD)) {
- send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_UNSUPPORT, 0, NULL, 0, -1);
- break;
- }
- memset(&ied0, 0, sizeof(ied0));
- res = iax_firmware_append(&ied0, (unsigned char *)ies.devicetype, ies.fwdesc);
- if (res < 0)
- send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
- else if (res > 0)
- send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_FWDATA, 0, ied0.buf, ied0.pos, -1);
- else
- send_command(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_FWDATA, 0, ied0.buf, ied0.pos, -1);
- if (!iaxs[fr->callno]) {
- ast_mutex_unlock(&iaxsl[fr->callno]);
- return 1;
- }
- break;
- default:
- if (option_debug)
- ast_log(LOG_DEBUG, "Unknown IAX command %d on %d/%d\n", f.subclass, fr->callno, iaxs[fr->callno]->peercallno);
- memset(&ied0, 0, sizeof(ied0));
- iax_ie_append_byte(&ied0, IAX_IE_IAX_UNKNOWN, f.subclass);
- send_command(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_UNSUPPORT, 0, ied0.buf, ied0.pos, -1);
- }
- /* Don't actually pass these frames along */
- if ((f.subclass != IAX_COMMAND_ACK) &&
- (f.subclass != IAX_COMMAND_TXCNT) &&
- (f.subclass != IAX_COMMAND_TXACC) &&
- (f.subclass != IAX_COMMAND_INVAL) &&
- (f.subclass != IAX_COMMAND_VNAK)) {
- if (iaxs[fr->callno] && iaxs[fr->callno]->aseqno != iaxs[fr->callno]->iseqno)
- send_command_immediate(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr->ts, NULL, 0,fr->iseqno);
- }
- ast_mutex_unlock(&iaxsl[fr->callno]);
- return 1;
- }
- /* Unless this is an ACK or INVAL frame, ack it */
- if (iaxs[fr->callno] && iaxs[fr->callno]->aseqno != iaxs[fr->callno]->iseqno)
- send_command_immediate(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr->ts, NULL, 0,fr->iseqno);
- } else if (minivid) {
- f.frametype = AST_FRAME_VIDEO;
- if (iaxs[fr->callno]->videoformat > 0)
- f.subclass = iaxs[fr->callno]->videoformat | (ntohs(vh->ts) & 0x8000 ? 1 : 0);
- else {
- ast_log(LOG_WARNING, "Received mini frame before first full video frame\n");
- iax2_vnak(fr->callno);
- ast_mutex_unlock(&iaxsl[fr->callno]);
- return 1;
- }
- f.datalen = res - sizeof(*vh);
- if (f.datalen)
- f.data = thread->buf + sizeof(*vh);
- else
- f.data = NULL;
-#ifdef IAXTESTS
- if (test_resync) {
- fr->ts = (iaxs[fr->callno]->last & 0xFFFF8000L) | ((ntohs(vh->ts) + test_resync) & 0x7fff);
- } else
-#endif /* IAXTESTS */
- fr->ts = (iaxs[fr->callno]->last & 0xFFFF8000L) | (ntohs(vh->ts) & 0x7fff);
- } else {
- /* A mini frame */
- f.frametype = AST_FRAME_VOICE;
- if (iaxs[fr->callno]->voiceformat > 0)
- f.subclass = iaxs[fr->callno]->voiceformat;
- else {
- if (option_debug)
- ast_log(LOG_DEBUG, "Received mini frame before first full voice frame\n");
- iax2_vnak(fr->callno);
- ast_mutex_unlock(&iaxsl[fr->callno]);
- return 1;
- }
- f.datalen = res - sizeof(struct ast_iax2_mini_hdr);
- if (f.datalen < 0) {
- ast_log(LOG_WARNING, "Datalen < 0?\n");
- ast_mutex_unlock(&iaxsl[fr->callno]);
- return 1;
- }
- if (f.datalen)
- f.data = thread->buf + sizeof(*mh);
- else
- f.data = NULL;
-#ifdef IAXTESTS
- if (test_resync) {
- fr->ts = (iaxs[fr->callno]->last & 0xFFFF0000L) | ((ntohs(mh->ts) + test_resync) & 0xffff);
- } else
-#endif /* IAXTESTS */
- fr->ts = (iaxs[fr->callno]->last & 0xFFFF0000L) | ntohs(mh->ts);
- /* FIXME? Surely right here would be the right place to undo timestamp wraparound? */
- }
- /* Don't pass any packets until we're started */
- if (!ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED)) {
- ast_mutex_unlock(&iaxsl[fr->callno]);
- return 1;
- }
- /* Common things */
- f.src = "IAX2";
- f.mallocd = 0;
- f.offset = 0;
- f.len = 0;
- if (f.datalen && (f.frametype == AST_FRAME_VOICE)) {
- f.samples = ast_codec_get_samples(&f);
- /* We need to byteswap incoming slinear samples from network byte order */
- if (f.subclass == AST_FORMAT_SLINEAR)
- ast_frame_byteswap_be(&f);
- } else
- f.samples = 0;
- iax_frame_wrap(fr, &f);
-
- /* If this is our most recent packet, use it as our basis for timestamping */
- if (iaxs[fr->callno] && iaxs[fr->callno]->last < fr->ts) {
- /*iaxs[fr->callno]->last = fr->ts; (do it afterwards cos schedule/forward_delivery needs the last ts too)*/
- fr->outoforder = 0;
- } else {
- if (option_debug && iaxdebug && iaxs[fr->callno])
- ast_log(LOG_DEBUG, "Received out of order packet... (type=%d, subclass %d, ts = %d, last = %d)\n", f.frametype, f.subclass, fr->ts, iaxs[fr->callno]->last);
- fr->outoforder = -1;
- }
- fr->cacheable = ((f.frametype == AST_FRAME_VOICE) || (f.frametype == AST_FRAME_VIDEO));
- duped_fr = iaxfrdup2(fr);
- if (duped_fr) {
- schedule_delivery(duped_fr, updatehistory, 0, &fr->ts);
- }
- if (iaxs[fr->callno] && iaxs[fr->callno]->last < fr->ts) {
- iaxs[fr->callno]->last = fr->ts;
-#if 1
- if (option_debug && iaxdebug)
- ast_log(LOG_DEBUG, "For call=%d, set last=%d\n", fr->callno, fr->ts);
-#endif
- }
-
- /* Always run again */
- ast_mutex_unlock(&iaxsl[fr->callno]);
- return 1;
-}
-
-/* Function to clean up process thread if it is cancelled */
-static void iax2_process_thread_cleanup(void *data)
-{
- struct iax2_thread *thread = data;
- ast_mutex_destroy(&thread->lock);
- ast_cond_destroy(&thread->cond);
- free(thread);
- ast_atomic_dec_and_test(&iaxactivethreadcount);
-}
-
-static void *iax2_process_thread(void *data)
-{
- struct iax2_thread *thread = data;
- struct timeval tv;
- struct timespec ts;
- int put_into_idle = 0;
-
- ast_atomic_fetchadd_int(&iaxactivethreadcount,1);
- pthread_cleanup_push(iax2_process_thread_cleanup, data);
- for(;;) {
- /* Wait for something to signal us to be awake */
- ast_mutex_lock(&thread->lock);
-
- /* Flag that we're ready to accept signals */
- thread->ready_for_signal = 1;
-
- /* Put into idle list if applicable */
- if (put_into_idle)
- insert_idle_thread(thread);
-
- if (thread->type == IAX_TYPE_DYNAMIC) {
- struct iax2_thread *t = NULL;
- /* Wait to be signalled or time out */
- tv = ast_tvadd(ast_tvnow(), ast_samp2tv(30000, 1000));
- ts.tv_sec = tv.tv_sec;
- ts.tv_nsec = tv.tv_usec * 1000;
- if (ast_cond_timedwait(&thread->cond, &thread->lock, &ts) == ETIMEDOUT) {
- /* This thread was never put back into the available dynamic
- * thread list, so just go away. */
- if (!put_into_idle) {
- ast_mutex_unlock(&thread->lock);
- break;
- }
- AST_LIST_LOCK(&dynamic_list);
- /* Account for the case where this thread is acquired *right* after a timeout */
- if ((t = AST_LIST_REMOVE(&dynamic_list, thread, list)))
- iaxdynamicthreadcount--;
- AST_LIST_UNLOCK(&dynamic_list);
- if (t) {
- /* This dynamic thread timed out waiting for a task and was
- * not acquired immediately after the timeout,
- * so it's time to go away. */
- ast_mutex_unlock(&thread->lock);
- break;
- }
- /* Someone grabbed our thread *right* after we timed out.
- * Wait for them to set us up with something to do and signal
- * us to continue. */
- tv = ast_tvadd(ast_tvnow(), ast_samp2tv(30000, 1000));
- ts.tv_sec = tv.tv_sec;
- ts.tv_nsec = tv.tv_usec * 1000;
- if (ast_cond_timedwait(&thread->cond, &thread->lock, &ts) == ETIMEDOUT)
- {
- ast_mutex_unlock(&thread->lock);
- break;
- }
- }
- } else {
- ast_cond_wait(&thread->cond, &thread->lock);
- }
-
- /* Go back into our respective list */
- put_into_idle = 1;
-
- ast_mutex_unlock(&thread->lock);
-
- if (thread->iostate == IAX_IOSTATE_IDLE)
- continue;
-
- /* Add ourselves to the active list now */
- AST_LIST_LOCK(&active_list);
- AST_LIST_INSERT_HEAD(&active_list, thread, list);
- AST_LIST_UNLOCK(&active_list);
-
- /* See what we need to do */
- switch(thread->iostate) {
- case IAX_IOSTATE_READY:
- thread->actions++;
- thread->iostate = IAX_IOSTATE_PROCESSING;
- socket_process(thread);
- handle_deferred_full_frames(thread);
- break;
- case IAX_IOSTATE_SCHEDREADY:
- thread->actions++;
- thread->iostate = IAX_IOSTATE_PROCESSING;
-#ifdef SCHED_MULTITHREADED
- thread->schedfunc(thread->scheddata);
-#endif
- break;
- }
- time(&thread->checktime);
- thread->iostate = IAX_IOSTATE_IDLE;
-#ifdef DEBUG_SCHED_MULTITHREAD
- thread->curfunc[0]='\0';
-#endif
-
- /* Now... remove ourselves from the active list, and return to the idle list */
- AST_LIST_LOCK(&active_list);
- AST_LIST_REMOVE(&active_list, thread, list);
- AST_LIST_UNLOCK(&active_list);
-
- /* Make sure another frame didn't sneak in there after we thought we were done. */
- handle_deferred_full_frames(thread);
- }
-
- /*!\note For some reason, idle threads are exiting without being removed
- * from an idle list, which is causing memory corruption. Forcibly remove
- * it from the list, if it's there.
- */
- AST_LIST_LOCK(&idle_list);
- AST_LIST_REMOVE(&idle_list, thread, list);
- AST_LIST_UNLOCK(&idle_list);
-
- AST_LIST_LOCK(&dynamic_list);
- AST_LIST_REMOVE(&dynamic_list, thread, list);
- AST_LIST_UNLOCK(&dynamic_list);
-
- /* I am exiting here on my own volition, I need to clean up my own data structures
- * Assume that I am no longer in any of the lists (idle, active, or dynamic)
- */
- pthread_cleanup_pop(1);
-
- return NULL;
-}
-
-static int iax2_do_register(struct iax2_registry *reg)
-{
- struct iax_ie_data ied;
- if (option_debug && iaxdebug)
- ast_log(LOG_DEBUG, "Sending registration request for '%s'\n", reg->username);
-
- if (reg->dnsmgr &&
- ((reg->regstate == REG_STATE_TIMEOUT) || !reg->addr.sin_addr.s_addr)) {
- /* Maybe the IP has changed, force DNS refresh */
- ast_dnsmgr_refresh(reg->dnsmgr);
- }
-
- /*
- * if IP has Changed, free allocated call to create a new one with new IP
- * call has the pointer to IP and must be updated to the new one
- */
- if (reg->dnsmgr && ast_dnsmgr_changed(reg->dnsmgr) && (reg->callno > 0)) {
- int callno = reg->callno;
- ast_mutex_lock(&iaxsl[callno]);
- iax2_destroy(callno);
- ast_mutex_unlock(&iaxsl[callno]);
- reg->callno = 0;
- }
- if (!reg->addr.sin_addr.s_addr) {
- if (option_debug && iaxdebug)
- ast_log(LOG_DEBUG, "Unable to send registration request for '%s' without IP address\n", reg->username);
- /* Setup the next registration attempt */
- AST_SCHED_DEL(sched, reg->expire);
- reg->expire = iax2_sched_add(sched, (5 * reg->refresh / 6) * 1000, iax2_do_register_s, reg);
- return -1;
- }
-
- if (!reg->callno) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Allocate call number\n");
- reg->callno = find_callno_locked(0, 0, &reg->addr, NEW_FORCE, defaultsockfd, 0);
- if (reg->callno < 1) {
- ast_log(LOG_WARNING, "Unable to create call for registration\n");
- return -1;
- } else if (option_debug)
- ast_log(LOG_DEBUG, "Registration created on call %d\n", reg->callno);
- iaxs[reg->callno]->reg = reg;
- ast_mutex_unlock(&iaxsl[reg->callno]);
- }
- /* Schedule the next registration attempt */
- AST_SCHED_DEL(sched, reg->expire);
- /* Setup the next registration a little early */
- reg->expire = iax2_sched_add(sched, (5 * reg->refresh / 6) * 1000, iax2_do_register_s, reg);
- /* Send the request */
- memset(&ied, 0, sizeof(ied));
- iax_ie_append_str(&ied, IAX_IE_USERNAME, reg->username);
- iax_ie_append_short(&ied, IAX_IE_REFRESH, reg->refresh);
- send_command(iaxs[reg->callno],AST_FRAME_IAX, IAX_COMMAND_REGREQ, 0, ied.buf, ied.pos, -1);
- reg->regstate = REG_STATE_REGSENT;
- return 0;
-}
-
-static char *iax2_prov_complete_template_3rd(const char *line, const char *word, int pos, int state)
-{
- if (pos != 3)
- return NULL;
- return iax_prov_complete_template(line, word, pos, state);
-}
-
-static int iax2_provision(struct sockaddr_in *end, int sockfd, char *dest, const char *template, int force)
-{
- /* Returns 1 if provisioned, -1 if not able to find destination, or 0 if no provisioning
- is found for template */
- struct iax_ie_data provdata;
- struct iax_ie_data ied;
- unsigned int sig;
- struct sockaddr_in sin;
- int callno;
- struct create_addr_info cai;
-
- memset(&cai, 0, sizeof(cai));
-
- if (option_debug)
- ast_log(LOG_DEBUG, "Provisioning '%s' from template '%s'\n", dest, template);
-
- if (iax_provision_build(&provdata, &sig, template, force)) {
- if (option_debug)
- ast_log(LOG_DEBUG, "No provisioning found for template '%s'\n", template);
- return 0;
- }
-
- if (end) {
- memcpy(&sin, end, sizeof(sin));
- cai.sockfd = sockfd;
- } else if (create_addr(dest, NULL, &sin, &cai))
- return -1;
-
- /* Build the rest of the message */
- memset(&ied, 0, sizeof(ied));
- iax_ie_append_raw(&ied, IAX_IE_PROVISIONING, provdata.buf, provdata.pos);
-
- callno = find_callno_locked(0, 0, &sin, NEW_FORCE, cai.sockfd, 0);
- if (!callno)
- return -1;
-
- if (iaxs[callno]) {
- /* Schedule autodestruct in case they don't ever give us anything back */
- AST_SCHED_DEL(sched, iaxs[callno]->autoid);
- iaxs[callno]->autoid = iax2_sched_add(sched, 15000, auto_hangup, (void *)(long)callno);
- ast_set_flag(iaxs[callno], IAX_PROVISION);
- /* Got a call number now, so go ahead and send the provisioning information */
- send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_PROVISION, 0, ied.buf, ied.pos, -1);
- }
- ast_mutex_unlock(&iaxsl[callno]);
-
- return 1;
-}
-
-static char *papp = "IAX2Provision";
-static char *psyn = "Provision a calling IAXy with a given template";
-static char *pdescrip =
-" IAX2Provision([template]): Provisions the calling IAXy (assuming\n"
-"the calling entity is in fact an IAXy) with the given template or\n"
-"default if one is not specified. Returns -1 on error or 0 on success.\n";
-
-/*! iax2provision
-\ingroup applications
-*/
-static int iax2_prov_app(struct ast_channel *chan, void *data)
-{
- int res;
- char *sdata;
- char *opts;
- int force =0;
- unsigned short callno = PTR_TO_CALLNO(chan->tech_pvt);
- if (ast_strlen_zero(data))
- data = "default";
- sdata = ast_strdupa(data);
- opts = strchr(sdata, '|');
- if (opts)
- *opts='\0';
-
- if (chan->tech != &iax2_tech) {
- ast_log(LOG_NOTICE, "Can't provision a non-IAX device!\n");
- return -1;
- }
- if (!callno || !iaxs[callno] || !iaxs[callno]->addr.sin_addr.s_addr) {
- ast_log(LOG_NOTICE, "Can't provision something with no IP?\n");
- return -1;
- }
- res = iax2_provision(&iaxs[callno]->addr, iaxs[callno]->sockfd, NULL, sdata, force);
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Provisioned IAXY at '%s' with '%s'= %d\n",
- ast_inet_ntoa(iaxs[callno]->addr.sin_addr),
- sdata, res);
- return res;
-}
-
-
-static int iax2_prov_cmd(int fd, int argc, char *argv[])
-{
- int force = 0;
- int res;
- if (argc < 4)
- return RESULT_SHOWUSAGE;
- if ((argc > 4)) {
- if (!strcasecmp(argv[4], "forced"))
- force = 1;
- else
- return RESULT_SHOWUSAGE;
- }
- res = iax2_provision(NULL, -1, argv[2], argv[3], force);
- if (res < 0)
- ast_cli(fd, "Unable to find peer/address '%s'\n", argv[2]);
- else if (res < 1)
- ast_cli(fd, "No template (including wildcard) matching '%s'\n", argv[3]);
- else
- ast_cli(fd, "Provisioning '%s' with template '%s'%s\n", argv[2], argv[3], force ? ", forced" : "");
- return RESULT_SUCCESS;
-}
-
-static void __iax2_poke_noanswer(const void *data)
-{
- struct iax2_peer *peer = (struct iax2_peer *)data;
- int callno;
-
- if (peer->lastms > -1) {
- ast_log(LOG_NOTICE, "Peer '%s' is now UNREACHABLE! Time: %d\n", peer->name, peer->lastms);
- manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "Peer: IAX2/%s\r\nPeerStatus: Unreachable\r\nTime: %d\r\n", peer->name, peer->lastms);
- ast_device_state_changed("IAX2/%s", peer->name); /* Activate notification */
- }
- if ((callno = peer->callno) > 0) {
- ast_mutex_lock(&iaxsl[callno]);
- iax2_destroy(callno);
- ast_mutex_unlock(&iaxsl[callno]);
- }
- peer->callno = 0;
- peer->lastms = -1;
- /* Try again quickly */
- peer->pokeexpire = iax2_sched_add(sched, peer->pokefreqnotok, iax2_poke_peer_s, peer_ref(peer));
- if (peer->pokeexpire == -1)
- peer_unref(peer);
-}
-
-static int iax2_poke_noanswer(const void *data)
-{
- struct iax2_peer *peer = (struct iax2_peer *)data;
- peer->pokeexpire = -1;
-#ifdef SCHED_MULTITHREADED
- if (schedule_action(__iax2_poke_noanswer, data))
-#endif
- __iax2_poke_noanswer(data);
- peer_unref(peer);
- return 0;
-}
-
-static int iax2_poke_peer_cb(void *obj, void *arg, int flags)
-{
- struct iax2_peer *peer = obj;
-
- iax2_poke_peer(peer, 0);
-
- return 0;
-}
-
-static int iax2_poke_peer(struct iax2_peer *peer, int heldcall)
-{
- int callno;
- if (!peer->maxms || (!peer->addr.sin_addr.s_addr && !peer->dnsmgr)) {
- /* IF we have no IP without dnsmgr, or this isn't to be monitored, return
- immediately after clearing things out */
- peer->lastms = 0;
- peer->historicms = 0;
- peer->pokeexpire = -1;
- peer->callno = 0;
- return 0;
- }
-
- /* The peer could change the callno inside iax2_destroy, since we do deadlock avoidance */
- if ((callno = peer->callno) > 0) {
- ast_log(LOG_NOTICE, "Still have a callno...\n");
- ast_mutex_lock(&iaxsl[callno]);
- iax2_destroy(callno);
- ast_mutex_unlock(&iaxsl[callno]);
- }
- if (heldcall)
- ast_mutex_unlock(&iaxsl[heldcall]);
- callno = peer->callno = find_callno(0, 0, &peer->addr, NEW_FORCE, peer->sockfd, 0);
- if (heldcall)
- ast_mutex_lock(&iaxsl[heldcall]);
- if (peer->callno < 1) {
- ast_log(LOG_WARNING, "Unable to allocate call for poking peer '%s'\n", peer->name);
- return -1;
- }
-
- /* Speed up retransmission times for this qualify call */
- iaxs[peer->callno]->pingtime = peer->maxms / 4 + 1;
- iaxs[peer->callno]->peerpoke = peer;
-
- /* Remove any pending pokeexpire task */
- if (peer->pokeexpire > -1) {
- if (!ast_sched_del(sched, peer->pokeexpire)) {
- peer->pokeexpire = -1;
- peer_unref(peer);
- }
- }
-
- /* Queue up a new task to handle no reply */
- /* If the host is already unreachable then use the unreachable interval instead */
- if (peer->lastms < 0) {
- peer->pokeexpire = iax2_sched_add(sched, peer->pokefreqnotok, iax2_poke_noanswer, peer_ref(peer));
- } else
- peer->pokeexpire = iax2_sched_add(sched, DEFAULT_MAXMS * 2, iax2_poke_noanswer, peer_ref(peer));
-
- if (peer->pokeexpire == -1)
- peer_unref(peer);
-
- /* And send the poke */
- ast_mutex_lock(&iaxsl[callno]);
- if (iaxs[callno]) {
- send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_POKE, 0, NULL, 0, -1);
- }
- ast_mutex_unlock(&iaxsl[callno]);
-
- return 0;
-}
-
-static void free_context(struct iax2_context *con)
-{
- struct iax2_context *conl;
- while(con) {
- conl = con;
- con = con->next;
- free(conl);
- }
-}
-
-static struct ast_channel *iax2_request(const char *type, int format, void *data, int *cause)
-{
- int callno;
- int res;
- int fmt, native;
- struct sockaddr_in sin;
- struct ast_channel *c;
- struct parsed_dial_string pds;
- struct create_addr_info cai;
- char *tmpstr;
-
- memset(&pds, 0, sizeof(pds));
- tmpstr = ast_strdupa(data);
- parse_dial_string(tmpstr, &pds);
-
- if (ast_strlen_zero(pds.peer)) {
- ast_log(LOG_WARNING, "No peer provided in the IAX2 dial string '%s'\n", (char *) data);
- return NULL;
- }
-
- memset(&cai, 0, sizeof(cai));
- cai.capability = iax2_capability;
-
- ast_copy_flags(&cai, &globalflags, IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF);
-
- /* Populate our address from the given */
- if (create_addr(pds.peer, NULL, &sin, &cai)) {
- *cause = AST_CAUSE_UNREGISTERED;
- return NULL;
- }
-
- if (pds.port)
- sin.sin_port = htons(atoi(pds.port));
-
- callno = find_callno_locked(0, 0, &sin, NEW_FORCE, cai.sockfd, 0);
- if (callno < 1) {
- ast_log(LOG_WARNING, "Unable to create call\n");
- *cause = AST_CAUSE_CONGESTION;
- return NULL;
- }
-
- /* If this is a trunk, update it now */
- ast_copy_flags(iaxs[callno], &cai, IAX_TRUNK | IAX_SENDANI | IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF);
- if (ast_test_flag(&cai, IAX_TRUNK)) {
- int new_callno;
- if ((new_callno = make_trunk(callno, 1)) != -1)
- callno = new_callno;
- }
- iaxs[callno]->maxtime = cai.maxtime;
- if (cai.found)
- ast_string_field_set(iaxs[callno], host, pds.peer);
-
- c = ast_iax2_new(callno, AST_STATE_DOWN, cai.capability);
-
- ast_mutex_unlock(&iaxsl[callno]);
-
- if (c) {
- /* Choose a format we can live with */
- if (c->nativeformats & format)
- c->nativeformats &= format;
- else {
- native = c->nativeformats;
- fmt = format;
- res = ast_translator_best_choice(&fmt, &native);
- if (res < 0) {
- ast_log(LOG_WARNING, "Unable to create translator path for %s to %s on %s\n",
- ast_getformatname(c->nativeformats), ast_getformatname(fmt), c->name);
- ast_hangup(c);
- return NULL;
- }
- c->nativeformats = native;
- }
- c->readformat = ast_best_codec(c->nativeformats);
- c->writeformat = c->readformat;
- }
-
- return c;
-}
-
-static void *sched_thread(void *ignore)
-{
- int count;
- int res;
- struct timeval tv;
- struct timespec ts;
-
- for (;;) {
- pthread_testcancel();
- ast_mutex_lock(&sched_lock);
- res = ast_sched_wait(sched);
- if ((res > 1000) || (res < 0))
- res = 1000;
- tv = ast_tvadd(ast_tvnow(), ast_samp2tv(res, 1000));
- ts.tv_sec = tv.tv_sec;
- ts.tv_nsec = tv.tv_usec * 1000;
- ast_cond_timedwait(&sched_cond, &sched_lock, &ts);
- ast_mutex_unlock(&sched_lock);
- pthread_testcancel();
-
- count = ast_sched_runq(sched);
- if (option_debug && count >= 20)
- ast_log(LOG_DEBUG, "chan_iax2: ast_sched_runq ran %d scheduled tasks all at once\n", count);
- }
- return NULL;
-}
-
-static void *network_thread(void *ignore)
-{
- /* Our job is simple: Send queued messages, retrying if necessary. Read frames
- from the network, and queue them for delivery to the channels */
- int res, count, wakeup;
- struct iax_frame *f;
-
- if (timingfd > -1)
- ast_io_add(io, timingfd, timing_read, AST_IO_IN | AST_IO_PRI, NULL);
-
- for(;;) {
- pthread_testcancel();
-
- /* Go through the queue, sending messages which have not yet been
- sent, and scheduling retransmissions if appropriate */
- AST_LIST_LOCK(&iaxq.queue);
- count = 0;
- wakeup = -1;
- AST_LIST_TRAVERSE_SAFE_BEGIN(&iaxq.queue, f, list) {
- if (f->sentyet)
- continue;
-
- /* Try to lock the pvt, if we can't... don't fret - defer it till later */
- if (ast_mutex_trylock(&iaxsl[f->callno])) {
- wakeup = 1;
- continue;
- }
-
- f->sentyet++;
-
- if (iaxs[f->callno]) {
- send_packet(f);
- count++;
- }
-
- ast_mutex_unlock(&iaxsl[f->callno]);
-
- if (f->retries < 0) {
- /* This is not supposed to be retransmitted */
- AST_LIST_REMOVE_CURRENT(&iaxq.queue, list);
- iaxq.count--;
- /* Free the iax frame */
- iax_frame_free(f);
- } else {
- /* We need reliable delivery. Schedule a retransmission */
- f->retries++;
- f->retrans = iax2_sched_add(sched, f->retrytime, attempt_transmit, f);
- }
- }
- AST_LIST_TRAVERSE_SAFE_END
- AST_LIST_UNLOCK(&iaxq.queue);
-
- pthread_testcancel();
-
- if (option_debug && count >= 20)
- ast_log(LOG_DEBUG, "chan_iax2: Sent %d queued outbound frames all at once\n", count);
-
- /* Now do the IO, and run scheduled tasks */
- res = ast_io_wait(io, wakeup);
- if (res >= 0) {
- if (option_debug && res >= 20)
- ast_log(LOG_DEBUG, "chan_iax2: ast_io_wait ran %d I/Os all at once\n", res);
- }
- }
- return NULL;
-}
-
-static int start_network_thread(void)
-{
- pthread_attr_t attr;
- int threadcount = 0;
- int x;
- for (x = 0; x < iaxthreadcount; x++) {
- struct iax2_thread *thread = ast_calloc(1, sizeof(struct iax2_thread));
- if (thread) {
- thread->type = IAX_TYPE_POOL;
- thread->threadnum = ++threadcount;
- ast_mutex_init(&thread->lock);
- ast_cond_init(&thread->cond, NULL);
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- if (ast_pthread_create(&thread->threadid, &attr, iax2_process_thread, thread)) {
- ast_log(LOG_WARNING, "Failed to create new thread!\n");
- free(thread);
- thread = NULL;
- }
- AST_LIST_LOCK(&idle_list);
- AST_LIST_INSERT_TAIL(&idle_list, thread, list);
- AST_LIST_UNLOCK(&idle_list);
- }
- }
- ast_pthread_create_background(&schedthreadid, NULL, sched_thread, NULL);
- ast_pthread_create_background(&netthreadid, NULL, network_thread, NULL);
- if (option_verbose > 1)
- ast_verbose(VERBOSE_PREFIX_2 "%d helper threads started\n", threadcount);
- return 0;
-}
-
-static struct iax2_context *build_context(char *context)
-{
- struct iax2_context *con;
-
- if ((con = ast_calloc(1, sizeof(*con))))
- ast_copy_string(con->context, context, sizeof(con->context));
-
- return con;
-}
-
-static int get_auth_methods(char *value)
-{
- int methods = 0;
- if (strstr(value, "rsa"))
- methods |= IAX_AUTH_RSA;
- if (strstr(value, "md5"))
- methods |= IAX_AUTH_MD5;
- if (strstr(value, "plaintext"))
- methods |= IAX_AUTH_PLAINTEXT;
- return methods;
-}
-
-
-/*! \brief Check if address can be used as packet source.
- \return 0 address available, 1 address unavailable, -1 error
-*/
-static int check_srcaddr(struct sockaddr *sa, socklen_t salen)
-{
- int sd;
- int res;
-
- sd = socket(AF_INET, SOCK_DGRAM, 0);
- if (sd < 0) {
- ast_log(LOG_ERROR, "Socket: %s\n", strerror(errno));
- return -1;
- }
-
- res = bind(sd, sa, salen);
- if (res < 0) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Can't bind: %s\n", strerror(errno));
- close(sd);
- return 1;
- }
-
- close(sd);
- return 0;
-}
-
-/*! \brief Parse the "sourceaddress" value,
- lookup in netsock list and set peer's sockfd. Defaults to defaultsockfd if
- not found. */
-static int peer_set_srcaddr(struct iax2_peer *peer, const char *srcaddr)
-{
- struct sockaddr_in sin;
- int nonlocal = 1;
- int port = IAX_DEFAULT_PORTNO;
- int sockfd = defaultsockfd;
- char *tmp;
- char *addr;
- char *portstr;
-
- if (!(tmp = ast_strdupa(srcaddr)))
- return -1;
-
- addr = strsep(&tmp, ":");
- portstr = tmp;
-
- if (portstr) {
- port = atoi(portstr);
- if (port < 1)
- port = IAX_DEFAULT_PORTNO;
- }
-
- if (!ast_get_ip(&sin, addr)) {
- struct ast_netsock *sock;
- int res;
-
- sin.sin_port = 0;
- sin.sin_family = AF_INET;
- res = check_srcaddr((struct sockaddr *) &sin, sizeof(sin));
- if (res == 0) {
- /* ip address valid. */
- sin.sin_port = htons(port);
- if (!(sock = ast_netsock_find(netsock, &sin)))
- sock = ast_netsock_find(outsock, &sin);
- if (sock) {
- sockfd = ast_netsock_sockfd(sock);
- nonlocal = 0;
- } else {
- unsigned int orig_saddr = sin.sin_addr.s_addr;
- /* INADDR_ANY matches anyway! */
- sin.sin_addr.s_addr = INADDR_ANY;
- if (ast_netsock_find(netsock, &sin)) {
- sin.sin_addr.s_addr = orig_saddr;
- sock = ast_netsock_bind(outsock, io, srcaddr, port, tos, socket_read, NULL);
- if (sock) {
- sockfd = ast_netsock_sockfd(sock);
- ast_netsock_unref(sock);
- nonlocal = 0;
- } else {
- nonlocal = 2;
- }
- }
- }
- }
- }
-
- peer->sockfd = sockfd;
-
- if (nonlocal == 1) {
- ast_log(LOG_WARNING, "Non-local or unbound address specified (%s) in sourceaddress for '%s', reverting to default\n",
- srcaddr, peer->name);
- return -1;
- } else if (nonlocal == 2) {
- ast_log(LOG_WARNING, "Unable to bind to sourceaddress '%s' for '%s', reverting to default\n",
- srcaddr, peer->name);
- return -1;
- } else {
- if (option_debug)
- ast_log(LOG_DEBUG, "Using sourceaddress %s for '%s'\n", srcaddr, peer->name);
- return 0;
- }
-}
-
-static void peer_destructor(void *obj)
-{
- struct iax2_peer *peer = obj;
- int callno = peer->callno;
-
- ast_free_ha(peer->ha);
-
- if (callno > 0) {
- ast_mutex_lock(&iaxsl[callno]);
- iax2_destroy(callno);
- ast_mutex_unlock(&iaxsl[callno]);
- }
-
- register_peer_exten(peer, 0);
-
- if (peer->dnsmgr)
- ast_dnsmgr_release(peer->dnsmgr);
-
- ast_string_field_free_memory(peer);
-}
-
-/*! \brief Create peer structure based on configuration */
-static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, struct ast_variable *alt, int temponly)
-{
- struct iax2_peer *peer = NULL;
- struct ast_ha *oldha = NULL;
- int maskfound=0;
- int found=0;
- int firstpass=1;
- struct iax2_peer tmp_peer = {
- .name = name,
- };
-
- if (!temponly) {
- peer = ao2_find(peers, &tmp_peer, OBJ_POINTER);
- if (peer && !ast_test_flag(peer, IAX_DELME))
- firstpass = 0;
- }
-
- if (peer) {
- found++;
- if (firstpass) {
- oldha = peer->ha;
- peer->ha = NULL;
- }
- unlink_peer(peer);
- } else if ((peer = ao2_alloc(sizeof(*peer), peer_destructor))) {
- peer->expire = -1;
- peer->pokeexpire = -1;
- peer->sockfd = defaultsockfd;
- if (ast_string_field_init(peer, 32))
- peer = peer_unref(peer);
- }
-
- if (peer) {
- if (firstpass) {
- ast_copy_flags(peer, &globalflags, IAX_USEJITTERBUF | IAX_FORCEJITTERBUF);
- peer->encmethods = iax2_encryption;
- peer->adsi = adsi;
- ast_string_field_set(peer,secret,"");
- if (!found) {
- ast_string_field_set(peer, name, name);
- peer->addr.sin_port = htons(IAX_DEFAULT_PORTNO);
- peer->expiry = min_reg_expire;
- }
- peer->prefs = prefs;
- peer->capability = iax2_capability;
- peer->smoothing = 0;
- peer->pokefreqok = DEFAULT_FREQ_OK;
- peer->pokefreqnotok = DEFAULT_FREQ_NOTOK;
- ast_string_field_set(peer,context,"");
- ast_string_field_set(peer,peercontext,"");
- ast_clear_flag(peer, IAX_HASCALLERID);
- ast_string_field_set(peer, cid_name, "");
- ast_string_field_set(peer, cid_num, "");
- }
-
- if (!v) {
- v = alt;
- alt = NULL;
- }
- while(v) {
- if (!strcasecmp(v->name, "secret")) {
- ast_string_field_set(peer, secret, v->value);
- } else if (!strcasecmp(v->name, "mailbox")) {
- ast_string_field_set(peer, mailbox, v->value);
- } else if (!strcasecmp(v->name, "hasvoicemail")) {
- if (ast_true(v->value) && ast_strlen_zero(peer->mailbox)) {
- ast_string_field_set(peer, mailbox, name);
- }
- } else if (!strcasecmp(v->name, "mohinterpret")) {
- ast_string_field_set(peer, mohinterpret, v->value);
- } else if (!strcasecmp(v->name, "mohsuggest")) {
- ast_string_field_set(peer, mohsuggest, v->value);
- } else if (!strcasecmp(v->name, "dbsecret")) {
- ast_string_field_set(peer, dbsecret, v->value);
- } else if (!strcasecmp(v->name, "trunk")) {
- ast_set2_flag(peer, ast_true(v->value), IAX_TRUNK);
- if (ast_test_flag(peer, IAX_TRUNK) && (timingfd < 0)) {
- ast_log(LOG_WARNING, "Unable to support trunking on peer '%s' without timing\n", peer->name);
- ast_clear_flag(peer, IAX_TRUNK);
- }
- } else if (!strcasecmp(v->name, "auth")) {
- peer->authmethods = get_auth_methods(v->value);
- } else if (!strcasecmp(v->name, "encryption")) {
- peer->encmethods = get_encrypt_methods(v->value);
- } else if (!strcasecmp(v->name, "notransfer")) {
- ast_log(LOG_NOTICE, "The option 'notransfer' is deprecated in favor of 'transfer' which has options 'yes', 'no', and 'mediaonly'\n");
- ast_clear_flag(peer, IAX_TRANSFERMEDIA);
- ast_set2_flag(peer, ast_true(v->value), IAX_NOTRANSFER);
- } else if (!strcasecmp(v->name, "transfer")) {
- if (!strcasecmp(v->value, "mediaonly")) {
- ast_set_flags_to(peer, IAX_NOTRANSFER|IAX_TRANSFERMEDIA, IAX_TRANSFERMEDIA);
- } else if (ast_true(v->value)) {
- ast_set_flags_to(peer, IAX_NOTRANSFER|IAX_TRANSFERMEDIA, 0);
- } else
- ast_set_flags_to(peer, IAX_NOTRANSFER|IAX_TRANSFERMEDIA, IAX_NOTRANSFER);
- } else if (!strcasecmp(v->name, "jitterbuffer")) {
- ast_set2_flag(peer, ast_true(v->value), IAX_USEJITTERBUF);
- } else if (!strcasecmp(v->name, "forcejitterbuffer")) {
- ast_set2_flag(peer, ast_true(v->value), IAX_FORCEJITTERBUF);
- } else if (!strcasecmp(v->name, "host")) {
- if (!strcasecmp(v->value, "dynamic")) {
- /* They'll register with us */
- ast_set_flag(peer, IAX_DYNAMIC);
- if (!found) {
- /* Initialize stuff iff we're not found, otherwise
- we keep going with what we had */
- memset(&peer->addr.sin_addr, 0, 4);
- if (peer->addr.sin_port) {
- /* If we've already got a port, make it the default rather than absolute */
- peer->defaddr.sin_port = peer->addr.sin_port;
- peer->addr.sin_port = 0;
- }
- }
- } else {
- /* Non-dynamic. Make sure we become that way if we're not */
- AST_SCHED_DEL(sched, peer->expire);
- ast_clear_flag(peer, IAX_DYNAMIC);
- if (ast_dnsmgr_lookup(v->value, &peer->addr.sin_addr, &peer->dnsmgr))
- return peer_unref(peer);
- if (!peer->addr.sin_port)
- peer->addr.sin_port = htons(IAX_DEFAULT_PORTNO);
- }
- if (!maskfound)
- inet_aton("255.255.255.255", &peer->mask);
- } else if (!strcasecmp(v->name, "defaultip")) {
- if (ast_get_ip(&peer->defaddr, v->value))
- return peer_unref(peer);
- } else if (!strcasecmp(v->name, "sourceaddress")) {
- peer_set_srcaddr(peer, v->value);
- } else if (!strcasecmp(v->name, "permit") ||
- !strcasecmp(v->name, "deny")) {
- peer->ha = ast_append_ha(v->name, v->value, peer->ha);
- } else if (!strcasecmp(v->name, "mask")) {
- maskfound++;
- inet_aton(v->value, &peer->mask);
- } else if (!strcasecmp(v->name, "context")) {
- ast_string_field_set(peer, context, v->value);
- } else if (!strcasecmp(v->name, "regexten")) {
- ast_string_field_set(peer, regexten, v->value);
- } else if (!strcasecmp(v->name, "peercontext")) {
- ast_string_field_set(peer, peercontext, v->value);
- } else if (!strcasecmp(v->name, "port")) {
- if (ast_test_flag(peer, IAX_DYNAMIC))
- peer->defaddr.sin_port = htons(atoi(v->value));
- else
- peer->addr.sin_port = htons(atoi(v->value));
- } else if (!strcasecmp(v->name, "username")) {
- ast_string_field_set(peer, username, v->value);
- } else if (!strcasecmp(v->name, "allow")) {
- ast_parse_allow_disallow(&peer->prefs, &peer->capability, v->value, 1);
- } else if (!strcasecmp(v->name, "disallow")) {
- ast_parse_allow_disallow(&peer->prefs, &peer->capability, v->value, 0);
- } else if (!strcasecmp(v->name, "callerid")) {
- if (!ast_strlen_zero(v->value)) {
- char name2[80];
- char num2[80];
- ast_callerid_split(v->value, name2, sizeof(name2), num2, sizeof(num2));
- ast_string_field_set(peer, cid_name, name2);
- ast_string_field_set(peer, cid_num, num2);
- } else {
- ast_string_field_set(peer, cid_name, "");
- ast_string_field_set(peer, cid_num, "");
- }
- ast_set_flag(peer, IAX_HASCALLERID);
- } else if (!strcasecmp(v->name, "fullname")) {
- ast_string_field_set(peer, cid_name, S_OR(v->value, ""));
- ast_set_flag(peer, IAX_HASCALLERID);
- } else if (!strcasecmp(v->name, "cid_number")) {
- ast_string_field_set(peer, cid_num, S_OR(v->value, ""));
- ast_set_flag(peer, IAX_HASCALLERID);
- } else if (!strcasecmp(v->name, "sendani")) {
- ast_set2_flag(peer, ast_true(v->value), IAX_SENDANI);
- } else if (!strcasecmp(v->name, "inkeys")) {
- ast_string_field_set(peer, inkeys, v->value);
- } else if (!strcasecmp(v->name, "outkey")) {
- ast_string_field_set(peer, outkey, v->value);
- } else if (!strcasecmp(v->name, "qualify")) {
- if (!strcasecmp(v->value, "no")) {
- peer->maxms = 0;
- } else if (!strcasecmp(v->value, "yes")) {
- peer->maxms = DEFAULT_MAXMS;
- } else if (sscanf(v->value, "%d", &peer->maxms) != 1) {
- ast_log(LOG_WARNING, "Qualification of peer '%s' should be 'yes', 'no', or a number of milliseconds at line %d of iax.conf\n", peer->name, v->lineno);
- peer->maxms = 0;
- }
- } else if (!strcasecmp(v->name, "qualifysmoothing")) {
- peer->smoothing = ast_true(v->value);
- } else if (!strcasecmp(v->name, "qualifyfreqok")) {
- if (sscanf(v->value, "%d", &peer->pokefreqok) != 1) {
- ast_log(LOG_WARNING, "Qualification testing frequency of peer '%s' when OK should a number of milliseconds at line %d of iax.conf\n", peer->name, v->lineno);
- }
- } else if (!strcasecmp(v->name, "qualifyfreqnotok")) {
- if (sscanf(v->value, "%d", &peer->pokefreqnotok) != 1) {
- ast_log(LOG_WARNING, "Qualification testing frequency of peer '%s' when NOT OK should be a number of milliseconds at line %d of iax.conf\n", peer->name, v->lineno);
- } else ast_log(LOG_WARNING, "Set peer->pokefreqnotok to %d\n", peer->pokefreqnotok);
- } else if (!strcasecmp(v->name, "timezone")) {
- ast_string_field_set(peer, zonetag, v->value);
- } else if (!strcasecmp(v->name, "adsi")) {
- peer->adsi = ast_true(v->value);
- }/* else if (strcasecmp(v->name,"type")) */
- /* ast_log(LOG_WARNING, "Ignoring %s\n", v->name); */
- v = v->next;
- if (!v) {
- v = alt;
- alt = NULL;
- }
- }
- if (!peer->authmethods)
- peer->authmethods = IAX_AUTH_MD5 | IAX_AUTH_PLAINTEXT;
- ast_clear_flag(peer, IAX_DELME);
- /* Make sure these are IPv4 addresses */
- peer->addr.sin_family = AF_INET;
- }
- if (oldha)
- ast_free_ha(oldha);
- return peer;
-}
-
-static void user_destructor(void *obj)
-{
- struct iax2_user *user = obj;
-
- ast_free_ha(user->ha);
- free_context(user->contexts);
- if(user->vars) {
- ast_variables_destroy(user->vars);
- user->vars = NULL;
- }
- ast_string_field_free_memory(user);
-}
-
-/*! \brief Create in-memory user structure from configuration */
-static struct iax2_user *build_user(const char *name, struct ast_variable *v, struct ast_variable *alt, int temponly)
-{
- struct iax2_user *user = NULL;
- struct iax2_context *con, *conl = NULL;
- struct ast_ha *oldha = NULL;
- struct iax2_context *oldcon = NULL;
- int format;
- int firstpass=1;
- int oldcurauthreq = 0;
- char *varname = NULL, *varval = NULL;
- struct ast_variable *tmpvar = NULL;
- struct iax2_user tmp_user = {
- .name = name,
- };
-
- if (!temponly) {
- user = ao2_find(users, &tmp_user, OBJ_POINTER);
- if (user && !ast_test_flag(user, IAX_DELME))
- firstpass = 0;
- }
-
- if (user) {
- if (firstpass) {
- oldcurauthreq = user->curauthreq;
- oldha = user->ha;
- oldcon = user->contexts;
- user->ha = NULL;
- user->contexts = NULL;
- }
- /* Already in the list, remove it and it will be added back (or FREE'd) */
- ao2_unlink(users, user);
- } else {
- user = ao2_alloc(sizeof(*user), user_destructor);
- }
-
- if (user) {
- if (firstpass) {
- ast_string_field_free_memory(user);
- memset(user, 0, sizeof(struct iax2_user));
- if (ast_string_field_init(user, 32)) {
- user = user_unref(user);
- goto cleanup;
- }
- user->maxauthreq = maxauthreq;
- user->curauthreq = oldcurauthreq;
- user->prefs = prefs;
- user->capability = iax2_capability;
- user->encmethods = iax2_encryption;
- user->adsi = adsi;
- ast_string_field_set(user, name, name);
- ast_string_field_set(user, language, language);
- ast_copy_flags(user, &globalflags, IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_CODEC_USER_FIRST | IAX_CODEC_NOPREFS | IAX_CODEC_NOCAP);
- ast_clear_flag(user, IAX_HASCALLERID);
- ast_string_field_set(user, cid_name, "");
- ast_string_field_set(user, cid_num, "");
- }
- if (!v) {
- v = alt;
- alt = NULL;
- }
- while(v) {
- if (!strcasecmp(v->name, "context")) {
- con = build_context(v->value);
- if (con) {
- if (conl)
- conl->next = con;
- else
- user->contexts = con;
- conl = con;
- }
- } else if (!strcasecmp(v->name, "permit") ||
- !strcasecmp(v->name, "deny")) {
- user->ha = ast_append_ha(v->name, v->value, user->ha);
- } else if (!strcasecmp(v->name, "setvar")) {
- varname = ast_strdupa(v->value);
- if (varname && (varval = strchr(varname,'='))) {
- *varval = '\0';
- varval++;
- if((tmpvar = ast_variable_new(varname, varval))) {
- tmpvar->next = user->vars;
- user->vars = tmpvar;
- }
- }
- } else if (!strcasecmp(v->name, "allow")) {
- ast_parse_allow_disallow(&user->prefs, &user->capability, v->value, 1);
- } else if (!strcasecmp(v->name, "disallow")) {
- ast_parse_allow_disallow(&user->prefs, &user->capability,v->value, 0);
- } else if (!strcasecmp(v->name, "trunk")) {
- ast_set2_flag(user, ast_true(v->value), IAX_TRUNK);
- if (ast_test_flag(user, IAX_TRUNK) && (timingfd < 0)) {
- ast_log(LOG_WARNING, "Unable to support trunking on user '%s' without timing\n", user->name);
- ast_clear_flag(user, IAX_TRUNK);
- }
- } else if (!strcasecmp(v->name, "auth")) {
- user->authmethods = get_auth_methods(v->value);
- } else if (!strcasecmp(v->name, "encryption")) {
- user->encmethods = get_encrypt_methods(v->value);
- } else if (!strcasecmp(v->name, "notransfer")) {
- ast_log(LOG_NOTICE, "The option 'notransfer' is deprecated in favor of 'transfer' which has options 'yes', 'no', and 'mediaonly'\n");
- ast_clear_flag(user, IAX_TRANSFERMEDIA);
- ast_set2_flag(user, ast_true(v->value), IAX_NOTRANSFER);
- } else if (!strcasecmp(v->name, "transfer")) {
- if (!strcasecmp(v->value, "mediaonly")) {
- ast_set_flags_to(user, IAX_NOTRANSFER|IAX_TRANSFERMEDIA, IAX_TRANSFERMEDIA);
- } else if (ast_true(v->value)) {
- ast_set_flags_to(user, IAX_NOTRANSFER|IAX_TRANSFERMEDIA, 0);
- } else
- ast_set_flags_to(user, IAX_NOTRANSFER|IAX_TRANSFERMEDIA, IAX_NOTRANSFER);
- } else if (!strcasecmp(v->name, "codecpriority")) {
- if(!strcasecmp(v->value, "caller"))
- ast_set_flag(user, IAX_CODEC_USER_FIRST);
- else if(!strcasecmp(v->value, "disabled"))
- ast_set_flag(user, IAX_CODEC_NOPREFS);
- else if(!strcasecmp(v->value, "reqonly")) {
- ast_set_flag(user, IAX_CODEC_NOCAP);
- ast_set_flag(user, IAX_CODEC_NOPREFS);
- }
- } else if (!strcasecmp(v->name, "jitterbuffer")) {
- ast_set2_flag(user, ast_true(v->value), IAX_USEJITTERBUF);
- } else if (!strcasecmp(v->name, "forcejitterbuffer")) {
- ast_set2_flag(user, ast_true(v->value), IAX_FORCEJITTERBUF);
- } else if (!strcasecmp(v->name, "dbsecret")) {
- ast_string_field_set(user, dbsecret, v->value);
- } else if (!strcasecmp(v->name, "secret")) {
- if (!ast_strlen_zero(user->secret)) {
- char *old = ast_strdupa(user->secret);
-
- ast_string_field_build(user, secret, "%s;%s", old, v->value);
- } else
- ast_string_field_set(user, secret, v->value);
- } else if (!strcasecmp(v->name, "callerid")) {
- if (!ast_strlen_zero(v->value) && strcasecmp(v->value, "asreceived")) {
- char name2[80];
- char num2[80];
- ast_callerid_split(v->value, name2, sizeof(name2), num2, sizeof(num2));
- ast_string_field_set(user, cid_name, name2);
- ast_string_field_set(user, cid_num, num2);
- ast_set_flag(user, IAX_HASCALLERID);
- } else {
- ast_clear_flag(user, IAX_HASCALLERID);
- ast_string_field_set(user, cid_name, "");
- ast_string_field_set(user, cid_num, "");
- }
- } else if (!strcasecmp(v->name, "fullname")) {
- if (!ast_strlen_zero(v->value)) {
- ast_string_field_set(user, cid_name, v->value);
- ast_set_flag(user, IAX_HASCALLERID);
- } else {
- ast_string_field_set(user, cid_name, "");
- if (ast_strlen_zero(user->cid_num))
- ast_clear_flag(user, IAX_HASCALLERID);
- }
- } else if (!strcasecmp(v->name, "cid_number")) {
- if (!ast_strlen_zero(v->value)) {
- ast_string_field_set(user, cid_num, v->value);
- ast_set_flag(user, IAX_HASCALLERID);
- } else {
- ast_string_field_set(user, cid_num, "");
- if (ast_strlen_zero(user->cid_name))
- ast_clear_flag(user, IAX_HASCALLERID);
- }
- } else if (!strcasecmp(v->name, "accountcode")) {
- ast_string_field_set(user, accountcode, v->value);
- } else if (!strcasecmp(v->name, "mohinterpret")) {
- ast_string_field_set(user, mohinterpret, v->value);
- } else if (!strcasecmp(v->name, "mohsuggest")) {
- ast_string_field_set(user, mohsuggest, v->value);
- } else if (!strcasecmp(v->name, "language")) {
- ast_string_field_set(user, language, v->value);
- } else if (!strcasecmp(v->name, "amaflags")) {
- format = ast_cdr_amaflags2int(v->value);
- if (format < 0) {
- ast_log(LOG_WARNING, "Invalid AMA Flags: %s at line %d\n", v->value, v->lineno);
- } else {
- user->amaflags = format;
- }
- } else if (!strcasecmp(v->name, "inkeys")) {
- ast_string_field_set(user, inkeys, v->value);
- } else if (!strcasecmp(v->name, "maxauthreq")) {
- user->maxauthreq = atoi(v->value);
- if (user->maxauthreq < 0)
- user->maxauthreq = 0;
- } else if (!strcasecmp(v->name, "adsi")) {
- user->adsi = ast_true(v->value);
- }/* else if (strcasecmp(v->name,"type")) */
- /* ast_log(LOG_WARNING, "Ignoring %s\n", v->name); */
- v = v->next;
- if (!v) {
- v = alt;
- alt = NULL;
- }
- }
- if (!user->authmethods) {
- if (!ast_strlen_zero(user->secret)) {
- user->authmethods = IAX_AUTH_MD5 | IAX_AUTH_PLAINTEXT;
- if (!ast_strlen_zero(user->inkeys))
- user->authmethods |= IAX_AUTH_RSA;
- } else if (!ast_strlen_zero(user->inkeys)) {
- user->authmethods = IAX_AUTH_RSA;
- } else {
- user->authmethods = IAX_AUTH_MD5 | IAX_AUTH_PLAINTEXT;
- }
- }
- ast_clear_flag(user, IAX_DELME);
- }
-cleanup:
- if (oldha)
- ast_free_ha(oldha);
- if (oldcon)
- free_context(oldcon);
- return user;
-}
-
-static int peer_delme_cb(void *obj, void *arg, int flags)
-{
- struct iax2_peer *peer = obj;
-
- ast_set_flag(peer, IAX_DELME);
-
- return 0;
-}
-
-static int user_delme_cb(void *obj, void *arg, int flags)
-{
- struct iax2_user *user = obj;
-
- ast_set_flag(user, IAX_DELME);
-
- return 0;
-}
-
-static void delete_users(void)
-{
- struct iax2_registry *reg;
-
- ao2_callback(users, 0, user_delme_cb, NULL);
-
- AST_LIST_LOCK(&registrations);
- while ((reg = AST_LIST_REMOVE_HEAD(&registrations, entry))) {
- ast_sched_del(sched, reg->expire);
- if (reg->callno) {
- int callno = reg->callno;
- ast_mutex_lock(&iaxsl[callno]);
- if (iaxs[callno]) {
- iaxs[callno]->reg = NULL;
- iax2_destroy(callno);
- }
- ast_mutex_unlock(&iaxsl[callno]);
- }
- if (reg->dnsmgr)
- ast_dnsmgr_release(reg->dnsmgr);
- free(reg);
- }
- AST_LIST_UNLOCK(&registrations);
-
- ao2_callback(peers, 0, peer_delme_cb, NULL);
-}
-
-static void prune_users(void)
-{
- struct iax2_user *user;
- struct ao2_iterator i;
-
- i = ao2_iterator_init(users, 0);
- while ((user = ao2_iterator_next(&i))) {
- if (ast_test_flag(user, IAX_DELME))
- ao2_unlink(users, user);
- user_unref(user);
- }
-}
-
-/* Prune peers who still are supposed to be deleted */
-static void prune_peers(void)
-{
- struct iax2_peer *peer;
- struct ao2_iterator i;
-
- i = ao2_iterator_init(peers, 0);
- while ((peer = ao2_iterator_next(&i))) {
- if (ast_test_flag(peer, IAX_DELME))
- unlink_peer(peer);
- peer_unref(peer);
- }
-}
-
-static void set_timing(void)
-{
-#ifdef HAVE_DAHDI
- int bs = trunkfreq * 8;
- if (timingfd > -1) {
- if (
-#ifdef DAHDI_TIMERACK
- ioctl(timingfd, DAHDI_TIMERCONFIG, &bs) &&
-#endif
- ioctl(timingfd, DAHDI_SET_BLOCKSIZE, &bs))
- ast_log(LOG_WARNING, "Unable to set blocksize on timing source\n");
- }
-#endif
-}
-
-static void set_config_destroy(void)
-{
- strcpy(accountcode, "");
- strcpy(language, "");
- strcpy(mohinterpret, "default");
- strcpy(mohsuggest, "");
- amaflags = 0;
- delayreject = 0;
- ast_clear_flag((&globalflags), IAX_NOTRANSFER);
- ast_clear_flag((&globalflags), IAX_TRANSFERMEDIA);
- ast_clear_flag((&globalflags), IAX_USEJITTERBUF);
- ast_clear_flag((&globalflags), IAX_FORCEJITTERBUF);
- delete_users();
-}
-
-/*! \brief Load configuration */
-static int set_config(char *config_file, int reload)
-{
- struct ast_config *cfg, *ucfg;
- int capability=iax2_capability;
- struct ast_variable *v;
- char *cat;
- const char *utype;
- const char *tosval;
- int format;
- int portno = IAX_DEFAULT_PORTNO;
- int x;
- struct iax2_user *user;
- struct iax2_peer *peer;
- struct ast_netsock *ns;
-#if 0
- static unsigned short int last_port=0;
-#endif
-
- cfg = ast_config_load(config_file);
-
- if (!cfg) {
- ast_log(LOG_ERROR, "Unable to load config %s\n", config_file);
- return -1;
- }
-
- if (reload) {
- set_config_destroy();
- }
-
- /* Reset global codec prefs */
- memset(&prefs, 0 , sizeof(struct ast_codec_pref));
-
- /* Reset Global Flags */
- memset(&globalflags, 0, sizeof(globalflags));
- ast_set_flag(&globalflags, IAX_RTUPDATE);
-
-#ifdef SO_NO_CHECK
- nochecksums = 0;
-#endif
-
- min_reg_expire = IAX_DEFAULT_REG_EXPIRE;
- max_reg_expire = IAX_DEFAULT_REG_EXPIRE;
-
- maxauthreq = 3;
-
- v = ast_variable_browse(cfg, "general");
-
- /* Seed initial tos value */
- tosval = ast_variable_retrieve(cfg, "general", "tos");
- if (tosval) {
- if (ast_str2tos(tosval, &tos))
- ast_log(LOG_WARNING, "Invalid tos value, see doc/ip-tos.txt for more information.\n");
- }
- while(v) {
- if (!strcasecmp(v->name, "bindport")){
- if (reload)
- ast_log(LOG_NOTICE, "Ignoring bindport on reload\n");
- else
- portno = atoi(v->value);
- } else if (!strcasecmp(v->name, "pingtime"))
- ping_time = atoi(v->value);
- else if (!strcasecmp(v->name, "iaxthreadcount")) {
- if (reload) {
- if (atoi(v->value) != iaxthreadcount)
- ast_log(LOG_NOTICE, "Ignoring any changes to iaxthreadcount during reload\n");
- } else {
- iaxthreadcount = atoi(v->value);
- if (iaxthreadcount < 1) {
- ast_log(LOG_NOTICE, "iaxthreadcount must be at least 1.\n");
- iaxthreadcount = 1;
- } else if (iaxthreadcount > 256) {
- ast_log(LOG_NOTICE, "limiting iaxthreadcount to 256\n");
- iaxthreadcount = 256;
- }
- }
- } else if (!strcasecmp(v->name, "iaxmaxthreadcount")) {
- if (reload) {
- AST_LIST_LOCK(&dynamic_list);
- iaxmaxthreadcount = atoi(v->value);
- AST_LIST_UNLOCK(&dynamic_list);
- } else {
- iaxmaxthreadcount = atoi(v->value);
- if (iaxmaxthreadcount < 0) {
- ast_log(LOG_NOTICE, "iaxmaxthreadcount must be at least 0.\n");
- iaxmaxthreadcount = 0;
- } else if (iaxmaxthreadcount > 256) {
- ast_log(LOG_NOTICE, "Limiting iaxmaxthreadcount to 256\n");
- iaxmaxthreadcount = 256;
- }
- }
- } else if (!strcasecmp(v->name, "nochecksums")) {
-#ifdef SO_NO_CHECK
- if (ast_true(v->value))
- nochecksums = 1;
- else
- nochecksums = 0;
-#else
- if (ast_true(v->value))
- ast_log(LOG_WARNING, "Disabling RTP checksums is not supported on this operating system!\n");
-#endif
- }
- else if (!strcasecmp(v->name, "maxjitterbuffer"))
- maxjitterbuffer = atoi(v->value);
- else if (!strcasecmp(v->name, "resyncthreshold"))
- resyncthreshold = atoi(v->value);
- else if (!strcasecmp(v->name, "maxjitterinterps"))
- maxjitterinterps = atoi(v->value);
- else if (!strcasecmp(v->name, "lagrqtime"))
- lagrq_time = atoi(v->value);
- else if (!strcasecmp(v->name, "maxregexpire"))
- max_reg_expire = atoi(v->value);
- else if (!strcasecmp(v->name, "minregexpire"))
- min_reg_expire = atoi(v->value);
- else if (!strcasecmp(v->name, "bindaddr")) {
- if (reload) {
- ast_log(LOG_NOTICE, "Ignoring bindaddr on reload\n");
- } else {
- if (!(ns = ast_netsock_bind(netsock, io, v->value, portno, tos, socket_read, NULL))) {
- ast_log(LOG_WARNING, "Unable apply binding to '%s' at line %d\n", v->value, v->lineno);
- } else {
- if (option_verbose > 1) {
- if (strchr(v->value, ':'))
- ast_verbose(VERBOSE_PREFIX_2 "Binding IAX2 to '%s'\n", v->value);
- else
- ast_verbose(VERBOSE_PREFIX_2 "Binding IAX2 to '%s:%d'\n", v->value, portno);
- }
- if (defaultsockfd < 0)
- defaultsockfd = ast_netsock_sockfd(ns);
- ast_netsock_unref(ns);
- }
- }
- } else if (!strcasecmp(v->name, "authdebug"))
- authdebug = ast_true(v->value);
- else if (!strcasecmp(v->name, "encryption"))
- iax2_encryption = get_encrypt_methods(v->value);
- else if (!strcasecmp(v->name, "notransfer")) {
- ast_log(LOG_NOTICE, "The option 'notransfer' is deprecated in favor of 'transfer' which has options 'yes', 'no', and 'mediaonly'\n");
- ast_clear_flag((&globalflags), IAX_TRANSFERMEDIA);
- ast_set2_flag((&globalflags), ast_true(v->value), IAX_NOTRANSFER);
- } else if (!strcasecmp(v->name, "transfer")) {
- if (!strcasecmp(v->value, "mediaonly")) {
- ast_set_flags_to((&globalflags), IAX_NOTRANSFER|IAX_TRANSFERMEDIA, IAX_TRANSFERMEDIA);
- } else if (ast_true(v->value)) {
- ast_set_flags_to((&globalflags), IAX_NOTRANSFER|IAX_TRANSFERMEDIA, 0);
- } else
- ast_set_flags_to((&globalflags), IAX_NOTRANSFER|IAX_TRANSFERMEDIA, IAX_NOTRANSFER);
- } else if (!strcasecmp(v->name, "codecpriority")) {
- if(!strcasecmp(v->value, "caller"))
- ast_set_flag((&globalflags), IAX_CODEC_USER_FIRST);
- else if(!strcasecmp(v->value, "disabled"))
- ast_set_flag((&globalflags), IAX_CODEC_NOPREFS);
- else if(!strcasecmp(v->value, "reqonly")) {
- ast_set_flag((&globalflags), IAX_CODEC_NOCAP);
- ast_set_flag((&globalflags), IAX_CODEC_NOPREFS);
- }
- } else if (!strcasecmp(v->name, "jitterbuffer"))
- ast_set2_flag((&globalflags), ast_true(v->value), IAX_USEJITTERBUF);
- else if (!strcasecmp(v->name, "forcejitterbuffer"))
- ast_set2_flag((&globalflags), ast_true(v->value), IAX_FORCEJITTERBUF);
- else if (!strcasecmp(v->name, "delayreject"))
- delayreject = ast_true(v->value);
- else if (!strcasecmp(v->name, "allowfwdownload"))
- ast_set2_flag((&globalflags), ast_true(v->value), IAX_ALLOWFWDOWNLOAD);
- else if (!strcasecmp(v->name, "rtcachefriends"))
- ast_set2_flag((&globalflags), ast_true(v->value), IAX_RTCACHEFRIENDS);
- else if (!strcasecmp(v->name, "rtignoreregexpire"))
- ast_set2_flag((&globalflags), ast_true(v->value), IAX_RTIGNOREREGEXPIRE);
- else if (!strcasecmp(v->name, "rtupdate"))
- ast_set2_flag((&globalflags), ast_true(v->value), IAX_RTUPDATE);
- else if (!strcasecmp(v->name, "trunktimestamps"))
- ast_set2_flag(&globalflags, ast_true(v->value), IAX_TRUNKTIMESTAMPS);
- else if (!strcasecmp(v->name, "rtautoclear")) {
- int i = atoi(v->value);
- if(i > 0)
- global_rtautoclear = i;
- else
- i = 0;
- ast_set2_flag((&globalflags), i || ast_true(v->value), IAX_RTAUTOCLEAR);
- } else if (!strcasecmp(v->name, "trunkfreq")) {
- trunkfreq = atoi(v->value);
- if (trunkfreq < 10)
- trunkfreq = 10;
- } else if (!strcasecmp(v->name, "autokill")) {
- if (sscanf(v->value, "%d", &x) == 1) {
- if (x >= 0)
- autokill = x;
- else
- ast_log(LOG_NOTICE, "Nice try, but autokill has to be >0 or 'yes' or 'no' at line %d\n", v->lineno);
- } else if (ast_true(v->value)) {
- autokill = DEFAULT_MAXMS;
- } else {
- autokill = 0;
- }
- } else if (!strcasecmp(v->name, "bandwidth")) {
- if (!strcasecmp(v->value, "low")) {
- capability = IAX_CAPABILITY_LOWBANDWIDTH;
- } else if (!strcasecmp(v->value, "medium")) {
- capability = IAX_CAPABILITY_MEDBANDWIDTH;
- } else if (!strcasecmp(v->value, "high")) {
- capability = IAX_CAPABILITY_FULLBANDWIDTH;
- } else
- ast_log(LOG_WARNING, "bandwidth must be either low, medium, or high\n");
- } else if (!strcasecmp(v->name, "allow")) {
- ast_parse_allow_disallow(&prefs, &capability, v->value, 1);
- } else if (!strcasecmp(v->name, "disallow")) {
- ast_parse_allow_disallow(&prefs, &capability, v->value, 0);
- } else if (!strcasecmp(v->name, "register")) {
- iax2_register(v->value, v->lineno);
- } else if (!strcasecmp(v->name, "iaxcompat")) {
- iaxcompat = ast_true(v->value);
- } else if (!strcasecmp(v->name, "regcontext")) {
- ast_copy_string(regcontext, v->value, sizeof(regcontext));
- /* Create context if it doesn't exist already */
- if (!ast_context_find(regcontext))
- ast_context_create(NULL, regcontext, "IAX2");
- } else if (!strcasecmp(v->name, "tos")) {
- if (ast_str2tos(v->value, &tos))
- ast_log(LOG_WARNING, "Invalid tos value at line %d, see doc/ip-tos.txt for more information.'\n", v->lineno);
- } else if (!strcasecmp(v->name, "accountcode")) {
- ast_copy_string(accountcode, v->value, sizeof(accountcode));
- } else if (!strcasecmp(v->name, "mohinterpret")) {
- ast_copy_string(mohinterpret, v->value, sizeof(mohinterpret));
- } else if (!strcasecmp(v->name, "mohsuggest")) {
- ast_copy_string(mohsuggest, v->value, sizeof(mohsuggest));
- } else if (!strcasecmp(v->name, "amaflags")) {
- format = ast_cdr_amaflags2int(v->value);
- if (format < 0) {
- ast_log(LOG_WARNING, "Invalid AMA Flags: %s at line %d\n", v->value, v->lineno);
- } else {
- amaflags = format;
- }
- } else if (!strcasecmp(v->name, "language")) {
- ast_copy_string(language, v->value, sizeof(language));
- } else if (!strcasecmp(v->name, "maxauthreq")) {
- maxauthreq = atoi(v->value);
- if (maxauthreq < 0)
- maxauthreq = 0;
- } else if (!strcasecmp(v->name, "adsi")) {
- adsi = ast_true(v->value);
- } /*else if (strcasecmp(v->name,"type")) */
- /* ast_log(LOG_WARNING, "Ignoring %s\n", v->name); */
- v = v->next;
- }
-
- if (defaultsockfd < 0) {
- if (!(ns = ast_netsock_bind(netsock, io, "0.0.0.0", portno, tos, socket_read, NULL))) {
- ast_log(LOG_ERROR, "Unable to create network socket: %s\n", strerror(errno));
- } else {
- if (option_verbose > 1)
- ast_verbose(VERBOSE_PREFIX_2 "Binding IAX2 to default address 0.0.0.0:%d\n", portno);
- defaultsockfd = ast_netsock_sockfd(ns);
- ast_netsock_unref(ns);
- }
- }
- if (reload) {
- ast_netsock_release(outsock);
- outsock = ast_netsock_list_alloc();
- if (!outsock) {
- ast_log(LOG_ERROR, "Could not allocate outsock list.\n");
- return -1;
- }
- ast_netsock_init(outsock);
- }
-
- if (min_reg_expire > max_reg_expire) {
- ast_log(LOG_WARNING, "Minimum registration interval of %d is more than maximum of %d, resetting minimum to %d\n",
- min_reg_expire, max_reg_expire, max_reg_expire);
- min_reg_expire = max_reg_expire;
- }
- iax2_capability = capability;
-
- ucfg = ast_config_load("users.conf");
- if (ucfg) {
- struct ast_variable *gen;
- int genhasiax;
- int genregisteriax;
- const char *hasiax, *registeriax;
-
- genhasiax = ast_true(ast_variable_retrieve(ucfg, "general", "hasiax"));
- genregisteriax = ast_true(ast_variable_retrieve(ucfg, "general", "registeriax"));
- gen = ast_variable_browse(ucfg, "general");
- cat = ast_category_browse(ucfg, NULL);
- while (cat) {
- if (strcasecmp(cat, "general")) {
- hasiax = ast_variable_retrieve(ucfg, cat, "hasiax");
- registeriax = ast_variable_retrieve(ucfg, cat, "registeriax");
- if (ast_true(hasiax) || (!hasiax && genhasiax)) {
- /* Start with general parameters, then specific parameters, user and peer */
- user = build_user(cat, gen, ast_variable_browse(ucfg, cat), 0);
- if (user) {
- __ao2_link(users, user, (MAX_PEER_BUCKETS == 1) ? 1 : 0);
- user = user_unref(user);
- }
- peer = build_peer(cat, gen, ast_variable_browse(ucfg, cat), 0);
- if (peer) {
- if (ast_test_flag(peer, IAX_DYNAMIC))
- reg_source_db(peer);
- __ao2_link(peers, peer, (MAX_PEER_BUCKETS == 1) ? 1 : 0);
- peer = peer_unref(peer);
- }
- }
- if (ast_true(registeriax) || (!registeriax && genregisteriax)) {
- char tmp[256];
- const char *host = ast_variable_retrieve(ucfg, cat, "host");
- const char *username = ast_variable_retrieve(ucfg, cat, "username");
- const char *secret = ast_variable_retrieve(ucfg, cat, "secret");
- if (!host)
- host = ast_variable_retrieve(ucfg, "general", "host");
- if (!username)
- username = ast_variable_retrieve(ucfg, "general", "username");
- if (!secret)
- secret = ast_variable_retrieve(ucfg, "general", "secret");
- if (!ast_strlen_zero(username) && !ast_strlen_zero(host)) {
- if (!ast_strlen_zero(secret))
- snprintf(tmp, sizeof(tmp), "%s:%s@%s", username, secret, host);
- else
- snprintf(tmp, sizeof(tmp), "%s@%s", username, host);
- iax2_register(tmp, 0);
- }
- }
- }
- cat = ast_category_browse(ucfg, cat);
- }
- ast_config_destroy(ucfg);
- }
-
- cat = ast_category_browse(cfg, NULL);
- while(cat) {
- if (strcasecmp(cat, "general")) {
- utype = ast_variable_retrieve(cfg, cat, "type");
- if (utype) {
- if (!strcasecmp(utype, "user") || !strcasecmp(utype, "friend")) {
- user = build_user(cat, ast_variable_browse(cfg, cat), NULL, 0);
- if (user) {
- __ao2_link(users, user, (MAX_PEER_BUCKETS == 1) ? 1 : 0);
- user = user_unref(user);
- }
- }
- if (!strcasecmp(utype, "peer") || !strcasecmp(utype, "friend")) {
- peer = build_peer(cat, ast_variable_browse(cfg, cat), NULL, 0);
- if (peer) {
- if (ast_test_flag(peer, IAX_DYNAMIC))
- reg_source_db(peer);
- __ao2_link(peers, peer, (MAX_PEER_BUCKETS == 1) ? 1 : 0);
- peer = peer_unref(peer);
- }
- } else if (strcasecmp(utype, "user")) {
- ast_log(LOG_WARNING, "Unknown type '%s' for '%s' in %s\n", utype, cat, config_file);
- }
- } else
- ast_log(LOG_WARNING, "Section '%s' lacks type\n", cat);
- }
- cat = ast_category_browse(cfg, cat);
- }
- ast_config_destroy(cfg);
- set_timing();
- return 1;
-}
-
-static void poke_all_peers(void)
-{
- struct ao2_iterator i;
- struct iax2_peer *peer;
-
- i = ao2_iterator_init(peers, 0);
- while ((peer = ao2_iterator_next(&i))) {
- iax2_poke_peer(peer, 0);
- peer_unref(peer);
- }
-}
-static int reload_config(void)
-{
- char *config = "iax.conf";
- struct iax2_registry *reg;
-
- if (set_config(config, 1) > 0) {
- prune_peers();
- prune_users();
- AST_LIST_LOCK(&registrations);
- AST_LIST_TRAVERSE(&registrations, reg, entry)
- iax2_do_register(reg);
- AST_LIST_UNLOCK(&registrations);
- /* Qualify hosts, too */
- poke_all_peers();
- }
- reload_firmware(0);
- iax_provision_reload();
-
- return 0;
-}
-
-static int iax2_reload(int fd, int argc, char *argv[])
-{
- return reload_config();
-}
-
-static int reload(void)
-{
- return reload_config();
-}
-
-static int cache_get_callno_locked(const char *data)
-{
- struct sockaddr_in sin;
- int x;
- int callno;
- struct iax_ie_data ied;
- struct create_addr_info cai;
- struct parsed_dial_string pds;
- char *tmpstr;
-
- for (x = 0; x < ARRAY_LEN(iaxs); x++) {
- /* Look for an *exact match* call. Once a call is negotiated, it can only
- look up entries for a single context */
- if (!ast_mutex_trylock(&iaxsl[x])) {
- if (iaxs[x] && !strcasecmp(data, iaxs[x]->dproot))
- return x;
- ast_mutex_unlock(&iaxsl[x]);
- }
- }
-
- /* No match found, we need to create a new one */
-
- memset(&cai, 0, sizeof(cai));
- memset(&ied, 0, sizeof(ied));
- memset(&pds, 0, sizeof(pds));
-
- tmpstr = ast_strdupa(data);
- parse_dial_string(tmpstr, &pds);
-
- if (ast_strlen_zero(pds.peer)) {
- ast_log(LOG_WARNING, "No peer provided in the IAX2 dial string '%s'\n", data);
- return -1;
- }
-
- /* Populate our address from the given */
- if (create_addr(pds.peer, NULL, &sin, &cai))
- return -1;
-
- if (option_debug)
- ast_log(LOG_DEBUG, "peer: %s, username: %s, password: %s, context: %s\n",
- pds.peer, pds.username, pds.password, pds.context);
-
- callno = find_callno_locked(0, 0, &sin, NEW_FORCE, cai.sockfd, 0);
- if (callno < 1) {
- ast_log(LOG_WARNING, "Unable to create call\n");
- return -1;
- }
-
- ast_string_field_set(iaxs[callno], dproot, data);
- iaxs[callno]->capability = IAX_CAPABILITY_FULLBANDWIDTH;
-
- iax_ie_append_short(&ied, IAX_IE_VERSION, IAX_PROTO_VERSION);
- iax_ie_append_str(&ied, IAX_IE_CALLED_NUMBER, "TBD");
- /* the string format is slightly different from a standard dial string,
- because the context appears in the 'exten' position
- */
- if (pds.exten)
- iax_ie_append_str(&ied, IAX_IE_CALLED_CONTEXT, pds.exten);
- if (pds.username)
- iax_ie_append_str(&ied, IAX_IE_USERNAME, pds.username);
- iax_ie_append_int(&ied, IAX_IE_FORMAT, IAX_CAPABILITY_FULLBANDWIDTH);
- iax_ie_append_int(&ied, IAX_IE_CAPABILITY, IAX_CAPABILITY_FULLBANDWIDTH);
- /* Keep password handy */
- if (pds.password)
- ast_string_field_set(iaxs[callno], secret, pds.password);
- if (pds.key)
- ast_string_field_set(iaxs[callno], outkey, pds.key);
- /* Start the call going */
- send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_NEW, 0, ied.buf, ied.pos, -1);
-
- return callno;
-}
-
-static struct iax2_dpcache *find_cache(struct ast_channel *chan, const char *data, const char *context, const char *exten, int priority)
-{
- struct iax2_dpcache *dp, *prev = NULL, *next;
- struct timeval tv;
- int x;
- int com[2];
- int timeout;
- int old=0;
- int outfd;
- int abort;
- int callno;
- struct ast_channel *c;
- struct ast_frame *f;
- gettimeofday(&tv, NULL);
- dp = dpcache;
- while(dp) {
- next = dp->next;
- /* Expire old caches */
- if (ast_tvcmp(tv, dp->expiry) > 0) {
- /* It's expired, let it disappear */
- if (prev)
- prev->next = dp->next;
- else
- dpcache = dp->next;
- if (!dp->peer && !(dp->flags & CACHE_FLAG_PENDING) && !dp->callno) {
- /* Free memory and go again */
- free(dp);
- } else {
- ast_log(LOG_WARNING, "DP still has peer field or pending or callno (flags = %d, peer = %p callno = %d)\n", dp->flags, dp->peer, dp->callno);
- }
- dp = next;
- continue;
- }
- /* We found an entry that matches us! */
- if (!strcmp(dp->peercontext, data) && !strcmp(dp->exten, exten))
- break;
- prev = dp;
- dp = next;
- }
- if (!dp) {
- /* No matching entry. Create a new one. */
- /* First, can we make a callno? */
- callno = cache_get_callno_locked(data);
- if (callno < 0) {
- ast_log(LOG_WARNING, "Unable to generate call for '%s'\n", data);
- return NULL;
- }
- if (!(dp = ast_calloc(1, sizeof(*dp)))) {
- ast_mutex_unlock(&iaxsl[callno]);
- return NULL;
- }
- ast_copy_string(dp->peercontext, data, sizeof(dp->peercontext));
- ast_copy_string(dp->exten, exten, sizeof(dp->exten));
- gettimeofday(&dp->expiry, NULL);
- dp->orig = dp->expiry;
- /* Expires in 30 mins by default */
- dp->expiry.tv_sec += iaxdefaultdpcache;
- dp->next = dpcache;
- dp->flags = CACHE_FLAG_PENDING;
- for (x=0;x<sizeof(dp->waiters) / sizeof(dp->waiters[0]); x++)
- dp->waiters[x] = -1;
- dpcache = dp;
- dp->peer = iaxs[callno]->dpentries;
- iaxs[callno]->dpentries = dp;
- /* Send the request if we're already up */
- if (ast_test_flag(&iaxs[callno]->state, IAX_STATE_STARTED))
- iax2_dprequest(dp, callno);
- ast_mutex_unlock(&iaxsl[callno]);
- }
- /* By here we must have a dp */
- if (dp->flags & CACHE_FLAG_PENDING) {
- /* Okay, here it starts to get nasty. We need a pipe now to wait
- for a reply to come back so long as it's pending */
- for (x=0;x<sizeof(dp->waiters) / sizeof(dp->waiters[0]); x++) {
- /* Find an empty slot */
- if (dp->waiters[x] < 0)
- break;
- }
- if (x >= sizeof(dp->waiters) / sizeof(dp->waiters[0])) {
- ast_log(LOG_WARNING, "No more waiter positions available\n");
- return NULL;
- }
- if (pipe(com)) {
- ast_log(LOG_WARNING, "Unable to create pipe for comm\n");
- return NULL;
- }
- dp->waiters[x] = com[1];
- /* Okay, now we wait */
- timeout = iaxdefaulttimeout * 1000;
- /* Temporarily unlock */
- ast_mutex_unlock(&dpcache_lock);
- /* Defer any dtmf */
- if (chan)
- old = ast_channel_defer_dtmf(chan);
- abort = 0;
- while(timeout) {
- c = ast_waitfor_nandfds(&chan, chan ? 1 : 0, &com[0], 1, NULL, &outfd, &timeout);
- if (outfd > -1) {
- break;
- }
- if (c) {
- f = ast_read(c);
- if (f)
- ast_frfree(f);
- else {
- /* Got hung up on, abort! */
- break;
- abort = 1;
- }
- }
- }
- if (!timeout) {
- ast_log(LOG_WARNING, "Timeout waiting for %s exten %s\n", data, exten);
- }
- ast_mutex_lock(&dpcache_lock);
- dp->waiters[x] = -1;
- close(com[1]);
- close(com[0]);
- if (abort) {
- /* Don't interpret anything, just abort. Not sure what th epoint
- of undeferring dtmf on a hung up channel is but hey whatever */
- if (!old && chan)
- ast_channel_undefer_dtmf(chan);
- return NULL;
- }
- if (!(dp->flags & CACHE_FLAG_TIMEOUT)) {
- /* Now to do non-independent analysis the results of our wait */
- if (dp->flags & CACHE_FLAG_PENDING) {
- /* Still pending... It's a timeout. Wake everybody up. Consider it no longer
- pending. Don't let it take as long to timeout. */
- dp->flags &= ~CACHE_FLAG_PENDING;
- dp->flags |= CACHE_FLAG_TIMEOUT;
- /* Expire after only 60 seconds now. This is designed to help reduce backlog in heavily loaded
- systems without leaving it unavailable once the server comes back online */
- dp->expiry.tv_sec = dp->orig.tv_sec + 60;
- for (x = 0; x < ARRAY_LEN(dp->waiters); x++) {
- if (dp->waiters[x] > -1) {
- if (write(dp->waiters[x], "asdf", 4) < 0) {
- ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
- }
- }
- }
- }
- }
- /* Our caller will obtain the rest */
- if (!old && chan)
- ast_channel_undefer_dtmf(chan);
- }
- return dp;
-}
-
-/*! \brief Part of the IAX2 switch interface */
-static int iax2_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
-{
- struct iax2_dpcache *dp;
- int res = 0;
-#if 0
- ast_log(LOG_NOTICE, "iax2_exists: con: %s, exten: %s, pri: %d, cid: %s, data: %s\n", context, exten, priority, callerid ? callerid : "<unknown>", data);
-#endif
- if ((priority != 1) && (priority != 2))
- return 0;
- ast_mutex_lock(&dpcache_lock);
- dp = find_cache(chan, data, context, exten, priority);
- if (dp) {
- if (dp->flags & CACHE_FLAG_EXISTS)
- res= 1;
- }
- ast_mutex_unlock(&dpcache_lock);
- if (!dp) {
- ast_log(LOG_WARNING, "Unable to make DP cache\n");
- }
- return res;
-}
-
-/*! \brief part of the IAX2 dial plan switch interface */
-static int iax2_canmatch(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
-{
- int res = 0;
- struct iax2_dpcache *dp;
-#if 0
- ast_log(LOG_NOTICE, "iax2_canmatch: con: %s, exten: %s, pri: %d, cid: %s, data: %s\n", context, exten, priority, callerid ? callerid : "<unknown>", data);
-#endif
- if ((priority != 1) && (priority != 2))
- return 0;
- ast_mutex_lock(&dpcache_lock);
- dp = find_cache(chan, data, context, exten, priority);
- if (dp) {
- if (dp->flags & CACHE_FLAG_CANEXIST)
- res= 1;
- }
- ast_mutex_unlock(&dpcache_lock);
- if (!dp) {
- ast_log(LOG_WARNING, "Unable to make DP cache\n");
- }
- return res;
-}
-
-/*! \brief Part of the IAX2 Switch interface */
-static int iax2_matchmore(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
-{
- int res = 0;
- struct iax2_dpcache *dp;
-#if 0
- ast_log(LOG_NOTICE, "iax2_matchmore: con: %s, exten: %s, pri: %d, cid: %s, data: %s\n", context, exten, priority, callerid ? callerid : "<unknown>", data);
-#endif
- if ((priority != 1) && (priority != 2))
- return 0;
- ast_mutex_lock(&dpcache_lock);
- dp = find_cache(chan, data, context, exten, priority);
- if (dp) {
- if (dp->flags & CACHE_FLAG_MATCHMORE)
- res= 1;
- }
- ast_mutex_unlock(&dpcache_lock);
- if (!dp) {
- ast_log(LOG_WARNING, "Unable to make DP cache\n");
- }
- return res;
-}
-
-/*! \brief Execute IAX2 dialplan switch */
-static int iax2_exec(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
-{
- char odata[256];
- char req[256];
- char *ncontext;
- struct iax2_dpcache *dp;
- struct ast_app *dial;
-#if 0
- ast_log(LOG_NOTICE, "iax2_exec: con: %s, exten: %s, pri: %d, cid: %s, data: %s, newstack: %d\n", context, exten, priority, callerid ? callerid : "<unknown>", data, newstack);
-#endif
- if (priority == 2) {
- /* Indicate status, can be overridden in dialplan */
- const char *dialstatus = pbx_builtin_getvar_helper(chan, "DIALSTATUS");
- if (dialstatus) {
- dial = pbx_findapp(dialstatus);
- if (dial)
- pbx_exec(chan, dial, "");
- }
- return -1;
- } else if (priority != 1)
- return -1;
- ast_mutex_lock(&dpcache_lock);
- dp = find_cache(chan, data, context, exten, priority);
- if (dp) {
- if (dp->flags & CACHE_FLAG_EXISTS) {
- ast_copy_string(odata, data, sizeof(odata));
- ncontext = strchr(odata, '/');
- if (ncontext) {
- *ncontext = '\0';
- ncontext++;
- snprintf(req, sizeof(req), "IAX2/%s/%s@%s", odata, exten, ncontext);
- } else {
- snprintf(req, sizeof(req), "IAX2/%s/%s", odata, exten);
- }
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Executing Dial('%s')\n", req);
- } else {
- ast_mutex_unlock(&dpcache_lock);
- ast_log(LOG_WARNING, "Can't execute nonexistent extension '%s[@%s]' in data '%s'\n", exten, context, data);
- return -1;
- }
- }
- ast_mutex_unlock(&dpcache_lock);
- dial = pbx_findapp("Dial");
- if (dial) {
- return pbx_exec(chan, dial, req);
- } else {
- ast_log(LOG_WARNING, "No dial application registered\n");
- }
- return -1;
-}
-
-static int function_iaxpeer(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
-{
- struct iax2_peer *peer;
- char *peername, *colname;
-
- peername = ast_strdupa(data);
-
- /* if our channel, return the IP address of the endpoint of current channel */
- if (!strcmp(peername,"CURRENTCHANNEL")) {
- unsigned short callno;
- if (chan->tech != &iax2_tech)
- return -1;
- callno = PTR_TO_CALLNO(chan->tech_pvt);
- ast_copy_string(buf, iaxs[callno]->addr.sin_addr.s_addr ? ast_inet_ntoa(iaxs[callno]->addr.sin_addr) : "", len);
- return 0;
- }
-
- if ((colname = strchr(peername, ':'))) /*! \todo : will be removed after the 1.4 relese */
- *colname++ = '\0';
- else if ((colname = strchr(peername, '|')))
- *colname++ = '\0';
- else
- colname = "ip";
-
- if (!(peer = find_peer(peername, 1)))
- return -1;
-
- if (!strcasecmp(colname, "ip")) {
- ast_copy_string(buf, peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "", len);
- } else if (!strcasecmp(colname, "status")) {
- peer_status(peer, buf, len);
- } else if (!strcasecmp(colname, "mailbox")) {
- ast_copy_string(buf, peer->mailbox, len);
- } else if (!strcasecmp(colname, "context")) {
- ast_copy_string(buf, peer->context, len);
- } else if (!strcasecmp(colname, "expire")) {
- snprintf(buf, len, "%d", peer->expire);
- } else if (!strcasecmp(colname, "dynamic")) {
- ast_copy_string(buf, (ast_test_flag(peer, IAX_DYNAMIC) ? "yes" : "no"), len);
- } else if (!strcasecmp(colname, "callerid_name")) {
- ast_copy_string(buf, peer->cid_name, len);
- } else if (!strcasecmp(colname, "callerid_num")) {
- ast_copy_string(buf, peer->cid_num, len);
- } else if (!strcasecmp(colname, "codecs")) {
- ast_getformatname_multiple(buf, len -1, peer->capability);
- } else if (!strncasecmp(colname, "codec[", 6)) {
- char *codecnum, *ptr;
- int index = 0, codec = 0;
-
- codecnum = strchr(colname, '[');
- *codecnum = '\0';
- codecnum++;
- if ((ptr = strchr(codecnum, ']'))) {
- *ptr = '\0';
- }
- index = atoi(codecnum);
- if((codec = ast_codec_pref_index(&peer->prefs, index))) {
- ast_copy_string(buf, ast_getformatname(codec), len);
- } else {
- buf[0] = '\0';
- }
- } else {
- buf[0] = '\0';
- }
-
- peer_unref(peer);
-
- return 0;
-}
-
-struct ast_custom_function iaxpeer_function = {
- .name = "IAXPEER",
- .synopsis = "Gets IAX peer information",
- .syntax = "IAXPEER(<peername|CURRENTCHANNEL>[|item])",
- .read = function_iaxpeer,
- .desc = "If peername specified, valid items are:\n"
- "- ip (default) The IP address.\n"
- "- status The peer's status (if qualify=yes)\n"
- "- mailbox The configured mailbox.\n"
- "- context The configured context.\n"
- "- expire The epoch time of the next expire.\n"
- "- dynamic Is it dynamic? (yes/no).\n"
- "- callerid_name The configured Caller ID name.\n"
- "- callerid_num The configured Caller ID number.\n"
- "- codecs The configured codecs.\n"
- "- codec[x] Preferred codec index number 'x' (beginning with zero).\n"
- "\n"
- "If CURRENTCHANNEL specified, returns IP address of current channel\n"
- "\n"
-};
-
-
-/*! \brief Part of the device state notification system ---*/
-static int iax2_devicestate(void *data)
-{
- struct parsed_dial_string pds;
- char *tmp = ast_strdupa(data);
- struct iax2_peer *p;
- int res = AST_DEVICE_INVALID;
-
- memset(&pds, 0, sizeof(pds));
- parse_dial_string(tmp, &pds);
-
- if (ast_strlen_zero(pds.peer)) {
- ast_log(LOG_WARNING, "No peer provided in the IAX2 dial string '%s'\n", (char *) data);
- return res;
- }
-
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Checking device state for device %s\n", pds.peer);
-
- /* SLD: FIXME: second call to find_peer during registration */
- if (!(p = find_peer(pds.peer, 1)))
- return res;
-
- res = AST_DEVICE_UNAVAILABLE;
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "iax2_devicestate: Found peer. What's device state of %s? addr=%d, defaddr=%d maxms=%d, lastms=%d\n",
- pds.peer, p->addr.sin_addr.s_addr, p->defaddr.sin_addr.s_addr, p->maxms, p->lastms);
-
- if ((p->addr.sin_addr.s_addr || p->defaddr.sin_addr.s_addr) &&
- (!p->maxms || ((p->lastms > -1) && (p->historicms <= p->maxms)))) {
- /* Peer is registered, or have default IP address
- and a valid registration */
- if (p->historicms == 0 || p->historicms <= p->maxms)
- /* let the core figure out whether it is in use or not */
- res = AST_DEVICE_UNKNOWN;
- }
-
- peer_unref(p);
-
- return res;
-}
-
-static struct ast_switch iax2_switch =
-{
- name: "IAX2",
- description: "IAX Remote Dialplan Switch",
- exists: iax2_exists,
- canmatch: iax2_canmatch,
- exec: iax2_exec,
- matchmore: iax2_matchmore,
-};
-
-static char show_stats_usage[] =
-"Usage: iax2 show stats\n"
-" Display statistics on IAX channel driver.\n";
-
-static char show_cache_usage[] =
-"Usage: iax2 show cache\n"
-" Display currently cached IAX Dialplan results.\n";
-
-static char show_peer_usage[] =
-"Usage: iax2 show peer <name>\n"
-" Display details on specific IAX peer\n";
-
-static char prune_realtime_usage[] =
-"Usage: iax2 prune realtime [<peername>|all]\n"
-" Prunes object(s) from the cache\n";
-
-static char iax2_reload_usage[] =
-"Usage: iax2 reload\n"
-" Reloads IAX configuration from iax.conf\n";
-
-static char show_prov_usage[] =
-"Usage: iax2 provision <host> <template> [forced]\n"
-" Provisions the given peer or IP address using a template\n"
-" matching either 'template' or '*' if the template is not\n"
-" found. If 'forced' is specified, even empty provisioning\n"
-" fields will be provisioned as empty fields.\n";
-
-static char show_users_usage[] =
-"Usage: iax2 show users [like <pattern>]\n"
-" Lists all known IAX2 users.\n"
-" Optional regular expression pattern is used to filter the user list.\n";
-
-static char show_channels_usage[] =
-"Usage: iax2 show channels\n"
-" Lists all currently active IAX channels.\n";
-
-static char show_netstats_usage[] =
-"Usage: iax2 show netstats\n"
-" Lists network status for all currently active IAX channels.\n";
-
-static char show_threads_usage[] =
-"Usage: iax2 show threads\n"
-" Lists status of IAX helper threads\n";
-
-static char show_peers_usage[] =
-"Usage: iax2 show peers [registered] [like <pattern>]\n"
-" Lists all known IAX2 peers.\n"
-" Optional 'registered' argument lists only peers with known addresses.\n"
-" Optional regular expression pattern is used to filter the peer list.\n";
-
-static char show_firmware_usage[] =
-"Usage: iax2 show firmware\n"
-" Lists all known IAX firmware images.\n";
-
-static char show_reg_usage[] =
-"Usage: iax2 show registry\n"
-" Lists all registration requests and status.\n";
-
-static char debug_usage[] =
-"Usage: iax2 set debug\n"
-" Enables dumping of IAX packets for debugging purposes\n";
-
-static char no_debug_usage[] =
-"Usage: iax2 set debug off\n"
-" Disables dumping of IAX packets for debugging purposes\n";
-
-static char debug_trunk_usage[] =
-"Usage: iax2 set debug trunk\n"
-" Requests current status of IAX trunking\n";
-
-static char no_debug_trunk_usage[] =
-"Usage: iax2 set debug trunk off\n"
-" Requests current status of IAX trunking\n";
-
-static char debug_jb_usage[] =
-"Usage: iax2 set debug jb\n"
-" Enables jitterbuffer debugging information\n";
-
-static char no_debug_jb_usage[] =
-"Usage: iax2 set debug jb off\n"
-" Disables jitterbuffer debugging information\n";
-
-static char iax2_test_losspct_usage[] =
-"Usage: iax2 test losspct <percentage>\n"
-" For testing, throws away <percentage> percent of incoming packets\n";
-
-#ifdef IAXTESTS
-static char iax2_test_late_usage[] =
-"Usage: iax2 test late <ms>\n"
-" For testing, count the next frame as <ms> ms late\n";
-
-static char iax2_test_resync_usage[] =
-"Usage: iax2 test resync <ms>\n"
-" For testing, adjust all future frames by <ms> ms\n";
-
-static char iax2_test_jitter_usage[] =
-"Usage: iax2 test jitter <ms> <pct>\n"
-" For testing, simulate maximum jitter of +/- <ms> on <pct> percentage of packets. If <pct> is not specified, adds jitter to all packets.\n";
-#endif /* IAXTESTS */
-
-static struct ast_cli_entry cli_iax2_trunk_debug_deprecated = {
- { "iax2", "trunk", "debug", NULL },
- iax2_do_trunk_debug, NULL,
- NULL };
-
-static struct ast_cli_entry cli_iax2_jb_debug_deprecated = {
- { "iax2", "jb", "debug", NULL },
- iax2_do_jb_debug, NULL,
- NULL };
-
-static struct ast_cli_entry cli_iax2_no_debug_deprecated = {
- { "iax2", "no", "debug", NULL },
- iax2_no_debug, NULL,
- NULL };
-
-static struct ast_cli_entry cli_iax2_no_trunk_debug_deprecated = {
- { "iax2", "no", "trunk", "debug", NULL },
- iax2_no_trunk_debug, NULL,
- NULL };
-
-static struct ast_cli_entry cli_iax2_no_jb_debug_deprecated = {
- { "iax2", "no", "jb", "debug", NULL },
- iax2_no_jb_debug, NULL,
- NULL };
-
-static struct ast_cli_entry cli_iax2[] = {
- { { "iax2", "show", "cache", NULL },
- iax2_show_cache, "Display IAX cached dialplan",
- show_cache_usage, NULL, },
-
- { { "iax2", "show", "channels", NULL },
- iax2_show_channels, "List active IAX channels",
- show_channels_usage, NULL, },
-
- { { "iax2", "show", "firmware", NULL },
- iax2_show_firmware, "List available IAX firmwares",
- show_firmware_usage, NULL, },
-
- { { "iax2", "show", "netstats", NULL },
- iax2_show_netstats, "List active IAX channel netstats",
- show_netstats_usage, NULL, },
-
- { { "iax2", "show", "peers", NULL },
- iax2_show_peers, "List defined IAX peers",
- show_peers_usage, NULL, },
-
- { { "iax2", "show", "registry", NULL },
- iax2_show_registry, "Display IAX registration status",
- show_reg_usage, NULL, },
-
- { { "iax2", "show", "stats", NULL },
- iax2_show_stats, "Display IAX statistics",
- show_stats_usage, NULL, },
-
- { { "iax2", "show", "threads", NULL },
- iax2_show_threads, "Display IAX helper thread info",
- show_threads_usage, NULL, },
-
- { { "iax2", "show", "users", NULL },
- iax2_show_users, "List defined IAX users",
- show_users_usage, NULL, },
-
- { { "iax2", "prune", "realtime", NULL },
- iax2_prune_realtime, "Prune a cached realtime lookup",
- prune_realtime_usage, complete_iax2_show_peer },
-
- { { "iax2", "reload", NULL },
- iax2_reload, "Reload IAX configuration",
- iax2_reload_usage },
-
- { { "iax2", "show", "peer", NULL },
- iax2_show_peer, "Show details on specific IAX peer",
- show_peer_usage, complete_iax2_show_peer },
-
- { { "iax2", "set", "debug", NULL },
- iax2_do_debug, "Enable IAX debugging",
- debug_usage },
-
- { { "iax2", "set", "debug", "trunk", NULL },
- iax2_do_trunk_debug, "Enable IAX trunk debugging",
- debug_trunk_usage, NULL, &cli_iax2_trunk_debug_deprecated },
-
- { { "iax2", "set", "debug", "jb", NULL },
- iax2_do_jb_debug, "Enable IAX jitterbuffer debugging",
- debug_jb_usage, NULL, &cli_iax2_jb_debug_deprecated },
-
- { { "iax2", "set", "debug", "off", NULL },
- iax2_no_debug, "Disable IAX debugging",
- no_debug_usage, NULL, &cli_iax2_no_debug_deprecated },
-
- { { "iax2", "set", "debug", "trunk", "off", NULL },
- iax2_no_trunk_debug, "Disable IAX trunk debugging",
- no_debug_trunk_usage, NULL, &cli_iax2_no_trunk_debug_deprecated },
-
- { { "iax2", "set", "debug", "jb", "off", NULL },
- iax2_no_jb_debug, "Disable IAX jitterbuffer debugging",
- no_debug_jb_usage, NULL, &cli_iax2_no_jb_debug_deprecated },
-
- { { "iax2", "test", "losspct", NULL },
- iax2_test_losspct, "Set IAX2 incoming frame loss percentage",
- iax2_test_losspct_usage },
-
- { { "iax2", "provision", NULL },
- iax2_prov_cmd, "Provision an IAX device",
- show_prov_usage, iax2_prov_complete_template_3rd },
-
-#ifdef IAXTESTS
- { { "iax2", "test", "late", NULL },
- iax2_test_late, "Test the receipt of a late frame",
- iax2_test_late_usage },
-
- { { "iax2", "test", "resync", NULL },
- iax2_test_resync, "Test a resync in received timestamps",
- iax2_test_resync_usage },
-
- { { "iax2", "test", "jitter", NULL },
- iax2_test_jitter, "Simulates jitter for testing",
- iax2_test_jitter_usage },
-#endif /* IAXTESTS */
-};
-
-static int __unload_module(void)
-{
- struct iax2_thread *thread = NULL;
- int x;
-
- /* Make sure threads do not hold shared resources when they are canceled */
-
- /* Grab the sched lock resource to keep it away from threads about to die */
- /* Cancel the network thread, close the net socket */
- if (netthreadid != AST_PTHREADT_NULL) {
- AST_LIST_LOCK(&iaxq.queue);
- ast_mutex_lock(&sched_lock);
- pthread_cancel(netthreadid);
- ast_cond_signal(&sched_cond);
- ast_mutex_unlock(&sched_lock); /* Release the schedule lock resource */
- AST_LIST_UNLOCK(&iaxq.queue);
- pthread_join(netthreadid, NULL);
- }
- if (schedthreadid != AST_PTHREADT_NULL) {
- ast_mutex_lock(&sched_lock);
- pthread_cancel(schedthreadid);
- ast_cond_signal(&sched_cond);
- ast_mutex_unlock(&sched_lock);
- pthread_join(schedthreadid, NULL);
- }
-
- /* Call for all threads to halt */
- AST_LIST_LOCK(&idle_list);
- AST_LIST_TRAVERSE_SAFE_BEGIN(&idle_list, thread, list) {
- AST_LIST_REMOVE_CURRENT(&idle_list, list);
- pthread_cancel(thread->threadid);
- }
- AST_LIST_TRAVERSE_SAFE_END
- AST_LIST_UNLOCK(&idle_list);
-
- AST_LIST_LOCK(&active_list);
- AST_LIST_TRAVERSE_SAFE_BEGIN(&active_list, thread, list) {
- AST_LIST_REMOVE_CURRENT(&active_list, list);
- pthread_cancel(thread->threadid);
- }
- AST_LIST_TRAVERSE_SAFE_END
- AST_LIST_UNLOCK(&active_list);
-
- AST_LIST_LOCK(&dynamic_list);
- AST_LIST_TRAVERSE_SAFE_BEGIN(&dynamic_list, thread, list) {
- AST_LIST_REMOVE_CURRENT(&dynamic_list, list);
- pthread_cancel(thread->threadid);
- }
- AST_LIST_TRAVERSE_SAFE_END
- AST_LIST_UNLOCK(&dynamic_list);
-
- AST_LIST_HEAD_DESTROY(&iaxq.queue);
-
- /* Wait for threads to exit */
- while(0 < iaxactivethreadcount)
- usleep(10000);
-
- ast_netsock_release(netsock);
- ast_netsock_release(outsock);
- for (x = 0; x < ARRAY_LEN(iaxs); x++) {
- if (iaxs[x]) {
- iax2_destroy(x);
- }
- }
- ast_manager_unregister( "IAXpeers" );
- ast_manager_unregister( "IAXnetstats" );
- ast_unregister_application(papp);
- ast_cli_unregister_multiple(cli_iax2, sizeof(cli_iax2) / sizeof(struct ast_cli_entry));
- ast_unregister_switch(&iax2_switch);
- ast_channel_unregister(&iax2_tech);
- delete_users();
- iax_provision_unload();
- sched_context_destroy(sched);
- reload_firmware(1);
-
- ast_mutex_destroy(&waresl.lock);
-
- for (x = 0; x < ARRAY_LEN(iaxsl); x++) {
- ast_mutex_destroy(&iaxsl[x]);
- }
-
- ao2_ref(peers, -1);
- ao2_ref(users, -1);
- ao2_ref(iax_peercallno_pvts, -1);
-
- return 0;
-}
-
-static int unload_module(void)
-{
- ast_custom_function_unregister(&iaxpeer_function);
- return __unload_module();
-}
-
-static int peer_set_sock_cb(void *obj, void *arg, int flags)
-{
- struct iax2_peer *peer = obj;
-
- if (peer->sockfd < 0)
- peer->sockfd = defaultsockfd;
-
- return 0;
-}
-
-static int pvt_hash_cb(const void *obj, const int flags)
-{
- const struct chan_iax2_pvt *pvt = obj;
-
- return pvt->peercallno;
-}
-
-static int pvt_cmp_cb(void *obj, void *arg, int flags)
-{
- struct chan_iax2_pvt *pvt = obj, *pvt2 = arg;
-
- /* The frames_received field is used to hold whether we're matching
- * against a full frame or not ... */
-
- return match(&pvt2->addr, pvt2->peercallno, pvt2->callno, pvt,
- pvt2->frames_received) ? CMP_MATCH | CMP_STOP : 0;
-}
-
-/*! \brief Load IAX2 module, load configuraiton ---*/
-static int load_module(void)
-{
- char *config = "iax.conf";
- int res = 0;
- int x;
- struct iax2_registry *reg = NULL;
-
- peers = ao2_container_alloc(MAX_PEER_BUCKETS, peer_hash_cb, peer_cmp_cb);
- if (!peers)
- return AST_MODULE_LOAD_FAILURE;
- users = ao2_container_alloc(MAX_USER_BUCKETS, user_hash_cb, user_cmp_cb);
- if (!users) {
- ao2_ref(peers, -1);
- return AST_MODULE_LOAD_FAILURE;
- }
- iax_peercallno_pvts = ao2_container_alloc(IAX_MAX_CALLS, pvt_hash_cb, pvt_cmp_cb);
- if (!iax_peercallno_pvts) {
- ao2_ref(peers, -1);
- ao2_ref(users, -1);
- return AST_MODULE_LOAD_FAILURE;
- }
-
- ast_custom_function_register(&iaxpeer_function);
-
- iax_set_output(iax_debug_output);
- iax_set_error(iax_error_output);
- jb_setoutput(jb_error_output, jb_warning_output, NULL);
-
-#ifdef HAVE_DAHDI
-#ifdef DAHDI_TIMERACK
- timingfd = open(DAHDI_FILE_TIMER, O_RDWR);
- if (timingfd < 0)
-#endif
- timingfd = open(DAHDI_FILE_PSEUDO, O_RDWR);
- if (timingfd < 0)
- ast_log(LOG_WARNING, "Unable to open IAX timing interface: %s\n", strerror(errno));
-#endif
-
- memset(iaxs, 0, sizeof(iaxs));
-
- for (x = 0; x < ARRAY_LEN(iaxsl); x++) {
- ast_mutex_init(&iaxsl[x]);
- }
-
- ast_cond_init(&sched_cond, NULL);
-
- io = io_context_create();
- sched = sched_context_create();
-
- if (!io || !sched) {
- ast_log(LOG_ERROR, "Out of memory\n");
- return -1;
- }
-
- netsock = ast_netsock_list_alloc();
- if (!netsock) {
- ast_log(LOG_ERROR, "Could not allocate netsock list.\n");
- return -1;
- }
- ast_netsock_init(netsock);
-
- outsock = ast_netsock_list_alloc();
- if (!outsock) {
- ast_log(LOG_ERROR, "Could not allocate outsock list.\n");
- return -1;
- }
- ast_netsock_init(outsock);
-
- ast_mutex_init(&waresl.lock);
-
- AST_LIST_HEAD_INIT(&iaxq.queue);
-
- ast_cli_register_multiple(cli_iax2, sizeof(cli_iax2) / sizeof(struct ast_cli_entry));
-
- ast_register_application(papp, iax2_prov_app, psyn, pdescrip);
-
- ast_manager_register( "IAXpeers", 0, manager_iax2_show_peers, "List IAX Peers" );
- ast_manager_register( "IAXnetstats", 0, manager_iax2_show_netstats, "Show IAX Netstats" );
-
- if(set_config(config, 0) == -1)
- return AST_MODULE_LOAD_DECLINE;
-
- if (ast_channel_register(&iax2_tech)) {
- ast_log(LOG_ERROR, "Unable to register channel class %s\n", "IAX2");
- __unload_module();
- return -1;
- }
-
- if (ast_register_switch(&iax2_switch))
- ast_log(LOG_ERROR, "Unable to register IAX switch\n");
-
- res = start_network_thread();
- if (!res) {
- if (option_verbose > 1)
- ast_verbose(VERBOSE_PREFIX_2 "IAX Ready and Listening\n");
- } else {
- ast_log(LOG_ERROR, "Unable to start network thread\n");
- ast_netsock_release(netsock);
- ast_netsock_release(outsock);
- }
-
- AST_LIST_LOCK(&registrations);
- AST_LIST_TRAVERSE(&registrations, reg, entry)
- iax2_do_register(reg);
- AST_LIST_UNLOCK(&registrations);
-
- ao2_callback(peers, 0, peer_set_sock_cb, NULL);
- ao2_callback(peers, 0, iax2_poke_peer_cb, NULL);
-
- reload_firmware(0);
- iax_provision_reload();
- return res;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Inter Asterisk eXchange (Ver 2)",
- .load = load_module,
- .unload = unload_module,
- .reload = reload,
- );
diff --git a/1.4.23-rc4/channels/chan_local.c b/1.4.23-rc4/channels/chan_local.c
deleted file mode 100644
index b2e3c72b8..000000000
--- a/1.4.23-rc4/channels/chan_local.c
+++ /dev/null
@@ -1,808 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 1999 - 2005, Digium, Inc.
- *
- * Mark Spencer <markster@digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \author Mark Spencer <markster@digium.com>
- *
- * \brief Local Proxy Channel
- *
- * \ingroup channel_drivers
- */
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/socket.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <sys/signal.h>
-
-#include "asterisk/lock.h"
-#include "asterisk/channel.h"
-#include "asterisk/config.h"
-#include "asterisk/logger.h"
-#include "asterisk/module.h"
-#include "asterisk/pbx.h"
-#include "asterisk/options.h"
-#include "asterisk/lock.h"
-#include "asterisk/sched.h"
-#include "asterisk/io.h"
-#include "asterisk/rtp.h"
-#include "asterisk/acl.h"
-#include "asterisk/callerid.h"
-#include "asterisk/file.h"
-#include "asterisk/cli.h"
-#include "asterisk/app.h"
-#include "asterisk/musiconhold.h"
-#include "asterisk/manager.h"
-#include "asterisk/stringfields.h"
-#include "asterisk/devicestate.h"
-
-static const char tdesc[] = "Local Proxy Channel Driver";
-
-#define IS_OUTBOUND(a,b) (a == b->chan ? 1 : 0)
-
-static struct ast_channel *local_request(const char *type, int format, void *data, int *cause);
-static int local_digit_begin(struct ast_channel *ast, char digit);
-static int local_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
-static int local_call(struct ast_channel *ast, char *dest, int timeout);
-static int local_hangup(struct ast_channel *ast);
-static int local_answer(struct ast_channel *ast);
-static struct ast_frame *local_read(struct ast_channel *ast);
-static int local_write(struct ast_channel *ast, struct ast_frame *f);
-static int local_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
-static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
-static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);
-static int local_sendtext(struct ast_channel *ast, const char *text);
-static int local_devicestate(void *data);
-
-/* PBX interface structure for channel registration */
-static const struct ast_channel_tech local_tech = {
- .type = "Local",
- .description = tdesc,
- .capabilities = -1,
- .requester = local_request,
- .send_digit_begin = local_digit_begin,
- .send_digit_end = local_digit_end,
- .call = local_call,
- .hangup = local_hangup,
- .answer = local_answer,
- .read = local_read,
- .write = local_write,
- .write_video = local_write,
- .exception = local_read,
- .indicate = local_indicate,
- .fixup = local_fixup,
- .send_html = local_sendhtml,
- .send_text = local_sendtext,
- .devicestate = local_devicestate,
-};
-
-struct local_pvt {
- ast_mutex_t lock; /* Channel private lock */
- unsigned int flags; /* Private flags */
- char context[AST_MAX_CONTEXT]; /* Context to call */
- char exten[AST_MAX_EXTENSION]; /* Extension to call */
- int reqformat; /* Requested format */
- struct ast_channel *owner; /* Master Channel */
- struct ast_channel *chan; /* Outbound channel */
- struct ast_module_user *u_owner; /*! reference to keep the module loaded while in use */
- struct ast_module_user *u_chan; /*! reference to keep the module loaded while in use */
- AST_LIST_ENTRY(local_pvt) list; /* Next entity */
-};
-
-#define LOCAL_GLARE_DETECT (1 << 0) /*!< Detect glare on hangup */
-#define LOCAL_CANCEL_QUEUE (1 << 1) /*!< Cancel queue */
-#define LOCAL_ALREADY_MASQED (1 << 2) /*!< Already masqueraded */
-#define LOCAL_LAUNCHED_PBX (1 << 3) /*!< PBX was launched */
-#define LOCAL_NO_OPTIMIZATION (1 << 4) /*!< Do not optimize using masquerading */
-
-static AST_LIST_HEAD_STATIC(locals, local_pvt);
-
-/*! \brief Adds devicestate to local channels */
-static int local_devicestate(void *data)
-{
- char *exten = ast_strdupa(data);
- char *context = NULL, *opts = NULL;
- int res;
-
- if (!(context = strchr(exten, '@'))) {
- ast_log(LOG_WARNING, "Someone used Local/%s somewhere without a @context. This is bad.\n", exten);
- return AST_DEVICE_INVALID;
- }
-
- *context++ = '\0';
-
- /* Strip options if they exist */
- if ((opts = strchr(context, '/')))
- *opts = '\0';
-
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Checking if extension %s@%s exists (devicestate)\n", exten, context);
- res = ast_exists_extension(NULL, context, exten, 1, NULL);
- if (!res)
- return AST_DEVICE_INVALID;
- else
- return AST_DEVICE_UNKNOWN;
-}
-
-/*!
- * \note Assumes the pvt is no longer in the pvts list
- */
-static struct local_pvt *local_pvt_destroy(struct local_pvt *pvt)
-{
- ast_mutex_destroy(&pvt->lock);
- free(pvt);
- return NULL;
-}
-
-static int local_queue_frame(struct local_pvt *p, int isoutbound, struct ast_frame *f,
- struct ast_channel *us, int us_locked)
-{
- struct ast_channel *other = NULL;
-
- /* Recalculate outbound channel */
- other = isoutbound ? p->owner : p->chan;
-
- /* do not queue frame if generator is on both local channels */
- if (us && us->generator && other->generator)
- return 0;
-
- /* Set glare detection */
- ast_set_flag(p, LOCAL_GLARE_DETECT);
- if (ast_test_flag(p, LOCAL_CANCEL_QUEUE)) {
- /* We had a glare on the hangup. Forget all this business,
- return and destroy p. */
- ast_mutex_unlock(&p->lock);
- p = local_pvt_destroy(p);
- return -1;
- }
- if (!other) {
- ast_clear_flag(p, LOCAL_GLARE_DETECT);
- return 0;
- }
-
- /* Ensure that we have both channels locked */
- while (other && ast_channel_trylock(other)) {
- ast_mutex_unlock(&p->lock);
- if (us && us_locked) {
- do {
- ast_channel_unlock(us);
- usleep(1);
- ast_channel_lock(us);
- } while (ast_mutex_trylock(&p->lock));
- } else {
- usleep(1);
- ast_mutex_lock(&p->lock);
- }
- other = isoutbound ? p->owner : p->chan;
- }
-
- if (other) {
- ast_queue_frame(other, f);
- ast_channel_unlock(other);
- }
-
- ast_clear_flag(p, LOCAL_GLARE_DETECT);
-
- return 0;
-}
-
-static int local_answer(struct ast_channel *ast)
-{
- struct local_pvt *p = ast->tech_pvt;
- int isoutbound;
- int res = -1;
-
- if (!p)
- return -1;
-
- ast_mutex_lock(&p->lock);
- isoutbound = IS_OUTBOUND(ast, p);
- if (isoutbound) {
- /* Pass along answer since somebody answered us */
- struct ast_frame answer = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
- res = local_queue_frame(p, isoutbound, &answer, ast, 1);
- } else
- ast_log(LOG_WARNING, "Huh? Local is being asked to answer?\n");
- if (!res)
- ast_mutex_unlock(&p->lock);
- return res;
-}
-
-static void check_bridge(struct local_pvt *p, int isoutbound)
-{
- struct ast_channel_monitor *tmp;
- if (ast_test_flag(p, LOCAL_ALREADY_MASQED) || ast_test_flag(p, LOCAL_NO_OPTIMIZATION) || !p->chan || !p->owner || (p->chan->_bridge != ast_bridged_channel(p->chan)))
- return;
-
- /* only do the masquerade if we are being called on the outbound channel,
- if it has been bridged to another channel and if there are no pending
- frames on the owner channel (because they would be transferred to the
- outbound channel during the masquerade)
- */
- if (isoutbound && p->chan->_bridge /* Not ast_bridged_channel! Only go one step! */ && AST_LIST_EMPTY(&p->owner->readq)) {
- /* Masquerade bridged channel into owner */
- /* Lock everything we need, one by one, and give up if
- we can't get everything. Remember, we'll get another
- chance in just a little bit */
- if (!ast_mutex_trylock(&(p->chan->_bridge)->lock)) {
- if (!p->chan->_bridge->_softhangup) {
- if (!ast_mutex_trylock(&p->owner->lock)) {
- if (!p->owner->_softhangup) {
- if (p->owner->monitor && !p->chan->_bridge->monitor) {
- /* If a local channel is being monitored, we don't want a masquerade
- * to cause the monitor to go away. Since the masquerade swaps the monitors,
- * pre-swapping the monitors before the masquerade will ensure that the monitor
- * ends up where it is expected.
- */
- tmp = p->owner->monitor;
- p->owner->monitor = p->chan->_bridge->monitor;
- p->chan->_bridge->monitor = tmp;
- }
- if (p->chan->audiohooks) {
- struct ast_audiohook_list *audiohooks_swapper;
- audiohooks_swapper = p->chan->audiohooks;
- p->chan->audiohooks = p->owner->audiohooks;
- p->owner->audiohooks = audiohooks_swapper;
- }
- ast_channel_masquerade(p->owner, p->chan->_bridge);
- ast_set_flag(p, LOCAL_ALREADY_MASQED);
- }
- ast_mutex_unlock(&p->owner->lock);
- }
- ast_mutex_unlock(&(p->chan->_bridge)->lock);
- }
- }
- /* We only allow masquerading in one 'direction'... it's important to preserve the state
- (group variables, etc.) that live on p->chan->_bridge (and were put there by the dialplan)
- when the local channels go away.
- */
-#if 0
- } else if (!isoutbound && p->owner && p->owner->_bridge && p->chan && AST_LIST_EMPTY(&p->chan->readq)) {
- /* Masquerade bridged channel into chan */
- if (!ast_mutex_trylock(&(p->owner->_bridge)->lock)) {
- if (!p->owner->_bridge->_softhangup) {
- if (!ast_mutex_trylock(&p->chan->lock)) {
- if (!p->chan->_softhangup) {
- ast_channel_masquerade(p->chan, p->owner->_bridge);
- ast_set_flag(p, LOCAL_ALREADY_MASQED);
- }
- ast_mutex_unlock(&p->chan->lock);
- }
- }
- ast_mutex_unlock(&(p->owner->_bridge)->lock);
- }
-#endif
- }
-}
-
-static struct ast_frame *local_read(struct ast_channel *ast)
-{
- return &ast_null_frame;
-}
-
-static int local_write(struct ast_channel *ast, struct ast_frame *f)
-{
- struct local_pvt *p = ast->tech_pvt;
- int res = -1;
- int isoutbound;
-
- if (!p)
- return -1;
-
- /* Just queue for delivery to the other side */
- ast_mutex_lock(&p->lock);
- isoutbound = IS_OUTBOUND(ast, p);
- if (f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO))
- check_bridge(p, isoutbound);
- if (!ast_test_flag(p, LOCAL_ALREADY_MASQED))
- res = local_queue_frame(p, isoutbound, f, ast, 1);
- else {
- if (option_debug)
- ast_log(LOG_DEBUG, "Not posting to queue since already masked on '%s'\n", ast->name);
- res = 0;
- }
- if (!res)
- ast_mutex_unlock(&p->lock);
- return res;
-}
-
-static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
-{
- struct local_pvt *p = newchan->tech_pvt;
-
- if (!p)
- return -1;
-
- ast_mutex_lock(&p->lock);
-
- if ((p->owner != oldchan) && (p->chan != oldchan)) {
- ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan);
- ast_mutex_unlock(&p->lock);
- return -1;
- }
- if (p->owner == oldchan)
- p->owner = newchan;
- else
- p->chan = newchan;
- ast_mutex_unlock(&p->lock);
- return 0;
-}
-
-static int local_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
-{
- struct local_pvt *p = ast->tech_pvt;
- int res = 0;
- struct ast_frame f = { AST_FRAME_CONTROL, };
- int isoutbound;
-
- if (!p)
- return -1;
-
- /* If this is an MOH hold or unhold, do it on the Local channel versus real channel */
- if (condition == AST_CONTROL_HOLD) {
- ast_moh_start(ast, data, NULL);
- } else if (condition == AST_CONTROL_UNHOLD) {
- ast_moh_stop(ast);
- } else {
- /* Queue up a frame representing the indication as a control frame */
- ast_mutex_lock(&p->lock);
- isoutbound = IS_OUTBOUND(ast, p);
- f.subclass = condition;
- f.data = (void*)data;
- f.datalen = datalen;
- if (!(res = local_queue_frame(p, isoutbound, &f, ast, 1)))
- ast_mutex_unlock(&p->lock);
- }
-
- return res;
-}
-
-static int local_digit_begin(struct ast_channel *ast, char digit)
-{
- struct local_pvt *p = ast->tech_pvt;
- int res = -1;
- struct ast_frame f = { AST_FRAME_DTMF_BEGIN, };
- int isoutbound;
-
- if (!p)
- return -1;
-
- ast_mutex_lock(&p->lock);
- isoutbound = IS_OUTBOUND(ast, p);
- f.subclass = digit;
- if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
- ast_mutex_unlock(&p->lock);
-
- return res;
-}
-
-static int local_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
-{
- struct local_pvt *p = ast->tech_pvt;
- int res = -1;
- struct ast_frame f = { AST_FRAME_DTMF_END, };
- int isoutbound;
-
- if (!p)
- return -1;
-
- ast_mutex_lock(&p->lock);
- isoutbound = IS_OUTBOUND(ast, p);
- f.subclass = digit;
- f.len = duration;
- if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
- ast_mutex_unlock(&p->lock);
-
- return res;
-}
-
-static int local_sendtext(struct ast_channel *ast, const char *text)
-{
- struct local_pvt *p = ast->tech_pvt;
- int res = -1;
- struct ast_frame f = { AST_FRAME_TEXT, };
- int isoutbound;
-
- if (!p)
- return -1;
-
- ast_mutex_lock(&p->lock);
- isoutbound = IS_OUTBOUND(ast, p);
- f.data = (char *) text;
- f.datalen = strlen(text) + 1;
- if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
- ast_mutex_unlock(&p->lock);
- return res;
-}
-
-static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
-{
- struct local_pvt *p = ast->tech_pvt;
- int res = -1;
- struct ast_frame f = { AST_FRAME_HTML, };
- int isoutbound;
-
- if (!p)
- return -1;
-
- ast_mutex_lock(&p->lock);
- isoutbound = IS_OUTBOUND(ast, p);
- f.subclass = subclass;
- f.data = (char *)data;
- f.datalen = datalen;
- if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
- ast_mutex_unlock(&p->lock);
- return res;
-}
-
-/*! \brief Initiate new call, part of PBX interface
- * dest is the dial string */
-static int local_call(struct ast_channel *ast, char *dest, int timeout)
-{
- struct local_pvt *p = ast->tech_pvt;
- int res;
- struct ast_var_t *varptr = NULL, *new;
- size_t len, namelen;
-
- if (!p)
- return -1;
-
- ast_mutex_lock(&p->lock);
-
- /*
- * Note that cid_num and cid_name aren't passed in the ast_channel_alloc
- * call, so it's done here instead.
- */
- p->chan->cid.cid_dnid = ast_strdup(p->owner->cid.cid_dnid);
- p->chan->cid.cid_num = ast_strdup(p->owner->cid.cid_num);
- p->chan->cid.cid_name = ast_strdup(p->owner->cid.cid_name);
- p->chan->cid.cid_rdnis = ast_strdup(p->owner->cid.cid_rdnis);
- p->chan->cid.cid_ani = ast_strdup(p->owner->cid.cid_ani);
- p->chan->cid.cid_pres = p->owner->cid.cid_pres;
- p->chan->cid.cid_ani2 = p->owner->cid.cid_ani2;
- p->chan->cid.cid_ton = p->owner->cid.cid_ton;
- p->chan->cid.cid_tns = p->owner->cid.cid_tns;
- ast_string_field_set(p->chan, language, p->owner->language);
- ast_string_field_set(p->chan, accountcode, p->owner->accountcode);
- ast_string_field_set(p->chan, musicclass, p->owner->musicclass);
- ast_cdr_update(p->chan);
- p->chan->cdrflags = p->owner->cdrflags;
-
- if (!ast_exists_extension(NULL, p->chan->context, p->chan->exten, 1, p->owner->cid.cid_num)) {
- ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n", p->chan->exten, p->chan->context);
- ast_mutex_unlock(&p->lock);
- return -1;
- }
-
- /* copy the channel variables from the incoming channel to the outgoing channel */
- /* Note that due to certain assumptions, they MUST be in the same order */
- AST_LIST_TRAVERSE(&p->owner->varshead, varptr, entries) {
- namelen = strlen(varptr->name);
- len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2;
- if ((new = ast_calloc(1, len))) {
- memcpy(new, varptr, len);
- new->value = &(new->name[0]) + namelen + 1;
- AST_LIST_INSERT_TAIL(&p->chan->varshead, new, entries);
- }
- }
- ast_channel_datastore_inherit(p->owner, p->chan);
-
- /* Start switch on sub channel */
- if (!(res = ast_pbx_start(p->chan)))
- ast_set_flag(p, LOCAL_LAUNCHED_PBX);
-
- ast_mutex_unlock(&p->lock);
- return res;
-}
-
-/*! \brief Hangup a call through the local proxy channel */
-static int local_hangup(struct ast_channel *ast)
-{
- struct local_pvt *p = ast->tech_pvt;
- int isoutbound;
- struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_HANGUP };
- struct ast_channel *ochan = NULL;
- int glaredetect = 0, res = 0;
-
- if (!p)
- return -1;
-
- while (ast_mutex_trylock(&p->lock)) {
- ast_channel_unlock(ast);
- usleep(1);
- ast_channel_lock(ast);
- }
-
- isoutbound = IS_OUTBOUND(ast, p);
- if (isoutbound) {
- const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS");
- if ((status) && (p->owner)) {
- /* Deadlock avoidance */
- while (p->owner && ast_channel_trylock(p->owner)) {
- ast_mutex_unlock(&p->lock);
- if (ast) {
- ast_channel_unlock(ast);
- }
- usleep(1);
- if (ast) {
- ast_channel_lock(ast);
- }
- ast_mutex_lock(&p->lock);
- }
- if (p->owner) {
- pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status);
- ast_channel_unlock(p->owner);
- }
- }
- p->chan = NULL;
- ast_clear_flag(p, LOCAL_LAUNCHED_PBX);
- ast_module_user_remove(p->u_chan);
- } else {
- p->owner = NULL;
- ast_module_user_remove(p->u_owner);
- while (p->chan && ast_channel_trylock(p->chan)) {
- DEADLOCK_AVOIDANCE(&p->lock);
- }
- if (p->chan) {
- ast_queue_hangup(p->chan);
- ast_channel_unlock(p->chan);
- }
- }
-
- ast->tech_pvt = NULL;
-
- if (!p->owner && !p->chan) {
- /* Okay, done with the private part now, too. */
- glaredetect = ast_test_flag(p, LOCAL_GLARE_DETECT);
- /* If we have a queue holding, don't actually destroy p yet, but
- let local_queue do it. */
- if (glaredetect)
- ast_set_flag(p, LOCAL_CANCEL_QUEUE);
- ast_mutex_unlock(&p->lock);
- /* Remove from list */
- AST_LIST_LOCK(&locals);
- AST_LIST_REMOVE(&locals, p, list);
- AST_LIST_UNLOCK(&locals);
- /* Grab / release lock just in case */
- ast_mutex_lock(&p->lock);
- ast_mutex_unlock(&p->lock);
- /* And destroy */
- if (!glaredetect) {
- p = local_pvt_destroy(p);
- }
- return 0;
- }
- if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX))
- /* Need to actually hangup since there is no PBX */
- ochan = p->chan;
- else
- res = local_queue_frame(p, isoutbound, &f, NULL, 1);
- if (!res)
- ast_mutex_unlock(&p->lock);
- if (ochan)
- ast_hangup(ochan);
- return 0;
-}
-
-/*! \brief Create a call structure */
-static struct local_pvt *local_alloc(const char *data, int format)
-{
- struct local_pvt *tmp = NULL;
- char *c = NULL, *opts = NULL;
-
- if (!(tmp = ast_calloc(1, sizeof(*tmp))))
- return NULL;
-
- /* Initialize private structure information */
- ast_mutex_init(&tmp->lock);
- ast_copy_string(tmp->exten, data, sizeof(tmp->exten));
-
- /* Look for options */
- if ((opts = strchr(tmp->exten, '/'))) {
- *opts++ = '\0';
- if (strchr(opts, 'n'))
- ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION);
- }
-
- /* Look for a context */
- if ((c = strchr(tmp->exten, '@')))
- *c++ = '\0';
-
- ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context));
-
- tmp->reqformat = format;
-
-#if 0
- /* We can't do this check here, because we don't know the CallerID yet, and
- * the CallerID could potentially affect what step is actually taken (or
- * even if that step exists). */
- if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) {
- ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context);
- tmp = local_pvt_destroy(tmp);
- } else {
-#endif
- /* Add to list */
- AST_LIST_LOCK(&locals);
- AST_LIST_INSERT_HEAD(&locals, tmp, list);
- AST_LIST_UNLOCK(&locals);
-#if 0
- }
-#endif
-
- return tmp;
-}
-
-/*! \brief Start new local channel */
-static struct ast_channel *local_new(struct local_pvt *p, int state)
-{
- struct ast_channel *tmp = NULL, *tmp2 = NULL;
- int randnum = ast_random() & 0xffff, fmt = 0;
- const char *t;
- int ama;
-
- /* Allocate two new Asterisk channels */
- /* safe accountcode */
- if (p->owner && p->owner->accountcode)
- t = p->owner->accountcode;
- else
- t = "";
-
- if (p->owner)
- ama = p->owner->amaflags;
- else
- ama = 0;
- if (!(tmp = ast_channel_alloc(1, state, 0, 0, t, p->exten, p->context, ama, "Local/%s@%s-%04x,1", p->exten, p->context, randnum))
- || !(tmp2 = ast_channel_alloc(1, AST_STATE_RING, 0, 0, t, p->exten, p->context, ama, "Local/%s@%s-%04x,2", p->exten, p->context, randnum))) {
- if (tmp)
- ast_channel_free(tmp);
- if (tmp2)
- ast_channel_free(tmp2);
- ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n");
- return NULL;
- }
-
- tmp2->tech = tmp->tech = &local_tech;
-
- tmp->nativeformats = p->reqformat;
- tmp2->nativeformats = p->reqformat;
-
- /* Determine our read/write format and set it on each channel */
- fmt = ast_best_codec(p->reqformat);
- tmp->writeformat = fmt;
- tmp2->writeformat = fmt;
- tmp->rawwriteformat = fmt;
- tmp2->rawwriteformat = fmt;
- tmp->readformat = fmt;
- tmp2->readformat = fmt;
- tmp->rawreadformat = fmt;
- tmp2->rawreadformat = fmt;
-
- tmp->tech_pvt = p;
- tmp2->tech_pvt = p;
-
- p->owner = tmp;
- p->chan = tmp2;
- p->u_owner = ast_module_user_add(p->owner);
- p->u_chan = ast_module_user_add(p->chan);
-
- ast_copy_string(tmp->context, p->context, sizeof(tmp->context));
- ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context));
- ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten));
- tmp->priority = 1;
- tmp2->priority = 1;
-
- return tmp;
-}
-
-/*! \brief Part of PBX interface */
-static struct ast_channel *local_request(const char *type, int format, void *data, int *cause)
-{
- struct local_pvt *p = NULL;
- struct ast_channel *chan = NULL;
-
- /* Allocate a new private structure and then Asterisk channel */
- if ((p = local_alloc(data, format))) {
- if (!(chan = local_new(p, AST_STATE_DOWN))) {
- AST_LIST_LOCK(&locals);
- AST_LIST_REMOVE(&locals, p, list);
- AST_LIST_UNLOCK(&locals);
- p = local_pvt_destroy(p);
- }
- }
-
- return chan;
-}
-
-/*! \brief CLI command "local show channels" */
-static int locals_show(int fd, int argc, char **argv)
-{
- struct local_pvt *p = NULL;
-
- if (argc != 3)
- return RESULT_SHOWUSAGE;
-
- AST_LIST_LOCK(&locals);
- if (!AST_LIST_EMPTY(&locals)) {
- AST_LIST_TRAVERSE(&locals, p, list) {
- ast_mutex_lock(&p->lock);
- ast_cli(fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context);
- ast_mutex_unlock(&p->lock);
- }
- } else
- ast_cli(fd, "No local channels in use\n");
- AST_LIST_UNLOCK(&locals);
-
- return RESULT_SUCCESS;
-}
-
-static char show_locals_usage[] =
-"Usage: local show channels\n"
-" Provides summary information on active local proxy channels.\n";
-
-static struct ast_cli_entry cli_local[] = {
- { { "local", "show", "channels", NULL },
- locals_show, "List status of local channels",
- show_locals_usage },
-};
-
-/*! \brief Load module into PBX, register channel */
-static int load_module(void)
-{
- /* Make sure we can register our channel type */
- if (ast_channel_register(&local_tech)) {
- ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n");
- return -1;
- }
- ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
- return 0;
-}
-
-/*! \brief Unload the local proxy channel from Asterisk */
-static int unload_module(void)
-{
- struct local_pvt *p = NULL;
-
- /* First, take us out of the channel loop */
- ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
- ast_channel_unregister(&local_tech);
- if (!AST_LIST_LOCK(&locals)) {
- /* Hangup all interfaces if they have an owner */
- AST_LIST_TRAVERSE(&locals, p, list) {
- if (p->owner)
- ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
- }
- AST_LIST_UNLOCK(&locals);
- } else {
- ast_log(LOG_WARNING, "Unable to lock the monitor\n");
- return -1;
- }
- return 0;
-}
-
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Local Proxy Channel (Note: used internally by other modules)");
diff --git a/1.4.23-rc4/channels/chan_mgcp.c b/1.4.23-rc4/channels/chan_mgcp.c
deleted file mode 100644
index 1d5114bee..000000000
--- a/1.4.23-rc4/channels/chan_mgcp.c
+++ /dev/null
@@ -1,4430 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 1999 - 2006, Digium, Inc.
- *
- * Mark Spencer <markster@digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Implementation of Media Gateway Control Protocol
- *
- * \author Mark Spencer <markster@digium.com>
- *
- * \par See also
- * \arg \ref Config_mgcp
- *
- * \ingroup channel_drivers
- */
-/*** MODULEINFO
- <depend>res_features</depend>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <net/if.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <netdb.h>
-#include <sys/signal.h>
-#include <signal.h>
-#include <netinet/in.h>
-#include <netinet/in_systm.h>
-#include <netinet/ip.h>
-#include <arpa/inet.h>
-#include <ctype.h>
-
-#include "asterisk/lock.h"
-#include "asterisk/channel.h"
-#include "asterisk/config.h"
-#include "asterisk/logger.h"
-#include "asterisk/module.h"
-#include "asterisk/pbx.h"
-#include "asterisk/options.h"
-#include "asterisk/lock.h"
-#include "asterisk/sched.h"
-#include "asterisk/io.h"
-#include "asterisk/rtp.h"
-#include "asterisk/acl.h"
-#include "asterisk/callerid.h"
-#include "asterisk/cli.h"
-#include "asterisk/say.h"
-#include "asterisk/cdr.h"
-#include "asterisk/astdb.h"
-#include "asterisk/features.h"
-#include "asterisk/app.h"
-#include "asterisk/musiconhold.h"
-#include "asterisk/utils.h"
-#include "asterisk/causes.h"
-#include "asterisk/dsp.h"
-#include "asterisk/devicestate.h"
-#include "asterisk/stringfields.h"
-#include "asterisk/abstract_jb.h"
-
-#ifndef IPTOS_MINCOST
-#define IPTOS_MINCOST 0x02
-#endif
-
-/*
- * Define to work around buggy dlink MGCP phone firmware which
- * appears not to know that "rt" is part of the "G" package.
- */
-/* #define DLINK_BUGGY_FIRMWARE */
-
-#define MGCPDUMPER
-#define DEFAULT_EXPIRY 120
-#define MAX_EXPIRY 3600
-#define CANREINVITE 1
-
-#ifndef INADDR_NONE
-#define INADDR_NONE (in_addr_t)(-1)
-#endif
-
-/*! Global jitterbuffer configuration - by default, jb is disabled */
-static struct ast_jb_conf default_jbconf =
-{
- .flags = 0,
- .max_size = -1,
- .resync_threshold = -1,
- .impl = ""
-};
-static struct ast_jb_conf global_jbconf;
-
-static const char tdesc[] = "Media Gateway Control Protocol (MGCP)";
-static const char config[] = "mgcp.conf";
-
-#define MGCP_DTMF_RFC2833 (1 << 0)
-#define MGCP_DTMF_INBAND (1 << 1)
-#define MGCP_DTMF_HYBRID (1 << 2)
-
-#define DEFAULT_MGCP_GW_PORT 2427 /*!< From RFC 2705 */
-#define DEFAULT_MGCP_CA_PORT 2727 /*!< From RFC 2705 */
-#define MGCP_MAX_PACKET 1500 /*!< Also from RFC 2543, should sub headers tho */
-#define DEFAULT_RETRANS 1000 /*!< How frequently to retransmit */
-#define MAX_RETRANS 5 /*!< Try only 5 times for retransmissions */
-
-/*! MGCP rtp stream modes { */
-#define MGCP_CX_SENDONLY 0
-#define MGCP_CX_RECVONLY 1
-#define MGCP_CX_SENDRECV 2
-#define MGCP_CX_CONF 3
-#define MGCP_CX_CONFERENCE 3
-#define MGCP_CX_MUTE 4
-#define MGCP_CX_INACTIVE 4
-/*! } */
-
-static char *mgcp_cxmodes[] = {
- "sendonly",
- "recvonly",
- "sendrecv",
- "confrnce",
- "inactive"
-};
-
-enum {
- MGCP_CMD_EPCF,
- MGCP_CMD_CRCX,
- MGCP_CMD_MDCX,
- MGCP_CMD_DLCX,
- MGCP_CMD_RQNT,
- MGCP_CMD_NTFY,
- MGCP_CMD_AUEP,
- MGCP_CMD_AUCX,
- MGCP_CMD_RSIP
-};
-
-static char context[AST_MAX_EXTENSION] = "default";
-
-static char language[MAX_LANGUAGE] = "";
-static char musicclass[MAX_MUSICCLASS] = "";
-static char cid_num[AST_MAX_EXTENSION] = "";
-static char cid_name[AST_MAX_EXTENSION] = "";
-
-static int dtmfmode = 0;
-static int nat = 0;
-
-static ast_group_t cur_callergroup = 0;
-static ast_group_t cur_pickupgroup = 0;
-
-static int tos = 0;
-
-static int immediate = 0;
-
-static int callwaiting = 0;
-
-static int callreturn = 0;
-
-static int slowsequence = 0;
-
-static int threewaycalling = 0;
-
-/*! This is for flashhook transfers */
-static int transfer = 0;
-
-static int cancallforward = 0;
-
-static int singlepath = 0;
-
-static int canreinvite = CANREINVITE;
-
-static char accountcode[AST_MAX_ACCOUNT_CODE] = "";
-
-static char mailbox[AST_MAX_EXTENSION];
-
-static int amaflags = 0;
-
-static int adsi = 0;
-
-static unsigned int oseq;
-
-/*! Wait up to 16 seconds for first digit (FXO logic) */
-static int firstdigittimeout = 16000;
-
-/*! How long to wait for following digits (FXO logic) */
-static int gendigittimeout = 8000;
-
-/*! How long to wait for an extra digit, if there is an ambiguous match */
-static int matchdigittimeout = 3000;
-
-/*! Protect the monitoring thread, so only one process can kill or start it, and not
- when it's doing something critical. */
-AST_MUTEX_DEFINE_STATIC(netlock);
-
-AST_MUTEX_DEFINE_STATIC(monlock);
-
-/*! This is the thread for the monitor which checks for input on the channels
- which are not currently in use. */
-static pthread_t monitor_thread = AST_PTHREADT_NULL;
-
-static int restart_monitor(void);
-
-static int capability = AST_FORMAT_ULAW;
-static int nonCodecCapability = AST_RTP_DTMF;
-
-static char ourhost[MAXHOSTNAMELEN];
-static struct in_addr __ourip;
-static int ourport;
-
-static int mgcpdebug = 0;
-
-static struct sched_context *sched;
-static struct io_context *io;
-/*! The private structures of the mgcp channels are linked for
- ! selecting outgoing channels */
-
-#define MGCP_MAX_HEADERS 64
-#define MGCP_MAX_LINES 64
-
-struct mgcp_request {
- int len;
- char *verb;
- char *identifier;
- char *endpoint;
- char *version;
- int headers; /*!< MGCP Headers */
- char *header[MGCP_MAX_HEADERS];
- int lines; /*!< SDP Content */
- char *line[MGCP_MAX_LINES];
- char data[MGCP_MAX_PACKET];
- int cmd; /*!< int version of verb = command */
- unsigned int trid; /*!< int version of identifier = transaction id */
- struct mgcp_request *next; /*!< next in the queue */
-};
-
-/*! \brief mgcp_message: MGCP message for queuing up */
-struct mgcp_message {
- struct mgcp_endpoint *owner_ep;
- struct mgcp_subchannel *owner_sub;
- int retrans;
- unsigned long expire;
- unsigned int seqno;
- int len;
- struct mgcp_message *next;
- char buf[0];
-};
-
-#define RESPONSE_TIMEOUT 30 /*!< in seconds */
-
-struct mgcp_response {
- time_t whensent;
- int len;
- int seqno;
- struct mgcp_response *next;
- char buf[0];
-};
-
-#define MAX_SUBS 2
-
-#define SUB_REAL 0
-#define SUB_ALT 1
-
-struct mgcp_subchannel {
- /*! subchannel magic string.
- Needed to prove that any subchannel pointer passed by asterisk
- really points to a valid subchannel memory area.
- Ugly.. But serves the purpose for the time being.
- */
-#define MGCP_SUBCHANNEL_MAGIC "!978!"
- char magic[6];
- ast_mutex_t lock;
- int id;
- struct ast_channel *owner;
- struct mgcp_endpoint *parent;
- struct ast_rtp *rtp;
- struct sockaddr_in tmpdest;
- char txident[80]; /*! \todo FIXME txident is replaced by rqnt_ident in endpoint.
- This should be obsoleted */
- char cxident[80];
- char callid[80];
- int cxmode;
- struct mgcp_request *cx_queue; /*!< pending CX commands */
- ast_mutex_t cx_queue_lock; /*!< CX queue lock */
- int nat;
- int iseq; /*!< Not used? RTP? */
- int outgoing;
- int alreadygone;
- struct mgcp_subchannel *next; /*!< for out circular linked list */
-};
-
-#define MGCP_ONHOOK 1
-#define MGCP_OFFHOOK 2
-
-#define TYPE_TRUNK 1
-#define TYPE_LINE 2
-
-struct mgcp_endpoint {
- ast_mutex_t lock;
- char name[80];
- struct mgcp_subchannel *sub; /*!< Pointer to our current connection, channel and stuff */
- char accountcode[AST_MAX_ACCOUNT_CODE];
- char exten[AST_MAX_EXTENSION]; /*!< Extention where to start */
- char context[AST_MAX_EXTENSION];
- char language[MAX_LANGUAGE];
- char cid_num[AST_MAX_EXTENSION]; /*!< Caller*ID number */
- char cid_name[AST_MAX_EXTENSION]; /*!< Caller*ID name */
- char lastcallerid[AST_MAX_EXTENSION]; /*!< Last Caller*ID */
- char call_forward[AST_MAX_EXTENSION]; /*!< Last Caller*ID */
- char mailbox[AST_MAX_EXTENSION];
- char musicclass[MAX_MUSICCLASS];
- char curtone[80]; /*!< Current tone */
- char dtmf_buf[AST_MAX_EXTENSION]; /*!< place to collect digits be */
- ast_group_t callgroup;
- ast_group_t pickupgroup;
- int callwaiting;
- int hascallwaiting;
- int transfer;
- int threewaycalling;
- int singlepath;
- int cancallforward;
- int canreinvite;
- int callreturn;
- int dnd; /* How does this affect callwait? Do we just deny a mgcp_request if we're dnd? */
- int hascallerid;
- int hidecallerid;
- int dtmfmode;
- int amaflags;
- int type;
- int slowsequence; /*!< MS: Sequence the endpoint as a whole */
- int group;
- int iseq; /*!< Not used? */
- int lastout; /*!< tracking this on the subchannels. Is it needed here? */
- int needdestroy; /*!< Not used? */
- int capability;
- int nonCodecCapability;
- int onhooktime;
- int msgstate; /*!< voicemail message state */
- int immediate;
- int hookstate;
- int adsi;
- char rqnt_ident[80]; /*!< request identifier */
- struct mgcp_request *rqnt_queue; /*!< pending RQNT commands */
- ast_mutex_t rqnt_queue_lock;
- struct mgcp_request *cmd_queue; /*!< pending commands other than RQNT */
- ast_mutex_t cmd_queue_lock;
- int delme; /*!< needed for reload */
- int needaudit; /*!< needed for reload */
- struct ast_dsp *dsp; /*!< XXX Should there be a dsp/subchannel? XXX */
- /* owner is tracked on the subchannels, and the *sub indicates whos in charge */
- /* struct ast_channel *owner; */
- /* struct ast_rtp *rtp; */
- /* struct sockaddr_in tmpdest; */
- /* message go the the endpoint and not the channel so they stay here */
- struct mgcp_endpoint *next;
- struct mgcp_gateway *parent;
-};
-
-static struct mgcp_gateway {
- /* A gateway containing one or more endpoints */
- char name[80];
- int isnamedottedip; /*!< is the name FQDN or dotted ip */
- struct sockaddr_in addr;
- struct sockaddr_in defaddr;
- struct in_addr ourip;
- int dynamic;
- int expire; /*!< XXX Should we ever expire dynamic registrations? XXX */
- struct mgcp_endpoint *endpoints;
- struct ast_ha *ha;
-/* obsolete
- time_t lastouttime;
- int lastout;
- int messagepending;
-*/
-/* Wildcard endpoint name */
- char wcardep[30];
- struct mgcp_message *msgs; /*!< gw msg queue */
- ast_mutex_t msgs_lock; /*!< queue lock */
- int retransid; /*!< retrans timer id */
- int delme; /*!< needed for reload */
- struct mgcp_response *responses;
- struct mgcp_gateway *next;
-} *gateways;
-
-AST_MUTEX_DEFINE_STATIC(mgcp_reload_lock);
-static int mgcp_reloading = 0;
-
-/*! \brief gatelock: mutex for gateway/endpoint lists */
-AST_MUTEX_DEFINE_STATIC(gatelock);
-
-static int mgcpsock = -1;
-
-static struct sockaddr_in bindaddr;
-
-static struct ast_frame *mgcp_read(struct ast_channel *ast);
-static int transmit_response(struct mgcp_subchannel *sub, char *msg, struct mgcp_request *req, char *msgrest);
-static int transmit_notify_request(struct mgcp_subchannel *sub, char *tone);
-static int transmit_modify_request(struct mgcp_subchannel *sub);
-static int transmit_notify_request_with_callerid(struct mgcp_subchannel *sub, char *tone, char *callernum, char *callername);
-static int transmit_modify_with_sdp(struct mgcp_subchannel *sub, struct ast_rtp *rtp, int codecs);
-static int transmit_connection_del(struct mgcp_subchannel *sub);
-static int transmit_audit_endpoint(struct mgcp_endpoint *p);
-static void start_rtp(struct mgcp_subchannel *sub);
-static void handle_response(struct mgcp_endpoint *p, struct mgcp_subchannel *sub,
- int result, unsigned int ident, struct mgcp_request *resp);
-static void dump_cmd_queues(struct mgcp_endpoint *p, struct mgcp_subchannel *sub);
-static int mgcp_do_reload(void);
-static int mgcp_reload(int fd, int argc, char *argv[]);
-
-static struct ast_channel *mgcp_request(const char *type, int format, void *data, int *cause);
-static int mgcp_call(struct ast_channel *ast, char *dest, int timeout);
-static int mgcp_hangup(struct ast_channel *ast);
-static int mgcp_answer(struct ast_channel *ast);
-static struct ast_frame *mgcp_read(struct ast_channel *ast);
-static int mgcp_write(struct ast_channel *ast, struct ast_frame *frame);
-static int mgcp_indicate(struct ast_channel *ast, int ind, const void *data, size_t datalen);
-static int mgcp_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
-static int mgcp_senddigit_begin(struct ast_channel *ast, char digit);
-static int mgcp_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration);
-static int mgcp_devicestate(void *data);
-static void add_header_offhook(struct mgcp_subchannel *sub, struct mgcp_request *resp);
-
-static const struct ast_channel_tech mgcp_tech = {
- .type = "MGCP",
- .description = tdesc,
- .capabilities = AST_FORMAT_ULAW,
- .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER,
- .requester = mgcp_request,
- .devicestate = mgcp_devicestate,
- .call = mgcp_call,
- .hangup = mgcp_hangup,
- .answer = mgcp_answer,
- .read = mgcp_read,
- .write = mgcp_write,
- .indicate = mgcp_indicate,
- .fixup = mgcp_fixup,
- .send_digit_begin = mgcp_senddigit_begin,
- .send_digit_end = mgcp_senddigit_end,
- .bridge = ast_rtp_bridge,
-};
-
-static int has_voicemail(struct mgcp_endpoint *p)
-{
- return ast_app_has_voicemail(p->mailbox, NULL);
-}
-
-static int unalloc_sub(struct mgcp_subchannel *sub)
-{
- struct mgcp_endpoint *p = sub->parent;
- if (p->sub == sub) {
- ast_log(LOG_WARNING, "Trying to unalloc the real channel %s@%s?!?\n", p->name, p->parent->name);
- return -1;
- }
- ast_log(LOG_DEBUG, "Released sub %d of channel %s@%s\n", sub->id, p->name, p->parent->name);
-
- sub->owner = NULL;
- if (!ast_strlen_zero(sub->cxident)) {
- transmit_connection_del(sub);
- }
- sub->cxident[0] = '\0';
- sub->callid[0] = '\0';
- sub->cxmode = MGCP_CX_INACTIVE;
- sub->outgoing = 0;
- sub->alreadygone = 0;
- memset(&sub->tmpdest, 0, sizeof(sub->tmpdest));
- if (sub->rtp) {
- ast_rtp_destroy(sub->rtp);
- sub->rtp = NULL;
- }
- dump_cmd_queues(NULL, sub); /* SC */
- return 0;
-}
-
-/* modified for new transport mechanism */
-static int __mgcp_xmit(struct mgcp_gateway *gw, char *data, int len)
-{
- int res;
- if (gw->addr.sin_addr.s_addr)
- res=sendto(mgcpsock, data, len, 0, (struct sockaddr *)&gw->addr, sizeof(struct sockaddr_in));
- else
- res=sendto(mgcpsock, data, len, 0, (struct sockaddr *)&gw->defaddr, sizeof(struct sockaddr_in));
- if (res != len) {
- ast_log(LOG_WARNING, "mgcp_xmit returned %d: %s\n", res, strerror(errno));
- }
- return res;
-}
-
-static int resend_response(struct mgcp_subchannel *sub, struct mgcp_response *resp)
-{
- struct mgcp_endpoint *p = sub->parent;
- int res;
- if (mgcpdebug) {
- ast_verbose("Retransmitting:\n%s\n to %s:%d\n", resp->buf, ast_inet_ntoa(p->parent->addr.sin_addr), ntohs(p->parent->addr.sin_port));
- }
- res = __mgcp_xmit(p->parent, resp->buf, resp->len);
- if (res > 0)
- res = 0;
- return res;
-}
-
-static int send_response(struct mgcp_subchannel *sub, struct mgcp_request *req)
-{
- struct mgcp_endpoint *p = sub->parent;
- int res;
- if (mgcpdebug) {
- ast_verbose("Transmitting:\n%s\n to %s:%d\n", req->data, ast_inet_ntoa(p->parent->addr.sin_addr), ntohs(p->parent->addr.sin_port));
- }
- res = __mgcp_xmit(p->parent, req->data, req->len);
- if (res > 0)
- res = 0;
- return res;
-}
-
-/* modified for new transport framework */
-static void dump_queue(struct mgcp_gateway *gw, struct mgcp_endpoint *p)
-{
- struct mgcp_message *cur, *q = NULL, *w, *prev;
-
- ast_mutex_lock(&gw->msgs_lock);
- prev = NULL, cur = gw->msgs;
- while (cur) {
- if (!p || cur->owner_ep == p) {
- if (prev)
- prev->next = cur->next;
- else
- gw->msgs = cur->next;
-
- ast_log(LOG_NOTICE, "Removing message from %s transaction %u\n",
- gw->name, cur->seqno);
-
- w = cur;
- cur = cur->next;
- if (q) {
- w->next = q;
- } else {
- w->next = NULL;
- }
- q = w;
- } else {
- prev = cur, cur=cur->next;
- }
- }
- ast_mutex_unlock(&gw->msgs_lock);
-
- while (q) {
- cur = q;
- q = q->next;
- free(cur);
- }
-}
-
-static void mgcp_queue_frame(struct mgcp_subchannel *sub, struct ast_frame *f)
-{
- for(;;) {
- if (sub->owner) {
- if (!ast_mutex_trylock(&sub->owner->lock)) {
- ast_queue_frame(sub->owner, f);
- ast_mutex_unlock(&sub->owner->lock);
- break;
- } else {
- DEADLOCK_AVOIDANCE(&sub->lock);
- }
- } else
- break;
- }
-}
-
-static void mgcp_queue_hangup(struct mgcp_subchannel *sub)
-{
- for(;;) {
- if (sub->owner) {
- if (!ast_mutex_trylock(&sub->owner->lock)) {
- ast_queue_hangup(sub->owner);
- ast_mutex_unlock(&sub->owner->lock);
- break;
- } else {
- DEADLOCK_AVOIDANCE(&sub->lock);
- }
- } else
- break;
- }
-}
-
-static void mgcp_queue_control(struct mgcp_subchannel *sub, int control)
-{
- struct ast_frame f = { AST_FRAME_CONTROL, };
- f.subclass = control;
- return mgcp_queue_frame(sub, &f);
-}
-
-static int retrans_pkt(const void *data)
-{
- struct mgcp_gateway *gw = (struct mgcp_gateway *)data;
- struct mgcp_message *cur, *exq = NULL, *w, *prev;
- int res = 0;
-
- /* find out expired msgs */
- ast_mutex_lock(&gw->msgs_lock);
-
- prev = NULL, cur = gw->msgs;
- while (cur) {
- if (cur->retrans < MAX_RETRANS) {
- cur->retrans++;
- if (mgcpdebug) {
- ast_verbose("Retransmitting #%d transaction %u on [%s]\n",
- cur->retrans, cur->seqno, gw->name);
- }
- __mgcp_xmit(gw, cur->buf, cur->len);
-
- prev = cur;
- cur = cur->next;
- } else {
- if (prev)
- prev->next = cur->next;
- else
- gw->msgs = cur->next;
-
- ast_log(LOG_WARNING, "Maximum retries exceeded for transaction %u on [%s]\n",
- cur->seqno, gw->name);
-
- w = cur;
- cur = cur->next;
-
- if (exq) {
- w->next = exq;
- } else {
- w->next = NULL;
- }
- exq = w;
- }
- }
-
- if (!gw->msgs) {
- gw->retransid = -1;
- res = 0;
- } else {
- res = 1;
- }
- ast_mutex_unlock(&gw->msgs_lock);
-
- while (exq) {
- cur = exq;
- /* time-out transaction */
- handle_response(cur->owner_ep, cur->owner_sub, 406, cur->seqno, NULL);
- exq = exq->next;
- free(cur);
- }
-
- return res;
-}
-
-/* modified for the new transaction mechanism */
-static int mgcp_postrequest(struct mgcp_endpoint *p, struct mgcp_subchannel *sub,
- char *data, int len, unsigned int seqno)
-{
- struct mgcp_message *msg = malloc(sizeof(struct mgcp_message) + len);
- struct mgcp_message *cur;
- struct mgcp_gateway *gw = ((p && p->parent) ? p->parent : NULL);
- struct timeval tv;
-
- if (!msg) {
- return -1;
- }
- if (!gw) {
- return -1;
- }
-/* SC
- time(&t);
- if (gw->messagepending && (gw->lastouttime + 20 < t)) {
- ast_log(LOG_NOTICE, "Timeout waiting for response to message:%d, lastouttime: %ld, now: %ld. Dumping pending queue\n",
- gw->msgs ? gw->msgs->seqno : -1, (long) gw->lastouttime, (long) t);
- dump_queue(sub->parent);
- }
-*/
- msg->owner_sub = sub;
- msg->owner_ep = p;
- msg->seqno = seqno;
- msg->next = NULL;
- msg->len = len;
- msg->retrans = 0;
- memcpy(msg->buf, data, msg->len);
-
- ast_mutex_lock(&gw->msgs_lock);
- cur = gw->msgs;
- if (cur) {
- while(cur->next)
- cur = cur->next;
- cur->next = msg;
- } else {
- gw->msgs = msg;
- }
-
- if (gettimeofday(&tv, NULL) < 0) {
- /* This shouldn't ever happen, but let's be sure */
- ast_log(LOG_NOTICE, "gettimeofday() failed!\n");
- } else {
- msg->expire = tv.tv_sec * 1000 + tv.tv_usec / 1000 + DEFAULT_RETRANS;
-
- if (gw->retransid == -1)
- gw->retransid = ast_sched_add(sched, DEFAULT_RETRANS, retrans_pkt, (void *)gw);
- }
- ast_mutex_unlock(&gw->msgs_lock);
-/* SC
- if (!gw->messagepending) {
- gw->messagepending = 1;
- gw->lastout = seqno;
- gw->lastouttime = t;
-*/
- __mgcp_xmit(gw, msg->buf, msg->len);
- /* XXX Should schedule retransmission XXX */
-/* SC
- } else
- ast_log(LOG_DEBUG, "Deferring transmission of transaction %d\n", seqno);
-*/
- return 0;
-}
-
-/* modified for new transport */
-static int send_request(struct mgcp_endpoint *p, struct mgcp_subchannel *sub,
- struct mgcp_request *req, unsigned int seqno)
-{
- int res = 0;
- struct mgcp_request **queue, *q, *r, *t;
- ast_mutex_t *l;
-
- ast_log(LOG_DEBUG, "Slow sequence is %d\n", p->slowsequence);
- if (p->slowsequence) {
- queue = &p->cmd_queue;
- l = &p->cmd_queue_lock;
- ast_mutex_lock(l);
- } else {
- switch (req->cmd) {
- case MGCP_CMD_DLCX:
- queue = &sub->cx_queue;
- l = &sub->cx_queue_lock;
- ast_mutex_lock(l);
- q = sub->cx_queue;
- /* delete pending cx cmds */
- while (q) {
- r = q->next;
- free(q);
- q = r;
- }
- *queue = NULL;
- break;
-
- case MGCP_CMD_CRCX:
- case MGCP_CMD_MDCX:
- queue = &sub->cx_queue;
- l = &sub->cx_queue_lock;
- ast_mutex_lock(l);
- break;
-
- case MGCP_CMD_RQNT:
- queue = &p->rqnt_queue;
- l = &p->rqnt_queue_lock;
- ast_mutex_lock(l);
- break;
-
- default:
- queue = &p->cmd_queue;
- l = &p->cmd_queue_lock;
- ast_mutex_lock(l);
- break;
- }
- }
-
- r = (struct mgcp_request *) malloc (sizeof(struct mgcp_request));
- if (!r) {
- ast_log(LOG_WARNING, "Cannot post MGCP request: insufficient memory\n");
- ast_mutex_unlock(l);
- return -1;
- }
- memcpy(r, req, sizeof(struct mgcp_request));
-
- if (!(*queue)) {
- if (mgcpdebug) {
- ast_verbose("Posting Request:\n%s to %s:%d\n", req->data,
- ast_inet_ntoa(p->parent->addr.sin_addr), ntohs(p->parent->addr.sin_port));
- }
-
- res = mgcp_postrequest(p, sub, req->data, req->len, seqno);
- } else {
- if (mgcpdebug) {
- ast_verbose("Queueing Request:\n%s to %s:%d\n", req->data,
- ast_inet_ntoa(p->parent->addr.sin_addr), ntohs(p->parent->addr.sin_port));
- }
- }
-
- /* XXX find tail. We could also keep tail in the data struct for faster access */
- for (t = *queue; t && t->next; t = t->next);
-
- r->next = NULL;
- if (t)
- t->next = r;
- else
- *queue = r;
-
- ast_mutex_unlock(l);
-
- return res;
-}
-
-static int mgcp_call(struct ast_channel *ast, char *dest, int timeout)
-{
- int res;
- struct mgcp_endpoint *p;
- struct mgcp_subchannel *sub;
- char tone[50] = "";
- const char *distinctive_ring = NULL;
- struct varshead *headp;
- struct ast_var_t *current;
-
- if (mgcpdebug) {
- ast_verbose(VERBOSE_PREFIX_3 "MGCP mgcp_call(%s)\n", ast->name);
- }
- sub = ast->tech_pvt;
- p = sub->parent;
- headp = &ast->varshead;
- AST_LIST_TRAVERSE(headp,current,entries) {
- /* Check whether there is an ALERT_INFO variable */
- if (strcasecmp(ast_var_name(current),"ALERT_INFO") == 0) {
- distinctive_ring = ast_var_value(current);
- }
- }
-
- ast_mutex_lock(&sub->lock);
- switch (p->hookstate) {
- case MGCP_OFFHOOK:
- if (!ast_strlen_zero(distinctive_ring)) {
- snprintf(tone, sizeof(tone), "L/wt%s", distinctive_ring);
- if (mgcpdebug) {
- ast_verbose(VERBOSE_PREFIX_3 "MGCP distinctive callwait %s\n", tone);
- }
- } else {
- snprintf(tone, sizeof(tone), "L/wt");
- if (mgcpdebug) {
- ast_verbose(VERBOSE_PREFIX_3 "MGCP normal callwait %s\n", tone);
- }
- }
- break;
- case MGCP_ONHOOK:
- default:
- if (!ast_strlen_zero(distinctive_ring)) {
- snprintf(tone, sizeof(tone), "L/r%s", distinctive_ring);
- if (mgcpdebug) {
- ast_verbose(VERBOSE_PREFIX_3 "MGCP distinctive ring %s\n", tone);
- }
- } else {
- snprintf(tone, sizeof(tone), "L/rg");
- if (mgcpdebug) {
- ast_verbose(VERBOSE_PREFIX_3 "MGCP default ring\n");
- }
- }
- break;
- }
-
- if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
- ast_log(LOG_WARNING, "mgcp_call called on %s, neither down nor reserved\n", ast->name);
- ast_mutex_unlock(&sub->lock);
- return -1;
- }
-
- res = 0;
- sub->outgoing = 1;
- sub->cxmode = MGCP_CX_RECVONLY;
- if (p->type == TYPE_LINE) {
- if (!sub->rtp) {
- start_rtp(sub);
- } else {
- transmit_modify_request(sub);
- }
-
- if (sub->next->owner && !ast_strlen_zero(sub->next->cxident) && !ast_strlen_zero(sub->next->callid)) {
- /* try to prevent a callwait from disturbing the other connection */
- sub->next->cxmode = MGCP_CX_RECVONLY;
- transmit_modify_request(sub->next);
- }
-
- transmit_notify_request_with_callerid(sub, tone, ast->cid.cid_num, ast->cid.cid_name);
- ast_setstate(ast, AST_STATE_RINGING);
-
- if (sub->next->owner && !ast_strlen_zero(sub->next->cxident) && !ast_strlen_zero(sub->next->callid)) {
- /* Put the connection back in sendrecv */
- sub->next->cxmode = MGCP_CX_SENDRECV;
- transmit_modify_request(sub->next);
- }
- } else {
- ast_log(LOG_NOTICE, "Don't know how to dial on trunks yet\n");
- res = -1;
- }
- ast_mutex_unlock(&sub->lock);
- ast_queue_control(ast, AST_CONTROL_RINGING);
- return res;
-}
-
-static int mgcp_hangup(struct ast_channel *ast)
-{
- struct mgcp_subchannel *sub = ast->tech_pvt;
- struct mgcp_endpoint *p = sub->parent;
-
- if (option_debug) {
- ast_log(LOG_DEBUG, "mgcp_hangup(%s)\n", ast->name);
- }
- if (!ast->tech_pvt) {
- ast_log(LOG_DEBUG, "Asked to hangup channel not connected\n");
- return 0;
- }
- if (strcmp(sub->magic, MGCP_SUBCHANNEL_MAGIC)) {
- ast_log(LOG_DEBUG, "Invalid magic. MGCP subchannel freed up already.\n");
- return 0;
- }
- ast_mutex_lock(&sub->lock);
- if (mgcpdebug) {
- ast_verbose(VERBOSE_PREFIX_3 "MGCP mgcp_hangup(%s) on %s@%s\n", ast->name, p->name, p->parent->name);
- }
-
- if ((p->dtmfmode & MGCP_DTMF_INBAND) && p->dsp) {
- /* check whether other channel is active. */
- if (!sub->next->owner) {
- if (p->dtmfmode & MGCP_DTMF_HYBRID)
- p->dtmfmode &= ~MGCP_DTMF_INBAND;
- if (mgcpdebug) {
- ast_verbose(VERBOSE_PREFIX_2 "MGCP free dsp on %s@%s\n", p->name, p->parent->name);
- }
- ast_dsp_free(p->dsp);
- p->dsp = NULL;
- }
- }
-
- sub->owner = NULL;
- if (!ast_strlen_zero(sub->cxident)) {
- transmit_connection_del(sub);
- }
- sub->cxident[0] = '\0';
- if ((sub == p->sub) && sub->next->owner) {
- if (p->hookstate == MGCP_OFFHOOK) {
- if (sub->next->owner && ast_bridged_channel(sub->next->owner)) {
- transmit_notify_request_with_callerid(p->sub, "L/wt", ast_bridged_channel(sub->next->owner)->cid.cid_num, ast_bridged_channel(sub->next->owner)->cid.cid_name);
- }
- } else {
- /* set our other connection as the primary and swith over to it */
- p->sub = sub->next;
- p->sub->cxmode = MGCP_CX_RECVONLY;
- transmit_modify_request(p->sub);
- if (sub->next->owner && ast_bridged_channel(sub->next->owner)) {
- transmit_notify_request_with_callerid(p->sub, "L/rg", ast_bridged_channel(sub->next->owner)->cid.cid_num, ast_bridged_channel(sub->next->owner)->cid.cid_name);
- }
- }
-
- } else if ((sub == p->sub->next) && p->hookstate == MGCP_OFFHOOK) {
- transmit_notify_request(sub, "L/v");
- } else if (p->hookstate == MGCP_OFFHOOK) {
- transmit_notify_request(sub, "L/ro");
- } else {
- transmit_notify_request(sub, "");
- }
-
- ast->tech_pvt = NULL;
- sub->alreadygone = 0;
- sub->outgoing = 0;
- sub->cxmode = MGCP_CX_INACTIVE;
- sub->callid[0] = '\0';
- if (p) {
- memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
- }
- /* Reset temporary destination */
- memset(&sub->tmpdest, 0, sizeof(sub->tmpdest));
- if (sub->rtp) {
- ast_rtp_destroy(sub->rtp);
- sub->rtp = NULL;
- }
-
- ast_module_unref(ast_module_info->self);
-
- if ((p->hookstate == MGCP_ONHOOK) && (!sub->next->rtp)) {
- p->hidecallerid = 0;
- if (p->hascallwaiting && !p->callwaiting) {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Enabling call waiting on %s\n", ast->name);
- p->callwaiting = -1;
- }
- if (has_voicemail(p)) {
- if (mgcpdebug) {
- ast_verbose(VERBOSE_PREFIX_3 "MGCP mgcp_hangup(%s) on %s@%s set vmwi(+)\n",
- ast->name, p->name, p->parent->name);
- }
- transmit_notify_request(sub, "L/vmwi(+)");
- } else {
- if (mgcpdebug) {
- ast_verbose(VERBOSE_PREFIX_3 "MGCP mgcp_hangup(%s) on %s@%s set vmwi(-)\n",
- ast->name, p->name, p->parent->name);
- }
- transmit_notify_request(sub, "L/vmwi(-)");
- }
- }
- ast_mutex_unlock(&sub->lock);
- return 0;
-}
-
-static int mgcp_show_endpoints(int fd, int argc, char *argv[])
-{
- struct mgcp_gateway *g;
- struct mgcp_endpoint *e;
- int hasendpoints = 0;
-
- if (argc != 3)
- return RESULT_SHOWUSAGE;
- ast_mutex_lock(&gatelock);
- g = gateways;
- while(g) {
- e = g->endpoints;
- ast_cli(fd, "Gateway '%s' at %s (%s)\n", g->name, g->addr.sin_addr.s_addr ? ast_inet_ntoa(g->addr.sin_addr) : ast_inet_ntoa(g->defaddr.sin_addr), g->dynamic ? "Dynamic" : "Static");
- while(e) {
- /* Don't show wilcard endpoint */
- if (strcmp(e->name, g->wcardep) !=0)
- ast_cli(fd, " -- '%s@%s in '%s' is %s\n", e->name, g->name, e->context, e->sub->owner ? "active" : "idle");
- hasendpoints = 1;
- e = e->next;
- }
- if (!hasendpoints) {
- ast_cli(fd, " << No Endpoints Defined >> ");
- }
- g = g->next;
- }
- ast_mutex_unlock(&gatelock);
- return RESULT_SUCCESS;
-}
-
-static char show_endpoints_usage[] =
-"Usage: mgcp show endpoints\n"
-" Lists all endpoints known to the MGCP (Media Gateway Control Protocol) subsystem.\n";
-
-static char audit_endpoint_usage[] =
-"Usage: mgcp audit endpoint <endpointid>\n"
-" Lists the capabilities of an endpoint in the MGCP (Media Gateway Control Protocol) subsystem.\n"
-" mgcp debug MUST be on to see the results of this command.\n";
-
-static char debug_usage[] =
-"Usage: mgcp set debug\n"
-" Enables dumping of MGCP packets for debugging purposes\n";
-
-static char no_debug_usage[] =
-"Usage: mgcp set debug off\n"
-" Disables dumping of MGCP packets for debugging purposes\n";
-
-static char mgcp_reload_usage[] =
-"Usage: mgcp reload\n"
-" Reloads MGCP configuration from mgcp.conf\n"
-" Deprecated: please use 'reload chan_mgcp.so' instead.\n";
-
-static int mgcp_audit_endpoint(int fd, int argc, char *argv[])
-{
- struct mgcp_gateway *g;
- struct mgcp_endpoint *e;
- int found = 0;
- char *ename,*gname, *c;
-
- if (!mgcpdebug) {
- return RESULT_SHOWUSAGE;
- }
- if (argc != 4)
- return RESULT_SHOWUSAGE;
- /* split the name into parts by null */
- ename = argv[3];
- gname = ename;
- while (*gname) {
- if (*gname == '@') {
- *gname = 0;
- gname++;
- break;
- }
- gname++;
- }
- if (gname[0] == '[')
- gname++;
- if ((c = strrchr(gname, ']')))
- *c = '\0';
- ast_mutex_lock(&gatelock);
- g = gateways;
- while(g) {
- if (!strcasecmp(g->name, gname)) {
- e = g->endpoints;
- while(e) {
- if (!strcasecmp(e->name, ename)) {
- found = 1;
- transmit_audit_endpoint(e);
- break;
- }
- e = e->next;
- }
- if (found) {
- break;
- }
- }
- g = g->next;
- }
- if (!found) {
- ast_cli(fd, " << Could not find endpoint >> ");
- }
- ast_mutex_unlock(&gatelock);
- return RESULT_SUCCESS;
-}
-
-static int mgcp_do_debug(int fd, int argc, char *argv[])
-{
- if (argc != 3)
- return RESULT_SHOWUSAGE;
- mgcpdebug = 1;
- ast_cli(fd, "MGCP Debugging Enabled\n");
- return RESULT_SUCCESS;
-}
-
-static int mgcp_no_debug(int fd, int argc, char *argv[])
-{
- if (argc != 4)
- return RESULT_SHOWUSAGE;
- mgcpdebug = 0;
- ast_cli(fd, "MGCP Debugging Disabled\n");
- return RESULT_SUCCESS;
-}
-
-static struct ast_cli_entry cli_mgcp[] = {
- { { "mgcp", "audit", "endpoint", NULL },
- mgcp_audit_endpoint, "Audit specified MGCP endpoint",
- audit_endpoint_usage },
-
- { { "mgcp", "show", "endpoints", NULL },
- mgcp_show_endpoints, "List defined MGCP endpoints",
- show_endpoints_usage },
-
- { { "mgcp", "set", "debug", NULL },
- mgcp_do_debug, "Enable MGCP debugging",
- debug_usage },
-
- { { "mgcp", "set", "debug", "off", NULL },
- mgcp_no_debug, "Disable MGCP debugging",
- no_debug_usage },
-
- { { "mgcp", "reload", NULL },
- mgcp_reload, "Reload MGCP configuration",
- mgcp_reload_usage },
-};
-
-static int mgcp_answer(struct ast_channel *ast)
-{
- int res = 0;
- struct mgcp_subchannel *sub = ast->tech_pvt;
- struct mgcp_endpoint *p = sub->parent;
-
- ast_mutex_lock(&sub->lock);
- sub->cxmode = MGCP_CX_SENDRECV;
- if (!sub->rtp) {
- start_rtp(sub);
- } else {
- transmit_modify_request(sub);
- }
- /* verbose level check */
- if (option_verbose > 2) {
- ast_verbose(VERBOSE_PREFIX_3 "MGCP mgcp_answer(%s) on %s@%s-%d\n",
- ast->name, p->name, p->parent->name, sub->id);
- }
- if (ast->_state != AST_STATE_UP) {
- ast_setstate(ast, AST_STATE_UP);
- if (option_debug)
- ast_log(LOG_DEBUG, "mgcp_answer(%s)\n", ast->name);
- transmit_notify_request(sub, "");
- transmit_modify_request(sub);
- }
- ast_mutex_unlock(&sub->lock);
- return res;
-}
-
-static struct ast_frame *mgcp_rtp_read(struct mgcp_subchannel *sub)
-{
- /* Retrieve audio/etc from channel. Assumes sub->lock is already held. */
- struct ast_frame *f;
-
- f = ast_rtp_read(sub->rtp);
- /* Don't send RFC2833 if we're not supposed to */
- if (f && (f->frametype == AST_FRAME_DTMF) && !(sub->parent->dtmfmode & MGCP_DTMF_RFC2833))
- return &ast_null_frame;
- if (sub->owner) {
- /* We already hold the channel lock */
- if (f->frametype == AST_FRAME_VOICE) {
- if (f->subclass != sub->owner->nativeformats) {
- ast_log(LOG_DEBUG, "Oooh, format changed to %d\n", f->subclass);
- sub->owner->nativeformats = f->subclass;
- ast_set_read_format(sub->owner, sub->owner->readformat);
- ast_set_write_format(sub->owner, sub->owner->writeformat);
- }
- /* Courtesy fearnor aka alex@pilosoft.com */
- if ((sub->parent->dtmfmode & MGCP_DTMF_INBAND) && (sub->parent->dsp)) {
-#if 0
- ast_log(LOG_NOTICE, "MGCP ast_dsp_process\n");
-#endif
- f = ast_dsp_process(sub->owner, sub->parent->dsp, f);
- }
- }
- }
- return f;
-}
-
-
-static struct ast_frame *mgcp_read(struct ast_channel *ast)
-{
- struct ast_frame *f;
- struct mgcp_subchannel *sub = ast->tech_pvt;
- ast_mutex_lock(&sub->lock);
- f = mgcp_rtp_read(sub);
- ast_mutex_unlock(&sub->lock);
- return f;
-}
-
-static int mgcp_write(struct ast_channel *ast, struct ast_frame *frame)
-{
- struct mgcp_subchannel *sub = ast->tech_pvt;
- int res = 0;
- if (frame->frametype != AST_FRAME_VOICE) {
- if (frame->frametype == AST_FRAME_IMAGE)
- return 0;
- else {
- ast_log(LOG_WARNING, "Can't send %d type frames with MGCP write\n", frame->frametype);
- return 0;
- }
- } else {
- if (!(frame->subclass & ast->nativeformats)) {
- ast_log(LOG_WARNING, "Asked to transmit frame type %d, while native formats is %d (read/write = %d/%d)\n",
- frame->subclass, ast->nativeformats, ast->readformat, ast->writeformat);
- return -1;
- }
- }
- if (sub) {
- ast_mutex_lock(&sub->lock);
- if ((sub->parent->sub == sub) || !sub->parent->singlepath) {
- if (sub->rtp) {
- res = ast_rtp_write(sub->rtp, frame);
- }
- }
- ast_mutex_unlock(&sub->lock);
- }
- return res;
-}
-
-static int mgcp_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
-{
- struct mgcp_subchannel *sub = newchan->tech_pvt;
-
- ast_mutex_lock(&sub->lock);
- ast_log(LOG_NOTICE, "mgcp_fixup(%s, %s)\n", oldchan->name, newchan->name);
- if (sub->owner != oldchan) {
- ast_mutex_unlock(&sub->lock);
- ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, sub->owner);
- return -1;
- }
- sub->owner = newchan;
- ast_mutex_unlock(&sub->lock);
- return 0;
-}
-
-static int mgcp_senddigit_begin(struct ast_channel *ast, char digit)
-{
- struct mgcp_subchannel *sub = ast->tech_pvt;
- struct mgcp_endpoint *p = sub->parent;
- int res = 0;
-
- ast_mutex_lock(&sub->lock);
- if (p->dtmfmode & MGCP_DTMF_INBAND || p->dtmfmode & MGCP_DTMF_HYBRID) {
- ast_log(LOG_DEBUG, "Sending DTMF using inband/hybrid\n");
- res = -1; /* Let asterisk play inband indications */
- } else if (p->dtmfmode & MGCP_DTMF_RFC2833) {
- ast_log(LOG_DEBUG, "Sending DTMF using RFC2833");
- ast_rtp_senddigit_begin(sub->rtp, digit);
- } else {
- ast_log(LOG_ERROR, "Don't know about DTMF_MODE %d\n", p->dtmfmode);
- }
- ast_mutex_unlock(&sub->lock);
-
- return res;
-}
-
-static int mgcp_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration)
-{
- struct mgcp_subchannel *sub = ast->tech_pvt;
- struct mgcp_endpoint *p = sub->parent;
- int res = 0;
- char tmp[4];
-
- ast_mutex_lock(&sub->lock);
- if (p->dtmfmode & MGCP_DTMF_INBAND || p->dtmfmode & MGCP_DTMF_HYBRID) {
- ast_log(LOG_DEBUG, "Stopping DTMF using inband/hybrid\n");
- res = -1; /* Tell Asterisk to stop inband indications */
- } else if (p->dtmfmode & MGCP_DTMF_RFC2833) {
- ast_log(LOG_DEBUG, "Stopping DTMF using RFC2833\n");
- tmp[0] = 'D';
- tmp[1] = '/';
- tmp[2] = digit;
- tmp[3] = '\0';
- transmit_notify_request(sub, tmp);
- ast_rtp_senddigit_end(sub->rtp, digit);
- } else {
- ast_log(LOG_ERROR, "Don't know about DTMF_MODE %d\n", p->dtmfmode);
- }
- ast_mutex_unlock(&sub->lock);
-
- return res;
-}
-
-/*!
- * \brief mgcp_devicestate: channel callback for device status monitoring
- * \param data tech/resource name of MGCP device to query
- *
- * Callback for device state management in channel subsystem
- * to obtain device status (up/down) of a specific MGCP endpoint
- *
- * \return device status result (from devicestate.h) AST_DEVICE_INVALID (not available) or AST_DEVICE_UNKNOWN (available but unknown state)
- */
-static int mgcp_devicestate(void *data)
-{
- struct mgcp_gateway *g;
- struct mgcp_endpoint *e = NULL;
- char *tmp, *endpt, *gw;
- int ret = AST_DEVICE_INVALID;
-
- endpt = ast_strdupa(data);
- if ((tmp = strchr(endpt, '@'))) {
- *tmp++ = '\0';
- gw = tmp;
- } else
- goto error;
-
- ast_mutex_lock(&gatelock);
- g = gateways;
- while (g) {
- if (strcasecmp(g->name, gw) == 0) {
- e = g->endpoints;
- break;
- }
- g = g->next;
- }
-
- if (!e)
- goto error;
-
- while (e) {
- if (strcasecmp(e->name, endpt) == 0)
- break;
- e = e->next;
- }
-
- if (!e)
- goto error;
-
- /*
- * As long as the gateway/endpoint is valid, we'll
- * assume that the device is available and its state
- * can be tracked.
- */
- ret = AST_DEVICE_UNKNOWN;
-
-error:
- ast_mutex_unlock(&gatelock);
- return ret;
-}
-
-static char *control2str(int ind) {
- switch (ind) {
- case AST_CONTROL_HANGUP:
- return "Other end has hungup";
- case AST_CONTROL_RING:
- return "Local ring";
- case AST_CONTROL_RINGING:
- return "Remote end is ringing";
- case AST_CONTROL_ANSWER:
- return "Remote end has answered";
- case AST_CONTROL_BUSY:
- return "Remote end is busy";
- case AST_CONTROL_TAKEOFFHOOK:
- return "Make it go off hook";
- case AST_CONTROL_OFFHOOK:
- return "Line is off hook";
- case AST_CONTROL_CONGESTION:
- return "Congestion (circuits busy)";
- case AST_CONTROL_FLASH:
- return "Flash hook";
- case AST_CONTROL_WINK:
- return "Wink";
- case AST_CONTROL_OPTION:
- return "Set a low-level option";
- case AST_CONTROL_RADIO_KEY:
- return "Key Radio";
- case AST_CONTROL_RADIO_UNKEY:
- return "Un-Key Radio";
- }
- return "UNKNOWN";
-}
-
-static int mgcp_indicate(struct ast_channel *ast, int ind, const void *data, size_t datalen)
-{
- struct mgcp_subchannel *sub = ast->tech_pvt;
- int res = 0;
-
- if (mgcpdebug) {
- ast_verbose(VERBOSE_PREFIX_3 "MGCP asked to indicate %d '%s' condition on channel %s\n",
- ind, control2str(ind), ast->name);
- }
- ast_mutex_lock(&sub->lock);
- switch(ind) {
- case AST_CONTROL_RINGING:
-#ifdef DLINK_BUGGY_FIRMWARE
- transmit_notify_request(sub, "rt");
-#else
- transmit_notify_request(sub, "G/rt");
-#endif
- break;
- case AST_CONTROL_BUSY:
- transmit_notify_request(sub, "L/bz");
- break;
- case AST_CONTROL_CONGESTION:
- transmit_notify_request(sub, "G/cg");
- break;
- case AST_CONTROL_HOLD:
- ast_moh_start(ast, data, NULL);
- break;
- case AST_CONTROL_UNHOLD:
- ast_moh_stop(ast);
- break;
- case AST_CONTROL_SRCUPDATE:
- ast_rtp_new_source(sub->rtp);
- break;
- case -1:
- transmit_notify_request(sub, "");
- break;
- default:
- ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", ind);
- res = -1;
- }
- ast_mutex_unlock(&sub->lock);
- return res;
-}
-
-static struct ast_channel *mgcp_new(struct mgcp_subchannel *sub, int state)
-{
- struct ast_channel *tmp;
- struct mgcp_endpoint *i = sub->parent;
- int fmt;
-
- tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, i->accountcode, i->exten, i->context, i->amaflags, "MGCP/%s@%s-%d", i->name, i->parent->name, sub->id);
- if (tmp) {
- tmp->tech = &mgcp_tech;
- tmp->nativeformats = i->capability;
- if (!tmp->nativeformats)
- tmp->nativeformats = capability;
- fmt = ast_best_codec(tmp->nativeformats);
- ast_string_field_build(tmp, name, "MGCP/%s@%s-%d", i->name, i->parent->name, sub->id);
- if (sub->rtp)
- tmp->fds[0] = ast_rtp_fd(sub->rtp);
- if (i->dtmfmode & (MGCP_DTMF_INBAND | MGCP_DTMF_HYBRID)) {
- i->dsp = ast_dsp_new();
- ast_dsp_set_features(i->dsp,DSP_FEATURE_DTMF_DETECT);
- /* this is to prevent clipping of dtmf tones during dsp processing */
- ast_dsp_digitmode(i->dsp, DSP_DIGITMODE_NOQUELCH);
- } else {
- i->dsp = NULL;
- }
- if (state == AST_STATE_RING)
- tmp->rings = 1;
- tmp->writeformat = fmt;
- tmp->rawwriteformat = fmt;
- tmp->readformat = fmt;
- tmp->rawreadformat = fmt;
- tmp->tech_pvt = sub;
- if (!ast_strlen_zero(i->language))
- ast_string_field_set(tmp, language, i->language);
- if (!ast_strlen_zero(i->accountcode))
- ast_string_field_set(tmp, accountcode, i->accountcode);
- if (i->amaflags)
- tmp->amaflags = i->amaflags;
- sub->owner = tmp;
- ast_module_ref(ast_module_info->self);
- tmp->callgroup = i->callgroup;
- tmp->pickupgroup = i->pickupgroup;
- ast_string_field_set(tmp, call_forward, i->call_forward);
- ast_copy_string(tmp->context, i->context, sizeof(tmp->context));
- ast_copy_string(tmp->exten, i->exten, sizeof(tmp->exten));
-
- /* Don't use ast_set_callerid() here because it will
- * generate a needless NewCallerID event */
- tmp->cid.cid_ani = ast_strdup(i->cid_num);
-
- if (!i->adsi)
- tmp->adsicpe = AST_ADSI_UNAVAILABLE;
- tmp->priority = 1;
- if (sub->rtp)
- ast_jb_configure(tmp, &global_jbconf);
- if (state != AST_STATE_DOWN) {
- if (ast_pbx_start(tmp)) {
- ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
- ast_hangup(tmp);
- tmp = NULL;
- }
- }
- /* verbose level check */
- if (option_verbose > 2) {
- ast_verbose(VERBOSE_PREFIX_3 "MGCP mgcp_new(%s) created in state: %s\n",
- tmp->name, ast_state2str(state));
- }
- } else {
- ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
- }
- return tmp;
-}
-
-static char* get_sdp_by_line(char* line, char *name, int nameLen)
-{
- if (strncasecmp(line, name, nameLen) == 0 && line[nameLen] == '=') {
- char* r = line + nameLen + 1;
- while (*r && (*r < 33)) ++r;
- return r;
- }
- return "";
-}
-
-static char *get_sdp(struct mgcp_request *req, char *name)
-{
- int x;
- int len = strlen(name);
- char *r;
-
- for (x=0; x<req->lines; x++) {
- r = get_sdp_by_line(req->line[x], name, len);
- if (r[0] != '\0') return r;
- }
- return "";
-}
-
-static void sdpLineNum_iterator_init(int* iterator)
-{
- *iterator = 0;
-}
-
-static char* get_sdp_iterate(int* iterator, struct mgcp_request *req, char *name)
-{
- int len = strlen(name);
- char *r;
- while (*iterator < req->lines) {
- r = get_sdp_by_line(req->line[(*iterator)++], name, len);
- if (r[0] != '\0') return r;
- }
- return "";
-}
-
-static char *__get_header(struct mgcp_request *req, char *name, int *start)
-{
- int x;
- int len = strlen(name);
- char *r;
- for (x=*start;x<req->headers;x++) {
- if (!strncasecmp(req->header[x], name, len) &&
- (req->header[x][len] == ':')) {
- r = req->header[x] + len + 1;
- while(*r && (*r < 33))
- r++;
- *start = x+1;
- return r;
- }
- }
- /* Don't return NULL, so get_header is always a valid pointer */
- return "";
-}
-
-static char *get_header(struct mgcp_request *req, char *name)
-{
- int start = 0;
- return __get_header(req, name, &start);
-}
-
-/*! \brief get_csv: (SC:) get comma separated value */
-static char *get_csv(char *c, int *len, char **next)
-{
- char *s;
-
- *next = NULL, *len = 0;
- if (!c) return NULL;
-
- while (*c && (*c < 33 || *c == ','))
- c++;
-
- s = c;
- while (*c && (*c >= 33 && *c != ','))
- c++, (*len)++;
- *next = c;
-
- if (*len == 0)
- s = NULL, *next = NULL;
-
- return s;
-}
-
-static struct mgcp_subchannel *find_subchannel_and_lock(char *name, int msgid, struct sockaddr_in *sin)
-{
- struct mgcp_endpoint *p = NULL;
- struct mgcp_subchannel *sub = NULL;
- struct mgcp_gateway *g;
- char tmp[256] = "";
- char *at = NULL, *c;
- int found = 0;
- if (name) {
- ast_copy_string(tmp, name, sizeof(tmp));
- at = strchr(tmp, '@');
- if (!at) {
- ast_log(LOG_NOTICE, "Endpoint '%s' has no at sign!\n", name);
- return NULL;
- }
- *at++ = '\0';
- }
- ast_mutex_lock(&gatelock);
- if (at && (at[0] == '[')) {
- at++;
- c = strrchr(at, ']');
- if (c)
- *c = '\0';
- }
- g = gateways;
- while(g) {
- if ((!name || !strcasecmp(g->name, at)) &&
- (sin || g->addr.sin_addr.s_addr || g->defaddr.sin_addr.s_addr)) {
- /* Found the gateway. If it's dynamic, save it's address -- now for the endpoint */
- if (sin && g->dynamic && name) {
- if ((g->addr.sin_addr.s_addr != sin->sin_addr.s_addr) ||
- (g->addr.sin_port != sin->sin_port)) {
- memcpy(&g->addr, sin, sizeof(g->addr));
- if (ast_ouraddrfor(&g->addr.sin_addr, &g->ourip))
- memcpy(&g->ourip, &__ourip, sizeof(g->ourip));
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Registered MGCP gateway '%s' at %s port %d\n", g->name, ast_inet_ntoa(g->addr.sin_addr), ntohs(g->addr.sin_port));
- }
- }
- /* not dynamic, check if the name matches */
- else if (name) {
- if (strcasecmp(g->name, at)) {
- g = g->next;
- continue;
- }
- }
- /* not dynamic, no name, check if the addr matches */
- else if (!name && sin) {
- if ((g->addr.sin_addr.s_addr != sin->sin_addr.s_addr) ||
- (g->addr.sin_port != sin->sin_port)) {
- g = g->next;
- continue;
- }
- } else {
- g = g->next;
- continue;
- }
- /* SC */
- p = g->endpoints;
- while(p) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Searching on %s@%s for subchannel\n",
- p->name, g->name);
- if (msgid) {
-#if 0 /* new transport mech */
- sub = p->sub;
- do {
- if (option_debug)
- ast_log(LOG_DEBUG, "Searching on %s@%s-%d for subchannel with lastout: %d\n",
- p->name, g->name, sub->id, msgid);
- if (sub->lastout == msgid) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Found subchannel sub%d to handle request %d sub->lastout: %d\n",
- sub->id, msgid, sub->lastout);
- found = 1;
- break;
- }
- sub = sub->next;
- } while (sub != p->sub);
- if (found) {
- break;
- }
-#endif
- /* SC */
- sub = p->sub;
- found = 1;
- /* SC */
- break;
- } else if (name && !strcasecmp(p->name, tmp)) {
- ast_log(LOG_DEBUG, "Coundn't determine subchannel, assuming current master %s@%s-%d\n",
- p->name, g->name, p->sub->id);
- sub = p->sub;
- found = 1;
- break;
- }
- p = p->next;
- }
- if (sub && found) {
- ast_mutex_lock(&sub->lock);
- break;
- }
- }
- g = g->next;
- }
- ast_mutex_unlock(&gatelock);
- if (!sub) {
- if (name) {
- if (g)
- ast_log(LOG_NOTICE, "Endpoint '%s' not found on gateway '%s'\n", tmp, at);
- else
- ast_log(LOG_NOTICE, "Gateway '%s' (and thus its endpoint '%s') does not exist\n", at, tmp);
- }
- }
- return sub;
-}
-
-static void parse(struct mgcp_request *req)
-{
- /* Divide fields by NULL's */
- char *c;
- int f = 0;
- c = req->data;
-
- /* First header starts immediately */
- req->header[f] = c;
- while(*c) {
- if (*c == '\n') {
- /* We've got a new header */
- *c = 0;
-#if 0
- printf("Header: %s (%d)\n", req->header[f], strlen(req->header[f]));
-#endif
- if (ast_strlen_zero(req->header[f])) {
- /* Line by itself means we're now in content */
- c++;
- break;
- }
- if (f >= MGCP_MAX_HEADERS - 1) {
- ast_log(LOG_WARNING, "Too many MGCP headers...\n");
- } else
- f++;
- req->header[f] = c + 1;
- } else if (*c == '\r') {
- /* Ignore but eliminate \r's */
- *c = 0;
- }
- c++;
- }
- /* Check for last header */
- if (!ast_strlen_zero(req->header[f]))
- f++;
- req->headers = f;
- /* Now we process any mime content */
- f = 0;
- req->line[f] = c;
- while(*c) {
- if (*c == '\n') {
- /* We've got a new line */
- *c = 0;
-#if 0
- printf("Line: %s (%d)\n", req->line[f], strlen(req->line[f]));
-#endif
- if (f >= MGCP_MAX_LINES - 1) {
- ast_log(LOG_WARNING, "Too many SDP lines...\n");
- } else
- f++;
- req->line[f] = c + 1;
- } else if (*c == '\r') {
- /* Ignore and eliminate \r's */
- *c = 0;
- }
- c++;
- }
- /* Check for last line */
- if (!ast_strlen_zero(req->line[f]))
- f++;
- req->lines = f;
- /* Parse up the initial header */
- c = req->header[0];
- while(*c && *c < 33) c++;
- /* First the verb */
- req->verb = c;
- while(*c && (*c > 32)) c++;
- if (*c) {
- *c = '\0';
- c++;
- while(*c && (*c < 33)) c++;
- req->identifier = c;
- while(*c && (*c > 32)) c++;
- if (*c) {
- *c = '\0';
- c++;
- while(*c && (*c < 33)) c++;
- req->endpoint = c;
- while(*c && (*c > 32)) c++;
- if (*c) {
- *c = '\0';
- c++;
- while(*c && (*c < 33)) c++;
- req->version = c;
- while(*c && (*c > 32)) c++;
- while(*c && (*c < 33)) c++;
- while(*c && (*c > 32)) c++;
- *c = '\0';
- }
- }
- }
-
- if (mgcpdebug) {
- ast_verbose("Verb: '%s', Identifier: '%s', Endpoint: '%s', Version: '%s'\n",
- req->verb, req->identifier, req->endpoint, req->version);
- ast_verbose("%d headers, %d lines\n", req->headers, req->lines);
- }
- if (*c)
- ast_log(LOG_WARNING, "Odd content, extra stuff left over ('%s')\n", c);
-}
-
-static int process_sdp(struct mgcp_subchannel *sub, struct mgcp_request *req)
-{
- char *m;
- char *c;
- char *a;
- char host[258];
- int len;
- int portno;
- int peercapability, peerNonCodecCapability;
- struct sockaddr_in sin;
- char *codecs;
- struct ast_hostent ahp; struct hostent *hp;
- int codec, codec_count=0;
- int iterator;
- struct mgcp_endpoint *p = sub->parent;
-
- /* Get codec and RTP info from SDP */
- m = get_sdp(req, "m");
- c = get_sdp(req, "c");
- if (ast_strlen_zero(m) || ast_strlen_zero(c)) {
- ast_log(LOG_WARNING, "Insufficient information for SDP (m = '%s', c = '%s')\n", m, c);
- return -1;
- }
- if (sscanf(c, "IN IP4 %256s", host) != 1) {
- ast_log(LOG_WARNING, "Invalid host in c= line, '%s'\n", c);
- return -1;
- }
- /* XXX This could block for a long time, and block the main thread! XXX */
- hp = ast_gethostbyname(host, &ahp);
- if (!hp) {
- ast_log(LOG_WARNING, "Unable to lookup host in c= line, '%s'\n", c);
- return -1;
- }
- if (sscanf(m, "audio %d RTP/AVP %n", &portno, &len) != 1) {
- ast_log(LOG_WARNING, "Unable to determine port number for RTP in '%s'\n", m);
- return -1;
- }
- sin.sin_family = AF_INET;
- memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
- sin.sin_port = htons(portno);
- ast_rtp_set_peer(sub->rtp, &sin);
-#if 0
- printf("Peer RTP is at port %s:%d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
-#endif
- /* Scan through the RTP payload types specified in a "m=" line: */
- ast_rtp_pt_clear(sub->rtp);
- codecs = ast_strdupa(m + len);
- while (!ast_strlen_zero(codecs)) {
- if (sscanf(codecs, "%d%n", &codec, &len) != 1) {
- if (codec_count)
- break;
- ast_log(LOG_WARNING, "Error in codec string '%s' at '%s'\n", m, codecs);
- return -1;
- }
- ast_rtp_set_m_type(sub->rtp, codec);
- codec_count++;
- codecs += len;
- }
-
- /* Next, scan through each "a=rtpmap:" line, noting each */
- /* specified RTP payload type (with corresponding MIME subtype): */
- sdpLineNum_iterator_init(&iterator);
- while ((a = get_sdp_iterate(&iterator, req, "a"))[0] != '\0') {
- char* mimeSubtype = ast_strdupa(a); /* ensures we have enough space */
- if (sscanf(a, "rtpmap: %u %[^/]/", &codec, mimeSubtype) != 2)
- continue;
- /* Note: should really look at the 'freq' and '#chans' params too */
- ast_rtp_set_rtpmap_type(sub->rtp, codec, "audio", mimeSubtype, 0);
- }
-
- /* Now gather all of the codecs that were asked for: */
- ast_rtp_get_current_formats(sub->rtp, &peercapability, &peerNonCodecCapability);
- p->capability = capability & peercapability;
- if (mgcpdebug) {
- ast_verbose("Capabilities: us - %d, them - %d, combined - %d\n",
- capability, peercapability, p->capability);
- ast_verbose("Non-codec capabilities: us - %d, them - %d, combined - %d\n",
- nonCodecCapability, peerNonCodecCapability, p->nonCodecCapability);
- }
- if (!p->capability) {
- ast_log(LOG_WARNING, "No compatible codecs!\n");
- return -1;
- }
- return 0;
-}
-
-static int add_header(struct mgcp_request *req, char *var, char *value)
-{
- if (req->len >= sizeof(req->data) - 4) {
- ast_log(LOG_WARNING, "Out of space, can't add anymore\n");
- return -1;
- }
- if (req->lines) {
- ast_log(LOG_WARNING, "Can't add more headers when lines have been added\n");
- return -1;
- }
- req->header[req->headers] = req->data + req->len;
- snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s: %s\r\n", var, value);
- req->len += strlen(req->header[req->headers]);
- if (req->headers < MGCP_MAX_HEADERS)
- req->headers++;
- else {
- ast_log(LOG_WARNING, "Out of header space\n");
- return -1;
- }
- return 0;
-}
-
-static int add_line(struct mgcp_request *req, char *line)
-{
- if (req->len >= sizeof(req->data) - 4) {
- ast_log(LOG_WARNING, "Out of space, can't add anymore\n");
- return -1;
- }
- if (!req->lines) {
- /* Add extra empty return */
- snprintf(req->data + req->len, sizeof(req->data) - req->len, "\r\n");
- req->len += strlen(req->data + req->len);
- }
- req->line[req->lines] = req->data + req->len;
- snprintf(req->line[req->lines], sizeof(req->data) - req->len, "%s", line);
- req->len += strlen(req->line[req->lines]);
- if (req->lines < MGCP_MAX_LINES)
- req->lines++;
- else {
- ast_log(LOG_WARNING, "Out of line space\n");
- return -1;
- }
- return 0;
-}
-
-static int init_resp(struct mgcp_request *req, char *resp, struct mgcp_request *orig, char *resprest)
-{
- /* Initialize a response */
- if (req->headers || req->len) {
- ast_log(LOG_WARNING, "Request already initialized?!?\n");
- return -1;
- }
- req->header[req->headers] = req->data + req->len;
- snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s %s %s\r\n", resp, orig->identifier, resprest);
- req->len += strlen(req->header[req->headers]);
- if (req->headers < MGCP_MAX_HEADERS)
- req->headers++;
- else
- ast_log(LOG_WARNING, "Out of header space\n");
- return 0;
-}
-
-static int init_req(struct mgcp_endpoint *p, struct mgcp_request *req, char *verb)
-{
- /* Initialize a response */
- if (req->headers || req->len) {
- ast_log(LOG_WARNING, "Request already initialized?!?\n");
- return -1;
- }
- req->header[req->headers] = req->data + req->len;
- /* check if we need brackets around the gw name */
- if (p->parent->isnamedottedip)
- snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s %d %s@[%s] MGCP 1.0\r\n", verb, oseq, p->name, p->parent->name);
- else
- snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s %d %s@%s MGCP 1.0\r\n", verb, oseq, p->name, p->parent->name);
- req->len += strlen(req->header[req->headers]);
- if (req->headers < MGCP_MAX_HEADERS)
- req->headers++;
- else
- ast_log(LOG_WARNING, "Out of header space\n");
- return 0;
-}
-
-
-static int respprep(struct mgcp_request *resp, struct mgcp_endpoint *p, char *msg, struct mgcp_request *req, char *msgrest)
-{
- memset(resp, 0, sizeof(*resp));
- init_resp(resp, msg, req, msgrest);
- return 0;
-}
-
-static int reqprep(struct mgcp_request *req, struct mgcp_endpoint *p, char *verb)
-{
- memset(req, 0, sizeof(struct mgcp_request));
- oseq++;
- if (oseq > 999999999)
- oseq = 1;
- init_req(p, req, verb);
- return 0;
-}
-
-static int transmit_response(struct mgcp_subchannel *sub, char *msg, struct mgcp_request *req, char *msgrest)
-{
- struct mgcp_request resp;
- struct mgcp_endpoint *p = sub->parent;
- struct mgcp_response *mgr;
-
- respprep(&resp, p, msg, req, msgrest);
- mgr = malloc(sizeof(struct mgcp_response) + resp.len + 1);
- if (mgr) {
- /* Store MGCP response in case we have to retransmit */
- memset(mgr, 0, sizeof(struct mgcp_response));
- sscanf(req->identifier, "%d", &mgr->seqno);
- time(&mgr->whensent);
- mgr->len = resp.len;
- memcpy(mgr->buf, resp.data, resp.len);
- mgr->buf[resp.len] = '\0';
- mgr->next = p->parent->responses;
- p->parent->responses = mgr;
- }
- return send_response(sub, &resp);
-}
-
-
-static int add_sdp(struct mgcp_request *resp, struct mgcp_subchannel *sub, struct ast_rtp *rtp)
-{
- int len;
- int codec;
- char costr[80];
- struct sockaddr_in sin;
- char v[256];
- char s[256];
- char o[256];
- char c[256];
- char t[256];
- char m[256] = "";
- char a[1024] = "";
- int x;
- struct sockaddr_in dest;
- struct mgcp_endpoint *p = sub->parent;
- /* XXX We break with the "recommendation" and send our IP, in order that our
- peer doesn't have to ast_gethostbyname() us XXX */
- len = 0;
- if (!sub->rtp) {
- ast_log(LOG_WARNING, "No way to add SDP without an RTP structure\n");
- return -1;
- }
- ast_rtp_get_us(sub->rtp, &sin);
- if (rtp) {
- ast_rtp_get_peer(rtp, &dest);
- } else {
- if (sub->tmpdest.sin_addr.s_addr) {
- dest.sin_addr = sub->tmpdest.sin_addr;
- dest.sin_port = sub->tmpdest.sin_port;
- /* Reset temporary destination */
- memset(&sub->tmpdest, 0, sizeof(sub->tmpdest));
- } else {
- dest.sin_addr = p->parent->ourip;
- dest.sin_port = sin.sin_port;
- }
- }
- if (mgcpdebug) {
- ast_verbose("We're at %s port %d\n", ast_inet_ntoa(p->parent->ourip), ntohs(sin.sin_port));
- }
- snprintf(v, sizeof(v), "v=0\r\n");
- snprintf(o, sizeof(o), "o=root %d %d IN IP4 %s\r\n", (int)getpid(), (int)getpid(), ast_inet_ntoa(dest.sin_addr));
- snprintf(s, sizeof(s), "s=session\r\n");
- snprintf(c, sizeof(c), "c=IN IP4 %s\r\n", ast_inet_ntoa(dest.sin_addr));
- snprintf(t, sizeof(t), "t=0 0\r\n");
- snprintf(m, sizeof(m), "m=audio %d RTP/AVP", ntohs(dest.sin_port));
- for (x = 1; x <= AST_FORMAT_MAX_AUDIO; x <<= 1) {
- if (p->capability & x) {
- if (mgcpdebug) {
- ast_verbose("Answering with capability %d\n", x);
- }
- codec = ast_rtp_lookup_code(sub->rtp, 1, x);
- if (codec > -1) {
- snprintf(costr, sizeof(costr), " %d", codec);
- strncat(m, costr, sizeof(m) - strlen(m) - 1);
- snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, ast_rtp_lookup_mime_subtype(1, x, 0));
- strncat(a, costr, sizeof(a) - strlen(a) - 1);
- }
- }
- }
- for (x = 1; x <= AST_RTP_MAX; x <<= 1) {
- if (p->nonCodecCapability & x) {
- if (mgcpdebug) {
- ast_verbose("Answering with non-codec capability %d\n", x);
- }
- codec = ast_rtp_lookup_code(sub->rtp, 0, x);
- if (codec > -1) {
- snprintf(costr, sizeof(costr), " %d", codec);
- strncat(m, costr, sizeof(m) - strlen(m) - 1);
- snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, ast_rtp_lookup_mime_subtype(0, x, 0));
- strncat(a, costr, sizeof(a) - strlen(a) - 1);
- if (x == AST_RTP_DTMF) {
- /* Indicate we support DTMF... Not sure about 16,
- but MSN supports it so dang it, we will too... */
- snprintf(costr, sizeof costr, "a=fmtp:%d 0-16\r\n", codec);
- strncat(a, costr, sizeof(a) - strlen(a) - 1);
- }
- }
- }
- }
- strncat(m, "\r\n", sizeof(m) - strlen(m) - 1);
- len = strlen(v) + strlen(s) + strlen(o) + strlen(c) + strlen(t) + strlen(m) + strlen(a);
- snprintf(costr, sizeof(costr), "%d", len);
- add_line(resp, v);
- add_line(resp, o);
- add_line(resp, s);
- add_line(resp, c);
- add_line(resp, t);
- add_line(resp, m);
- add_line(resp, a);
- return 0;
-}
-
-static int transmit_modify_with_sdp(struct mgcp_subchannel *sub, struct ast_rtp *rtp, int codecs)
-{
- struct mgcp_request resp;
- char local[256];
- char tmp[80];
- int x;
- int capability;
- struct mgcp_endpoint *p = sub->parent;
-
- capability = p->capability;
- if (codecs)
- capability = codecs;
- if (ast_strlen_zero(sub->cxident) && rtp) {
- /* We don't have a CXident yet, store the destination and
- wait a bit */
- ast_rtp_get_peer(rtp, &sub->tmpdest);
- return 0;
- }
- snprintf(local, sizeof(local), "p:20");
- for (x=1;x<= AST_FORMAT_MAX_AUDIO; x <<= 1) {
- if (p->capability & x) {
- snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype(1, x, 0));
- strncat(local, tmp, sizeof(local) - strlen(local) - 1);
- }
- }
- reqprep(&resp, p, "MDCX");
- add_header(&resp, "C", sub->callid);
- add_header(&resp, "L", local);
- add_header(&resp, "M", mgcp_cxmodes[sub->cxmode]);
- /* X header should not be sent. kept for compatibility */
- add_header(&resp, "X", sub->txident);
- add_header(&resp, "I", sub->cxident);
- /*add_header(&resp, "S", "");*/
- add_sdp(&resp, sub, rtp);
- /* fill in new fields */
- resp.cmd = MGCP_CMD_MDCX;
- resp.trid = oseq;
- return send_request(p, sub, &resp, oseq); /* SC */
-}
-
-static int transmit_connect_with_sdp(struct mgcp_subchannel *sub, struct ast_rtp *rtp)
-{
- struct mgcp_request resp;
- char local[256];
- char tmp[80];
- int x;
- struct mgcp_endpoint *p = sub->parent;
-
- snprintf(local, sizeof(local), "p:20");
- for (x=1;x<= AST_FORMAT_MAX_AUDIO; x <<= 1) {
- if (p->capability & x) {
- snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype(1, x, 0));
- strncat(local, tmp, sizeof(local) - strlen(local) - 1);
- }
- }
- if (mgcpdebug) {
- ast_verbose(VERBOSE_PREFIX_3 "Creating connection for %s@%s-%d in cxmode: %s callid: %s\n",
- p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode], sub->callid);
- }
- reqprep(&resp, p, "CRCX");
- add_header(&resp, "C", sub->callid);
- add_header(&resp, "L", local);
- add_header(&resp, "M", mgcp_cxmodes[sub->cxmode]);
- /* X header should not be sent. kept for compatibility */
- add_header(&resp, "X", sub->txident);
- /*add_header(&resp, "S", "");*/
- add_sdp(&resp, sub, rtp);
- /* fill in new fields */
- resp.cmd = MGCP_CMD_CRCX;
- resp.trid = oseq;
- return send_request(p, sub, &resp, oseq); /* SC */
-}
-
-static int transmit_notify_request(struct mgcp_subchannel *sub, char *tone)
-{
- struct mgcp_request resp;
- struct mgcp_endpoint *p = sub->parent;
-
- if (mgcpdebug) {
- ast_verbose(VERBOSE_PREFIX_3 "MGCP Asked to indicate tone: %s on %s@%s-%d in cxmode: %s\n",
- tone, p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode]);
- }
- ast_copy_string(p->curtone, tone, sizeof(p->curtone));
- reqprep(&resp, p, "RQNT");
- add_header(&resp, "X", p->rqnt_ident); /* SC */
- switch (p->hookstate) {
- case MGCP_ONHOOK:
- add_header(&resp, "R", "L/hd(N)");
- break;
- case MGCP_OFFHOOK:
- add_header_offhook(sub, &resp);
- break;
- }
- if (!ast_strlen_zero(tone)) {
- add_header(&resp, "S", tone);
- }
- /* fill in new fields */
- resp.cmd = MGCP_CMD_RQNT;
- resp.trid = oseq;
- return send_request(p, NULL, &resp, oseq); /* SC */
-}
-
-static int transmit_notify_request_with_callerid(struct mgcp_subchannel *sub, char *tone, char *callernum, char *callername)
-{
- struct mgcp_request resp;
- char tone2[256];
- char *l, *n;
- time_t t;
- struct tm tm;
- struct mgcp_endpoint *p = sub->parent;
-
- time(&t);
- ast_localtime(&t, &tm, NULL);
- n = callername;
- l = callernum;
- if (!n)
- n = "";
- if (!l)
- l = "";
-
- /* Keep track of last callerid for blacklist and callreturn */
- ast_copy_string(p->lastcallerid, l, sizeof(p->lastcallerid));
-
- snprintf(tone2, sizeof(tone2), "%s,L/ci(%02d/%02d/%02d/%02d,%s,%s)", tone,
- tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, l, n);
- ast_copy_string(p->curtone, tone, sizeof(p->curtone));
- reqprep(&resp, p, "RQNT");
- add_header(&resp, "X", p->rqnt_ident); /* SC */
- switch (p->hookstate) {
- case MGCP_ONHOOK:
- add_header(&resp, "R", "L/hd(N)");
- break;
- case MGCP_OFFHOOK:
- add_header_offhook(sub, &resp);
- break;
- }
- if (!ast_strlen_zero(tone2)) {
- add_header(&resp, "S", tone2);
- }
- if (mgcpdebug) {
- ast_verbose(VERBOSE_PREFIX_3 "MGCP Asked to indicate tone: %s on %s@%s-%d in cxmode: %s\n",
- tone2, p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode]);
- }
- /* fill in new fields */
- resp.cmd = MGCP_CMD_RQNT;
- resp.trid = oseq;
- return send_request(p, NULL, &resp, oseq); /* SC */
-}
-
-static int transmit_modify_request(struct mgcp_subchannel *sub)
-{
- struct mgcp_request resp;
- struct mgcp_endpoint *p = sub->parent;
-
- if (ast_strlen_zero(sub->cxident)) {
- /* We don't have a CXident yet, store the destination and
- wait a bit */
- return 0;
- }
- if (mgcpdebug) {
- ast_verbose(VERBOSE_PREFIX_3 "Modified %s@%s-%d with new mode: %s on callid: %s\n",
- p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode], sub->callid);
- }
- reqprep(&resp, p, "MDCX");
- add_header(&resp, "C", sub->callid);
- add_header(&resp, "M", mgcp_cxmodes[sub->cxmode]);
- /* X header should not be sent. kept for compatibility */
- add_header(&resp, "X", sub->txident);
- add_header(&resp, "I", sub->cxident);
- switch (sub->parent->hookstate) {
- case MGCP_ONHOOK:
- add_header(&resp, "R", "L/hd(N)");
- break;
- case MGCP_OFFHOOK:
- add_header_offhook(sub, &resp);
- break;
- }
- /* fill in new fields */
- resp.cmd = MGCP_CMD_MDCX;
- resp.trid = oseq;
- return send_request(p, sub, &resp, oseq); /* SC */
-}
-
-
-static void add_header_offhook(struct mgcp_subchannel *sub, struct mgcp_request *resp)
-{
- struct mgcp_endpoint *p = sub->parent;
-
- if (p && p->sub && p->sub->owner && p->sub->owner->_state >= AST_STATE_RINGING && (p->dtmfmode & (MGCP_DTMF_INBAND | MGCP_DTMF_HYBRID)))
- add_header(resp, "R", "L/hu(N),L/hf(N)");
- else
- add_header(resp, "R", "L/hu(N),L/hf(N),D/[0-9#*](N)");
-}
-
-static int transmit_audit_endpoint(struct mgcp_endpoint *p)
-{
- struct mgcp_request resp;
- reqprep(&resp, p, "AUEP");
- /* removed unknown param VS */
- /*add_header(&resp, "F", "A,R,D,S,X,N,I,T,O,ES,E,MD,M");*/
- add_header(&resp, "F", "A");
- /* fill in new fields */
- resp.cmd = MGCP_CMD_AUEP;
- resp.trid = oseq;
- return send_request(p, NULL, &resp, oseq); /* SC */
-}
-
-static int transmit_connection_del(struct mgcp_subchannel *sub)
-{
- struct mgcp_endpoint *p = sub->parent;
- struct mgcp_request resp;
-
- if (mgcpdebug) {
- ast_verbose(VERBOSE_PREFIX_3 "Delete connection %s %s@%s-%d with new mode: %s on callid: %s\n",
- sub->cxident, p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode], sub->callid);
- }
- reqprep(&resp, p, "DLCX");
- /* check if call id is avail */
- if (sub->callid[0])
- add_header(&resp, "C", sub->callid);
- /* X header should not be sent. kept for compatibility */
- add_header(&resp, "X", sub->txident);
- /* check if cxident is avail */
- if (sub->cxident[0])
- add_header(&resp, "I", sub->cxident);
- /* fill in new fields */
- resp.cmd = MGCP_CMD_DLCX;
- resp.trid = oseq;
- return send_request(p, sub, &resp, oseq); /* SC */
-}
-
-static int transmit_connection_del_w_params(struct mgcp_endpoint *p, char *callid, char *cxident)
-{
- struct mgcp_request resp;
-
- if (mgcpdebug) {
- ast_verbose(VERBOSE_PREFIX_3 "Delete connection %s %s@%s on callid: %s\n",
- cxident ? cxident : "", p->name, p->parent->name, callid ? callid : "");
- }
- reqprep(&resp, p, "DLCX");
- /* check if call id is avail */
- if (callid && *callid)
- add_header(&resp, "C", callid);
- /* check if cxident is avail */
- if (cxident && *cxident)
- add_header(&resp, "I", cxident);
- /* fill in new fields */
- resp.cmd = MGCP_CMD_DLCX;
- resp.trid = oseq;
- return send_request(p, p->sub, &resp, oseq);
-}
-
-/*! \brief dump_cmd_queues: (SC:) cleanup pending commands */
-static void dump_cmd_queues(struct mgcp_endpoint *p, struct mgcp_subchannel *sub)
-{
- struct mgcp_request *t, *q;
-
- if (p) {
- ast_mutex_lock(&p->rqnt_queue_lock);
- for (q = p->rqnt_queue; q; t = q->next, free(q), q=t);
- p->rqnt_queue = NULL;
- ast_mutex_unlock(&p->rqnt_queue_lock);
-
- ast_mutex_lock(&p->cmd_queue_lock);
- for (q = p->cmd_queue; q; t = q->next, free(q), q=t);
- p->cmd_queue = NULL;
- ast_mutex_unlock(&p->cmd_queue_lock);
-
- ast_mutex_lock(&p->sub->cx_queue_lock);
- for (q = p->sub->cx_queue; q; t = q->next, free(q), q=t);
- p->sub->cx_queue = NULL;
- ast_mutex_unlock(&p->sub->cx_queue_lock);
-
- ast_mutex_lock(&p->sub->next->cx_queue_lock);
- for (q = p->sub->next->cx_queue; q; t = q->next, free(q), q=t);
- p->sub->next->cx_queue = NULL;
- ast_mutex_unlock(&p->sub->next->cx_queue_lock);
- } else if (sub) {
- ast_mutex_lock(&sub->cx_queue_lock);
- for (q = sub->cx_queue; q; t = q->next, free(q), q=t);
- sub->cx_queue = NULL;
- ast_mutex_unlock(&sub->cx_queue_lock);
- }
-}
-
-
-/*! \brief find_command: (SC:) remove command transaction from queue */
-static struct mgcp_request *find_command(struct mgcp_endpoint *p, struct mgcp_subchannel *sub,
- struct mgcp_request **queue, ast_mutex_t *l, int ident)
-{
- struct mgcp_request *prev, *req;
-
- ast_mutex_lock(l);
- for (prev = NULL, req = *queue; req; prev = req, req = req->next) {
- if (req->trid == ident) {
- /* remove from queue */
- if (!prev)
- *queue = req->next;
- else
- prev->next = req->next;
-
- /* send next pending command */
- if (*queue) {
- if (mgcpdebug) {
- ast_verbose("Posting Queued Request:\n%s to %s:%d\n", (*queue)->data,
- ast_inet_ntoa(p->parent->addr.sin_addr), ntohs(p->parent->addr.sin_port));
- }
-
- mgcp_postrequest(p, sub, (*queue)->data, (*queue)->len, (*queue)->trid);
- }
- break;
- }
- }
- ast_mutex_unlock(l);
- return req;
-}
-
-/* modified for new transport mechanism */
-static void handle_response(struct mgcp_endpoint *p, struct mgcp_subchannel *sub,
- int result, unsigned int ident, struct mgcp_request *resp)
-{
- char *c;
- struct mgcp_request *req;
- struct mgcp_gateway *gw = p->parent;
-
- if (result < 200) {
- /* provisional response */
- return;
- }
-
- if (p->slowsequence)
- req = find_command(p, sub, &p->cmd_queue, &p->cmd_queue_lock, ident);
- else if (sub)
- req = find_command(p, sub, &sub->cx_queue, &sub->cx_queue_lock, ident);
- else if (!(req = find_command(p, sub, &p->rqnt_queue, &p->rqnt_queue_lock, ident)))
- req = find_command(p, sub, &p->cmd_queue, &p->cmd_queue_lock, ident);
-
- if (!req) {
- if (option_verbose > 2) {
- ast_verbose(VERBOSE_PREFIX_3 "No command found on [%s] for transaction %d. Ignoring...\n",
- gw->name, ident);
- }
- return;
- }
-
- if (p && (result >= 400) && (result <= 599)) {
- switch (result) {
- case 401:
- p->hookstate = MGCP_OFFHOOK;
- break;
- case 402:
- p->hookstate = MGCP_ONHOOK;
- break;
- case 406:
- ast_log(LOG_NOTICE, "Transaction %d timed out\n", ident);
- break;
- case 407:
- ast_log(LOG_NOTICE, "Transaction %d aborted\n", ident);
- break;
- }
- if (sub) {
- if (sub->owner) {
- ast_log(LOG_NOTICE, "Terminating on result %d from %s@%s-%d\n",
- result, p->name, p->parent->name, sub ? sub->id:-1);
- mgcp_queue_hangup(sub);
- }
- } else {
- if (p->sub->next->owner) {
- ast_log(LOG_NOTICE, "Terminating on result %d from %s@%s-%d\n",
- result, p->name, p->parent->name, sub ? sub->id:-1);
- mgcp_queue_hangup(p->sub);
- }
-
- if (p->sub->owner) {
- ast_log(LOG_NOTICE, "Terminating on result %d from %s@%s-%d\n",
- result, p->name, p->parent->name, sub ? sub->id:-1);
- mgcp_queue_hangup(p->sub);
- }
-
- dump_cmd_queues(p, NULL);
- }
- }
-
- if (resp) {
- if (req->cmd == MGCP_CMD_CRCX) {
- if ((c = get_header(resp, "I"))) {
- if (!ast_strlen_zero(c) && sub) {
- /* if we are hanging up do not process this conn. */
- if (sub->owner) {
- if (!ast_strlen_zero(sub->cxident)) {
- if (strcasecmp(c, sub->cxident)) {
- ast_log(LOG_WARNING, "Subchannel already has a cxident. sub->cxident: %s requested %s\n", sub->cxident, c);
- }
- }
- ast_copy_string(sub->cxident, c, sizeof(sub->cxident));
- if (sub->tmpdest.sin_addr.s_addr) {
- transmit_modify_with_sdp(sub, NULL, 0);
- }
- } else {
- /* XXX delete this one
- callid and conn id may already be lost.
- so the following del conn may have a side effect of
- cleaning up the next subchannel */
- transmit_connection_del(sub);
- }
- }
- }
- }
-
- if (req->cmd == MGCP_CMD_AUEP) {
- /* check stale connection ids */
- if ((c = get_header(resp, "I"))) {
- char *v, *n;
- int len;
- while ((v = get_csv(c, &len, &n))) {
- if (len) {
- if (strncasecmp(v, p->sub->cxident, len) &&
- strncasecmp(v, p->sub->next->cxident, len)) {
- /* connection id not found. delete it */
- char cxident[80] = "";
-
- if (len > (sizeof(cxident) - 1))
- len = sizeof(cxident) - 1;
- ast_copy_string(cxident, v, len);
- if (option_verbose > 2) {
- ast_verbose(VERBOSE_PREFIX_3 "Non existing connection id %s on %s@%s \n",
- cxident, p->name, gw->name);
- }
- transmit_connection_del_w_params(p, NULL, cxident);
- }
- }
- c = n;
- }
- }
-
- /* Try to determine the hookstate returned from an audit endpoint command */
- if ((c = get_header(resp, "ES"))) {
- if (!ast_strlen_zero(c)) {
- if (strstr(c, "hu")) {
- if (p->hookstate != MGCP_ONHOOK) {
- /* XXX cleanup if we think we are offhook XXX */
- if ((p->sub->owner || p->sub->next->owner ) &&
- p->hookstate == MGCP_OFFHOOK)
- mgcp_queue_hangup(sub);
- p->hookstate = MGCP_ONHOOK;
-
- /* update the requested events according to the new hookstate */
- transmit_notify_request(p->sub, "");
-
- /* verbose level check */
- if (option_verbose > 2) {
- ast_verbose(VERBOSE_PREFIX_3 "Setting hookstate of %s@%s to ONHOOK\n", p->name, gw->name);
- }
- }
- } else if (strstr(c, "hd")) {
- if (p->hookstate != MGCP_OFFHOOK) {
- p->hookstate = MGCP_OFFHOOK;
-
- /* update the requested events according to the new hookstate */
- transmit_notify_request(p->sub, "");
-
- /* verbose level check */
- if (option_verbose > 2) {
- ast_verbose(VERBOSE_PREFIX_3 "Setting hookstate of %s@%s to OFFHOOK\n", p->name, gw->name);
- }
- }
- }
- }
- }
- }
-
- if (resp && resp->lines) {
- /* do not process sdp if we are hanging up. this may be a late response */
- if (sub && sub->owner) {
- if (!sub->rtp)
- start_rtp(sub);
- if (sub->rtp)
- process_sdp(sub, resp);
- }
- }
- }
-
- free(req);
-}
-
-static void start_rtp(struct mgcp_subchannel *sub)
-{
- ast_mutex_lock(&sub->lock);
- /* check again to be on the safe side */
- if (sub->rtp) {
- ast_rtp_destroy(sub->rtp);
- sub->rtp = NULL;
- }
- /* Allocate the RTP now */
- sub->rtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr);
- if (sub->rtp && sub->owner)
- sub->owner->fds[0] = ast_rtp_fd(sub->rtp);
- if (sub->rtp)
- ast_rtp_setnat(sub->rtp, sub->nat);
-#if 0
- ast_rtp_set_callback(p->rtp, rtpready);
- ast_rtp_set_data(p->rtp, p);
-#endif
- /* Make a call*ID */
- snprintf(sub->callid, sizeof(sub->callid), "%08lx%s", ast_random(), sub->txident);
- /* Transmit the connection create */
- transmit_connect_with_sdp(sub, NULL);
- ast_mutex_unlock(&sub->lock);
-}
-
-static void *mgcp_ss(void *data)
-{
- struct ast_channel *chan = data;
- struct mgcp_subchannel *sub = chan->tech_pvt;
- struct mgcp_endpoint *p = sub->parent;
- /* char exten[AST_MAX_EXTENSION] = ""; */
- int len = 0;
- int timeout = firstdigittimeout;
- int res= 0;
- int getforward = 0;
- int loop_pause = 100;
-
- len = strlen(p->dtmf_buf);
-
- while(len < AST_MAX_EXTENSION-1) {
- res = 1; /* Assume that we will get a digit */
- while (strlen(p->dtmf_buf) == len){
- ast_safe_sleep(chan, loop_pause);
- timeout -= loop_pause;
- if (timeout <= 0){
- res = 0;
- break;
- }
- res = 1;
- }
-
- timeout = 0;
- len = strlen(p->dtmf_buf);
-
- if (!ast_ignore_pattern(chan->context, p->dtmf_buf)) {
- /*res = tone_zone_play_tone(p->subs[index].zfd, -1);*/
- ast_indicate(chan, -1);
- } else {
- /* XXX Redundant? We should already be playing dialtone */
- /*tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALTONE);*/
- transmit_notify_request(sub, "L/dl");
- }
- if (ast_exists_extension(chan, chan->context, p->dtmf_buf, 1, p->cid_num)) {
- if (!res || !ast_matchmore_extension(chan, chan->context, p->dtmf_buf, 1, p->cid_num)) {
- if (getforward) {
- /* Record this as the forwarding extension */
- ast_copy_string(p->call_forward, p->dtmf_buf, sizeof(p->call_forward));
- if (option_verbose > 2) {
- ast_verbose(VERBOSE_PREFIX_3 "Setting call forward to '%s' on channel %s\n",
- p->call_forward, chan->name);
- }
- /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
- transmit_notify_request(sub, "L/sl");
- if (res)
- break;
- usleep(500000);
- /*res = tone_zone_play_tone(p->subs[index].zfd, -1);*/
- ast_indicate(chan, -1);
- sleep(1);
- memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
- /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALTONE);*/
- transmit_notify_request(sub, "L/dl");
- len = 0;
- getforward = 0;
- } else {
- /*res = tone_zone_play_tone(p->subs[index].zfd, -1);*/
- ast_indicate(chan, -1);
- ast_copy_string(chan->exten, p->dtmf_buf, sizeof(chan->exten));
- memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
- ast_set_callerid(chan,
- p->hidecallerid ? "" : p->cid_num,
- p->hidecallerid ? "" : p->cid_name,
- chan->cid.cid_ani ? NULL : p->cid_num);
- ast_setstate(chan, AST_STATE_RING);
- /*zt_enable_ec(p);*/
- if (p->dtmfmode & MGCP_DTMF_HYBRID) {
- p->dtmfmode |= MGCP_DTMF_INBAND;
- ast_indicate(chan, -1);
- }
- res = ast_pbx_run(chan);
- if (res) {
- ast_log(LOG_WARNING, "PBX exited non-zero\n");
- /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_CONGESTION);*/
- /*transmit_notify_request(p, "nbz", 1);*/
- transmit_notify_request(sub, "G/cg");
- }
- return NULL;
- }
- } else {
- /* It's a match, but they just typed a digit, and there is an ambiguous match,
- so just set the timeout to matchdigittimeout and wait some more */
- timeout = matchdigittimeout;
- }
- } else if (res == 0) {
- ast_log(LOG_DEBUG, "not enough digits (and no ambiguous match)...\n");
- /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_CONGESTION);*/
- transmit_notify_request(sub, "G/cg");
- /*zt_wait_event(p->subs[index].zfd);*/
- ast_hangup(chan);
- memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
- return NULL;
- } else if (p->hascallwaiting && p->callwaiting && !strcmp(p->dtmf_buf, "*70")) {
- if (option_verbose > 2) {
- ast_verbose(VERBOSE_PREFIX_3 "Disabling call waiting on %s\n", chan->name);
- }
- /* Disable call waiting if enabled */
- p->callwaiting = 0;
- /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
- transmit_notify_request(sub, "L/sl");
- len = 0;
- memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
- timeout = firstdigittimeout;
- } else if (!strcmp(p->dtmf_buf,ast_pickup_ext())) {
- /* Scan all channels and see if any there
- * ringing channqels with that have call groups
- * that equal this channels pickup group
- */
- if (ast_pickup_call(chan)) {
- ast_log(LOG_WARNING, "No call pickup possible...\n");
- /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_CONGESTION);*/
- transmit_notify_request(sub, "G/cg");
- }
- memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
- ast_hangup(chan);
- return NULL;
- } else if (!p->hidecallerid && !strcmp(p->dtmf_buf, "*67")) {
- if (option_verbose > 2) {
- ast_verbose(VERBOSE_PREFIX_3 "Disabling Caller*ID on %s\n", chan->name);
- }
- /* Disable Caller*ID if enabled */
- p->hidecallerid = 1;
- ast_set_callerid(chan, "", "", NULL);
- /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
- transmit_notify_request(sub, "L/sl");
- len = 0;
- memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
- timeout = firstdigittimeout;
- } else if (p->callreturn && !strcmp(p->dtmf_buf, "*69")) {
- res = 0;
- if (!ast_strlen_zero(p->lastcallerid)) {
- res = ast_say_digit_str(chan, p->lastcallerid, "", chan->language);
- }
- if (!res)
- /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
- transmit_notify_request(sub, "L/sl");
- break;
- } else if (!strcmp(p->dtmf_buf, "*78")) {
- /* Do not disturb */
- if (option_verbose > 2) {
- ast_verbose(VERBOSE_PREFIX_3 "Enabled DND on channel %s\n", chan->name);
- }
- /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
- transmit_notify_request(sub, "L/sl");
- p->dnd = 1;
- getforward = 0;
- memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
- len = 0;
- } else if (!strcmp(p->dtmf_buf, "*79")) {
- /* Do not disturb */
- if (option_verbose > 2) {
- ast_verbose(VERBOSE_PREFIX_3 "Disabled DND on channel %s\n", chan->name);
- }
- /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
- transmit_notify_request(sub, "L/sl");
- p->dnd = 0;
- getforward = 0;
- memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
- len = 0;
- } else if (p->cancallforward && !strcmp(p->dtmf_buf, "*72")) {
- /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
- transmit_notify_request(sub, "L/sl");
- getforward = 1;
- memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
- len = 0;
- } else if (p->cancallforward && !strcmp(p->dtmf_buf, "*73")) {
- if (option_verbose > 2) {
- ast_verbose(VERBOSE_PREFIX_3 "Cancelling call forwarding on channel %s\n", chan->name);
- }
- /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
- transmit_notify_request(sub, "L/sl");
- memset(p->call_forward, 0, sizeof(p->call_forward));
- getforward = 0;
- memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
- len = 0;
- } else if (!strcmp(p->dtmf_buf, ast_parking_ext()) &&
- sub->next->owner && ast_bridged_channel(sub->next->owner)) {
- /* This is a three way call, the main call being a real channel,
- and we're parking the first call. */
- ast_masq_park_call(ast_bridged_channel(sub->next->owner), chan, 0, NULL);
- if (option_verbose > 2) {
- ast_verbose(VERBOSE_PREFIX_3 "Parking call to '%s'\n", chan->name);
- }
- break;
- } else if (!ast_strlen_zero(p->lastcallerid) && !strcmp(p->dtmf_buf, "*60")) {
- if (option_verbose > 2) {
- ast_verbose(VERBOSE_PREFIX_3 "Blacklisting number %s\n", p->lastcallerid);
- }
- res = ast_db_put("blacklist", p->lastcallerid, "1");
- if (!res) {
- /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
- transmit_notify_request(sub, "L/sl");
- memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
- len = 0;
- }
- } else if (p->hidecallerid && !strcmp(p->dtmf_buf, "*82")) {
- if (option_verbose > 2) {
- ast_verbose(VERBOSE_PREFIX_3 "Enabling Caller*ID on %s\n", chan->name);
- }
- /* Enable Caller*ID if enabled */
- p->hidecallerid = 0;
- ast_set_callerid(chan, p->cid_num, p->cid_name, NULL);
- /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
- transmit_notify_request(sub, "L/sl");
- len = 0;
- memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
- timeout = firstdigittimeout;
- } else if (!ast_canmatch_extension(chan, chan->context, p->dtmf_buf, 1, chan->cid.cid_num) &&
- ((p->dtmf_buf[0] != '*') || (strlen(p->dtmf_buf) > 2))) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Can't match %s from '%s' in context %s\n", p->dtmf_buf, chan->cid.cid_num ? chan->cid.cid_num : "<Unknown Caller>", chan->context);
- break;
- }
- if (!timeout)
- timeout = gendigittimeout;
- if (len && !ast_ignore_pattern(chan->context, p->dtmf_buf))
- /*tone_zone_play_tone(p->subs[index].zfd, -1);*/
- ast_indicate(chan, -1);
- }
-#if 0
- for (;;) {
- res = ast_waitfordigit(chan, to);
- if (!res) {
- ast_log(LOG_DEBUG, "Timeout...\n");
- break;
- }
- if (res < 0) {
- ast_log(LOG_DEBUG, "Got hangup...\n");
- ast_hangup(chan);
- break;
- }
- exten[pos++] = res;
- if (!ast_ignore_pattern(chan->context, exten))
- ast_indicate(chan, -1);
- if (ast_matchmore_extension(chan, chan->context, exten, 1, chan->callerid)) {
- if (ast_exists_extension(chan, chan->context, exten, 1, chan->callerid))
- to = 3000;
- else
- to = 8000;
- } else
- break;
- }
- if (ast_exists_extension(chan, chan->context, exten, 1, chan->callerid)) {
- ast_copy_string(chan->exten, exten, sizeof(chan->exten)1);
- if (!p->rtp) {
- start_rtp(p);
- }
- ast_setstate(chan, AST_STATE_RING);
- chan->rings = 1;
- if (ast_pbx_run(chan)) {
- ast_log(LOG_WARNING, "Unable to launch PBX on %s\n", chan->name);
- } else {
- memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
- return NULL;
- }
- }
-#endif
- ast_hangup(chan);
- memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
- return NULL;
-}
-
-static int attempt_transfer(struct mgcp_endpoint *p)
-{
- /* *************************
- * I hope this works.
- * Copied out of chan_zap
- * Cross your fingers
- * *************************/
-
- /* In order to transfer, we need at least one of the channels to
- actually be in a call bridge. We can't conference two applications
- together (but then, why would we want to?) */
- if (ast_bridged_channel(p->sub->owner)) {
- /* The three-way person we're about to transfer to could still be in MOH, so
- stop if now if appropriate */
- if (ast_bridged_channel(p->sub->next->owner))
- ast_queue_control(p->sub->next->owner, AST_CONTROL_UNHOLD);
- if (p->sub->owner->_state == AST_STATE_RINGING) {
- ast_indicate(ast_bridged_channel(p->sub->next->owner), AST_CONTROL_RINGING);
- }
- if (ast_channel_masquerade(p->sub->next->owner, ast_bridged_channel(p->sub->owner))) {
- ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
- ast_bridged_channel(p->sub->owner)->name, p->sub->next->owner->name);
- return -1;
- }
- /* Orphan the channel */
- unalloc_sub(p->sub->next);
- } else if (ast_bridged_channel(p->sub->next->owner)) {
- if (p->sub->owner->_state == AST_STATE_RINGING) {
- ast_indicate(ast_bridged_channel(p->sub->next->owner), AST_CONTROL_RINGING);
- }
- ast_queue_control(p->sub->next->owner, AST_CONTROL_UNHOLD);
- if (ast_channel_masquerade(p->sub->owner, ast_bridged_channel(p->sub->next->owner))) {
- ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
- ast_bridged_channel(p->sub->next->owner)->name, p->sub->owner->name);
- return -1;
- }
- /*swap_subs(p, SUB_THREEWAY, SUB_REAL);*/
- if (option_verbose > 2) {
- ast_verbose(VERBOSE_PREFIX_3 "Swapping %d for %d on %s@%s\n", p->sub->id, p->sub->next->id, p->name, p->parent->name);
- }
- p->sub = p->sub->next;
- unalloc_sub(p->sub->next);
- /* Tell the caller not to hangup */
- return 1;
- } else {
- ast_log(LOG_DEBUG, "Neither %s nor %s are in a bridge, nothing to transfer\n",
- p->sub->owner->name, p->sub->next->owner->name);
- p->sub->next->owner->_softhangup |= AST_SOFTHANGUP_DEV;
- if (p->sub->next->owner) {
- p->sub->next->alreadygone = 1;
- mgcp_queue_hangup(p->sub->next);
- }
- }
- return 0;
-}
-
-static void handle_hd_hf(struct mgcp_subchannel *sub, char *ev)
-{
- struct mgcp_endpoint *p = sub->parent;
- struct ast_channel *c;
- pthread_t t;
- pthread_attr_t attr;
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-
- /* Off hook / answer */
- if (sub->outgoing) {
- /* Answered */
- if (sub->owner) {
- if (ast_bridged_channel(sub->owner))
- ast_queue_control(sub->owner, AST_CONTROL_UNHOLD);
- sub->cxmode = MGCP_CX_SENDRECV;
- if (!sub->rtp) {
- start_rtp(sub);
- } else {
- transmit_modify_request(sub);
- }
- /*transmit_notify_request(sub, "aw");*/
- transmit_notify_request(sub, "");
- mgcp_queue_control(sub, AST_CONTROL_ANSWER);
- }
- } else {
- /* Start switch */
- /*sub->cxmode = MGCP_CX_SENDRECV;*/
- if (!sub->owner) {
- if (!sub->rtp) {
- start_rtp(sub);
- } else {
- transmit_modify_request(sub);
- }
- if (p->immediate) {
- /* The channel is immediately up. Start right away */
-#ifdef DLINK_BUGGY_FIRMWARE
- transmit_notify_request(sub, "rt");
-#else
- transmit_notify_request(sub, "G/rt");
-#endif
- c = mgcp_new(sub, AST_STATE_RING);
- if (!c) {
- ast_log(LOG_WARNING, "Unable to start PBX on channel %s@%s\n", p->name, p->parent->name);
- transmit_notify_request(sub, "G/cg");
- ast_hangup(c);
- }
- } else {
- if (has_voicemail(p)) {
- transmit_notify_request(sub, "L/sl");
- } else {
- transmit_notify_request(sub, "L/dl");
- }
- c = mgcp_new(sub, AST_STATE_DOWN);
- if (c) {
- if (ast_pthread_create(&t, &attr, mgcp_ss, c)) {
- ast_log(LOG_WARNING, "Unable to create switch thread: %s\n", strerror(errno));
- ast_hangup(c);
- }
- } else {
- ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", p->name, p->parent->name);
- }
- }
- } else {
- if (p->hookstate == MGCP_OFFHOOK) {
- ast_log(LOG_WARNING, "Off hook, but already have owner on %s@%s\n", p->name, p->parent->name);
- } else {
- ast_log(LOG_WARNING, "On hook, but already have owner on %s@%s\n", p->name, p->parent->name);
- ast_log(LOG_WARNING, "If we're onhook why are we here trying to handle a hd or hf?\n");
- }
- if (ast_bridged_channel(sub->owner))
- ast_queue_control(sub->owner, AST_CONTROL_UNHOLD);
- sub->cxmode = MGCP_CX_SENDRECV;
- if (!sub->rtp) {
- start_rtp(sub);
- } else {
- transmit_modify_request(sub);
- }
- /*transmit_notify_request(sub, "aw");*/
- transmit_notify_request(sub, "");
- /*ast_queue_control(sub->owner, AST_CONTROL_ANSWER);*/
- }
- }
- pthread_attr_destroy(&attr);
-}
-
-static int handle_request(struct mgcp_subchannel *sub, struct mgcp_request *req, struct sockaddr_in *sin)
-{
- char *ev, *s;
- struct ast_frame f = { 0, };
- struct mgcp_endpoint *p = sub->parent;
- struct mgcp_gateway *g = NULL;
- int res;
-
- if (mgcpdebug) {
- ast_verbose("Handling request '%s' on %s@%s\n", req->verb, p->name, p->parent->name);
- }
- /* Clear out potential response */
- if (!strcasecmp(req->verb, "RSIP")) {
- /* Test if this RSIP request is just a keepalive */
- if(!strcasecmp( get_header(req, "RM"), "X-keepalive")) {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Received keepalive request from %s@%s\n", p->name, p->parent->name);
- transmit_response(sub, "200", req, "OK");
- } else {
- dump_queue(p->parent, p);
- dump_cmd_queues(p, NULL);
-
- if (option_verbose > 2 && (strcmp(p->name, p->parent->wcardep) != 0)) {
- ast_verbose(VERBOSE_PREFIX_3 "Resetting interface %s@%s\n", p->name, p->parent->name);
- }
- /* For RSIP on wildcard we reset all endpoints */
- if (!strcmp(p->name, p->parent->wcardep)) {
- /* Reset all endpoints */
- struct mgcp_endpoint *tmp_ep;
-
- g = p->parent;
- tmp_ep = g->endpoints;
- while (tmp_ep) {
- /*if ((strcmp(tmp_ep->name, "*") != 0) && (strcmp(tmp_ep->name, "aaln/" "*") != 0)) {*/
- if (strcmp(tmp_ep->name, g->wcardep) != 0) {
- struct mgcp_subchannel *tmp_sub, *first_sub;
- if (option_verbose > 2) {
- ast_verbose(VERBOSE_PREFIX_3 "Resetting interface %s@%s\n", tmp_ep->name, p->parent->name);
- }
-
- first_sub = tmp_ep->sub;
- tmp_sub = tmp_ep->sub;
- while (tmp_sub) {
- mgcp_queue_hangup(tmp_sub);
- tmp_sub = tmp_sub->next;
- if (tmp_sub == first_sub)
- break;
- }
- }
- tmp_ep = tmp_ep->next;
- }
- } else if (sub->owner) {
- mgcp_queue_hangup(sub);
- }
- transmit_response(sub, "200", req, "OK");
- /* We dont send NTFY or AUEP to wildcard ep */
- if (strcmp(p->name, p->parent->wcardep) != 0) {
- transmit_notify_request(sub, "");
- /* Audit endpoint.
- Idea is to prevent lost lines due to race conditions
- */
- transmit_audit_endpoint(p);
- }
- }
- } else if (!strcasecmp(req->verb, "NTFY")) {
- /* Acknowledge and be sure we keep looking for the same things */
- transmit_response(sub, "200", req, "OK");
- /* Notified of an event */
- ev = get_header(req, "O");
- s = strchr(ev, '/');
- if (s) ev = s + 1;
- ast_log(LOG_DEBUG, "Endpoint '%s@%s-%d' observed '%s'\n", p->name, p->parent->name, sub->id, ev);
- /* Keep looking for events unless this was a hangup */
- if (strcasecmp(ev, "hu") && strcasecmp(ev, "hd") && strcasecmp(ev, "ping")) {
- transmit_notify_request(sub, p->curtone);
- }
- if (!strcasecmp(ev, "hd")) {
- p->hookstate = MGCP_OFFHOOK;
- sub->cxmode = MGCP_CX_SENDRECV;
- handle_hd_hf(sub, ev);
- } else if (!strcasecmp(ev, "hf")) {
- /* We can assume we are offhook if we received a hookflash */
- /* First let's just do call wait and ignore threeway */
- /* We're currently in charge */
- if (p->hookstate != MGCP_OFFHOOK) {
- /* Cisco c7940 sends hf even if the phone is onhook */
- /* Thanks to point on IRC for pointing this out */
- return -1;
- }
- /* do not let * conference two down channels */
- if (sub->owner && sub->owner->_state == AST_STATE_DOWN && !sub->next->owner)
- return -1;
-
- if (p->callwaiting || p->transfer || p->threewaycalling) {
- if (option_verbose > 2) {
- ast_verbose(VERBOSE_PREFIX_3 "Swapping %d for %d on %s@%s\n", p->sub->id, p->sub->next->id, p->name, p->parent->name);
- }
- p->sub = p->sub->next;
-
- /* transfer control to our next subchannel */
- if (!sub->next->owner) {
- /* plave the first call on hold and start up a new call */
- sub->cxmode = MGCP_CX_MUTE;
- if (option_verbose > 2) {
- ast_verbose(VERBOSE_PREFIX_3 "MGCP Muting %d on %s@%s\n", sub->id, p->name, p->parent->name);
- }
- transmit_modify_request(sub);
- if (sub->owner && ast_bridged_channel(sub->owner))
- ast_queue_control(sub->owner, AST_CONTROL_HOLD);
- sub->next->cxmode = MGCP_CX_RECVONLY;
- handle_hd_hf(sub->next, ev);
- } else if (sub->owner && sub->next->owner) {
- /* We've got two active calls lets decide whether or not to conference or just flip flop */
- if ((!sub->outgoing) && (!sub->next->outgoing)) {
- /* We made both calls lets conferenct */
- if (option_verbose > 2) {
- ast_verbose(VERBOSE_PREFIX_3 "MGCP Conferencing %d and %d on %s@%s\n",
- sub->id, sub->next->id, p->name, p->parent->name);
- }
- sub->cxmode = MGCP_CX_CONF;
- sub->next->cxmode = MGCP_CX_CONF;
- if (ast_bridged_channel(sub->next->owner))
- ast_queue_control(sub->next->owner, AST_CONTROL_UNHOLD);
- transmit_modify_request(sub);
- transmit_modify_request(sub->next);
- } else {
- /* Let's flipflop between calls */
- /* XXX Need to check for state up ??? */
- /* XXX Need a way to indicate the current call, or maybe the call that's waiting */
- if (option_verbose > 2) {
- ast_verbose(VERBOSE_PREFIX_3 "We didn't make one of the calls FLIPFLOP %d and %d on %s@%s\n",
- sub->id, sub->next->id, p->name, p->parent->name);
- }
- sub->cxmode = MGCP_CX_MUTE;
- if (option_verbose > 2) {
- ast_verbose(VERBOSE_PREFIX_3 "MGCP Muting %d on %s@%s\n", sub->id, p->name, p->parent->name);
- }
- transmit_modify_request(sub);
- if (ast_bridged_channel(sub->owner))
- ast_queue_control(sub->owner, AST_CONTROL_HOLD);
-
- if (ast_bridged_channel(sub->next->owner))
- ast_queue_control(sub->next->owner, AST_CONTROL_HOLD);
-
- handle_hd_hf(sub->next, ev);
- }
- } else {
- /* We've most likely lost one of our calls find an active call and bring it up */
- if (sub->owner) {
- p->sub = sub;
- } else if (sub->next->owner) {
- p->sub = sub->next;
- } else {
- /* We seem to have lost both our calls */
- /* XXX - What do we do now? */
- return -1;
- }
- if (ast_bridged_channel(p->sub->owner))
- ast_queue_control(p->sub->owner, AST_CONTROL_UNHOLD);
- p->sub->cxmode = MGCP_CX_SENDRECV;
- transmit_modify_request(p->sub);
- }
- } else {
- ast_log(LOG_WARNING, "Callwaiting, call transfer or threeway calling not enabled on endpoint %s@%s\n",
- p->name, p->parent->name);
- }
- } else if (!strcasecmp(ev, "hu")) {
- p->hookstate = MGCP_ONHOOK;
- sub->cxmode = MGCP_CX_RECVONLY;
- ast_log(LOG_DEBUG, "MGCP %s@%s Went on hook\n", p->name, p->parent->name);
- /* Do we need to send MDCX before a DLCX ?
- if (sub->rtp) {
- transmit_modify_request(sub);
- }
- */
- if (p->transfer && (sub->owner && sub->next->owner) && ((!sub->outgoing) || (!sub->next->outgoing))) {
- /* We're allowed to transfer, we have two avtive calls and */
- /* we made at least one of the calls. Let's try and transfer */
- ast_mutex_lock(&p->sub->next->lock);
- res = attempt_transfer(p);
- if (res < 0) {
- if (p->sub->next->owner) {
- sub->next->alreadygone = 1;
- mgcp_queue_hangup(sub->next);
- }
- } else if (res) {
- ast_log(LOG_WARNING, "Transfer attempt failed\n");
- ast_mutex_unlock(&p->sub->next->lock);
- return -1;
- }
- ast_mutex_unlock(&p->sub->next->lock);
- } else {
- /* Hangup the current call */
- /* If there is another active call, mgcp_hangup will ring the phone with the other call */
- if (sub->owner) {
- sub->alreadygone = 1;
- mgcp_queue_hangup(sub);
- } else {
- /* verbose level check */
- if (option_verbose > 2) {
- ast_verbose(VERBOSE_PREFIX_3 "MGCP handle_request(%s@%s-%d) ast_channel already destroyed, resending DLCX.\n",
- p->name, p->parent->name, sub->id);
- }
- /* Instruct the other side to remove the connection since it apparently *
- * still thinks the channel is active. *
- * For Cisco IAD2421 /BAK/ */
- transmit_connection_del(sub);
- }
- }
- if ((p->hookstate == MGCP_ONHOOK) && (!sub->rtp) && (!sub->next->rtp)) {
- p->hidecallerid = 0;
- if (p->hascallwaiting && !p->callwaiting) {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Enabling call waiting on MGCP/%s@%s-%d\n", p->name, p->parent->name, sub->id);
- p->callwaiting = -1;
- }
- if (has_voicemail(p)) {
- if (option_verbose > 2) {
- ast_verbose(VERBOSE_PREFIX_3 "MGCP handle_request(%s@%s) set vmwi(+)\n", p->name, p->parent->name);
- }
- transmit_notify_request(sub, "L/vmwi(+)");
- } else {
- if (option_verbose > 2) {
- ast_verbose(VERBOSE_PREFIX_3 "MGCP handle_request(%s@%s) set vmwi(-)\n", p->name, p->parent->name);
- }
- transmit_notify_request(sub, "L/vmwi(-)");
- }
- }
- } else if ((strlen(ev) == 1) &&
- (((ev[0] >= '0') && (ev[0] <= '9')) ||
- ((ev[0] >= 'A') && (ev[0] <= 'D')) ||
- (ev[0] == '*') || (ev[0] == '#'))) {
- if (sub && sub->owner && (sub->owner->_state >= AST_STATE_UP)) {
- f.frametype = AST_FRAME_DTMF;
- f.subclass = ev[0];
- f.src = "mgcp";
- /* XXX MUST queue this frame to all subs in threeway call if threeway call is active */
- mgcp_queue_frame(sub, &f);
- ast_mutex_lock(&sub->next->lock);
- if (sub->next->owner)
- mgcp_queue_frame(sub->next, &f);
- ast_mutex_unlock(&sub->next->lock);
- if (strstr(p->curtone, "wt") && (ev[0] == 'A')) {
- memset(p->curtone, 0, sizeof(p->curtone));
- }
- } else {
- p->dtmf_buf[strlen(p->dtmf_buf)] = ev[0];
- p->dtmf_buf[strlen(p->dtmf_buf)] = '\0';
- }
- } else if (!strcasecmp(ev, "T")) {
- /* Digit timeout -- unimportant */
- } else if (!strcasecmp(ev, "ping")) {
- /* ping -- unimportant */
- } else {
- ast_log(LOG_NOTICE, "Received unknown event '%s' from %s@%s\n", ev, p->name, p->parent->name);
- }
- } else {
- ast_log(LOG_WARNING, "Unknown verb '%s' received from %s\n", req->verb, ast_inet_ntoa(sin->sin_addr));
- transmit_response(sub, "510", req, "Unknown verb");
- }
- return 0;
-}
-
-static int find_and_retrans(struct mgcp_subchannel *sub, struct mgcp_request *req)
-{
- int seqno=0;
- time_t now;
- struct mgcp_response *prev = NULL, *cur, *next, *answer=NULL;
- time(&now);
- if (sscanf(req->identifier, "%d", &seqno) != 1)
- seqno = 0;
- cur = sub->parent->parent->responses;
- while(cur) {
- next = cur->next;
- if (now - cur->whensent > RESPONSE_TIMEOUT) {
- /* Delete this entry */
- if (prev)
- prev->next = next;
- else
- sub->parent->parent->responses = next;
- free(cur);
- } else {
- if (seqno == cur->seqno)
- answer = cur;
- prev = cur;
- }
- cur = next;
- }
- if (answer) {
- resend_response(sub, answer);
- return 1;
- }
- return 0;
-}
-
-static int mgcpsock_read(int *id, int fd, short events, void *ignore)
-{
- struct mgcp_request req;
- struct sockaddr_in sin;
- struct mgcp_subchannel *sub;
- int res;
- socklen_t len;
- int result;
- int ident;
- len = sizeof(sin);
- memset(&req, 0, sizeof(req));
- res = recvfrom(mgcpsock, req.data, sizeof(req.data) - 1, 0, (struct sockaddr *)&sin, &len);
- if (res < 0) {
- if (errno != ECONNREFUSED)
- ast_log(LOG_WARNING, "Recv error: %s\n", strerror(errno));
- return 1;
- }
- req.data[res] = '\0';
- req.len = res;
- if (mgcpdebug) {
- ast_verbose("MGCP read: \n%s\nfrom %s:%d\n", req.data, ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
- }
- parse(&req);
- if (req.headers < 1) {
- /* Must have at least one header */
- return 1;
- }
- if (ast_strlen_zero(req.identifier)) {
- ast_log(LOG_NOTICE, "Message from %s missing identifier\n", ast_inet_ntoa(sin.sin_addr));
- return 1;
- }
-
- if (sscanf(req.verb, "%d", &result) && sscanf(req.identifier, "%d", &ident)) {
- /* Try to find who this message is for, if it's important */
- sub = find_subchannel_and_lock(NULL, ident, &sin);
- if (sub) {
- struct mgcp_gateway *gw = sub->parent->parent;
- struct mgcp_message *cur, *prev;
-
- ast_mutex_unlock(&sub->lock);
- ast_mutex_lock(&gw->msgs_lock);
- for (prev = NULL, cur = gw->msgs; cur; prev = cur, cur = cur->next) {
- if (cur->seqno == ident) {
- ast_log(LOG_DEBUG, "Got response back on transaction %d\n", ident);
- if (prev)
- prev->next = cur->next;
- else
- gw->msgs = cur->next;
- break;
- }
- }
-
- /* stop retrans timer if the queue is empty */
- if (!gw->msgs) {
- AST_SCHED_DEL(sched, gw->retransid);
- }
-
- ast_mutex_unlock(&gw->msgs_lock);
- if (cur) {
- handle_response(cur->owner_ep, cur->owner_sub, result, ident, &req);
- free(cur);
- return 1;
- }
-
- ast_log(LOG_NOTICE, "Got response back on [%s] for transaction %d we aren't sending?\n",
- gw->name, ident);
- }
- } else {
- if (ast_strlen_zero(req.endpoint) ||
- ast_strlen_zero(req.version) ||
- ast_strlen_zero(req.verb)) {
- ast_log(LOG_NOTICE, "Message must have a verb, an idenitifier, version, and endpoint\n");
- return 1;
- }
- /* Process request, with iflock held */
- sub = find_subchannel_and_lock(req.endpoint, 0, &sin);
- if (sub) {
- /* look first to find a matching response in the queue */
- if (!find_and_retrans(sub, &req))
- /* pass the request off to the currently mastering subchannel */
- handle_request(sub, &req, &sin);
- ast_mutex_unlock(&sub->lock);
- }
- }
- return 1;
-}
-
-static int *mgcpsock_read_id = NULL;
-
-static void *do_monitor(void *data)
-{
- int res;
- int reloading;
- /*struct mgcp_gateway *g;*/
- /*struct mgcp_endpoint *e;*/
- /*time_t thispass = 0, lastpass = 0;*/
-
- /* Add an I/O event to our UDP socket */
- if (mgcpsock > -1)
- mgcpsock_read_id = ast_io_add(io, mgcpsock, mgcpsock_read, AST_IO_IN, NULL);
-
- /* This thread monitors all the frame relay interfaces which are not yet in use
- (and thus do not have a separate thread) indefinitely */
- /* From here on out, we die whenever asked */
- for(;;) {
- /* Check for a reload request */
- ast_mutex_lock(&mgcp_reload_lock);
- reloading = mgcp_reloading;
- mgcp_reloading = 0;
- ast_mutex_unlock(&mgcp_reload_lock);
- if (reloading) {
- if (option_verbose > 0)
- ast_verbose(VERBOSE_PREFIX_1 "Reloading MGCP\n");
- mgcp_do_reload();
- /* Add an I/O event to our UDP socket */
- if (mgcpsock > -1)
- mgcpsock_read_id = ast_io_add(io, mgcpsock, mgcpsock_read, AST_IO_IN, NULL);
- }
-
- /* Check for interfaces needing to be killed */
- /* Don't let anybody kill us right away. Nobody should lock the interface list
- and wait for the monitor list, but the other way around is okay. */
- ast_mutex_lock(&monlock);
- /* Lock the network interface */
- ast_mutex_lock(&netlock);
-
-#if 0
- /* XXX THIS IS COMPLETELY HOSED */
- /* The gateway goes into a state of panic */
- /* If the vmwi indicator is sent while it is reseting interfaces */
- lastpass = thispass;
- thispass = time(NULL);
- g = gateways;
- while(g) {
- if (thispass != lastpass) {
- e = g->endpoints;
- while(e) {
- if (e->type == TYPE_LINE) {
- res = has_voicemail(e);
- if ((e->msgstate != res) && (e->hookstate == MGCP_ONHOOK) && (!e->rtp)){
- if (res) {
- transmit_notify_request(e, "L/vmwi(+)");
- } else {
- transmit_notify_request(e, "L/vmwi(-)");
- }
- e->msgstate = res;
- e->onhooktime = thispass;
- }
- }
- e = e->next;
- }
- }
- g = g->next;
- }
-#endif
- /* Okay, now that we know what to do, release the network lock */
- ast_mutex_unlock(&netlock);
- /* And from now on, we're okay to be killed, so release the monitor lock as well */
- ast_mutex_unlock(&monlock);
- pthread_testcancel();
- /* Wait for sched or io */
- res = ast_sched_wait(sched);
- /* copied from chan_sip.c */
- if ((res < 0) || (res > 1000))
- res = 1000;
- res = ast_io_wait(io, res);
- ast_mutex_lock(&monlock);
- if (res >= 0)
- ast_sched_runq(sched);
- ast_mutex_unlock(&monlock);
- }
- /* Never reached */
- return NULL;
-}
-
-static int restart_monitor(void)
-{
- /* If we're supposed to be stopped -- stay stopped */
- if (monitor_thread == AST_PTHREADT_STOP)
- return 0;
- if (ast_mutex_lock(&monlock)) {
- ast_log(LOG_WARNING, "Unable to lock monitor\n");
- return -1;
- }
- if (monitor_thread == pthread_self()) {
- ast_mutex_unlock(&monlock);
- ast_log(LOG_WARNING, "Cannot kill myself\n");
- return -1;
- }
- if (monitor_thread != AST_PTHREADT_NULL) {
- /* Wake up the thread */
- pthread_kill(monitor_thread, SIGURG);
- } else {
- /* Start a new monitor */
- if (ast_pthread_create_background(&monitor_thread, NULL, do_monitor, NULL) < 0) {
- ast_mutex_unlock(&monlock);
- ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
- return -1;
- }
- }
- ast_mutex_unlock(&monlock);
- return 0;
-}
-
-static struct ast_channel *mgcp_request(const char *type, int format, void *data, int *cause)
-{
- int oldformat;
- struct mgcp_subchannel *sub;
- struct ast_channel *tmpc = NULL;
- char tmp[256];
- char *dest = data;
-
- oldformat = format;
- format &= capability;
- if (!format) {
- ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", format);
- return NULL;
- }
- ast_copy_string(tmp, dest, sizeof(tmp));
- if (ast_strlen_zero(tmp)) {
- ast_log(LOG_NOTICE, "MGCP Channels require an endpoint\n");
- return NULL;
- }
- sub = find_subchannel_and_lock(tmp, 0, NULL);
- if (!sub) {
- ast_log(LOG_WARNING, "Unable to find MGCP endpoint '%s'\n", tmp);
- *cause = AST_CAUSE_UNREGISTERED;
- return NULL;
- }
-
- if (option_verbose > 2) {
- ast_verbose(VERBOSE_PREFIX_3 "MGCP mgcp_request(%s)\n", tmp);
- ast_verbose(VERBOSE_PREFIX_3 "MGCP cw: %d, dnd: %d, so: %d, sno: %d\n",
- sub->parent->callwaiting, sub->parent->dnd, sub->owner ? 1 : 0, sub->next->owner ? 1: 0);
- }
- /* Must be busy */
- if (((sub->parent->callwaiting) && ((sub->owner) && (sub->next->owner))) ||
- ((!sub->parent->callwaiting) && (sub->owner)) ||
- (sub->parent->dnd && (ast_strlen_zero(sub->parent->call_forward)))) {
- if (sub->parent->hookstate == MGCP_ONHOOK) {
- if (has_voicemail(sub->parent)) {
- transmit_notify_request(sub,"L/vmwi(+)");
- } else {
- transmit_notify_request(sub,"L/vmwi(-)");
- }
- }
- *cause = AST_CAUSE_BUSY;
- ast_mutex_unlock(&sub->lock);
- return NULL;
- }
- tmpc = mgcp_new(sub->owner ? sub->next : sub, AST_STATE_DOWN);
- ast_mutex_unlock(&sub->lock);
- if (!tmpc)
- ast_log(LOG_WARNING, "Unable to make channel for '%s'\n", tmp);
- restart_monitor();
- return tmpc;
-}
-
-/* modified for reload support */
-/*! \brief build_gateway: parse mgcp.conf and create gateway/endpoint structures */
-static struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v)
-{
- struct mgcp_gateway *gw;
- struct mgcp_endpoint *e;
- struct mgcp_subchannel *sub;
- /*char txident[80];*/
- int i=0, y=0;
- int gw_reload = 0;
- int ep_reload = 0;
- canreinvite = CANREINVITE;
-
- /* locate existing gateway */
- gw = gateways;
- while (gw) {
- if (!strcasecmp(cat, gw->name)) {
- /* gateway already exists */
- gw->delme = 0;
- gw_reload = 1;
- break;
- }
- gw = gw->next;
- }
-
- if (!gw)
- gw = malloc(sizeof(struct mgcp_gateway));
-
- if (gw) {
- if (!gw_reload) {
- memset(gw, 0, sizeof(struct mgcp_gateway));
- gw->expire = -1;
- gw->retransid = -1; /* SC */
- ast_mutex_init(&gw->msgs_lock);
- ast_copy_string(gw->name, cat, sizeof(gw->name));
- /* check if the name is numeric ip */
- if ((strchr(gw->name, '.')) && inet_addr(gw->name) != INADDR_NONE)
- gw->isnamedottedip = 1;
- }
- while(v) {
- if (!strcasecmp(v->name, "host")) {
- if (!strcasecmp(v->value, "dynamic")) {
- /* They'll register with us */
- gw->dynamic = 1;
- memset(&gw->addr.sin_addr, 0, 4);
- if (gw->addr.sin_port) {
- /* If we've already got a port, make it the default rather than absolute */
- gw->defaddr.sin_port = gw->addr.sin_port;
- gw->addr.sin_port = 0;
- }
- } else {
- /* Non-dynamic. Make sure we become that way if we're not */
- AST_SCHED_DEL(sched, gw->expire);
- gw->dynamic = 0;
- if (ast_get_ip(&gw->addr, v->value)) {
- if (!gw_reload) {
- ast_mutex_destroy(&gw->msgs_lock);
- free(gw);
- }
- return NULL;
- }
- }
- } else if (!strcasecmp(v->name, "defaultip")) {
- if (ast_get_ip(&gw->defaddr, v->value)) {
- if (!gw_reload) {
- ast_mutex_destroy(&gw->msgs_lock);
- free(gw);
- }
- return NULL;
- }
- } else if (!strcasecmp(v->name, "permit") ||
- !strcasecmp(v->name, "deny")) {
- gw->ha = ast_append_ha(v->name, v->value, gw->ha);
- } else if (!strcasecmp(v->name, "port")) {
- gw->addr.sin_port = htons(atoi(v->value));
- } else if (!strcasecmp(v->name, "context")) {
- ast_copy_string(context, v->value, sizeof(context));
- } else if (!strcasecmp(v->name, "dtmfmode")) {
- if (!strcasecmp(v->value, "inband"))
- dtmfmode = MGCP_DTMF_INBAND;
- else if (!strcasecmp(v->value, "rfc2833"))
- dtmfmode = MGCP_DTMF_RFC2833;
- else if (!strcasecmp(v->value, "hybrid"))
- dtmfmode = MGCP_DTMF_HYBRID;
- else if (!strcasecmp(v->value, "none"))
- dtmfmode = 0;
- else
- ast_log(LOG_WARNING, "'%s' is not a valid DTMF mode at line %d\n", v->value, v->lineno);
- } else if (!strcasecmp(v->name, "nat")) {
- nat = ast_true(v->value);
- } else if (!strcasecmp(v->name, "callerid")) {
- if (!strcasecmp(v->value, "asreceived")) {
- cid_num[0] = '\0';
- cid_name[0] = '\0';
- } else {
- ast_callerid_split(v->value, cid_name, sizeof(cid_name), cid_num, sizeof(cid_num));
- }
- } else if (!strcasecmp(v->name, "language")) {
- ast_copy_string(language, v->value, sizeof(language));
- } else if (!strcasecmp(v->name, "accountcode")) {
- ast_copy_string(accountcode, v->value, sizeof(accountcode));
- } else if (!strcasecmp(v->name, "amaflags")) {
- y = ast_cdr_amaflags2int(v->value);
- if (y < 0) {
- ast_log(LOG_WARNING, "Invalid AMA flags: %s at line %d\n", v->value, v->lineno);
- } else {
- amaflags = y;
- }
- } else if (!strcasecmp(v->name, "musiconhold")) {
- ast_copy_string(musicclass, v->value, sizeof(musicclass));
- } else if (!strcasecmp(v->name, "callgroup")) {
- cur_callergroup = ast_get_group(v->value);
- } else if (!strcasecmp(v->name, "pickupgroup")) {
- cur_pickupgroup = ast_get_group(v->value);
- } else if (!strcasecmp(v->name, "immediate")) {
- immediate = ast_true(v->value);
- } else if (!strcasecmp(v->name, "cancallforward")) {
- cancallforward = ast_true(v->value);
- } else if (!strcasecmp(v->name, "singlepath")) {
- singlepath = ast_true(v->value);
- } else if (!strcasecmp(v->name, "canreinvite")) {
- canreinvite = ast_true(v->value);
- } else if (!strcasecmp(v->name, "mailbox")) {
- ast_copy_string(mailbox, v->value, sizeof(mailbox));
- } else if (!strcasecmp(v->name, "hasvoicemail")) {
- if (ast_true(v->value) && ast_strlen_zero(mailbox)) {
- ast_copy_string(mailbox, gw->name, sizeof(mailbox));
- }
- } else if (!strcasecmp(v->name, "adsi")) {
- adsi = ast_true(v->value);
- } else if (!strcasecmp(v->name, "callreturn")) {
- callreturn = ast_true(v->value);
- } else if (!strcasecmp(v->name, "callwaiting")) {
- callwaiting = ast_true(v->value);
- } else if (!strcasecmp(v->name, "slowsequence")) {
- slowsequence = ast_true(v->value);
- } else if (!strcasecmp(v->name, "transfer")) {
- transfer = ast_true(v->value);
- } else if (!strcasecmp(v->name, "threewaycalling")) {
- threewaycalling = ast_true(v->value);
- } else if (!strcasecmp(v->name, "wcardep")) {
- /* locate existing endpoint */
- e = gw->endpoints;
- while (e) {
- if (!strcasecmp(v->value, e->name)) {
- /* endpoint already exists */
- e->delme = 0;
- ep_reload = 1;
- break;
- }
- e = e->next;
- }
-
- if (!e) {
- /* Allocate wildcard endpoint */
- e = malloc(sizeof(struct mgcp_endpoint));
- ep_reload = 0;
- }
-
- if (e) {
- if (!ep_reload) {
- memset(e, 0, sizeof(struct mgcp_endpoint));
- ast_mutex_init(&e->lock);
- ast_mutex_init(&e->rqnt_queue_lock);
- ast_mutex_init(&e->cmd_queue_lock);
- ast_copy_string(e->name, v->value, sizeof(e->name));
- e->needaudit = 1;
- }
- ast_copy_string(gw->wcardep, v->value, sizeof(gw->wcardep));
- /* XXX Should we really check for uniqueness?? XXX */
- ast_copy_string(e->accountcode, accountcode, sizeof(e->accountcode));
- ast_copy_string(e->context, context, sizeof(e->context));
- ast_copy_string(e->cid_num, cid_num, sizeof(e->cid_num));
- ast_copy_string(e->cid_name, cid_name, sizeof(e->cid_name));
- ast_copy_string(e->language, language, sizeof(e->language));
- ast_copy_string(e->musicclass, musicclass, sizeof(e->musicclass));
- ast_copy_string(e->mailbox, mailbox, sizeof(e->mailbox));
- snprintf(e->rqnt_ident, sizeof(e->rqnt_ident), "%08lx", ast_random());
- e->msgstate = -1;
- e->amaflags = amaflags;
- e->capability = capability;
- e->parent = gw;
- e->dtmfmode = dtmfmode;
- if (!ep_reload && e->sub && e->sub->rtp)
- e->dtmfmode |= MGCP_DTMF_INBAND;
- e->adsi = adsi;
- e->type = TYPE_LINE;
- e->immediate = immediate;
- e->callgroup=cur_callergroup;
- e->pickupgroup=cur_pickupgroup;
- e->callreturn = callreturn;
- e->cancallforward = cancallforward;
- e->singlepath = singlepath;
- e->canreinvite = canreinvite;
- e->callwaiting = callwaiting;
- e->hascallwaiting = callwaiting;
- e->slowsequence = slowsequence;
- e->transfer = transfer;
- e->threewaycalling = threewaycalling;
- e->onhooktime = time(NULL);
- /* ASSUME we're onhook */
- e->hookstate = MGCP_ONHOOK;
- if (!ep_reload) {
- /*snprintf(txident, sizeof(txident), "%08lx", ast_random());*/
- for (i = 0; i < MAX_SUBS; i++) {
- sub = malloc(sizeof(struct mgcp_subchannel));
- if (sub) {
- ast_verbose(VERBOSE_PREFIX_3 "Allocating subchannel '%d' on %s@%s\n", i, e->name, gw->name);
- memset(sub, 0, sizeof(struct mgcp_subchannel));
- ast_mutex_init(&sub->lock);
- ast_mutex_init(&sub->cx_queue_lock);
- sub->parent = e;
- sub->id = i;
- snprintf(sub->txident, sizeof(sub->txident), "%08lx", ast_random());
- /*stnrcpy(sub->txident, txident, sizeof(sub->txident) - 1);*/
- sub->cxmode = MGCP_CX_INACTIVE;
- sub->nat = nat;
- sub->next = e->sub;
- e->sub = sub;
- } else {
- /* XXX Should find a way to clean up our memory */
- ast_log(LOG_WARNING, "Out of memory allocating subchannel\n");
- return NULL;
- }
- }
- /* Make out subs a circular linked list so we can always sping through the whole bunch */
- sub = e->sub;
- /* find the end of the list */
- while(sub->next){
- sub = sub->next;
- }
- /* set the last sub->next to the first sub */
- sub->next = e->sub;
-
- e->next = gw->endpoints;
- gw->endpoints = e;
- }
- }
- } else if (!strcasecmp(v->name, "trunk") ||
- !strcasecmp(v->name, "line")) {
-
- /* locate existing endpoint */
- e = gw->endpoints;
- while (e) {
- if (!strcasecmp(v->value, e->name)) {
- /* endpoint already exists */
- e->delme = 0;
- ep_reload = 1;
- break;
- }
- e = e->next;
- }
-
- if (!e) {
- e = malloc(sizeof(struct mgcp_endpoint));
- ep_reload = 0;
- }
-
- if (e) {
- if (!ep_reload) {
- memset(e, 0, sizeof(struct mgcp_endpoint));
- ast_mutex_init(&e->lock);
- ast_mutex_init(&e->rqnt_queue_lock);
- ast_mutex_init(&e->cmd_queue_lock);
- ast_copy_string(e->name, v->value, sizeof(e->name));
- e->needaudit = 1;
- }
- /* XXX Should we really check for uniqueness?? XXX */
- ast_copy_string(e->accountcode, accountcode, sizeof(e->accountcode));
- ast_copy_string(e->context, context, sizeof(e->context));
- ast_copy_string(e->cid_num, cid_num, sizeof(e->cid_num));
- ast_copy_string(e->cid_name, cid_name, sizeof(e->cid_name));
- ast_copy_string(e->language, language, sizeof(e->language));
- ast_copy_string(e->musicclass, musicclass, sizeof(e->musicclass));
- ast_copy_string(e->mailbox, mailbox, sizeof(e->mailbox));
- if (!ast_strlen_zero(mailbox)) {
- ast_verbose(VERBOSE_PREFIX_3 "Setting mailbox '%s' on %s@%s\n", mailbox, gw->name, e->name);
- }
- if (!ep_reload) {
- /* XXX potential issue due to reload */
- e->msgstate = -1;
- e->parent = gw;
- }
- e->amaflags = amaflags;
- e->capability = capability;
- e->dtmfmode = dtmfmode;
- e->adsi = adsi;
- if (!strcasecmp(v->name, "trunk"))
- e->type = TYPE_TRUNK;
- else
- e->type = TYPE_LINE;
-
- e->immediate = immediate;
- e->callgroup=cur_callergroup;
- e->pickupgroup=cur_pickupgroup;
- e->callreturn = callreturn;
- e->cancallforward = cancallforward;
- e->canreinvite = canreinvite;
- e->singlepath = singlepath;
- e->callwaiting = callwaiting;
- e->hascallwaiting = callwaiting;
- e->slowsequence = slowsequence;
- e->transfer = transfer;
- e->threewaycalling = threewaycalling;
- if (!ep_reload) {
- e->onhooktime = time(NULL);
- /* ASSUME we're onhook */
- e->hookstate = MGCP_ONHOOK;
- snprintf(e->rqnt_ident, sizeof(e->rqnt_ident), "%08lx", ast_random());
- }
-
- for (i = 0, sub = NULL; i < MAX_SUBS; i++) {
- if (!ep_reload) {
- sub = malloc(sizeof(struct mgcp_subchannel));
- } else {
- if (!sub)
- sub = e->sub;
- else
- sub = sub->next;
- }
-
- if (sub) {
- if (!ep_reload) {
- ast_verbose(VERBOSE_PREFIX_3 "Allocating subchannel '%d' on %s@%s\n", i, e->name, gw->name);
- memset(sub, 0, sizeof(struct mgcp_subchannel));
- ast_mutex_init(&sub->lock);
- ast_mutex_init(&sub->cx_queue_lock);
- ast_copy_string(sub->magic, MGCP_SUBCHANNEL_MAGIC, sizeof(sub->magic));
- sub->parent = e;
- sub->id = i;
- snprintf(sub->txident, sizeof(sub->txident), "%08lx", ast_random());
- sub->cxmode = MGCP_CX_INACTIVE;
- sub->next = e->sub;
- e->sub = sub;
- }
- sub->nat = nat;
- } else {
- /* XXX Should find a way to clean up our memory */
- ast_log(LOG_WARNING, "Out of memory allocating subchannel\n");
- return NULL;
- }
- }
- if (!ep_reload) {
- /* Make out subs a circular linked list so we can always sping through the whole bunch */
- sub = e->sub;
- /* find the end of the list */
- while (sub->next) {
- sub = sub->next;
- }
- /* set the last sub->next to the first sub */
- sub->next = e->sub;
-
- e->next = gw->endpoints;
- gw->endpoints = e;
- }
- }
- } else
- ast_log(LOG_WARNING, "Don't know keyword '%s' at line %d\n", v->name, v->lineno);
- v = v->next;
- }
- }
- if (!ntohl(gw->addr.sin_addr.s_addr) && !gw->dynamic) {
- ast_log(LOG_WARNING, "Gateway '%s' lacks IP address and isn't dynamic\n", gw->name);
- if (!gw_reload) {
- ast_mutex_destroy(&gw->msgs_lock);
- free(gw);
- }
- return NULL;
- }
- gw->defaddr.sin_family = AF_INET;
- gw->addr.sin_family = AF_INET;
- if (gw->defaddr.sin_addr.s_addr && !ntohs(gw->defaddr.sin_port))
- gw->defaddr.sin_port = htons(DEFAULT_MGCP_GW_PORT);
- if (gw->addr.sin_addr.s_addr && !ntohs(gw->addr.sin_port))
- gw->addr.sin_port = htons(DEFAULT_MGCP_GW_PORT);
- if (gw->addr.sin_addr.s_addr)
- if (ast_ouraddrfor(&gw->addr.sin_addr, &gw->ourip))
- memcpy(&gw->ourip, &__ourip, sizeof(gw->ourip));
-
- return (gw_reload ? NULL : gw);
-}
-
-static enum ast_rtp_get_result mgcp_get_rtp_peer(struct ast_channel *chan, struct ast_rtp **rtp)
-{
- struct mgcp_subchannel *sub = NULL;
-
- if (!(sub = chan->tech_pvt) || !(sub->rtp))
- return AST_RTP_GET_FAILED;
-
- *rtp = sub->rtp;
-
- if (sub->parent->canreinvite)
- return AST_RTP_TRY_NATIVE;
- else
- return AST_RTP_TRY_PARTIAL;
-}
-
-static int mgcp_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs, int nat_active)
-{
- /* XXX Is there such thing as video support with MGCP? XXX */
- struct mgcp_subchannel *sub;
- sub = chan->tech_pvt;
- if (sub && !sub->alreadygone) {
- transmit_modify_with_sdp(sub, rtp, codecs);
- return 0;
- }
- return -1;
-}
-
-static struct ast_rtp_protocol mgcp_rtp = {
- .type = "MGCP",
- .get_rtp_info = mgcp_get_rtp_peer,
- .set_rtp_peer = mgcp_set_rtp_peer,
-};
-
-static void destroy_endpoint(struct mgcp_endpoint *e)
-{
- struct mgcp_subchannel *sub = e->sub->next, *s;
- int i;
-
- for (i = 0; i < MAX_SUBS; i++) {
- ast_mutex_lock(&sub->lock);
- if (!ast_strlen_zero(sub->cxident)) {
- transmit_connection_del(sub);
- }
- if (sub->rtp) {
- ast_rtp_destroy(sub->rtp);
- sub->rtp = NULL;
- }
- memset(sub->magic, 0, sizeof(sub->magic));
- mgcp_queue_hangup(sub);
- dump_cmd_queues(NULL, sub);
- ast_mutex_unlock(&sub->lock);
- sub = sub->next;
- }
-
- if (e->dsp) {
- ast_dsp_free(e->dsp);
- }
-
- dump_queue(e->parent, e);
- dump_cmd_queues(e, NULL);
-
- sub = e->sub;
- for (i = 0; (i < MAX_SUBS) && sub; i++) {
- s = sub;
- sub = sub->next;
- ast_mutex_destroy(&s->lock);
- ast_mutex_destroy(&s->cx_queue_lock);
- free(s);
- }
- ast_mutex_destroy(&e->lock);
- ast_mutex_destroy(&e->rqnt_queue_lock);
- ast_mutex_destroy(&e->cmd_queue_lock);
- free(e);
-}
-
-static void destroy_gateway(struct mgcp_gateway *g)
-{
- if (g->ha)
- ast_free_ha(g->ha);
-
- dump_queue(g, NULL);
-
- free (g);
-}
-
-static void prune_gateways(void)
-{
- struct mgcp_gateway *g, *z, *r;
- struct mgcp_endpoint *e, *p, *t;
-
- ast_mutex_lock(&gatelock);
-
- /* prune gateways */
- for (z = NULL, g = gateways; g;) {
- /* prune endpoints */
- for (p = NULL, e = g->endpoints; e; ) {
- if (e->delme || g->delme) {
- t = e;
- e = e->next;
- if (!p)
- g->endpoints = e;
- else
- p->next = e;
- destroy_endpoint(t);
- } else {
- p = e;
- e = e->next;
- }
- }
-
- if (g->delme) {
- r = g;
- g = g->next;
- if (!z)
- gateways = g;
- else
- z->next = g;
-
- destroy_gateway(r);
- } else {
- z = g;
- g = g->next;
- }
- }
-
- ast_mutex_unlock(&gatelock);
-}
-
-static int reload_config(void)
-{
- struct ast_config *cfg;
- struct ast_variable *v;
- struct mgcp_gateway *g;
- struct mgcp_endpoint *e;
- char *cat;
- struct ast_hostent ahp;
- struct hostent *hp;
- int format;
-
- if (gethostname(ourhost, sizeof(ourhost)-1)) {
- ast_log(LOG_WARNING, "Unable to get hostname, MGCP disabled\n");
- return 0;
- }
- cfg = ast_config_load(config);
-
- /* We *must* have a config file otherwise stop immediately */
- if (!cfg) {
- ast_log(LOG_NOTICE, "Unable to load config %s, MGCP disabled\n", config);
- return 0;
- }
- memset(&bindaddr, 0, sizeof(bindaddr));
- dtmfmode = 0;
-
- /* Copy the default jb config over global_jbconf */
- memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
-
- v = ast_variable_browse(cfg, "general");
- while (v) {
- /* handle jb conf */
- if (!ast_jb_read_conf(&global_jbconf, v->name, v->value)) {
- v = v->next;
- continue;
- }
-
- /* Create the interface list */
- if (!strcasecmp(v->name, "bindaddr")) {
- if (!(hp = ast_gethostbyname(v->value, &ahp))) {
- ast_log(LOG_WARNING, "Invalid address: %s\n", v->value);
- } else {
- memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr));
- }
- } else if (!strcasecmp(v->name, "allow")) {
- format = ast_getformatbyname(v->value);
- if (format < 1)
- ast_log(LOG_WARNING, "Cannot allow unknown format '%s'\n", v->value);
- else
- capability |= format;
- } else if (!strcasecmp(v->name, "disallow")) {
- format = ast_getformatbyname(v->value);
- if (format < 1)
- ast_log(LOG_WARNING, "Cannot disallow unknown format '%s'\n", v->value);
- else
- capability &= ~format;
- } else if (!strcasecmp(v->name, "tos")) {
- if (sscanf(v->value, "%d", &format) == 1)
- tos = format & 0xff;
- else if (!strcasecmp(v->value, "lowdelay"))
- tos = IPTOS_LOWDELAY;
- else if (!strcasecmp(v->value, "throughput"))
- tos = IPTOS_THROUGHPUT;
- else if (!strcasecmp(v->value, "reliability"))
- tos = IPTOS_RELIABILITY;
- else if (!strcasecmp(v->value, "mincost"))
- tos = IPTOS_MINCOST;
- else if (!strcasecmp(v->value, "none"))
- tos = 0;
- else
- ast_log(LOG_WARNING, "Invalid tos value at line %d, should be 'lowdelay', 'throughput', 'reliability', 'mincost', or 'none'\n", v->lineno);
- } else if (!strcasecmp(v->name, "port")) {
- if (sscanf(v->value, "%d", &ourport) == 1) {
- bindaddr.sin_port = htons(ourport);
- } else {
- ast_log(LOG_WARNING, "Invalid port number '%s' at line %d of %s\n", v->value, v->lineno, config);
- }
- }
- v = v->next;
- }
-
- /* mark existing entries for deletion */
- ast_mutex_lock(&gatelock);
- g = gateways;
- while (g) {
- g->delme = 1;
- e = g->endpoints;
- while (e) {
- e->delme = 1;
- e = e->next;
- }
- g = g->next;
- }
- ast_mutex_unlock(&gatelock);
-
- cat = ast_category_browse(cfg, NULL);
- while(cat) {
- if (strcasecmp(cat, "general")) {
- ast_mutex_lock(&gatelock);
- g = build_gateway(cat, ast_variable_browse(cfg, cat));
- if (g) {
- if (option_verbose > 2) {
- ast_verbose(VERBOSE_PREFIX_3 "Added gateway '%s'\n", g->name);
- }
- g->next = gateways;
- gateways = g;
- }
- ast_mutex_unlock(&gatelock);
-
- /* FS: process queue and IO */
- if (monitor_thread == pthread_self()) {
- if (sched) ast_sched_runq(sched);
- if (io) ast_io_wait(io, 10);
- }
- }
- cat = ast_category_browse(cfg, cat);
- }
-
- /* prune deleted entries etc. */
- prune_gateways();
-
- if (ntohl(bindaddr.sin_addr.s_addr)) {
- memcpy(&__ourip, &bindaddr.sin_addr, sizeof(__ourip));
- } else {
- hp = ast_gethostbyname(ourhost, &ahp);
- if (!hp) {
- ast_log(LOG_WARNING, "Unable to get our IP address, MGCP disabled\n");
- ast_config_destroy(cfg);
- return 0;
- }
- memcpy(&__ourip, hp->h_addr, sizeof(__ourip));
- }
- if (!ntohs(bindaddr.sin_port))
- bindaddr.sin_port = ntohs(DEFAULT_MGCP_CA_PORT);
- bindaddr.sin_family = AF_INET;
- ast_mutex_lock(&netlock);
- if (mgcpsock > -1)
- close(mgcpsock);
-
- if (mgcpsock_read_id != NULL)
- ast_io_remove(io, mgcpsock_read_id);
- mgcpsock_read_id = NULL;
-
- mgcpsock = socket(AF_INET, SOCK_DGRAM, 0);
- if (mgcpsock < 0) {
- ast_log(LOG_WARNING, "Unable to create MGCP socket: %s\n", strerror(errno));
- } else {
- if (bind(mgcpsock, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) < 0) {
- ast_log(LOG_WARNING, "Failed to bind to %s:%d: %s\n",
- ast_inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port),
- strerror(errno));
- close(mgcpsock);
- mgcpsock = -1;
- } else {
- if (option_verbose > 1) {
- ast_verbose(VERBOSE_PREFIX_2 "MGCP Listening on %s:%d\n",
- ast_inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port));
- ast_verbose(VERBOSE_PREFIX_2 "Using TOS bits %d\n", tos);
- }
- if (setsockopt(mgcpsock, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)))
- ast_log(LOG_WARNING, "Unable to set TOS to %d\n", tos);
- }
- }
- ast_mutex_unlock(&netlock);
- ast_config_destroy(cfg);
-
- /* send audit only to the new endpoints */
- g = gateways;
- while (g) {
- e = g->endpoints;
- while (e && e->needaudit) {
- e->needaudit = 0;
- transmit_audit_endpoint(e);
- ast_verbose(VERBOSE_PREFIX_3 "MGCP Auditing endpoint %s@%s for hookstate\n", e->name, g->name);
- e = e->next;
- }
- g = g->next;
- }
-
- return 0;
-}
-
-/*! \brief load_module: PBX load module - initialization ---*/
-static int load_module(void)
-{
- if (!(sched = sched_context_create())) {
- ast_log(LOG_WARNING, "Unable to create schedule context\n");
- return AST_MODULE_LOAD_FAILURE;
- }
-
- if (!(io = io_context_create())) {
- ast_log(LOG_WARNING, "Unable to create I/O context\n");
- sched_context_destroy(sched);
- return AST_MODULE_LOAD_FAILURE;
- }
-
- if (reload_config())
- return AST_MODULE_LOAD_DECLINE;
-
- /* Make sure we can register our mgcp channel type */
- if (ast_channel_register(&mgcp_tech)) {
- ast_log(LOG_ERROR, "Unable to register channel class 'MGCP'\n");
- io_context_destroy(io);
- sched_context_destroy(sched);
- return AST_MODULE_LOAD_FAILURE;
- }
-
- ast_rtp_proto_register(&mgcp_rtp);
- ast_cli_register_multiple(cli_mgcp, sizeof(cli_mgcp) / sizeof(struct ast_cli_entry));
-
- /* And start the monitor for the first time */
- restart_monitor();
-
- return AST_MODULE_LOAD_SUCCESS;
-}
-
-/*! \brief mgcp_do_reload: Reload module */
-static int mgcp_do_reload(void)
-{
- reload_config();
- return 0;
-}
-
-static int mgcp_reload(int fd, int argc, char *argv[])
-{
- static int deprecated = 0;
- if (!deprecated && argc > 0) {
- ast_log(LOG_WARNING, "'mgcp reload' is deprecated. Please use 'reload chan_mgcp.so' instead.\n");
- deprecated = 1;
- }
-
- ast_mutex_lock(&mgcp_reload_lock);
- if (mgcp_reloading) {
- ast_verbose("Previous mgcp reload not yet done\n");
- } else
- mgcp_reloading = 1;
- ast_mutex_unlock(&mgcp_reload_lock);
- restart_monitor();
- return 0;
-}
-
-static int reload(void)
-{
- mgcp_reload(0, 0, NULL);
- return 0;
-}
-
-static int unload_module(void)
-{
- struct mgcp_endpoint *e;
- struct mgcp_gateway *g;
-
- /* Check to see if we're reloading */
- if (ast_mutex_trylock(&mgcp_reload_lock)) {
- ast_log(LOG_WARNING, "MGCP is currently reloading. Unable to remove module.\n");
- return -1;
- } else {
- mgcp_reloading = 1;
- ast_mutex_unlock(&mgcp_reload_lock);
- }
-
- /* First, take us out of the channel loop */
- ast_channel_unregister(&mgcp_tech);
-
- /* Shut down the monitoring thread */
- if (!ast_mutex_lock(&monlock)) {
- if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP)) {
- pthread_cancel(monitor_thread);
- pthread_kill(monitor_thread, SIGURG);
- pthread_join(monitor_thread, NULL);
- }
- monitor_thread = AST_PTHREADT_STOP;
- ast_mutex_unlock(&monlock);
- } else {
- ast_log(LOG_WARNING, "Unable to lock the monitor\n");
- /* We always want to leave this in a consistent state */
- ast_channel_register(&mgcp_tech);
- mgcp_reloading = 0;
- mgcp_reload(0, 0, NULL);
- return -1;
- }
-
- if (!ast_mutex_lock(&gatelock)) {
- for (g = gateways; g; g = g->next) {
- g->delme = 1;
- for (e = g->endpoints; e; e = e->next)
- e->delme = 1;
- }
-
- prune_gateways();
- ast_mutex_unlock(&gatelock);
- } else {
- ast_log(LOG_WARNING, "Unable to lock the gateways list.\n");
- /* We always want to leave this in a consistent state */
- ast_channel_register(&mgcp_tech);
- /* Allow the monitor to restart */
- monitor_thread = AST_PTHREADT_NULL;
- mgcp_reloading = 0;
- mgcp_reload(0, 0, NULL);
- return -1;
- }
-
- close(mgcpsock);
- ast_rtp_proto_unregister(&mgcp_rtp);
- ast_cli_unregister_multiple(cli_mgcp, sizeof(cli_mgcp) / sizeof(struct ast_cli_entry));
- sched_context_destroy(sched);
-
- return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Media Gateway Control Protocol (MGCP)",
- .load = load_module,
- .unload = unload_module,
- .reload = reload,
- );
diff --git a/1.4.23-rc4/channels/chan_misdn.c b/1.4.23-rc4/channels/chan_misdn.c
deleted file mode 100644
index c5965a1c1..000000000
--- a/1.4.23-rc4/channels/chan_misdn.c
+++ /dev/null
@@ -1,5775 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2004 - 2006, Christian Richter
- *
- * Christian Richter <crich@beronet.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- *
- */
-
-/*!
- * \file
- *
- * \brief the chan_misdn channel driver for Asterisk
- *
- * \author Christian Richter <crich@beronet.com>
- *
- * \extref MISDN http://www.misdn.org/
- *
- * \ingroup channel_drivers
- */
-
-/*** MODULEINFO
- <depend>isdnnet</depend>
- <depend>misdn</depend>
- <depend>suppserv</depend>
- ***/
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
-#include <stdio.h>
-#include <pthread.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/time.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <arpa/inet.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <signal.h>
-#include <sys/file.h>
-#include <semaphore.h>
-
-#include "asterisk/channel.h"
-#include "asterisk/config.h"
-#include "asterisk/logger.h"
-#include "asterisk/module.h"
-#include "asterisk/pbx.h"
-#include "asterisk/options.h"
-#include "asterisk/io.h"
-#include "asterisk/frame.h"
-#include "asterisk/translate.h"
-#include "asterisk/cli.h"
-#include "asterisk/musiconhold.h"
-#include "asterisk/dsp.h"
-#include "asterisk/translate.h"
-#include "asterisk/config.h"
-#include "asterisk/file.h"
-#include "asterisk/callerid.h"
-#include "asterisk/indications.h"
-#include "asterisk/app.h"
-#include "asterisk/features.h"
-#include "asterisk/term.h"
-#include "asterisk/sched.h"
-#include "asterisk/stringfields.h"
-#include "asterisk/causes.h"
-
-#include "chan_misdn_config.h"
-#include "isdn_lib.h"
-
-char global_tracefile[BUFFERSIZE + 1];
-
-static int g_config_initialized = 0;
-
-struct misdn_jb{
- int size;
- int upper_threshold;
- char *samples, *ok;
- int wp,rp;
- int state_empty;
- int state_full;
- int state_buffer;
- int bytes_wrote;
- ast_mutex_t mutexjb;
-};
-
-
-
-/*! \brief allocates the jb-structure and initialize the elements */
-struct misdn_jb *misdn_jb_init(int size, int upper_threshold);
-
-/*! \brief frees the data and destroys the given jitterbuffer struct */
-void misdn_jb_destroy(struct misdn_jb *jb);
-
-/*! \brief fills the jitterbuffer with len data returns < 0 if there was an
-error (buffer overrun). */
-int misdn_jb_fill(struct misdn_jb *jb, const char *data, int len);
-
-/*! \brief gets len bytes out of the jitterbuffer if available, else only the
-available data is returned and the return value indicates the number
-of data. */
-int misdn_jb_empty(struct misdn_jb *jb, char *data, int len);
-
-
-/* BEGIN: chan_misdn.h */
-
-ast_mutex_t release_lock;
-
-enum misdn_chan_state {
- MISDN_NOTHING=0, /*!< at beginning */
- MISDN_WAITING4DIGS, /*!< when waiting for infos */
- MISDN_EXTCANTMATCH, /*!< when asterisk couldn't match our ext */
- MISDN_INCOMING_SETUP, /*!< for incoming setups*/
- MISDN_DIALING, /*!< when pbx_start */
- MISDN_PROGRESS, /*!< we got a progress */
- MISDN_PROCEEDING, /*!< we got a progress */
- MISDN_CALLING, /*!< when misdn_call is called */
- MISDN_CALLING_ACKNOWLEDGE, /*!< when we get SETUP_ACK */
- MISDN_ALERTING, /*!< when Alerting */
- MISDN_BUSY, /*!< when BUSY */
- MISDN_CONNECTED, /*!< when connected */
- MISDN_PRECONNECTED, /*!< when connected */
- MISDN_DISCONNECTED, /*!< when connected */
- MISDN_RELEASED, /*!< when connected */
- MISDN_BRIDGED, /*!< when bridged */
- MISDN_CLEANING, /*!< when hangup from * but we were connected before */
- MISDN_HUNGUP_FROM_MISDN, /*!< when DISCONNECT/RELEASE/REL_COMP came from misdn */
- MISDN_HUNGUP_FROM_AST, /*!< when DISCONNECT/RELEASE/REL_COMP came out of misdn_hangup */
- MISDN_HOLDED, /*!< if this chan is holded */
- MISDN_HOLD_DISCONNECT, /*!< if this chan is holded */
-
-};
-
-#define ORG_AST 1
-#define ORG_MISDN 2
-
-struct hold_info {
- /*!
- * \brief Logical port the channel call record is HOLDED on
- * because the B channel is no longer associated.
- */
- int port;
-
- /*!
- * \brief Original B channel number the HOLDED call was using.
- * \note Used only for debug display messages.
- */
- int channel;
-};
-
-/*!
- * \brief Channel call record structure
- */
-struct chan_list {
- /*!
- * \brief The "allowed_bearers" string read in from /etc/asterisk/misdn.conf
- */
- char allowed_bearers[BUFFERSIZE + 1];
-
- /*!
- * \brief State of the channel
- */
- enum misdn_chan_state state;
-
- /*!
- * \brief TRUE if a hangup needs to be queued
- * \note This is a debug flag only used to catch calls to hangup_chan() that are already hungup.
- */
- int need_queue_hangup;
-
- /*!
- * \brief TRUE if a channel can be hung up by calling asterisk directly when done.
- */
- int need_hangup;
-
- /*!
- * \brief TRUE if we could send an AST_CONTROL_BUSY if needed.
- */
- int need_busy;
-
- /*!
- * \brief Who originally created this channel. ORG_AST or ORG_MISDN
- */
- int originator;
-
- /*!
- * \brief TRUE of we are not to respond immediately to a SETUP message. Check the dialplan first.
- * \note The "noautorespond_on_setup" boolean read in from /etc/asterisk/misdn.conf
- */
- int noautorespond_on_setup;
-
- int norxtone; /* Boolean assigned values but the value is not used. */
-
- /*!
- * \brief TRUE if we are not to generate tones (Playtones)
- */
- int notxtone;
-
- /*!
- * \brief TRUE if echo canceller is enabled. Value is toggled.
- */
- int toggle_ec;
-
- /*!
- * \brief TRUE if you want to send Tone Indications to an incoming
- * ISDN channel on a TE Port.
- * \note The "incoming_early_audio" boolean read in from /etc/asterisk/misdn.conf
- */
- int incoming_early_audio;
-
- /*!
- * \brief TRUE if DTMF digits are to be passed inband only.
- * \note It is settable by the misdn_set_opt() application.
- */
- int ignore_dtmf;
-
- /*!
- * \brief Pipe file descriptor handles array.
- * Read from pipe[0], write to pipe[1]
- */
- int pipe[2];
-
- /*!
- * \brief Read buffer for inbound audio from pipe[0]
- */
- char ast_rd_buf[4096];
-
- /*!
- * \brief Inbound audio frame returned by misdn_read().
- */
- struct ast_frame frame;
-
- /*!
- * \brief Fax detection option. (0:no 1:yes 2:yes+nojump)
- * \note The "faxdetect" option string read in from /etc/asterisk/misdn.conf
- * \note It is settable by the misdn_set_opt() application.
- */
- int faxdetect;
-
- /*!
- * \brief Number of seconds to detect a Fax machine when detection enabled.
- * \note 0 disables the timeout.
- * \note The "faxdetect_timeout" value read in from /etc/asterisk/misdn.conf
- */
- int faxdetect_timeout;
-
- /*!
- * \brief Starting time of fax detection with timeout when nonzero.
- */
- struct timeval faxdetect_tv;
-
- /*!
- * \brief TRUE if a fax has been detected.
- */
- int faxhandled;
-
- /*!
- * \brief TRUE if we will use the Asterisk DSP to detect DTMF/Fax
- * \note The "astdtmf" boolean read in from /etc/asterisk/misdn.conf
- */
- int ast_dsp;
-
- /*!
- * \brief Jitterbuffer length
- * \note The "jitterbuffer" value read in from /etc/asterisk/misdn.conf
- */
- int jb_len;
-
- /*!
- * \brief Jitterbuffer upper threshold
- * \note The "jitterbuffer_upper_threshold" value read in from /etc/asterisk/misdn.conf
- */
- int jb_upper_threshold;
-
- /*!
- * \brief Allocated jitterbuffer controller
- * \note misdn_jb_init() creates the jitterbuffer.
- * \note Must use misdn_jb_destroy() to clean up.
- */
- struct misdn_jb *jb;
-
- /*!
- * \brief Allocated DSP controller
- * \note ast_dsp_new() creates the DSP controller.
- * \note Must use ast_dsp_free() to clean up.
- */
- struct ast_dsp *dsp;
-
- /*!
- * \brief Allocated audio frame sample translator
- * \note ast_translator_build_path() creates the translator path.
- * \note Must use ast_translator_free_path() to clean up.
- */
- struct ast_trans_pvt *trans;
-
- /*!
- * \brief Associated Asterisk channel structure.
- */
- struct ast_channel * ast;
-
- //int dummy; /* Not used */
-
- /*!
- * \brief Associated B channel structure.
- */
- struct misdn_bchannel *bc;
-
- /*!
- * \brief HOLDED channel information
- */
- struct hold_info hold_info;
-
- /*!
- * \brief From associated B channel: Layer 3 process ID
- * \note Used to find the HOLDED channel call record when retrieving a call.
- */
- unsigned int l3id;
-
- /*!
- * \brief From associated B channel: B Channel mISDN driver layer ID from mISDN_get_layerid()
- * \note Used only for debug display messages.
- */
- int addr;
-
- /*!
- * \brief Incoming call dialplan context identifier.
- * \note The "context" string read in from /etc/asterisk/misdn.conf
- */
- char context[AST_MAX_CONTEXT];
-
- /*!
- * \brief The configured music-on-hold class to use for this call.
- * \note The "musicclass" string read in from /etc/asterisk/misdn.conf
- */
- char mohinterpret[MAX_MUSICCLASS];
-
- //int zero_read_cnt; /* Not used */
-
- /*!
- * \brief Number of outgoing audio frames dropped since last debug gripe message.
- */
- int dropped_frame_cnt;
-
- /*!
- * \brief TRUE if we must do the ringback tones.
- * \note The "far_alerting" boolean read in from /etc/asterisk/misdn.conf
- */
- int far_alerting;
-
- /*!
- * \brief TRUE if NT should disconnect an overlap dialing call when a timeout occurs.
- * \note The "nttimeout" boolean read in from /etc/asterisk/misdn.conf
- */
- int nttimeout;
-
- /*!
- * \brief Other channel call record PID
- * \note Value imported from Asterisk environment variable MISDN_PID
- */
- int other_pid;
-
- /*!
- * \brief Bridged other channel call record
- * \note Pointer set when other_pid imported from Asterisk environment
- * variable MISDN_PID by either side.
- */
- struct chan_list *other_ch;
-
- /*!
- * \brief Tone zone sound used for dialtone generation.
- * \note Used as a boolean. Non-NULL to prod generation if enabled.
- */
- const struct tone_zone_sound *ts;
-
- /*!
- * \brief Enables overlap dialing for the set amount of seconds. (0 = Disabled)
- * \note The "overlapdial" value read in from /etc/asterisk/misdn.conf
- */
- int overlap_dial;
-
- /*!
- * \brief Overlap dialing timeout Task ID. -1 if not running.
- */
- int overlap_dial_task;
-
- /*!
- * \brief overlap_tv access lock.
- */
- ast_mutex_t overlap_tv_lock;
-
- /*!
- * \brief Overlap timer start time. Timer restarted for every digit received.
- */
- struct timeval overlap_tv;
-
- //struct chan_list *peer; /* Not used */
-
- /*!
- * \brief Next channel call record in the list.
- */
- struct chan_list *next;
- //struct chan_list *prev; /* Not used */
- //struct chan_list *first; /* Not used */
-};
-
-
-
-void export_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch);
-void import_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch);
-
-struct robin_list {
- char *group;
- int port;
- int channel;
- struct robin_list *next;
- struct robin_list *prev;
-};
-static struct robin_list *robin = NULL;
-
-
-
-static struct ast_frame *process_ast_dsp(struct chan_list *tmp, struct ast_frame *frame);
-
-
-
-static inline void free_robin_list_r (struct robin_list *r)
-{
- if (r) {
- if (r->next)
- free_robin_list_r(r->next);
- if (r->group)
- free(r->group);
- free(r);
- }
-}
-
-static void free_robin_list ( void )
-{
- free_robin_list_r(robin);
- robin = NULL;
-}
-
-static struct robin_list* get_robin_position (char *group)
-{
- struct robin_list *new;
- struct robin_list *iter = robin;
- for (; iter; iter = iter->next) {
- if (!strcasecmp(iter->group, group))
- return iter;
- }
- new = (struct robin_list *) calloc(1, sizeof(struct robin_list));
- new->group = strndup(group, strlen(group));
- new->port = 0;
- new->channel = 0;
- if (robin) {
- new->next = robin;
- robin->prev = new;
- }
- robin = new;
- return robin;
-}
-
-
-/*! \brief the main schedule context for stuff like l1 watcher, overlap dial, ... */
-static struct sched_context *misdn_tasks = NULL;
-static pthread_t misdn_tasks_thread;
-
-static int *misdn_ports;
-
-static void chan_misdn_log(int level, int port, char *tmpl, ...)
- __attribute__((format(printf, 3, 4)));
-
-static struct ast_channel *misdn_new(struct chan_list *cl, int state, char *exten, char *callerid, int format, int port, int c);
-static void send_digit_to_chan(struct chan_list *cl, char digit );
-
-static void hangup_chan(struct chan_list *ch);
-static int pbx_start_chan(struct chan_list *ch);
-
-#define MISDN_ASTERISK_TECH_PVT(ast) ast->tech_pvt
-#define MISDN_ASTERISK_PVT(ast) 1
-
-#include "asterisk/strings.h"
-
-/* #define MISDN_DEBUG 1 */
-
-static const char misdn_type[] = "mISDN";
-
-static int tracing = 0 ;
-
-/*! \brief Only alaw and mulaw is allowed for now */
-static int prefformat = AST_FORMAT_ALAW ; /* AST_FORMAT_SLINEAR ; AST_FORMAT_ULAW | */
-
-static int *misdn_debug;
-static int *misdn_debug_only;
-static int max_ports;
-
-static int *misdn_in_calls;
-static int *misdn_out_calls;
-
-
-struct chan_list dummy_cl;
-
-/*!
- * \brief Global channel call record list head.
- */
-struct chan_list *cl_te=NULL;
-ast_mutex_t cl_te_lock;
-
-static enum event_response_e
-cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data);
-
-static void send_cause2ast(struct ast_channel *ast, struct misdn_bchannel*bc, struct chan_list *ch);
-
-static void cl_queue_chan(struct chan_list **list, struct chan_list *chan);
-static void cl_dequeue_chan(struct chan_list **list, struct chan_list *chan);
-static struct chan_list *find_chan_by_bc(struct chan_list *list, struct misdn_bchannel *bc);
-static struct chan_list *find_chan_by_pid(struct chan_list *list, int pid);
-
-
-
-static int dialtone_indicate(struct chan_list *cl);
-static int hanguptone_indicate(struct chan_list *cl);
-static int stop_indicate(struct chan_list *cl);
-
-static int start_bc_tones(struct chan_list *cl);
-static int stop_bc_tones(struct chan_list *cl);
-static void release_chan(struct misdn_bchannel *bc);
-
-static int misdn_check_l2l1(struct ast_channel *chan, void *data);
-static int misdn_set_opt_exec(struct ast_channel *chan, void *data);
-static int misdn_facility_exec(struct ast_channel *chan, void *data);
-
-int chan_misdn_jb_empty(struct misdn_bchannel *bc, char *buf, int len);
-
-
-void debug_numplan(int port, int numplan, char *type);
-
-
-int add_out_calls(int port);
-int add_in_calls(int port);
-
-
-#ifdef MISDN_1_2
-static int update_pipeline_config(struct misdn_bchannel *bc);
-#else
-static int update_ec_config(struct misdn_bchannel *bc);
-#endif
-
-
-
-/*************** Helpers *****************/
-
-static struct chan_list * get_chan_by_ast(struct ast_channel *ast)
-{
- struct chan_list *tmp;
-
- for (tmp=cl_te; tmp; tmp = tmp->next) {
- if ( tmp->ast == ast ) return tmp;
- }
-
- return NULL;
-}
-
-static struct chan_list * get_chan_by_ast_name(char *name)
-{
- struct chan_list *tmp;
-
- for (tmp=cl_te; tmp; tmp = tmp->next) {
- if ( tmp->ast && strcmp(tmp->ast->name,name) == 0) return tmp;
- }
-
- return NULL;
-}
-
-
-
-struct allowed_bearers {
- char *name; /*!< Bearer capability name string used in /etc/misdn.conf allowed_bearers */
- char *display; /*!< Bearer capability displayable name */
- int cap; /*!< SETUP message bearer capability field code value */
- int deprecated; /*!< TRUE if this entry is deprecated. (Misspelled or bad name to use) */
-};
-
-/* *INDENT-OFF* */
-static const struct allowed_bearers allowed_bearers_array[]= {
- /* Name, Displayable Name Bearer Capability, Deprecated */
- { "speech", "Speech", INFO_CAPABILITY_SPEECH, 0 },
- { "3_1khz", "3.1KHz Audio", INFO_CAPABILITY_AUDIO_3_1K, 0 },
- { "digital_unrestricted", "Unrestricted Digital", INFO_CAPABILITY_DIGITAL_UNRESTRICTED, 0 },
- { "digital_restricted", "Restricted Digital", INFO_CAPABILITY_DIGITAL_RESTRICTED, 0 },
- { "digital_restriced", "Restricted Digital", INFO_CAPABILITY_DIGITAL_RESTRICTED, 1 }, /* Allow misspelling for backwards compatibility */
- { "video", "Video", INFO_CAPABILITY_VIDEO, 0 }
-};
-/* *INDENT-ON* */
-
-static const char *bearer2str(int cap)
-{
- unsigned index;
-
- for (index = 0; index < ARRAY_LEN(allowed_bearers_array); ++index) {
- if (allowed_bearers_array[index].cap == cap) {
- return allowed_bearers_array[index].display;
- }
- } /* end for */
-
- return "Unknown Bearer";
-}
-
-
-static void print_facility(struct FacParm *fac, struct misdn_bchannel *bc)
-{
- switch (fac->Function) {
- case Fac_CD:
- chan_misdn_log(1,bc->port," --> calldeflect to: %s, presentable: %s\n", fac->u.CDeflection.DeflectedToNumber,
- fac->u.CDeflection.PresentationAllowed ? "yes" : "no");
- break;
- case Fac_AOCDCurrency:
- if (fac->u.AOCDcur.chargeNotAvailable)
- chan_misdn_log(1,bc->port," --> AOCD currency: charge not available\n");
- else if (fac->u.AOCDcur.freeOfCharge)
- chan_misdn_log(1,bc->port," --> AOCD currency: free of charge\n");
- else if (fac->u.AOCDchu.billingId >= 0)
- chan_misdn_log(1,bc->port," --> AOCD currency: currency:%s amount:%d multiplier:%d typeOfChargingInfo:%s billingId:%d\n",
- fac->u.AOCDcur.currency, fac->u.AOCDcur.currencyAmount, fac->u.AOCDcur.multiplier,
- (fac->u.AOCDcur.typeOfChargingInfo == 0) ? "subTotal" : "total", fac->u.AOCDcur.billingId);
- else
- chan_misdn_log(1,bc->port," --> AOCD currency: currency:%s amount:%d multiplier:%d typeOfChargingInfo:%s\n",
- fac->u.AOCDcur.currency, fac->u.AOCDcur.currencyAmount, fac->u.AOCDcur.multiplier,
- (fac->u.AOCDcur.typeOfChargingInfo == 0) ? "subTotal" : "total");
- break;
- case Fac_AOCDChargingUnit:
- if (fac->u.AOCDchu.chargeNotAvailable)
- chan_misdn_log(1,bc->port," --> AOCD charging unit: charge not available\n");
- else if (fac->u.AOCDchu.freeOfCharge)
- chan_misdn_log(1,bc->port," --> AOCD charging unit: free of charge\n");
- else if (fac->u.AOCDchu.billingId >= 0)
- chan_misdn_log(1,bc->port," --> AOCD charging unit: recordedUnits:%d typeOfChargingInfo:%s billingId:%d\n",
- fac->u.AOCDchu.recordedUnits, (fac->u.AOCDchu.typeOfChargingInfo == 0) ? "subTotal" : "total", fac->u.AOCDchu.billingId);
- else
- chan_misdn_log(1,bc->port," --> AOCD charging unit: recordedUnits:%d typeOfChargingInfo:%s\n",
- fac->u.AOCDchu.recordedUnits, (fac->u.AOCDchu.typeOfChargingInfo == 0) ? "subTotal" : "total");
- break;
- default:
- chan_misdn_log(1,bc->port," --> unknown facility\n");
- break;
- }
-}
-
-static void print_bearer(struct misdn_bchannel *bc)
-{
-
- chan_misdn_log(2, bc->port, " --> Bearer: %s\n",bearer2str(bc->capability));
-
- switch(bc->law) {
- case INFO_CODEC_ALAW:
- chan_misdn_log(2, bc->port, " --> Codec: Alaw\n");
- break;
- case INFO_CODEC_ULAW:
- chan_misdn_log(2, bc->port, " --> Codec: Ulaw\n");
- break;
- }
-}
-
-static void export_aoc_vars(int originator, struct ast_channel *ast, struct misdn_bchannel *bc)
-{
- char buf[128];
-
- if (!ast)
- return;
-
- if (originator == ORG_AST) {
- ast = ast_bridged_channel(ast);
- if (!ast)
- return;
- }
-
- switch (bc->AOCDtype) {
- case Fac_AOCDCurrency:
- pbx_builtin_setvar_helper(ast, "AOCD_Type", "currency");
- if (bc->AOCD.currency.chargeNotAvailable)
- pbx_builtin_setvar_helper(ast, "AOCD_ChargeAvailable", "no");
- else {
- pbx_builtin_setvar_helper(ast, "AOCD_ChargeAvailable", "yes");
- if (bc->AOCD.currency.freeOfCharge)
- pbx_builtin_setvar_helper(ast, "AOCD_FreeOfCharge", "yes");
- else {
- pbx_builtin_setvar_helper(ast, "AOCD_FreeOfCharge", "no");
- if (snprintf(buf, sizeof(buf), "%d %s", bc->AOCD.currency.currencyAmount * bc->AOCD.currency.multiplier, bc->AOCD.currency.currency) < sizeof(buf)) {
- pbx_builtin_setvar_helper(ast, "AOCD_Amount", buf);
- if (bc->AOCD.currency.billingId >= 0 && snprintf(buf, sizeof(buf), "%d", bc->AOCD.currency.billingId) < sizeof(buf))
- pbx_builtin_setvar_helper(ast, "AOCD_BillingId", buf);
- }
- }
- }
- break;
- case Fac_AOCDChargingUnit:
- pbx_builtin_setvar_helper(ast, "AOCD_Type", "charging_unit");
- if (bc->AOCD.chargingUnit.chargeNotAvailable)
- pbx_builtin_setvar_helper(ast, "AOCD_ChargeAvailable", "no");
- else {
- pbx_builtin_setvar_helper(ast, "AOCD_ChargeAvailable", "yes");
- if (bc->AOCD.chargingUnit.freeOfCharge)
- pbx_builtin_setvar_helper(ast, "AOCD_FreeOfCharge", "yes");
- else {
- pbx_builtin_setvar_helper(ast, "AOCD_FreeOfCharge", "no");
- if (snprintf(buf, sizeof(buf), "%d", bc->AOCD.chargingUnit.recordedUnits) < sizeof(buf)) {
- pbx_builtin_setvar_helper(ast, "AOCD_RecordedUnits", buf);
- if (bc->AOCD.chargingUnit.billingId >= 0 && snprintf(buf, sizeof(buf), "%d", bc->AOCD.chargingUnit.billingId) < sizeof(buf))
- pbx_builtin_setvar_helper(ast, "AOCD_BillingId", buf);
- }
- }
- }
- break;
- default:
- break;
- }
-}
-
-/*************** Helpers END *************/
-
-static void sighandler(int sig)
-{}
-
-static void* misdn_tasks_thread_func (void *data)
-{
- int wait;
- struct sigaction sa;
-
- sa.sa_handler = sighandler;
- sa.sa_flags = SA_NODEFER;
- sigemptyset(&sa.sa_mask);
- sigaddset(&sa.sa_mask, SIGUSR1);
- sigaction(SIGUSR1, &sa, NULL);
-
- sem_post((sem_t *)data);
-
- while (1) {
- wait = ast_sched_wait(misdn_tasks);
- if (wait < 0)
- wait = 8000;
- if (poll(NULL, 0, wait) < 0)
- chan_misdn_log(4, 0, "Waking up misdn_tasks thread\n");
- ast_sched_runq(misdn_tasks);
- }
- return NULL;
-}
-
-static void misdn_tasks_init (void)
-{
- sem_t blocker;
- int i = 5;
-
- if (sem_init(&blocker, 0, 0)) {
- perror("chan_misdn: Failed to initialize semaphore!");
- exit(1);
- }
-
- chan_misdn_log(4, 0, "Starting misdn_tasks thread\n");
-
- misdn_tasks = sched_context_create();
- pthread_create(&misdn_tasks_thread, NULL, misdn_tasks_thread_func, &blocker);
-
- while (sem_wait(&blocker) && --i);
- sem_destroy(&blocker);
-}
-
-static void misdn_tasks_destroy (void)
-{
- if (misdn_tasks) {
- chan_misdn_log(4, 0, "Killing misdn_tasks thread\n");
- if ( pthread_cancel(misdn_tasks_thread) == 0 ) {
- cb_log(4, 0, "Joining misdn_tasks thread\n");
- pthread_join(misdn_tasks_thread, NULL);
- }
- sched_context_destroy(misdn_tasks);
- }
-}
-
-static inline void misdn_tasks_wakeup (void)
-{
- pthread_kill(misdn_tasks_thread, SIGUSR1);
-}
-
-static inline int _misdn_tasks_add_variable (int timeout, ast_sched_cb callback, const void *data, int variable)
-{
- int task_id;
-
- if (!misdn_tasks) {
- misdn_tasks_init();
- }
- task_id = ast_sched_add_variable(misdn_tasks, timeout, callback, data, variable);
- misdn_tasks_wakeup();
-
- return task_id;
-}
-
-static int misdn_tasks_add (int timeout, ast_sched_cb callback, const void *data)
-{
- return _misdn_tasks_add_variable(timeout, callback, data, 0);
-}
-
-static int misdn_tasks_add_variable (int timeout, ast_sched_cb callback, const void *data)
-{
- return _misdn_tasks_add_variable(timeout, callback, data, 1);
-}
-
-static void misdn_tasks_remove (int task_id)
-{
- AST_SCHED_DEL(misdn_tasks, task_id);
-}
-
-static int misdn_l1_task (const void *data)
-{
- misdn_lib_isdn_l1watcher(*(int *)data);
- chan_misdn_log(5, *(int *)data, "L1watcher timeout\n");
- return 1;
-}
-
-static int misdn_overlap_dial_task (const void *data)
-{
- struct timeval tv_end, tv_now;
- int diff;
- struct chan_list *ch = (struct chan_list *)data;
-
- chan_misdn_log(4, ch->bc->port, "overlap dial task, chan_state: %d\n", ch->state);
-
- if (ch->state != MISDN_WAITING4DIGS) {
- ch->overlap_dial_task = -1;
- return 0;
- }
-
- ast_mutex_lock(&ch->overlap_tv_lock);
- tv_end = ch->overlap_tv;
- ast_mutex_unlock(&ch->overlap_tv_lock);
-
- tv_end.tv_sec += ch->overlap_dial;
- tv_now = ast_tvnow();
-
- diff = ast_tvdiff_ms(tv_end, tv_now);
-
- if (diff <= 100) {
- char *dad=ch->bc->dad, sexten[]="s";
- /* if we are 100ms near the timeout, we are satisfied.. */
- stop_indicate(ch);
-
- if (ast_strlen_zero(ch->bc->dad)) {
- dad=sexten;
- strcpy(ch->ast->exten, sexten);
- }
-
- if (ast_exists_extension(ch->ast, ch->context, dad, 1, ch->bc->oad)) {
- ch->state=MISDN_DIALING;
- if (pbx_start_chan(ch) < 0) {
- chan_misdn_log(-1, ch->bc->port, "ast_pbx_start returned < 0 in misdn_overlap_dial_task\n");
- goto misdn_overlap_dial_task_disconnect;
- }
- } else {
-misdn_overlap_dial_task_disconnect:
- hanguptone_indicate(ch);
- ch->bc->out_cause = AST_CAUSE_UNALLOCATED;
- ch->state=MISDN_CLEANING;
- misdn_lib_send_event(ch->bc, EVENT_DISCONNECT);
- }
- ch->overlap_dial_task = -1;
- return 0;
- } else
- return diff;
-}
-
-static void send_digit_to_chan(struct chan_list *cl, char digit )
-{
- static const char* dtmf_tones[] = {
- "!941+1336/100,!0/100", /* 0 */
- "!697+1209/100,!0/100", /* 1 */
- "!697+1336/100,!0/100", /* 2 */
- "!697+1477/100,!0/100", /* 3 */
- "!770+1209/100,!0/100", /* 4 */
- "!770+1336/100,!0/100", /* 5 */
- "!770+1477/100,!0/100", /* 6 */
- "!852+1209/100,!0/100", /* 7 */
- "!852+1336/100,!0/100", /* 8 */
- "!852+1477/100,!0/100", /* 9 */
- "!697+1633/100,!0/100", /* A */
- "!770+1633/100,!0/100", /* B */
- "!852+1633/100,!0/100", /* C */
- "!941+1633/100,!0/100", /* D */
- "!941+1209/100,!0/100", /* * */
- "!941+1477/100,!0/100" }; /* # */
- struct ast_channel *chan=cl->ast;
-
- if (digit >= '0' && digit <='9')
- ast_playtones_start(chan,0,dtmf_tones[digit-'0'], 0);
- else if (digit >= 'A' && digit <= 'D')
- ast_playtones_start(chan,0,dtmf_tones[digit-'A'+10], 0);
- else if (digit == '*')
- ast_playtones_start(chan,0,dtmf_tones[14], 0);
- else if (digit == '#')
- ast_playtones_start(chan,0,dtmf_tones[15], 0);
- else {
- /* not handled */
- ast_log(LOG_DEBUG, "Unable to handle DTMF tone '%c' for '%s'\n", digit, chan->name);
- }
-}
-
-/*** CLI HANDLING ***/
-static int misdn_set_debug(int fd, int argc, char *argv[])
-{
- int level;
-
- if (argc != 4 && argc != 5 && argc != 6 && argc != 7)
- return RESULT_SHOWUSAGE;
-
- level = atoi(argv[3]);
-
- switch (argc) {
- case 4:
- case 5:
- {
- int i;
- int only = 0;
- if (argc == 5) {
- if (strncasecmp(argv[4], "only", strlen(argv[4])))
- return RESULT_SHOWUSAGE;
- else
- only = 1;
- }
-
- for (i = 0; i <= max_ports; i++) {
- misdn_debug[i] = level;
- misdn_debug_only[i] = only;
- }
- ast_cli(fd, "changing debug level for all ports to %d%s\n",misdn_debug[0], only?" (only)":"");
- }
- break;
- case 6:
- case 7:
- {
- int port;
- if (strncasecmp(argv[4], "port", strlen(argv[4])))
- return RESULT_SHOWUSAGE;
- port = atoi(argv[5]);
- if (port <= 0 || port > max_ports) {
- switch (max_ports) {
- case 0:
- ast_cli(fd, "port number not valid! no ports available so you won't get lucky with any number here...\n");
- break;
- case 1:
- ast_cli(fd, "port number not valid! only port 1 is available.\n");
- break;
- default:
- ast_cli(fd, "port number not valid! only ports 1 to %d are available.\n", max_ports);
- }
- return 0;
- }
- if (argc == 7) {
- if (strncasecmp(argv[6], "only", strlen(argv[6])))
- return RESULT_SHOWUSAGE;
- else
- misdn_debug_only[port] = 1;
- } else
- misdn_debug_only[port] = 0;
- misdn_debug[port] = level;
- ast_cli(fd, "changing debug level to %d%s for port %d\n", misdn_debug[port], misdn_debug_only[port]?" (only)":"", port);
- }
- }
- return 0;
-}
-
-static int misdn_set_crypt_debug(int fd, int argc, char *argv[])
-{
- if (argc != 5) return RESULT_SHOWUSAGE;
-
- return 0;
-}
-
-static int misdn_port_block(int fd, int argc, char *argv[])
-{
- int port;
-
- if (argc != 4)
- return RESULT_SHOWUSAGE;
-
- port = atoi(argv[3]);
-
- misdn_lib_port_block(port);
-
- return 0;
-}
-
-static int misdn_port_unblock(int fd, int argc, char *argv[])
-{
- int port;
-
- if (argc != 4)
- return RESULT_SHOWUSAGE;
-
- port = atoi(argv[3]);
-
- misdn_lib_port_unblock(port);
-
- return 0;
-}
-
-
-static int misdn_restart_port (int fd, int argc, char *argv[])
-{
- int port;
-
- if (argc != 4)
- return RESULT_SHOWUSAGE;
-
- port = atoi(argv[3]);
-
- misdn_lib_port_restart(port);
-
- return 0;
-}
-
-static int misdn_restart_pid (int fd, int argc, char *argv[])
-{
- int pid;
-
- if (argc != 4)
- return RESULT_SHOWUSAGE;
-
- pid = atoi(argv[3]);
-
- misdn_lib_pid_restart(pid);
-
- return 0;
-}
-
-static int misdn_port_up (int fd, int argc, char *argv[])
-{
- int port;
-
- if (argc != 4)
- return RESULT_SHOWUSAGE;
-
- port = atoi(argv[3]);
-
- misdn_lib_get_port_up(port);
-
- return 0;
-}
-
-static int misdn_port_down (int fd, int argc, char *argv[])
-{
- int port;
-
- if (argc != 4)
- return RESULT_SHOWUSAGE;
-
- port = atoi(argv[3]);
-
- misdn_lib_get_port_down(port);
-
- return 0;
-}
-
-static inline void show_config_description (int fd, enum misdn_cfg_elements elem)
-{
- char section[BUFFERSIZE];
- char name[BUFFERSIZE];
- char desc[BUFFERSIZE];
- char def[BUFFERSIZE];
- char tmp[BUFFERSIZE];
-
- misdn_cfg_get_name(elem, tmp, sizeof(tmp));
- term_color(name, tmp, COLOR_BRWHITE, 0, sizeof(tmp));
- misdn_cfg_get_desc(elem, desc, sizeof(desc), def, sizeof(def));
-
- if (elem < MISDN_CFG_LAST)
- term_color(section, "PORTS SECTION", COLOR_YELLOW, 0, sizeof(section));
- else
- term_color(section, "GENERAL SECTION", COLOR_YELLOW, 0, sizeof(section));
-
- if (*def)
- ast_cli(fd, "[%s] %s (Default: %s)\n\t%s\n", section, name, def, desc);
- else
- ast_cli(fd, "[%s] %s\n\t%s\n", section, name, desc);
-}
-
-static int misdn_show_config (int fd, int argc, char *argv[])
-{
- char buffer[BUFFERSIZE];
- enum misdn_cfg_elements elem;
- int linebreak;
- int onlyport = -1;
- int ok = 0;
-
- if (argc >= 4) {
- if (!strcmp(argv[3], "description")) {
- if (argc == 5) {
- enum misdn_cfg_elements elem = misdn_cfg_get_elem(argv[4]);
- if (elem == MISDN_CFG_FIRST)
- ast_cli(fd, "Unknown element: %s\n", argv[4]);
- else
- show_config_description(fd, elem);
- return 0;
- }
- return RESULT_SHOWUSAGE;
- }
- if (!strcmp(argv[3], "descriptions")) {
- if ((argc == 4) || ((argc == 5) && !strcmp(argv[4], "general"))) {
- for (elem = MISDN_GEN_FIRST + 1; elem < MISDN_GEN_LAST; ++elem) {
- show_config_description(fd, elem);
- ast_cli(fd, "\n");
- }
- ok = 1;
- }
- if ((argc == 4) || ((argc == 5) && !strcmp(argv[4], "ports"))) {
- for (elem = MISDN_CFG_FIRST + 1; elem < MISDN_CFG_LAST - 1 /* the ptp hack, remove the -1 when ptp is gone */; ++elem) {
- show_config_description(fd, elem);
- ast_cli(fd, "\n");
- }
- ok = 1;
- }
- return ok ? 0 : RESULT_SHOWUSAGE;
- }
- if (!sscanf(argv[3], "%d", &onlyport) || onlyport < 0) {
- ast_cli(fd, "Unknown option: %s\n", argv[3]);
- return RESULT_SHOWUSAGE;
- }
- }
-
- if (argc == 3 || onlyport == 0) {
- ast_cli(fd, "Misdn General-Config:\n");
- for (elem = MISDN_GEN_FIRST + 1, linebreak = 1; elem < MISDN_GEN_LAST; elem++, linebreak++) {
- misdn_cfg_get_config_string(0, elem, buffer, BUFFERSIZE);
- ast_cli(fd, "%-36s%s", buffer, !(linebreak % 2) ? "\n" : "");
- }
- ast_cli(fd, "\n");
- }
-
- if (onlyport < 0) {
- int port = misdn_cfg_get_next_port(0);
- for (; port > 0; port = misdn_cfg_get_next_port(port)) {
- ast_cli(fd, "\n[PORT %d]\n", port);
- for (elem = MISDN_CFG_FIRST + 1, linebreak = 1; elem < MISDN_CFG_LAST; elem++, linebreak++) {
- misdn_cfg_get_config_string(port, elem, buffer, BUFFERSIZE);
- ast_cli(fd, "%-36s%s", buffer, !(linebreak % 2) ? "\n" : "");
- }
- ast_cli(fd, "\n");
- }
- }
-
- if (onlyport > 0) {
- if (misdn_cfg_is_port_valid(onlyport)) {
- ast_cli(fd, "[PORT %d]\n", onlyport);
- for (elem = MISDN_CFG_FIRST + 1, linebreak = 1; elem < MISDN_CFG_LAST; elem++, linebreak++) {
- misdn_cfg_get_config_string(onlyport, elem, buffer, BUFFERSIZE);
- ast_cli(fd, "%-36s%s", buffer, !(linebreak % 2) ? "\n" : "");
- }
- ast_cli(fd, "\n");
- } else {
- ast_cli(fd, "Port %d is not active!\n", onlyport);
- }
- }
-
- return 0;
-}
-
-struct state_struct {
- enum misdn_chan_state state;
- char txt[255];
-};
-
-static struct state_struct state_array[] = {
- {MISDN_NOTHING,"NOTHING"}, /* at beginning */
- {MISDN_WAITING4DIGS,"WAITING4DIGS"}, /* when waiting for infos */
- {MISDN_EXTCANTMATCH,"EXTCANTMATCH"}, /* when asterisk couldn't match our ext */
- {MISDN_INCOMING_SETUP,"INCOMING SETUP"}, /* when pbx_start */
- {MISDN_DIALING,"DIALING"}, /* when pbx_start */
- {MISDN_PROGRESS,"PROGRESS"}, /* when pbx_start */
- {MISDN_PROCEEDING,"PROCEEDING"}, /* when pbx_start */
- {MISDN_CALLING,"CALLING"}, /* when misdn_call is called */
- {MISDN_CALLING_ACKNOWLEDGE,"CALLING_ACKNOWLEDGE"}, /* when misdn_call is called */
- {MISDN_ALERTING,"ALERTING"}, /* when Alerting */
- {MISDN_BUSY,"BUSY"}, /* when BUSY */
- {MISDN_CONNECTED,"CONNECTED"}, /* when connected */
- {MISDN_PRECONNECTED,"PRECONNECTED"}, /* when connected */
- {MISDN_DISCONNECTED,"DISCONNECTED"}, /* when connected */
- {MISDN_RELEASED,"RELEASED"}, /* when connected */
- {MISDN_BRIDGED,"BRIDGED"}, /* when bridged */
- {MISDN_CLEANING,"CLEANING"}, /* when hangup from * but we were connected before */
- {MISDN_HUNGUP_FROM_MISDN,"HUNGUP_FROM_MISDN"}, /* when DISCONNECT/RELEASE/REL_COMP came from misdn */
- {MISDN_HOLDED,"HOLDED"}, /* when DISCONNECT/RELEASE/REL_COMP came from misdn */
- {MISDN_HOLD_DISCONNECT,"HOLD_DISCONNECT"}, /* when DISCONNECT/RELEASE/REL_COMP came from misdn */
- {MISDN_HUNGUP_FROM_AST,"HUNGUP_FROM_AST"} /* when DISCONNECT/RELEASE/REL_COMP came out of misdn_hangup */
-};
-
-static const char *misdn_get_ch_state(struct chan_list *p)
-{
- int i;
- static char state[8];
-
- if( !p) return NULL;
-
- for (i = 0; i < sizeof(state_array) / sizeof(struct state_struct); i++) {
- if (state_array[i].state == p->state)
- return state_array[i].txt;
- }
-
- snprintf(state, sizeof(state), "%d", p->state) ;
-
- return state;
-}
-
-
-
-static void reload_config(void)
-{
- int i, cfg_debug;
-
- if (!g_config_initialized) {
- ast_log(LOG_WARNING, "chan_misdn is not initialized properly, still reloading ?\n");
- return ;
- }
-
- free_robin_list();
- misdn_cfg_reload();
- misdn_cfg_update_ptp();
- misdn_cfg_get(0, MISDN_GEN_TRACEFILE, global_tracefile, BUFFERSIZE);
- misdn_cfg_get(0, MISDN_GEN_DEBUG, &cfg_debug, sizeof(int));
-
- for (i = 0; i <= max_ports; i++) {
- misdn_debug[i] = cfg_debug;
- misdn_debug_only[i] = 0;
- }
-}
-
-static int misdn_reload (int fd, int argc, char *argv[])
-{
- ast_cli(fd, "Reloading mISDN configuration\n");
- reload_config();
- return 0;
-}
-
-static void print_bc_info (int fd, struct chan_list *help, struct misdn_bchannel *bc)
-{
- struct ast_channel *ast = help->ast;
- ast_cli(fd,
- "* Pid:%d Prt:%d Ch:%d Mode:%s Org:%s dad:%s oad:%s rad:%s ctx:%s state:%s\n",
-
- bc->pid, bc->port, bc->channel,
- bc->nt ? "NT" : "TE",
- help->originator == ORG_AST ? "*" : "I",
- ast ? ast->exten : NULL,
- ast ? ast->cid.cid_num : NULL,
- bc->rad,
- ast ? ast->context : NULL,
- misdn_get_ch_state(help)
- );
- if (misdn_debug[bc->port] > 0)
- ast_cli(fd,
- " --> astname: %s\n"
- " --> ch_l3id: %x\n"
- " --> ch_addr: %x\n"
- " --> bc_addr: %x\n"
- " --> bc_l3id: %x\n"
- " --> display: %s\n"
- " --> activated: %d\n"
- " --> state: %s\n"
- " --> capability: %s\n"
-#ifdef MISDN_1_2
- " --> pipeline: %s\n"
-#else
- " --> echo_cancel: %d\n"
-#endif
- " --> notone : rx %d tx:%d\n"
- " --> bc_hold: %d\n",
- help->ast->name,
- help->l3id,
- help->addr,
- bc->addr,
- bc ? bc->l3_id : -1,
- bc->display,
-
- bc->active,
- bc_state2str(bc->bc_state),
- bearer2str(bc->capability),
-#ifdef MISDN_1_2
- bc->pipeline,
-#else
- bc->ec_enable,
-#endif
-
- help->norxtone, help->notxtone,
- bc->holded
- );
-
-}
-
-static int misdn_show_cls (int fd, int argc, char *argv[])
-{
- struct chan_list *help;
-
- help = cl_te;
-
- ast_cli(fd, "Channel List: %p\n", cl_te);
-
- for (; help; help = help->next) {
- struct misdn_bchannel *bc = help->bc;
- struct ast_channel *ast = help->ast;
- if (!ast) {
- if (!bc) {
- ast_cli(fd, "chan_list obj. with l3id:%x has no bc and no ast Leg\n", help->l3id);
- continue;
- }
- ast_cli(fd, "bc with pid:%d has no Ast Leg\n", bc->pid);
- continue;
- }
-
- if (misdn_debug[0] > 2)
- ast_cli(fd, "Bc:%p Ast:%p\n", bc, ast);
- if (bc) {
- print_bc_info(fd, help, bc);
- } else {
- if (help->state == MISDN_HOLDED) {
- ast_cli(fd, "ITS A HOLDED BC:\n");
- ast_cli(fd, " --> l3_id: %x\n"
- " --> dad:%s oad:%s\n"
- " --> hold_port: %d\n"
- " --> hold_channel: %d\n",
- help->l3id,
- ast->exten,
- ast->cid.cid_num,
- help->hold_info.port,
- help->hold_info.channel
- );
- } else {
- ast_cli(fd, "* Channel in unknown STATE !!! Exten:%s, Callerid:%s\n", ast->exten, ast->cid.cid_num);
- }
- }
- }
-
- misdn_dump_chanlist();
-
- return 0;
-}
-
-static int misdn_show_cl (int fd, int argc, char *argv[])
-{
- struct chan_list *help;
-
- if (argc != 4)
- return RESULT_SHOWUSAGE;
-
- help = cl_te;
-
- for (; help; help = help->next) {
- struct misdn_bchannel *bc = help->bc;
- struct ast_channel *ast = help->ast;
-
- if (bc && ast) {
- if (!strcasecmp(ast->name,argv[3])) {
- print_bc_info(fd, help, bc);
- break;
- }
- }
- }
-
- return 0;
-}
-
-ast_mutex_t lock;
-int MAXTICS = 8;
-
-static int misdn_set_tics (int fd, int argc, char *argv[])
-{
- if (argc != 4)
- return RESULT_SHOWUSAGE;
-
- MAXTICS = atoi(argv[3]);
-
- return 0;
-}
-
-static int misdn_show_stacks (int fd, int argc, char *argv[])
-{
- int port;
-
- ast_cli(fd, "BEGIN STACK_LIST:\n");
- for (port = misdn_cfg_get_next_port(0); port > 0;
- port = misdn_cfg_get_next_port(port)) {
- char buf[128];
- get_show_stack_details(port, buf);
- ast_cli(fd, " %s Debug:%d%s\n", buf, misdn_debug[port], misdn_debug_only[port] ? "(only)" : "");
- }
-
- return 0;
-}
-
-static int misdn_show_ports_stats (int fd, int argc, char *argv[])
-{
- int port;
-
- ast_cli(fd, "Port\tin_calls\tout_calls\n");
- for (port = misdn_cfg_get_next_port(0); port > 0;
- port = misdn_cfg_get_next_port(port)) {
- ast_cli(fd, "%d\t%d\t\t%d\n", port, misdn_in_calls[port], misdn_out_calls[port]);
- }
- ast_cli(fd, "\n");
-
- return 0;
-}
-
-static int misdn_show_port (int fd, int argc, char *argv[])
-{
- int port;
- char buf[128];
-
- if (argc != 4)
- return RESULT_SHOWUSAGE;
-
- port = atoi(argv[3]);
-
- ast_cli(fd, "BEGIN STACK_LIST:\n");
- get_show_stack_details(port, buf);
- ast_cli(fd, " %s Debug:%d%s\n", buf, misdn_debug[port], misdn_debug_only[port] ? "(only)" : "");
-
- return 0;
-}
-
-static int misdn_send_cd (int fd, int argc, char *argv[])
-{
- char *channame;
- char *nr;
- struct chan_list *tmp;
-
- if (argc != 5)
- return RESULT_SHOWUSAGE;
-
-
- {
- channame = argv[3];
- nr = argv[4];
-
- ast_cli(fd, "Sending Calldeflection (%s) to %s\n", nr, channame);
- tmp = get_chan_by_ast_name(channame);
- if (!tmp) {
- ast_cli(fd, "Sending CD with nr %s to %s failed: Channel does not exist.\n",nr, channame);
- return 0;
- }
-
- if (strlen(nr) >= 15) {
- ast_cli(fd, "Sending CD with nr %s to %s failed: Number too long (up to 15 digits are allowed).\n",nr, channame);
- return 0;
- }
- tmp->bc->fac_out.Function = Fac_CD;
- ast_copy_string((char *)tmp->bc->fac_out.u.CDeflection.DeflectedToNumber, nr, sizeof(tmp->bc->fac_out.u.CDeflection.DeflectedToNumber));
- misdn_lib_send_event(tmp->bc, EVENT_FACILITY);
- }
-
- return 0;
-}
-
-static int misdn_send_restart(int fd, int argc, char *argv[])
-{
- int port;
- int channel;
-
- if (argc < 4 || argc > 5)
- return RESULT_SHOWUSAGE;
-
- port = atoi(argv[3]);
-
- if (argc == 5) {
- channel = atoi(argv[4]);
- misdn_lib_send_restart(port, channel);
- } else {
- misdn_lib_send_restart(port, -1);
- }
-
- return 0;
-}
-
-static int misdn_send_digit (int fd, int argc, char *argv[])
-{
- char *channame;
- char *msg;
- struct chan_list *tmp;
- int i, msglen;
-
- if (argc != 5)
- return RESULT_SHOWUSAGE;
-
- channame = argv[3];
- msg = argv[4];
- msglen = strlen(msg);
-
- ast_cli(fd, "Sending %s to %s\n", msg, channame);
-
- tmp = get_chan_by_ast_name(channame);
- if (!tmp) {
- ast_cli(fd, "Sending %s to %s failed Channel does not exist\n", msg, channame);
- return 0;
- }
-#if 1
- for (i = 0; i < msglen; i++) {
- ast_cli(fd, "Sending: %c\n", msg[i]);
- send_digit_to_chan(tmp, msg[i]);
- /* res = ast_safe_sleep(tmp->ast, 250); */
- usleep(250000);
- /* res = ast_waitfor(tmp->ast,100); */
- }
-#else
- ast_dtmf_stream(tmp->ast, NULL, msg, 250);
-#endif
-
- return 0;
-}
-
-static int misdn_toggle_echocancel (int fd, int argc, char *argv[])
-{
- char *channame;
- struct chan_list *tmp;
-
- if (argc != 4)
- return RESULT_SHOWUSAGE;
-
- channame = argv[3];
-
- ast_cli(fd, "Toggling EchoCancel on %s\n", channame);
-
- tmp = get_chan_by_ast_name(channame);
- if (!tmp) {
- ast_cli(fd, "Toggling EchoCancel %s failed Channel does not exist\n", channame);
- return 0;
- }
-
- tmp->toggle_ec = tmp->toggle_ec ? 0 : 1;
-
- if (tmp->toggle_ec) {
-#ifdef MISDN_1_2
- update_pipeline_config(tmp->bc);
-#else
- update_ec_config(tmp->bc);
-#endif
- manager_ec_enable(tmp->bc);
- } else {
- manager_ec_disable(tmp->bc);
- }
-
- return 0;
-}
-
-static int misdn_send_display (int fd, int argc, char *argv[])
-{
- char *channame;
- char *msg;
- struct chan_list *tmp;
-
- if (argc != 5)
- return RESULT_SHOWUSAGE;
-
- channame = argv[3];
- msg = argv[4];
-
- ast_cli(fd, "Sending %s to %s\n", msg, channame);
- tmp = get_chan_by_ast_name(channame);
-
- if (tmp && tmp->bc) {
- ast_copy_string(tmp->bc->display, msg, sizeof(tmp->bc->display));
- misdn_lib_send_event(tmp->bc, EVENT_INFORMATION);
- } else {
- ast_cli(fd, "No such channel %s\n", channame);
- return RESULT_FAILURE;
- }
-
- return RESULT_SUCCESS;
-}
-
-static char *complete_ch_helper(const char *line, const char *word, int pos, int state, int rpos)
-{
- struct ast_channel *c;
- int which=0;
- char *ret;
- if (pos != rpos)
- return NULL;
- c = ast_channel_walk_locked(NULL);
- while(c) {
- if (!strncasecmp(word, c->name, strlen(word))) {
- if (++which > state)
- break;
- }
- ast_mutex_unlock(&c->lock);
- c = ast_channel_walk_locked(c);
- }
- if (c) {
- ret = strdup(c->name);
- ast_mutex_unlock(&c->lock);
- } else
- ret = NULL;
- return ret;
-}
-
-static char *complete_ch(const char *line, const char *word, int pos, int state)
-{
- return complete_ch_helper(line, word, pos, state, 3);
-}
-
-static char *complete_debug_port (const char *line, const char *word, int pos, int state)
-{
- if (state)
- return NULL;
-
- switch (pos) {
- case 4:
- if (*word == 'p')
- return strdup("port");
- else if (*word == 'o')
- return strdup("only");
- break;
- case 6:
- if (*word == 'o')
- return strdup("only");
- break;
- }
- return NULL;
-}
-
-static char *complete_show_config (const char *line, const char *word, int pos, int state)
-{
- char buffer[BUFFERSIZE];
- enum misdn_cfg_elements elem;
- int wordlen = strlen(word);
- int which = 0;
- int port = 0;
-
- switch (pos) {
- case 3:
- if ((!strncmp(word, "description", wordlen)) && (++which > state))
- return strdup("description");
- if ((!strncmp(word, "descriptions", wordlen)) && (++which > state))
- return strdup("descriptions");
- if ((!strncmp(word, "0", wordlen)) && (++which > state))
- return strdup("0");
- while ((port = misdn_cfg_get_next_port(port)) != -1) {
- snprintf(buffer, sizeof(buffer), "%d", port);
- if ((!strncmp(word, buffer, wordlen)) && (++which > state)) {
- return strdup(buffer);
- }
- }
- break;
- case 4:
- if (strstr(line, "description ")) {
- for (elem = MISDN_CFG_FIRST + 1; elem < MISDN_GEN_LAST; ++elem) {
- if ((elem == MISDN_CFG_LAST) || (elem == MISDN_GEN_FIRST))
- continue;
- misdn_cfg_get_name(elem, buffer, BUFFERSIZE);
- if (!wordlen || !strncmp(word, buffer, wordlen)) {
- if (++which > state)
- return strdup(buffer);
- }
- }
- } else if (strstr(line, "descriptions ")) {
- if ((!wordlen || !strncmp(word, "general", wordlen)) && (++which > state))
- return strdup("general");
- if ((!wordlen || !strncmp(word, "ports", wordlen)) && (++which > state))
- return strdup("ports");
- }
- break;
- }
- return NULL;
-}
-
-static struct ast_cli_entry chan_misdn_clis[] = {
- { {"misdn","send","calldeflect", NULL}, misdn_send_cd, "Sends CallDeflection to mISDN Channel",
- "Usage: misdn send calldeflect <channel> \"<nr>\" \n", complete_ch },
- { {"misdn","send","digit", NULL}, misdn_send_digit, "Sends DTMF Digit to mISDN Channel",
- "Usage: misdn send digit <channel> \"<msg>\" \n"
- " Send <digit> to <channel> as DTMF Tone\n"
- " when channel is a mISDN channel\n", complete_ch },
- { {"misdn","toggle","echocancel", NULL}, misdn_toggle_echocancel, "Toggles EchoCancel on mISDN Channel",
- "Usage: misdn toggle echocancel <channel>\n", complete_ch },
- { {"misdn","send","display", NULL}, misdn_send_display, "Sends Text to mISDN Channel",
- "Usage: misdn send display <channel> \"<msg>\" \n"
- " Send <msg> to <channel> as Display Message\n"
- " when channel is a mISDN channel\n", complete_ch },
- { {"misdn","show","config", NULL}, misdn_show_config, "Shows internal mISDN config, read from cfg-file",
- "Usage: misdn show config [<port> | description <config element> | descriptions [general|ports]]\n"
- " Use 0 for <port> to only print the general config.\n", complete_show_config },
- { {"misdn","reload", NULL}, misdn_reload, "Reloads internal mISDN config, read from cfg-file",
- "Usage: misdn reload\n" },
- { {"misdn","set","tics", NULL}, misdn_set_tics, "",
- "\n" },
- { {"misdn","show","channels", NULL}, misdn_show_cls, "Shows internal mISDN chan_list",
- "Usage: misdn show channels\n" },
- { {"misdn","show","channel", NULL}, misdn_show_cl, "Shows internal mISDN chan_list",
- "Usage: misdn show channels\n", complete_ch },
- { {"misdn","port","block", NULL}, misdn_port_block, "Blocks the given port",
- "Usage: misdn port block\n" },
- { {"misdn","port","unblock", NULL}, misdn_port_unblock, "Unblocks the given port",
- "Usage: misdn port unblock\n" },
- { {"misdn","restart","port", NULL}, misdn_restart_port, "Restarts the given port",
- "Usage: misdn restart port\n" },
- { {"misdn","restart","pid", NULL}, misdn_restart_pid, "Restarts the given pid",
- "Usage: misdn restart pid\n" },
- { {"misdn","send","restart", NULL}, misdn_send_restart,
- "Sends a restart for every bchannel on the given port",
- "Usage: misdn send restart <port>\n"},
- { {"misdn","port","up", NULL}, misdn_port_up, "Tries to establish L1 on the given port",
- "Usage: misdn port up <port>\n" },
- { {"misdn","port","down", NULL}, misdn_port_down, "Tries to deactivate the L1 on the given port",
- "Usage: misdn port down <port>\n" },
- { {"misdn","show","stacks", NULL}, misdn_show_stacks, "Shows internal mISDN stack_list",
- "Usage: misdn show stacks\n" },
- { {"misdn","show","ports","stats", NULL}, misdn_show_ports_stats, "Shows chan_misdns call statistics per port",
- "Usage: misdn show port stats\n" },
- { {"misdn","show","port", NULL}, misdn_show_port, "Shows detailed information for given port",
- "Usage: misdn show port <port>\n" },
- { {"misdn","set","debug", NULL}, misdn_set_debug, "Sets Debuglevel of chan_misdn",
- "Usage: misdn set debug <level> [only] | [port <port> [only]]\n", complete_debug_port },
- { {"misdn","set","crypt","debug", NULL}, misdn_set_crypt_debug, "Sets CryptDebuglevel of chan_misdn, at the moment, level={1,2}",
- "Usage: misdn set crypt debug <level>\n" }
-};
-
-/*! \brief Updates caller ID information from config */
-static int update_config(struct chan_list *ch, int orig)
-{
- struct ast_channel *ast;
- struct misdn_bchannel *bc;
- int port, hdlc = 0;
- int pres, screen;
-
- if (!ch) {
- ast_log(LOG_WARNING, "Cannot configure without chanlist\n");
- return -1;
- }
-
- ast = ch->ast;
- bc = ch->bc;
- if (! ast || ! bc) {
- ast_log(LOG_WARNING, "Cannot configure without ast || bc\n");
- return -1;
- }
-
- port = bc->port;
-
- chan_misdn_log(7, port, "update_config: Getting Config\n");
-
- misdn_cfg_get(port, MISDN_CFG_HDLC, &hdlc, sizeof(int));
-
- if (hdlc) {
- switch (bc->capability) {
- case INFO_CAPABILITY_DIGITAL_UNRESTRICTED:
- case INFO_CAPABILITY_DIGITAL_RESTRICTED:
- chan_misdn_log(1, bc->port, " --> CONF HDLC\n");
- bc->hdlc = 1;
- break;
- }
- }
-
-
- misdn_cfg_get(port, MISDN_CFG_PRES, &pres, sizeof(pres));
- misdn_cfg_get(port, MISDN_CFG_SCREEN, &screen, sizeof(screen));
- chan_misdn_log(2, port, " --> pres: %d screen: %d\n", pres, screen);
-
- if (pres < 0 || screen < 0) {
- chan_misdn_log(2, port, " --> pres: %x\n", ast->cid.cid_pres);
-
- switch (ast->cid.cid_pres & 0x60) {
- case AST_PRES_RESTRICTED:
- bc->pres = 1;
- chan_misdn_log(2, port, " --> PRES: Restricted (1)\n");
- break;
- case AST_PRES_UNAVAILABLE:
- bc->pres = 2;
- chan_misdn_log(2, port, " --> PRES: Unavailable (2)\n");
- break;
- default:
- bc->pres = 0;
- chan_misdn_log(2, port, " --> PRES: Allowed (0)\n");
- break;
- }
-
- switch (ast->cid.cid_pres & 0x3) {
- default:
- case AST_PRES_USER_NUMBER_UNSCREENED:
- bc->screen = 0;
- chan_misdn_log(2, port, " --> SCREEN: Unscreened (0)\n");
- break;
- case AST_PRES_USER_NUMBER_PASSED_SCREEN:
- bc->screen = 1;
- chan_misdn_log(2, port, " --> SCREEN: Passed Screen (1)\n");
- break;
- case AST_PRES_USER_NUMBER_FAILED_SCREEN:
- bc->screen = 2;
- chan_misdn_log(2, port, " --> SCREEN: Failed Screen (2)\n");
- break;
- case AST_PRES_NETWORK_NUMBER:
- bc->screen = 3;
- chan_misdn_log(2, port, " --> SCREEN: Network Nr. (3)\n");
- break;
- }
- } else {
- bc->screen = screen;
- bc->pres = pres;
- }
-
- return 0;
-}
-
-
-static void config_jitterbuffer(struct chan_list *ch)
-{
- struct misdn_bchannel *bc = ch->bc;
- int len = ch->jb_len, threshold = ch->jb_upper_threshold;
-
- chan_misdn_log(5, bc->port, "config_jb: Called\n");
-
- if (! len) {
- chan_misdn_log(1, bc->port, "config_jb: Deactivating Jitterbuffer\n");
- bc->nojitter=1;
- } else {
- if (len <= 100 || len > 8000) {
- chan_misdn_log(0, bc->port, "config_jb: Jitterbuffer out of Bounds, setting to 1000\n");
- len = 1000;
- }
-
- if ( threshold > len ) {
- chan_misdn_log(0, bc->port, "config_jb: Jitterbuffer Threshold > Jitterbuffer setting to Jitterbuffer -1\n");
- }
-
- if ( ch->jb) {
- cb_log(0, bc->port, "config_jb: We've got a Jitterbuffer Already on this port.\n");
- misdn_jb_destroy(ch->jb);
- ch->jb = NULL;
- }
-
- ch->jb=misdn_jb_init(len, threshold);
-
- if (!ch->jb )
- bc->nojitter = 1;
- }
-}
-
-
-void debug_numplan(int port, int numplan, char *type)
-{
- switch (numplan) {
- case NUMPLAN_INTERNATIONAL:
- chan_misdn_log(2, port, " --> %s: International\n", type);
- break;
- case NUMPLAN_NATIONAL:
- chan_misdn_log(2, port, " --> %s: National\n", type);
- break;
- case NUMPLAN_SUBSCRIBER:
- chan_misdn_log(2, port, " --> %s: Subscriber\n", type);
- break;
- case NUMPLAN_UNKNOWN:
- chan_misdn_log(2, port, " --> %s: Unknown\n", type);
- break;
- /* Maybe we should cut off the prefix if present ? */
- default:
- chan_misdn_log(0, port, " --> !!!! Wrong dialplan setting, please see the misdn.conf sample file\n ");
- break;
- }
-}
-
-
-#ifdef MISDN_1_2
-static int update_pipeline_config(struct misdn_bchannel *bc)
-{
- int ec;
-
- misdn_cfg_get(bc->port, MISDN_CFG_PIPELINE, bc->pipeline, sizeof(bc->pipeline));
-
- if (*bc->pipeline)
- return 0;
-
- misdn_cfg_get(bc->port, MISDN_CFG_ECHOCANCEL, &ec, sizeof(int));
- if (ec == 1)
- ast_copy_string(bc->pipeline, "mg2ec", sizeof(bc->pipeline));
- else if (ec > 1)
- snprintf(bc->pipeline, sizeof(bc->pipeline), "mg2ec(deftaps=%d)", ec);
-
- return 0;
-}
-#else
-static int update_ec_config(struct misdn_bchannel *bc)
-{
- int ec;
- int port = bc->port;
-
- misdn_cfg_get(port, MISDN_CFG_ECHOCANCEL, &ec, sizeof(int));
-
- if (ec == 1) {
- bc->ec_enable = 1;
- } else if (ec > 1) {
- bc->ec_enable = 1;
- bc->ec_deftaps = ec;
- }
-
- return 0;
-}
-#endif
-
-
-static int read_config(struct chan_list *ch, int orig)
-{
- struct ast_channel *ast;
- struct misdn_bchannel *bc;
- int port;
- int hdlc = 0;
- char lang[BUFFERSIZE + 1];
- char faxdetect[BUFFERSIZE + 1];
- char buf[256];
- char buf2[256];
- ast_group_t pg;
- ast_group_t cg;
-
- if (!ch) {
- ast_log(LOG_WARNING, "Cannot configure without chanlist\n");
- return -1;
- }
-
- ast = ch->ast;
- bc = ch->bc;
- if (! ast || ! bc) {
- ast_log(LOG_WARNING, "Cannot configure without ast || bc\n");
- return -1;
- }
-
- port = bc->port;
- chan_misdn_log(1, port, "read_config: Getting Config\n");
-
- misdn_cfg_get(port, MISDN_CFG_LANGUAGE, lang, BUFFERSIZE);
- ast_string_field_set(ast, language, lang);
-
- misdn_cfg_get(port, MISDN_CFG_MUSICCLASS, ch->mohinterpret, sizeof(ch->mohinterpret));
-
- misdn_cfg_get(port, MISDN_CFG_TXGAIN, &bc->txgain, sizeof(int));
- misdn_cfg_get(port, MISDN_CFG_RXGAIN, &bc->rxgain, sizeof(int));
-
- misdn_cfg_get(port, MISDN_CFG_INCOMING_EARLY_AUDIO, &ch->incoming_early_audio, sizeof(int));
-
- misdn_cfg_get(port, MISDN_CFG_SENDDTMF, &bc->send_dtmf, sizeof(int));
-
- misdn_cfg_get(port, MISDN_CFG_ASTDTMF, &ch->ast_dsp, sizeof(int));
-
- if (ch->ast_dsp) {
- ch->ignore_dtmf = 1;
- }
-
- misdn_cfg_get(port, MISDN_CFG_NEED_MORE_INFOS, &bc->need_more_infos, sizeof(int));
- misdn_cfg_get(port, MISDN_CFG_NTTIMEOUT, &ch->nttimeout, sizeof(int));
-
- misdn_cfg_get(port, MISDN_CFG_NOAUTORESPOND_ON_SETUP, &ch->noautorespond_on_setup, sizeof(int));
-
- misdn_cfg_get(port, MISDN_CFG_FAR_ALERTING, &ch->far_alerting, sizeof(int));
-
- misdn_cfg_get(port, MISDN_CFG_ALLOWED_BEARERS, &ch->allowed_bearers, BUFFERSIZE);
-
- misdn_cfg_get(port, MISDN_CFG_FAXDETECT, faxdetect, BUFFERSIZE);
-
- misdn_cfg_get(port, MISDN_CFG_HDLC, &hdlc, sizeof(int));
-
- if (hdlc) {
- switch (bc->capability) {
- case INFO_CAPABILITY_DIGITAL_UNRESTRICTED:
- case INFO_CAPABILITY_DIGITAL_RESTRICTED:
- chan_misdn_log(1, bc->port, " --> CONF HDLC\n");
- bc->hdlc = 1;
- break;
- }
-
- }
- /*Initialize new Jitterbuffer*/
- misdn_cfg_get(port, MISDN_CFG_JITTERBUFFER, &ch->jb_len, sizeof(int));
- misdn_cfg_get(port, MISDN_CFG_JITTERBUFFER_UPPER_THRESHOLD, &ch->jb_upper_threshold, sizeof(int));
-
- config_jitterbuffer(ch);
-
- misdn_cfg_get(bc->port, MISDN_CFG_CONTEXT, ch->context, sizeof(ch->context));
-
- ast_copy_string(ast->context, ch->context, sizeof(ast->context));
-
-#ifdef MISDN_1_2
- update_pipeline_config(bc);
-#else
- update_ec_config(bc);
-#endif
-
- {
- int eb3;
-
- misdn_cfg_get( bc->port, MISDN_CFG_EARLY_BCONNECT, &eb3, sizeof(int));
- bc->early_bconnect=eb3;
- }
-
- misdn_cfg_get(port, MISDN_CFG_PICKUPGROUP, &pg, sizeof(pg));
- misdn_cfg_get(port, MISDN_CFG_CALLGROUP, &cg, sizeof(cg));
-
- chan_misdn_log(5, port, " --> * CallGrp:%s PickupGrp:%s\n", ast_print_group(buf, sizeof(buf), cg), ast_print_group(buf2, sizeof(buf2), pg));
- ast->pickupgroup = pg;
- ast->callgroup = cg;
-
- if (orig == ORG_AST) {
- char callerid[BUFFERSIZE + 1];
-
- /* ORIGINATOR Asterisk (outgoing call) */
-
- misdn_cfg_get(port, MISDN_CFG_TE_CHOOSE_CHANNEL, &(bc->te_choose_channel), sizeof(int));
-
- if (strstr(faxdetect, "outgoing") || strstr(faxdetect, "both")) {
- if (strstr(faxdetect, "nojump"))
- ch->faxdetect = 2;
- else
- ch->faxdetect = 1;
- }
-
- misdn_cfg_get(port, MISDN_CFG_CALLERID, callerid, BUFFERSIZE);
- if ( ! ast_strlen_zero(callerid) ) {
- chan_misdn_log(1, port, " --> * Setting Cid to %s\n", callerid);
- ast_copy_string(bc->oad, callerid, sizeof(bc->oad));
- }
-
- misdn_cfg_get(port, MISDN_CFG_DIALPLAN, &bc->dnumplan, sizeof(int));
- misdn_cfg_get(port, MISDN_CFG_LOCALDIALPLAN, &bc->onumplan, sizeof(int));
- misdn_cfg_get(port, MISDN_CFG_CPNDIALPLAN, &bc->cpnnumplan, sizeof(int));
- debug_numplan(port, bc->dnumplan, "TON");
- debug_numplan(port, bc->onumplan, "LTON");
- debug_numplan(port, bc->cpnnumplan, "CTON");
-
- ch->overlap_dial = 0;
- } else {
- /* ORIGINATOR MISDN (incoming call) */
- char prefix[BUFFERSIZE + 1] = "";
-
- if (strstr(faxdetect, "incoming") || strstr(faxdetect, "both")) {
- if (strstr(faxdetect, "nojump"))
- ch->faxdetect = 2;
- else
- ch->faxdetect = 1;
- }
-
- misdn_cfg_get(port, MISDN_CFG_CPNDIALPLAN, &bc->cpnnumplan, sizeof(int));
- debug_numplan(port, bc->cpnnumplan, "CTON");
-
- switch (bc->onumplan) {
- case NUMPLAN_INTERNATIONAL:
- misdn_cfg_get(bc->port, MISDN_CFG_INTERNATPREFIX, prefix, BUFFERSIZE);
- break;
-
- case NUMPLAN_NATIONAL:
- misdn_cfg_get(bc->port, MISDN_CFG_NATPREFIX, prefix, BUFFERSIZE);
- break;
- default:
- break;
- }
-
- ast_copy_string(buf, bc->oad, sizeof(buf));
- snprintf(bc->oad, sizeof(bc->oad), "%s%s", prefix, buf);
-
- if (!ast_strlen_zero(bc->dad)) {
- ast_copy_string(bc->orig_dad, bc->dad, sizeof(bc->orig_dad));
- }
-
- if ( ast_strlen_zero(bc->dad) && !ast_strlen_zero(bc->keypad)) {
- ast_copy_string(bc->dad, bc->keypad, sizeof(bc->dad));
- }
-
- prefix[0] = 0;
-
- switch (bc->dnumplan) {
- case NUMPLAN_INTERNATIONAL:
- misdn_cfg_get(bc->port, MISDN_CFG_INTERNATPREFIX, prefix, BUFFERSIZE);
- break;
- case NUMPLAN_NATIONAL:
- misdn_cfg_get(bc->port, MISDN_CFG_NATPREFIX, prefix, BUFFERSIZE);
- break;
- default:
- break;
- }
-
- ast_copy_string(buf, bc->dad, sizeof(buf));
- snprintf(bc->dad, sizeof(bc->dad), "%s%s", prefix, buf);
-
- if (strcmp(bc->dad, ast->exten)) {
- ast_copy_string(ast->exten, bc->dad, sizeof(ast->exten));
- }
-
- ast_set_callerid(ast, bc->oad, NULL, bc->oad);
-
- if ( !ast_strlen_zero(bc->rad) ) {
- if (ast->cid.cid_rdnis)
- free(ast->cid.cid_rdnis);
- ast->cid.cid_rdnis = strdup(bc->rad);
- }
-
- misdn_cfg_get(bc->port, MISDN_CFG_OVERLAP_DIAL, &ch->overlap_dial, sizeof(ch->overlap_dial));
- ast_mutex_init(&ch->overlap_tv_lock);
- } /* ORIG MISDN END */
-
- ch->overlap_dial_task = -1;
-
- if (ch->faxdetect || ch->ast_dsp) {
- misdn_cfg_get(port, MISDN_CFG_FAXDETECT_TIMEOUT, &ch->faxdetect_timeout, sizeof(ch->faxdetect_timeout));
- if (!ch->dsp)
- ch->dsp = ast_dsp_new();
- if (ch->dsp) {
- if (ch->faxdetect)
- ast_dsp_set_features(ch->dsp, DSP_FEATURE_DTMF_DETECT | DSP_FEATURE_FAX_DETECT);
- else
- ast_dsp_set_features(ch->dsp, DSP_FEATURE_DTMF_DETECT );
- }
- if (!ch->trans)
- ch->trans = ast_translator_build_path(AST_FORMAT_SLINEAR, AST_FORMAT_ALAW);
- }
-
- /* AOCD initialization */
- bc->AOCDtype = Fac_None;
-
- return 0;
-}
-
-
-/*****************************/
-/*** AST Indications Start ***/
-/*****************************/
-
-static int misdn_call(struct ast_channel *ast, char *dest, int timeout)
-{
- int port = 0;
- int r;
- int exceed;
- int bridging;
- struct chan_list *ch;
- struct misdn_bchannel *newbc;
- char *opts, *ext;
- char *dest_cp;
-
- if (!ast) {
- ast_log(LOG_WARNING, " --> ! misdn_call called on ast_channel *ast where ast == NULL\n");
- return -1;
- }
-
- if (((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) || !dest ) {
- ast_log(LOG_WARNING, " --> ! misdn_call called on %s, neither down nor reserved (or dest==NULL)\n", ast->name);
- ast->hangupcause = AST_CAUSE_NORMAL_TEMPORARY_FAILURE;
- ast_setstate(ast, AST_STATE_DOWN);
- return -1;
- }
-
- ch = MISDN_ASTERISK_TECH_PVT(ast);
- if (!ch) {
- ast_log(LOG_WARNING, " --> ! misdn_call called on %s, neither down nor reserved (or dest==NULL)\n", ast->name);
- ast->hangupcause = AST_CAUSE_NORMAL_TEMPORARY_FAILURE;
- ast_setstate(ast, AST_STATE_DOWN);
- return -1;
- }
-
- newbc = ch->bc;
- if (!newbc) {
- ast_log(LOG_WARNING, " --> ! misdn_call called on %s, neither down nor reserved (or dest==NULL)\n", ast->name);
- ast->hangupcause = AST_CAUSE_NORMAL_TEMPORARY_FAILURE;
- ast_setstate(ast, AST_STATE_DOWN);
- return -1;
- }
-
- /*
- * dest is ---v
- * Dial(mISDN/g:group_name[/extension[/options]])
- * Dial(mISDN/port[:preselected_channel][/extension[/options]])
- *
- * The dial extension could be empty if you are using MISDN_KEYPAD
- * to control ISDN provider features.
- */
- dest_cp = ast_strdupa(dest);
- strsep(&dest_cp, "/");/* Discard port/group token */
- ext = strsep(&dest_cp, "/");
- if (!ext) {
- ext = "";
- }
- opts = dest_cp;
-
- port = newbc->port;
-
- if ((exceed = add_out_calls(port))) {
- char tmp[16];
- snprintf(tmp, sizeof(tmp), "%d", exceed);
- pbx_builtin_setvar_helper(ast, "MAX_OVERFLOW", tmp);
- return -1;
- }
-
- chan_misdn_log(1, port, "* CALL: %s\n", dest);
-
- chan_misdn_log(2, port, " --> * dad:%s tech:%s ctx:%s\n", ast->exten, ast->name, ast->context);
-
- chan_misdn_log(3, port, " --> * adding2newbc ext %s\n", ast->exten);
- if (ast->exten) {
- ast_copy_string(ast->exten, ext, sizeof(ast->exten));
- ast_copy_string(newbc->dad, ext, sizeof(newbc->dad));
- }
-
- ast_copy_string(newbc->rad, S_OR(ast->cid.cid_rdnis, ""), sizeof(newbc->rad));
-
- chan_misdn_log(3, port, " --> * adding2newbc callerid %s\n", ast->cid.cid_num);
- if (ast_strlen_zero(newbc->oad) && !ast_strlen_zero(ast->cid.cid_num)) {
- ast_copy_string(newbc->oad, ast->cid.cid_num, sizeof(newbc->oad));
- }
-
- newbc->capability = ast->transfercapability;
- pbx_builtin_setvar_helper(ast, "TRANSFERCAPABILITY", ast_transfercapability2str(newbc->capability));
- if ( ast->transfercapability == INFO_CAPABILITY_DIGITAL_UNRESTRICTED) {
- chan_misdn_log(2, port, " --> * Call with flag Digital\n");
- }
-
- /* update screening and presentation */
- update_config(ch, ORG_AST);
-
- /* fill in some ies from channel vary*/
- import_ch(ast, newbc, ch);
-
- /* Finally The Options Override Everything */
- if (opts)
- misdn_set_opt_exec(ast, opts);
- else
- chan_misdn_log(2, port, "NO OPTS GIVEN\n");
-
- /*check for bridging*/
- misdn_cfg_get(0, MISDN_GEN_BRIDGING, &bridging, sizeof(bridging));
- if (bridging && ch->other_ch) {
-#ifdef MISDN_1_2
- chan_misdn_log(1, port, "Disabling EC (aka Pipeline) on both Sides\n");
- *ch->bc->pipeline = 0;
- *ch->other_ch->bc->pipeline = 0;
-#else
- chan_misdn_log(1, port, "Disabling EC on both Sides\n");
- ch->bc->ec_enable = 0;
- ch->other_ch->bc->ec_enable = 0;
-#endif
- }
-
- r = misdn_lib_send_event( newbc, EVENT_SETUP );
-
- /** we should have l3id after sending setup **/
- ch->l3id = newbc->l3_id;
-
- if ( r == -ENOCHAN ) {
- chan_misdn_log(0, port, " --> * Theres no Channel at the moment .. !\n");
- chan_misdn_log(1, port, " --> * SEND: State Down pid:%d\n", newbc ? newbc->pid : -1);
- ast->hangupcause = AST_CAUSE_NORMAL_CIRCUIT_CONGESTION;
- ast_setstate(ast, AST_STATE_DOWN);
- return -1;
- }
-
- chan_misdn_log(2, port, " --> * SEND: State Dialing pid:%d\n", newbc ? newbc->pid : 1);
-
- ast_setstate(ast, AST_STATE_DIALING);
- ast->hangupcause = AST_CAUSE_NORMAL_CLEARING;
-
- if (newbc->nt)
- stop_bc_tones(ch);
-
- ch->state = MISDN_CALLING;
-
- return 0;
-}
-
-
-static int misdn_answer(struct ast_channel *ast)
-{
- struct chan_list *p;
- const char *tmp;
-
- if (!ast || !(p = MISDN_ASTERISK_TECH_PVT(ast))) return -1;
-
- chan_misdn_log(1, p ? (p->bc ? p->bc->port : 0) : 0, "* ANSWER:\n");
-
- if (!p) {
- ast_log(LOG_WARNING, " --> Channel not connected ??\n");
- ast_queue_hangup(ast);
- }
-
- if (!p->bc) {
- chan_misdn_log(1, 0, " --> Got Answer, but there is no bc obj ??\n");
-
- ast_queue_hangup(ast);
- }
-
- tmp = pbx_builtin_getvar_helper(p->ast, "CRYPT_KEY");
- if (!ast_strlen_zero(tmp)) {
- chan_misdn_log(1, p->bc->port, " --> Connection will be BF crypted\n");
- ast_copy_string(p->bc->crypt_key, tmp, sizeof(p->bc->crypt_key));
- } else {
- chan_misdn_log(3, p->bc->port, " --> Connection is without BF encryption\n");
- }
-
- tmp = pbx_builtin_getvar_helper(ast, "MISDN_DIGITAL_TRANS");
- if (!ast_strlen_zero(tmp) && ast_true(tmp)) {
- chan_misdn_log(1, p->bc->port, " --> Connection is transparent digital\n");
- p->bc->nodsp = 1;
- p->bc->hdlc = 0;
- p->bc->nojitter = 1;
- }
-
- p->state = MISDN_CONNECTED;
- stop_indicate(p);
-
- if ( ast_strlen_zero(p->bc->cad) ) {
- chan_misdn_log(2,p->bc->port," --> empty cad using dad\n");
- ast_copy_string(p->bc->cad, p->bc->dad, sizeof(p->bc->cad));
- }
-
- misdn_lib_send_event( p->bc, EVENT_CONNECT);
- start_bc_tones(p);
-
- return 0;
-}
-
-static int misdn_digit_begin(struct ast_channel *chan, char digit)
-{
- /* XXX Modify this callback to support Asterisk controlling the length of DTMF */
- return 0;
-}
-
-static int misdn_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
-{
- struct chan_list *p;
- struct misdn_bchannel *bc;
-
- if (!ast || !(p = MISDN_ASTERISK_TECH_PVT(ast))) return -1;
-
- bc = p->bc;
- chan_misdn_log(1, bc ? bc->port : 0, "* IND : Digit %c\n", digit);
-
- if (!bc) {
- ast_log(LOG_WARNING, " --> !! Got Digit Event without having bchannel Object\n");
- return -1;
- }
-
- switch (p->state ) {
- case MISDN_CALLING:
- {
- int l;
- char buf[8];
- buf[0]=digit;
- buf[1]=0;
-
- l = sizeof(bc->infos_pending);
- strncat(bc->infos_pending, buf, l - strlen(bc->infos_pending) - 1);
- }
- break;
- case MISDN_CALLING_ACKNOWLEDGE:
- {
- bc->info_dad[0]=digit;
- bc->info_dad[1]=0;
-
- {
- int l = sizeof(bc->dad);
- strncat(bc->dad, bc->info_dad, l - strlen(bc->dad) - 1);
- }
- {
- int l = sizeof(p->ast->exten);
- strncpy(p->ast->exten, bc->dad, l);
- p->ast->exten[l-1] = 0;
- }
-
- misdn_lib_send_event( bc, EVENT_INFORMATION);
- }
- break;
- default:
- /* Do not send Digits in CONNECTED State, when
- * the other side is too mISDN. */
- if (p->other_ch )
- return 0;
-
- if ( bc->send_dtmf )
- send_digit_to_chan(p,digit);
- break;
- }
-
- return 0;
-}
-
-
-static int misdn_fixup(struct ast_channel *oldast, struct ast_channel *ast)
-{
- struct chan_list *p;
-
- if (!ast || ! (p=MISDN_ASTERISK_TECH_PVT(ast) )) return -1;
-
- chan_misdn_log(1, p->bc ? p->bc->port : 0, "* IND: Got Fixup State:%s L3id:%x\n", misdn_get_ch_state(p), p->l3id);
-
- p->ast = ast;
-
- return 0;
-}
-
-
-
-static int misdn_indication(struct ast_channel *ast, int cond, const void *data, size_t datalen)
-{
- struct chan_list *p;
-
- if (!ast || ! (p=MISDN_ASTERISK_TECH_PVT(ast))) {
- ast_log(LOG_WARNING, "Returned -1 in misdn_indication\n");
- return -1;
- }
-
- if (!p->bc ) {
- chan_misdn_log(1, 0, "* IND : Indication from %s\n", ast->exten);
- ast_log(LOG_WARNING, "Private Pointer but no bc ?\n");
- return -1;
- }
-
- chan_misdn_log(5, p->bc->port, "* IND : Indication [%d] from %s\n", cond, ast->exten);
-
- switch (cond) {
- case AST_CONTROL_BUSY:
- chan_misdn_log(1, p->bc->port, "* IND :\tbusy pid:%d\n", p->bc ? p->bc->pid : -1);
- ast_setstate(ast, AST_STATE_BUSY);
-
- p->bc->out_cause = AST_CAUSE_USER_BUSY;
- if (p->state != MISDN_CONNECTED) {
- start_bc_tones(p);
- misdn_lib_send_event( p->bc, EVENT_DISCONNECT);
- } else {
- chan_misdn_log(-1, p->bc->port, " --> !! Got Busy in Connected State !?! ast:%s\n", ast->name);
- }
- return -1;
- case AST_CONTROL_RING:
- chan_misdn_log(1, p->bc->port, "* IND :\tring pid:%d\n", p->bc ? p->bc->pid : -1);
- return -1;
- case AST_CONTROL_RINGING:
- chan_misdn_log(1, p->bc->port, "* IND :\tringing pid:%d\n", p->bc ? p->bc->pid : -1);
- switch (p->state) {
- case MISDN_ALERTING:
- chan_misdn_log(2, p->bc->port, " --> * IND :\tringing pid:%d but I was Ringing before, so ignoring it\n", p->bc ? p->bc->pid : -1);
- break;
- case MISDN_CONNECTED:
- chan_misdn_log(2, p->bc->port, " --> * IND :\tringing pid:%d but Connected, so just send TONE_ALERTING without state changes \n", p->bc ? p->bc->pid : -1);
- return -1;
- default:
- p->state = MISDN_ALERTING;
- chan_misdn_log(2, p->bc->port, " --> * IND :\tringing pid:%d\n", p->bc ? p->bc->pid : -1);
- misdn_lib_send_event( p->bc, EVENT_ALERTING);
-
- if (p->other_ch && p->other_ch->bc) {
- if (misdn_inband_avail(p->other_ch->bc)) {
- chan_misdn_log(2, p->bc->port, " --> other End is mISDN and has inband info available\n");
- break;
- }
-
- if (!p->other_ch->bc->nt) {
- chan_misdn_log(2, p->bc->port, " --> other End is mISDN TE so it has inband info for sure (?)\n");
- break;
- }
- }
-
- chan_misdn_log(3, p->bc->port, " --> * SEND: State Ring pid:%d\n", p->bc ? p->bc->pid : -1);
- ast_setstate(ast, AST_STATE_RING);
-
- if (!p->bc->nt && (p->originator == ORG_MISDN) && !p->incoming_early_audio)
- chan_misdn_log(2, p->bc->port, " --> incoming_early_audio off\n");
- else
- return -1;
- }
- break;
- case AST_CONTROL_ANSWER:
- chan_misdn_log(1, p->bc->port, " --> * IND :\tanswer pid:%d\n", p->bc ? p->bc->pid : -1);
- start_bc_tones(p);
- break;
- case AST_CONTROL_TAKEOFFHOOK:
- chan_misdn_log(1, p->bc->port, " --> *\ttakeoffhook pid:%d\n", p->bc ? p->bc->pid : -1);
- return -1;
- case AST_CONTROL_OFFHOOK:
- chan_misdn_log(1, p->bc->port, " --> *\toffhook pid:%d\n", p->bc ? p->bc->pid : -1);
- return -1;
- case AST_CONTROL_FLASH:
- chan_misdn_log(1, p->bc->port, " --> *\tflash pid:%d\n", p->bc ? p->bc->pid : -1);
- break;
- case AST_CONTROL_PROGRESS:
- chan_misdn_log(1, p->bc->port, " --> * IND :\tprogress pid:%d\n", p->bc ? p->bc->pid : -1);
- misdn_lib_send_event( p->bc, EVENT_PROGRESS);
- break;
- case AST_CONTROL_PROCEEDING:
- chan_misdn_log(1, p->bc->port, " --> * IND :\tproceeding pid:%d\n", p->bc ? p->bc->pid : -1);
- misdn_lib_send_event( p->bc, EVENT_PROCEEDING);
- break;
- case AST_CONTROL_CONGESTION:
- chan_misdn_log(1, p->bc->port, " --> * IND :\tcongestion pid:%d\n", p->bc ? p->bc->pid : -1);
-
- p->bc->out_cause = AST_CAUSE_SWITCH_CONGESTION;
- start_bc_tones(p);
- misdn_lib_send_event( p->bc, EVENT_DISCONNECT);
-
- if (p->bc->nt) {
- hanguptone_indicate(p);
- }
- break;
- case -1 :
- chan_misdn_log(1, p->bc->port, " --> * IND :\t-1! (stop indication) pid:%d\n", p->bc ? p->bc->pid : -1);
-
- stop_indicate(p);
-
- if (p->state == MISDN_CONNECTED)
- start_bc_tones(p);
- break;
- case AST_CONTROL_HOLD:
- ast_moh_start(ast, data, p->mohinterpret);
- chan_misdn_log(1, p->bc->port, " --> *\tHOLD pid:%d\n", p->bc ? p->bc->pid : -1);
- break;
- case AST_CONTROL_UNHOLD:
- ast_moh_stop(ast);
- chan_misdn_log(1, p->bc->port, " --> *\tUNHOLD pid:%d\n", p->bc ? p->bc->pid : -1);
- break;
- default:
- chan_misdn_log(1, p->bc->port, " --> * Unknown Indication:%d pid:%d\n", cond, p->bc ? p->bc->pid : -1);
- }
-
- return 0;
-}
-
-static int misdn_hangup(struct ast_channel *ast)
-{
- struct chan_list *p;
- struct misdn_bchannel *bc = NULL;
- const char *varcause = NULL;
-
- ast_log(LOG_DEBUG, "misdn_hangup(%s)\n", ast->name);
-
- if (!ast || ! (p=MISDN_ASTERISK_TECH_PVT(ast) ) ) return -1;
-
- if (!p) {
- chan_misdn_log(3, 0, "misdn_hangup called, without chan_list obj.\n");
- return 0 ;
- }
-
- bc = p->bc;
-
- if (bc) {
- const char *tmp=pbx_builtin_getvar_helper(ast,"MISDN_USERUSER");
- if (tmp) {
- ast_log(LOG_NOTICE, "MISDN_USERUSER: %s\n", tmp);
- strcpy(bc->uu, tmp);
- bc->uulen=strlen(bc->uu);
- }
- }
-
- MISDN_ASTERISK_TECH_PVT(ast) = NULL;
- p->ast = NULL;
-
- if (ast->_state == AST_STATE_RESERVED ||
- p->state == MISDN_NOTHING ||
- p->state == MISDN_HOLDED ||
- p->state == MISDN_HOLD_DISCONNECT ) {
-
- CLEAN_CH:
- /* between request and call */
- ast_log(LOG_DEBUG, "State Reserved (or nothing) => chanIsAvail\n");
- MISDN_ASTERISK_TECH_PVT(ast) = NULL;
-
- ast_mutex_lock(&release_lock);
- cl_dequeue_chan(&cl_te, p);
- close(p->pipe[0]);
- close(p->pipe[1]);
- free(p);
- ast_mutex_unlock(&release_lock);
-
- if (bc)
- misdn_lib_release(bc);
-
- return 0;
- }
-
- if (!bc) {
- ast_log(LOG_WARNING, "Hangup with private but no bc ? state:%s l3id:%x\n", misdn_get_ch_state(p), p->l3id);
- goto CLEAN_CH;
- }
-
-
- p->need_hangup = 0;
- p->need_queue_hangup = 0;
- p->need_busy = 0;
-
-
- if (!p->bc->nt)
- stop_bc_tones(p);
-
- bc->out_cause = ast->hangupcause ? ast->hangupcause : AST_CAUSE_NORMAL_CLEARING;
-
- if ((varcause = pbx_builtin_getvar_helper(ast, "HANGUPCAUSE")) ||
- (varcause = pbx_builtin_getvar_helper(ast, "PRI_CAUSE"))) {
- int tmpcause = atoi(varcause);
- bc->out_cause = tmpcause ? tmpcause : AST_CAUSE_NORMAL_CLEARING;
- }
-
- chan_misdn_log(1, bc->port, "* IND : HANGUP\tpid:%d ctx:%s dad:%s oad:%s State:%s\n", p->bc ? p->bc->pid : -1, ast->context, ast->exten, ast->cid.cid_num, misdn_get_ch_state(p));
- chan_misdn_log(3, bc->port, " --> l3id:%x\n", p->l3id);
- chan_misdn_log(3, bc->port, " --> cause:%d\n", bc->cause);
- chan_misdn_log(2, bc->port, " --> out_cause:%d\n", bc->out_cause);
- chan_misdn_log(2, bc->port, " --> state:%s\n", misdn_get_ch_state(p));
-
- switch (p->state) {
- case MISDN_INCOMING_SETUP:
- case MISDN_CALLING:
- /* This is the only place in misdn_hangup, where we
- * can call release_chan, else it might create lot's of trouble
- * */
- ast_log(LOG_NOTICE, "release channel, in CALLING/INCOMING_SETUP state.. no other events happened\n");
- release_chan(bc);
-
- p->state = MISDN_CLEANING;
- if (bc->need_release_complete)
- misdn_lib_send_event( bc, EVENT_RELEASE_COMPLETE);
- break;
- case MISDN_HOLDED:
- case MISDN_DIALING:
- start_bc_tones(p);
- hanguptone_indicate(p);
-
- if (bc->need_disconnect)
- misdn_lib_send_event( bc, EVENT_DISCONNECT);
- break;
- case MISDN_CALLING_ACKNOWLEDGE:
- start_bc_tones(p);
- hanguptone_indicate(p);
-
- if (bc->need_disconnect)
- misdn_lib_send_event( bc, EVENT_DISCONNECT);
- break;
-
- case MISDN_ALERTING:
- case MISDN_PROGRESS:
- case MISDN_PROCEEDING:
- if (p->originator != ORG_AST)
- hanguptone_indicate(p);
-
- /*p->state=MISDN_CLEANING;*/
- if (bc->need_disconnect)
- misdn_lib_send_event( bc, EVENT_DISCONNECT);
- break;
- case MISDN_CONNECTED:
- case MISDN_PRECONNECTED:
- /* Alerting or Disconnect */
- if (p->bc->nt) {
- start_bc_tones(p);
- hanguptone_indicate(p);
- p->bc->progress_indicator = INFO_PI_INBAND_AVAILABLE;
- }
- if (bc->need_disconnect)
- misdn_lib_send_event( bc, EVENT_DISCONNECT);
-
- /*p->state=MISDN_CLEANING;*/
- break;
- case MISDN_DISCONNECTED:
- if (bc->need_release)
- misdn_lib_send_event( bc, EVENT_RELEASE);
- p->state = MISDN_CLEANING; /* MISDN_HUNGUP_FROM_AST; */
- break;
-
- case MISDN_RELEASED:
- case MISDN_CLEANING:
- p->state = MISDN_CLEANING;
- break;
-
- case MISDN_BUSY:
- break;
-
- case MISDN_HOLD_DISCONNECT:
- /* need to send release here */
- chan_misdn_log(1, bc->port, " --> cause %d\n", bc->cause);
- chan_misdn_log(1, bc->port, " --> out_cause %d\n", bc->out_cause);
-
- bc->out_cause = -1;
- if (bc->need_release)
- misdn_lib_send_event(bc, EVENT_RELEASE);
- p->state = MISDN_CLEANING;
- break;
- default:
- if (bc->nt) {
- bc->out_cause = -1;
- if (bc->need_release)
- misdn_lib_send_event(bc, EVENT_RELEASE);
- p->state = MISDN_CLEANING;
- } else {
- if (bc->need_disconnect)
- misdn_lib_send_event(bc, EVENT_DISCONNECT);
- }
- }
-
- p->state = MISDN_CLEANING;
-
- chan_misdn_log(3, bc->port, " --> Channel: %s hanguped new state:%s\n", ast->name, misdn_get_ch_state(p));
-
- return 0;
-}
-
-
-static struct ast_frame *process_ast_dsp(struct chan_list *tmp, struct ast_frame *frame)
-{
- struct ast_frame *f,*f2;
-
- if (tmp->trans) {
- f2 = ast_translate(tmp->trans, frame, 0);
- f = ast_dsp_process(tmp->ast, tmp->dsp, f2);
- } else {
- chan_misdn_log(0, tmp->bc->port, "No T-Path found\n");
- return NULL;
- }
-
- if (!f || (f->frametype != AST_FRAME_DTMF))
- return frame;
-
- ast_log(LOG_DEBUG, "Detected inband DTMF digit: %c\n", f->subclass);
-
- if (tmp->faxdetect && (f->subclass == 'f')) {
- /* Fax tone -- Handle and return NULL */
- if (!tmp->faxhandled) {
- struct ast_channel *ast = tmp->ast;
- tmp->faxhandled++;
- chan_misdn_log(0, tmp->bc->port, "Fax detected, preparing %s for fax transfer.\n", ast->name);
- tmp->bc->rxgain = 0;
- isdn_lib_update_rxgain(tmp->bc);
- tmp->bc->txgain = 0;
- isdn_lib_update_txgain(tmp->bc);
-#ifdef MISDN_1_2
- *tmp->bc->pipeline = 0;
-#else
- tmp->bc->ec_enable = 0;
-#endif
- isdn_lib_update_ec(tmp->bc);
- isdn_lib_stop_dtmf(tmp->bc);
- switch (tmp->faxdetect) {
- case 1:
- if (strcmp(ast->exten, "fax")) {
- char *context;
- char context_tmp[BUFFERSIZE];
- misdn_cfg_get(tmp->bc->port, MISDN_CFG_FAXDETECT_CONTEXT, &context_tmp, sizeof(context_tmp));
- context = ast_strlen_zero(context_tmp) ? (ast_strlen_zero(ast->macrocontext) ? ast->context : ast->macrocontext) : context_tmp;
- if (ast_exists_extension(ast, context, "fax", 1, ast->cid.cid_num)) {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Redirecting %s to fax extension (context:%s)\n", ast->name, context);
- /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
- pbx_builtin_setvar_helper(ast,"FAXEXTEN",ast->exten);
- if (ast_async_goto(ast, context, "fax", 1))
- ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast->name, context);
- } else
- ast_log(LOG_NOTICE, "Fax detected, but no fax extension ctx:%s exten:%s\n", context, ast->exten);
- } else {
- ast_log(LOG_DEBUG, "Already in a fax extension, not redirecting\n");
- }
- break;
- case 2:
- ast_verbose(VERBOSE_PREFIX_3 "Not redirecting %s to fax extension, nojump is set.\n", ast->name);
- break;
- }
- } else {
- ast_log(LOG_DEBUG, "Fax already handled\n");
- }
- }
-
- if (tmp->ast_dsp && (f->subclass != 'f')) {
- chan_misdn_log(2, tmp->bc->port, " --> * SEND: DTMF (AST_DSP) :%c\n", f->subclass);
- }
-
- return f;
-}
-
-
-static struct ast_frame *misdn_read(struct ast_channel *ast)
-{
- struct chan_list *tmp;
- fd_set rrfs;
- struct timeval tv;
- int len, t;
-
- if (!ast) {
- chan_misdn_log(1, 0, "misdn_read called without ast\n");
- return NULL;
- }
- if (!(tmp = MISDN_ASTERISK_TECH_PVT(ast))) {
- chan_misdn_log(1, 0, "misdn_read called without ast->pvt\n");
- return NULL;
- }
-
- if (!tmp->bc && !(tmp->state == MISDN_HOLDED)) {
- chan_misdn_log(1, 0, "misdn_read called without bc\n");
- return NULL;
- }
-
- tv.tv_sec=0;
- tv.tv_usec=20000;
-
- FD_ZERO(&rrfs);
- FD_SET(tmp->pipe[0],&rrfs);
-
- t=select(FD_SETSIZE,&rrfs,NULL, NULL,&tv);
-
- if (!t) {
- chan_misdn_log(3, tmp->bc->port, "read Select Timed out\n");
- len=160;
- }
-
- if (t<0) {
- chan_misdn_log(-1, tmp->bc->port, "Select Error (err=%s)\n",strerror(errno));
- return NULL;
- }
-
- if (FD_ISSET(tmp->pipe[0],&rrfs)) {
- len=read(tmp->pipe[0],tmp->ast_rd_buf,sizeof(tmp->ast_rd_buf));
-
- if (len<=0) {
- /* we hangup here, since our pipe is closed */
- chan_misdn_log(2,tmp->bc->port,"misdn_read: Pipe closed, hanging up\n");
- return NULL;
- }
-
- } else {
- return NULL;
- }
-
- tmp->frame.frametype = AST_FRAME_VOICE;
- tmp->frame.subclass = AST_FORMAT_ALAW;
- tmp->frame.datalen = len;
- tmp->frame.samples = len;
- tmp->frame.mallocd = 0;
- tmp->frame.offset = 0;
- tmp->frame.delivery = ast_tv(0,0);
- tmp->frame.src = NULL;
- tmp->frame.data = tmp->ast_rd_buf;
-
- if (tmp->faxdetect && !tmp->faxhandled) {
- if (tmp->faxdetect_timeout) {
- if (ast_tvzero(tmp->faxdetect_tv)) {
- tmp->faxdetect_tv = ast_tvnow();
- chan_misdn_log(2, tmp->bc->port, "faxdetect: starting detection with timeout: %ds ...\n", tmp->faxdetect_timeout);
- return process_ast_dsp(tmp, &tmp->frame);
- } else {
- struct timeval tv_now = ast_tvnow();
- int diff = ast_tvdiff_ms(tv_now, tmp->faxdetect_tv);
- if (diff <= (tmp->faxdetect_timeout * 1000)) {
- chan_misdn_log(5, tmp->bc->port, "faxdetect: detecting ...\n");
- return process_ast_dsp(tmp, &tmp->frame);
- } else {
- chan_misdn_log(2, tmp->bc->port, "faxdetect: stopping detection (time ran out) ...\n");
- tmp->faxdetect = 0;
- return &tmp->frame;
- }
- }
- } else {
- chan_misdn_log(5, tmp->bc->port, "faxdetect: detecting ... (no timeout)\n");
- return process_ast_dsp(tmp, &tmp->frame);
- }
- } else {
- if (tmp->ast_dsp)
- return process_ast_dsp(tmp, &tmp->frame);
- else
- return &tmp->frame;
- }
-}
-
-
-static int misdn_write(struct ast_channel *ast, struct ast_frame *frame)
-{
- struct chan_list *ch;
- int i = 0;
-
- if (!ast || ! (ch = MISDN_ASTERISK_TECH_PVT(ast)) ) return -1;
-
- if (ch->state == MISDN_HOLDED) {
- chan_misdn_log(7, 0, "misdn_write: Returning because holded\n");
- return 0;
- }
-
- if (!ch->bc ) {
- ast_log(LOG_WARNING, "private but no bc\n");
- return -1;
- }
-
- if (ch->notxtone) {
- chan_misdn_log(7, ch->bc->port, "misdn_write: Returning because notxtone\n");
- return 0;
- }
-
-
- if (!frame->subclass) {
- chan_misdn_log(4, ch->bc->port, "misdn_write: * prods us\n");
- return 0;
- }
-
- if (!(frame->subclass & prefformat)) {
-
- chan_misdn_log(-1, ch->bc->port, "Got Unsupported Frame with Format:%d\n", frame->subclass);
- return 0;
- }
-
-
- if (!frame->samples ) {
- chan_misdn_log(4, ch->bc->port, "misdn_write: zero write\n");
-
- if (!strcmp(frame->src,"ast_prod")) {
- chan_misdn_log(1, ch->bc->port, "misdn_write: state (%s) prodded.\n", misdn_get_ch_state(ch));
-
- if (ch->ts) {
- chan_misdn_log(4, ch->bc->port, "Starting Playtones\n");
- misdn_lib_tone_generator_start(ch->bc);
- }
- return 0;
- }
-
- return -1;
- }
-
- if ( ! ch->bc->addr ) {
- chan_misdn_log(8, ch->bc->port, "misdn_write: no addr for bc dropping:%d\n", frame->samples);
- return 0;
- }
-
-#ifdef MISDN_DEBUG
- {
- int i, max = 5 > frame->samples ? frame->samples : 5;
-
- printf("write2mISDN %p %d bytes: ", p, frame->samples);
-
- for (i = 0; i < max; i++)
- printf("%2.2x ", ((char*) frame->data)[i]);
- printf ("\n");
- }
-#endif
-
- switch (ch->bc->bc_state) {
- case BCHAN_ACTIVATED:
- case BCHAN_BRIDGED:
- break;
- default:
- if (!ch->dropped_frame_cnt)
- chan_misdn_log(5, ch->bc->port, "BC not active (nor bridged) dropping: %d frames addr:%x exten:%s cid:%s ch->state:%s bc_state:%d l3id:%x\n", frame->samples, ch->bc->addr, ast->exten, ast->cid.cid_num, misdn_get_ch_state( ch), ch->bc->bc_state, ch->bc->l3_id);
-
- ch->dropped_frame_cnt++;
- if (ch->dropped_frame_cnt > 100) {
- ch->dropped_frame_cnt = 0;
- chan_misdn_log(5, ch->bc->port, "BC not active (nor bridged) dropping: %d frames addr:%x dropped > 100 frames!\n", frame->samples, ch->bc->addr);
- }
-
- return 0;
- }
-
- chan_misdn_log(9, ch->bc->port, "Sending :%d bytes to MISDN\n", frame->samples);
- if ( !ch->bc->nojitter && misdn_cap_is_speech(ch->bc->capability) ) {
- /* Buffered Transmit (triggered by read from isdn side)*/
- if (misdn_jb_fill(ch->jb, frame->data, frame->samples) < 0) {
- if (ch->bc->active)
- cb_log(0, ch->bc->port, "Misdn Jitterbuffer Overflow.\n");
- }
-
- } else {
- /*transmit without jitterbuffer*/
- i = misdn_lib_tx2misdn_frm(ch->bc, frame->data, frame->samples);
- }
-
- return 0;
-}
-
-
-
-
-static enum ast_bridge_result misdn_bridge (struct ast_channel *c0,
- struct ast_channel *c1, int flags,
- struct ast_frame **fo,
- struct ast_channel **rc,
- int timeoutms)
-
-{
- struct chan_list *ch1, *ch2;
- struct ast_channel *carr[2], *who;
- int to = -1;
- struct ast_frame *f;
- int p1_b, p2_b;
- int bridging;
-
- ch1 = get_chan_by_ast(c0);
- ch2 = get_chan_by_ast(c1);
-
- carr[0] = c0;
- carr[1] = c1;
-
- if (!(ch1 && ch2))
- return -1;
-
- misdn_cfg_get(ch1->bc->port, MISDN_CFG_BRIDGING, &p1_b, sizeof(int));
- misdn_cfg_get(ch2->bc->port, MISDN_CFG_BRIDGING, &p2_b, sizeof(int));
-
- if (! p1_b || ! p2_b) {
- ast_log(LOG_NOTICE, "Falling back to Asterisk bridging\n");
- return AST_BRIDGE_FAILED;
- }
-
- misdn_cfg_get(0, MISDN_GEN_BRIDGING, &bridging, sizeof(int));
- if (bridging) {
- /* trying to make a mISDN_dsp conference */
- chan_misdn_log(1, ch1->bc->port, "I SEND: Making conference with Number:%d\n", ch1->bc->pid + 1);
- misdn_lib_bridge(ch1->bc, ch2->bc);
- }
-
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Native bridging %s and %s\n", c0->name, c1->name);
-
- chan_misdn_log(1, ch1->bc->port, "* Making Native Bridge between %s and %s\n", ch1->bc->oad, ch2->bc->oad);
-
- if (! (flags & AST_BRIDGE_DTMF_CHANNEL_0) )
- ch1->ignore_dtmf = 1;
-
- if (! (flags & AST_BRIDGE_DTMF_CHANNEL_1) )
- ch2->ignore_dtmf = 1;
-
- for (;/*ever*/;) {
- to = -1;
- who = ast_waitfor_n(carr, 2, &to);
-
- if (!who) {
- ast_log(LOG_NOTICE, "misdn_bridge: empty read, breaking out\n");
- break;
- }
- f = ast_read(who);
-
- if (!f || f->frametype == AST_FRAME_CONTROL) {
- /* got hangup .. */
-
- if (!f)
- chan_misdn_log(4, ch1->bc->port, "Read Null Frame\n");
- else
- chan_misdn_log(4, ch1->bc->port, "Read Frame Control class:%d\n", f->subclass);
-
- *fo = f;
- *rc = who;
- break;
- }
-
- if ( f->frametype == AST_FRAME_DTMF ) {
- chan_misdn_log(1, 0, "Read DTMF %d from %s\n", f->subclass, who->exten);
-
- *fo = f;
- *rc = who;
- break;
- }
-
-#if 0
- if (f->frametype == AST_FRAME_VOICE) {
- chan_misdn_log(1, ch1->bc->port, "I SEND: Splitting conference with Number:%d\n", ch1->bc->pid +1);
-
- continue;
- }
-#endif
-
- if (who == c0) {
- ast_write(c1, f);
- }
- else {
- ast_write(c0, f);
- }
- }
-
- chan_misdn_log(1, ch1->bc->port, "I SEND: Splitting conference with Number:%d\n", ch1->bc->pid + 1);
-
- misdn_lib_split_bridge(ch1->bc, ch2->bc);
-
- return AST_BRIDGE_COMPLETE;
-}
-
-/** AST INDICATIONS END **/
-
-static int dialtone_indicate(struct chan_list *cl)
-{
- const struct tone_zone_sound *ts = NULL;
- struct ast_channel *ast = cl->ast;
- int nd = 0;
-
- if (!ast) {
- chan_misdn_log(0, cl->bc->port, "No Ast in dialtone_indicate\n");
- return -1;
- }
-
- misdn_cfg_get(cl->bc->port, MISDN_CFG_NODIALTONE, &nd, sizeof(nd));
-
- if (nd) {
- chan_misdn_log(1, cl->bc->port, "Not sending Dialtone, because config wants it\n");
- return 0;
- }
-
- chan_misdn_log(3, cl->bc->port, " --> Dial\n");
- ts = ast_get_indication_tone(ast->zone, "dial");
- cl->ts = ts;
-
- if (ts) {
- cl->notxtone = 0;
- cl->norxtone = 0;
- /* This prods us in misdn_write */
- ast_playtones_start(ast, 0, ts->data, 0);
- }
-
- return 0;
-}
-
-static int hanguptone_indicate(struct chan_list *cl)
-{
- misdn_lib_send_tone(cl->bc, TONE_HANGUP);
- return 0;
-}
-
-static int stop_indicate(struct chan_list *cl)
-{
- struct ast_channel *ast = cl->ast;
-
- if (!ast) {
- chan_misdn_log(0, cl->bc->port, "No Ast in stop_indicate\n");
- return -1;
- }
-
- chan_misdn_log(3, cl->bc->port, " --> None\n");
- misdn_lib_tone_generator_stop(cl->bc);
- ast_playtones_stop(ast);
-
- cl->ts = NULL;
- /*ast_deactivate_generator(ast);*/
-
- return 0;
-}
-
-
-static int start_bc_tones(struct chan_list* cl)
-{
- misdn_lib_tone_generator_stop(cl->bc);
- cl->notxtone = 0;
- cl->norxtone = 0;
- return 0;
-}
-
-static int stop_bc_tones(struct chan_list *cl)
-{
- if (!cl) return -1;
-
- cl->notxtone = 1;
- cl->norxtone = 1;
-
- return 0;
-}
-
-
-static struct chan_list *init_chan_list(int orig)
-{
- struct chan_list *cl;
-
- cl = calloc(1, sizeof(struct chan_list));
- if (!cl) {
- chan_misdn_log(-1, 0, "misdn_request: malloc failed!");
- return NULL;
- }
-
- cl->originator = orig;
- cl->need_queue_hangup = 1;
- cl->need_hangup = 1;
- cl->need_busy = 1;
- cl->overlap_dial_task = -1;
-
- return cl;
-}
-
-static struct ast_channel *misdn_request(const char *type, int format, void *data, int *cause)
-{
- struct ast_channel *tmp = NULL;
- char group[BUFFERSIZE + 1] = "";
- char dial_str[128];
- char *buf2 = ast_strdupa(data);
- char *ext;
- char *port_str;
- char *p = NULL;
- int channel = 0;
- int port = 0;
- struct misdn_bchannel *newbc = NULL;
- int dec = 0;
-
- struct chan_list *cl = init_chan_list(ORG_AST);
-
- snprintf(dial_str, sizeof(dial_str), "%s/%s", misdn_type, (char *) data);
-
- /*
- * data is ---v
- * Dial(mISDN/g:group_name[/extension[/options]])
- * Dial(mISDN/port[:preselected_channel][/extension[/options]])
- *
- * The dial extension could be empty if you are using MISDN_KEYPAD
- * to control ISDN provider features.
- */
- port_str = strsep(&buf2, "/");
- if (!ast_strlen_zero(port_str)) {
- if (port_str[0] == 'g' && port_str[1] == ':' ) {
- /* We make a group call lets checkout which ports are in my group */
- port_str += 2;
- ast_copy_string(group, port_str, sizeof(group));
- chan_misdn_log(2, 0, " --> Group Call group: %s\n", group);
- } else if ((p = strchr(port_str, ':'))) {
- /* we have a preselected channel */
- *p = 0;
- channel = atoi(++p);
- port = atoi(port_str);
- chan_misdn_log(2, port, " --> Call on preselected Channel (%d).\n", channel);
- } else {
- port = atoi(port_str);
- }
- } else {
- ast_log(LOG_WARNING, " --> ! IND : Dial(%s) WITHOUT Port or Group, check extensions.conf\n", dial_str);
- return NULL;
- }
-
- ext = strsep(&buf2, "/");
- if (!ext) {
- ext = "";
- }
-
- if (misdn_cfg_is_group_method(group, METHOD_STANDARD_DEC)) {
- chan_misdn_log(4, port, " --> STARTING STANDARD DEC...\n");
- dec = 1;
- }
-
- if (!ast_strlen_zero(group)) {
- char cfg_group[BUFFERSIZE + 1];
- struct robin_list *rr = NULL;
-
- /* Group dial */
-
- if (misdn_cfg_is_group_method(group, METHOD_ROUND_ROBIN)) {
- chan_misdn_log(4, port, " --> STARTING ROUND ROBIN...\n");
- rr = get_robin_position(group);
- }
-
- if (rr) {
- int port_start = 0;
- int port_bak = rr->port;
- int chan_bak = rr->channel;
-
- if (!rr->port)
- rr->port = misdn_cfg_get_next_port_spin(rr->port);
-
- for (; rr->port > 0; rr->port = misdn_cfg_get_next_port_spin(rr->port)) {
- int port_up;
- int check;
- int max_chan;
- int last_chance = 0;
-
- misdn_cfg_get(rr->port, MISDN_CFG_GROUPNAME, cfg_group, BUFFERSIZE);
- if (strcasecmp(cfg_group, group))
- continue;
-
- misdn_cfg_get(rr->port, MISDN_CFG_PMP_L1_CHECK, &check, sizeof(int));
- port_up = misdn_lib_port_up(rr->port, check);
-
- if (check && !port_up)
- chan_misdn_log(1, rr->port, "L1 is not Up on this Port\n");
-
- if (check && port_up < 0)
- ast_log(LOG_WARNING,"This port (%d) is blocked\n", rr->port);
-
- if ((port_start == rr->port) && (port_up <= 0))
- break;
-
- if (!port_start)
- port_start = rr->port;
-
- if (port_up <= 0)
- continue;
-
- max_chan = misdn_lib_get_maxchans(rr->port);
-
- for (++rr->channel; !last_chance && rr->channel <= max_chan; ++rr->channel) {
- if (rr->port == port_bak && rr->channel == chan_bak)
- last_chance = 1;
-
- chan_misdn_log(1, 0, "trying port:%d channel:%d\n", rr->port, rr->channel);
- newbc = misdn_lib_get_free_bc(rr->port, rr->channel, 0, 0);
- if (newbc) {
- chan_misdn_log(4, rr->port, " Success! Found port:%d channel:%d\n", newbc->port, newbc->channel);
- if (port_up)
- chan_misdn_log(4, rr->port, "portup:%d\n", port_up);
- port = rr->port;
- break;
- }
- }
-
- if (newbc || last_chance)
- break;
-
- rr->channel = 0;
- }
- if (!newbc) {
- rr->port = port_bak;
- rr->channel = chan_bak;
- }
- } else {
- for (port = misdn_cfg_get_next_port(0); port > 0;
- port = misdn_cfg_get_next_port(port)) {
-
- misdn_cfg_get(port, MISDN_CFG_GROUPNAME, cfg_group, BUFFERSIZE);
-
- chan_misdn_log(3, port, "Group [%s] Port [%d]\n", group, port);
- if (!strcasecmp(cfg_group, group)) {
- int port_up;
- int check;
- misdn_cfg_get(port, MISDN_CFG_PMP_L1_CHECK, &check, sizeof(int));
- port_up = misdn_lib_port_up(port, check);
-
- chan_misdn_log(4, port, "portup:%d\n", port_up);
-
- if (port_up > 0) {
- newbc = misdn_lib_get_free_bc(port, 0, 0, dec);
- if (newbc)
- break;
- }
- }
- }
- }
-
- /* Group dial failed ?*/
- if (!newbc) {
- ast_log(LOG_WARNING,
- "Could not Dial out on group '%s'.\n"
- "\tEither the L2 and L1 on all of these ports where DOWN (see 'show application misdn_check_l2l1')\n"
- "\tOr there was no free channel on none of the ports\n\n"
- , group);
- return NULL;
- }
- } else {
- /* 'Normal' Port dial * Port dial */
- if (channel)
- chan_misdn_log(1, port, " --> preselected_channel: %d\n", channel);
- newbc = misdn_lib_get_free_bc(port, channel, 0, dec);
-
- if (!newbc) {
- ast_log(LOG_WARNING, "Could not create channel on port:%d with extensions:%s\n", port, ext);
- return NULL;
- }
- }
-
-
- /* create ast_channel and link all the objects together */
- cl->bc = newbc;
-
- tmp = misdn_new(cl, AST_STATE_RESERVED, ext, NULL, format, port, channel);
- if (!tmp) {
- ast_log(LOG_ERROR,"Could not create Asterisk object\n");
- return NULL;
- }
-
- cl->ast=tmp;
-
- /* register chan in local list */
- cl_queue_chan(&cl_te, cl) ;
-
- /* fill in the config into the objects */
- read_config(cl, ORG_AST);
-
- /* important */
- cl->need_hangup = 0;
-
- return tmp;
-}
-
-
-static int misdn_send_text(struct ast_channel *chan, const char *text)
-{
- struct chan_list *tmp = chan->tech_pvt;
-
- if (tmp && tmp->bc) {
- ast_copy_string(tmp->bc->display, text, sizeof(tmp->bc->display));
- misdn_lib_send_event(tmp->bc, EVENT_INFORMATION);
- } else {
- ast_log(LOG_WARNING, "No chan_list but send_text request?\n");
- return -1;
- }
-
- return 0;
-}
-
-static struct ast_channel_tech misdn_tech = {
- .type = "mISDN",
- .description = "Channel driver for mISDN Support (Bri/Pri)",
- .capabilities = AST_FORMAT_ALAW ,
- .requester = misdn_request,
- .send_digit_begin = misdn_digit_begin,
- .send_digit_end = misdn_digit_end,
- .call = misdn_call,
- .bridge = misdn_bridge,
- .hangup = misdn_hangup,
- .answer = misdn_answer,
- .read = misdn_read,
- .write = misdn_write,
- .indicate = misdn_indication,
- .fixup = misdn_fixup,
- .send_text = misdn_send_text,
- .properties = 0
-};
-
-static struct ast_channel_tech misdn_tech_wo_bridge = {
- .type = "mISDN",
- .description = "Channel driver for mISDN Support (Bri/Pri)",
- .capabilities = AST_FORMAT_ALAW ,
- .requester = misdn_request,
- .send_digit_begin = misdn_digit_begin,
- .send_digit_end = misdn_digit_end,
- .call = misdn_call,
- .hangup = misdn_hangup,
- .answer = misdn_answer,
- .read = misdn_read,
- .write = misdn_write,
- .indicate = misdn_indication,
- .fixup = misdn_fixup,
- .send_text = misdn_send_text,
- .properties = 0
-};
-
-
-static int glob_channel = 0;
-
-static void update_name(struct ast_channel *tmp, int port, int c)
-{
- int chan_offset = 0;
- int tmp_port = misdn_cfg_get_next_port(0);
- for (; tmp_port > 0; tmp_port = misdn_cfg_get_next_port(tmp_port)) {
- if (tmp_port == port)
- break;
- chan_offset += misdn_lib_port_is_pri(tmp_port) ? 30 : 2;
- }
- if (c < 0)
- c = 0;
-
- ast_string_field_build(tmp, name, "%s/%d-u%d",
- misdn_type, chan_offset + c, glob_channel++);
-
- chan_misdn_log(3, port, " --> updating channel name to [%s]\n", tmp->name);
-}
-
-static struct ast_channel *misdn_new(struct chan_list *chlist, int state, char *exten, char *callerid, int format, int port, int c)
-{
- struct ast_channel *tmp;
- char *cid_name = 0, *cid_num = 0;
- int chan_offset = 0;
- int tmp_port = misdn_cfg_get_next_port(0);
- int bridging;
-
- for (; tmp_port > 0; tmp_port = misdn_cfg_get_next_port(tmp_port)) {
- if (tmp_port == port)
- break;
- chan_offset += misdn_lib_port_is_pri(tmp_port) ? 30 : 2;
- }
- if (c < 0)
- c = 0;
-
- if (callerid) {
- ast_callerid_parse(callerid, &cid_name, &cid_num);
- }
-
- tmp = ast_channel_alloc(1, state, cid_num, cid_name, "", exten, "", 0, "%s/%d-u%d", misdn_type, chan_offset + c, glob_channel++);
- if (tmp) {
- chan_misdn_log(2, 0, " --> * NEW CHANNEL dad:%s oad:%s\n", exten, callerid);
-
- tmp->nativeformats = prefformat;
-
- tmp->readformat = format;
- tmp->rawreadformat = format;
- tmp->writeformat = format;
- tmp->rawwriteformat = format;
-
- tmp->tech_pvt = chlist;
-
- misdn_cfg_get(0, MISDN_GEN_BRIDGING, &bridging, sizeof(int));
-
- if (bridging)
- tmp->tech = &misdn_tech;
- else
- tmp->tech = &misdn_tech_wo_bridge;
-
- tmp->writeformat = format;
- tmp->readformat = format;
- tmp->priority=1;
-
- if (exten)
- ast_copy_string(tmp->exten, exten, sizeof(tmp->exten));
- else
- chan_misdn_log(1, 0, "misdn_new: no exten given.\n");
-
- if (callerid)
- /* Don't use ast_set_callerid() here because it will
- * generate a needless NewCallerID event */
- tmp->cid.cid_ani = ast_strdup(cid_num);
-
- if (pipe(chlist->pipe) < 0)
- perror("Pipe failed\n");
- tmp->fds[0] = chlist->pipe[0];
-
- if (state == AST_STATE_RING)
- tmp->rings = 1;
- else
- tmp->rings = 0;
-
- } else {
- chan_misdn_log(-1, 0, "Unable to allocate channel structure\n");
- }
-
- return tmp;
-}
-
-static struct chan_list *find_chan_by_bc(struct chan_list *list, struct misdn_bchannel *bc)
-{
- struct chan_list *help = list;
- for (; help; help = help->next) {
- if (help->bc == bc) return help;
- }
-
- chan_misdn_log(6, bc->port, "$$$ find_chan: No channel found for oad:%s dad:%s\n", bc->oad, bc->dad);
-
- return NULL;
-}
-
-static struct chan_list *find_chan_by_pid(struct chan_list *list, int pid)
-{
- struct chan_list *help = list;
- for (; help; help = help->next) {
- if ( help->bc && (help->bc->pid == pid) ) return help;
- }
-
- chan_misdn_log(6, 0, "$$$ find_chan: No channel found for pid:%d\n", pid);
-
- return NULL;
-}
-
-static struct chan_list *find_holded(struct chan_list *list, struct misdn_bchannel *bc)
-{
- struct chan_list *help = list;
-
- if (bc->pri) return NULL;
-
- chan_misdn_log(6, bc->port, "$$$ find_holded: channel:%d oad:%s dad:%s\n", bc->channel, bc->oad, bc->dad);
- for (;help; help = help->next) {
- chan_misdn_log(4, bc->port, "$$$ find_holded: --> holded:%d channel:%d\n", help->state == MISDN_HOLDED, help->hold_info.channel);
- if ((help->state == MISDN_HOLDED) &&
- (help->hold_info.port == bc->port))
- return help;
- }
- chan_misdn_log(6, bc->port, "$$$ find_chan: No channel found for oad:%s dad:%s\n", bc->oad, bc->dad);
-
- return NULL;
-}
-
-
-static struct chan_list *find_holded_l3(struct chan_list *list, unsigned long l3_id, int w)
-{
- struct chan_list *help = list;
-
- for (; help; help = help->next) {
- if ( (help->state == MISDN_HOLDED) &&
- (help->l3id == l3_id)
- )
- return help;
- }
-
- return NULL;
-}
-
-static void cl_queue_chan(struct chan_list **list, struct chan_list *chan)
-{
- chan_misdn_log(4, chan->bc ? chan->bc->port : 0, "* Queuing chan %p\n", chan);
-
- ast_mutex_lock(&cl_te_lock);
- if (!*list) {
- *list = chan;
- } else {
- struct chan_list *help = *list;
- for (; help->next; help = help->next);
- help->next = chan;
- }
- chan->next = NULL;
- ast_mutex_unlock(&cl_te_lock);
-}
-
-static void cl_dequeue_chan(struct chan_list **list, struct chan_list *chan)
-{
- struct chan_list *help;
-
- if (chan->dsp)
- ast_dsp_free(chan->dsp);
- if (chan->trans)
- ast_translator_free_path(chan->trans);
-
- ast_mutex_lock(&cl_te_lock);
- if (!*list) {
- ast_mutex_unlock(&cl_te_lock);
- return;
- }
-
- if (*list == chan) {
- *list = (*list)->next;
- ast_mutex_unlock(&cl_te_lock);
- return;
- }
-
- for (help = *list; help->next; help = help->next) {
- if (help->next == chan) {
- help->next = help->next->next;
- ast_mutex_unlock(&cl_te_lock);
- return;
- }
- }
-
- ast_mutex_unlock(&cl_te_lock);
-}
-
-/** Channel Queue End **/
-
-
-static int pbx_start_chan(struct chan_list *ch)
-{
- int ret = ast_pbx_start(ch->ast);
-
- if (ret >= 0)
- ch->need_hangup = 0;
- else
- ch->need_hangup = 1;
-
- return ret;
-}
-
-static void hangup_chan(struct chan_list *ch)
-{
- int port = ch ? (ch->bc ? ch->bc->port : 0) : 0;
- if (!ch) {
- cb_log(1, 0, "Cannot hangup chan, no ch\n");
- return;
- }
-
- cb_log(5, port, "hangup_chan called\n");
-
- if (ch->need_hangup) {
- cb_log(2, port, " --> hangup\n");
- send_cause2ast(ch->ast, ch->bc, ch);
- ch->need_hangup = 0;
- ch->need_queue_hangup = 0;
- if (ch->ast)
- ast_hangup(ch->ast);
- return;
- }
-
- if (!ch->need_queue_hangup) {
- cb_log(2, port, " --> No need to queue hangup\n");
- }
-
- ch->need_queue_hangup = 0;
- if (ch->ast) {
- send_cause2ast(ch->ast, ch->bc, ch);
-
- if (ch->ast)
- ast_queue_hangup(ch->ast);
- cb_log(2, port, " --> queue_hangup\n");
- } else {
- cb_log(1, port, "Cannot hangup chan, no ast\n");
- }
-}
-
-/** Isdn asks us to release channel, pendant to misdn_hangup **/
-static void release_chan(struct misdn_bchannel *bc) {
- struct ast_channel *ast = NULL;
-
- ast_mutex_lock(&release_lock);
- {
- struct chan_list *ch=find_chan_by_bc(cl_te, bc);
- if (!ch) {
- chan_misdn_log(1, bc->port, "release_chan: Ch not found!\n");
- ast_mutex_unlock(&release_lock);
- return;
- }
-
- if (ch->ast) {
- ast = ch->ast;
- }
-
- chan_misdn_log(5, bc->port, "release_chan: bc with l3id: %x\n", bc->l3_id);
-
- /*releasing jitterbuffer*/
- if (ch->jb ) {
- misdn_jb_destroy(ch->jb);
- ch->jb = NULL;
- } else {
- if (!bc->nojitter)
- chan_misdn_log(5, bc->port, "Jitterbuffer already destroyed.\n");
- }
-
- if (ch->overlap_dial) {
- if (ch->overlap_dial_task != -1) {
- misdn_tasks_remove(ch->overlap_dial_task);
- ch->overlap_dial_task = -1;
- }
- ast_mutex_destroy(&ch->overlap_tv_lock);
- }
-
- if (ch->originator == ORG_AST) {
- misdn_out_calls[bc->port]--;
- } else {
- misdn_in_calls[bc->port]--;
- }
-
- if (ch) {
- close(ch->pipe[0]);
- close(ch->pipe[1]);
-
- if (ast && MISDN_ASTERISK_TECH_PVT(ast)) {
- chan_misdn_log(1, bc->port, "* RELEASING CHANNEL pid:%d ctx:%s dad:%s oad:%s state: %s\n", bc ? bc->pid : -1, ast->context, ast->exten, ast->cid.cid_num, misdn_get_ch_state(ch));
- chan_misdn_log(3, bc->port, " --> * State Down\n");
- MISDN_ASTERISK_TECH_PVT(ast) = NULL;
-
- if (ast->_state != AST_STATE_RESERVED) {
- chan_misdn_log(3, bc->port, " --> Setting AST State to down\n");
- ast_setstate(ast, AST_STATE_DOWN);
- }
- }
-
- ch->state = MISDN_CLEANING;
- cl_dequeue_chan(&cl_te, ch);
-
- free(ch);
- } else {
- /* chan is already cleaned, so exiting */
- }
- }
- ast_mutex_unlock(&release_lock);
-/*** release end **/
-}
-
-static void misdn_transfer_bc(struct chan_list *tmp_ch, struct chan_list *holded_chan)
-{
- chan_misdn_log(4, 0, "TRANSFERRING %s to %s\n", holded_chan->ast->name, tmp_ch->ast->name);
-
- tmp_ch->state = MISDN_HOLD_DISCONNECT;
-
- ast_moh_stop(ast_bridged_channel(holded_chan->ast));
-
- holded_chan->state=MISDN_CONNECTED;
- /* misdn_lib_transfer(holded_chan->bc); */
- ast_channel_masquerade(holded_chan->ast, ast_bridged_channel(tmp_ch->ast));
-}
-
-
-static void do_immediate_setup(struct misdn_bchannel *bc, struct chan_list *ch, struct ast_channel *ast)
-{
- char predial[256]="";
- char *p = predial;
-
- struct ast_frame fr;
-
- strncpy(predial, ast->exten, sizeof(predial) -1 );
-
- ch->state = MISDN_DIALING;
-
- if (!ch->noautorespond_on_setup) {
- if (bc->nt) {
- int ret;
- ret = misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE );
- } else {
- int ret;
- if ( misdn_lib_is_ptp(bc->port)) {
- ret = misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE );
- } else {
- ret = misdn_lib_send_event(bc, EVENT_PROCEEDING );
- }
- }
- } else {
- ch->state = MISDN_INCOMING_SETUP;
- }
-
- chan_misdn_log(1, bc->port, "* Starting Ast ctx:%s dad:%s oad:%s with 's' extension\n", ast->context, ast->exten, ast->cid.cid_num);
-
- strcpy(ast->exten, "s");
-
- if (pbx_start_chan(ch) < 0) {
- ast = NULL;
- hangup_chan(ch);
- hanguptone_indicate(ch);
-
- if (bc->nt)
- misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE );
- else
- misdn_lib_send_event(bc, EVENT_DISCONNECT );
- }
-
-
- while (!ast_strlen_zero(p) ) {
- fr.frametype = AST_FRAME_DTMF;
- fr.subclass = *p;
- fr.src = NULL;
- fr.data = NULL;
- fr.datalen = 0;
- fr.samples = 0;
- fr.mallocd = 0;
- fr.offset = 0;
- fr.delivery = ast_tv(0,0);
-
- if (ch->ast && MISDN_ASTERISK_PVT(ch->ast) && MISDN_ASTERISK_TECH_PVT(ch->ast)) {
- ast_queue_frame(ch->ast, &fr);
- }
- p++;
- }
-}
-
-
-
-static void send_cause2ast(struct ast_channel *ast, struct misdn_bchannel *bc, struct chan_list *ch) {
- if (!ast) {
- chan_misdn_log(1, 0, "send_cause2ast: No Ast\n");
- return;
- }
- if (!bc) {
- chan_misdn_log(1, 0, "send_cause2ast: No BC\n");
- return;
- }
- if (!ch) {
- chan_misdn_log(1, 0, "send_cause2ast: No Ch\n");
- return;
- }
-
- ast->hangupcause = bc->cause;
-
- switch (bc->cause) {
-
- case AST_CAUSE_UNALLOCATED:
- case AST_CAUSE_NO_ROUTE_TRANSIT_NET:
- case AST_CAUSE_NO_ROUTE_DESTINATION:
- case 4: /* Send special information tone */
- case AST_CAUSE_NUMBER_CHANGED:
- case AST_CAUSE_DESTINATION_OUT_OF_ORDER:
- /* Congestion Cases */
- /*
- * Not Queueing the Congestion anymore, since we want to hear
- * the inband message
- *
- chan_misdn_log(1, bc ? bc->port : 0, " --> * SEND: Queue Congestion pid:%d\n", bc ? bc->pid : -1);
- ch->state = MISDN_BUSY;
-
- ast_queue_control(ast, AST_CONTROL_CONGESTION);
- */
- break;
-
- case AST_CAUSE_CALL_REJECTED:
- case AST_CAUSE_USER_BUSY:
- ch->state = MISDN_BUSY;
-
- if (!ch->need_busy) {
- chan_misdn_log(1, bc ? bc->port : 0, "Queued busy already\n");
- break;
- }
-
- chan_misdn_log(1, bc ? bc->port : 0, " --> * SEND: Queue Busy pid:%d\n", bc ? bc->pid : -1);
-
- ast_queue_control(ast, AST_CONTROL_BUSY);
-
- ch->need_busy = 0;
-
- break;
- }
-}
-
-
-/*! \brief Import parameters from the dialplan environment variables */
-void import_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch)
-{
- const char *tmp;
-
- tmp = pbx_builtin_getvar_helper(chan, "MISDN_PID");
- if (tmp) {
- ch->other_pid = atoi(tmp);
- chan_misdn_log(3, bc->port, " --> IMPORT_PID: importing pid:%s\n", tmp);
- if (ch->other_pid > 0) {
- ch->other_ch = find_chan_by_pid(cl_te, ch->other_pid);
- if (ch->other_ch)
- ch->other_ch->other_ch = ch;
- }
- }
-
- tmp = pbx_builtin_getvar_helper(chan, "MISDN_ADDRESS_COMPLETE");
- if (tmp && (atoi(tmp) == 1)) {
- bc->sending_complete = 1;
- }
-
- tmp = pbx_builtin_getvar_helper(chan, "MISDN_USERUSER");
- if (tmp) {
- ast_log(LOG_NOTICE, "MISDN_USERUSER: %s\n", tmp);
- ast_copy_string(bc->uu, tmp, sizeof(bc->uu));
- bc->uulen = strlen(bc->uu);
- }
-
- tmp = pbx_builtin_getvar_helper(chan, "MISDN_KEYPAD");
- if (tmp) {
- ast_copy_string(bc->keypad, tmp, sizeof(bc->keypad));
- }
-}
-
-/*! \brief Export parameters to the dialplan environment variables */
-void export_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch)
-{
- char tmp[32];
- chan_misdn_log(3, bc->port, " --> EXPORT_PID: pid:%d\n", bc->pid);
- snprintf(tmp, sizeof(tmp), "%d", bc->pid);
- pbx_builtin_setvar_helper(chan, "_MISDN_PID", tmp);
-
- if (bc->sending_complete) {
- snprintf(tmp, sizeof(tmp), "%d", bc->sending_complete);
- pbx_builtin_setvar_helper(chan, "MISDN_ADDRESS_COMPLETE", tmp);
- }
-
- if (bc->urate) {
- snprintf(tmp, sizeof(tmp), "%d", bc->urate);
- pbx_builtin_setvar_helper(chan, "MISDN_URATE", tmp);
- }
-
- if (bc->uulen && (bc->uulen < sizeof(bc->uu))) {
- bc->uu[bc->uulen] = 0;
- pbx_builtin_setvar_helper(chan, "MISDN_USERUSER", bc->uu);
- }
-
- if (!ast_strlen_zero(bc->keypad))
- pbx_builtin_setvar_helper(chan, "MISDN_KEYPAD", bc->keypad);
-}
-
-int add_in_calls(int port)
-{
- int max_in_calls;
-
- misdn_cfg_get(port, MISDN_CFG_MAX_IN, &max_in_calls, sizeof(max_in_calls));
- misdn_in_calls[port]++;
-
- if (max_in_calls >= 0 && max_in_calls < misdn_in_calls[port]) {
- ast_log(LOG_NOTICE, "Marking Incoming Call on port[%d]\n", port);
- return misdn_in_calls[port] - max_in_calls;
- }
-
- return 0;
-}
-
-int add_out_calls(int port)
-{
- int max_out_calls;
-
- misdn_cfg_get(port, MISDN_CFG_MAX_OUT, &max_out_calls, sizeof(max_out_calls));
-
- if (max_out_calls >= 0 && max_out_calls <= misdn_out_calls[port]) {
- ast_log(LOG_NOTICE, "Rejecting Outgoing Call on port[%d]\n", port);
- return (misdn_out_calls[port] + 1) - max_out_calls;
- }
-
- misdn_out_calls[port]++;
-
- return 0;
-}
-
-static void start_pbx(struct chan_list *ch, struct misdn_bchannel *bc, struct ast_channel *chan) {
- if (pbx_start_chan(ch) < 0) {
- hangup_chan(ch);
- chan_misdn_log(-1, bc->port, "ast_pbx_start returned <0 in SETUP\n");
- if (bc->nt) {
- hanguptone_indicate(ch);
- misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE);
- } else
- misdn_lib_send_event(bc, EVENT_RELEASE);
- }
-}
-
-static void wait_for_digits(struct chan_list *ch, struct misdn_bchannel *bc, struct ast_channel *chan) {
- ch->state=MISDN_WAITING4DIGS;
- misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE );
- if (bc->nt && !bc->dad[0])
- dialtone_indicate(ch);
-}
-
-
-/************************************************************/
-/* Receive Events from isdn_lib here */
-/************************************************************/
-static enum event_response_e
-cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
-{
- int msn_valid;
- struct chan_list *ch = find_chan_by_bc(cl_te, bc);
-
- if (event != EVENT_BCHAN_DATA && event != EVENT_TONE_GENERATE) { /* Debug Only Non-Bchan */
- int debuglevel = 1;
- if ( event == EVENT_CLEANUP && !user_data)
- debuglevel = 5;
-
- chan_misdn_log(debuglevel, bc->port, "I IND :%s oad:%s dad:%s pid:%d state:%s\n", manager_isdn_get_info(event), bc->oad, bc->dad, bc->pid, ch ? misdn_get_ch_state(ch) : "none");
- if (debuglevel == 1) {
- misdn_lib_log_ies(bc);
- chan_misdn_log(4, bc->port, " --> bc_state:%s\n", bc_state2str(bc->bc_state));
- }
- }
-
- if (!ch) {
- switch(event) {
- case EVENT_SETUP:
- case EVENT_DISCONNECT:
- case EVENT_PORT_ALARM:
- case EVENT_RETRIEVE:
- case EVENT_NEW_BC:
- case EVENT_FACILITY:
- break;
- case EVENT_RELEASE_COMPLETE:
- chan_misdn_log(1, bc->port, " --> no Ch, so we've already released.\n");
- break;
- case EVENT_CLEANUP:
- case EVENT_TONE_GENERATE:
- case EVENT_BCHAN_DATA:
- return -1;
- default:
- chan_misdn_log(1, bc->port, "Chan not existing at the moment bc->l3id:%x bc:%p event:%s port:%d channel:%d\n", bc->l3_id, bc, manager_isdn_get_info(event), bc->port, bc->channel);
- return -1;
- }
- }
-
- if (ch) {
- switch (event) {
- case EVENT_TONE_GENERATE:
- break;
- case EVENT_DISCONNECT:
- case EVENT_RELEASE:
- case EVENT_RELEASE_COMPLETE:
- case EVENT_CLEANUP:
- case EVENT_TIMEOUT:
- if (!ch->ast)
- chan_misdn_log(3, bc->port, "ast_hangup already called, so we have no ast ptr anymore in event(%s)\n", manager_isdn_get_info(event));
- break;
- default:
- if (!ch->ast || !MISDN_ASTERISK_PVT(ch->ast) || !MISDN_ASTERISK_TECH_PVT(ch->ast)) {
- if (event != EVENT_BCHAN_DATA)
- ast_log(LOG_NOTICE, "No Ast or No private Pointer in Event (%d:%s)\n", event, manager_isdn_get_info(event));
- return -1;
- }
- }
- }
-
-
- switch (event) {
- case EVENT_PORT_ALARM:
- {
- int boa = 0;
- misdn_cfg_get(bc->port, MISDN_CFG_ALARM_BLOCK, &boa, sizeof(int));
- if (boa) {
- cb_log(1, bc->port, " --> blocking\n");
- misdn_lib_port_block(bc->port);
- }
- }
- break;
- case EVENT_BCHAN_ACTIVATED:
- break;
-
- case EVENT_NEW_CHANNEL:
- update_name(ch->ast,bc->port,bc->channel);
- break;
-
- case EVENT_NEW_L3ID:
- ch->l3id=bc->l3_id;
- ch->addr=bc->addr;
- break;
-
- case EVENT_NEW_BC:
- if (!ch) {
- ch = find_holded(cl_te,bc);
- }
-
- if (!ch) {
- ast_log(LOG_WARNING, "NEW_BC without chan_list?\n");
- break;
- }
-
- if (bc)
- ch->bc = (struct misdn_bchannel *)user_data;
- break;
-
- case EVENT_DTMF_TONE:
- {
- /* sending INFOS as DTMF-Frames :) */
- struct ast_frame fr;
-
- memset(&fr, 0, sizeof(fr));
- fr.frametype = AST_FRAME_DTMF;
- fr.subclass = bc->dtmf ;
- fr.src = NULL;
- fr.data = NULL;
- fr.datalen = 0;
- fr.samples = 0;
- fr.mallocd = 0;
- fr.offset = 0;
- fr.delivery = ast_tv(0,0);
-
- if (!ch->ignore_dtmf) {
- chan_misdn_log(2, bc->port, " --> DTMF:%c\n", bc->dtmf);
- ast_queue_frame(ch->ast, &fr);
- } else {
- chan_misdn_log(2, bc->port, " --> Ignoring DTMF:%c due to bridge flags\n", bc->dtmf);
- }
- }
- break;
- case EVENT_STATUS:
- break;
-
- case EVENT_INFORMATION:
- {
- if ( ch->state != MISDN_CONNECTED )
- stop_indicate(ch);
-
- if (!ch->ast)
- break;
-
- if (ch->state == MISDN_WAITING4DIGS ) {
- /* Ok, incomplete Setup, waiting till extension exists */
- if (ast_strlen_zero(bc->info_dad) && ! ast_strlen_zero(bc->keypad)) {
- chan_misdn_log(1, bc->port, " --> using keypad as info\n");
- ast_copy_string(bc->info_dad, bc->keypad, sizeof(bc->info_dad));
- }
-
- strncat(bc->dad, bc->info_dad, sizeof(bc->dad) - strlen(bc->dad) - 1);
- ast_copy_string(ch->ast->exten, bc->dad, sizeof(ch->ast->exten));
-
- /* Check for Pickup Request first */
- if (!strcmp(ch->ast->exten, ast_pickup_ext())) {
- if (ast_pickup_call(ch->ast)) {
- hangup_chan(ch);
- } else {
- struct ast_channel *chan = ch->ast;
- ch->state = MISDN_CALLING_ACKNOWLEDGE;
- ast_setstate(chan, AST_STATE_DOWN);
- hangup_chan(ch);
- ch->ast = NULL;
- break;
- }
- }
-
- if (!ast_canmatch_extension(ch->ast, ch->context, bc->dad, 1, bc->oad)) {
- if (ast_exists_extension(ch->ast, ch->context, "i", 1, bc->oad)) {
- ast_log(LOG_WARNING, "Extension can never match, So jumping to 'i' extension. port(%d)\n", bc->port);
- strcpy(ch->ast->exten, "i");
-
- ch->state = MISDN_DIALING;
- start_pbx(ch, bc, ch->ast);
- break;
- }
-
- ast_log(LOG_WARNING, "Extension can never match, so disconnecting on port(%d).\n"
- "\tMaybe you want to add an 'i' extension to catch this case.\n",
- bc->port);
-
- if (bc->nt)
- hanguptone_indicate(ch);
- ch->state = MISDN_EXTCANTMATCH;
- bc->out_cause = AST_CAUSE_UNALLOCATED;
-
- misdn_lib_send_event(bc, EVENT_DISCONNECT);
- break;
- }
-
- if (ch->overlap_dial) {
- ast_mutex_lock(&ch->overlap_tv_lock);
- ch->overlap_tv = ast_tvnow();
- ast_mutex_unlock(&ch->overlap_tv_lock);
- if (ch->overlap_dial_task == -1) {
- ch->overlap_dial_task =
- misdn_tasks_add_variable(ch->overlap_dial, misdn_overlap_dial_task, ch);
- }
- break;
- }
-
- if (ast_exists_extension(ch->ast, ch->context, bc->dad, 1, bc->oad)) {
-
- ch->state = MISDN_DIALING;
- start_pbx(ch, bc, ch->ast);
- }
- } else {
- /* sending INFOS as DTMF-Frames :) */
- struct ast_frame fr;
- int digits;
-
- memset(&fr, 0, sizeof(fr));
- fr.frametype = AST_FRAME_DTMF;
- fr.subclass = bc->info_dad[0] ;
- fr.src = NULL;
- fr.data = NULL;
- fr.datalen = 0;
- fr.samples = 0;
- fr.mallocd = 0;
- fr.offset = 0;
- fr.delivery = ast_tv(0,0);
-
- misdn_cfg_get(0, MISDN_GEN_APPEND_DIGITS2EXTEN, &digits, sizeof(int));
- if (ch->state != MISDN_CONNECTED ) {
- if (digits) {
- strncat(bc->dad, bc->info_dad, sizeof(bc->dad) - strlen(bc->dad) - 1);
- ast_copy_string(ch->ast->exten, bc->dad, sizeof(ch->ast->exten));
- ast_cdr_update(ch->ast);
- }
-
- ast_queue_frame(ch->ast, &fr);
- }
- }
- }
- break;
- case EVENT_SETUP:
- {
- struct chan_list *ch = find_chan_by_bc(cl_te, bc);
- struct ast_channel *chan;
- int exceed;
- int pres, screen;
- int ai;
- int im;
-
- if (ch) {
- switch (ch->state) {
- case MISDN_NOTHING:
- ch = NULL;
- break;
- default:
- chan_misdn_log(1, bc->port, " --> Ignoring Call we have already one\n");
- return RESPONSE_IGNORE_SETUP_WITHOUT_CLOSE; /* Ignore MSNs which are not in our List */
- }
- }
-
- msn_valid = misdn_cfg_is_msn_valid(bc->port, bc->dad);
- if (!bc->nt && ! msn_valid) {
- chan_misdn_log(1, bc->port, " --> Ignoring Call, its not in our MSN List\n");
- return RESPONSE_IGNORE_SETUP; /* Ignore MSNs which are not in our List */
- }
-
- if (bc->cw) {
- int cause;
- chan_misdn_log(0, bc->port, " --> Call Waiting on PMP sending RELEASE_COMPLETE\n");
- misdn_cfg_get(bc->port, MISDN_CFG_REJECT_CAUSE, &cause, sizeof(cause));
- bc->out_cause = cause ? cause : AST_CAUSE_NORMAL_CLEARING;
- return RESPONSE_RELEASE_SETUP;
- }
-
- print_bearer(bc);
-
- ch = init_chan_list(ORG_MISDN);
-
- if (!ch) {
- chan_misdn_log(-1, bc->port, "cb_events: malloc for chan_list failed!\n");
- return 0;
- }
-
- ch->bc = bc;
- ch->l3id = bc->l3_id;
- ch->addr = bc->addr;
- ch->originator = ORG_MISDN;
-
- chan = misdn_new(ch, AST_STATE_RESERVED, bc->dad, bc->oad, AST_FORMAT_ALAW, bc->port, bc->channel);
- if (!chan) {
- misdn_lib_send_event(bc,EVENT_RELEASE_COMPLETE);
- ast_log(LOG_ERROR, "cb_events: misdn_new failed !\n");
- return 0;
- }
-
- ch->ast = chan;
-
- if ((exceed = add_in_calls(bc->port))) {
- char tmp[16];
- snprintf(tmp, sizeof(tmp), "%d", exceed);
- pbx_builtin_setvar_helper(chan, "MAX_OVERFLOW", tmp);
- }
-
- read_config(ch, ORG_MISDN);
-
- export_ch(chan, bc, ch);
-
- ch->ast->rings = 1;
- ast_setstate(ch->ast, AST_STATE_RINGING);
-
- switch (bc->pres) {
- case 1:
- pres = AST_PRES_RESTRICTED;
- chan_misdn_log(2, bc->port, " --> PRES: Restricted (1)\n");
- break;
- case 2:
- pres = AST_PRES_UNAVAILABLE;
- chan_misdn_log(2, bc->port, " --> PRES: Unavailable (2)\n");
- break;
- default:
- pres = AST_PRES_ALLOWED;
- chan_misdn_log(2, bc->port, " --> PRES: Allowed (%d)\n", bc->pres);
- break;
- }
-
- switch (bc->screen) {
- default:
- case 0:
- screen = AST_PRES_USER_NUMBER_UNSCREENED;
- chan_misdn_log(2, bc->port, " --> SCREEN: Unscreened (%d)\n", bc->screen);
- break;
- case 1:
- screen = AST_PRES_USER_NUMBER_PASSED_SCREEN;
- chan_misdn_log(2, bc->port, " --> SCREEN: Passed screen (1)\n");
- break;
- case 2:
- screen = AST_PRES_USER_NUMBER_FAILED_SCREEN;
- chan_misdn_log(2, bc->port, " --> SCREEN: failed screen (2)\n");
- break;
- case 3:
- screen = AST_PRES_NETWORK_NUMBER;
- chan_misdn_log(2, bc->port, " --> SCREEN: Network Number (3)\n");
- break;
- }
-
- chan->cid.cid_pres = pres | screen;
-
- pbx_builtin_setvar_helper(chan, "TRANSFERCAPABILITY", ast_transfercapability2str(bc->capability));
- chan->transfercapability = bc->capability;
-
- switch (bc->capability) {
- case INFO_CAPABILITY_DIGITAL_UNRESTRICTED:
- pbx_builtin_setvar_helper(chan, "CALLTYPE", "DIGITAL");
- break;
- default:
- pbx_builtin_setvar_helper(chan, "CALLTYPE", "SPEECH");
- }
-
- /** queue new chan **/
- cl_queue_chan(&cl_te, ch);
-
- if (!strstr(ch->allowed_bearers, "all")) {
- int i;
-
- for (i = 0; i < ARRAY_LEN(allowed_bearers_array); ++i) {
- if (allowed_bearers_array[i].cap == bc->capability) {
- if (strstr(ch->allowed_bearers, allowed_bearers_array[i].name)) {
- /* The bearer capability is allowed */
- if (allowed_bearers_array[i].deprecated) {
- chan_misdn_log(0, bc->port, "%s in allowed_bearers list is deprecated\n",
- allowed_bearers_array[i].name);
- }
- break;
- }
- }
- } /* end for */
- if (i == ARRAY_LEN(allowed_bearers_array)) {
- /* We did not find the bearer capability */
- chan_misdn_log(0, bc->port, "Bearer capability not allowed: %s(%d)\n",
- bearer2str(bc->capability), bc->capability);
- bc->out_cause = AST_CAUSE_INCOMPATIBLE_DESTINATION;
-
- ch->state = MISDN_EXTCANTMATCH;
- misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE);
- return RESPONSE_OK;
- }
- }
-
- /* Check for Pickup Request first */
- if (!strcmp(chan->exten, ast_pickup_ext())) {
- if (!ch->noautorespond_on_setup) {
- int ret;/** Sending SETUP_ACK**/
- ret = misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE );
- } else {
- ch->state = MISDN_INCOMING_SETUP;
- }
- if (ast_pickup_call(chan)) {
- hangup_chan(ch);
- } else {
- ch->state = MISDN_CALLING_ACKNOWLEDGE;
- ast_setstate(chan, AST_STATE_DOWN);
- hangup_chan(ch);
- ch->ast = NULL;
- break;
- }
- }
-
- /*
- * added support for s extension hope it will help those poor cretains
- * which haven't overlap dial.
- */
- misdn_cfg_get(bc->port, MISDN_CFG_ALWAYS_IMMEDIATE, &ai, sizeof(ai));
- if (ai) {
- do_immediate_setup(bc, ch, chan);
- break;
- }
-
- /* check if we should jump into s when we have no dad */
- misdn_cfg_get(bc->port, MISDN_CFG_IMMEDIATE, &im, sizeof(im));
- if (im && ast_strlen_zero(bc->dad)) {
- do_immediate_setup(bc, ch, chan);
- break;
- }
-
- chan_misdn_log(5, bc->port, "CONTEXT:%s\n", ch->context);
- if(!ast_canmatch_extension(ch->ast, ch->context, bc->dad, 1, bc->oad)) {
- if (ast_exists_extension(ch->ast, ch->context, "i", 1, bc->oad)) {
- ast_log(LOG_WARNING, "Extension can never match, So jumping to 'i' extension. port(%d)\n", bc->port);
- strcpy(ch->ast->exten, "i");
- misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE);
- ch->state = MISDN_DIALING;
- start_pbx(ch, bc, chan);
- break;
- }
-
- ast_log(LOG_WARNING, "Extension can never match, so disconnecting on port(%d).\n"
- "\tMaybe you want to add an 'i' extension to catch this case.\n",
- bc->port);
- if (bc->nt)
- hanguptone_indicate(ch);
-
- ch->state = MISDN_EXTCANTMATCH;
- bc->out_cause = AST_CAUSE_UNALLOCATED;
-
- if (bc->nt)
- misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE );
- else
- misdn_lib_send_event(bc, EVENT_RELEASE );
-
- break;
- }
-
- /* Whatever happens, when sending_complete is set or we are PTMP TE, we will definitely
- * jump into the dialplan, when the dialed extension does not exist, the 's' extension
- * will be used by Asterisk automatically. */
- if (bc->sending_complete || (!bc->nt && !misdn_lib_is_ptp(bc->port))) {
- if (!ch->noautorespond_on_setup) {
- ch->state=MISDN_DIALING;
- misdn_lib_send_event(bc, EVENT_PROCEEDING );
- } else {
- ch->state = MISDN_INCOMING_SETUP;
- }
- start_pbx(ch, bc, chan);
- break;
- }
-
-
- /*
- * When we are NT and overlapdial is set and if
- * the number is empty, we wait for the ISDN timeout
- * instead of our own timer.
- */
- if (ch->overlap_dial && bc->nt && !bc->dad[0] ) {
- wait_for_digits(ch, bc, chan);
- break;
- }
-
- /*
- * If overlapdial we will definitely send a SETUP_ACKNOWLEDGE and wait for more
- * Infos with a Interdigit Timeout.
- * */
- if (ch->overlap_dial) {
- ast_mutex_lock(&ch->overlap_tv_lock);
- ch->overlap_tv = ast_tvnow();
- ast_mutex_unlock(&ch->overlap_tv_lock);
-
- wait_for_digits(ch, bc, chan);
- if (ch->overlap_dial_task == -1)
- ch->overlap_dial_task =
- misdn_tasks_add_variable(ch->overlap_dial, misdn_overlap_dial_task, ch);
-
- break;
- }
-
- /* If the extension does not exist and we're not TE_PTMP we wait for more digits
- * without interdigit timeout.
- * */
- if (!ast_exists_extension(ch->ast, ch->context, bc->dad, 1, bc->oad)) {
- wait_for_digits(ch, bc, chan);
- break;
- }
-
- /*
- * If the extension exists let's just jump into it.
- * */
- if (ast_exists_extension(ch->ast, ch->context, bc->dad, 1, bc->oad)) {
- if (bc->need_more_infos)
- misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE );
- else
- misdn_lib_send_event(bc, EVENT_PROCEEDING);
-
- ch->state = MISDN_DIALING;
- start_pbx(ch, bc, chan);
- break;
- }
- }
- break;
-
- case EVENT_SETUP_ACKNOWLEDGE:
- {
- ch->state = MISDN_CALLING_ACKNOWLEDGE;
-
- if (bc->channel)
- update_name(ch->ast,bc->port,bc->channel);
-
- if (!ast_strlen_zero(bc->infos_pending)) {
- /* TX Pending Infos */
- strncat(bc->dad, bc->infos_pending, sizeof(bc->dad) - strlen(bc->dad) - 1);
-
- if (!ch->ast)
- break;
- ast_copy_string(ch->ast->exten, bc->dad, sizeof(ch->ast->exten));
- ast_copy_string(bc->info_dad, bc->infos_pending, sizeof(bc->info_dad));
- ast_copy_string(bc->infos_pending, "", sizeof(bc->infos_pending));
-
- misdn_lib_send_event(bc, EVENT_INFORMATION);
- }
- }
- break;
- case EVENT_PROCEEDING:
- {
- if (bc->channel)
- update_name(ch->ast, bc->port, bc->channel);
-
- if (misdn_cap_is_speech(bc->capability) &&
- misdn_inband_avail(bc) ) {
- start_bc_tones(ch);
- }
-
- ch->state = MISDN_PROCEEDING;
-
- if (!ch->ast)
- break;
-
- ast_queue_control(ch->ast, AST_CONTROL_PROCEEDING);
- }
- break;
- case EVENT_PROGRESS:
- if (bc->channel)
- update_name(ch->ast, bc->port, bc->channel);
-
- if (!bc->nt ) {
- if ( misdn_cap_is_speech(bc->capability) &&
- misdn_inband_avail(bc)
- ) {
- start_bc_tones(ch);
- }
-
- ch->state = MISDN_PROGRESS;
-
- if (!ch->ast)
- break;
- ast_queue_control(ch->ast, AST_CONTROL_PROGRESS);
- }
- break;
-
-
- case EVENT_ALERTING:
- {
- if (bc->channel)
- update_name(ch->ast, bc->port, bc->channel);
-
- ch->state = MISDN_ALERTING;
-
- if (!ch->ast)
- break;
-
- ast_queue_control(ch->ast, AST_CONTROL_RINGING);
- ast_setstate(ch->ast, AST_STATE_RINGING);
-
- cb_log(7, bc->port, " --> Set State Ringing\n");
-
- if (misdn_cap_is_speech(bc->capability) && misdn_inband_avail(bc)) {
- cb_log(1, bc->port, "Starting Tones, we have inband Data\n");
- start_bc_tones(ch);
- } else {
- cb_log(3, bc->port, " --> We have no inband Data, the other end must create ringing\n");
- if (ch->far_alerting) {
- cb_log(1, bc->port, " --> The other end can not do ringing eh ?.. we must do all ourself..");
- start_bc_tones(ch);
- /*tone_indicate(ch, TONE_FAR_ALERTING);*/
- }
- }
- }
- break;
- case EVENT_CONNECT:
- {
- struct ast_channel *bridged;
-
- /*we answer when we've got our very new L3 ID from the NT stack */
- misdn_lib_send_event(bc, EVENT_CONNECT_ACKNOWLEDGE);
-
- if (!ch->ast)
- break;
-
- bridged = ast_bridged_channel(ch->ast);
- stop_indicate(ch);
-
- if (bridged && !strcasecmp(bridged->tech->type, "mISDN")) {
- struct chan_list *bridged_ch = MISDN_ASTERISK_TECH_PVT(bridged);
-
- chan_misdn_log(1, bc->port, " --> copying cpndialplan:%d and cad:%s to the A-Channel\n", bc->cpnnumplan, bc->cad);
- if (bridged_ch) {
- bridged_ch->bc->cpnnumplan = bc->cpnnumplan;
- ast_copy_string(bridged_ch->bc->cad, bc->cad, sizeof(bridged_ch->bc->cad));
- }
- }
- }
- ch->l3id=bc->l3_id;
- ch->addr=bc->addr;
-
- start_bc_tones(ch);
-
- ch->state = MISDN_CONNECTED;
-
- ast_queue_control(ch->ast, AST_CONTROL_ANSWER);
- break;
- case EVENT_CONNECT_ACKNOWLEDGE:
- {
- ch->l3id = bc->l3_id;
- ch->addr = bc->addr;
-
- start_bc_tones(ch);
-
- ch->state = MISDN_CONNECTED;
- }
- break;
- case EVENT_DISCONNECT:
- /*we might not have an ch->ast ptr here anymore*/
- if (ch) {
- struct chan_list *holded_ch = find_holded(cl_te, bc);
-
- chan_misdn_log(3, bc->port, " --> org:%d nt:%d, inbandavail:%d state:%d\n", ch->originator, bc->nt, misdn_inband_avail(bc), ch->state);
- if (ch->originator == ORG_AST && !bc->nt && misdn_inband_avail(bc) && ch->state != MISDN_CONNECTED) {
- /* If there's inband information available (e.g. a
- recorded message saying what was wrong with the
- dialled number, or perhaps even giving an
- alternative number, then play it instead of
- immediately releasing the call */
- chan_misdn_log(1, bc->port, " --> Inband Info Avail, not sending RELEASE\n");
-
- ch->state = MISDN_DISCONNECTED;
- start_bc_tones(ch);
-
- if (ch->ast) {
- ch->ast->hangupcause = bc->cause;
- if (bc->cause == AST_CAUSE_USER_BUSY)
- ast_queue_control(ch->ast, AST_CONTROL_BUSY);
- }
- ch->need_busy = 0;
- break;
- }
-
- /*Check for holded channel, to implement transfer*/
- if (holded_ch && holded_ch != ch && ch->ast && ch->state == MISDN_CONNECTED) {
- cb_log(1, bc->port, " --> found holded ch\n");
- misdn_transfer_bc(ch, holded_ch) ;
- }
-
- bc->need_disconnect = 0;
-
- stop_bc_tones(ch);
- hangup_chan(ch);
-#if 0
- } else {
- ch = find_holded_l3(cl_te, bc->l3_id,1);
- if (ch) {
- hangup_chan(ch);
- }
-#endif
- }
- bc->out_cause = -1;
- if (bc->need_release)
- misdn_lib_send_event(bc, EVENT_RELEASE);
- break;
-
- case EVENT_RELEASE:
- {
- bc->need_disconnect = 0;
- bc->need_release = 0;
-
- hangup_chan(ch);
- release_chan(bc);
- }
- break;
- case EVENT_RELEASE_COMPLETE:
- {
- bc->need_disconnect = 0;
- bc->need_release = 0;
- bc->need_release_complete = 0;
-
- stop_bc_tones(ch);
- hangup_chan(ch);
-
- if (ch)
- ch->state = MISDN_CLEANING;
-
- release_chan(bc);
- }
- break;
- case EVENT_BCHAN_ERROR:
- case EVENT_CLEANUP:
- {
- stop_bc_tones(ch);
-
- switch (ch->state) {
- case MISDN_CALLING:
- bc->cause = AST_CAUSE_DESTINATION_OUT_OF_ORDER;
- break;
- default:
- break;
- }
-
- hangup_chan(ch);
- release_chan(bc);
- }
- break;
-
- case EVENT_TONE_GENERATE:
- {
- int tone_len = bc->tone_cnt;
- struct ast_channel *ast = ch->ast;
- void *tmp;
- int res;
- int (*generate)(struct ast_channel *chan, void *tmp, int datalen, int samples);
-
- chan_misdn_log(9, bc->port, "TONE_GEN: len:%d\n", tone_len);
-
- if (!ast)
- break;
-
- if (!ast->generator)
- break;
-
- tmp = ast->generatordata;
- ast->generatordata = NULL;
- generate = ast->generator->generate;
-
- if (tone_len < 0 || tone_len > 512 ) {
- ast_log(LOG_NOTICE, "TONE_GEN: len was %d, set to 128\n", tone_len);
- tone_len = 128;
- }
-
- res = generate(ast, tmp, tone_len, tone_len);
- ast->generatordata = tmp;
-
- if (res) {
- ast_log(LOG_WARNING, "Auto-deactivating generator\n");
- ast_deactivate_generator(ast);
- } else {
- bc->tone_cnt = 0;
- }
- }
- break;
-
- case EVENT_BCHAN_DATA:
- {
- if (!misdn_cap_is_speech(ch->bc->capability)) {
- struct ast_frame frame;
- /*In Data Modes we queue frames*/
- frame.frametype = AST_FRAME_VOICE; /*we have no data frames yet*/
- frame.subclass = AST_FORMAT_ALAW;
- frame.datalen = bc->bframe_len;
- frame.samples = bc->bframe_len;
- frame.mallocd = 0;
- frame.offset = 0;
- frame.delivery = ast_tv(0,0);
- frame.src = NULL;
- frame.data = bc->bframe;
-
- if (ch->ast)
- ast_queue_frame(ch->ast, &frame);
- } else {
- fd_set wrfs;
- struct timeval tv = { 0, 0 };
- int t;
-
- FD_ZERO(&wrfs);
- FD_SET(ch->pipe[1], &wrfs);
-
- t = select(FD_SETSIZE, NULL, &wrfs, NULL, &tv);
-
- if (!t) {
- chan_misdn_log(9, bc->port, "Select Timed out\n");
- break;
- }
-
- if (t < 0) {
- chan_misdn_log(-1, bc->port, "Select Error (err=%s)\n", strerror(errno));
- break;
- }
-
- if (FD_ISSET(ch->pipe[1], &wrfs)) {
- chan_misdn_log(9, bc->port, "writing %d bytes to asterisk\n", bc->bframe_len);
- if (write(ch->pipe[1], bc->bframe, bc->bframe_len) <= 0) {
- chan_misdn_log(0, bc->port, "Write returned <=0 (err=%s) --> hanging up channel\n", strerror(errno));
-
- stop_bc_tones(ch);
- hangup_chan(ch);
- release_chan(bc);
- }
- } else {
- chan_misdn_log(1, bc->port, "Write Pipe full!\n");
- }
- }
- }
- break;
- case EVENT_TIMEOUT:
- {
- if (ch && bc)
- chan_misdn_log(1, bc->port, "--> state: %s\n", misdn_get_ch_state(ch));
-
- switch (ch->state) {
- case MISDN_DIALING:
- case MISDN_PROGRESS:
- if (bc->nt && !ch->nttimeout)
- break;
-
- case MISDN_CALLING:
- case MISDN_ALERTING:
- case MISDN_PROCEEDING:
- case MISDN_CALLING_ACKNOWLEDGE:
- if (bc->nt) {
- bc->progress_indicator = INFO_PI_INBAND_AVAILABLE;
- hanguptone_indicate(ch);
- }
-
- bc->out_cause = AST_CAUSE_UNALLOCATED;
- misdn_lib_send_event(bc, EVENT_DISCONNECT);
- break;
-
- case MISDN_WAITING4DIGS:
- if (bc->nt) {
- bc->progress_indicator = INFO_PI_INBAND_AVAILABLE;
- bc->out_cause = AST_CAUSE_UNALLOCATED;
- hanguptone_indicate(ch);
- misdn_lib_send_event(bc, EVENT_DISCONNECT);
- } else {
- bc->out_cause = AST_CAUSE_NORMAL_CLEARING;
- misdn_lib_send_event(bc, EVENT_RELEASE);
- }
-
- break;
-
- case MISDN_CLEANING:
- chan_misdn_log(1,bc->port," --> in state cleaning .. so ignoring, the stack should clean it for us\n");
- break;
-
- default:
- misdn_lib_send_event(bc,EVENT_RELEASE_COMPLETE);
- }
- }
- break;
-
-
- /****************************/
- /** Supplementary Services **/
- /****************************/
- case EVENT_RETRIEVE:
- {
- struct ast_channel *hold_ast;
-
- if (!ch) {
- chan_misdn_log(4, bc->port, " --> no CH, searching in holded\n");
- ch = find_holded_l3(cl_te, bc->l3_id, 1);
- }
-
- if (!ch) {
- ast_log(LOG_WARNING, "Found no Holded channel, cannot Retrieve\n");
- misdn_lib_send_event(bc, EVENT_RETRIEVE_REJECT);
- break;
- }
-
- /*remember the channel again*/
- ch->bc = bc;
- ch->state = MISDN_CONNECTED;
-
- ch->hold_info.port = 0;
- ch->hold_info.channel = 0;
-
- hold_ast = ast_bridged_channel(ch->ast);
-
- if (hold_ast) {
- ast_moh_stop(hold_ast);
- }
-
- if (misdn_lib_send_event(bc, EVENT_RETRIEVE_ACKNOWLEDGE) < 0) {
- chan_misdn_log(4, bc->port, " --> RETRIEVE_ACK failed\n");
- misdn_lib_send_event(bc, EVENT_RETRIEVE_REJECT);
- }
- }
- break;
-
- case EVENT_HOLD:
- {
- int hold_allowed;
- struct ast_channel *bridged;
-
- misdn_cfg_get(bc->port, MISDN_CFG_HOLD_ALLOWED, &hold_allowed, sizeof(int));
-
- if (!hold_allowed) {
-
- chan_misdn_log(-1, bc->port, "Hold not allowed this port.\n");
- misdn_lib_send_event(bc, EVENT_HOLD_REJECT);
- break;
- }
-
- bridged = ast_bridged_channel(ch->ast);
- if (bridged) {
- chan_misdn_log(2, bc->port, "Bridge Partner is of type: %s\n", bridged->tech->type);
- ch->state = MISDN_HOLDED;
- ch->l3id = bc->l3_id;
-
- misdn_lib_send_event(bc, EVENT_HOLD_ACKNOWLEDGE);
-
- /* XXX This should queue an AST_CONTROL_HOLD frame on this channel
- * instead of starting moh on the bridged channel directly */
- ast_moh_start(bridged, NULL, NULL);
-
- /*forget the channel now*/
- ch->bc = NULL;
- ch->hold_info.port = bc->port;
- ch->hold_info.channel = bc->channel;
-
- } else {
- misdn_lib_send_event(bc, EVENT_HOLD_REJECT);
- chan_misdn_log(0, bc->port, "We aren't bridged to anybody\n");
- }
- }
- break;
-
- case EVENT_FACILITY:
- if (!ch) {
- /* This may come from a call we don't know nothing about, so we ignore it. */
- chan_misdn_log(-1, bc->port, "Got EVENT_FACILITY but we don't have a ch!\n");
- break;
- }
-
- print_facility(&(bc->fac_in), bc);
-
- switch (bc->fac_in.Function) {
- case Fac_CD:
- {
- struct ast_channel *bridged = ast_bridged_channel(ch->ast);
- struct chan_list *ch_br;
- if (bridged && MISDN_ASTERISK_TECH_PVT(bridged)) {
- ch_br = MISDN_ASTERISK_TECH_PVT(bridged);
- /*ch->state = MISDN_FACILITY_DEFLECTED;*/
- if (ch_br->bc) {
- if (ast_exists_extension(bridged, ch->context, (char *)bc->fac_in.u.CDeflection.DeflectedToNumber, 1, bc->oad)) {
- ch_br->state = MISDN_DIALING;
- if (pbx_start_chan(ch_br) < 0) {
- chan_misdn_log(-1, ch_br->bc->port, "ast_pbx_start returned < 0 in misdn_overlap_dial_task\n");
- }
- }
- }
- }
- misdn_lib_send_event(bc, EVENT_DISCONNECT);
- }
- break;
- case Fac_AOCDCurrency:
- {
- bc->AOCDtype = Fac_AOCDCurrency;
- memcpy(&(bc->AOCD.currency), &(bc->fac_in.u.AOCDcur), sizeof(struct FacAOCDCurrency));
- export_aoc_vars(ch->originator, ch->ast, bc);
- }
- break;
- case Fac_AOCDChargingUnit:
- {
- bc->AOCDtype = Fac_AOCDChargingUnit;
- memcpy(&(bc->AOCD.chargingUnit), &(bc->fac_in.u.AOCDchu), sizeof(struct FacAOCDChargingUnit));
- export_aoc_vars(ch->originator, ch->ast, bc);
- }
- break;
- default:
- chan_misdn_log(0, bc->port," --> not yet handled: facility type:%d\n", bc->fac_in.Function);
- }
-
- break;
-
- case EVENT_RESTART:
-
- if (!bc->dummy) {
- stop_bc_tones(ch);
- release_chan(bc);
- }
- break;
-
- default:
- chan_misdn_log(1, 0, "Got Unknown Event\n");
- break;
- }
-
- return RESPONSE_OK;
-}
-
-/** TE STUFF END **/
-
-/******************************************
- *
- * Asterisk Channel Endpoint END
- *
- *
- *******************************************/
-
-
-
-static int unload_module(void)
-{
- /* First, take us out of the channel loop */
- ast_log(LOG_VERBOSE, "-- Unregistering mISDN Channel Driver --\n");
-
- misdn_tasks_destroy();
-
- if (!g_config_initialized)
- return 0;
-
- ast_cli_unregister_multiple(chan_misdn_clis, sizeof(chan_misdn_clis) / sizeof(struct ast_cli_entry));
-
- /* ast_unregister_application("misdn_crypt"); */
- ast_unregister_application("misdn_set_opt");
- ast_unregister_application("misdn_facility");
- ast_unregister_application("misdn_check_l2l1");
-
- ast_channel_unregister(&misdn_tech);
-
- free_robin_list();
- misdn_cfg_destroy();
- misdn_lib_destroy();
-
- if (misdn_debug)
- free(misdn_debug);
- if (misdn_debug_only)
- free(misdn_debug_only);
- free(misdn_ports);
-
- return 0;
-}
-
-static int load_module(void)
-{
- int i, port;
- int ntflags = 0, ntkc = 0;
- char ports[256] = "";
- char tempbuf[BUFFERSIZE + 1];
- char ntfile[BUFFERSIZE + 1];
- struct misdn_lib_iface iface = {
- .cb_event = cb_events,
- .cb_log = chan_misdn_log,
- .cb_jb_empty = chan_misdn_jb_empty,
- };
-
- max_ports = misdn_lib_maxports_get();
-
- if (max_ports <= 0) {
- ast_log(LOG_ERROR, "Unable to initialize mISDN\n");
- return AST_MODULE_LOAD_DECLINE;
- }
-
- if (misdn_cfg_init(max_ports)) {
- ast_log(LOG_ERROR, "Unable to initialize misdn_config.\n");
- return AST_MODULE_LOAD_DECLINE;
- }
- g_config_initialized = 1;
-
- misdn_debug = (int *) malloc(sizeof(int) * (max_ports + 1));
- if (!misdn_debug) {
- ast_log(LOG_ERROR, "Out of memory for misdn_debug\n");
- return AST_MODULE_LOAD_DECLINE;
- }
- misdn_ports = (int *) malloc(sizeof(int) * (max_ports + 1));
- if (!misdn_ports) {
- ast_log(LOG_ERROR, "Out of memory for misdn_ports\n");
- return AST_MODULE_LOAD_DECLINE;
- }
- misdn_cfg_get(0, MISDN_GEN_DEBUG, &misdn_debug[0], sizeof(int));
- for (i = 1; i <= max_ports; i++) {
- misdn_debug[i] = misdn_debug[0];
- misdn_ports[i] = i;
- }
- *misdn_ports = 0;
- misdn_debug_only = (int *) calloc(max_ports + 1, sizeof(int));
-
- misdn_cfg_get(0, MISDN_GEN_TRACEFILE, tempbuf, BUFFERSIZE);
- if (!ast_strlen_zero(tempbuf))
- tracing = 1;
-
- misdn_in_calls = (int *) malloc(sizeof(int) * (max_ports + 1));
- misdn_out_calls = (int *) malloc(sizeof(int) * (max_ports + 1));
-
- for (i = 1; i <= max_ports; i++) {
- misdn_in_calls[i] = 0;
- misdn_out_calls[i] = 0;
- }
-
- ast_mutex_init(&cl_te_lock);
- ast_mutex_init(&release_lock);
-
- misdn_cfg_update_ptp();
- misdn_cfg_get_ports_string(ports);
-
- if (!ast_strlen_zero(ports))
- chan_misdn_log(0, 0, "Got: %s from get_ports\n", ports);
- if (misdn_lib_init(ports, &iface, NULL))
- chan_misdn_log(0, 0, "No te ports initialized\n");
-
- misdn_cfg_get(0, MISDN_GEN_NTDEBUGFLAGS, &ntflags, sizeof(int));
- misdn_cfg_get(0, MISDN_GEN_NTDEBUGFILE, &ntfile, BUFFERSIZE);
- misdn_lib_nt_debug_init(ntflags, ntfile);
-
- misdn_cfg_get( 0, MISDN_GEN_NTKEEPCALLS, &ntkc, sizeof(int));
- misdn_lib_nt_keepcalls(ntkc);
-
- if (ast_channel_register(&misdn_tech)) {
- ast_log(LOG_ERROR, "Unable to register channel class %s\n", misdn_type);
- unload_module();
- return -1;
- }
-
- ast_cli_register_multiple(chan_misdn_clis, sizeof(chan_misdn_clis) / sizeof(struct ast_cli_entry));
-
- ast_register_application("misdn_set_opt", misdn_set_opt_exec, "misdn_set_opt",
- "misdn_set_opt(:<opt><optarg>:<opt><optarg>...):\n"
- "Sets mISDN opts. and optargs\n"
- "\n"
- "The available options are:\n"
- " a - Have Asterisk detect DTMF tones on called channel\n"
- " c - Make crypted outgoing call, optarg is keyindex\n"
- " d - Send display text to called phone, text is the optarg\n"
- " e - Perform echo cancelation on this channel,\n"
- " takes taps as optarg (32,64,128,256)\n"
- " e! - Disable echo cancelation on this channel\n"
- " f - Enable fax detection\n"
- " h - Make digital outgoing call\n"
- " h1 - Make HDLC mode digital outgoing call\n"
- " i - Ignore detected DTMF tones, don't signal them to Asterisk,\n"
- " they will be transported inband.\n"
- " jb - Set jitter buffer length, optarg is length\n"
- " jt - Set jitter buffer upper threshold, optarg is threshold\n"
- " jn - Disable jitter buffer\n"
- " n - Disable mISDN DSP on channel.\n"
- " Disables: echo cancel, DTMF detection, and volume control.\n"
- " p - Caller ID presentation,\n"
- " optarg is either 'allowed' or 'restricted'\n"
- " s - Send Non-inband DTMF as inband\n"
- " vr - Rx gain control, optarg is gain\n"
- " vt - Tx gain control, optarg is gain\n"
- );
-
-
- ast_register_application("misdn_facility", misdn_facility_exec, "misdn_facility",
- "misdn_facility(<FACILITY_TYPE>|<ARG1>|..)\n"
- "Sends the Facility Message FACILITY_TYPE with \n"
- "the given Arguments to the current ISDN Channel\n"
- "Supported Facilities are:\n"
- "\n"
- "type=calldeflect args=Nr where to deflect\n"
- );
-
-
- ast_register_application("misdn_check_l2l1", misdn_check_l2l1, "misdn_check_l2l1",
- "misdn_check_l2l1(<port>||g:<groupname>,timeout)"
- "Checks if the L2 and L1 are up on either the given <port> or\n"
- "on the ports in the group with <groupname>\n"
- "If the L1/L2 are down, check_l2l1 gets up the L1/L2 and waits\n"
- "for <timeout> seconds that this happens. Otherwise, nothing happens\n"
- "\n"
- "This application, ensures the L1/L2 state of the Ports in a group\n"
- "it is intended to make the pmp_l1_check option redundant and to\n"
- "fix a buggy switch config from your provider\n"
- "\n"
- "a sample dialplan would look like:\n\n"
- "exten => _X.,1,misdn_check_l2l1(g:out|2)\n"
- "exten => _X.,n,dial(mISDN/g:out/${EXTEN})\n"
- "\n"
- );
-
-
- misdn_cfg_get(0, MISDN_GEN_TRACEFILE, global_tracefile, BUFFERSIZE);
-
- /* start the l1 watchers */
-
- for (port = misdn_cfg_get_next_port(0); port >= 0; port = misdn_cfg_get_next_port(port)) {
- int l1timeout;
- misdn_cfg_get(port, MISDN_CFG_L1_TIMEOUT, &l1timeout, sizeof(l1timeout));
- if (l1timeout) {
- chan_misdn_log(4, 0, "Adding L1watcher task: port:%d timeout:%ds\n", port, l1timeout);
- misdn_tasks_add(l1timeout * 1000, misdn_l1_task, &misdn_ports[port]);
- }
- }
-
- chan_misdn_log(0, 0, "-- mISDN Channel Driver Registered --\n");
-
- return 0;
-}
-
-
-
-static int reload(void)
-{
- reload_config();
-
- return 0;
-}
-
-/*** SOME APPS ;)***/
-
-static int misdn_facility_exec(struct ast_channel *chan, void *data)
-{
- struct chan_list *ch = MISDN_ASTERISK_TECH_PVT(chan);
- char *tok, *tokb;
-
- chan_misdn_log(0, 0, "TYPE: %s\n", chan->tech->type);
-
- if (strcasecmp(chan->tech->type, "mISDN")) {
- ast_log(LOG_WARNING, "misdn_facility makes only sense with chan_misdn channels!\n");
- return -1;
- }
-
- if (ast_strlen_zero((char *)data)) {
- ast_log(LOG_WARNING, "misdn_facility Requires arguments\n");
- return -1;
- }
-
- tok = strtok_r((char*) data, "|", &tokb) ;
-
- if (!tok) {
- ast_log(LOG_WARNING, "misdn_facility Requires arguments\n");
- return -1;
- }
-
- if (!strcasecmp(tok, "calldeflect")) {
- tok = strtok_r(NULL, "|", &tokb) ;
-
- if (!tok) {
- ast_log(LOG_WARNING, "Facility: Call Defl Requires arguments\n");
- }
-
- if (strlen(tok) >= sizeof(ch->bc->fac_out.u.CDeflection.DeflectedToNumber)) {
- ast_log(LOG_WARNING, "Facility: Number argument too long (up to 15 digits are allowed). Ignoring.\n");
- return 0;
- }
- ch->bc->fac_out.Function = Fac_CD;
- ast_copy_string((char *)ch->bc->fac_out.u.CDeflection.DeflectedToNumber, tok, sizeof(ch->bc->fac_out.u.CDeflection.DeflectedToNumber));
- misdn_lib_send_event(ch->bc, EVENT_FACILITY);
- } else {
- chan_misdn_log(1, ch->bc->port, "Unknown Facility: %s\n", tok);
- }
-
- return 0;
-}
-
-static int misdn_check_l2l1(struct ast_channel *chan, void *data)
-{
- char group[BUFFERSIZE + 1];
- char *port_str;
- int port = 0;
- int timeout;
- int dowait = 0;
- int port_up;
-
- AST_DECLARE_APP_ARGS(args,
- AST_APP_ARG(grouppar);
- AST_APP_ARG(timeout);
- );
-
- if (ast_strlen_zero((char *)data)) {
- ast_log(LOG_WARNING, "misdn_check_l2l1 Requires arguments\n");
- return -1;
- }
-
- AST_STANDARD_APP_ARGS(args, data);
-
- if (args.argc != 2) {
- ast_log(LOG_WARNING, "Wrong argument count\n");
- return 0;
- }
-
- /*ast_log(LOG_NOTICE, "Arguments: group/port '%s' timeout '%s'\n", args.grouppar, args.timeout);*/
- timeout = atoi(args.timeout);
- port_str = args.grouppar;
-
- if (port_str[0] == 'g' && port_str[1] == ':' ) {
- /* We make a group call lets checkout which ports are in my group */
- port_str += 2;
- ast_copy_string(group, port_str, sizeof(group));
- chan_misdn_log(2, 0, "Checking Ports in group: %s\n", group);
-
- for ( port = misdn_cfg_get_next_port(port);
- port > 0;
- port = misdn_cfg_get_next_port(port)) {
- char cfg_group[BUFFERSIZE + 1];
-
- chan_misdn_log(2, 0, "trying port %d\n", port);
-
- misdn_cfg_get(port, MISDN_CFG_GROUPNAME, cfg_group, BUFFERSIZE);
-
- if (!strcasecmp(cfg_group, group)) {
- port_up = misdn_lib_port_up(port, 1);
-
- if (!port_up) {
- chan_misdn_log(2, 0, " --> port '%d'\n", port);
- misdn_lib_get_port_up(port);
- dowait = 1;
- }
- }
- }
-
- } else {
- port = atoi(port_str);
- chan_misdn_log(2, 0, "Checking Port: %d\n",port);
- port_up = misdn_lib_port_up(port, 1);
- if (!port_up) {
- misdn_lib_get_port_up(port);
- dowait = 1;
- }
- }
-
- if (dowait) {
- chan_misdn_log(2, 0, "Waiting for '%d' seconds\n", timeout);
- sleep(timeout);
- }
-
- return 0;
-}
-
-static int misdn_set_opt_exec(struct ast_channel *chan, void *data)
-{
- struct chan_list *ch = MISDN_ASTERISK_TECH_PVT(chan);
- char *tok, *tokb;
- int keyidx = 0;
- int rxgain = 0;
- int txgain = 0;
- int change_jitter = 0;
-
- if (strcasecmp(chan->tech->type, "mISDN")) {
- ast_log(LOG_WARNING, "misdn_set_opt makes only sense with chan_misdn channels!\n");
- return -1;
- }
-
- if (ast_strlen_zero((char *)data)) {
- ast_log(LOG_WARNING, "misdn_set_opt Requires arguments\n");
- return -1;
- }
-
- for (tok = strtok_r((char*) data, ":", &tokb);
- tok;
- tok = strtok_r(NULL, ":", &tokb) ) {
- int neglect = 0;
-
- if (tok[0] == '!' ) {
- neglect = 1;
- tok++;
- }
-
- switch(tok[0]) {
-
- case 'd' :
- ast_copy_string(ch->bc->display, ++tok, sizeof(ch->bc->display));
- chan_misdn_log(1, ch->bc->port, "SETOPT: Display:%s\n", ch->bc->display);
- break;
-
- case 'n':
- chan_misdn_log(1, ch->bc->port, "SETOPT: No DSP\n");
- ch->bc->nodsp = 1;
- break;
-
- case 'j':
- chan_misdn_log(1, ch->bc->port, "SETOPT: jitter\n");
- tok++;
- change_jitter = 1;
-
- switch ( tok[0] ) {
- case 'b':
- ch->jb_len = atoi(++tok);
- chan_misdn_log(1, ch->bc->port, " --> buffer_len:%d\n", ch->jb_len);
- break;
- case 't' :
- ch->jb_upper_threshold = atoi(++tok);
- chan_misdn_log(1, ch->bc->port, " --> upper_threshold:%d\n", ch->jb_upper_threshold);
- break;
- case 'n':
- ch->bc->nojitter = 1;
- chan_misdn_log(1, ch->bc->port, " --> nojitter\n");
- break;
- default:
- ch->jb_len = 4000;
- ch->jb_upper_threshold = 0;
- chan_misdn_log(1, ch->bc->port, " --> buffer_len:%d (default)\n", ch->jb_len);
- chan_misdn_log(1, ch->bc->port, " --> upper_threshold:%d (default)\n", ch->jb_upper_threshold);
- }
- break;
- case 'v':
- tok++;
-
- switch (tok[0]) {
- case 'r' :
- rxgain = atoi(++tok);
- if (rxgain < -8)
- rxgain = -8;
- if (rxgain > 8)
- rxgain = 8;
- ch->bc->rxgain = rxgain;
- chan_misdn_log(1, ch->bc->port, "SETOPT: Volume:%d\n", rxgain);
- break;
- case 't':
- txgain = atoi(++tok);
- if (txgain < -8)
- txgain = -8;
- if (txgain > 8)
- txgain = 8;
- ch->bc->txgain = txgain;
- chan_misdn_log(1, ch->bc->port, "SETOPT: Volume:%d\n", txgain);
- break;
- }
- break;
-
- case 'c':
- keyidx = atoi(++tok);
- {
- char keys[4096];
- char *key = NULL, *tmp = keys;
- int i;
- misdn_cfg_get(0, MISDN_GEN_CRYPT_KEYS, keys, sizeof(keys));
-
- for (i = 0; i < keyidx; i++) {
- key = strsep(&tmp, ",");
- }
-
- if (key) {
- ast_copy_string(ch->bc->crypt_key, key, sizeof(ch->bc->crypt_key));
- }
-
- chan_misdn_log(0, ch->bc->port, "SETOPT: crypt with key:%s\n", ch->bc->crypt_key);
- break;
- }
- case 'e':
- chan_misdn_log(1, ch->bc->port, "SETOPT: EchoCancel\n");
-
- if (neglect) {
- chan_misdn_log(1, ch->bc->port, " --> disabled\n");
-#ifdef MISDN_1_2
- *ch->bc->pipeline = 0;
-#else
- ch->bc->ec_enable = 0;
-#endif
- } else {
-#ifdef MISDN_1_2
- update_pipeline_config(ch->bc);
-#else
- ch->bc->ec_enable = 1;
- ch->bc->orig = ch->originator;
- tok++;
- if (*tok) {
- ch->bc->ec_deftaps = atoi(tok);
- }
-#endif
- }
-
- break;
- case 'h':
- chan_misdn_log(1, ch->bc->port, "SETOPT: Digital\n");
-
- if (strlen(tok) > 1 && tok[1] == '1') {
- chan_misdn_log(1, ch->bc->port, "SETOPT: HDLC \n");
- if (!ch->bc->hdlc) {
- ch->bc->hdlc = 1;
- }
- }
- ch->bc->capability = INFO_CAPABILITY_DIGITAL_UNRESTRICTED;
- break;
-
- case 's':
- chan_misdn_log(1, ch->bc->port, "SETOPT: Send DTMF\n");
- ch->bc->send_dtmf = 1;
- break;
-
- case 'f':
- chan_misdn_log(1, ch->bc->port, "SETOPT: Faxdetect\n");
- ch->faxdetect = 1;
- misdn_cfg_get(ch->bc->port, MISDN_CFG_FAXDETECT_TIMEOUT, &ch->faxdetect_timeout, sizeof(ch->faxdetect_timeout));
- break;
-
- case 'a':
- chan_misdn_log(1, ch->bc->port, "SETOPT: AST_DSP (for DTMF)\n");
- ch->ast_dsp = 1;
- break;
-
- case 'p':
- chan_misdn_log(1, ch->bc->port, "SETOPT: callerpres: %s\n", &tok[1]);
- /* CRICH: callingpres!!! */
- if (strstr(tok,"allowed")) {
- ch->bc->pres = 0;
- } else if (strstr(tok, "restricted")) {
- ch->bc->pres = 1;
- } else if (strstr(tok, "not_screened")) {
- chan_misdn_log(0, ch->bc->port, "SETOPT: callerpres: not_screened is deprecated\n");
- ch->bc->pres = 1;
- }
- break;
- case 'i' :
- chan_misdn_log(1, ch->bc->port, "Ignoring dtmf tones, just use them inband\n");
- ch->ignore_dtmf=1;
- break;
- default:
- break;
- }
- }
-
- if (change_jitter)
- config_jitterbuffer(ch);
-
- if (ch->faxdetect || ch->ast_dsp) {
- if (!ch->dsp)
- ch->dsp = ast_dsp_new();
- if (ch->dsp)
- ast_dsp_set_features(ch->dsp, DSP_FEATURE_DTMF_DETECT| DSP_FEATURE_FAX_DETECT);
- if (!ch->trans)
- ch->trans = ast_translator_build_path(AST_FORMAT_SLINEAR, AST_FORMAT_ALAW);
- }
-
- if (ch->ast_dsp) {
- chan_misdn_log(1, ch->bc->port, "SETOPT: with AST_DSP we deactivate mISDN_dsp\n");
- ch->bc->nodsp = 1;
- ch->bc->nojitter = 1;
- }
-
- return 0;
-}
-
-
-int chan_misdn_jb_empty ( struct misdn_bchannel *bc, char *buf, int len)
-{
- struct chan_list *ch = find_chan_by_bc(cl_te, bc);
-
- if (ch && ch->jb) {
- return misdn_jb_empty(ch->jb, buf, len);
- }
-
- return -1;
-}
-
-
-
-/*******************************************************/
-/***************** JITTERBUFFER ************************/
-/*******************************************************/
-
-
-/* allocates the jb-structure and initialize the elements*/
-struct misdn_jb *misdn_jb_init(int size, int upper_threshold)
-{
- int i;
- struct misdn_jb *jb;
-
- jb = malloc(sizeof(struct misdn_jb));
- if (!jb) {
- chan_misdn_log(-1, 0, "No free Mem for jb\n");
- return NULL;
- }
- jb->size = size;
- jb->upper_threshold = upper_threshold;
- jb->wp = 0;
- jb->rp = 0;
- jb->state_full = 0;
- jb->state_empty = 0;
- jb->bytes_wrote = 0;
- jb->samples = malloc(size * sizeof(char));
- if (!jb->samples) {
- free(jb);
- chan_misdn_log(-1, 0, "No free Mem for jb->samples\n");
- return NULL;
- }
-
- jb->ok = malloc(size * sizeof(char));
- if (!jb->ok) {
- free(jb->samples);
- free(jb);
- chan_misdn_log(-1, 0, "No free Mem for jb->ok\n");
- return NULL;
- }
-
- for (i = 0; i < size; i++)
- jb->ok[i] = 0;
-
- ast_mutex_init(&jb->mutexjb);
-
- return jb;
-}
-
-/* frees the data and destroys the given jitterbuffer struct */
-void misdn_jb_destroy(struct misdn_jb *jb)
-{
- ast_mutex_destroy(&jb->mutexjb);
-
- free(jb->ok);
- free(jb->samples);
- free(jb);
-}
-
-/* fills the jitterbuffer with len data returns < 0 if there was an
- error (buffer overflow). */
-int misdn_jb_fill(struct misdn_jb *jb, const char *data, int len)
-{
- int i, j, rp, wp;
-
- if (!jb || ! data)
- return 0;
-
- ast_mutex_lock(&jb->mutexjb);
-
- wp = jb->wp;
- rp = jb->rp;
-
- for (i = 0; i < len; i++) {
- jb->samples[wp] = data[i];
- jb->ok[wp] = 1;
- wp = (wp != jb->size - 1) ? wp + 1 : 0;
-
- if (wp == jb->rp)
- jb->state_full = 1;
- }
-
- if (wp >= rp)
- jb->state_buffer = wp - rp;
- else
- jb->state_buffer = jb->size - rp + wp;
- chan_misdn_log(9, 0, "misdn_jb_fill: written:%d | Buffer status:%d p:%p\n", len, jb->state_buffer, jb);
-
- if (jb->state_full) {
- jb->wp = wp;
-
- rp = wp;
- for (j = 0; j < jb->upper_threshold; j++)
- rp = (rp != 0) ? rp - 1 : jb->size - 1;
- jb->rp = rp;
- jb->state_full = 0;
- jb->state_empty = 1;
-
- ast_mutex_unlock(&jb->mutexjb);
-
- return -1;
- }
-
- if (!jb->state_empty) {
- jb->bytes_wrote += len;
- if (jb->bytes_wrote >= jb->upper_threshold) {
- jb->state_empty = 1;
- jb->bytes_wrote = 0;
- }
- }
- jb->wp = wp;
-
- ast_mutex_unlock(&jb->mutexjb);
-
- return 0;
-}
-
-/* gets len bytes out of the jitterbuffer if available, else only the
-available data is returned and the return value indicates the number
-of data. */
-int misdn_jb_empty(struct misdn_jb *jb, char *data, int len)
-{
- int i, wp, rp, read = 0;
-
- ast_mutex_lock(&jb->mutexjb);
-
- rp = jb->rp;
- wp = jb->wp;
-
- if (jb->state_empty) {
- for (i = 0; i < len; i++) {
- if (wp == rp) {
- jb->rp = rp;
- jb->state_empty = 0;
-
- ast_mutex_unlock(&jb->mutexjb);
-
- return read;
- } else {
- if (jb->ok[rp] == 1) {
- data[i] = jb->samples[rp];
- jb->ok[rp] = 0;
- rp = (rp != jb->size - 1) ? rp + 1 : 0;
- read += 1;
- }
- }
- }
-
- if (wp >= rp)
- jb->state_buffer = wp - rp;
- else
- jb->state_buffer = jb->size - rp + wp;
- chan_misdn_log(9, 0, "misdn_jb_empty: read:%d | Buffer status:%d p:%p\n", len, jb->state_buffer, jb);
-
- jb->rp = rp;
- } else
- chan_misdn_log(9, 0, "misdn_jb_empty: Wait...requested:%d p:%p\n", len, jb);
-
- ast_mutex_unlock(&jb->mutexjb);
-
- return read;
-}
-
-
-
-
-/*******************************************************/
-/*************** JITTERBUFFER END *********************/
-/*******************************************************/
-
-
-
-
-static void chan_misdn_log(int level, int port, char *tmpl, ...)
-{
- va_list ap;
- char buf[1024];
- char port_buf[8];
-
- if (! ((0 <= port) && (port <= max_ports))) {
- ast_log(LOG_WARNING, "cb_log called with out-of-range port number! (%d)\n", port);
- port = 0;
- level = -1;
- }
-
- snprintf(port_buf, sizeof(port_buf), "P[%2d] ", port);
-
- va_start(ap, tmpl);
- vsnprintf(buf, sizeof(buf), tmpl, ap);
- va_end(ap);
-
- if (level == -1)
- ast_log(LOG_WARNING, "%s", buf);
-
- else if (misdn_debug_only[port] ?
- (level == 1 && misdn_debug[port]) || (level == misdn_debug[port])
- : level <= misdn_debug[port]) {
-
- ast_console_puts(port_buf);
- ast_console_puts(buf);
- }
-
- if ((level <= misdn_debug[0]) && !ast_strlen_zero(global_tracefile) ) {
- time_t tm = time(NULL);
- char *tmp = ctime(&tm), *p;
-
- FILE *fp = fopen(global_tracefile, "a+");
-
- p = strchr(tmp, '\n');
- if (p)
- *p = ':';
-
- if (!fp) {
- ast_console_puts("Error opening Tracefile: [ ");
- ast_console_puts(global_tracefile);
- ast_console_puts(" ] ");
-
- ast_console_puts(strerror(errno));
- ast_console_puts("\n");
- return ;
- }
-
- fputs(tmp, fp);
- fputs(" ", fp);
- fputs(port_buf, fp);
- fputs(" ", fp);
- fputs(buf, fp);
-
- fclose(fp);
- }
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Channel driver for mISDN Support (BRI/PRI)",
- .load = load_module,
- .unload = unload_module,
- .reload = reload,
-);
diff --git a/1.4.23-rc4/channels/chan_nbs.c b/1.4.23-rc4/channels/chan_nbs.c
deleted file mode 100644
index b231127ce..000000000
--- a/1.4.23-rc4/channels/chan_nbs.c
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 1999 - 2006, Digium, Inc.
- *
- * Mark Spencer <markster@digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Network broadcast sound support channel driver
- *
- * \author Mark Spencer <markster@digium.com>
- *
- * \ingroup channel_drivers
- */
-
-/*** MODULEINFO
- <depend>nbs</depend>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
-#include <stdio.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/time.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <arpa/inet.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <nbs.h>
-
-#include "asterisk/lock.h"
-#include "asterisk/channel.h"
-#include "asterisk/config.h"
-#include "asterisk/logger.h"
-#include "asterisk/module.h"
-#include "asterisk/pbx.h"
-#include "asterisk/options.h"
-#include "asterisk/utils.h"
-
-static const char tdesc[] = "Network Broadcast Sound Driver";
-
-/* Only linear is allowed */
-static int prefformat = AST_FORMAT_SLINEAR;
-
-static char context[AST_MAX_EXTENSION] = "default";
-static char type[] = "NBS";
-
-/* NBS creates private structures on demand */
-
-struct nbs_pvt {
- NBS *nbs;
- struct ast_channel *owner; /* Channel we belong to, possibly NULL */
- char app[16]; /* Our app */
- char stream[80]; /* Our stream */
- struct ast_frame fr; /* "null" frame */
- struct ast_module_user *u; /*! for holding a reference to this module */
-};
-
-static struct ast_channel *nbs_request(const char *type, int format, void *data, int *cause);
-static int nbs_call(struct ast_channel *ast, char *dest, int timeout);
-static int nbs_hangup(struct ast_channel *ast);
-static struct ast_frame *nbs_xread(struct ast_channel *ast);
-static int nbs_xwrite(struct ast_channel *ast, struct ast_frame *frame);
-
-static const struct ast_channel_tech nbs_tech = {
- .type = type,
- .description = tdesc,
- .capabilities = AST_FORMAT_SLINEAR,
- .requester = nbs_request,
- .call = nbs_call,
- .hangup = nbs_hangup,
- .read = nbs_xread,
- .write = nbs_xwrite,
-};
-
-static int nbs_call(struct ast_channel *ast, char *dest, int timeout)
-{
- struct nbs_pvt *p;
-
- p = ast->tech_pvt;
-
- if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
- ast_log(LOG_WARNING, "nbs_call called on %s, neither down nor reserved\n", ast->name);
- return -1;
- }
- /* When we call, it just works, really, there's no destination... Just
- ring the phone and wait for someone to answer */
- if (option_debug)
- ast_log(LOG_DEBUG, "Calling %s on %s\n", dest, ast->name);
-
- /* If we can't connect, return congestion */
- if (nbs_connect(p->nbs)) {
- ast_log(LOG_WARNING, "NBS Connection failed on %s\n", ast->name);
- ast_queue_control(ast, AST_CONTROL_CONGESTION);
- } else {
- ast_setstate(ast, AST_STATE_RINGING);
- ast_queue_control(ast, AST_CONTROL_ANSWER);
- }
-
- return 0;
-}
-
-static void nbs_destroy(struct nbs_pvt *p)
-{
- if (p->nbs)
- nbs_delstream(p->nbs);
- ast_module_user_remove(p->u);
- free(p);
-}
-
-static struct nbs_pvt *nbs_alloc(void *data)
-{
- struct nbs_pvt *p;
- int flags = 0;
- char stream[256];
- char *opts;
-
- ast_copy_string(stream, data, sizeof(stream));
- if ((opts = strchr(stream, ':'))) {
- *opts = '\0';
- opts++;
- } else
- opts = "";
- p = malloc(sizeof(struct nbs_pvt));
- if (p) {
- memset(p, 0, sizeof(struct nbs_pvt));
- if (!ast_strlen_zero(opts)) {
- if (strchr(opts, 'm'))
- flags |= NBS_FLAG_MUTE;
- if (strchr(opts, 'o'))
- flags |= NBS_FLAG_OVERSPEAK;
- if (strchr(opts, 'e'))
- flags |= NBS_FLAG_EMERGENCY;
- if (strchr(opts, 'O'))
- flags |= NBS_FLAG_OVERRIDE;
- } else
- flags = NBS_FLAG_OVERSPEAK;
-
- ast_copy_string(p->stream, stream, sizeof(p->stream));
- p->nbs = nbs_newstream("asterisk", stream, flags);
- if (!p->nbs) {
- ast_log(LOG_WARNING, "Unable to allocate new NBS stream '%s' with flags %d\n", stream, flags);
- free(p);
- p = NULL;
- } else {
- /* Set for 8000 hz mono, 640 samples */
- nbs_setbitrate(p->nbs, 8000);
- nbs_setchannels(p->nbs, 1);
- nbs_setblocksize(p->nbs, 640);
- nbs_setblocking(p->nbs, 0);
- }
- }
- return p;
-}
-
-static int nbs_hangup(struct ast_channel *ast)
-{
- struct nbs_pvt *p;
- p = ast->tech_pvt;
- if (option_debug)
- ast_log(LOG_DEBUG, "nbs_hangup(%s)\n", ast->name);
- if (!ast->tech_pvt) {
- ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
- return 0;
- }
- nbs_destroy(p);
- ast->tech_pvt = NULL;
- ast_setstate(ast, AST_STATE_DOWN);
- return 0;
-}
-
-static struct ast_frame *nbs_xread(struct ast_channel *ast)
-{
- struct nbs_pvt *p = ast->tech_pvt;
-
-
- /* Some nice norms */
- p->fr.datalen = 0;
- p->fr.samples = 0;
- p->fr.data = NULL;
- p->fr.src = type;
- p->fr.offset = 0;
- p->fr.mallocd=0;
- p->fr.delivery.tv_sec = 0;
- p->fr.delivery.tv_usec = 0;
-
- ast_log(LOG_DEBUG, "Returning null frame on %s\n", ast->name);
-
- return &p->fr;
-}
-
-static int nbs_xwrite(struct ast_channel *ast, struct ast_frame *frame)
-{
- struct nbs_pvt *p = ast->tech_pvt;
- /* Write a frame of (presumably voice) data */
- if (frame->frametype != AST_FRAME_VOICE) {
- if (frame->frametype != AST_FRAME_IMAGE)
- ast_log(LOG_WARNING, "Don't know what to do with frame type '%d'\n", frame->frametype);
- return 0;
- }
- if (!(frame->subclass &
- (AST_FORMAT_SLINEAR))) {
- ast_log(LOG_WARNING, "Cannot handle frames in %d format\n", frame->subclass);
- return 0;
- }
- if (ast->_state != AST_STATE_UP) {
- /* Don't try tos end audio on-hook */
- return 0;
- }
- if (nbs_write(p->nbs, frame->data, frame->datalen / 2) < 0)
- return -1;
- return 0;
-}
-
-static struct ast_channel *nbs_new(struct nbs_pvt *i, int state)
-{
- struct ast_channel *tmp;
- tmp = ast_channel_alloc(1, state, 0, 0, "", "s", context, 0, "NBS/%s", i->stream);
- if (tmp) {
- tmp->tech = &nbs_tech;
- tmp->fds[0] = nbs_fd(i->nbs);
- tmp->nativeformats = prefformat;
- tmp->rawreadformat = prefformat;
- tmp->rawwriteformat = prefformat;
- tmp->writeformat = prefformat;
- tmp->readformat = prefformat;
- if (state == AST_STATE_RING)
- tmp->rings = 1;
- tmp->tech_pvt = i;
- ast_copy_string(tmp->context, context, sizeof(tmp->context));
- ast_copy_string(tmp->exten, "s", sizeof(tmp->exten));
- ast_string_field_set(tmp, language, "");
- i->owner = tmp;
- i->u = ast_module_user_add(tmp);
- if (state != AST_STATE_DOWN) {
- if (ast_pbx_start(tmp)) {
- ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
- ast_hangup(tmp);
- }
- }
- } else
- ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
- return tmp;
-}
-
-
-static struct ast_channel *nbs_request(const char *type, int format, void *data, int *cause)
-{
- int oldformat;
- struct nbs_pvt *p;
- struct ast_channel *tmp = NULL;
-
- oldformat = format;
- format &= (AST_FORMAT_SLINEAR);
- if (!format) {
- ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", oldformat);
- return NULL;
- }
- p = nbs_alloc(data);
- if (p) {
- tmp = nbs_new(p, AST_STATE_DOWN);
- if (!tmp)
- nbs_destroy(p);
- }
- return tmp;
-}
-
-static int unload_module(void)
-{
- /* First, take us out of the channel loop */
- ast_channel_unregister(&nbs_tech);
- return 0;
-}
-
-static int load_module(void)
-{
- /* Make sure we can register our channel type */
- if (ast_channel_register(&nbs_tech)) {
- ast_log(LOG_ERROR, "Unable to register channel class %s\n", type);
- return -1;
- }
- return 0;
-}
-
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Network Broadcast Sound Support");
diff --git a/1.4.23-rc4/channels/chan_oss.c b/1.4.23-rc4/channels/chan_oss.c
deleted file mode 100644
index ac62f2005..000000000
--- a/1.4.23-rc4/channels/chan_oss.c
+++ /dev/null
@@ -1,1899 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 1999 - 2005, Digium, Inc.
- *
- * Mark Spencer <markster@digium.com>
- *
- * FreeBSD changes and multiple device support by Luigi Rizzo, 2005.05.25
- * note-this code best seen with ts=8 (8-spaces tabs) in the editor
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Channel driver for OSS sound cards
- *
- * \author Mark Spencer <markster@digium.com>
- * \author Luigi Rizzo
- *
- * \par See also
- * \arg \ref Config_oss
- *
- * \ingroup channel_drivers
- */
-
-/*** MODULEINFO
- <depend>ossaudio</depend>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
-#include <stdio.h>
-#include <ctype.h>
-#include <math.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <fcntl.h>
-#include <sys/time.h>
-#include <stdlib.h>
-#include <errno.h>
-
-#ifdef __linux
-#include <linux/soundcard.h>
-#elif defined(__FreeBSD__)
-#include <sys/soundcard.h>
-#else
-#include <soundcard.h>
-#endif
-
-#include "asterisk/lock.h"
-#include "asterisk/frame.h"
-#include "asterisk/logger.h"
-#include "asterisk/callerid.h"
-#include "asterisk/channel.h"
-#include "asterisk/module.h"
-#include "asterisk/options.h"
-#include "asterisk/pbx.h"
-#include "asterisk/config.h"
-#include "asterisk/cli.h"
-#include "asterisk/utils.h"
-#include "asterisk/causes.h"
-#include "asterisk/endian.h"
-#include "asterisk/stringfields.h"
-#include "asterisk/abstract_jb.h"
-#include "asterisk/musiconhold.h"
-
-/* ringtones we use */
-#include "busy_tone.h"
-#include "ring_tone.h"
-#include "ring10.h"
-#include "answer.h"
-
-/*! Global jitterbuffer configuration - by default, jb is disabled */
-static struct ast_jb_conf default_jbconf =
-{
- .flags = 0,
- .max_size = -1,
- .resync_threshold = -1,
- .impl = "",
-};
-static struct ast_jb_conf global_jbconf;
-
-/*
- * Basic mode of operation:
- *
- * we have one keyboard (which receives commands from the keyboard)
- * and multiple headset's connected to audio cards.
- * Cards/Headsets are named as the sections of oss.conf.
- * The section called [general] contains the default parameters.
- *
- * At any time, the keyboard is attached to one card, and you
- * can switch among them using the command 'console foo'
- * where 'foo' is the name of the card you want.
- *
- * oss.conf parameters are
-START_CONFIG
-
-[general]
- ; General config options, with default values shown.
- ; You should use one section per device, with [general] being used
- ; for the first device and also as a template for other devices.
- ;
- ; All but 'debug' can go also in the device-specific sections.
- ;
- ; debug = 0x0 ; misc debug flags, default is 0
-
- ; Set the device to use for I/O
- ; device = /dev/dsp
-
- ; Optional mixer command to run upon startup (e.g. to set
- ; volume levels, mutes, etc.
- ; mixer =
-
- ; Software mic volume booster (or attenuator), useful for sound
- ; cards or microphones with poor sensitivity. The volume level
- ; is in dB, ranging from -20.0 to +20.0
- ; boost = n ; mic volume boost in dB
-
- ; Set the callerid for outgoing calls
- ; callerid = John Doe <555-1234>
-
- ; autoanswer = no ; no autoanswer on call
- ; autohangup = yes ; hangup when other party closes
- ; extension = s ; default extension to call
- ; context = default ; default context for outgoing calls
- ; language = "" ; default language
-
- ; Default Music on Hold class to use when this channel is placed on hold in
- ; the case that the music class is not set on the channel with
- ; Set(CHANNEL(musicclass)=whatever) in the dialplan and the peer channel
- ; putting this one on hold did not suggest a class to use.
- ;
- ; mohinterpret=default
-
- ; If you set overridecontext to 'yes', then the whole dial string
- ; will be interpreted as an extension, which is extremely useful
- ; to dial SIP, IAX and other extensions which use the '@' character.
- ; The default is 'no' just for backward compatibility, but the
- ; suggestion is to change it.
- ; overridecontext = no ; if 'no', the last @ will start the context
- ; if 'yes' the whole string is an extension.
-
- ; low level device parameters in case you have problems with the
- ; device driver on your operating system. You should not touch these
- ; unless you know what you are doing.
- ; queuesize = 10 ; frames in device driver
- ; frags = 8 ; argument to SETFRAGMENT
-
- ;------------------------------ JITTER BUFFER CONFIGURATION --------------------------
- ; jbenable = yes ; Enables the use of a jitterbuffer on the receiving side of an
- ; OSS channel. Defaults to "no". An enabled jitterbuffer will
- ; be used only if the sending side can create and the receiving
- ; side can not accept jitter. The OSS channel can't accept jitter,
- ; thus an enabled jitterbuffer on the receive OSS side will always
- ; be used if the sending side can create jitter.
-
- ; jbmaxsize = 200 ; Max length of the jitterbuffer in milliseconds.
-
- ; jbresyncthreshold = 1000 ; Jump in the frame timestamps over which the jitterbuffer is
- ; resynchronized. Useful to improve the quality of the voice, with
- ; big jumps in/broken timestamps, usualy sent from exotic devices
- ; and programs. Defaults to 1000.
-
- ; jbimpl = fixed ; Jitterbuffer implementation, used on the receiving side of an OSS
- ; channel. Two implementations are currenlty available - "fixed"
- ; (with size always equals to jbmax-size) and "adaptive" (with
- ; variable size, actually the new jb of IAX2). Defaults to fixed.
-
- ; jblog = no ; Enables jitterbuffer frame logging. Defaults to "no".
- ;-----------------------------------------------------------------------------------
-
-[card1]
- ; device = /dev/dsp1 ; alternate device
-
-END_CONFIG
-
-.. and so on for the other cards.
-
- */
-
-/*
- * Helper macros to parse config arguments. They will go in a common
- * header file if their usage is globally accepted. In the meantime,
- * we define them here. Typical usage is as below.
- * Remember to open a block right before M_START (as it declares
- * some variables) and use the M_* macros WITHOUT A SEMICOLON:
- *
- * {
- * M_START(v->name, v->value)
- *
- * M_BOOL("dothis", x->flag1)
- * M_STR("name", x->somestring)
- * M_F("bar", some_c_code)
- * M_END(some_final_statement)
- * ... other code in the block
- * }
- *
- * XXX NOTE these macros should NOT be replicated in other parts of asterisk.
- * Likely we will come up with a better way of doing config file parsing.
- */
-#define M_START(var, val) \
- char *__s = var; char *__val = val;
-#define M_END(x) x;
-#define M_F(tag, f) if (!strcasecmp((__s), tag)) { f; } else
-#define M_BOOL(tag, dst) M_F(tag, (dst) = ast_true(__val) )
-#define M_UINT(tag, dst) M_F(tag, (dst) = strtoul(__val, NULL, 0) )
-#define M_STR(tag, dst) M_F(tag, ast_copy_string(dst, __val, sizeof(dst)))
-
-/*
- * The following parameters are used in the driver:
- *
- * FRAME_SIZE the size of an audio frame, in samples.
- * 160 is used almost universally, so you should not change it.
- *
- * FRAGS the argument for the SETFRAGMENT ioctl.
- * Overridden by the 'frags' parameter in oss.conf
- *
- * Bits 0-7 are the base-2 log of the device's block size,
- * bits 16-31 are the number of blocks in the driver's queue.
- * There are a lot of differences in the way this parameter
- * is supported by different drivers, so you may need to
- * experiment a bit with the value.
- * A good default for linux is 30 blocks of 64 bytes, which
- * results in 6 frames of 320 bytes (160 samples).
- * FreeBSD works decently with blocks of 256 or 512 bytes,
- * leaving the number unspecified.
- * Note that this only refers to the device buffer size,
- * this module will then try to keep the lenght of audio
- * buffered within small constraints.
- *
- * QUEUE_SIZE The max number of blocks actually allowed in the device
- * driver's buffer, irrespective of the available number.
- * Overridden by the 'queuesize' parameter in oss.conf
- *
- * Should be >=2, and at most as large as the hw queue above
- * (otherwise it will never be full).
- */
-
-#define FRAME_SIZE 160
-#define QUEUE_SIZE 10
-
-#if defined(__FreeBSD__)
-#define FRAGS 0x8
-#else
-#define FRAGS ( ( (6 * 5) << 16 ) | 0x6 )
-#endif
-
-/*
- * XXX text message sizes are probably 256 chars, but i am
- * not sure if there is a suitable definition anywhere.
- */
-#define TEXT_SIZE 256
-
-#if 0
-#define TRYOPEN 1 /* try to open on startup */
-#endif
-#define O_CLOSE 0x444 /* special 'close' mode for device */
-/* Which device to use */
-#if defined( __OpenBSD__ ) || defined( __NetBSD__ )
-#define DEV_DSP "/dev/audio"
-#else
-#define DEV_DSP "/dev/dsp"
-#endif
-
-#ifndef MIN
-#define MIN(a,b) ((a) < (b) ? (a) : (b))
-#endif
-#ifndef MAX
-#define MAX(a,b) ((a) > (b) ? (a) : (b))
-#endif
-
-static char *config = "oss.conf"; /* default config file */
-
-static int oss_debug;
-
-/*
- * Each sound is made of 'datalen' samples of sound, repeated as needed to
- * generate 'samplen' samples of data, then followed by 'silencelen' samples
- * of silence. The loop is repeated if 'repeat' is set.
- */
-struct sound {
- int ind;
- char *desc;
- short *data;
- int datalen;
- int samplen;
- int silencelen;
- int repeat;
-};
-
-static struct sound sounds[] = {
- { AST_CONTROL_RINGING, "RINGING", ringtone, sizeof(ringtone)/2, 16000, 32000, 1 },
- { AST_CONTROL_BUSY, "BUSY", busy, sizeof(busy)/2, 4000, 4000, 1 },
- { AST_CONTROL_CONGESTION, "CONGESTION", busy, sizeof(busy)/2, 2000, 2000, 1 },
- { AST_CONTROL_RING, "RING10", ring10, sizeof(ring10)/2, 16000, 32000, 1 },
- { AST_CONTROL_ANSWER, "ANSWER", answer, sizeof(answer)/2, 2200, 0, 0 },
- { -1, NULL, 0, 0, 0, 0 }, /* end marker */
-};
-
-
-/*
- * descriptor for one of our channels.
- * There is one used for 'default' values (from the [general] entry in
- * the configuration file), and then one instance for each device
- * (the default is cloned from [general], others are only created
- * if the relevant section exists).
- */
-struct chan_oss_pvt {
- struct chan_oss_pvt *next;
-
- char *name;
- /*
- * cursound indicates which in struct sound we play. -1 means nothing,
- * any other value is a valid sound, in which case sampsent indicates
- * the next sample to send in [0..samplen + silencelen]
- * nosound is set to disable the audio data from the channel
- * (so we can play the tones etc.).
- */
- int sndcmd[2]; /* Sound command pipe */
- int cursound; /* index of sound to send */
- int sampsent; /* # of sound samples sent */
- int nosound; /* set to block audio from the PBX */
-
- int total_blocks; /* total blocks in the output device */
- int sounddev;
- enum { M_UNSET, M_FULL, M_READ, M_WRITE } duplex;
- int autoanswer;
- int autohangup;
- int hookstate;
- char *mixer_cmd; /* initial command to issue to the mixer */
- unsigned int queuesize; /* max fragments in queue */
- unsigned int frags; /* parameter for SETFRAGMENT */
-
- int warned; /* various flags used for warnings */
-#define WARN_used_blocks 1
-#define WARN_speed 2
-#define WARN_frag 4
- int w_errors; /* overfull in the write path */
- struct timeval lastopen;
-
- int overridecontext;
- int mute;
-
- /* boost support. BOOST_SCALE * 10 ^(BOOST_MAX/20) must
- * be representable in 16 bits to avoid overflows.
- */
-#define BOOST_SCALE (1<<9)
-#define BOOST_MAX 40 /* slightly less than 7 bits */
- int boost; /* input boost, scaled by BOOST_SCALE */
- char device[64]; /* device to open */
-
- pthread_t sthread;
-
- struct ast_channel *owner;
- char ext[AST_MAX_EXTENSION];
- char ctx[AST_MAX_CONTEXT];
- char language[MAX_LANGUAGE];
- char cid_name[256]; /*XXX */
- char cid_num[256]; /*XXX */
- char mohinterpret[MAX_MUSICCLASS];
-
- /* buffers used in oss_write */
- char oss_write_buf[FRAME_SIZE * 2];
- int oss_write_dst;
- /* buffers used in oss_read - AST_FRIENDLY_OFFSET space for headers
- * plus enough room for a full frame
- */
- char oss_read_buf[FRAME_SIZE * 2 + AST_FRIENDLY_OFFSET];
- int readpos; /* read position above */
- struct ast_frame read_f; /* returned by oss_read */
-};
-
-static struct chan_oss_pvt oss_default = {
- .cursound = -1,
- .sounddev = -1,
- .duplex = M_UNSET, /* XXX check this */
- .autoanswer = 1,
- .autohangup = 1,
- .queuesize = QUEUE_SIZE,
- .frags = FRAGS,
- .ext = "s",
- .ctx = "default",
- .readpos = AST_FRIENDLY_OFFSET, /* start here on reads */
- .lastopen = { 0, 0 },
- .boost = BOOST_SCALE,
-};
-
-static char *oss_active; /* the active device */
-
-static int setformat(struct chan_oss_pvt *o, int mode);
-
-static struct ast_channel *oss_request(const char *type, int format, void *data
-, int *cause);
-static int oss_digit_begin(struct ast_channel *c, char digit);
-static int oss_digit_end(struct ast_channel *c, char digit, unsigned int duration);
-static int oss_text(struct ast_channel *c, const char *text);
-static int oss_hangup(struct ast_channel *c);
-static int oss_answer(struct ast_channel *c);
-static struct ast_frame *oss_read(struct ast_channel *chan);
-static int oss_call(struct ast_channel *c, char *dest, int timeout);
-static int oss_write(struct ast_channel *chan, struct ast_frame *f);
-static int oss_indicate(struct ast_channel *chan, int cond, const void *data, size_t datalen);
-static int oss_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
-static char tdesc[] = "OSS Console Channel Driver";
-
-static const struct ast_channel_tech oss_tech = {
- .type = "Console",
- .description = tdesc,
- .capabilities = AST_FORMAT_SLINEAR,
- .requester = oss_request,
- .send_digit_begin = oss_digit_begin,
- .send_digit_end = oss_digit_end,
- .send_text = oss_text,
- .hangup = oss_hangup,
- .answer = oss_answer,
- .read = oss_read,
- .call = oss_call,
- .write = oss_write,
- .indicate = oss_indicate,
- .fixup = oss_fixup,
-};
-
-/*
- * returns a pointer to the descriptor with the given name
- */
-static struct chan_oss_pvt *find_desc(char *dev)
-{
- struct chan_oss_pvt *o = NULL;
-
- if (!dev)
- ast_log(LOG_WARNING, "null dev\n");
-
- for (o = oss_default.next; o && o->name && dev && strcmp(o->name, dev) != 0; o = o->next);
-
- if (!o)
- ast_log(LOG_WARNING, "could not find <%s>\n", dev ? dev : "--no-device--");
-
- return o;
-}
-
-/*
- * split a string in extension-context, returns pointers to malloc'ed
- * strings.
- * If we do not have 'overridecontext' then the last @ is considered as
- * a context separator, and the context is overridden.
- * This is usually not very necessary as you can play with the dialplan,
- * and it is nice not to need it because you have '@' in SIP addresses.
- * Return value is the buffer address.
- */
-static char *ast_ext_ctx(const char *src, char **ext, char **ctx)
-{
- struct chan_oss_pvt *o = find_desc(oss_active);
-
- if (ext == NULL || ctx == NULL)
- return NULL; /* error */
-
- *ext = *ctx = NULL;
-
- if (src && *src != '\0')
- *ext = ast_strdup(src);
-
- if (*ext == NULL)
- return NULL;
-
- if (!o->overridecontext) {
- /* parse from the right */
- *ctx = strrchr(*ext, '@');
- if (*ctx)
- *(*ctx)++ = '\0';
- }
-
- return *ext;
-}
-
-/*
- * Returns the number of blocks used in the audio output channel
- */
-static int used_blocks(struct chan_oss_pvt *o)
-{
- struct audio_buf_info info;
-
- if (ioctl(o->sounddev, SNDCTL_DSP_GETOSPACE, &info)) {
- if (!(o->warned & WARN_used_blocks)) {
- ast_log(LOG_WARNING, "Error reading output space\n");
- o->warned |= WARN_used_blocks;
- }
- return 1;
- }
-
- if (o->total_blocks == 0) {
- if (0) /* debugging */
- ast_log(LOG_WARNING, "fragtotal %d size %d avail %d\n", info.fragstotal, info.fragsize, info.fragments);
- o->total_blocks = info.fragments;
- }
-
- return o->total_blocks - info.fragments;
-}
-
-/* Write an exactly FRAME_SIZE sized frame */
-static int soundcard_writeframe(struct chan_oss_pvt *o, short *data)
-{
- int res;
-
- if (o->sounddev < 0)
- setformat(o, O_RDWR);
- if (o->sounddev < 0)
- return 0; /* not fatal */
- /*
- * Nothing complex to manage the audio device queue.
- * If the buffer is full just drop the extra, otherwise write.
- * XXX in some cases it might be useful to write anyways after
- * a number of failures, to restart the output chain.
- */
- res = used_blocks(o);
- if (res > o->queuesize) { /* no room to write a block */
- if (o->w_errors++ == 0 && (oss_debug & 0x4))
- ast_log(LOG_WARNING, "write: used %d blocks (%d)\n", res, o->w_errors);
- return 0;
- }
- o->w_errors = 0;
- return write(o->sounddev, ((void *) data), FRAME_SIZE * 2);
-}
-
-/*
- * Handler for 'sound writable' events from the sound thread.
- * Builds a frame from the high level description of the sounds,
- * and passes it to the audio device.
- * The actual sound is made of 1 or more sequences of sound samples
- * (s->datalen, repeated to make s->samplen samples) followed by
- * s->silencelen samples of silence. The position in the sequence is stored
- * in o->sampsent, which goes between 0 .. s->samplen+s->silencelen.
- * In case we fail to write a frame, don't update o->sampsent.
- */
-static void send_sound(struct chan_oss_pvt *o)
-{
- short myframe[FRAME_SIZE];
- int ofs, l, start;
- int l_sampsent = o->sampsent;
- struct sound *s;
-
- if (o->cursound < 0) /* no sound to send */
- return;
-
- s = &sounds[o->cursound];
-
- for (ofs = 0; ofs < FRAME_SIZE; ofs += l) {
- l = s->samplen - l_sampsent; /* # of available samples */
- if (l > 0) {
- start = l_sampsent % s->datalen; /* source offset */
- if (l > FRAME_SIZE - ofs) /* don't overflow the frame */
- l = FRAME_SIZE - ofs;
- if (l > s->datalen - start) /* don't overflow the source */
- l = s->datalen - start;
- bcopy(s->data + start, myframe + ofs, l * 2);
- if (0)
- ast_log(LOG_WARNING, "send_sound sound %d/%d of %d into %d\n", l_sampsent, l, s->samplen, ofs);
- l_sampsent += l;
- } else { /* end of samples, maybe some silence */
- static const short silence[FRAME_SIZE] = { 0, };
-
- l += s->silencelen;
- if (l > 0) {
- if (l > FRAME_SIZE - ofs)
- l = FRAME_SIZE - ofs;
- bcopy(silence, myframe + ofs, l * 2);
- l_sampsent += l;
- } else { /* silence is over, restart sound if loop */
- if (s->repeat == 0) { /* last block */
- o->cursound = -1;
- o->nosound = 0; /* allow audio data */
- if (ofs < FRAME_SIZE) /* pad with silence */
- bcopy(silence, myframe + ofs, (FRAME_SIZE - ofs) * 2);
- }
- l_sampsent = 0;
- }
- }
- }
- l = soundcard_writeframe(o, myframe);
- if (l > 0)
- o->sampsent = l_sampsent; /* update status */
-}
-
-static void *sound_thread(void *arg)
-{
- char ign[4096];
- struct chan_oss_pvt *o = (struct chan_oss_pvt *) arg;
-
- /*
- * Just in case, kick the driver by trying to read from it.
- * Ignore errors - this read is almost guaranteed to fail.
- */
- if (read(o->sounddev, ign, sizeof(ign)) < 0) {
- }
- for (;;) {
- fd_set rfds, wfds;
- int maxfd, res;
-
- FD_ZERO(&rfds);
- FD_ZERO(&wfds);
- FD_SET(o->sndcmd[0], &rfds);
- maxfd = o->sndcmd[0]; /* pipe from the main process */
- if (o->cursound > -1 && o->sounddev < 0)
- setformat(o, O_RDWR); /* need the channel, try to reopen */
- else if (o->cursound == -1 && o->owner == NULL)
- setformat(o, O_CLOSE); /* can close */
- if (o->sounddev > -1) {
- if (!o->owner) { /* no one owns the audio, so we must drain it */
- FD_SET(o->sounddev, &rfds);
- maxfd = MAX(o->sounddev, maxfd);
- }
- if (o->cursound > -1) {
- FD_SET(o->sounddev, &wfds);
- maxfd = MAX(o->sounddev, maxfd);
- }
- }
- /* ast_select emulates linux behaviour in terms of timeout handling */
- res = ast_select(maxfd + 1, &rfds, &wfds, NULL, NULL);
- if (res < 1) {
- ast_log(LOG_WARNING, "select failed: %s\n", strerror(errno));
- sleep(1);
- continue;
- }
- if (FD_ISSET(o->sndcmd[0], &rfds)) {
- /* read which sound to play from the pipe */
- int i, what = -1;
-
- if (read(o->sndcmd[0], &what, sizeof(what)) != sizeof(what)) {
- ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
- continue;
- }
- for (i = 0; sounds[i].ind != -1; i++) {
- if (sounds[i].ind == what) {
- o->cursound = i;
- o->sampsent = 0;
- o->nosound = 1; /* block audio from pbx */
- break;
- }
- }
- if (sounds[i].ind == -1)
- ast_log(LOG_WARNING, "invalid sound index: %d\n", what);
- }
- if (o->sounddev > -1) {
- if (FD_ISSET(o->sounddev, &rfds)) /* read and ignore errors */
- if (read(o->sounddev, ign, sizeof(ign)) < 0) {
- }
- if (FD_ISSET(o->sounddev, &wfds))
- send_sound(o);
- }
- }
- return NULL; /* Never reached */
-}
-
-/*
- * reset and close the device if opened,
- * then open and initialize it in the desired mode,
- * trigger reads and writes so we can start using it.
- */
-static int setformat(struct chan_oss_pvt *o, int mode)
-{
- int fmt, desired, res, fd;
-
- if (o->sounddev >= 0) {
- ioctl(o->sounddev, SNDCTL_DSP_RESET, 0);
- close(o->sounddev);
- o->duplex = M_UNSET;
- o->sounddev = -1;
- }
- if (mode == O_CLOSE) /* we are done */
- return 0;
- if (ast_tvdiff_ms(ast_tvnow(), o->lastopen) < 1000)
- return -1; /* don't open too often */
- o->lastopen = ast_tvnow();
- fd = o->sounddev = open(o->device, mode | O_NONBLOCK);
- if (fd < 0) {
- ast_log(LOG_WARNING, "Unable to re-open DSP device %s: %s\n", o->device, strerror(errno));
- return -1;
- }
- if (o->owner)
- o->owner->fds[0] = fd;
-
-#if __BYTE_ORDER == __LITTLE_ENDIAN
- fmt = AFMT_S16_LE;
-#else
- fmt = AFMT_S16_BE;
-#endif
- res = ioctl(fd, SNDCTL_DSP_SETFMT, &fmt);
- if (res < 0) {
- ast_log(LOG_WARNING, "Unable to set format to 16-bit signed\n");
- return -1;
- }
- switch (mode) {
- case O_RDWR:
- res = ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0);
- /* Check to see if duplex set (FreeBSD Bug) */
- res = ioctl(fd, SNDCTL_DSP_GETCAPS, &fmt);
- if (res == 0 && (fmt & DSP_CAP_DUPLEX)) {
- if (option_verbose > 1)
- ast_verbose(VERBOSE_PREFIX_2 "Console is full duplex\n");
- o->duplex = M_FULL;
- };
- break;
- case O_WRONLY:
- o->duplex = M_WRITE;
- break;
- case O_RDONLY:
- o->duplex = M_READ;
- break;
- }
-
- fmt = 0;
- res = ioctl(fd, SNDCTL_DSP_STEREO, &fmt);
- if (res < 0) {
- ast_log(LOG_WARNING, "Failed to set audio device to mono\n");
- return -1;
- }
- fmt = desired = DEFAULT_SAMPLE_RATE; /* 8000 Hz desired */
- res = ioctl(fd, SNDCTL_DSP_SPEED, &fmt);
-
- if (res < 0) {
- ast_log(LOG_WARNING, "Failed to set audio device to mono\n");
- return -1;
- }
- if (fmt != desired) {
- if (!(o->warned & WARN_speed)) {
- ast_log(LOG_WARNING,
- "Requested %d Hz, got %d Hz -- sound may be choppy\n",
- desired, fmt);
- o->warned |= WARN_speed;
- }
- }
- /*
- * on Freebsd, SETFRAGMENT does not work very well on some cards.
- * Default to use 256 bytes, let the user override
- */
- if (o->frags) {
- fmt = o->frags;
- res = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &fmt);
- if (res < 0) {
- if (!(o->warned & WARN_frag)) {
- ast_log(LOG_WARNING,
- "Unable to set fragment size -- sound may be choppy\n");
- o->warned |= WARN_frag;
- }
- }
- }
- /* on some cards, we need SNDCTL_DSP_SETTRIGGER to start outputting */
- res = PCM_ENABLE_INPUT | PCM_ENABLE_OUTPUT;
- res = ioctl(fd, SNDCTL_DSP_SETTRIGGER, &res);
- /* it may fail if we are in half duplex, never mind */
- return 0;
-}
-
-/*
- * some of the standard methods supported by channels.
- */
-static int oss_digit_begin(struct ast_channel *c, char digit)
-{
- return 0;
-}
-
-static int oss_digit_end(struct ast_channel *c, char digit, unsigned int duration)
-{
- /* no better use for received digits than print them */
- ast_verbose(" << Console Received digit %c of duration %u ms >> \n",
- digit, duration);
- return 0;
-}
-
-static int oss_text(struct ast_channel *c, const char *text)
-{
- /* print received messages */
- ast_verbose(" << Console Received text %s >> \n", text);
- return 0;
-}
-
-/* Play ringtone 'x' on device 'o' */
-static void ring(struct chan_oss_pvt *o, int x)
-{
- if (write(o->sndcmd[1], &x, sizeof(x)) < 0) {
- ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
- }
-}
-
-
-/*
- * handler for incoming calls. Either autoanswer, or start ringing
- */
-static int oss_call(struct ast_channel *c, char *dest, int timeout)
-{
- struct chan_oss_pvt *o = c->tech_pvt;
- struct ast_frame f = { 0, };
-
- ast_verbose(" << Call to device '%s' dnid '%s' rdnis '%s' on console from '%s' <%s> >>\n", dest, c->cid.cid_dnid, c->cid.cid_rdnis, c->cid.cid_name, c->cid.cid_num);
- if (o->autoanswer) {
- ast_verbose(" << Auto-answered >> \n");
- f.frametype = AST_FRAME_CONTROL;
- f.subclass = AST_CONTROL_ANSWER;
- ast_queue_frame(c, &f);
- } else {
- ast_verbose("<< Type 'answer' to answer, or use 'autoanswer' for future calls >> \n");
- f.frametype = AST_FRAME_CONTROL;
- f.subclass = AST_CONTROL_RINGING;
- ast_queue_frame(c, &f);
- ring(o, AST_CONTROL_RING);
- }
- return 0;
-}
-
-/*
- * remote side answered the phone
- */
-static int oss_answer(struct ast_channel *c)
-{
- struct chan_oss_pvt *o = c->tech_pvt;
-
- ast_verbose(" << Console call has been answered >> \n");
-#if 0
- /* play an answer tone (XXX do we really need it ?) */
- ring(o, AST_CONTROL_ANSWER);
-#endif
- ast_setstate(c, AST_STATE_UP);
- o->cursound = -1;
- o->nosound = 0;
- return 0;
-}
-
-static int oss_hangup(struct ast_channel *c)
-{
- struct chan_oss_pvt *o = c->tech_pvt;
-
- o->cursound = -1;
- o->nosound = 0;
- c->tech_pvt = NULL;
- o->owner = NULL;
- ast_verbose(" << Hangup on console >> \n");
- ast_module_unref(ast_module_info->self);
- if (o->hookstate) {
- if (o->autoanswer || o->autohangup) {
- /* Assume auto-hangup too */
- o->hookstate = 0;
- setformat(o, O_CLOSE);
- } else {
- /* Make congestion noise */
- ring(o, AST_CONTROL_CONGESTION);
- }
- }
- return 0;
-}
-
-/* used for data coming from the network */
-static int oss_write(struct ast_channel *c, struct ast_frame *f)
-{
- int src;
- struct chan_oss_pvt *o = c->tech_pvt;
-
- /* Immediately return if no sound is enabled */
- if (o->nosound)
- return 0;
- /* Stop any currently playing sound */
- o->cursound = -1;
- /*
- * we could receive a block which is not a multiple of our
- * FRAME_SIZE, so buffer it locally and write to the device
- * in FRAME_SIZE chunks.
- * Keep the residue stored for future use.
- */
- src = 0; /* read position into f->data */
- while (src < f->datalen) {
- /* Compute spare room in the buffer */
- int l = sizeof(o->oss_write_buf) - o->oss_write_dst;
-
- if (f->datalen - src >= l) { /* enough to fill a frame */
- memcpy(o->oss_write_buf + o->oss_write_dst, f->data + src, l);
- soundcard_writeframe(o, (short *) o->oss_write_buf);
- src += l;
- o->oss_write_dst = 0;
- } else { /* copy residue */
- l = f->datalen - src;
- memcpy(o->oss_write_buf + o->oss_write_dst, f->data + src, l);
- src += l; /* but really, we are done */
- o->oss_write_dst += l;
- }
- }
- return 0;
-}
-
-static struct ast_frame *oss_read(struct ast_channel *c)
-{
- int res;
- struct chan_oss_pvt *o = c->tech_pvt;
- struct ast_frame *f = &o->read_f;
-
- /* XXX can be simplified returning &ast_null_frame */
- /* prepare a NULL frame in case we don't have enough data to return */
- bzero(f, sizeof(struct ast_frame));
- f->frametype = AST_FRAME_NULL;
- f->src = oss_tech.type;
-
- res = read(o->sounddev, o->oss_read_buf + o->readpos, sizeof(o->oss_read_buf) - o->readpos);
- if (res < 0) /* audio data not ready, return a NULL frame */
- return f;
-
- o->readpos += res;
- if (o->readpos < sizeof(o->oss_read_buf)) /* not enough samples */
- return f;
-
- if (o->mute)
- return f;
-
- o->readpos = AST_FRIENDLY_OFFSET; /* reset read pointer for next frame */
- if (c->_state != AST_STATE_UP) /* drop data if frame is not up */
- return f;
- /* ok we can build and deliver the frame to the caller */
- f->frametype = AST_FRAME_VOICE;
- f->subclass = AST_FORMAT_SLINEAR;
- f->samples = FRAME_SIZE;
- f->datalen = FRAME_SIZE * 2;
- f->data = o->oss_read_buf + AST_FRIENDLY_OFFSET;
- if (o->boost != BOOST_SCALE) { /* scale and clip values */
- int i, x;
- int16_t *p = (int16_t *) f->data;
- for (i = 0; i < f->samples; i++) {
- x = (p[i] * o->boost) / BOOST_SCALE;
- if (x > 32767)
- x = 32767;
- else if (x < -32768)
- x = -32768;
- p[i] = x;
- }
- }
-
- f->offset = AST_FRIENDLY_OFFSET;
- return f;
-}
-
-static int oss_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
-{
- struct chan_oss_pvt *o = newchan->tech_pvt;
- o->owner = newchan;
- return 0;
-}
-
-static int oss_indicate(struct ast_channel *c, int cond, const void *data, size_t datalen)
-{
- struct chan_oss_pvt *o = c->tech_pvt;
- int res = -1;
-
- switch (cond) {
- case AST_CONTROL_BUSY:
- case AST_CONTROL_CONGESTION:
- case AST_CONTROL_RINGING:
- res = cond;
- break;
-
- case -1:
- o->cursound = -1;
- o->nosound = 0; /* when cursound is -1 nosound must be 0 */
- return 0;
-
- case AST_CONTROL_VIDUPDATE:
- res = -1;
- break;
- case AST_CONTROL_HOLD:
- ast_verbose(" << Console Has Been Placed on Hold >> \n");
- ast_moh_start(c, data, o->mohinterpret);
- break;
- case AST_CONTROL_UNHOLD:
- ast_verbose(" << Console Has Been Retrieved from Hold >> \n");
- ast_moh_stop(c);
- break;
- case AST_CONTROL_SRCUPDATE:
- break;
- default:
- ast_log(LOG_WARNING, "Don't know how to display condition %d on %s\n", cond, c->name);
- return -1;
- }
-
- if (res > -1)
- ring(o, res);
-
- return 0;
-}
-
-/*
- * allocate a new channel.
- */
-static struct ast_channel *oss_new(struct chan_oss_pvt *o, char *ext, char *ctx, int state)
-{
- struct ast_channel *c;
-
- c = ast_channel_alloc(1, state, o->cid_num, o->cid_name, "", ext, ctx, 0, "Console/%s", o->device + 5);
- if (c == NULL)
- return NULL;
- c->tech = &oss_tech;
- if (o->sounddev < 0)
- setformat(o, O_RDWR);
- c->fds[0] = o->sounddev; /* -1 if device closed, override later */
- c->nativeformats = AST_FORMAT_SLINEAR;
- c->readformat = AST_FORMAT_SLINEAR;
- c->writeformat = AST_FORMAT_SLINEAR;
- c->tech_pvt = o;
-
- if (!ast_strlen_zero(o->language))
- ast_string_field_set(c, language, o->language);
- /* Don't use ast_set_callerid() here because it will
- * generate a needless NewCallerID event */
- c->cid.cid_ani = ast_strdup(o->cid_num);
- if (!ast_strlen_zero(ext))
- c->cid.cid_dnid = ast_strdup(ext);
-
- o->owner = c;
- ast_module_ref(ast_module_info->self);
- ast_jb_configure(c, &global_jbconf);
- if (state != AST_STATE_DOWN) {
- if (ast_pbx_start(c)) {
- ast_log(LOG_WARNING, "Unable to start PBX on %s\n", c->name);
- ast_hangup(c);
- o->owner = c = NULL;
- /* XXX what about the channel itself ? */
- /* XXX what about usecnt ? */
- }
- }
-
- return c;
-}
-
-static struct ast_channel *oss_request(const char *type, int format, void *data, int *cause)
-{
- struct ast_channel *c;
- struct chan_oss_pvt *o = find_desc(data);
-
- ast_log(LOG_WARNING, "oss_request ty <%s> data 0x%p <%s>\n", type, data, (char *) data);
- if (o == NULL) {
- ast_log(LOG_NOTICE, "Device %s not found\n", (char *) data);
- /* XXX we could default to 'dsp' perhaps ? */
- return NULL;
- }
- if ((format & AST_FORMAT_SLINEAR) == 0) {
- ast_log(LOG_NOTICE, "Format 0x%x unsupported\n", format);
- return NULL;
- }
- if (o->owner) {
- ast_log(LOG_NOTICE, "Already have a call (chan %p) on the OSS channel\n", o->owner);
- *cause = AST_CAUSE_BUSY;
- return NULL;
- }
- c = oss_new(o, NULL, NULL, AST_STATE_DOWN);
- if (c == NULL) {
- ast_log(LOG_WARNING, "Unable to create new OSS channel\n");
- return NULL;
- }
- return c;
-}
-
-static int console_autoanswer_deprecated(int fd, int argc, char *argv[])
-{
- struct chan_oss_pvt *o = find_desc(oss_active);
-
- if (argc == 1) {
- ast_cli(fd, "Auto answer is %s.\n", o->autoanswer ? "on" : "off");
- return RESULT_SUCCESS;
- }
- if (argc != 2)
- return RESULT_SHOWUSAGE;
- if (o == NULL) {
- ast_log(LOG_WARNING, "Cannot find device %s (should not happen!)\n", oss_active);
- return RESULT_FAILURE;
- }
- if (!strcasecmp(argv[1], "on"))
- o->autoanswer = -1;
- else if (!strcasecmp(argv[1], "off"))
- o->autoanswer = 0;
- else
- return RESULT_SHOWUSAGE;
- return RESULT_SUCCESS;
-}
-
-static int console_autoanswer(int fd, int argc, char *argv[])
-{
- struct chan_oss_pvt *o = find_desc(oss_active);
-
- if (argc == 2) {
- ast_cli(fd, "Auto answer is %s.\n", o->autoanswer ? "on" : "off");
- return RESULT_SUCCESS;
- }
- if (argc != 3)
- return RESULT_SHOWUSAGE;
- if (o == NULL) {
- ast_log(LOG_WARNING, "Cannot find device %s (should not happen!)\n",
- oss_active);
- return RESULT_FAILURE;
- }
- if (!strcasecmp(argv[2], "on"))
- o->autoanswer = -1;
- else if (!strcasecmp(argv[2], "off"))
- o->autoanswer = 0;
- else
- return RESULT_SHOWUSAGE;
- return RESULT_SUCCESS;
-}
-
-static char *autoanswer_complete_deprecated(const char *line, const char *word, int pos, int state)
-{
- static char *choices[] = { "on", "off", NULL };
-
- return (pos != 2) ? NULL : ast_cli_complete(word, choices, state);
-}
-
-static char *autoanswer_complete(const char *line, const char *word, int pos, int state)
-{
- static char *choices[] = { "on", "off", NULL };
-
- return (pos != 3) ? NULL : ast_cli_complete(word, choices, state);
-}
-
-static char autoanswer_usage[] =
- "Usage: console autoanswer [on|off]\n"
- " Enables or disables autoanswer feature. If used without\n"
- " argument, displays the current on/off status of autoanswer.\n"
- " The default value of autoanswer is in 'oss.conf'.\n";
-
-/*
- * answer command from the console
- */
-static int console_answer_deprecated(int fd, int argc, char *argv[])
-{
- struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
- struct chan_oss_pvt *o = find_desc(oss_active);
-
- if (argc != 1)
- return RESULT_SHOWUSAGE;
- if (!o->owner) {
- ast_cli(fd, "No one is calling us\n");
- return RESULT_FAILURE;
- }
- o->hookstate = 1;
- o->cursound = -1;
- o->nosound = 0;
- ast_queue_frame(o->owner, &f);
-#if 0
- /* XXX do we really need it ? considering we shut down immediately... */
- ring(o, AST_CONTROL_ANSWER);
-#endif
- return RESULT_SUCCESS;
-}
-
-static int console_answer(int fd, int argc, char *argv[])
-{
- struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
- struct chan_oss_pvt *o = find_desc(oss_active);
-
- if (argc != 2)
- return RESULT_SHOWUSAGE;
- if (!o->owner) {
- ast_cli(fd, "No one is calling us\n");
- return RESULT_FAILURE;
- }
- o->hookstate = 1;
- o->cursound = -1;
- o->nosound = 0;
- ast_queue_frame(o->owner, &f);
-#if 0
- /* XXX do we really need it ? considering we shut down immediately... */
- ring(o, AST_CONTROL_ANSWER);
-#endif
- return RESULT_SUCCESS;
-}
-
-static char answer_usage[] =
- "Usage: console answer\n"
- " Answers an incoming call on the console (OSS) channel.\n";
-
-/*
- * concatenate all arguments into a single string. argv is NULL-terminated
- * so we can use it right away
- */
-static int console_sendtext_deprecated(int fd, int argc, char *argv[])
-{
- struct chan_oss_pvt *o = find_desc(oss_active);
- char buf[TEXT_SIZE];
-
- if (argc < 2)
- return RESULT_SHOWUSAGE;
- if (!o->owner) {
- ast_cli(fd, "Not in a call\n");
- return RESULT_FAILURE;
- }
- ast_join(buf, sizeof(buf) - 1, argv + 2);
- if (!ast_strlen_zero(buf)) {
- struct ast_frame f = { 0, };
- int i = strlen(buf);
- buf[i] = '\n';
- f.frametype = AST_FRAME_TEXT;
- f.subclass = 0;
- f.data = buf;
- f.datalen = i + 1;
- ast_queue_frame(o->owner, &f);
- }
- return RESULT_SUCCESS;
-}
-
-static int console_sendtext(int fd, int argc, char *argv[])
-{
- struct chan_oss_pvt *o = find_desc(oss_active);
- char buf[TEXT_SIZE];
-
- if (argc < 3)
- return RESULT_SHOWUSAGE;
- if (!o->owner) {
- ast_cli(fd, "Not in a call\n");
- return RESULT_FAILURE;
- }
- ast_join(buf, sizeof(buf) - 1, argv + 3);
- if (!ast_strlen_zero(buf)) {
- struct ast_frame f = { 0, };
- int i = strlen(buf);
- buf[i] = '\n';
- f.frametype = AST_FRAME_TEXT;
- f.subclass = 0;
- f.data = buf;
- f.datalen = i + 1;
- ast_queue_frame(o->owner, &f);
- }
- return RESULT_SUCCESS;
-}
-
-static char sendtext_usage[] =
- "Usage: console send text <message>\n"
- " Sends a text message for display on the remote terminal.\n";
-
-static int console_hangup_deprecated(int fd, int argc, char *argv[])
-{
- struct chan_oss_pvt *o = find_desc(oss_active);
-
- if (argc != 1)
- return RESULT_SHOWUSAGE;
- o->cursound = -1;
- o->nosound = 0;
- if (!o->owner && !o->hookstate) { /* XXX maybe only one ? */
- ast_cli(fd, "No call to hang up\n");
- return RESULT_FAILURE;
- }
- o->hookstate = 0;
- if (o->owner)
- ast_queue_hangup(o->owner);
- setformat(o, O_CLOSE);
- return RESULT_SUCCESS;
-}
-
-static int console_hangup(int fd, int argc, char *argv[])
-{
- struct chan_oss_pvt *o = find_desc(oss_active);
-
- if (argc != 2)
- return RESULT_SHOWUSAGE;
- o->cursound = -1;
- o->nosound = 0;
- if (!o->owner && !o->hookstate) { /* XXX maybe only one ? */
- ast_cli(fd, "No call to hang up\n");
- return RESULT_FAILURE;
- }
- o->hookstate = 0;
- if (o->owner)
- ast_queue_hangup(o->owner);
- setformat(o, O_CLOSE);
- return RESULT_SUCCESS;
-}
-
-static char hangup_usage[] =
- "Usage: console hangup\n"
- " Hangs up any call currently placed on the console.\n";
-
-static int console_flash_deprecated(int fd, int argc, char *argv[])
-{
- struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_FLASH };
- struct chan_oss_pvt *o = find_desc(oss_active);
-
- if (argc != 1)
- return RESULT_SHOWUSAGE;
- o->cursound = -1;
- o->nosound = 0; /* when cursound is -1 nosound must be 0 */
- if (!o->owner) { /* XXX maybe !o->hookstate too ? */
- ast_cli(fd, "No call to flash\n");
- return RESULT_FAILURE;
- }
- o->hookstate = 0;
- if (o->owner) /* XXX must be true, right ? */
- ast_queue_frame(o->owner, &f);
- return RESULT_SUCCESS;
-}
-
-static int console_flash(int fd, int argc, char *argv[])
-{
- struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_FLASH };
- struct chan_oss_pvt *o = find_desc(oss_active);
-
- if (argc != 2)
- return RESULT_SHOWUSAGE;
- o->cursound = -1;
- o->nosound = 0; /* when cursound is -1 nosound must be 0 */
- if (!o->owner) { /* XXX maybe !o->hookstate too ? */
- ast_cli(fd, "No call to flash\n");
- return RESULT_FAILURE;
- }
- o->hookstate = 0;
- if (o->owner) /* XXX must be true, right ? */
- ast_queue_frame(o->owner, &f);
- return RESULT_SUCCESS;
-}
-
-static char flash_usage[] =
- "Usage: console flash\n"
- " Flashes the call currently placed on the console.\n";
-
-static int console_dial_deprecated(int fd, int argc, char *argv[])
-{
- char *s = NULL, *mye = NULL, *myc = NULL;
- struct chan_oss_pvt *o = find_desc(oss_active);
-
- if (argc != 1 && argc != 2)
- return RESULT_SHOWUSAGE;
- if (o->owner) { /* already in a call */
- int i;
- struct ast_frame f = { AST_FRAME_DTMF, 0 };
-
- if (argc == 1) { /* argument is mandatory here */
- ast_cli(fd, "Already in a call. You can only dial digits until you hangup.\n");
- return RESULT_FAILURE;
- }
- s = argv[1];
- /* send the string one char at a time */
- for (i = 0; i < strlen(s); i++) {
- f.subclass = s[i];
- ast_queue_frame(o->owner, &f);
- }
- return RESULT_SUCCESS;
- }
- /* if we have an argument split it into extension and context */
- if (argc == 2)
- s = ast_ext_ctx(argv[1], &mye, &myc);
- /* supply default values if needed */
- if (mye == NULL)
- mye = o->ext;
- if (myc == NULL)
- myc = o->ctx;
- if (ast_exists_extension(NULL, myc, mye, 1, NULL)) {
- o->hookstate = 1;
- oss_new(o, mye, myc, AST_STATE_RINGING);
- } else
- ast_cli(fd, "No such extension '%s' in context '%s'\n", mye, myc);
- if (s)
- free(s);
- return RESULT_SUCCESS;
-}
-
-static int console_dial(int fd, int argc, char *argv[])
-{
- char *s = NULL, *mye = NULL, *myc = NULL;
- struct chan_oss_pvt *o = find_desc(oss_active);
-
- if (argc != 2 && argc != 3)
- return RESULT_SHOWUSAGE;
- if (o->owner) { /* already in a call */
- int i;
- struct ast_frame f = { AST_FRAME_DTMF, 0 };
-
- if (argc == 2) { /* argument is mandatory here */
- ast_cli(fd, "Already in a call. You can only dial digits until you hangup.\n");
- return RESULT_FAILURE;
- }
- s = argv[2];
- /* send the string one char at a time */
- for (i = 0; i < strlen(s); i++) {
- f.subclass = s[i];
- ast_queue_frame(o->owner, &f);
- }
- return RESULT_SUCCESS;
- }
- /* if we have an argument split it into extension and context */
- if (argc == 3)
- s = ast_ext_ctx(argv[2], &mye, &myc);
- /* supply default values if needed */
- if (mye == NULL)
- mye = o->ext;
- if (myc == NULL)
- myc = o->ctx;
- if (ast_exists_extension(NULL, myc, mye, 1, NULL)) {
- o->hookstate = 1;
- oss_new(o, mye, myc, AST_STATE_RINGING);
- } else
- ast_cli(fd, "No such extension '%s' in context '%s'\n", mye, myc);
- if (s)
- free(s);
- return RESULT_SUCCESS;
-}
-
-static char dial_usage[] =
- "Usage: console dial [extension[@context]]\n"
- " Dials a given extension (and context if specified)\n";
-
-static int __console_mute_unmute(int mute)
-{
- struct chan_oss_pvt *o = find_desc(oss_active);
-
- o->mute = mute;
- return RESULT_SUCCESS;
-}
-
-static int console_mute_deprecated(int fd, int argc, char *argv[])
-{
- if (argc != 1)
- return RESULT_SHOWUSAGE;
-
- return __console_mute_unmute(1);
-}
-
-static int console_mute(int fd, int argc, char *argv[])
-{
- if (argc != 2)
- return RESULT_SHOWUSAGE;
-
- return __console_mute_unmute(1);
-}
-
-static char mute_usage[] =
- "Usage: console mute\nMutes the microphone\n";
-
-static int console_unmute_deprecated(int fd, int argc, char *argv[])
-{
- if (argc != 1)
- return RESULT_SHOWUSAGE;
-
- return __console_mute_unmute(0);
-}
-
-static int console_unmute(int fd, int argc, char *argv[])
-{
- if (argc != 2)
- return RESULT_SHOWUSAGE;
-
- return __console_mute_unmute(0);
-}
-
-static char unmute_usage[] =
- "Usage: console unmute\nUnmutes the microphone\n";
-
-static int console_transfer_deprecated(int fd, int argc, char *argv[])
-{
- struct chan_oss_pvt *o = find_desc(oss_active);
- struct ast_channel *b = NULL;
- char *tmp, *ext, *ctx;
-
- if (argc != 2)
- return RESULT_SHOWUSAGE;
- if (o == NULL)
- return RESULT_FAILURE;
- if (o->owner ==NULL || (b = ast_bridged_channel(o->owner)) == NULL) {
- ast_cli(fd, "There is no call to transfer\n");
- return RESULT_SUCCESS;
- }
-
- tmp = ast_ext_ctx(argv[1], &ext, &ctx);
- if (ctx == NULL) /* supply default context if needed */
- ctx = o->owner->context;
- if (!ast_exists_extension(b, ctx, ext, 1, b->cid.cid_num))
- ast_cli(fd, "No such extension exists\n");
- else {
- ast_cli(fd, "Whee, transferring %s to %s@%s.\n",
- b->name, ext, ctx);
- if (ast_async_goto(b, ctx, ext, 1))
- ast_cli(fd, "Failed to transfer :(\n");
- }
- if (tmp)
- free(tmp);
- return RESULT_SUCCESS;
-}
-
-static int console_transfer(int fd, int argc, char *argv[])
-{
- struct chan_oss_pvt *o = find_desc(oss_active);
- struct ast_channel *b = NULL;
- char *tmp, *ext, *ctx;
-
- if (argc != 3)
- return RESULT_SHOWUSAGE;
- if (o == NULL)
- return RESULT_FAILURE;
- if (o->owner == NULL || (b = ast_bridged_channel(o->owner)) == NULL) {
- ast_cli(fd, "There is no call to transfer\n");
- return RESULT_SUCCESS;
- }
-
- tmp = ast_ext_ctx(argv[2], &ext, &ctx);
- if (ctx == NULL) /* supply default context if needed */
- ctx = o->owner->context;
- if (!ast_exists_extension(b, ctx, ext, 1, b->cid.cid_num))
- ast_cli(fd, "No such extension exists\n");
- else {
- ast_cli(fd, "Whee, transferring %s to %s@%s.\n", b->name, ext, ctx);
- if (ast_async_goto(b, ctx, ext, 1))
- ast_cli(fd, "Failed to transfer :(\n");
- }
- if (tmp)
- free(tmp);
- return RESULT_SUCCESS;
-}
-
-static char transfer_usage[] =
- "Usage: console transfer <extension>[@context]\n"
- " Transfers the currently connected call to the given extension (and\n"
- "context if specified)\n";
-
-static int console_active_deprecated(int fd, int argc, char *argv[])
-{
- if (argc == 1)
- ast_cli(fd, "active console is [%s]\n", oss_active);
- else if (argc != 2)
- return RESULT_SHOWUSAGE;
- else {
- struct chan_oss_pvt *o;
- if (strcmp(argv[1], "show") == 0) {
- for (o = oss_default.next; o; o = o->next)
- ast_cli(fd, "device [%s] exists\n", o->name);
- return RESULT_SUCCESS;
- }
- o = find_desc(argv[1]);
- if (o == NULL)
- ast_cli(fd, "No device [%s] exists\n", argv[1]);
- else
- oss_active = o->name;
- }
- return RESULT_SUCCESS;
-}
-
-static int console_active(int fd, int argc, char *argv[])
-{
- if (argc == 2)
- ast_cli(fd, "active console is [%s]\n", oss_active);
- else if (argc != 3)
- return RESULT_SHOWUSAGE;
- else {
- struct chan_oss_pvt *o;
- if (strcmp(argv[2], "show") == 0) {
- for (o = oss_default.next; o; o = o->next)
- ast_cli(fd, "device [%s] exists\n", o->name);
- return RESULT_SUCCESS;
- }
- o = find_desc(argv[2]);
- if (o == NULL)
- ast_cli(fd, "No device [%s] exists\n", argv[2]);
- else
- oss_active = o->name;
- }
- return RESULT_SUCCESS;
-}
-
-static char active_usage[] =
- "Usage: console active [device]\n"
- " If used without a parameter, displays which device is the current\n"
- "console. If a device is specified, the console sound device is changed to\n"
- "the device specified.\n";
-
-/*
- * store the boost factor
- */
-static void store_boost(struct chan_oss_pvt *o, char *s)
-{
- double boost = 0;
- if (sscanf(s, "%lf", &boost) != 1) {
- ast_log(LOG_WARNING, "invalid boost <%s>\n", s);
- return;
- }
- if (boost < -BOOST_MAX) {
- ast_log(LOG_WARNING, "boost %s too small, using %d\n", s, -BOOST_MAX);
- boost = -BOOST_MAX;
- } else if (boost > BOOST_MAX) {
- ast_log(LOG_WARNING, "boost %s too large, using %d\n", s, BOOST_MAX);
- boost = BOOST_MAX;
- }
- boost = exp(log(10) * boost / 20) * BOOST_SCALE;
- o->boost = boost;
- ast_log(LOG_WARNING, "setting boost %s to %d\n", s, o->boost);
-}
-
-static int do_boost(int fd, int argc, char *argv[])
-{
- struct chan_oss_pvt *o = find_desc(oss_active);
-
- if (argc == 2)
- ast_cli(fd, "boost currently %5.1f\n", 20 * log10(((double) o->boost / (double) BOOST_SCALE)));
- else if (argc == 3)
- store_boost(o, argv[2]);
- return RESULT_SUCCESS;
-}
-
-static struct ast_cli_entry cli_oss_answer_deprecated = {
- { "answer", NULL },
- console_answer_deprecated, NULL,
- NULL };
-
-static struct ast_cli_entry cli_oss_hangup_deprecated = {
- { "hangup", NULL },
- console_hangup_deprecated, NULL,
- NULL };
-
-static struct ast_cli_entry cli_oss_flash_deprecated = {
- { "flash", NULL },
- console_flash_deprecated, NULL,
- NULL };
-
-static struct ast_cli_entry cli_oss_dial_deprecated = {
- { "dial", NULL },
- console_dial_deprecated, NULL,
- NULL };
-
-static struct ast_cli_entry cli_oss_mute_deprecated = {
- { "mute", NULL },
- console_mute_deprecated, NULL,
- NULL };
-
-static struct ast_cli_entry cli_oss_unmute_deprecated = {
- { "unmute", NULL },
- console_unmute_deprecated, NULL,
- NULL };
-
-static struct ast_cli_entry cli_oss_transfer_deprecated = {
- { "transfer", NULL },
- console_transfer_deprecated, NULL,
- NULL };
-
-static struct ast_cli_entry cli_oss_send_text_deprecated = {
- { "send", "text", NULL },
- console_sendtext_deprecated, NULL,
- NULL };
-
-static struct ast_cli_entry cli_oss_autoanswer_deprecated = {
- { "autoanswer", NULL },
- console_autoanswer_deprecated, NULL,
- NULL, autoanswer_complete_deprecated };
-
-static struct ast_cli_entry cli_oss_boost_deprecated = {
- { "oss", "boost", NULL },
- do_boost, NULL,
- NULL };
-
-static struct ast_cli_entry cli_oss_active_deprecated = {
- { "console", NULL },
- console_active_deprecated, NULL,
- NULL };
-
-static struct ast_cli_entry cli_oss[] = {
- { { "console", "answer", NULL },
- console_answer, "Answer an incoming console call",
- answer_usage, NULL, &cli_oss_answer_deprecated },
-
- { { "console", "hangup", NULL },
- console_hangup, "Hangup a call on the console",
- hangup_usage, NULL, &cli_oss_hangup_deprecated },
-
- { { "console", "flash", NULL },
- console_flash, "Flash a call on the console",
- flash_usage, NULL, &cli_oss_flash_deprecated },
-
- { { "console", "dial", NULL },
- console_dial, "Dial an extension on the console",
- dial_usage, NULL, &cli_oss_dial_deprecated },
-
- { { "console", "mute", NULL },
- console_mute, "Disable mic input",
- mute_usage, NULL, &cli_oss_mute_deprecated },
-
- { { "console", "unmute", NULL },
- console_unmute, "Enable mic input",
- unmute_usage, NULL, &cli_oss_unmute_deprecated },
-
- { { "console", "transfer", NULL },
- console_transfer, "Transfer a call to a different extension",
- transfer_usage, NULL, &cli_oss_transfer_deprecated },
-
- { { "console", "send", "text", NULL },
- console_sendtext, "Send text to the remote device",
- sendtext_usage, NULL, &cli_oss_send_text_deprecated },
-
- { { "console", "autoanswer", NULL },
- console_autoanswer, "Sets/displays autoanswer",
- autoanswer_usage, autoanswer_complete, &cli_oss_autoanswer_deprecated },
-
- { { "console", "boost", NULL },
- do_boost, "Sets/displays mic boost in dB",
- NULL, NULL, &cli_oss_boost_deprecated },
-
- { { "console", "active", NULL },
- console_active, "Sets/displays active console",
- active_usage, NULL, &cli_oss_active_deprecated },
-};
-
-/*
- * store the mixer argument from the config file, filtering possibly
- * invalid or dangerous values (the string is used as argument for
- * system("mixer %s")
- */
-static void store_mixer(struct chan_oss_pvt *o, char *s)
-{
- int i;
-
- for (i = 0; i < strlen(s); i++) {
- if (!isalnum(s[i]) && index(" \t-/", s[i]) == NULL) {
- ast_log(LOG_WARNING, "Suspect char %c in mixer cmd, ignoring:\n\t%s\n", s[i], s);
- return;
- }
- }
- if (o->mixer_cmd)
- free(o->mixer_cmd);
- o->mixer_cmd = ast_strdup(s);
- ast_log(LOG_WARNING, "setting mixer %s\n", s);
-}
-
-/*
- * store the callerid components
- */
-static void store_callerid(struct chan_oss_pvt *o, char *s)
-{
- ast_callerid_split(s, o->cid_name, sizeof(o->cid_name), o->cid_num, sizeof(o->cid_num));
-}
-
-/*
- * grab fields from the config file, init the descriptor and open the device.
- */
-static struct chan_oss_pvt *store_config(struct ast_config *cfg, char *ctg)
-{
- struct ast_variable *v;
- struct chan_oss_pvt *o;
-
- if (ctg == NULL) {
- o = &oss_default;
- ctg = "general";
- } else {
- if (!(o = ast_calloc(1, sizeof(*o))))
- return NULL;
- *o = oss_default;
- /* "general" is also the default thing */
- if (strcmp(ctg, "general") == 0) {
- o->name = ast_strdup("dsp");
- oss_active = o->name;
- goto openit;
- }
- o->name = ast_strdup(ctg);
- }
-
- strcpy(o->mohinterpret, "default");
-
- o->lastopen = ast_tvnow(); /* don't leave it 0 or tvdiff may wrap */
- /* fill other fields from configuration */
- for (v = ast_variable_browse(cfg, ctg); v; v = v->next) {
- M_START(v->name, v->value);
-
- /* handle jb conf */
- if (!ast_jb_read_conf(&global_jbconf, v->name, v->value))
- continue;
-
- M_BOOL("autoanswer", o->autoanswer)
- M_BOOL("autohangup", o->autohangup)
- M_BOOL("overridecontext", o->overridecontext)
- M_STR("device", o->device)
- M_UINT("frags", o->frags)
- M_UINT("debug", oss_debug)
- M_UINT("queuesize", o->queuesize)
- M_STR("context", o->ctx)
- M_STR("language", o->language)
- M_STR("mohinterpret", o->mohinterpret)
- M_STR("extension", o->ext)
- M_F("mixer", store_mixer(o, v->value))
- M_F("callerid", store_callerid(o, v->value))
- M_F("boost", store_boost(o, v->value))
- M_END(;
- );
- }
- if (ast_strlen_zero(o->device))
- ast_copy_string(o->device, DEV_DSP, sizeof(o->device));
- if (o->mixer_cmd) {
- char *cmd;
-
- if (asprintf(&cmd, "mixer %s", o->mixer_cmd) < 0) {
- ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
- } else {
- ast_log(LOG_WARNING, "running [%s]\n", cmd);
- if (system(cmd) < 0) {
- ast_log(LOG_WARNING, "system() failed: %s\n", strerror(errno));
- }
- free(cmd);
- }
- }
- if (o == &oss_default) /* we are done with the default */
- return NULL;
-
- openit:
-#if TRYOPEN
- if (setformat(o, O_RDWR) < 0) { /* open device */
- if (option_verbose > 0) {
- ast_verbose(VERBOSE_PREFIX_2 "Device %s not detected\n", ctg);
- ast_verbose(VERBOSE_PREFIX_2 "Turn off OSS support by adding " "'noload=chan_oss.so' in /etc/asterisk/modules.conf\n");
- }
- goto error;
- }
- if (o->duplex != M_FULL)
- ast_log(LOG_WARNING, "XXX I don't work right with non " "full-duplex sound cards XXX\n");
-#endif /* TRYOPEN */
- if (pipe(o->sndcmd) != 0) {
- ast_log(LOG_ERROR, "Unable to create pipe\n");
- goto error;
- }
- ast_pthread_create_background(&o->sthread, NULL, sound_thread, o);
- /* link into list of devices */
- if (o != &oss_default) {
- o->next = oss_default.next;
- oss_default.next = o;
- }
- return o;
-
- error:
- if (o != &oss_default)
- free(o);
- return NULL;
-}
-
-static int load_module(void)
-{
- struct ast_config *cfg = NULL;
- char *ctg = NULL;
-
- /* Copy the default jb config over global_jbconf */
- memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
-
- /* load config file */
- if (!(cfg = ast_config_load(config))) {
- ast_log(LOG_NOTICE, "Unable to load config %s\n", config);
- return AST_MODULE_LOAD_DECLINE;
- }
-
- do {
- store_config(cfg, ctg);
- } while ( (ctg = ast_category_browse(cfg, ctg)) != NULL);
-
- ast_config_destroy(cfg);
-
- if (find_desc(oss_active) == NULL) {
- ast_log(LOG_NOTICE, "Device %s not found\n", oss_active);
- /* XXX we could default to 'dsp' perhaps ? */
- /* XXX should cleanup allocated memory etc. */
- return AST_MODULE_LOAD_FAILURE;
- }
-
- if (ast_channel_register(&oss_tech)) {
- ast_log(LOG_ERROR, "Unable to register channel type 'OSS'\n");
- return AST_MODULE_LOAD_FAILURE;
- }
-
- ast_cli_register_multiple(cli_oss, sizeof(cli_oss) / sizeof(struct ast_cli_entry));
-
- return AST_MODULE_LOAD_SUCCESS;
-}
-
-
-static int unload_module(void)
-{
- struct chan_oss_pvt *o;
-
- ast_channel_unregister(&oss_tech);
- ast_cli_unregister_multiple(cli_oss, sizeof(cli_oss) / sizeof(struct ast_cli_entry));
-
- for (o = oss_default.next; o; o = o->next) {
- close(o->sounddev);
- if (o->sndcmd[0] > 0) {
- close(o->sndcmd[0]);
- close(o->sndcmd[1]);
- }
- if (o->owner)
- ast_softhangup(o->owner, AST_SOFTHANGUP_APPUNLOAD);
- if (o->owner) /* XXX how ??? */
- return -1;
- /* XXX what about the thread ? */
- /* XXX what about the memory allocated ? */
- }
- return 0;
-}
-
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "OSS Console Channel Driver");
diff --git a/1.4.23-rc4/channels/chan_phone.c b/1.4.23-rc4/channels/chan_phone.c
deleted file mode 100644
index 55bda8b72..000000000
--- a/1.4.23-rc4/channels/chan_phone.c
+++ /dev/null
@@ -1,1433 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 1999 - 2005, Digium, Inc.
- *
- * Mark Spencer <markster@digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Generic Linux Telephony Interface driver
- *
- * \author Mark Spencer <markster@digium.com>
- *
- * \ingroup channel_drivers
- */
-
-/*** MODULEINFO
- <depend>ixjuser</depend>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
-#include <stdio.h>
-#include <string.h>
-#include <ctype.h>
-#include <sys/socket.h>
-#include <sys/time.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <arpa/inet.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <signal.h>
-#ifdef HAVE_LINUX_COMPILER_H
-#include <linux/compiler.h>
-#endif
-#include <linux/telephony.h>
-/* Still use some IXJ specific stuff */
-#include <linux/version.h>
-#include <linux/ixjuser.h>
-
-#include "asterisk/lock.h"
-#include "asterisk/channel.h"
-#include "asterisk/config.h"
-#include "asterisk/logger.h"
-#include "asterisk/module.h"
-#include "asterisk/pbx.h"
-#include "asterisk/options.h"
-#include "asterisk/utils.h"
-#include "asterisk/callerid.h"
-#include "asterisk/causes.h"
-#include "asterisk/stringfields.h"
-#include "asterisk/musiconhold.h"
-
-#include "DialTone.h"
-
-#ifdef QTI_PHONEJACK_TJ_PCI /* check for the newer quicknet driver v.3.1.0 which has this symbol */
-#define QNDRV_VER 310
-#else
-#define QNDRV_VER 100
-#endif
-
-#if QNDRV_VER > 100
-#ifdef __linux__
-#define IXJ_PHONE_RING_START(x) ioctl(p->fd, PHONE_RING_START, &x);
-#else /* FreeBSD and others */
-#define IXJ_PHONE_RING_START(x) ioctl(p->fd, PHONE_RING_START, x);
-#endif /* __linux__ */
-#else /* older driver */
-#define IXJ_PHONE_RING_START(x) ioctl(p->fd, PHONE_RING_START, &x);
-#endif
-
-#define DEFAULT_CALLER_ID "Unknown"
-#define PHONE_MAX_BUF 480
-#define DEFAULT_GAIN 0x100
-
-static const char tdesc[] = "Standard Linux Telephony API Driver";
-static const char config[] = "phone.conf";
-
-/* Default context for dialtone mode */
-static char context[AST_MAX_EXTENSION] = "default";
-
-/* Default language */
-static char language[MAX_LANGUAGE] = "";
-
-static int echocancel = AEC_OFF;
-
-static int silencesupression = 0;
-
-static int prefformat = AST_FORMAT_G723_1 | AST_FORMAT_SLINEAR | AST_FORMAT_ULAW;
-
-/* Protect the interface list (of phone_pvt's) */
-AST_MUTEX_DEFINE_STATIC(iflock);
-
-/* Protect the monitoring thread, so only one process can kill or start it, and not
- when it's doing something critical. */
-AST_MUTEX_DEFINE_STATIC(monlock);
-
-/* Boolean value whether the monitoring thread shall continue. */
-static unsigned int monitor;
-
-/* This is the thread for the monitor which checks for input on the channels
- which are not currently in use. */
-static pthread_t monitor_thread = AST_PTHREADT_NULL;
-
-static int restart_monitor(void);
-
-/* The private structures of the Phone Jack channels are linked for
- selecting outgoing channels */
-
-#define MODE_DIALTONE 1
-#define MODE_IMMEDIATE 2
-#define MODE_FXO 3
-#define MODE_FXS 4
-#define MODE_SIGMA 5
-
-static struct phone_pvt {
- int fd; /* Raw file descriptor for this device */
- struct ast_channel *owner; /* Channel we belong to, possibly NULL */
- int mode; /* Is this in the */
- int lastformat; /* Last output format */
- int lastinput; /* Last input format */
- int ministate; /* Miniature state, for dialtone mode */
- char dev[256]; /* Device name */
- struct phone_pvt *next; /* Next channel in list */
- struct ast_frame fr; /* Frame */
- char offset[AST_FRIENDLY_OFFSET];
- char buf[PHONE_MAX_BUF]; /* Static buffer for reading frames */
- int obuflen;
- int dialtone;
- int txgain, rxgain; /* gain control for playing, recording */
- /* 0x100 - 1.0, 0x200 - 2.0, 0x80 - 0.5 */
- int cpt; /* Call Progress Tone playing? */
- int silencesupression;
- char context[AST_MAX_EXTENSION];
- char obuf[PHONE_MAX_BUF * 2];
- char ext[AST_MAX_EXTENSION];
- char language[MAX_LANGUAGE];
- char cid_num[AST_MAX_EXTENSION];
- char cid_name[AST_MAX_EXTENSION];
-} *iflist = NULL;
-
-static char cid_num[AST_MAX_EXTENSION];
-static char cid_name[AST_MAX_EXTENSION];
-
-static struct ast_channel *phone_request(const char *type, int format, void *data, int *cause);
-static int phone_digit_begin(struct ast_channel *ast, char digit);
-static int phone_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
-static int phone_call(struct ast_channel *ast, char *dest, int timeout);
-static int phone_hangup(struct ast_channel *ast);
-static int phone_answer(struct ast_channel *ast);
-static struct ast_frame *phone_read(struct ast_channel *ast);
-static int phone_write(struct ast_channel *ast, struct ast_frame *frame);
-static struct ast_frame *phone_exception(struct ast_channel *ast);
-static int phone_send_text(struct ast_channel *ast, const char *text);
-static int phone_fixup(struct ast_channel *old, struct ast_channel *new);
-static int phone_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen);
-
-static const struct ast_channel_tech phone_tech = {
- .type = "Phone",
- .description = tdesc,
- .capabilities = AST_FORMAT_G723_1 | AST_FORMAT_SLINEAR | AST_FORMAT_ULAW,
- .requester = phone_request,
- .send_digit_begin = phone_digit_begin,
- .send_digit_end = phone_digit_end,
- .call = phone_call,
- .hangup = phone_hangup,
- .answer = phone_answer,
- .read = phone_read,
- .write = phone_write,
- .exception = phone_exception,
- .indicate = phone_indicate,
- .fixup = phone_fixup
-};
-
-static struct ast_channel_tech phone_tech_fxs = {
- .type = "Phone",
- .description = tdesc,
- .requester = phone_request,
- .send_digit_begin = phone_digit_begin,
- .send_digit_end = phone_digit_end,
- .call = phone_call,
- .hangup = phone_hangup,
- .answer = phone_answer,
- .read = phone_read,
- .write = phone_write,
- .exception = phone_exception,
- .write_video = phone_write,
- .send_text = phone_send_text,
- .indicate = phone_indicate,
- .fixup = phone_fixup
-};
-
-static struct ast_channel_tech *cur_tech;
-
-static int phone_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen)
-{
- struct phone_pvt *p = chan->tech_pvt;
- int res=-1;
- ast_log(LOG_DEBUG, "Requested indication %d on channel %s\n", condition, chan->name);
- switch(condition) {
- case AST_CONTROL_FLASH:
- ioctl(p->fd, IXJCTL_PSTN_SET_STATE, PSTN_ON_HOOK);
- usleep(320000);
- ioctl(p->fd, IXJCTL_PSTN_SET_STATE, PSTN_OFF_HOOK);
- p->lastformat = -1;
- res = 0;
- break;
- case AST_CONTROL_HOLD:
- ast_moh_start(chan, data, NULL);
- break;
- case AST_CONTROL_UNHOLD:
- ast_moh_stop(chan);
- break;
- case AST_CONTROL_SRCUPDATE:
- res = 0;
- break;
- default:
- ast_log(LOG_WARNING, "Condition %d is not supported on channel %s\n", condition, chan->name);
- }
- return res;
-}
-
-static int phone_fixup(struct ast_channel *old, struct ast_channel *new)
-{
- struct phone_pvt *pvt = old->tech_pvt;
- if (pvt && pvt->owner == old)
- pvt->owner = new;
- return 0;
-}
-
-static int phone_digit_begin(struct ast_channel *chan, char digit)
-{
- /* XXX Modify this callback to let Asterisk support controlling the length of DTMF */
- return 0;
-}
-
-static int phone_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
-{
- struct phone_pvt *p;
- int outdigit;
- p = ast->tech_pvt;
- ast_log(LOG_DEBUG, "Dialed %c\n", digit);
- switch(digit) {
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- outdigit = digit - '0';
- break;
- case '*':
- outdigit = 11;
- break;
- case '#':
- outdigit = 12;
- break;
- case 'f': /*flash*/
- case 'F':
- ioctl(p->fd, IXJCTL_PSTN_SET_STATE, PSTN_ON_HOOK);
- usleep(320000);
- ioctl(p->fd, IXJCTL_PSTN_SET_STATE, PSTN_OFF_HOOK);
- p->lastformat = -1;
- return 0;
- default:
- ast_log(LOG_WARNING, "Unknown digit '%c'\n", digit);
- return -1;
- }
- ast_log(LOG_DEBUG, "Dialed %d\n", outdigit);
- ioctl(p->fd, PHONE_PLAY_TONE, outdigit);
- p->lastformat = -1;
- return 0;
-}
-
-static int phone_call(struct ast_channel *ast, char *dest, int timeout)
-{
- struct phone_pvt *p;
-
- PHONE_CID cid;
- time_t UtcTime;
- struct tm tm;
- int start;
-
- time(&UtcTime);
- ast_localtime(&UtcTime, &tm, NULL);
-
- memset(&cid, 0, sizeof(PHONE_CID));
- if(&tm != NULL) {
- snprintf(cid.month, sizeof(cid.month), "%02d",(tm.tm_mon + 1));
- snprintf(cid.day, sizeof(cid.day), "%02d", tm.tm_mday);
- snprintf(cid.hour, sizeof(cid.hour), "%02d", tm.tm_hour);
- snprintf(cid.min, sizeof(cid.min), "%02d", tm.tm_min);
- }
- /* the standard format of ast->callerid is: "name" <number>, but not always complete */
- if (ast_strlen_zero(ast->cid.cid_name))
- strcpy(cid.name, DEFAULT_CALLER_ID);
- else
- ast_copy_string(cid.name, ast->cid.cid_name, sizeof(cid.name));
-
- if (ast->cid.cid_num)
- ast_copy_string(cid.number, ast->cid.cid_num, sizeof(cid.number));
-
- p = ast->tech_pvt;
-
- if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
- ast_log(LOG_WARNING, "phone_call called on %s, neither down nor reserved\n", ast->name);
- return -1;
- }
- if (option_debug)
- ast_log(LOG_DEBUG, "Ringing %s on %s (%d)\n", dest, ast->name, ast->fds[0]);
-
- start = IXJ_PHONE_RING_START(cid);
- if (start == -1)
- return -1;
-
- if (p->mode == MODE_FXS) {
- char *digit = strchr(dest, '/');
- if (digit)
- {
- digit++;
- while (*digit)
- phone_digit_end(ast, *digit++, 0);
- }
- }
-
- ast_setstate(ast, AST_STATE_RINGING);
- ast_queue_control(ast, AST_CONTROL_RINGING);
- return 0;
-}
-
-static int phone_hangup(struct ast_channel *ast)
-{
- struct phone_pvt *p;
- p = ast->tech_pvt;
- if (option_debug)
- ast_log(LOG_DEBUG, "phone_hangup(%s)\n", ast->name);
- if (!ast->tech_pvt) {
- ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
- return 0;
- }
- /* XXX Is there anything we can do to really hang up except stop recording? */
- ast_setstate(ast, AST_STATE_DOWN);
- if (ioctl(p->fd, PHONE_REC_STOP))
- ast_log(LOG_WARNING, "Failed to stop recording\n");
- if (ioctl(p->fd, PHONE_PLAY_STOP))
- ast_log(LOG_WARNING, "Failed to stop playing\n");
- if (ioctl(p->fd, PHONE_RING_STOP))
- ast_log(LOG_WARNING, "Failed to stop ringing\n");
- if (ioctl(p->fd, PHONE_CPT_STOP))
- ast_log(LOG_WARNING, "Failed to stop sounds\n");
-
- /* If it's an FXO, hang them up */
- if (p->mode == MODE_FXO) {
- if (ioctl(p->fd, PHONE_PSTN_SET_STATE, PSTN_ON_HOOK))
- ast_log(LOG_DEBUG, "ioctl(PHONE_PSTN_SET_STATE) failed on %s (%s)\n",ast->name, strerror(errno));
- }
-
- /* If they're off hook, give a busy signal */
- if (ioctl(p->fd, PHONE_HOOKSTATE)) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Got hunghup, giving busy signal\n");
- ioctl(p->fd, PHONE_BUSY);
- p->cpt = 1;
- }
- p->lastformat = -1;
- p->lastinput = -1;
- p->ministate = 0;
- p->obuflen = 0;
- p->dialtone = 0;
- memset(p->ext, 0, sizeof(p->ext));
- ((struct phone_pvt *)(ast->tech_pvt))->owner = NULL;
- ast_module_unref(ast_module_info->self);
- if (option_verbose > 2)
- ast_verbose( VERBOSE_PREFIX_3 "Hungup '%s'\n", ast->name);
- ast->tech_pvt = NULL;
- ast_setstate(ast, AST_STATE_DOWN);
- restart_monitor();
- return 0;
-}
-
-static int phone_setup(struct ast_channel *ast)
-{
- struct phone_pvt *p;
- p = ast->tech_pvt;
- ioctl(p->fd, PHONE_CPT_STOP);
- /* Nothing to answering really, just start recording */
- if (ast->rawreadformat == AST_FORMAT_G723_1) {
- /* Prefer g723 */
- ioctl(p->fd, PHONE_REC_STOP);
- if (p->lastinput != AST_FORMAT_G723_1) {
- p->lastinput = AST_FORMAT_G723_1;
- if (ioctl(p->fd, PHONE_REC_CODEC, G723_63)) {
- ast_log(LOG_WARNING, "Failed to set codec to g723.1\n");
- return -1;
- }
- }
- } else if (ast->rawreadformat == AST_FORMAT_SLINEAR) {
- ioctl(p->fd, PHONE_REC_STOP);
- if (p->lastinput != AST_FORMAT_SLINEAR) {
- p->lastinput = AST_FORMAT_SLINEAR;
- if (ioctl(p->fd, PHONE_REC_CODEC, LINEAR16)) {
- ast_log(LOG_WARNING, "Failed to set codec to signed linear 16\n");
- return -1;
- }
- }
- } else if (ast->rawreadformat == AST_FORMAT_ULAW) {
- ioctl(p->fd, PHONE_REC_STOP);
- if (p->lastinput != AST_FORMAT_ULAW) {
- p->lastinput = AST_FORMAT_ULAW;
- if (ioctl(p->fd, PHONE_REC_CODEC, ULAW)) {
- ast_log(LOG_WARNING, "Failed to set codec to uLaw\n");
- return -1;
- }
- }
- } else if (p->mode == MODE_FXS) {
- ioctl(p->fd, PHONE_REC_STOP);
- if (p->lastinput != ast->rawreadformat) {
- p->lastinput = ast->rawreadformat;
- if (ioctl(p->fd, PHONE_REC_CODEC, ast->rawreadformat)) {
- ast_log(LOG_WARNING, "Failed to set codec to %d\n",
- ast->rawreadformat);
- return -1;
- }
- }
- } else {
- ast_log(LOG_WARNING, "Can't do format %s\n", ast_getformatname(ast->rawreadformat));
- return -1;
- }
- if (ioctl(p->fd, PHONE_REC_START)) {
- ast_log(LOG_WARNING, "Failed to start recording\n");
- return -1;
- }
- /* set the DTMF times (the default is too short) */
- ioctl(p->fd, PHONE_SET_TONE_ON_TIME, 300);
- ioctl(p->fd, PHONE_SET_TONE_OFF_TIME, 200);
- return 0;
-}
-
-static int phone_answer(struct ast_channel *ast)
-{
- struct phone_pvt *p;
- p = ast->tech_pvt;
- /* In case it's a LineJack, take it off hook */
- if (p->mode == MODE_FXO) {
- if (ioctl(p->fd, PHONE_PSTN_SET_STATE, PSTN_OFF_HOOK))
- ast_log(LOG_DEBUG, "ioctl(PHONE_PSTN_SET_STATE) failed on %s (%s)\n", ast->name, strerror(errno));
- else
- ast_log(LOG_DEBUG, "Took linejack off hook\n");
- }
- phone_setup(ast);
- if (option_debug)
- ast_log(LOG_DEBUG, "phone_answer(%s)\n", ast->name);
- ast->rings = 0;
- ast_setstate(ast, AST_STATE_UP);
- return 0;
-}
-
-#if 0
-static char phone_2digit(char c)
-{
- if (c == 12)
- return '#';
- else if (c == 11)
- return '*';
- else if ((c < 10) && (c >= 0))
- return '0' + c - 1;
- else
- return '?';
-}
-#endif
-
-static struct ast_frame *phone_exception(struct ast_channel *ast)
-{
- int res;
- union telephony_exception phonee;
- struct phone_pvt *p = ast->tech_pvt;
- char digit;
-
- /* Some nice norms */
- p->fr.datalen = 0;
- p->fr.samples = 0;
- p->fr.data = NULL;
- p->fr.src = "Phone";
- p->fr.offset = 0;
- p->fr.mallocd=0;
- p->fr.delivery = ast_tv(0,0);
-
- phonee.bytes = ioctl(p->fd, PHONE_EXCEPTION);
- if (phonee.bits.dtmf_ready) {
- if (option_debug)
- ast_log(LOG_DEBUG, "phone_exception(): DTMF\n");
-
- /* We've got a digit -- Just handle this nicely and easily */
- digit = ioctl(p->fd, PHONE_GET_DTMF_ASCII);
- p->fr.subclass = digit;
- p->fr.frametype = AST_FRAME_DTMF;
- return &p->fr;
- }
- if (phonee.bits.hookstate) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Hookstate changed\n");
- res = ioctl(p->fd, PHONE_HOOKSTATE);
- /* See if we've gone on hook, if so, notify by returning NULL */
- if (option_debug)
- ast_log(LOG_DEBUG, "New hookstate: %d\n", res);
- if (!res && (p->mode != MODE_FXO))
- return NULL;
- else {
- if (ast->_state == AST_STATE_RINGING) {
- /* They've picked up the phone */
- p->fr.frametype = AST_FRAME_CONTROL;
- p->fr.subclass = AST_CONTROL_ANSWER;
- phone_setup(ast);
- ast_setstate(ast, AST_STATE_UP);
- return &p->fr;
- } else
- ast_log(LOG_WARNING, "Got off hook in weird state %d\n", ast->_state);
- }
- }
-#if 1
- if (phonee.bits.pstn_ring)
- ast_verbose("Unit is ringing\n");
- if (phonee.bits.caller_id) {
- ast_verbose("We have caller ID\n");
- }
- if (phonee.bits.pstn_wink)
- ast_verbose("Detected Wink\n");
-#endif
- /* Strange -- nothing there.. */
- p->fr.frametype = AST_FRAME_NULL;
- p->fr.subclass = 0;
- return &p->fr;
-}
-
-static struct ast_frame *phone_read(struct ast_channel *ast)
-{
- int res;
- struct phone_pvt *p = ast->tech_pvt;
-
-
- /* Some nice norms */
- p->fr.datalen = 0;
- p->fr.samples = 0;
- p->fr.data = NULL;
- p->fr.src = "Phone";
- p->fr.offset = 0;
- p->fr.mallocd=0;
- p->fr.delivery = ast_tv(0,0);
-
- /* Try to read some data... */
- CHECK_BLOCKING(ast);
- res = read(p->fd, p->buf, PHONE_MAX_BUF);
- ast_clear_flag(ast, AST_FLAG_BLOCKING);
- if (res < 0) {
-#if 0
- if (errno == EAGAIN) {
- ast_log(LOG_WARNING, "Null frame received\n");
- p->fr.frametype = AST_FRAME_NULL;
- p->fr.subclass = 0;
- return &p->fr;
- }
-#endif
- ast_log(LOG_WARNING, "Error reading: %s\n", strerror(errno));
- return NULL;
- }
- p->fr.data = p->buf;
- if (p->mode != MODE_FXS)
- switch(p->buf[0] & 0x3) {
- case '0':
- case '1':
- /* Normal */
- break;
- case '2':
- case '3':
- /* VAD/CNG, only send two words */
- res = 4;
- break;
- }
- p->fr.samples = 240;
- p->fr.datalen = res;
- p->fr.frametype = p->lastinput <= AST_FORMAT_MAX_AUDIO ?
- AST_FRAME_VOICE :
- p->lastinput <= AST_FORMAT_PNG ? AST_FRAME_IMAGE
- : AST_FRAME_VIDEO;
- p->fr.subclass = p->lastinput;
- p->fr.offset = AST_FRIENDLY_OFFSET;
- /* Byteswap from little-endian to native-endian */
- if (p->fr.subclass == AST_FORMAT_SLINEAR)
- ast_frame_byteswap_le(&p->fr);
- return &p->fr;
-}
-
-static int phone_write_buf(struct phone_pvt *p, const char *buf, int len, int frlen, int swap)
-{
- int res;
- /* Store as much of the buffer as we can, then write fixed frames */
- int space = sizeof(p->obuf) - p->obuflen;
- /* Make sure we have enough buffer space to store the frame */
- if (space < len)
- len = space;
- if (swap)
- ast_swapcopy_samples(p->obuf+p->obuflen, buf, len/2);
- else
- memcpy(p->obuf + p->obuflen, buf, len);
- p->obuflen += len;
- while(p->obuflen > frlen) {
- res = write(p->fd, p->obuf, frlen);
- if (res != frlen) {
- if (res < 1) {
-/*
- * Card is in non-blocking mode now and it works well now, but there are
- * lot of messages like this. So, this message is temporarily disabled.
- */
- return 0;
- } else {
- ast_log(LOG_WARNING, "Only wrote %d of %d bytes\n", res, frlen);
- }
- }
- p->obuflen -= frlen;
- /* Move memory if necessary */
- if (p->obuflen)
- memmove(p->obuf, p->obuf + frlen, p->obuflen);
- }
- return len;
-}
-
-static int phone_send_text(struct ast_channel *ast, const char *text)
-{
- int length = strlen(text);
- return phone_write_buf(ast->tech_pvt, text, length, length, 0) ==
- length ? 0 : -1;
-}
-
-static int phone_write(struct ast_channel *ast, struct ast_frame *frame)
-{
- struct phone_pvt *p = ast->tech_pvt;
- int res;
- int maxfr=0;
- char *pos;
- int sofar;
- int expected;
- int codecset = 0;
- char tmpbuf[4];
- /* Write a frame of (presumably voice) data */
- if (frame->frametype != AST_FRAME_VOICE && p->mode != MODE_FXS) {
- if (frame->frametype != AST_FRAME_IMAGE)
- ast_log(LOG_WARNING, "Don't know what to do with frame type '%d'\n", frame->frametype);
- return 0;
- }
- if (!(frame->subclass &
- (AST_FORMAT_G723_1 | AST_FORMAT_SLINEAR | AST_FORMAT_ULAW)) &&
- p->mode != MODE_FXS) {
- ast_log(LOG_WARNING, "Cannot handle frames in %d format\n", frame->subclass);
- return -1;
- }
-#if 0
- /* If we're not in up mode, go into up mode now */
- if (ast->_state != AST_STATE_UP) {
- ast_setstate(ast, AST_STATE_UP);
- phone_setup(ast);
- }
-#else
- if (ast->_state != AST_STATE_UP) {
- /* Don't try tos end audio on-hook */
- return 0;
- }
-#endif
- if (frame->subclass == AST_FORMAT_G723_1) {
- if (p->lastformat != AST_FORMAT_G723_1) {
- ioctl(p->fd, PHONE_PLAY_STOP);
- ioctl(p->fd, PHONE_REC_STOP);
- if (ioctl(p->fd, PHONE_PLAY_CODEC, G723_63)) {
- ast_log(LOG_WARNING, "Unable to set G723.1 mode\n");
- return -1;
- }
- if (ioctl(p->fd, PHONE_REC_CODEC, G723_63)) {
- ast_log(LOG_WARNING, "Unable to set G723.1 mode\n");
- return -1;
- }
- p->lastformat = AST_FORMAT_G723_1;
- p->lastinput = AST_FORMAT_G723_1;
- /* Reset output buffer */
- p->obuflen = 0;
- codecset = 1;
- }
- if (frame->datalen > 24) {
- ast_log(LOG_WARNING, "Frame size too large for G.723.1 (%d bytes)\n", frame->datalen);
- return -1;
- }
- maxfr = 24;
- } else if (frame->subclass == AST_FORMAT_SLINEAR) {
- if (p->lastformat != AST_FORMAT_SLINEAR) {
- ioctl(p->fd, PHONE_PLAY_STOP);
- ioctl(p->fd, PHONE_REC_STOP);
- if (ioctl(p->fd, PHONE_PLAY_CODEC, LINEAR16)) {
- ast_log(LOG_WARNING, "Unable to set 16-bit linear mode\n");
- return -1;
- }
- if (ioctl(p->fd, PHONE_REC_CODEC, LINEAR16)) {
- ast_log(LOG_WARNING, "Unable to set 16-bit linear mode\n");
- return -1;
- }
- p->lastformat = AST_FORMAT_SLINEAR;
- p->lastinput = AST_FORMAT_SLINEAR;
- codecset = 1;
- /* Reset output buffer */
- p->obuflen = 0;
- }
- maxfr = 480;
- } else if (frame->subclass == AST_FORMAT_ULAW) {
- if (p->lastformat != AST_FORMAT_ULAW) {
- ioctl(p->fd, PHONE_PLAY_STOP);
- ioctl(p->fd, PHONE_REC_STOP);
- if (ioctl(p->fd, PHONE_PLAY_CODEC, ULAW)) {
- ast_log(LOG_WARNING, "Unable to set uLaw mode\n");
- return -1;
- }
- if (ioctl(p->fd, PHONE_REC_CODEC, ULAW)) {
- ast_log(LOG_WARNING, "Unable to set uLaw mode\n");
- return -1;
- }
- p->lastformat = AST_FORMAT_ULAW;
- p->lastinput = AST_FORMAT_ULAW;
- codecset = 1;
- /* Reset output buffer */
- p->obuflen = 0;
- }
- maxfr = 240;
- } else {
- if (p->lastformat != frame->subclass) {
- ioctl(p->fd, PHONE_PLAY_STOP);
- ioctl(p->fd, PHONE_REC_STOP);
- if (ioctl(p->fd, PHONE_PLAY_CODEC, frame->subclass)) {
- ast_log(LOG_WARNING, "Unable to set %d mode\n",
- frame->subclass);
- return -1;
- }
- if (ioctl(p->fd, PHONE_REC_CODEC, frame->subclass)) {
- ast_log(LOG_WARNING, "Unable to set %d mode\n",
- frame->subclass);
- return -1;
- }
- p->lastformat = frame->subclass;
- p->lastinput = frame->subclass;
- codecset = 1;
- /* Reset output buffer */
- p->obuflen = 0;
- }
- maxfr = 480;
- }
- if (codecset) {
- ioctl(p->fd, PHONE_REC_DEPTH, 3);
- ioctl(p->fd, PHONE_PLAY_DEPTH, 3);
- if (ioctl(p->fd, PHONE_PLAY_START)) {
- ast_log(LOG_WARNING, "Failed to start playback\n");
- return -1;
- }
- if (ioctl(p->fd, PHONE_REC_START)) {
- ast_log(LOG_WARNING, "Failed to start recording\n");
- return -1;
- }
- }
- /* If we get here, we have a frame of Appropriate data */
- sofar = 0;
- pos = frame->data;
- while(sofar < frame->datalen) {
- /* Write in no more than maxfr sized frames */
- expected = frame->datalen - sofar;
- if (maxfr < expected)
- expected = maxfr;
- /* XXX Internet Phone Jack does not handle the 4-byte VAD frame properly! XXX
- we have to pad it to 24 bytes still. */
- if (frame->datalen == 4) {
- if (p->silencesupression) {
- memset(tmpbuf, 0, sizeof(tmpbuf));
- memcpy(tmpbuf, frame->data, 4);
- expected = 24;
- res = phone_write_buf(p, tmpbuf, expected, maxfr, 0);
- }
- res = 4;
- expected=4;
- } else {
- int swap = 0;
-#if __BYTE_ORDER == __BIG_ENDIAN
- if (frame->subclass == AST_FORMAT_SLINEAR)
- swap = 1; /* Swap big-endian samples to little-endian as we copy */
-#endif
- res = phone_write_buf(p, pos, expected, maxfr, swap);
- }
- if (res != expected) {
- if ((errno != EAGAIN) && (errno != EINTR)) {
- if (res < 0)
- ast_log(LOG_WARNING, "Write returned error (%s)\n", strerror(errno));
- /*
- * Card is in non-blocking mode now and it works well now, but there are
- * lot of messages like this. So, this message is temporarily disabled.
- */
-#if 0
- else
- ast_log(LOG_WARNING, "Only wrote %d of %d bytes\n", res, frame->datalen);
-#endif
- return -1;
- } else /* Pretend it worked */
- res = expected;
- }
- sofar += res;
- pos += res;
- }
- return 0;
-}
-
-static struct ast_channel *phone_new(struct phone_pvt *i, int state, char *context)
-{
- struct ast_channel *tmp;
- struct phone_codec_data codec;
- tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, "", i->ext, i->context, 0, "Phone/%s", i->dev + 5);
- if (tmp) {
- tmp->tech = cur_tech;
- tmp->fds[0] = i->fd;
- /* XXX Switching formats silently causes kernel panics XXX */
- if (i->mode == MODE_FXS &&
- ioctl(i->fd, PHONE_QUERY_CODEC, &codec) == 0) {
- if (codec.type == LINEAR16)
- tmp->nativeformats =
- tmp->rawreadformat =
- tmp->rawwriteformat =
- AST_FORMAT_SLINEAR;
- else {
- tmp->nativeformats =
- tmp->rawreadformat =
- tmp->rawwriteformat =
- prefformat & ~AST_FORMAT_SLINEAR;
- }
- }
- else {
- tmp->nativeformats = prefformat;
- tmp->rawreadformat = prefformat;
- tmp->rawwriteformat = prefformat;
- }
- /* no need to call ast_setstate: the channel_alloc already did its job */
- if (state == AST_STATE_RING)
- tmp->rings = 1;
- tmp->tech_pvt = i;
- ast_copy_string(tmp->context, context, sizeof(tmp->context));
- if (!ast_strlen_zero(i->ext))
- ast_copy_string(tmp->exten, i->ext, sizeof(tmp->exten));
- else
- strcpy(tmp->exten, "s");
- if (!ast_strlen_zero(i->language))
- ast_string_field_set(tmp, language, i->language);
-
- /* Don't use ast_set_callerid() here because it will
- * generate a NewCallerID event before the NewChannel event */
- tmp->cid.cid_ani = ast_strdup(i->cid_num);
-
- i->owner = tmp;
- ast_module_ref(ast_module_info->self);
- if (state != AST_STATE_DOWN) {
- if (state == AST_STATE_RING) {
- ioctl(tmp->fds[0], PHONE_RINGBACK);
- i->cpt = 1;
- }
- if (ast_pbx_start(tmp)) {
- ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
- ast_hangup(tmp);
- }
- }
- } else
- ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
- return tmp;
-}
-
-static void phone_mini_packet(struct phone_pvt *i)
-{
- int res;
- char buf[1024];
- /* Ignore stuff we read... */
- res = read(i->fd, buf, sizeof(buf));
- if (res < 1) {
- ast_log(LOG_WARNING, "Read returned %d: %s\n", res, strerror(errno));
- return;
- }
-}
-
-static void phone_check_exception(struct phone_pvt *i)
-{
- int offhook=0;
- char digit[2] = {0 , 0};
- union telephony_exception phonee;
- /* XXX Do something XXX */
-#if 0
- ast_log(LOG_DEBUG, "Exception!\n");
-#endif
- phonee.bytes = ioctl(i->fd, PHONE_EXCEPTION);
- if (phonee.bits.dtmf_ready) {
- digit[0] = ioctl(i->fd, PHONE_GET_DTMF_ASCII);
- if (i->mode == MODE_DIALTONE || i->mode == MODE_FXS || i->mode == MODE_SIGMA) {
- ioctl(i->fd, PHONE_PLAY_STOP);
- ioctl(i->fd, PHONE_REC_STOP);
- ioctl(i->fd, PHONE_CPT_STOP);
- i->dialtone = 0;
- if (strlen(i->ext) < AST_MAX_EXTENSION - 1)
- strncat(i->ext, digit, sizeof(i->ext) - strlen(i->ext) - 1);
- if ((i->mode != MODE_FXS ||
- !(phonee.bytes = ioctl(i->fd, PHONE_EXCEPTION)) ||
- !phonee.bits.dtmf_ready) &&
- ast_exists_extension(NULL, i->context, i->ext, 1, i->cid_num)) {
- /* It's a valid extension in its context, get moving! */
- phone_new(i, AST_STATE_RING, i->context);
- /* No need to restart monitor, we are the monitor */
- } else if (!ast_canmatch_extension(NULL, i->context, i->ext, 1, i->cid_num)) {
- /* There is nothing in the specified extension that can match anymore.
- Try the default */
- if (ast_exists_extension(NULL, "default", i->ext, 1, i->cid_num)) {
- /* Check the default, too... */
- phone_new(i, AST_STATE_RING, "default");
- /* XXX This should probably be justified better XXX */
- } else if (!ast_canmatch_extension(NULL, "default", i->ext, 1, i->cid_num)) {
- /* It's not a valid extension, give a busy signal */
- if (option_debug)
- ast_log(LOG_DEBUG, "%s can't match anything in %s or default\n", i->ext, i->context);
- ioctl(i->fd, PHONE_BUSY);
- i->cpt = 1;
- }
- }
-#if 0
- ast_verbose("Extension is %s\n", i->ext);
-#endif
- }
- }
- if (phonee.bits.hookstate) {
- offhook = ioctl(i->fd, PHONE_HOOKSTATE);
- if (offhook) {
- if (i->mode == MODE_IMMEDIATE) {
- phone_new(i, AST_STATE_RING, i->context);
- } else if (i->mode == MODE_DIALTONE) {
- ast_module_ref(ast_module_info->self);
- /* Reset the extension */
- i->ext[0] = '\0';
- /* Play the dialtone */
- i->dialtone++;
- ioctl(i->fd, PHONE_PLAY_STOP);
- ioctl(i->fd, PHONE_PLAY_CODEC, ULAW);
- ioctl(i->fd, PHONE_PLAY_START);
- i->lastformat = -1;
- } else if (i->mode == MODE_SIGMA) {
- ast_module_ref(ast_module_info->self);
- /* Reset the extension */
- i->ext[0] = '\0';
- /* Play the dialtone */
- i->dialtone++;
- ioctl(i->fd, PHONE_DIALTONE);
- }
- } else {
- if (i->dialtone)
- ast_module_unref(ast_module_info->self);
- memset(i->ext, 0, sizeof(i->ext));
- if (i->cpt)
- {
- ioctl(i->fd, PHONE_CPT_STOP);
- i->cpt = 0;
- }
- ioctl(i->fd, PHONE_PLAY_STOP);
- ioctl(i->fd, PHONE_REC_STOP);
- i->dialtone = 0;
- i->lastformat = -1;
- }
- }
- if (phonee.bits.pstn_ring) {
- ast_verbose("Unit is ringing\n");
- phone_new(i, AST_STATE_RING, i->context);
- }
- if (phonee.bits.caller_id)
- ast_verbose("We have caller ID\n");
-
-
-}
-
-static void *do_monitor(void *data)
-{
- fd_set rfds, efds;
- int n, res;
- struct phone_pvt *i;
- int tonepos = 0;
- /* The tone we're playing this round */
- struct timeval tv = {0,0};
- int dotone;
- /* This thread monitors all the frame relay interfaces which are not yet in use
- (and thus do not have a separate thread) indefinitely */
- while (monitor) {
- /* Don't let anybody kill us right away. Nobody should lock the interface list
- and wait for the monitor list, but the other way around is okay. */
- /* Lock the interface list */
- if (ast_mutex_lock(&iflock)) {
- ast_log(LOG_ERROR, "Unable to grab interface lock\n");
- return NULL;
- }
- /* Build the stuff we're going to select on, that is the socket of every
- phone_pvt that does not have an associated owner channel */
- n = -1;
- FD_ZERO(&rfds);
- FD_ZERO(&efds);
- i = iflist;
- dotone = 0;
- while (i) {
- if (FD_ISSET(i->fd, &rfds))
- ast_log(LOG_WARNING, "Descriptor %d appears twice (%s)?\n", i->fd, i->dev);
- if (!i->owner) {
- /* This needs to be watched, as it lacks an owner */
- FD_SET(i->fd, &rfds);
- FD_SET(i->fd, &efds);
- if (i->fd > n)
- n = i->fd;
- if (i->dialtone && i->mode != MODE_SIGMA) {
- /* Remember we're going to have to come back and play
- more dialtones */
- if (ast_tvzero(tv)) {
- /* If we're due for a dialtone, play one */
- if (write(i->fd, DialTone + tonepos, 240) != 240)
- ast_log(LOG_WARNING, "Dial tone write error\n");
- }
- dotone++;
- }
- }
-
- i = i->next;
- }
- /* Okay, now that we know what to do, release the interface lock */
- ast_mutex_unlock(&iflock);
-
- /* Wait indefinitely for something to happen */
- if (dotone && i && i->mode != MODE_SIGMA) {
- /* If we're ready to recycle the time, set it to 30 ms */
- tonepos += 240;
- if (tonepos >= sizeof(DialTone))
- tonepos = 0;
- if (ast_tvzero(tv)) {
- tv = ast_tv(30000, 0);
- }
- res = ast_select(n + 1, &rfds, NULL, &efds, &tv);
- } else {
- res = ast_select(n + 1, &rfds, NULL, &efds, NULL);
- tv = ast_tv(0,0);
- tonepos = 0;
- }
- /* Okay, select has finished. Let's see what happened. */
- if (res < 0) {
- ast_log(LOG_DEBUG, "select return %d: %s\n", res, strerror(errno));
- continue;
- }
- /* If there are no fd's changed, just continue, it's probably time
- to play some more dialtones */
- if (!res)
- continue;
- /* Alright, lock the interface list again, and let's look and see what has
- happened */
- if (ast_mutex_lock(&iflock)) {
- ast_log(LOG_WARNING, "Unable to lock the interface list\n");
- continue;
- }
-
- i = iflist;
- for(; i; i=i->next) {
- if (FD_ISSET(i->fd, &rfds)) {
- if (i->owner) {
- continue;
- }
- phone_mini_packet(i);
- }
- if (FD_ISSET(i->fd, &efds)) {
- if (i->owner) {
- continue;
- }
- phone_check_exception(i);
- }
- }
- ast_mutex_unlock(&iflock);
- }
- return NULL;
-
-}
-
-static int restart_monitor()
-{
- /* If we're supposed to be stopped -- stay stopped */
- if (monitor_thread == AST_PTHREADT_STOP)
- return 0;
- if (ast_mutex_lock(&monlock)) {
- ast_log(LOG_WARNING, "Unable to lock monitor\n");
- return -1;
- }
- if (monitor_thread == pthread_self()) {
- ast_mutex_unlock(&monlock);
- ast_log(LOG_WARNING, "Cannot kill myself\n");
- return -1;
- }
- if (monitor_thread != AST_PTHREADT_NULL) {
- if (ast_mutex_lock(&iflock)) {
- ast_mutex_unlock(&monlock);
- ast_log(LOG_WARNING, "Unable to lock the interface list\n");
- return -1;
- }
- monitor = 0;
- while (pthread_kill(monitor_thread, SIGURG) == 0)
- sched_yield();
- pthread_join(monitor_thread, NULL);
- ast_mutex_unlock(&iflock);
- }
- monitor = 1;
- /* Start a new monitor */
- if (ast_pthread_create_background(&monitor_thread, NULL, do_monitor, NULL) < 0) {
- ast_mutex_unlock(&monlock);
- ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
- return -1;
- }
- ast_mutex_unlock(&monlock);
- return 0;
-}
-
-static struct phone_pvt *mkif(char *iface, int mode, int txgain, int rxgain)
-{
- /* Make a phone_pvt structure for this interface */
- struct phone_pvt *tmp;
- int flags;
-
- tmp = malloc(sizeof(struct phone_pvt));
- if (tmp) {
- tmp->fd = open(iface, O_RDWR);
- if (tmp->fd < 0) {
- ast_log(LOG_WARNING, "Unable to open '%s'\n", iface);
- free(tmp);
- return NULL;
- }
- if (mode == MODE_FXO) {
- if (ioctl(tmp->fd, IXJCTL_PORT, PORT_PSTN))
- ast_log(LOG_DEBUG, "Unable to set port to PSTN\n");
- } else {
- if (ioctl(tmp->fd, IXJCTL_PORT, PORT_POTS))
- if (mode != MODE_FXS)
- ast_log(LOG_DEBUG, "Unable to set port to POTS\n");
- }
- ioctl(tmp->fd, PHONE_PLAY_STOP);
- ioctl(tmp->fd, PHONE_REC_STOP);
- ioctl(tmp->fd, PHONE_RING_STOP);
- ioctl(tmp->fd, PHONE_CPT_STOP);
- if (ioctl(tmp->fd, PHONE_PSTN_SET_STATE, PSTN_ON_HOOK))
- ast_log(LOG_DEBUG, "ioctl(PHONE_PSTN_SET_STATE) failed on %s (%s)\n",iface, strerror(errno));
- if (echocancel != AEC_OFF)
- ioctl(tmp->fd, IXJCTL_AEC_START, echocancel);
- if (silencesupression)
- tmp->silencesupression = 1;
-#ifdef PHONE_VAD
- ioctl(tmp->fd, PHONE_VAD, tmp->silencesupression);
-#endif
- tmp->mode = mode;
- flags = fcntl(tmp->fd, F_GETFL);
- fcntl(tmp->fd, F_SETFL, flags | O_NONBLOCK);
- tmp->owner = NULL;
- tmp->lastformat = -1;
- tmp->lastinput = -1;
- tmp->ministate = 0;
- memset(tmp->ext, 0, sizeof(tmp->ext));
- ast_copy_string(tmp->language, language, sizeof(tmp->language));
- ast_copy_string(tmp->dev, iface, sizeof(tmp->dev));
- ast_copy_string(tmp->context, context, sizeof(tmp->context));
- tmp->next = NULL;
- tmp->obuflen = 0;
- tmp->dialtone = 0;
- tmp->cpt = 0;
- ast_copy_string(tmp->cid_num, cid_num, sizeof(tmp->cid_num));
- ast_copy_string(tmp->cid_name, cid_name, sizeof(tmp->cid_name));
- tmp->txgain = txgain;
- ioctl(tmp->fd, PHONE_PLAY_VOLUME, tmp->txgain);
- tmp->rxgain = rxgain;
- ioctl(tmp->fd, PHONE_REC_VOLUME, tmp->rxgain);
- }
- return tmp;
-}
-
-static struct ast_channel *phone_request(const char *type, int format, void *data, int *cause)
-{
- int oldformat;
- struct phone_pvt *p;
- struct ast_channel *tmp = NULL;
- char *name = data;
-
- /* Search for an unowned channel */
- if (ast_mutex_lock(&iflock)) {
- ast_log(LOG_ERROR, "Unable to lock interface list???\n");
- return NULL;
- }
- p = iflist;
- while(p) {
- if (p->mode == MODE_FXS ||
- format & (AST_FORMAT_G723_1 | AST_FORMAT_SLINEAR | AST_FORMAT_ULAW)) {
- size_t length = strlen(p->dev + 5);
- if (strncmp(name, p->dev + 5, length) == 0 &&
- !isalnum(name[length])) {
- if (!p->owner) {
- tmp = phone_new(p, AST_STATE_DOWN, p->context);
- break;
- } else
- *cause = AST_CAUSE_BUSY;
- }
- }
- p = p->next;
- }
- ast_mutex_unlock(&iflock);
- restart_monitor();
- if (tmp == NULL) {
- oldformat = format;
- format &= (AST_FORMAT_G723_1 | AST_FORMAT_SLINEAR | AST_FORMAT_ULAW);
- if (!format) {
- ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", oldformat);
- return NULL;
- }
- }
- return tmp;
-}
-
-/* parse gain value from config file */
-static int parse_gain_value(char *gain_type, char *value)
-{
- float gain;
-
- /* try to scan number */
- if (sscanf(value, "%f", &gain) != 1)
- {
- ast_log(LOG_ERROR, "Invalid %s value '%s' in '%s' config\n",
- value, gain_type, config);
- return DEFAULT_GAIN;
- }
-
- /* multiplicate gain by 1.0 gain value */
- gain = gain * (float)DEFAULT_GAIN;
-
- /* percentage? */
- if (value[strlen(value) - 1] == '%')
- return (int)(gain / (float)100);
-
- return (int)gain;
-}
-
-static int __unload_module(void)
-{
- struct phone_pvt *p, *pl;
- /* First, take us out of the channel loop */
- if (cur_tech)
- ast_channel_unregister(cur_tech);
- if (!ast_mutex_lock(&iflock)) {
- /* Hangup all interfaces if they have an owner */
- p = iflist;
- while(p) {
- if (p->owner)
- ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
- p = p->next;
- }
- iflist = NULL;
- ast_mutex_unlock(&iflock);
- } else {
- ast_log(LOG_WARNING, "Unable to lock the monitor\n");
- return -1;
- }
- if (!ast_mutex_lock(&monlock)) {
- if (monitor_thread > AST_PTHREADT_NULL) {
- monitor = 0;
- while (pthread_kill(monitor_thread, SIGURG) == 0)
- sched_yield();
- pthread_join(monitor_thread, NULL);
- }
- monitor_thread = AST_PTHREADT_STOP;
- ast_mutex_unlock(&monlock);
- } else {
- ast_log(LOG_WARNING, "Unable to lock the monitor\n");
- return -1;
- }
-
- if (!ast_mutex_lock(&iflock)) {
- /* Destroy all the interfaces and free their memory */
- p = iflist;
- while(p) {
- /* Close the socket, assuming it's real */
- if (p->fd > -1)
- close(p->fd);
- pl = p;
- p = p->next;
- /* Free associated memory */
- free(pl);
- }
- iflist = NULL;
- ast_mutex_unlock(&iflock);
- } else {
- ast_log(LOG_WARNING, "Unable to lock the monitor\n");
- return -1;
- }
-
- return 0;
-}
-
-static int unload_module(void)
-{
- return __unload_module();
-}
-
-static int load_module(void)
-{
- struct ast_config *cfg;
- struct ast_variable *v;
- struct phone_pvt *tmp;
- int mode = MODE_IMMEDIATE;
- int txgain = DEFAULT_GAIN, rxgain = DEFAULT_GAIN; /* default gain 1.0 */
- cfg = ast_config_load(config);
-
- /* We *must* have a config file otherwise stop immediately */
- if (!cfg) {
- ast_log(LOG_ERROR, "Unable to load config %s\n", config);
- return AST_MODULE_LOAD_DECLINE;
- }
- if (ast_mutex_lock(&iflock)) {
- /* It's a little silly to lock it, but we mind as well just to be sure */
- ast_log(LOG_ERROR, "Unable to lock interface list???\n");
- return AST_MODULE_LOAD_FAILURE;
- }
- v = ast_variable_browse(cfg, "interfaces");
- while(v) {
- /* Create the interface list */
- if (!strcasecmp(v->name, "device")) {
- tmp = mkif(v->value, mode, txgain, rxgain);
- if (tmp) {
- tmp->next = iflist;
- iflist = tmp;
-
- } else {
- ast_log(LOG_ERROR, "Unable to register channel '%s'\n", v->value);
- ast_config_destroy(cfg);
- ast_mutex_unlock(&iflock);
- __unload_module();
- return AST_MODULE_LOAD_FAILURE;
- }
- } else if (!strcasecmp(v->name, "silencesupression")) {
- silencesupression = ast_true(v->value);
- } else if (!strcasecmp(v->name, "language")) {
- ast_copy_string(language, v->value, sizeof(language));
- } else if (!strcasecmp(v->name, "callerid")) {
- ast_callerid_split(v->value, cid_name, sizeof(cid_name), cid_num, sizeof(cid_num));
- } else if (!strcasecmp(v->name, "mode")) {
- if (!strncasecmp(v->value, "di", 2))
- mode = MODE_DIALTONE;
- else if (!strncasecmp(v->value, "sig", 3))
- mode = MODE_SIGMA;
- else if (!strncasecmp(v->value, "im", 2))
- mode = MODE_IMMEDIATE;
- else if (!strncasecmp(v->value, "fxs", 3)) {
- mode = MODE_FXS;
- prefformat = 0x01ff0000; /* All non-voice */
- }
- else if (!strncasecmp(v->value, "fx", 2))
- mode = MODE_FXO;
- else
- ast_log(LOG_WARNING, "Unknown mode: %s\n", v->value);
- } else if (!strcasecmp(v->name, "context")) {
- ast_copy_string(context, v->value, sizeof(context));
- } else if (!strcasecmp(v->name, "format")) {
- if (!strcasecmp(v->value, "g723.1")) {
- prefformat = AST_FORMAT_G723_1;
- } else if (!strcasecmp(v->value, "slinear")) {
- if (mode == MODE_FXS)
- prefformat |= AST_FORMAT_SLINEAR;
- else prefformat = AST_FORMAT_SLINEAR;
- } else if (!strcasecmp(v->value, "ulaw")) {
- prefformat = AST_FORMAT_ULAW;
- } else
- ast_log(LOG_WARNING, "Unknown format '%s'\n", v->value);
- } else if (!strcasecmp(v->name, "echocancel")) {
- if (!strcasecmp(v->value, "off")) {
- echocancel = AEC_OFF;
- } else if (!strcasecmp(v->value, "low")) {
- echocancel = AEC_LOW;
- } else if (!strcasecmp(v->value, "medium")) {
- echocancel = AEC_MED;
- } else if (!strcasecmp(v->value, "high")) {
- echocancel = AEC_HIGH;
- } else
- ast_log(LOG_WARNING, "Unknown echo cancellation '%s'\n", v->value);
- } else if (!strcasecmp(v->name, "txgain")) {
- txgain = parse_gain_value(v->name, v->value);
- } else if (!strcasecmp(v->name, "rxgain")) {
- rxgain = parse_gain_value(v->name, v->value);
- }
- v = v->next;
- }
- ast_mutex_unlock(&iflock);
-
- if (mode == MODE_FXS) {
- phone_tech_fxs.capabilities = prefformat;
- cur_tech = &phone_tech_fxs;
- } else
- cur_tech = (struct ast_channel_tech *) &phone_tech;
-
- /* Make sure we can register our Adtranphone channel type */
-
- if (ast_channel_register(cur_tech)) {
- ast_log(LOG_ERROR, "Unable to register channel class 'Phone'\n");
- ast_config_destroy(cfg);
- __unload_module();
- return AST_MODULE_LOAD_FAILURE;
- }
- ast_config_destroy(cfg);
- /* And start the monitor for the first time */
- restart_monitor();
- return AST_MODULE_LOAD_SUCCESS;
-}
-
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Linux Telephony API Support");
diff --git a/1.4.23-rc4/channels/chan_sip.c b/1.4.23-rc4/channels/chan_sip.c
deleted file mode 100644
index 004aaaabe..000000000
--- a/1.4.23-rc4/channels/chan_sip.c
+++ /dev/null
@@ -1,18893 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 1999 - 2006, Digium, Inc.
- *
- * Mark Spencer <markster@digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*!
- * \file
- * \brief Implementation of Session Initiation Protocol
- *
- * \author Mark Spencer <markster@digium.com>
- *
- * See Also:
- * \arg \ref AstCREDITS
- *
- * Implementation of RFC 3261 - without S/MIME, TCP and TLS support
- * Configuration file \link Config_sip sip.conf \endlink
- *
- *
- * \todo SIP over TCP
- * \todo SIP over TLS
- * \todo Better support of forking
- * \todo VIA branch tag transaction checking
- * \todo Transaction support
- *
- * \ingroup channel_drivers
- *
- * \par Overview of the handling of SIP sessions
- * The SIP channel handles several types of SIP sessions, or dialogs,
- * not all of them being "telephone calls".
- * - Incoming calls that will be sent to the PBX core
- * - Outgoing calls, generated by the PBX
- * - SIP subscriptions and notifications of states and voicemail messages
- * - SIP registrations, both inbound and outbound
- * - SIP peer management (peerpoke, OPTIONS)
- * - SIP text messages
- *
- * In the SIP channel, there's a list of active SIP dialogs, which includes
- * all of these when they are active. "sip show channels" in the CLI will
- * show most of these, excluding subscriptions which are shown by
- * "sip show subscriptions"
- *
- * \par incoming packets
- * Incoming packets are received in the monitoring thread, then handled by
- * sipsock_read(). This function parses the packet and matches an existing
- * dialog or starts a new SIP dialog.
- *
- * sipsock_read sends the packet to handle_request(), that parses a bit more.
- * if it's a response to an outbound request, it's sent to handle_response().
- * If it is a request, handle_request sends it to one of a list of functions
- * depending on the request type - INVITE, OPTIONS, REFER, BYE, CANCEL etc
- * sipsock_read locks the ast_channel if it exists (an active call) and
- * unlocks it after we have processed the SIP message.
- *
- * A new INVITE is sent to handle_request_invite(), that will end up
- * starting a new channel in the PBX, the new channel after that executing
- * in a separate channel thread. This is an incoming "call".
- * When the call is answered, either by a bridged channel or the PBX itself
- * the sip_answer() function is called.
- *
- * The actual media - Video or Audio - is mostly handled by the RTP subsystem
- * in rtp.c
- *
- * \par Outbound calls
- * Outbound calls are set up by the PBX through the sip_request_call()
- * function. After that, they are activated by sip_call().
- *
- * \par Hanging up
- * The PBX issues a hangup on both incoming and outgoing calls through
- * the sip_hangup() function
- *
- * \par Deprecated stuff
- * This is deprecated and will be removed after the 1.4 release
- * - the SIPUSERAGENT dialplan variable
- * - the ALERT_INFO dialplan variable
- */
-
-/*** MODULEINFO
- <depend>res_features</depend>
- ***/
-
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
-#include <stdio.h>
-#include <ctype.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <net/if.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <netdb.h>
-#include <signal.h>
-#include <sys/signal.h>
-#include <netinet/in.h>
-#include <netinet/in_systm.h>
-#include <arpa/inet.h>
-#include <netinet/ip.h>
-#include <regex.h>
-
-#include "asterisk/lock.h"
-#include "asterisk/channel.h"
-#include "asterisk/config.h"
-#include "asterisk/logger.h"
-#include "asterisk/module.h"
-#include "asterisk/pbx.h"
-#include "asterisk/options.h"
-#include "asterisk/sched.h"
-#include "asterisk/io.h"
-#include "asterisk/rtp.h"
-#include "asterisk/udptl.h"
-#include "asterisk/acl.h"
-#include "asterisk/manager.h"
-#include "asterisk/callerid.h"
-#include "asterisk/cli.h"
-#include "asterisk/app.h"
-#include "asterisk/musiconhold.h"
-#include "asterisk/dsp.h"
-#include "asterisk/features.h"
-#include "asterisk/srv.h"
-#include "asterisk/astdb.h"
-#include "asterisk/causes.h"
-#include "asterisk/utils.h"
-#include "asterisk/file.h"
-#include "asterisk/astobj.h"
-#include "asterisk/devicestate.h"
-#include "asterisk/linkedlists.h"
-#include "asterisk/stringfields.h"
-#include "asterisk/monitor.h"
-#include "asterisk/localtime.h"
-#include "asterisk/abstract_jb.h"
-#include "asterisk/compiler.h"
-#include "asterisk/threadstorage.h"
-#include "asterisk/translate.h"
-
-#ifndef FALSE
-#define FALSE 0
-#endif
-
-#ifndef TRUE
-#define TRUE 1
-#endif
-
-#define SIPBUFSIZE 512
-
-#define XMIT_ERROR -2
-
-#define VIDEO_CODEC_MASK 0x1fc0000 /*!< Video codecs from H.261 thru AST_FORMAT_MAX_VIDEO */
-#ifndef IPTOS_MINCOST
-#define IPTOS_MINCOST 0x02
-#endif
-
-/* #define VOCAL_DATA_HACK */
-
-#define DEFAULT_DEFAULT_EXPIRY 120
-#define DEFAULT_MIN_EXPIRY 60
-#define DEFAULT_MAX_EXPIRY 3600
-#define DEFAULT_REGISTRATION_TIMEOUT 20
-#define DEFAULT_MAX_FORWARDS "70"
-
-/* guard limit must be larger than guard secs */
-/* guard min must be < 1000, and should be >= 250 */
-#define EXPIRY_GUARD_SECS 15 /*!< How long before expiry do we reregister */
-#define EXPIRY_GUARD_LIMIT 30 /*!< Below here, we use EXPIRY_GUARD_PCT instead of
- EXPIRY_GUARD_SECS */
-#define EXPIRY_GUARD_MIN 500 /*!< This is the minimum guard time applied. If
- GUARD_PCT turns out to be lower than this, it
- will use this time instead.
- This is in milliseconds. */
-#define EXPIRY_GUARD_PCT 0.20 /*!< Percentage of expires timeout to use when
- below EXPIRY_GUARD_LIMIT */
-#define DEFAULT_EXPIRY 900 /*!< Expire slowly */
-
-static int min_expiry = DEFAULT_MIN_EXPIRY; /*!< Minimum accepted registration time */
-static int max_expiry = DEFAULT_MAX_EXPIRY; /*!< Maximum accepted registration time */
-static int default_expiry = DEFAULT_DEFAULT_EXPIRY;
-static int expiry = DEFAULT_EXPIRY;
-
-#ifndef MAX
-#define MAX(a,b) ((a) > (b) ? (a) : (b))
-#endif
-
-#define CALLERID_UNKNOWN "Unknown"
-
-#define DEFAULT_MAXMS 2000 /*!< Qualification: Must be faster than 2 seconds by default */
-#define DEFAULT_FREQ_OK 60 * 1000 /*!< Qualification: How often to check for the host to be up */
-#define DEFAULT_FREQ_NOTOK 10 * 1000 /*!< Qualification: How often to check, if the host is down... */
-
-#define DEFAULT_RETRANS 1000 /*!< How frequently to retransmit Default: 2 * 500 ms in RFC 3261 */
-#define MAX_RETRANS 6 /*!< Try only 6 times for retransmissions, a total of 7 transmissions */
-#define SIP_TRANS_TIMEOUT 32000 /*!< SIP request timeout (rfc 3261) 64*T1
- \todo Use known T1 for timeout (peerpoke)
- */
-#define DEFAULT_TRANS_TIMEOUT -1 /* Use default SIP transaction timeout */
-#define MAX_AUTHTRIES 3 /*!< Try authentication three times, then fail */
-
-#define SIP_MAX_HEADERS 64 /*!< Max amount of SIP headers to read */
-#define SIP_MAX_LINES 64 /*!< Max amount of lines in SIP attachment (like SDP) */
-#define SIP_MAX_PACKET 4096 /*!< Also from RFC 3261 (2543), should sub headers tho */
-
-#define SDP_MAX_RTPMAP_CODECS 32 /*!< Maximum number of codecs allowed in received SDP */
-
-#define INITIAL_CSEQ 101 /*!< our initial sip sequence number */
-
-/*! \brief Global jitterbuffer configuration - by default, jb is disabled */
-static struct ast_jb_conf default_jbconf =
-{
- .flags = 0,
- .max_size = -1,
- .resync_threshold = -1,
- .impl = ""
-};
-static struct ast_jb_conf global_jbconf;
-
-static const char config[] = "sip.conf";
-static const char notify_config[] = "sip_notify.conf";
-
-#define RTP 1
-#define NO_RTP 0
-
-/*! \brief Authorization scheme for call transfers
-\note Not a bitfield flag, since there are plans for other modes,
- like "only allow transfers for authenticated devices" */
-enum transfermodes {
- TRANSFER_OPENFORALL, /*!< Allow all SIP transfers */
- TRANSFER_CLOSED, /*!< Allow no SIP transfers */
-};
-
-
-enum sip_result {
- AST_SUCCESS = 0,
- AST_FAILURE = -1,
-};
-
-/*! \brief States for the INVITE transaction, not the dialog
- \note this is for the INVITE that sets up the dialog
-*/
-enum invitestates {
- INV_NONE = 0, /*!< No state at all, maybe not an INVITE dialog */
- INV_CALLING = 1, /*!< Invite sent, no answer */
- INV_PROCEEDING = 2, /*!< We got/sent 1xx message */
- INV_EARLY_MEDIA = 3, /*!< We got/sent 18x message with to-tag back */
- INV_COMPLETED = 4, /*!< Got final response with error. Wait for ACK, then CONFIRMED */
- INV_CONFIRMED = 5, /*!< Confirmed response - we've got an ack (Incoming calls only) */
- INV_TERMINATED = 6, /*!< Transaction done - either successful (AST_STATE_UP) or failed, but done
- The only way out of this is a BYE from one side */
- INV_CANCELLED = 7, /*!< Transaction cancelled by client or server in non-terminated state */
-};
-
-/* Do _NOT_ make any changes to this enum, or the array following it;
- if you think you are doing the right thing, you are probably
- not doing the right thing. If you think there are changes
- needed, get someone else to review them first _before_
- submitting a patch. If these two lists do not match properly
- bad things will happen.
-*/
-
-enum xmittype {
- XMIT_CRITICAL = 2, /*!< Transmit critical SIP message reliably, with re-transmits.
- If it fails, it's critical and will cause a teardown of the session */
- XMIT_RELIABLE = 1, /*!< Transmit SIP message reliably, with re-transmits */
- XMIT_UNRELIABLE = 0, /*!< Transmit SIP message without bothering with re-transmits */
-};
-
-enum parse_register_result {
- PARSE_REGISTER_FAILED,
- PARSE_REGISTER_UPDATE,
- PARSE_REGISTER_QUERY,
-};
-
-enum subscriptiontype {
- NONE = 0,
- XPIDF_XML,
- DIALOG_INFO_XML,
- CPIM_PIDF_XML,
- PIDF_XML,
- MWI_NOTIFICATION
-};
-
-static const struct cfsubscription_types {
- enum subscriptiontype type;
- const char * const event;
- const char * const mediatype;
- const char * const text;
-} subscription_types[] = {
- { NONE, "-", "unknown", "unknown" },
- /* RFC 4235: SIP Dialog event package */
- { DIALOG_INFO_XML, "dialog", "application/dialog-info+xml", "dialog-info+xml" },
- { CPIM_PIDF_XML, "presence", "application/cpim-pidf+xml", "cpim-pidf+xml" }, /* RFC 3863 */
- { PIDF_XML, "presence", "application/pidf+xml", "pidf+xml" }, /* RFC 3863 */
- { XPIDF_XML, "presence", "application/xpidf+xml", "xpidf+xml" }, /* Pre-RFC 3863 with MS additions */
- { MWI_NOTIFICATION, "message-summary", "application/simple-message-summary", "mwi" } /* RFC 3842: Mailbox notification */
-};
-
-/*! \brief SIP Request methods known by Asterisk */
-enum sipmethod {
- SIP_UNKNOWN, /* Unknown response */
- SIP_RESPONSE, /* Not request, response to outbound request */
- SIP_REGISTER,
- SIP_OPTIONS,
- SIP_NOTIFY,
- SIP_INVITE,
- SIP_ACK,
- SIP_PRACK, /* Not supported at all */
- SIP_BYE,
- SIP_REFER,
- SIP_SUBSCRIBE,
- SIP_MESSAGE,
- SIP_UPDATE, /* We can send UPDATE; but not accept it */
- SIP_INFO,
- SIP_CANCEL,
- SIP_PUBLISH, /* Not supported at all */
- SIP_PING, /* Not supported at all, no standard but still implemented out there */
-};
-
-/*! \brief Authentication types - proxy or www authentication
- \note Endpoints, like Asterisk, should always use WWW authentication to
- allow multiple authentications in the same call - to the proxy and
- to the end point.
-*/
-enum sip_auth_type {
- PROXY_AUTH,
- WWW_AUTH,
-};
-
-/*! \brief Authentication result from check_auth* functions */
-enum check_auth_result {
- AUTH_SUCCESSFUL = 0,
- AUTH_CHALLENGE_SENT = 1,
- AUTH_SECRET_FAILED = -1,
- AUTH_USERNAME_MISMATCH = -2,
- AUTH_NOT_FOUND = -3,
- AUTH_FAKE_AUTH = -4,
- AUTH_UNKNOWN_DOMAIN = -5,
- AUTH_PEER_NOT_DYNAMIC = -6,
- AUTH_ACL_FAILED = -7,
-};
-
-/*! \brief States for outbound registrations (with register= lines in sip.conf */
-enum sipregistrystate {
- REG_STATE_UNREGISTERED = 0, /*!< We are not registred */
- REG_STATE_REGSENT, /*!< Registration request sent */
- REG_STATE_AUTHSENT, /*!< We have tried to authenticate */
- REG_STATE_REGISTERED, /*!< Registred and done */
- REG_STATE_REJECTED, /*!< Registration rejected */
- REG_STATE_TIMEOUT, /*!< Registration timed out */
- REG_STATE_NOAUTH, /*!< We have no accepted credentials */
- REG_STATE_FAILED, /*!< Registration failed after several tries */
-};
-
-#define CAN_NOT_CREATE_DIALOG 0
-#define CAN_CREATE_DIALOG 1
-#define CAN_CREATE_DIALOG_UNSUPPORTED_METHOD 2
-
-/*! XXX Note that sip_methods[i].id == i must hold or the code breaks */
-static const struct cfsip_methods {
- enum sipmethod id;
- int need_rtp; /*!< when this is the 'primary' use for a pvt structure, does it need RTP? */
- char * const text;
- int can_create;
-} sip_methods[] = {
- { SIP_UNKNOWN, RTP, "-UNKNOWN-", CAN_CREATE_DIALOG },
- { SIP_RESPONSE, NO_RTP, "SIP/2.0", CAN_NOT_CREATE_DIALOG },
- { SIP_REGISTER, NO_RTP, "REGISTER", CAN_CREATE_DIALOG },
- { SIP_OPTIONS, NO_RTP, "OPTIONS", CAN_CREATE_DIALOG },
- { SIP_NOTIFY, NO_RTP, "NOTIFY", CAN_CREATE_DIALOG },
- { SIP_INVITE, RTP, "INVITE", CAN_CREATE_DIALOG },
- { SIP_ACK, NO_RTP, "ACK", CAN_NOT_CREATE_DIALOG },
- { SIP_PRACK, NO_RTP, "PRACK", CAN_NOT_CREATE_DIALOG },
- { SIP_BYE, NO_RTP, "BYE", CAN_NOT_CREATE_DIALOG },
- { SIP_REFER, NO_RTP, "REFER", CAN_CREATE_DIALOG },
- { SIP_SUBSCRIBE, NO_RTP, "SUBSCRIBE", CAN_CREATE_DIALOG },
- { SIP_MESSAGE, NO_RTP, "MESSAGE", CAN_CREATE_DIALOG },
- { SIP_UPDATE, NO_RTP, "UPDATE", CAN_NOT_CREATE_DIALOG },
- { SIP_INFO, NO_RTP, "INFO", CAN_NOT_CREATE_DIALOG },
- { SIP_CANCEL, NO_RTP, "CANCEL", CAN_NOT_CREATE_DIALOG },
- { SIP_PUBLISH, NO_RTP, "PUBLISH", CAN_CREATE_DIALOG_UNSUPPORTED_METHOD },
- { SIP_PING, NO_RTP, "PING", CAN_CREATE_DIALOG_UNSUPPORTED_METHOD }
-};
-
-/*! Define SIP option tags, used in Require: and Supported: headers
- We need to be aware of these properties in the phones to use
- the replace: header. We should not do that without knowing
- that the other end supports it...
- This is nothing we can configure, we learn by the dialog
- Supported: header on the REGISTER (peer) or the INVITE
- (other devices)
- We are not using many of these today, but will in the future.
- This is documented in RFC 3261
-*/
-#define SUPPORTED 1
-#define NOT_SUPPORTED 0
-
-#define SIP_OPT_REPLACES (1 << 0)
-#define SIP_OPT_100REL (1 << 1)
-#define SIP_OPT_TIMER (1 << 2)
-#define SIP_OPT_EARLY_SESSION (1 << 3)
-#define SIP_OPT_JOIN (1 << 4)
-#define SIP_OPT_PATH (1 << 5)
-#define SIP_OPT_PREF (1 << 6)
-#define SIP_OPT_PRECONDITION (1 << 7)
-#define SIP_OPT_PRIVACY (1 << 8)
-#define SIP_OPT_SDP_ANAT (1 << 9)
-#define SIP_OPT_SEC_AGREE (1 << 10)
-#define SIP_OPT_EVENTLIST (1 << 11)
-#define SIP_OPT_GRUU (1 << 12)
-#define SIP_OPT_TARGET_DIALOG (1 << 13)
-#define SIP_OPT_NOREFERSUB (1 << 14)
-#define SIP_OPT_HISTINFO (1 << 15)
-#define SIP_OPT_RESPRIORITY (1 << 16)
-
-/*! \brief List of well-known SIP options. If we get this in a require,
- we should check the list and answer accordingly. */
-static const struct cfsip_options {
- int id; /*!< Bitmap ID */
- int supported; /*!< Supported by Asterisk ? */
- char * const text; /*!< Text id, as in standard */
-} sip_options[] = { /* XXX used in 3 places */
- /* RFC3891: Replaces: header for transfer */
- { SIP_OPT_REPLACES, SUPPORTED, "replaces" },
- /* One version of Polycom firmware has the wrong label */
- { SIP_OPT_REPLACES, SUPPORTED, "replace" },
- /* RFC3262: PRACK 100% reliability */
- { SIP_OPT_100REL, NOT_SUPPORTED, "100rel" },
- /* RFC4028: SIP Session Timers */
- { SIP_OPT_TIMER, NOT_SUPPORTED, "timer" },
- /* RFC3959: SIP Early session support */
- { SIP_OPT_EARLY_SESSION, NOT_SUPPORTED, "early-session" },
- /* RFC3911: SIP Join header support */
- { SIP_OPT_JOIN, NOT_SUPPORTED, "join" },
- /* RFC3327: Path support */
- { SIP_OPT_PATH, NOT_SUPPORTED, "path" },
- /* RFC3840: Callee preferences */
- { SIP_OPT_PREF, NOT_SUPPORTED, "pref" },
- /* RFC3312: Precondition support */
- { SIP_OPT_PRECONDITION, NOT_SUPPORTED, "precondition" },
- /* RFC3323: Privacy with proxies*/
- { SIP_OPT_PRIVACY, NOT_SUPPORTED, "privacy" },
- /* RFC4092: Usage of the SDP ANAT Semantics in the SIP */
- { SIP_OPT_SDP_ANAT, NOT_SUPPORTED, "sdp-anat" },
- /* RFC3329: Security agreement mechanism */
- { SIP_OPT_SEC_AGREE, NOT_SUPPORTED, "sec_agree" },
- /* SIMPLE events: RFC4662 */
- { SIP_OPT_EVENTLIST, NOT_SUPPORTED, "eventlist" },
- /* GRUU: Globally Routable User Agent URI's */
- { SIP_OPT_GRUU, NOT_SUPPORTED, "gruu" },
- /* RFC4538: Target-dialog */
- { SIP_OPT_TARGET_DIALOG,NOT_SUPPORTED, "tdialog" },
- /* Disable the REFER subscription, RFC 4488 */
- { SIP_OPT_NOREFERSUB, NOT_SUPPORTED, "norefersub" },
- /* ietf-sip-history-info-06.txt */
- { SIP_OPT_HISTINFO, NOT_SUPPORTED, "histinfo" },
- /* ietf-sip-resource-priority-10.txt */
- { SIP_OPT_RESPRIORITY, NOT_SUPPORTED, "resource-priority" },
-};
-
-
-/*! \brief SIP Methods we support */
-#define ALLOWED_METHODS "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY"
-
-/*! \brief SIP Extensions we support */
-#define SUPPORTED_EXTENSIONS "replaces"
-
-/*! \brief Standard SIP port from RFC 3261. DO NOT CHANGE THIS */
-#define STANDARD_SIP_PORT 5060
-/* Note: in many SIP headers, absence of a port number implies port 5060,
- * and this is why we cannot change the above constant.
- * There is a limited number of places in asterisk where we could,
- * in principle, use a different "default" port number, but
- * we do not support this feature at the moment.
- */
-
-/* Default values, set and reset in reload_config before reading configuration */
-/* These are default values in the source. There are other recommended values in the
- sip.conf.sample for new installations. These may differ to keep backwards compatibility,
- yet encouraging new behaviour on new installations
- */
-#define DEFAULT_CONTEXT "default"
-#define DEFAULT_MOHINTERPRET "default"
-#define DEFAULT_MOHSUGGEST ""
-#define DEFAULT_VMEXTEN "asterisk"
-#define DEFAULT_CALLERID "asterisk"
-#define DEFAULT_NOTIFYMIME "application/simple-message-summary"
-#define DEFAULT_MWITIME 10
-#define DEFAULT_ALLOWGUEST TRUE
-#define DEFAULT_SRVLOOKUP TRUE /*!< Recommended setting is ON */
-#define DEFAULT_COMPACTHEADERS FALSE
-#define DEFAULT_TOS_SIP 0 /*!< Call signalling packets should be marked as DSCP CS3, but the default is 0 to be compatible with previous versions. */
-#define DEFAULT_TOS_AUDIO 0 /*!< Audio packets should be marked as DSCP EF (Expedited Forwarding), but the default is 0 to be compatible with previous versions. */
-#define DEFAULT_TOS_VIDEO 0 /*!< Video packets should be marked as DSCP AF41, but the default is 0 to be compatible with previous versions. */
-#define DEFAULT_ALLOW_EXT_DOM TRUE
-#define DEFAULT_REALM "asterisk"
-#define DEFAULT_NOTIFYRINGING TRUE
-#define DEFAULT_PEDANTIC FALSE
-#define DEFAULT_AUTOCREATEPEER FALSE
-#define DEFAULT_QUALIFY FALSE
-#define DEFAULT_T1MIN 100 /*!< 100 MS for minimal roundtrip time */
-#define DEFAULT_MAX_CALL_BITRATE (384) /*!< Max bitrate for video */
-#ifndef DEFAULT_USERAGENT
-#define DEFAULT_USERAGENT "Asterisk PBX" /*!< Default Useragent: header unless re-defined in sip.conf */
-#endif
-
-
-/* Default setttings are used as a channel setting and as a default when
- configuring devices */
-static char default_context[AST_MAX_CONTEXT];
-static char default_subscribecontext[AST_MAX_CONTEXT];
-static char default_language[MAX_LANGUAGE];
-static char default_callerid[AST_MAX_EXTENSION];
-static char default_fromdomain[AST_MAX_EXTENSION];
-static char default_notifymime[AST_MAX_EXTENSION];
-static int default_qualify; /*!< Default Qualify= setting */
-static char default_vmexten[AST_MAX_EXTENSION];
-static char default_mohinterpret[MAX_MUSICCLASS]; /*!< Global setting for moh class to use when put on hold */
-static char default_mohsuggest[MAX_MUSICCLASS]; /*!< Global setting for moh class to suggest when putting
- * a bridged channel on hold */
-static int default_maxcallbitrate; /*!< Maximum bitrate for call */
-static struct ast_codec_pref default_prefs; /*!< Default codec prefs */
-
-/* Global settings only apply to the channel */
-static int global_directrtpsetup; /*!< Enable support for Direct RTP setup (no re-invites) */
-static int global_limitonpeers; /*!< Match call limit on peers only */
-static int global_rtautoclear;
-static int global_notifyringing; /*!< Send notifications on ringing */
-static int global_notifyhold; /*!< Send notifications on hold */
-static int global_alwaysauthreject; /*!< Send 401 Unauthorized for all failing requests */
-static int srvlookup; /*!< SRV Lookup on or off. Default is on */
-static int pedanticsipchecking; /*!< Extra checking ? Default off */
-static int autocreatepeer; /*!< Auto creation of peers at registration? Default off. */
-static int global_relaxdtmf; /*!< Relax DTMF */
-static int global_rtptimeout; /*!< Time out call if no RTP */
-static int global_rtpholdtimeout;
-static int global_rtpkeepalive; /*!< Send RTP keepalives */
-static int global_reg_timeout;
-static int global_regattempts_max; /*!< Registration attempts before giving up */
-static int global_allowguest; /*!< allow unauthenticated users/peers to connect? */
-static int global_allowsubscribe; /*!< Flag for disabling ALL subscriptions, this is FALSE only if all peers are FALSE
- the global setting is in globals_flags[1] */
-static int global_mwitime; /*!< Time between MWI checks for peers */
-static unsigned int global_tos_sip; /*!< IP type of service for SIP packets */
-static unsigned int global_tos_audio; /*!< IP type of service for audio RTP packets */
-static unsigned int global_tos_video; /*!< IP type of service for video RTP packets */
-static int compactheaders; /*!< send compact sip headers */
-static int recordhistory; /*!< Record SIP history. Off by default */
-static int dumphistory; /*!< Dump history to verbose before destroying SIP dialog */
-static char global_realm[MAXHOSTNAMELEN]; /*!< Default realm */
-static char global_regcontext[AST_MAX_CONTEXT]; /*!< Context for auto-extensions */
-static char global_useragent[AST_MAX_EXTENSION]; /*!< Useragent for the SIP channel */
-static int allow_external_domains; /*!< Accept calls to external SIP domains? */
-static int global_callevents; /*!< Whether we send manager events or not */
-static int global_t1min; /*!< T1 roundtrip time minimum */
-static int global_autoframing; /*!< Turn autoframing on or off. */
-static enum transfermodes global_allowtransfer; /*!< SIP Refer restriction scheme */
-
-static int global_matchexterniplocally; /*!< Match externip/externhost setting against localnet setting */
-
-/*! \brief Codecs that we support by default: */
-static int global_capability = AST_FORMAT_ULAW | AST_FORMAT_ALAW | AST_FORMAT_GSM | AST_FORMAT_H263;
-
-/*! \brief Global list of addresses dynamic peers are not allowed to use */
-static struct ast_ha *global_contact_ha = NULL;
-static int global_dynamic_exclude_static = 0;
-
-/* Object counters */
-static int suserobjs = 0; /*!< Static users */
-static int ruserobjs = 0; /*!< Realtime users */
-static int speerobjs = 0; /*!< Statis peers */
-static int rpeerobjs = 0; /*!< Realtime peers */
-static int apeerobjs = 0; /*!< Autocreated peer objects */
-static int regobjs = 0; /*!< Registry objects */
-
-static struct ast_flags global_flags[2] = {{0}}; /*!< global SIP_ flags */
-
-/*! \brief Protect the SIP dialog list (of sip_pvt's) */
-AST_MUTEX_DEFINE_STATIC(iflock);
-
-/*! \brief Protect the monitoring thread, so only one process can kill or start it, and not
- when it's doing something critical. */
-AST_MUTEX_DEFINE_STATIC(netlock);
-
-AST_MUTEX_DEFINE_STATIC(monlock);
-
-AST_MUTEX_DEFINE_STATIC(sip_reload_lock);
-
-/*! \brief This is the thread for the monitor which checks for input on the channels
- which are not currently in use. */
-static pthread_t monitor_thread = AST_PTHREADT_NULL;
-
-static int sip_reloading = FALSE; /*!< Flag for avoiding multiple reloads at the same time */
-static enum channelreloadreason sip_reloadreason; /*!< Reason for last reload/load of configuration */
-
-static struct sched_context *sched; /*!< The scheduling context */
-static struct io_context *io; /*!< The IO context */
-static int *sipsock_read_id; /*!< ID of IO entry for sipsock FD */
-
-#define DEC_CALL_LIMIT 0
-#define INC_CALL_LIMIT 1
-#define DEC_CALL_RINGING 2
-#define INC_CALL_RINGING 3
-
-/*! \brief sip_request: The data grabbed from the UDP socket */
-struct sip_request {
- char *rlPart1; /*!< SIP Method Name or "SIP/2.0" protocol version */
- char *rlPart2; /*!< The Request URI or Response Status */
- int len; /*!< Length */
- int headers; /*!< # of SIP Headers */
- int method; /*!< Method of this request */
- int lines; /*!< Body Content */
- unsigned int flags; /*!< SIP_PKT Flags for this packet */
- char *header[SIP_MAX_HEADERS];
- char *line[SIP_MAX_LINES];
- char data[SIP_MAX_PACKET];
- unsigned int sdp_start; /*!< the line number where the SDP begins */
- unsigned int sdp_end; /*!< the line number where the SDP ends */
- AST_LIST_ENTRY(sip_request) next;
-};
-
-/*
- * A sip packet is stored into the data[] buffer, with the header followed
- * by an empty line and the body of the message.
- * On outgoing packets, data is accumulated in data[] with len reflecting
- * the next available byte, headers and lines count the number of lines
- * in both parts. There are no '\0' in data[0..len-1].
- *
- * On received packet, the input read from the socket is copied into data[],
- * len is set and the string is NUL-terminated. Then a parser fills up
- * the other fields -header[] and line[] to point to the lines of the
- * message, rlPart1 and rlPart2 parse the first lnie as below:
- *
- * Requests have in the first line METHOD URI SIP/2.0
- * rlPart1 = method; rlPart2 = uri;
- * Responses have in the first line SIP/2.0 code description
- * rlPart1 = SIP/2.0; rlPart2 = code + description;
- *
- */
-
-/*! \brief structure used in transfers */
-struct sip_dual {
- struct ast_channel *chan1; /*!< First channel involved */
- struct ast_channel *chan2; /*!< Second channel involved */
- struct sip_request req; /*!< Request that caused the transfer (REFER) */
- int seqno; /*!< Sequence number */
-};
-
-struct sip_pkt;
-
-/*! \brief Parameters to the transmit_invite function */
-struct sip_invite_param {
- const char *distinctive_ring; /*!< Distinctive ring header */
- int addsipheaders; /*!< Add extra SIP headers */
- const char *uri_options; /*!< URI options to add to the URI */
- const char *vxml_url; /*!< VXML url for Cisco phones */
- char *auth; /*!< Authentication */
- char *authheader; /*!< Auth header */
- enum sip_auth_type auth_type; /*!< Authentication type */
- const char *replaces; /*!< Replaces header for call transfers */
- int transfer; /*!< Flag - is this Invite part of a SIP transfer? (invite/replaces) */
-};
-
-/*! \brief Structure to save routing information for a SIP session */
-struct sip_route {
- struct sip_route *next;
- char hop[0];
-};
-
-/*! \brief Modes for SIP domain handling in the PBX */
-enum domain_mode {
- SIP_DOMAIN_AUTO, /*!< This domain is auto-configured */
- SIP_DOMAIN_CONFIG, /*!< This domain is from configuration */
-};
-
-/*! \brief Domain data structure.
- \note In the future, we will connect this to a configuration tree specific
- for this domain
-*/
-struct domain {
- char domain[MAXHOSTNAMELEN]; /*!< SIP domain we are responsible for */
- char context[AST_MAX_EXTENSION]; /*!< Incoming context for this domain */
- enum domain_mode mode; /*!< How did we find this domain? */
- AST_LIST_ENTRY(domain) list; /*!< List mechanics */
-};
-
-static AST_LIST_HEAD_STATIC(domain_list, domain); /*!< The SIP domain list */
-
-
-/*! \brief sip_history: Structure for saving transactions within a SIP dialog */
-struct sip_history {
- AST_LIST_ENTRY(sip_history) list;
- char event[0]; /* actually more, depending on needs */
-};
-
-AST_LIST_HEAD_NOLOCK(sip_history_head, sip_history); /*!< history list, entry in sip_pvt */
-
-/*! \brief sip_auth: Credentials for authentication to other SIP services */
-struct sip_auth {
- char realm[AST_MAX_EXTENSION]; /*!< Realm in which these credentials are valid */
- char username[256]; /*!< Username */
- char secret[256]; /*!< Secret */
- char md5secret[256]; /*!< MD5Secret */
- struct sip_auth *next; /*!< Next auth structure in list */
-};
-
-/*--- Various flags for the flags field in the pvt structure */
-#define SIP_ALREADYGONE (1 << 0) /*!< Whether or not we've already been destroyed by our peer */
-#define SIP_NEEDDESTROY (1 << 1) /*!< if we need to be destroyed by the monitor thread */
-#define SIP_NOVIDEO (1 << 2) /*!< Didn't get video in invite, don't offer */
-#define SIP_RINGING (1 << 3) /*!< Have sent 180 ringing */
-#define SIP_PROGRESS_SENT (1 << 4) /*!< Have sent 183 message progress */
-#define SIP_NEEDREINVITE (1 << 5) /*!< Do we need to send another reinvite? */
-#define SIP_PENDINGBYE (1 << 6) /*!< Need to send bye after we ack? */
-#define SIP_GOTREFER (1 << 7) /*!< Got a refer? */
-#define SIP_PROMISCREDIR (1 << 8) /*!< Promiscuous redirection */
-#define SIP_TRUSTRPID (1 << 9) /*!< Trust RPID headers? */
-#define SIP_USEREQPHONE (1 << 10) /*!< Add user=phone to numeric URI. Default off */
-#define SIP_REALTIME (1 << 11) /*!< Flag for realtime users */
-#define SIP_USECLIENTCODE (1 << 12) /*!< Trust X-ClientCode info message */
-#define SIP_OUTGOING (1 << 13) /*!< Direction of the last transaction in this dialog */
-#define SIP_FREE_BIT (1 << 14) /*!< ---- */
-#define SIP_DEFER_BYE_ON_TRANSFER (1 << 15) /*!< Do not hangup at first ast_hangup */
-#define SIP_DTMF (3 << 16) /*!< DTMF Support: four settings, uses two bits */
-#define SIP_DTMF_RFC2833 (0 << 16) /*!< DTMF Support: RTP DTMF - "rfc2833" */
-#define SIP_DTMF_INBAND (1 << 16) /*!< DTMF Support: Inband audio, only for ULAW/ALAW - "inband" */
-#define SIP_DTMF_INFO (2 << 16) /*!< DTMF Support: SIP Info messages - "info" */
-#define SIP_DTMF_AUTO (3 << 16) /*!< DTMF Support: AUTO switch between rfc2833 and in-band DTMF */
-/* NAT settings */
-#define SIP_NAT (3 << 18) /*!< four settings, uses two bits */
-#define SIP_NAT_NEVER (0 << 18) /*!< No nat support */
-#define SIP_NAT_RFC3581 (1 << 18) /*!< NAT RFC3581 */
-#define SIP_NAT_ROUTE (2 << 18) /*!< NAT Only ROUTE */
-#define SIP_NAT_ALWAYS (3 << 18) /*!< NAT Both ROUTE and RFC3581 */
-/* re-INVITE related settings */
-#define SIP_REINVITE (7 << 20) /*!< three bits used */
-#define SIP_CAN_REINVITE (1 << 20) /*!< allow peers to be reinvited to send media directly p2p */
-#define SIP_CAN_REINVITE_NAT (2 << 20) /*!< allow media reinvite when new peer is behind NAT */
-#define SIP_REINVITE_UPDATE (4 << 20) /*!< use UPDATE (RFC3311) when reinviting this peer */
-/* "insecure" settings */
-#define SIP_INSECURE_PORT (1 << 23) /*!< don't require matching port for incoming requests */
-#define SIP_INSECURE_INVITE (1 << 24) /*!< don't require authentication for incoming INVITEs */
-/* Sending PROGRESS in-band settings */
-#define SIP_PROG_INBAND (3 << 25) /*!< three settings, uses two bits */
-#define SIP_PROG_INBAND_NEVER (0 << 25)
-#define SIP_PROG_INBAND_NO (1 << 25)
-#define SIP_PROG_INBAND_YES (2 << 25)
-#define SIP_NO_HISTORY (1 << 27) /*!< Suppress recording request/response history */
-#define SIP_CALL_LIMIT (1 << 28) /*!< Call limit enforced for this call */
-#define SIP_SENDRPID (1 << 29) /*!< Remote Party-ID Support */
-#define SIP_INC_COUNT (1 << 30) /*!< Did this connection increment the counter of in-use calls? */
-#define SIP_G726_NONSTANDARD (1 << 31) /*!< Use non-standard packing for G726-32 data */
-
-#define SIP_FLAGS_TO_COPY \
- (SIP_PROMISCREDIR | SIP_TRUSTRPID | SIP_SENDRPID | SIP_DTMF | SIP_REINVITE | \
- SIP_PROG_INBAND | SIP_USECLIENTCODE | SIP_NAT | SIP_G726_NONSTANDARD | \
- SIP_USEREQPHONE | SIP_INSECURE_PORT | SIP_INSECURE_INVITE)
-
-/*--- a new page of flags (for flags[1] */
-/* realtime flags */
-#define SIP_PAGE2_RTCACHEFRIENDS (1 << 0)
-#define SIP_PAGE2_RTUPDATE (1 << 1)
-#define SIP_PAGE2_RTAUTOCLEAR (1 << 2)
-#define SIP_PAGE2_RT_FROMCONTACT (1 << 4)
-#define SIP_PAGE2_RTSAVE_SYSNAME (1 << 5)
-/* Space for addition of other realtime flags in the future */
-#define SIP_PAGE2_STATECHANGEQUEUE (1 << 9) /*!< D: Unsent state pending change exists */
-#define SIP_PAGE2_IGNOREREGEXPIRE (1 << 10)
-#define SIP_PAGE2_DEBUG (3 << 11)
-#define SIP_PAGE2_DEBUG_CONFIG (1 << 11)
-#define SIP_PAGE2_DEBUG_CONSOLE (1 << 12)
-#define SIP_PAGE2_DYNAMIC (1 << 13) /*!< Dynamic Peers register with Asterisk */
-#define SIP_PAGE2_SELFDESTRUCT (1 << 14) /*!< Automatic peers need to destruct themselves */
-#define SIP_PAGE2_VIDEOSUPPORT (1 << 15)
-#define SIP_PAGE2_ALLOWSUBSCRIBE (1 << 16) /*!< Allow subscriptions from this peer? */
-#define SIP_PAGE2_ALLOWOVERLAP (1 << 17) /*!< Allow overlap dialing ? */
-#define SIP_PAGE2_SUBSCRIBEMWIONLY (1 << 18) /*!< Only issue MWI notification if subscribed to */
-#define SIP_PAGE2_INC_RINGING (1 << 19) /*!< Did this connection increment the counter of in-use calls? */
-#define SIP_PAGE2_T38SUPPORT (7 << 20) /*!< T38 Fax Passthrough Support */
-#define SIP_PAGE2_T38SUPPORT_UDPTL (1 << 20) /*!< 20: T38 Fax Passthrough Support */
-#define SIP_PAGE2_T38SUPPORT_RTP (2 << 20) /*!< 21: T38 Fax Passthrough Support (not implemented) */
-#define SIP_PAGE2_T38SUPPORT_TCP (4 << 20) /*!< 22: T38 Fax Passthrough Support (not implemented) */
-#define SIP_PAGE2_CALL_ONHOLD (3 << 23) /*!< Call states */
-#define SIP_PAGE2_CALL_ONHOLD_ACTIVE (1 << 23) /*!< 23: Active hold */
-#define SIP_PAGE2_CALL_ONHOLD_ONEDIR (2 << 23) /*!< 23: One directional hold */
-#define SIP_PAGE2_CALL_ONHOLD_INACTIVE (3 << 23) /*!< 23: Inactive hold */
-#define SIP_PAGE2_RFC2833_COMPENSATE (1 << 25) /*!< 25: ???? */
-#define SIP_PAGE2_BUGGY_MWI (1 << 26) /*!< 26: Buggy CISCO MWI fix */
-#define SIP_PAGE2_OUTGOING_CALL (1 << 27) /*!< 27: Is this an outgoing call? */
-#define SIP_PAGE2_UDPTL_DESTINATION (1 << 28) /*!< 28: Use source IP of RTP as destination if NAT is enabled */
-#define SIP_PAGE2_DIALOG_ESTABLISHED (1 << 29) /*!< 29: Has a dialog been established? */
-
-#define SIP_PAGE2_FLAGS_TO_COPY \
- (SIP_PAGE2_ALLOWSUBSCRIBE | SIP_PAGE2_ALLOWOVERLAP | SIP_PAGE2_VIDEOSUPPORT | \
- SIP_PAGE2_T38SUPPORT | SIP_PAGE2_RFC2833_COMPENSATE | SIP_PAGE2_BUGGY_MWI | SIP_PAGE2_UDPTL_DESTINATION)
-
-/* SIP packet flags */
-#define SIP_PKT_DEBUG (1 << 0) /*!< Debug this packet */
-#define SIP_PKT_WITH_TOTAG (1 << 1) /*!< This packet has a to-tag */
-#define SIP_PKT_IGNORE (1 << 2) /*!< This is a re-transmit, ignore it */
-#define SIP_PKT_IGNORE_RESP (1 << 3) /*!< Resp ignore - ??? */
-#define SIP_PKT_IGNORE_REQ (1 << 4) /*!< Req ignore - ??? */
-
-/* T.38 set of flags */
-#define T38FAX_FILL_BIT_REMOVAL (1 << 0) /*!< Default: 0 (unset)*/
-#define T38FAX_TRANSCODING_MMR (1 << 1) /*!< Default: 0 (unset)*/
-#define T38FAX_TRANSCODING_JBIG (1 << 2) /*!< Default: 0 (unset)*/
-/* Rate management */
-#define T38FAX_RATE_MANAGEMENT_TRANSFERED_TCF (0 << 3)
-#define T38FAX_RATE_MANAGEMENT_LOCAL_TCF (1 << 3) /*!< Unset for transferredTCF (UDPTL), set for localTCF (TPKT) */
-/* UDP Error correction */
-#define T38FAX_UDP_EC_NONE (0 << 4) /*!< two bits, if unset NO t38UDPEC field in T38 SDP*/
-#define T38FAX_UDP_EC_FEC (1 << 4) /*!< Set for t38UDPFEC */
-#define T38FAX_UDP_EC_REDUNDANCY (2 << 4) /*!< Set for t38UDPRedundancy */
-/* T38 Spec version */
-#define T38FAX_VERSION (3 << 6) /*!< two bits, 2 values so far, up to 4 values max */
-#define T38FAX_VERSION_0 (0 << 6) /*!< Version 0 */
-#define T38FAX_VERSION_1 (1 << 6) /*!< Version 1 */
-/* Maximum Fax Rate */
-#define T38FAX_RATE_2400 (1 << 8) /*!< 2400 bps t38FaxRate */
-#define T38FAX_RATE_4800 (1 << 9) /*!< 4800 bps t38FaxRate */
-#define T38FAX_RATE_7200 (1 << 10) /*!< 7200 bps t38FaxRate */
-#define T38FAX_RATE_9600 (1 << 11) /*!< 9600 bps t38FaxRate */
-#define T38FAX_RATE_12000 (1 << 12) /*!< 12000 bps t38FaxRate */
-#define T38FAX_RATE_14400 (1 << 13) /*!< 14400 bps t38FaxRate */
-
-/*!< This is default: NO MMR and JBIG trancoding, NO fill bit removal, transferredTCF TCF, UDP FEC, Version 0 and 9600 max fax rate */
-static int global_t38_capability = T38FAX_VERSION_0 | T38FAX_RATE_2400 | T38FAX_RATE_4800 | T38FAX_RATE_7200 | T38FAX_RATE_9600;
-
-#define sipdebug ast_test_flag(&global_flags[1], SIP_PAGE2_DEBUG)
-#define sipdebug_config ast_test_flag(&global_flags[1], SIP_PAGE2_DEBUG_CONFIG)
-#define sipdebug_console ast_test_flag(&global_flags[1], SIP_PAGE2_DEBUG_CONSOLE)
-
-/*! \brief T38 States for a call */
-enum t38state {
- T38_DISABLED = 0, /*!< Not enabled */
- T38_LOCAL_DIRECT, /*!< Offered from local */
- T38_LOCAL_REINVITE, /*!< Offered from local - REINVITE */
- T38_PEER_DIRECT, /*!< Offered from peer */
- T38_PEER_REINVITE, /*!< Offered from peer - REINVITE */
- T38_ENABLED /*!< Negotiated (enabled) */
-};
-
-/*! \brief T.38 channel settings (at some point we need to make this alloc'ed */
-struct t38properties {
- struct ast_flags t38support; /*!< Flag for udptl, rtp or tcp support for this session */
- int capability; /*!< Our T38 capability */
- int peercapability; /*!< Peers T38 capability */
- int jointcapability; /*!< Supported T38 capability at both ends */
- enum t38state state; /*!< T.38 state */
-};
-
-/*! \brief Parameters to know status of transfer */
-enum referstatus {
- REFER_IDLE, /*!< No REFER is in progress */
- REFER_SENT, /*!< Sent REFER to transferee */
- REFER_RECEIVED, /*!< Received REFER from transferer */
- REFER_CONFIRMED, /*!< Refer confirmed with a 100 TRYING */
- REFER_ACCEPTED, /*!< Accepted by transferee */
- REFER_RINGING, /*!< Target Ringing */
- REFER_200OK, /*!< Answered by transfer target */
- REFER_FAILED, /*!< REFER declined - go on */
- REFER_NOAUTH /*!< We had no auth for REFER */
-};
-
-static const struct c_referstatusstring {
- enum referstatus status;
- char *text;
-} referstatusstrings[] = {
- { REFER_IDLE, "<none>" },
- { REFER_SENT, "Request sent" },
- { REFER_RECEIVED, "Request received" },
- { REFER_ACCEPTED, "Accepted" },
- { REFER_RINGING, "Target ringing" },
- { REFER_200OK, "Done" },
- { REFER_FAILED, "Failed" },
- { REFER_NOAUTH, "Failed - auth failure" }
-} ;
-
-/*! \brief Structure to handle SIP transfers. Dynamically allocated when needed */
-/* OEJ: Should be moved to string fields */
-struct sip_refer {
- char refer_to[AST_MAX_EXTENSION]; /*!< Place to store REFER-TO extension */
- char refer_to_domain[AST_MAX_EXTENSION]; /*!< Place to store REFER-TO domain */
- char refer_to_urioption[AST_MAX_EXTENSION]; /*!< Place to store REFER-TO uri options */
- char refer_to_context[AST_MAX_EXTENSION]; /*!< Place to store REFER-TO context */
- char referred_by[AST_MAX_EXTENSION]; /*!< Place to store REFERRED-BY extension */
- char referred_by_name[AST_MAX_EXTENSION]; /*!< Place to store REFERRED-BY extension */
- char refer_contact[AST_MAX_EXTENSION]; /*!< Place to store Contact info from a REFER extension */
- char replaces_callid[SIPBUFSIZE]; /*!< Replace info: callid */
- char replaces_callid_totag[SIPBUFSIZE/2]; /*!< Replace info: to-tag */
- char replaces_callid_fromtag[SIPBUFSIZE/2]; /*!< Replace info: from-tag */
- struct sip_pvt *refer_call; /*!< Call we are referring */
- int attendedtransfer; /*!< Attended or blind transfer? */
- int localtransfer; /*!< Transfer to local domain? */
- enum referstatus status; /*!< REFER status */
-};
-
-/*! \brief sip_pvt: PVT structures are used for each SIP dialog, ie. a call, a registration, a subscribe */
-static struct sip_pvt {
- ast_mutex_t lock; /*!< Dialog private lock */
- int method; /*!< SIP method that opened this dialog */
- enum invitestates invitestate; /*!< The state of the INVITE transaction only */
- AST_DECLARE_STRING_FIELDS(
- AST_STRING_FIELD(callid); /*!< Global CallID */
- AST_STRING_FIELD(randdata); /*!< Random data */
- AST_STRING_FIELD(accountcode); /*!< Account code */
- AST_STRING_FIELD(realm); /*!< Authorization realm */
- AST_STRING_FIELD(nonce); /*!< Authorization nonce */
- AST_STRING_FIELD(opaque); /*!< Opaque nonsense */
- AST_STRING_FIELD(qop); /*!< Quality of Protection, since SIP wasn't complicated enough yet. */
- AST_STRING_FIELD(domain); /*!< Authorization domain */
- AST_STRING_FIELD(from); /*!< The From: header */
- AST_STRING_FIELD(useragent); /*!< User agent in SIP request */
- AST_STRING_FIELD(exten); /*!< Extension where to start */
- AST_STRING_FIELD(context); /*!< Context for this call */
- AST_STRING_FIELD(subscribecontext); /*!< Subscribecontext */
- AST_STRING_FIELD(subscribeuri); /*!< Subscribecontext */
- AST_STRING_FIELD(fromdomain); /*!< Domain to show in the from field */
- AST_STRING_FIELD(fromuser); /*!< User to show in the user field */
- AST_STRING_FIELD(fromname); /*!< Name to show in the user field */
- AST_STRING_FIELD(tohost); /*!< Host we should put in the "to" field */
- AST_STRING_FIELD(language); /*!< Default language for this call */
- AST_STRING_FIELD(mohinterpret); /*!< MOH class to use when put on hold */
- AST_STRING_FIELD(mohsuggest); /*!< MOH class to suggest when putting a peer on hold */
- AST_STRING_FIELD(rdnis); /*!< Referring DNIS */
- AST_STRING_FIELD(theirtag); /*!< Their tag */
- AST_STRING_FIELD(username); /*!< [user] name */
- AST_STRING_FIELD(peername); /*!< [peer] name, not set if [user] */
- AST_STRING_FIELD(authname); /*!< Who we use for authentication */
- AST_STRING_FIELD(uri); /*!< Original requested URI */
- AST_STRING_FIELD(okcontacturi); /*!< URI from the 200 OK on INVITE */
- AST_STRING_FIELD(peersecret); /*!< Password */
- AST_STRING_FIELD(peermd5secret);
- AST_STRING_FIELD(cid_num); /*!< Caller*ID number */
- AST_STRING_FIELD(cid_name); /*!< Caller*ID name */
- AST_STRING_FIELD(via); /*!< Via: header */
- AST_STRING_FIELD(fullcontact); /*!< The Contact: that the UA registers with us */
- AST_STRING_FIELD(our_contact); /*!< Our contact header */
- AST_STRING_FIELD(rpid); /*!< Our RPID header */
- AST_STRING_FIELD(rpid_from); /*!< Our RPID From header */
- );
- unsigned int ocseq; /*!< Current outgoing seqno */
- unsigned int icseq; /*!< Current incoming seqno */
- ast_group_t callgroup; /*!< Call group */
- ast_group_t pickupgroup; /*!< Pickup group */
- int lastinvite; /*!< Last Cseq of invite */
- int lastnoninvite; /*!< Last Cseq of non-invite */
- struct ast_flags flags[2]; /*!< SIP_ flags */
- int timer_t1; /*!< SIP timer T1, ms rtt */
- unsigned int sipoptions; /*!< Supported SIP options on the other end */
- struct ast_codec_pref prefs; /*!< codec prefs */
- int capability; /*!< Special capability (codec) */
- int jointcapability; /*!< Supported capability at both ends (codecs) */
- int peercapability; /*!< Supported peer capability */
- int prefcodec; /*!< Preferred codec (outbound only) */
- int noncodeccapability; /*!< DTMF RFC2833 telephony-event */
- int jointnoncodeccapability; /*!< Joint Non codec capability */
- int redircodecs; /*!< Redirect codecs */
- int maxcallbitrate; /*!< Maximum Call Bitrate for Video Calls */
- struct t38properties t38; /*!< T38 settings */
- struct sockaddr_in udptlredirip; /*!< Where our T.38 UDPTL should be going if not to us */
- struct ast_udptl *udptl; /*!< T.38 UDPTL session */
- int callingpres; /*!< Calling presentation */
- int authtries; /*!< Times we've tried to authenticate */
- int expiry; /*!< How long we take to expire */
- long branch; /*!< The branch identifier of this session */
- long invite_branch; /*!< The branch used when we sent the initial INVITE */
- char tag[11]; /*!< Our tag for this session */
- int sessionid; /*!< SDP Session ID */
- int sessionversion; /*!< SDP Session Version */
- struct sockaddr_in sa; /*!< Our peer */
- struct sockaddr_in redirip; /*!< Where our RTP should be going if not to us */
- struct sockaddr_in vredirip; /*!< Where our Video RTP should be going if not to us */
- time_t lastrtprx; /*!< Last RTP received */
- time_t lastrtptx; /*!< Last RTP sent */
- int rtptimeout; /*!< RTP timeout time */
- struct sockaddr_in recv; /*!< Received as */
- struct in_addr ourip; /*!< Our IP */
- struct ast_channel *owner; /*!< Who owns us (if we have an owner) */
- struct sip_route *route; /*!< Head of linked list of routing steps (fm Record-Route) */
- int route_persistant; /*!< Is this the "real" route? */
- struct sip_auth *peerauth; /*!< Realm authentication */
- int noncecount; /*!< Nonce-count */
- char lastmsg[256]; /*!< Last Message sent/received */
- int amaflags; /*!< AMA Flags */
- int pendinginvite; /*!< Any pending INVITE or state NOTIFY (in subscribe pvt's) ? (seqno of this) */
- struct sip_request initreq; /*!< Request that opened the latest transaction
- within this SIP dialog */
-
- int maxtime; /*!< Max time for first response */
- int initid; /*!< Auto-congest ID if appropriate (scheduler) */
- int waitid; /*!< Wait ID for scheduler after 491 or other delays */
- int autokillid; /*!< Auto-kill ID (scheduler) */
- enum transfermodes allowtransfer; /*!< REFER: restriction scheme */
- struct sip_refer *refer; /*!< REFER: SIP transfer data structure */
- enum subscriptiontype subscribed; /*!< SUBSCRIBE: Is this dialog a subscription? */
- int stateid; /*!< SUBSCRIBE: ID for devicestate subscriptions */
- int laststate; /*!< SUBSCRIBE: Last known extension state */
- int dialogver; /*!< SUBSCRIBE: Version for subscription dialog-info */
-
- struct ast_dsp *vad; /*!< Voice Activation Detection dsp */
-
- struct sip_peer *relatedpeer; /*!< If this dialog is related to a peer, which one
- Used in peerpoke, mwi subscriptions */
- struct sip_registry *registry; /*!< If this is a REGISTER dialog, to which registry */
- struct ast_rtp *rtp; /*!< RTP Session */
- struct ast_rtp *vrtp; /*!< Video RTP session */
- struct sip_pkt *packets; /*!< Packets scheduled for re-transmission */
- struct sip_history_head *history; /*!< History of this SIP dialog */
- size_t history_entries; /*!< Number of entires in the history */
- struct ast_variable *chanvars; /*!< Channel variables to set for inbound call */
- AST_LIST_HEAD_NOLOCK(request_queue, sip_request) request_queue; /*!< Requests that arrived but could not be processed immediately */
- int request_queue_sched_id; /*!< Scheduler ID of any scheduled action to process queued requests */
- struct sip_pvt *next; /*!< Next dialog in chain */
- struct sip_invite_param *options; /*!< Options for INVITE */
- int autoframing;
-} *iflist = NULL;
-
-/*! Max entires in the history list for a sip_pvt */
-#define MAX_HISTORY_ENTRIES 50
-
-#define FLAG_RESPONSE (1 << 0)
-#define FLAG_FATAL (1 << 1)
-
-/*! \brief sip packet - raw format for outbound packets that are sent or scheduled for transmission */
-struct sip_pkt {
- struct sip_pkt *next; /*!< Next packet in linked list */
- int retrans; /*!< Retransmission number */
- int method; /*!< SIP method for this packet */
- int seqno; /*!< Sequence number */
- unsigned int flags; /*!< non-zero if this is a response packet (e.g. 200 OK) */
- struct sip_pvt *owner; /*!< Owner AST call */
- int retransid; /*!< Retransmission ID */
- int timer_a; /*!< SIP timer A, retransmission timer */
- int timer_t1; /*!< SIP Timer T1, estimated RTT or 500 ms */
- int packetlen; /*!< Length of packet */
- char data[0];
-};
-
-/*! \brief Structure for SIP user data. User's place calls to us */
-struct sip_user {
- /* Users who can access various contexts */
- ASTOBJ_COMPONENTS(struct sip_user);
- char secret[80]; /*!< Password */
- char md5secret[80]; /*!< Password in md5 */
- char context[AST_MAX_CONTEXT]; /*!< Default context for incoming calls */
- char subscribecontext[AST_MAX_CONTEXT]; /* Default context for subscriptions */
- char cid_num[80]; /*!< Caller ID num */
- char cid_name[80]; /*!< Caller ID name */
- char accountcode[AST_MAX_ACCOUNT_CODE]; /* Account code */
- char language[MAX_LANGUAGE]; /*!< Default language for this user */
- char mohinterpret[MAX_MUSICCLASS];/*!< Music on Hold class */
- char mohsuggest[MAX_MUSICCLASS];/*!< Music on Hold class */
- char useragent[256]; /*!< User agent in SIP request */
- struct ast_codec_pref prefs; /*!< codec prefs */
- ast_group_t callgroup; /*!< Call group */
- ast_group_t pickupgroup; /*!< Pickup Group */
- unsigned int sipoptions; /*!< Supported SIP options */
- struct ast_flags flags[2]; /*!< SIP_ flags */
- int amaflags; /*!< AMA flags for billing */
- int callingpres; /*!< Calling id presentation */
- int capability; /*!< Codec capability */
- int inUse; /*!< Number of calls in use */
- int call_limit; /*!< Limit of concurrent calls */
- enum transfermodes allowtransfer; /*! SIP Refer restriction scheme */
- struct ast_ha *ha; /*!< ACL setting */
- struct ast_variable *chanvars; /*!< Variables to set for channel created by user */
- int maxcallbitrate; /*!< Maximum Bitrate for a video call */
- int autoframing;
-};
-
-/*! \brief Structure for SIP peer data, we place calls to peers if registered or fixed IP address (host) */
-/* XXX field 'name' must be first otherwise sip_addrcmp() will fail */
-struct sip_peer {
- ASTOBJ_COMPONENTS(struct sip_peer); /*!< name, refcount, objflags, object pointers */
- /*!< peer->name is the unique name of this object */
- char secret[80]; /*!< Password */
- char md5secret[80]; /*!< Password in MD5 */
- struct sip_auth *auth; /*!< Realm authentication list */
- char context[AST_MAX_CONTEXT]; /*!< Default context for incoming calls */
- char subscribecontext[AST_MAX_CONTEXT]; /*!< Default context for subscriptions */
- char username[80]; /*!< Temporary username until registration */
- char accountcode[AST_MAX_ACCOUNT_CODE]; /*!< Account code */
- int amaflags; /*!< AMA Flags (for billing) */
- char tohost[MAXHOSTNAMELEN]; /*!< If not dynamic, IP address */
- char regexten[AST_MAX_EXTENSION]; /*!< Extension to register (if regcontext is used) */
- char fromuser[80]; /*!< From: user when calling this peer */
- char fromdomain[MAXHOSTNAMELEN]; /*!< From: domain when calling this peer */
- char fullcontact[256]; /*!< Contact registered with us (not in sip.conf) */
- char cid_num[80]; /*!< Caller ID num */
- char cid_name[80]; /*!< Caller ID name */
- int callingpres; /*!< Calling id presentation */
- int inUse; /*!< Number of calls in use */
- int inRinging; /*!< Number of calls ringing */
- int onHold; /*!< Peer has someone on hold */
- int call_limit; /*!< Limit of concurrent calls */
- enum transfermodes allowtransfer; /*! SIP Refer restriction scheme */
- char vmexten[AST_MAX_EXTENSION]; /*!< Dialplan extension for MWI notify message*/
- char mailbox[AST_MAX_EXTENSION]; /*!< Mailbox setting for MWI checks */
- char language[MAX_LANGUAGE]; /*!< Default language for prompts */
- char mohinterpret[MAX_MUSICCLASS];/*!< Music on Hold class */
- char mohsuggest[MAX_MUSICCLASS];/*!< Music on Hold class */
- char useragent[256]; /*!< User agent in SIP request (saved from registration) */
- struct ast_codec_pref prefs; /*!< codec prefs */
- int lastmsgssent;
- time_t lastmsgcheck; /*!< Last time we checked for MWI */
- unsigned int sipoptions; /*!< Supported SIP options */
- struct ast_flags flags[2]; /*!< SIP_ flags */
- int expire; /*!< When to expire this peer registration */
- int capability; /*!< Codec capability */
- int rtptimeout; /*!< RTP timeout */
- int rtpholdtimeout; /*!< RTP Hold Timeout */
- int rtpkeepalive; /*!< Send RTP packets for keepalive */
- ast_group_t callgroup; /*!< Call group */
- ast_group_t pickupgroup; /*!< Pickup group */
- struct sockaddr_in addr; /*!< IP address of peer */
- int maxcallbitrate; /*!< Maximum Bitrate for a video call */
-
- /* Qualification */
- struct sip_pvt *call; /*!< Call pointer */
- int pokeexpire; /*!< When to expire poke (qualify= checking) */
- int lastms; /*!< How long last response took (in ms), or -1 for no response */
- int maxms; /*!< Max ms we will accept for the host to be up, 0 to not monitor */
- struct timeval ps; /*!< Ping send time */
-
- struct sockaddr_in defaddr; /*!< Default IP address, used until registration */
- struct ast_ha *ha; /*!< Access control list */
- struct ast_ha *contactha; /*!< Restrict what IPs are allowed in the Contact header (for registration) */
- struct ast_variable *chanvars; /*!< Variables to set for channel created by user */
- struct sip_pvt *mwipvt; /*!< Subscription for MWI */
- int lastmsg;
- int autoframing;
-};
-
-
-
-/*! \brief Registrations with other SIP proxies */
-struct sip_registry {
- ASTOBJ_COMPONENTS_FULL(struct sip_registry,1,1);
- AST_DECLARE_STRING_FIELDS(
- AST_STRING_FIELD(callid); /*!< Global Call-ID */
- AST_STRING_FIELD(realm); /*!< Authorization realm */
- AST_STRING_FIELD(nonce); /*!< Authorization nonce */
- AST_STRING_FIELD(opaque); /*!< Opaque nonsense */
- AST_STRING_FIELD(qop); /*!< Quality of Protection, since SIP wasn't complicated enough yet. */
- AST_STRING_FIELD(domain); /*!< Authorization domain */
- AST_STRING_FIELD(username); /*!< Who we are registering as */
- AST_STRING_FIELD(authuser); /*!< Who we *authenticate* as */
- AST_STRING_FIELD(hostname); /*!< Domain or host we register to */
- AST_STRING_FIELD(secret); /*!< Password in clear text */
- AST_STRING_FIELD(md5secret); /*!< Password in md5 */
- AST_STRING_FIELD(contact); /*!< Contact extension */
- AST_STRING_FIELD(random);
- );
- int portno; /*!< Optional port override */
- int expire; /*!< Sched ID of expiration */
- int regattempts; /*!< Number of attempts (since the last success) */
- int timeout; /*!< sched id of sip_reg_timeout */
- int refresh; /*!< How often to refresh */
- struct sip_pvt *call; /*!< create a sip_pvt structure for each outbound "registration dialog" in progress */
- enum sipregistrystate regstate; /*!< Registration state (see above) */
- time_t regtime; /*!< Last succesful registration time */
- int callid_valid; /*!< 0 means we haven't chosen callid for this registry yet. */
- unsigned int ocseq; /*!< Sequence number we got to for REGISTERs for this registry */
- struct sockaddr_in us; /*!< Who the server thinks we are */
- int noncecount; /*!< Nonce-count */
- char lastmsg[256]; /*!< Last Message sent/received */
-};
-
-/* --- Linked lists of various objects --------*/
-
-/*! \brief The user list: Users and friends */
-static struct ast_user_list {
- ASTOBJ_CONTAINER_COMPONENTS(struct sip_user);
-} userl;
-
-/*! \brief The peer list: Peers and Friends */
-static struct ast_peer_list {
- ASTOBJ_CONTAINER_COMPONENTS(struct sip_peer);
-} peerl;
-
-/*! \brief The register list: Other SIP proxys we register with and place calls to */
-static struct ast_register_list {
- ASTOBJ_CONTAINER_COMPONENTS(struct sip_registry);
- int recheck;
-} regl;
-
-static void temp_pvt_cleanup(void *);
-
-/*! \brief A per-thread temporary pvt structure */
-AST_THREADSTORAGE_CUSTOM(ts_temp_pvt, temp_pvt_init, temp_pvt_cleanup);
-
-#ifdef LOW_MEMORY
-static void ts_ast_rtp_destroy(void *);
-
-AST_THREADSTORAGE_CUSTOM(ts_audio_rtp, ts_audio_rtp_init, ts_ast_rtp_destroy);
-AST_THREADSTORAGE_CUSTOM(ts_video_rtp, ts_video_rtp_init, ts_ast_rtp_destroy);
-#endif
-
-/*! \todo Move the sip_auth list to AST_LIST */
-static struct sip_auth *authl = NULL; /*!< Authentication list for realm authentication */
-
-
-/* --- Sockets and networking --------------*/
-static int sipsock = -1; /*!< Main socket for SIP network communication */
-static struct sockaddr_in bindaddr = { 0, }; /*!< The address we bind to */
-static struct sockaddr_in externip; /*!< External IP address if we are behind NAT */
-static char externhost[MAXHOSTNAMELEN]; /*!< External host name (possibly with dynamic DNS and DHCP */
-static time_t externexpire = 0; /*!< Expiration counter for re-resolving external host name in dynamic DNS */
-static int externrefresh = 10;
-static struct ast_ha *localaddr; /*!< List of local networks, on the same side of NAT as this Asterisk */
-static struct in_addr __ourip;
-static struct sockaddr_in outboundproxyip;
-static int ourport;
-static struct sockaddr_in debugaddr;
-
-static struct ast_config *notify_types; /*!< The list of manual NOTIFY types we know how to send */
-
-/*---------------------------- Forward declarations of functions in chan_sip.c */
-/*! \note This is added to help splitting up chan_sip.c into several files
- in coming releases */
-
-/*--- PBX interface functions */
-static struct ast_channel *sip_request_call(const char *type, int format, void *data, int *cause);
-static int sip_devicestate(void *data);
-static int sip_sendtext(struct ast_channel *ast, const char *text);
-static int sip_call(struct ast_channel *ast, char *dest, int timeout);
-static int sip_hangup(struct ast_channel *ast);
-static int sip_answer(struct ast_channel *ast);
-static struct ast_frame *sip_read(struct ast_channel *ast);
-static int sip_write(struct ast_channel *ast, struct ast_frame *frame);
-static int sip_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
-static int sip_transfer(struct ast_channel *ast, const char *dest);
-static int sip_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
-static int sip_senddigit_begin(struct ast_channel *ast, char digit);
-static int sip_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration);
-
-/*--- Transmitting responses and requests */
-static int sipsock_read(int *id, int fd, short events, void *ignore);
-static int __sip_xmit(struct sip_pvt *p, char *data, int len);
-static int __sip_reliable_xmit(struct sip_pvt *p, int seqno, int resp, char *data, int len, int fatal, int sipmethod);
-static int __transmit_response(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable);
-static int retrans_pkt(const void *data);
-static int transmit_sip_request(struct sip_pvt *p, struct sip_request *req);
-static int transmit_response_using_temp(ast_string_field callid, struct sockaddr_in *sin, int useglobal_nat, const int intended_method, const struct sip_request *req, const char *msg);
-static int transmit_response(struct sip_pvt *p, const char *msg, const struct sip_request *req);
-static int transmit_response_reliable(struct sip_pvt *p, const char *msg, const struct sip_request *req);
-static int transmit_response_with_date(struct sip_pvt *p, const char *msg, const struct sip_request *req);
-static int transmit_response_with_sdp(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable);
-static int transmit_response_with_unsupported(struct sip_pvt *p, const char *msg, const struct sip_request *req, const char *unsupported);
-static int transmit_response_with_auth(struct sip_pvt *p, const char *msg, const struct sip_request *req, const char *rand, enum xmittype reliable, const char *header, int stale);
-static int transmit_response_with_allow(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable);
-static void transmit_fake_auth_response(struct sip_pvt *p, struct sip_request *req, int reliable);
-static int transmit_request(struct sip_pvt *p, int sipmethod, int inc, enum xmittype reliable, int newbranch);
-static int transmit_request_with_auth(struct sip_pvt *p, int sipmethod, int seqno, enum xmittype reliable, int newbranch);
-static int transmit_invite(struct sip_pvt *p, int sipmethod, int sdp, int init);
-static int transmit_reinvite_with_sdp(struct sip_pvt *p);
-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);
-static int transmit_refer(struct sip_pvt *p, const char *dest);
-static int transmit_notify_with_mwi(struct sip_pvt *p, int newmsgs, int oldmsgs, char *vmexten);
-static int transmit_notify_with_sipfrag(struct sip_pvt *p, int cseq, char *message, int terminate);
-static int transmit_register(struct sip_registry *r, int sipmethod, const char *auth, const char *authheader);
-static int send_response(struct sip_pvt *p, struct sip_request *req, enum xmittype reliable, int seqno);
-static int send_request(struct sip_pvt *p, struct sip_request *req, enum xmittype reliable, int seqno);
-static void copy_request(struct sip_request *dst, const struct sip_request *src);
-static void receive_message(struct sip_pvt *p, struct sip_request *req);
-static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req);
-static int sip_send_mwi_to_peer(struct sip_peer *peer);
-static int does_peer_need_mwi(struct sip_peer *peer);
-
-/*--- Dialog management */
-static struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *sin,
- int useglobal_nat, const int intended_method);
-static int __sip_autodestruct(const void *data);
-static void sip_scheddestroy(struct sip_pvt *p, int ms);
-static int sip_cancel_destroy(struct sip_pvt *p);
-static void sip_destroy(struct sip_pvt *p);
-static int __sip_destroy(struct sip_pvt *p, int lockowner);
-static void __sip_ack(struct sip_pvt *p, int seqno, int resp, int sipmethod);
-static void __sip_pretend_ack(struct sip_pvt *p);
-static int __sip_semi_ack(struct sip_pvt *p, int seqno, int resp, int sipmethod);
-static int auto_congest(const void *nothing);
-static int update_call_counter(struct sip_pvt *fup, int event);
-static int hangup_sip2cause(int cause);
-static const char *hangup_cause2sip(int cause);
-static struct sip_pvt *find_call(struct sip_request *req, struct sockaddr_in *sin, const int intended_method);
-static void free_old_route(struct sip_route *route);
-static void list_route(struct sip_route *route);
-static void build_route(struct sip_pvt *p, struct sip_request *req, int backwards);
-static enum check_auth_result register_verify(struct sip_pvt *p, struct sockaddr_in *sin,
- struct sip_request *req, char *uri);
-static struct sip_pvt *get_sip_pvt_byid_locked(const char *callid, const char *totag, const char *fromtag);
-static void check_pendings(struct sip_pvt *p);
-static void *sip_park_thread(void *stuff);
-static int sip_park(struct ast_channel *chan1, struct ast_channel *chan2, struct sip_request *req, int seqno);
-static int sip_sipredirect(struct sip_pvt *p, const char *dest);
-
-/*--- Codec handling / SDP */
-static void try_suggested_sip_codec(struct sip_pvt *p);
-static const char* get_sdp_iterate(int* start, struct sip_request *req, const char *name);
-static const char *get_sdp(struct sip_request *req, const char *name);
-static int find_sdp(struct sip_request *req);
-static int process_sdp(struct sip_pvt *p, struct sip_request *req);
-static void add_codec_to_sdp(const struct sip_pvt *p, int codec, int sample_rate,
- char **m_buf, size_t *m_size, char **a_buf, size_t *a_size,
- int debug, int *min_packet_size);
-static void add_noncodec_to_sdp(const struct sip_pvt *p, int format, int sample_rate,
- char **m_buf, size_t *m_size, char **a_buf, size_t *a_size,
- int debug);
-static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p);
-static void stop_media_flows(struct sip_pvt *p);
-
-/*--- Authentication stuff */
-static int reply_digest(struct sip_pvt *p, struct sip_request *req, char *header, int sipmethod, char *digest, int digest_len);
-static int build_reply_digest(struct sip_pvt *p, int method, char *digest, int digest_len);
-static enum check_auth_result check_auth(struct sip_pvt *p, struct sip_request *req, const char *username,
- const char *secret, const char *md5secret, int sipmethod,
- char *uri, enum xmittype reliable, int ignore);
-static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_request *req,
- int sipmethod, char *uri, enum xmittype reliable,
- struct sockaddr_in *sin, struct sip_peer **authpeer);
-static int check_user(struct sip_pvt *p, struct sip_request *req, int sipmethod, char *uri, enum xmittype reliable, struct sockaddr_in *sin);
-
-/*--- Domain handling */
-static int check_sip_domain(const char *domain, char *context, size_t len); /* Check if domain is one of our local domains */
-static int add_sip_domain(const char *domain, const enum domain_mode mode, const char *context);
-static void clear_sip_domains(void);
-
-/*--- SIP realm authentication */
-static struct sip_auth *add_realm_authentication(struct sip_auth *authlist, char *configuration, int lineno);
-static int clear_realm_authentication(struct sip_auth *authlist); /* Clear realm authentication list (at reload) */
-static struct sip_auth *find_realm_authentication(struct sip_auth *authlist, const char *realm);
-
-/*--- Misc functions */
-static int sip_do_reload(enum channelreloadreason reason);
-static int reload_config(enum channelreloadreason reason);
-static int expire_register(const void *data);
-static void *do_monitor(void *data);
-static int restart_monitor(void);
-static int sip_send_mwi_to_peer(struct sip_peer *peer);
-static int sip_addrcmp(char *name, struct sockaddr_in *sin); /* Support for peer matching */
-static int sip_refer_allocate(struct sip_pvt *p);
-static void ast_quiet_chan(struct ast_channel *chan);
-static int attempt_transfer(struct sip_dual *transferer, struct sip_dual *target);
-
-/*--- Device monitoring and Device/extension state handling */
-static int cb_extensionstate(char *context, char* exten, int state, void *data);
-static int sip_devicestate(void *data);
-static int sip_poke_noanswer(const void *data);
-static int sip_poke_peer(struct sip_peer *peer);
-static void sip_poke_all_peers(void);
-static void sip_peer_hold(struct sip_pvt *p, int hold);
-
-/*--- Applications, functions, CLI and manager command helpers */
-static const char *sip_nat_mode(const struct sip_pvt *p);
-static int sip_show_inuse(int fd, int argc, char *argv[]);
-static char *transfermode2str(enum transfermodes mode) attribute_const;
-static char *nat2str(int nat) attribute_const;
-static int peer_status(struct sip_peer *peer, char *status, int statuslen);
-static int sip_show_users(int fd, int argc, char *argv[]);
-static int _sip_show_peers(int fd, int *total, struct mansession *s, const struct message *m, int argc, const char *argv[]);
-static int sip_show_peers(int fd, int argc, char *argv[]);
-static int sip_show_objects(int fd, int argc, char *argv[]);
-static void print_group(int fd, ast_group_t group, int crlf);
-static const char *dtmfmode2str(int mode) attribute_const;
-static const char *insecure2str(int port, int invite) attribute_const;
-static void cleanup_stale_contexts(char *new, char *old);
-static void print_codec_to_cli(int fd, struct ast_codec_pref *pref);
-static const char *domain_mode_to_text(const enum domain_mode mode);
-static int sip_show_domains(int fd, int argc, char *argv[]);
-static int _sip_show_peer(int type, int fd, struct mansession *s, const struct message *m, int argc, const char *argv[]);
-static int sip_show_peer(int fd, int argc, char *argv[]);
-static int sip_show_user(int fd, int argc, char *argv[]);
-static int sip_show_registry(int fd, int argc, char *argv[]);
-static int sip_show_settings(int fd, int argc, char *argv[]);
-static const char *subscription_type2str(enum subscriptiontype subtype) attribute_pure;
-static const struct cfsubscription_types *find_subscription_type(enum subscriptiontype subtype);
-static int __sip_show_channels(int fd, int argc, char *argv[], int subscriptions);
-static int sip_show_channels(int fd, int argc, char *argv[]);
-static int sip_show_subscriptions(int fd, int argc, char *argv[]);
-static int __sip_show_channels(int fd, int argc, char *argv[], int subscriptions);
-static char *complete_sipch(const char *line, const char *word, int pos, int state);
-static char *complete_sip_peer(const char *word, int state, int flags2);
-static char *complete_sip_show_peer(const char *line, const char *word, int pos, int state);
-static char *complete_sip_debug_peer(const char *line, const char *word, int pos, int state);
-static char *complete_sip_user(const char *word, int state, int flags2);
-static char *complete_sip_show_user(const char *line, const char *word, int pos, int state);
-static char *complete_sipnotify(const char *line, const char *word, int pos, int state);
-static char *complete_sip_prune_realtime_peer(const char *line, const char *word, int pos, int state);
-static char *complete_sip_prune_realtime_user(const char *line, const char *word, int pos, int state);
-static int sip_show_channel(int fd, int argc, char *argv[]);
-static int sip_show_history(int fd, int argc, char *argv[]);
-static int sip_do_debug_ip(int fd, int argc, char *argv[]);
-static int sip_do_debug_peer(int fd, int argc, char *argv[]);
-static int sip_do_debug(int fd, int argc, char *argv[]);
-static int sip_no_debug(int fd, int argc, char *argv[]);
-static int sip_notify(int fd, int argc, char *argv[]);
-static int sip_do_history(int fd, int argc, char *argv[]);
-static int sip_no_history(int fd, int argc, char *argv[]);
-static int func_header_read(struct ast_channel *chan, char *function, char *data, char *buf, size_t len);
-static int func_check_sipdomain(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len);
-static int function_sippeer(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len);
-static int function_sipchaninfo_read(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len);
-static int sip_dtmfmode(struct ast_channel *chan, void *data);
-static int sip_addheader(struct ast_channel *chan, void *data);
-static int sip_do_reload(enum channelreloadreason reason);
-static int sip_reload(int fd, int argc, char *argv[]);
-static int acf_channel_read(struct ast_channel *chan, char *funcname, char *preparse, char *buf, size_t buflen);
-
-/*--- Debugging
- Functions for enabling debug per IP or fully, or enabling history logging for
- a SIP dialog
-*/
-static void sip_dump_history(struct sip_pvt *dialog); /* Dump history to LOG_DEBUG at end of dialog, before destroying data */
-static inline int sip_debug_test_addr(const struct sockaddr_in *addr);
-static inline int sip_debug_test_pvt(struct sip_pvt *p);
-static void append_history_full(struct sip_pvt *p, const char *fmt, ...);
-static void sip_dump_history(struct sip_pvt *dialog);
-
-/*--- Device object handling */
-static struct sip_peer *temp_peer(const char *name);
-static struct sip_peer *build_peer(const char *name, struct ast_variable *v, struct ast_variable *alt, int realtime);
-static struct sip_user *build_user(const char *name, struct ast_variable *v, struct ast_variable *alt, int realtime);
-static int update_call_counter(struct sip_pvt *fup, int event);
-static void sip_destroy_peer(struct sip_peer *peer);
-static void sip_destroy_user(struct sip_user *user);
-static int sip_poke_peer(struct sip_peer *peer);
-static int sip_poke_peer_s(const void *data);
-static void set_peer_defaults(struct sip_peer *peer);
-static struct sip_peer *temp_peer(const char *name);
-static void register_peer_exten(struct sip_peer *peer, int onoff);
-static struct sip_peer *find_peer(const char *peer, struct sockaddr_in *sin, int realtime, int devstate_only);
-static struct sip_user *find_user(const char *name, int realtime);
-static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, struct sip_peer *p, struct sip_request *req);
-static int expire_register(const void *data);
-static void reg_source_db(struct sip_peer *peer);
-static void destroy_association(struct sip_peer *peer);
-static int handle_common_options(struct ast_flags *flags, struct ast_flags *mask, struct ast_variable *v);
-
-/* Realtime device support */
-static void realtime_update_peer(const char *peername, struct sockaddr_in *sin, const char *username, const char *fullcontact, int expirey);
-static struct sip_user *realtime_user(const char *username);
-static void update_peer(struct sip_peer *p, int expiry);
-static struct sip_peer *realtime_peer(const char *peername, struct sockaddr_in *sin, int devstate_only);
-static int sip_prune_realtime(int fd, int argc, char *argv[]);
-
-/*--- Internal UA client handling (outbound registrations) */
-static int ast_sip_ouraddrfor(struct in_addr *them, struct in_addr *us);
-static void sip_registry_destroy(struct sip_registry *reg);
-static int sip_register(char *value, int lineno);
-static char *regstate2str(enum sipregistrystate regstate) attribute_const;
-static int sip_reregister(const void *data);
-static int __sip_do_register(struct sip_registry *r);
-static int sip_reg_timeout(const void *data);
-static void sip_send_all_registers(void);
-
-/*--- Parsing SIP requests and responses */
-static void append_date(struct sip_request *req); /* Append date to SIP packet */
-static int determine_firstline_parts(struct sip_request *req);
-static const struct cfsubscription_types *find_subscription_type(enum subscriptiontype subtype);
-static const char *gettag(const struct sip_request *req, const char *header, char *tagbuf, int tagbufsize);
-static void set_insecure_flags(struct ast_flags *flags, const char *value, int lineno);
-static int find_sip_method(const char *msg);
-static unsigned int parse_sip_options(struct sip_pvt *pvt, const char *supported);
-static int parse_request(struct sip_request *req);
-static const char *get_header(const struct sip_request *req, const char *name);
-static char *referstatus2str(enum referstatus rstatus) attribute_pure;
-static int method_match(enum sipmethod id, const char *name);
-static void parse_copy(struct sip_request *dst, const struct sip_request *src);
-static char *get_in_brackets(char *tmp);
-static const char *find_alias(const char *name, const char *_default);
-static const char *__get_header(const struct sip_request *req, const char *name, int *start);
-static int lws2sws(char *msgbuf, int len);
-static void extract_uri(struct sip_pvt *p, struct sip_request *req);
-static int get_refer_info(struct sip_pvt *transferer, struct sip_request *outgoing_req);
-static int get_also_info(struct sip_pvt *p, struct sip_request *oreq);
-static int parse_ok_contact(struct sip_pvt *pvt, struct sip_request *req);
-static int set_address_from_contact(struct sip_pvt *pvt);
-static void check_via(struct sip_pvt *p, const struct sip_request *req);
-static char *get_calleridname(const char *input, char *output, size_t outputsize);
-static int get_rpid_num(const char *input, char *output, int maxlen);
-static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq);
-static int get_destination(struct sip_pvt *p, struct sip_request *oreq);
-static int get_msg_text(char *buf, int len, struct sip_request *req);
-static void free_old_route(struct sip_route *route);
-static int transmit_state_notify(struct sip_pvt *p, int state, int full, int timeout);
-
-/*--- Constructing requests and responses */
-static void initialize_initreq(struct sip_pvt *p, struct sip_request *req);
-static int init_req(struct sip_request *req, int sipmethod, const char *recip);
-static int reqprep(struct sip_request *req, struct sip_pvt *p, int sipmethod, int seqno, int newbranch);
-static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmethod);
-static int init_resp(struct sip_request *resp, const char *msg);
-static int respprep(struct sip_request *resp, struct sip_pvt *p, const char *msg, const struct sip_request *req);
-static const struct sockaddr_in *sip_real_dst(const struct sip_pvt *p);
-static void build_via(struct sip_pvt *p);
-static int create_addr_from_peer(struct sip_pvt *r, struct sip_peer *peer);
-static int create_addr(struct sip_pvt *dialog, const char *opeer);
-static char *generate_random_string(char *buf, size_t size);
-static void build_callid_pvt(struct sip_pvt *pvt);
-static void build_callid_registry(struct sip_registry *reg, struct in_addr ourip, const char *fromdomain);
-static void make_our_tag(char *tagbuf, size_t len);
-static int add_header(struct sip_request *req, const char *var, const char *value);
-static int add_header_contentLength(struct sip_request *req, int len);
-static int add_line(struct sip_request *req, const char *line);
-static int add_text(struct sip_request *req, const char *text);
-static int add_digit(struct sip_request *req, char digit, unsigned int duration);
-static int add_vidupdate(struct sip_request *req);
-static void add_route(struct sip_request *req, struct sip_route *route);
-static int copy_header(struct sip_request *req, const struct sip_request *orig, const char *field);
-static int copy_all_header(struct sip_request *req, const struct sip_request *orig, const char *field);
-static int copy_via_headers(struct sip_pvt *p, struct sip_request *req, const struct sip_request *orig, const char *field);
-static void set_destination(struct sip_pvt *p, char *uri);
-static void append_date(struct sip_request *req);
-static void build_contact(struct sip_pvt *p);
-static void build_rpid(struct sip_pvt *p);
-
-/*------Request handling functions */
-static int handle_request(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, int *recount, int *nounlock);
-static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int debug, int seqno, struct sockaddr_in *sin, int *recount, char *e, int *nounlock);
-static int handle_request_refer(struct sip_pvt *p, struct sip_request *req, int debug, int ignore, int seqno, int *nounlock);
-static int handle_request_bye(struct sip_pvt *p, struct sip_request *req);
-static int handle_request_register(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, char *e);
-static int handle_request_cancel(struct sip_pvt *p, struct sip_request *req);
-static int handle_request_message(struct sip_pvt *p, struct sip_request *req);
-static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, int seqno, char *e);
-static void handle_request_info(struct sip_pvt *p, struct sip_request *req);
-static int handle_request_options(struct sip_pvt *p, struct sip_request *req);
-static int handle_invite_replaces(struct sip_pvt *p, struct sip_request *req, int debug, int ignore, int seqno, struct sockaddr_in *sin);
-static int handle_request_notify(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, int seqno, char *e);
-static int local_attended_transfer(struct sip_pvt *transferer, struct sip_dual *current, struct sip_request *req, int seqno);
-
-/*------Response handling functions */
-static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int seqno);
-static void handle_response_refer(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int seqno);
-static int handle_response_register(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int ignore, int seqno);
-static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int ignore, int seqno);
-
-/*----- RTP interface functions */
-static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs, int nat_active);
-static enum ast_rtp_get_result sip_get_rtp_peer(struct ast_channel *chan, struct ast_rtp **rtp);
-static enum ast_rtp_get_result sip_get_vrtp_peer(struct ast_channel *chan, struct ast_rtp **rtp);
-static int sip_get_codec(struct ast_channel *chan);
-static struct ast_frame *sip_rtp_read(struct ast_channel *ast, struct sip_pvt *p, int *faxdetect);
-
-/*------ T38 Support --------- */
-static int sip_handle_t38_reinvite(struct ast_channel *chan, struct sip_pvt *pvt, int reinvite); /*!< T38 negotiation helper function */
-static int transmit_response_with_t38_sdp(struct sip_pvt *p, char *msg, struct sip_request *req, int retrans);
-static int transmit_reinvite_with_t38_sdp(struct sip_pvt *p);
-static struct ast_udptl *sip_get_udptl_peer(struct ast_channel *chan);
-static int sip_set_udptl_peer(struct ast_channel *chan, struct ast_udptl *udptl);
-
-/*! \brief Definition of this channel for PBX channel registration */
-static const struct ast_channel_tech sip_tech = {
- .type = "SIP",
- .description = "Session Initiation Protocol (SIP)",
- .capabilities = ((AST_FORMAT_MAX_AUDIO << 1) - 1),
- .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER,
- .requester = sip_request_call,
- .devicestate = sip_devicestate,
- .call = sip_call,
- .hangup = sip_hangup,
- .answer = sip_answer,
- .read = sip_read,
- .write = sip_write,
- .write_video = sip_write,
- .indicate = sip_indicate,
- .transfer = sip_transfer,
- .fixup = sip_fixup,
- .send_digit_begin = sip_senddigit_begin,
- .send_digit_end = sip_senddigit_end,
- .bridge = ast_rtp_bridge,
- .send_text = sip_sendtext,
- .func_channel_read = acf_channel_read,
-};
-
-/*! \brief This version of the sip channel tech has no send_digit_begin
- * callback. This is for use with channels using SIP INFO DTMF so that
- * the core knows that the channel doesn't want DTMF BEGIN frames. */
-static const struct ast_channel_tech sip_tech_info = {
- .type = "SIP",
- .description = "Session Initiation Protocol (SIP)",
- .capabilities = ((AST_FORMAT_MAX_AUDIO << 1) - 1),
- .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER,
- .requester = sip_request_call,
- .devicestate = sip_devicestate,
- .call = sip_call,
- .hangup = sip_hangup,
- .answer = sip_answer,
- .read = sip_read,
- .write = sip_write,
- .write_video = sip_write,
- .indicate = sip_indicate,
- .transfer = sip_transfer,
- .fixup = sip_fixup,
- .send_digit_end = sip_senddigit_end,
- .bridge = ast_rtp_bridge,
- .send_text = sip_sendtext,
- .func_channel_read = acf_channel_read,
-};
-
-/**--- some list management macros. **/
-
-#define UNLINK(element, head, prev) do { \
- if (prev) \
- (prev)->next = (element)->next; \
- else \
- (head) = (element)->next; \
- } while (0)
-
-/*! \brief Interface structure with callbacks used to connect to RTP module */
-static struct ast_rtp_protocol sip_rtp = {
- type: "SIP",
- get_rtp_info: sip_get_rtp_peer,
- get_vrtp_info: sip_get_vrtp_peer,
- set_rtp_peer: sip_set_rtp_peer,
- get_codec: sip_get_codec,
-};
-
-/*! \brief Interface structure with callbacks used to connect to UDPTL module*/
-static struct ast_udptl_protocol sip_udptl = {
- type: "SIP",
- get_udptl_info: sip_get_udptl_peer,
- set_udptl_peer: sip_set_udptl_peer,
-};
-
-/*! \brief Convert transfer status to string */
-static char *referstatus2str(enum referstatus rstatus)
-{
- int i = (sizeof(referstatusstrings) / sizeof(referstatusstrings[0]));
- int x;
-
- for (x = 0; x < i; x++) {
- if (referstatusstrings[x].status == rstatus)
- return (char *) referstatusstrings[x].text;
- }
- return "";
-}
-
-/*! \brief Initialize the initital request packet in the pvt structure.
- This packet is used for creating replies and future requests in
- a dialog */
-static void initialize_initreq(struct sip_pvt *p, struct sip_request *req)
-{
- if (p->initreq.headers && option_debug) {
- ast_log(LOG_DEBUG, "Initializing already initialized SIP dialog %s (presumably reinvite)\n", p->callid);
- }
- /* Use this as the basis */
- copy_request(&p->initreq, req);
- parse_request(&p->initreq);
- if (ast_test_flag(req, SIP_PKT_DEBUG))
- ast_verbose("%d headers, %d lines\n", p->initreq.headers, p->initreq.lines);
-}
-
-static void sip_alreadygone(struct sip_pvt *dialog)
-{
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Setting SIP_ALREADYGONE on dialog %s\n", dialog->callid);
- ast_set_flag(&dialog->flags[0], SIP_ALREADYGONE);
-}
-
-
-/*! \brief returns true if 'name' (with optional trailing whitespace)
- * matches the sip method 'id'.
- * Strictly speaking, SIP methods are case SENSITIVE, but we do
- * a case-insensitive comparison to be more tolerant.
- * following Jon Postel's rule: Be gentle in what you accept, strict with what you send
- */
-static int method_match(enum sipmethod id, const char *name)
-{
- int len = strlen(sip_methods[id].text);
- int l_name = name ? strlen(name) : 0;
- /* true if the string is long enough, and ends with whitespace, and matches */
- return (l_name >= len && name[len] < 33 &&
- !strncasecmp(sip_methods[id].text, name, len));
-}
-
-/*! \brief find_sip_method: Find SIP method from header */
-static int find_sip_method(const char *msg)
-{
- int i, res = 0;
-
- if (ast_strlen_zero(msg))
- return 0;
- for (i = 1; i < (sizeof(sip_methods) / sizeof(sip_methods[0])) && !res; i++) {
- if (method_match(i, msg))
- res = sip_methods[i].id;
- }
- return res;
-}
-
-/*! \brief Parse supported header in incoming packet */
-static unsigned int parse_sip_options(struct sip_pvt *pvt, const char *supported)
-{
- char *next, *sep;
- char *temp;
- unsigned int profile = 0;
- int i, found;
-
- if (ast_strlen_zero(supported) )
- return 0;
- temp = ast_strdupa(supported);
-
- if (option_debug > 2 && sipdebug)
- ast_log(LOG_DEBUG, "Begin: parsing SIP \"Supported: %s\"\n", supported);
-
- for (next = temp; next; next = sep) {
- found = FALSE;
- if ( (sep = strchr(next, ',')) != NULL)
- *sep++ = '\0';
- next = ast_skip_blanks(next);
- if (option_debug > 2 && sipdebug)
- ast_log(LOG_DEBUG, "Found SIP option: -%s-\n", next);
- for (i=0; i < (sizeof(sip_options) / sizeof(sip_options[0])); i++) {
- if (!strcasecmp(next, sip_options[i].text)) {
- profile |= sip_options[i].id;
- found = TRUE;
- if (option_debug > 2 && sipdebug)
- ast_log(LOG_DEBUG, "Matched SIP option: %s\n", next);
- break;
- }
- }
- if (!found && option_debug > 2 && sipdebug) {
- if (!strncasecmp(next, "x-", 2))
- ast_log(LOG_DEBUG, "Found private SIP option, not supported: %s\n", next);
- else
- ast_log(LOG_DEBUG, "Found no match for SIP option: %s (Please file bug report!)\n", next);
- }
- }
-
- if (pvt)
- pvt->sipoptions = profile;
- return profile;
-}
-
-/*! \brief See if we pass debug IP filter */
-static inline int sip_debug_test_addr(const struct sockaddr_in *addr)
-{
- if (!sipdebug)
- return 0;
- if (debugaddr.sin_addr.s_addr) {
- if (((ntohs(debugaddr.sin_port) != 0)
- && (debugaddr.sin_port != addr->sin_port))
- || (debugaddr.sin_addr.s_addr != addr->sin_addr.s_addr))
- return 0;
- }
- return 1;
-}
-
-/*! \brief The real destination address for a write */
-static const struct sockaddr_in *sip_real_dst(const struct sip_pvt *p)
-{
- return ast_test_flag(&p->flags[0], SIP_NAT) & SIP_NAT_ROUTE ? &p->recv : &p->sa;
-}
-
-/*! \brief Display SIP nat mode */
-static const char *sip_nat_mode(const struct sip_pvt *p)
-{
- return ast_test_flag(&p->flags[0], SIP_NAT) & SIP_NAT_ROUTE ? "NAT" : "no NAT";
-}
-
-/*! \brief Test PVT for debugging output */
-static inline int sip_debug_test_pvt(struct sip_pvt *p)
-{
- if (!sipdebug)
- return 0;
- return sip_debug_test_addr(sip_real_dst(p));
-}
-
-/*! \brief Transmit SIP message */
-static int __sip_xmit(struct sip_pvt *p, char *data, int len)
-{
- int res;
- const struct sockaddr_in *dst = sip_real_dst(p);
- res = sendto(sipsock, data, len, 0, (const struct sockaddr *)dst, sizeof(struct sockaddr_in));
-
- if (res == -1) {
- switch (errno) {
- case EBADF: /* Bad file descriptor - seems like this is generated when the host exist, but doesn't accept the UDP packet */
- case EHOSTUNREACH: /* Host can't be reached */
- case ENETDOWN: /* Inteface down */
- case ENETUNREACH: /* Network failure */
- case ECONNREFUSED: /* ICMP port unreachable */
- res = XMIT_ERROR; /* Don't bother with trying to transmit again */
- }
- }
- if (res != len)
- ast_log(LOG_WARNING, "sip_xmit of %p (len %d) to %s:%d returned %d: %s\n", data, len, ast_inet_ntoa(dst->sin_addr), ntohs(dst->sin_port), res, strerror(errno));
- return res;
-}
-
-
-/*! \brief Build a Via header for a request */
-static void build_via(struct sip_pvt *p)
-{
- /* Work around buggy UNIDEN UIP200 firmware */
- const char *rport = ast_test_flag(&p->flags[0], SIP_NAT) & SIP_NAT_RFC3581 ? ";rport" : "";
-
- /* z9hG4bK is a magic cookie. See RFC 3261 section 8.1.1.7 */
- ast_string_field_build(p, via, "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x%s",
- ast_inet_ntoa(p->ourip), ourport, (int) p->branch, rport);
-}
-
-/*! \brief NAT fix - decide which IP address to use for ASterisk server?
- *
- * Using the localaddr structure built up with localnet statements in sip.conf
- * apply it to their address to see if we need to substitute our
- * externip or can get away with our internal bindaddr
- */
-static enum sip_result ast_sip_ouraddrfor(struct in_addr *them, struct in_addr *us)
-{
- struct sockaddr_in theirs, ours;
-
- /* Get our local information */
- ast_ouraddrfor(them, us);
- theirs.sin_addr = *them;
- ours.sin_addr = *us;
-
- if (localaddr && externip.sin_addr.s_addr &&
- (ast_apply_ha(localaddr, &theirs)) &&
- (!global_matchexterniplocally || !ast_apply_ha(localaddr, &ours))) {
- if (externexpire && time(NULL) >= externexpire) {
- struct ast_hostent ahp;
- struct hostent *hp;
-
- externexpire = time(NULL) + externrefresh;
- if ((hp = ast_gethostbyname(externhost, &ahp))) {
- memcpy(&externip.sin_addr, hp->h_addr, sizeof(externip.sin_addr));
- } else
- ast_log(LOG_NOTICE, "Warning: Re-lookup of '%s' failed!\n", externhost);
- }
- *us = externip.sin_addr;
- if (option_debug) {
- ast_log(LOG_DEBUG, "Target address %s is not local, substituting externip\n",
- ast_inet_ntoa(*(struct in_addr *)&them->s_addr));
- }
- } else if (bindaddr.sin_addr.s_addr)
- *us = bindaddr.sin_addr;
- return AST_SUCCESS;
-}
-
-/*! \brief Append to SIP dialog history
- \return Always returns 0 */
-#define append_history(p, event, fmt , args... ) append_history_full(p, "%-15s " fmt, event, ## args)
-
-static void append_history_full(struct sip_pvt *p, const char *fmt, ...)
- __attribute__((format(printf, 2, 3)));
-
-/*! \brief Append to SIP dialog history with arg list */
-static void __attribute__((format(printf, 2, 0))) append_history_va(struct sip_pvt *p, const char *fmt, va_list ap)
-{
- char buf[80], *c = buf; /* max history length */
- struct sip_history *hist;
- int l;
-
- vsnprintf(buf, sizeof(buf), fmt, ap);
- strsep(&c, "\r\n"); /* Trim up everything after \r or \n */
- l = strlen(buf) + 1;
- if (!(hist = ast_calloc(1, sizeof(*hist) + l)))
- return;
- if (!p->history && !(p->history = ast_calloc(1, sizeof(*p->history)))) {
- free(hist);
- return;
- }
- memcpy(hist->event, buf, l);
- if (p->history_entries == MAX_HISTORY_ENTRIES) {
- struct sip_history *oldest;
- oldest = AST_LIST_REMOVE_HEAD(p->history, list);
- p->history_entries--;
- free(oldest);
- }
- AST_LIST_INSERT_TAIL(p->history, hist, list);
- p->history_entries++;
-}
-
-/*! \brief Append to SIP dialog history with arg list */
-static void append_history_full(struct sip_pvt *p, const char *fmt, ...)
-{
- va_list ap;
-
- if (!p)
- return;
-
- if (ast_test_flag(&p->flags[0], SIP_NO_HISTORY)
- && !recordhistory && !dumphistory) {
- return;
- }
-
- va_start(ap, fmt);
- append_history_va(p, fmt, ap);
- va_end(ap);
-
- return;
-}
-
-/*! \brief Retransmit SIP message if no answer (Called from scheduler) */
-static int retrans_pkt(const void *data)
-{
- struct sip_pkt *pkt = (struct sip_pkt *)data, *prev, *cur = NULL;
- int reschedule = DEFAULT_RETRANS;
- int xmitres = 0;
-
- /* Lock channel PVT */
- ast_mutex_lock(&pkt->owner->lock);
-
- if (pkt->retrans < MAX_RETRANS) {
- pkt->retrans++;
- if (!pkt->timer_t1) { /* Re-schedule using timer_a and timer_t1 */
- if (sipdebug && option_debug > 3)
- ast_log(LOG_DEBUG, "SIP TIMER: Not rescheduling id #%d:%s (Method %d) (No timer T1)\n", pkt->retransid, sip_methods[pkt->method].text, pkt->method);
- } else {
- int siptimer_a;
-
- if (sipdebug && option_debug > 3)
- ast_log(LOG_DEBUG, "SIP TIMER: Rescheduling retransmission #%d (%d) %s - %d\n", pkt->retransid, pkt->retrans, sip_methods[pkt->method].text, pkt->method);
- if (!pkt->timer_a)
- pkt->timer_a = 2 ;
- else
- pkt->timer_a = 2 * pkt->timer_a;
-
- /* For non-invites, a maximum of 4 secs */
- siptimer_a = pkt->timer_t1 * pkt->timer_a; /* Double each time */
- if (pkt->method != SIP_INVITE && siptimer_a > 4000)
- siptimer_a = 4000;
-
- /* Reschedule re-transmit */
- reschedule = siptimer_a;
- if (option_debug > 3)
- ast_log(LOG_DEBUG, "** SIP timers: Rescheduling retransmission %d to %d ms (t1 %d ms (Retrans id #%d)) \n", pkt->retrans +1, siptimer_a, pkt->timer_t1, pkt->retransid);
- }
-
- if (sip_debug_test_pvt(pkt->owner)) {
- const struct sockaddr_in *dst = sip_real_dst(pkt->owner);
- ast_verbose("Retransmitting #%d (%s) to %s:%d:\n%s\n---\n",
- pkt->retrans, sip_nat_mode(pkt->owner),
- ast_inet_ntoa(dst->sin_addr),
- ntohs(dst->sin_port), pkt->data);
- }
-
- append_history(pkt->owner, "ReTx", "%d %s", reschedule, pkt->data);
- xmitres = __sip_xmit(pkt->owner, pkt->data, pkt->packetlen);
- ast_mutex_unlock(&pkt->owner->lock);
- if (xmitres == XMIT_ERROR)
- ast_log(LOG_WARNING, "Network error on retransmit in dialog %s\n", pkt->owner->callid);
- else
- return reschedule;
- }
- /* Too many retries */
- if (pkt->owner && pkt->method != SIP_OPTIONS && xmitres == 0) {
- if (ast_test_flag(pkt, FLAG_FATAL) || sipdebug) /* Tell us if it's critical or if we're debugging */
- ast_log(LOG_WARNING, "Maximum retries exceeded on transmission %s for seqno %d (%s %s) -- See doc/sip-retransmit.txt.\n", pkt->owner->callid, pkt->seqno, (ast_test_flag(pkt, FLAG_FATAL)) ? "Critical" : "Non-critical", (ast_test_flag(pkt, FLAG_RESPONSE)) ? "Response" : "Request");
- } else if ((pkt->method == SIP_OPTIONS) && sipdebug) {
- ast_log(LOG_WARNING, "Cancelling retransmit of OPTIONs (call id %s) -- See doc/sip-retransmit.txt.\n", pkt->owner->callid);
- }
- if (xmitres == XMIT_ERROR) {
- ast_log(LOG_WARNING, "Transmit error :: Cancelling transmission of transaction in call id %s \n", pkt->owner->callid);
- append_history(pkt->owner, "XmitErr", "%s", (ast_test_flag(pkt, FLAG_FATAL)) ? "(Critical)" : "(Non-critical)");
- } else
- append_history(pkt->owner, "MaxRetries", "%s", (ast_test_flag(pkt, FLAG_FATAL)) ? "(Critical)" : "(Non-critical)");
-
- pkt->retransid = -1;
-
- if (ast_test_flag(pkt, FLAG_FATAL)) {
- while(pkt->owner->owner && ast_channel_trylock(pkt->owner->owner)) {
- DEADLOCK_AVOIDANCE(&pkt->owner->lock); /* SIP_PVT, not channel */
- }
-
- if (pkt->owner->owner && !pkt->owner->owner->hangupcause)
- pkt->owner->owner->hangupcause = AST_CAUSE_NO_USER_RESPONSE;
-
- if (pkt->owner->owner) {
- sip_alreadygone(pkt->owner);
- ast_log(LOG_WARNING, "Hanging up call %s - no reply to our critical packet (see doc/sip-retransmit.txt).\n", pkt->owner->callid);
- ast_queue_hangup(pkt->owner->owner);
- ast_channel_unlock(pkt->owner->owner);
- } else {
- /* If no channel owner, destroy now */
-
- /* Let the peerpoke system expire packets when the timer expires for poke_noanswer */
- if (pkt->method != SIP_OPTIONS) {
- ast_set_flag(&pkt->owner->flags[0], SIP_NEEDDESTROY);
- sip_alreadygone(pkt->owner);
- if (option_debug)
- append_history(pkt->owner, "DialogKill", "Killing this failed dialog immediately");
- }
- }
- }
-
- if (pkt->method == SIP_BYE) {
- /* We're not getting answers on SIP BYE's. Tear down the call anyway. */
- if (pkt->owner->owner)
- ast_channel_unlock(pkt->owner->owner);
- append_history(pkt->owner, "ByeFailure", "Remote peer doesn't respond to bye. Destroying call anyway.");
- ast_set_flag(&pkt->owner->flags[0], SIP_NEEDDESTROY);
- }
-
- /* In any case, go ahead and remove the packet */
- for (prev = NULL, cur = pkt->owner->packets; cur; prev = cur, cur = cur->next) {
- if (cur == pkt)
- break;
- }
- if (cur) {
- if (prev)
- prev->next = cur->next;
- else
- pkt->owner->packets = cur->next;
- ast_mutex_unlock(&pkt->owner->lock);
- free(cur);
- pkt = NULL;
- } else
- ast_log(LOG_WARNING, "Weird, couldn't find packet owner!\n");
- if (pkt)
- ast_mutex_unlock(&pkt->owner->lock);
- return 0;
-}
-
-/*! \brief Transmit packet with retransmits
- \return 0 on success, -1 on failure to allocate packet
-*/
-static enum sip_result __sip_reliable_xmit(struct sip_pvt *p, int seqno, int resp, char *data, int len, int fatal, int sipmethod)
-{
- struct sip_pkt *pkt;
- int siptimer_a = DEFAULT_RETRANS;
- int xmitres = 0;
-
- if (!(pkt = ast_calloc(1, sizeof(*pkt) + len + 1)))
- return AST_FAILURE;
- memcpy(pkt->data, data, len);
- pkt->method = sipmethod;
- pkt->packetlen = len;
- pkt->next = p->packets;
- pkt->owner = p;
- pkt->seqno = seqno;
- if (resp)
- ast_set_flag(pkt, FLAG_RESPONSE);
- pkt->data[len] = '\0';
- pkt->timer_t1 = p->timer_t1; /* Set SIP timer T1 */
- pkt->retransid = -1;
- if (fatal)
- ast_set_flag(pkt, FLAG_FATAL);
- if (pkt->timer_t1)
- siptimer_a = pkt->timer_t1 * 2;
-
- if (option_debug > 3 && sipdebug)
- ast_log(LOG_DEBUG, "*** SIP TIMER: Initializing retransmit timer on packet: Id #%d\n", pkt->retransid);
- pkt->retransid = -1;
- pkt->next = p->packets;
- p->packets = pkt;
- if (sipmethod == SIP_INVITE) {
- /* Note this is a pending invite */
- p->pendinginvite = seqno;
- }
-
- xmitres = __sip_xmit(pkt->owner, pkt->data, pkt->packetlen); /* Send packet */
-
- if (xmitres == XMIT_ERROR) { /* Serious network trouble, no need to try again */
- append_history(pkt->owner, "XmitErr", "%s", (ast_test_flag(pkt, FLAG_FATAL)) ? "(Critical)" : "(Non-critical)");
- return AST_FAILURE;
- } else {
- /* Schedule retransmission */
- pkt->retransid = ast_sched_add_variable(sched, siptimer_a, retrans_pkt, pkt, 1);
- return AST_SUCCESS;
- }
-}
-
-/*! \brief Kill a SIP dialog (called by scheduler) */
-static int __sip_autodestruct(const void *data)
-{
- struct sip_pvt *p = (struct sip_pvt *)data;
-
- /* If this is a subscription, tell the phone that we got a timeout */
- if (p->subscribed) {
- transmit_state_notify(p, AST_EXTENSION_DEACTIVATED, 1, TRUE); /* Send last notification */
- p->subscribed = NONE;
- append_history(p, "Subscribestatus", "timeout");
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Re-scheduled destruction of SIP subsription %s\n", p->callid ? p->callid : "<unknown>");
- return 10000; /* Reschedule this destruction so that we know that it's gone */
- }
-
- /* If there are packets still waiting for delivery, delay the destruction */
- /* via bug 12101, the two usages of SIP_NEEDDESTROY in the following block
- * of code make a sort of "safety relief valve", that allows sip channels
- * that were created via INVITE, then thru some sequence were CANCELED,
- * to die, rather than infinitely be rescheduled */
- if (p->packets && !ast_test_flag(&p->flags[0], SIP_NEEDDESTROY)) {
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Re-scheduled destruction of SIP call %s\n", p->callid ? p->callid : "<unknown>");
- append_history(p, "ReliableXmit", "timeout");
- if (p->method == SIP_CANCEL || p->method == SIP_BYE) {
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- }
- return 10000;
- }
-
- /* If we're destroying a subscription, dereference peer object too */
- if (p->subscribed == MWI_NOTIFICATION && p->relatedpeer)
- ASTOBJ_UNREF(p->relatedpeer,sip_destroy_peer);
-
- /* Reset schedule ID */
- p->autokillid = -1;
-
- if (option_debug)
- ast_log(LOG_DEBUG, "Auto destroying SIP dialog '%s'\n", p->callid);
- append_history(p, "AutoDestroy", "%s", p->callid);
- if (p->owner) {
- ast_log(LOG_WARNING, "Autodestruct on dialog '%s' with owner in place (Method: %s)\n", p->callid, sip_methods[p->method].text);
- ast_queue_hangup(p->owner);
- } else if (p->refer && !ast_test_flag(&p->flags[0], SIP_ALREADYGONE)) {
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Finally hanging up channel after transfer: %s\n", p->callid);
- transmit_request_with_auth(p, SIP_BYE, 0, XMIT_RELIABLE, 1);
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- } else
- sip_destroy(p);
- return 0;
-}
-
-/*! \brief Schedule destruction of SIP dialog */
-static void sip_scheddestroy(struct sip_pvt *p, int ms)
-{
- if (ms < 0) {
- if (p->timer_t1 == 0)
- p->timer_t1 = 500; /* Set timer T1 if not set (RFC 3261) */
- ms = p->timer_t1 * 64;
- }
- if (sip_debug_test_pvt(p))
- ast_verbose("Scheduling destruction of SIP dialog '%s' in %d ms (Method: %s)\n", p->callid, ms, sip_methods[p->method].text);
- if (!ast_test_flag(&p->flags[0], SIP_NO_HISTORY))
- append_history(p, "SchedDestroy", "%d ms", ms);
-
- AST_SCHED_DEL(sched, p->autokillid);
- p->autokillid = ast_sched_add(sched, ms, __sip_autodestruct, p);
-}
-
-/*! \brief Cancel destruction of SIP dialog */
-static int sip_cancel_destroy(struct sip_pvt *p)
-{
- int res = 0;
- if (p->autokillid > -1) {
- if (!(res = ast_sched_del(sched, p->autokillid))) {
- append_history(p, "CancelDestroy", "");
- p->autokillid = -1;
- }
- }
- return res;
-}
-
-/*! \brief Acknowledges receipt of a packet and stops retransmission
- * called with p locked*/
-static void __sip_ack(struct sip_pvt *p, int seqno, int resp, int sipmethod)
-{
- struct sip_pkt *cur, *prev = NULL;
-
- /* Just in case... */
- char *msg;
- int res = FALSE;
-
- msg = sip_methods[sipmethod].text;
-
- for (cur = p->packets; cur; prev = cur, cur = cur->next) {
- if ((cur->seqno == seqno) && ((ast_test_flag(cur, FLAG_RESPONSE)) == resp) &&
- ((ast_test_flag(cur, FLAG_RESPONSE)) ||
- (!strncasecmp(msg, cur->data, strlen(msg)) && (cur->data[strlen(msg)] < 33)))) {
- if (!resp && (seqno == p->pendinginvite)) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Acked pending invite %d\n", p->pendinginvite);
- p->pendinginvite = 0;
- }
- /* this is our baby */
- res = TRUE;
- UNLINK(cur, p->packets, prev);
- if (cur->retransid > -1) {
- if (sipdebug && option_debug > 3)
- ast_log(LOG_DEBUG, "** SIP TIMER: Cancelling retransmit of packet (reply received) Retransid #%d\n", cur->retransid);
- }
- /* This odd section is designed to thwart a
- * race condition in the packet scheduler. There are
- * two conditions under which deleting the packet from the
- * scheduler can fail.
- *
- * 1. The packet has been removed from the scheduler because retransmission
- * is being attempted. The problem is that if the packet is currently attempting
- * retransmission and we are at this point in the code, then that MUST mean
- * that retrans_pkt is waiting on p's lock. Therefore we will relinquish the
- * lock temporarily to allow retransmission.
- *
- * 2. The packet has reached its maximum number of retransmissions and has
- * been permanently removed from the packet scheduler. If this is the case, then
- * the packet's retransid will be set to -1. The atomicity of the setting and checking
- * of the retransid to -1 is ensured since in both cases p's lock is held.
- */
- while (cur->retransid > -1 && ast_sched_del(sched, cur->retransid)) {
- DEADLOCK_AVOIDANCE(&p->lock);
- }
- free(cur);
- break;
- }
- }
- if (option_debug)
- ast_log(LOG_DEBUG, "Stopping retransmission on '%s' of %s %d: Match %s\n", p->callid, resp ? "Response" : "Request", seqno, res == FALSE ? "Not Found" : "Found");
-}
-
-/*! \brief Pretend to ack all packets
- * called with p locked */
-static void __sip_pretend_ack(struct sip_pvt *p)
-{
- struct sip_pkt *cur = NULL;
-
- while (p->packets) {
- int method;
- if (cur == p->packets) {
- ast_log(LOG_WARNING, "Have a packet that doesn't want to give up! %s\n", sip_methods[cur->method].text);
- return;
- }
- cur = p->packets;
- method = (cur->method) ? cur->method : find_sip_method(cur->data);
- __sip_ack(p, cur->seqno, ast_test_flag(cur, FLAG_RESPONSE), method);
- }
-}
-
-/*! \brief Acks receipt of packet, keep it around (used for provisional responses) */
-static int __sip_semi_ack(struct sip_pvt *p, int seqno, int resp, int sipmethod)
-{
- struct sip_pkt *cur;
- int res = -1;
-
- for (cur = p->packets; cur; cur = cur->next) {
- if (cur->seqno == seqno && ast_test_flag(cur, FLAG_RESPONSE) == resp &&
- (ast_test_flag(cur, FLAG_RESPONSE) || method_match(sipmethod, cur->data))) {
- /* this is our baby */
- if (cur->retransid > -1) {
- if (option_debug > 3 && sipdebug)
- ast_log(LOG_DEBUG, "*** SIP TIMER: Cancelling retransmission #%d - %s (got response)\n", cur->retransid, sip_methods[sipmethod].text);
- }
- AST_SCHED_DEL(sched, cur->retransid);
- res = 0;
- break;
- }
- }
- if (option_debug)
- ast_log(LOG_DEBUG, "(Provisional) Stopping retransmission (but retaining packet) on '%s' %s %d: %s\n", p->callid, resp ? "Response" : "Request", seqno, res == -1 ? "Not Found" : "Found");
- return res;
-}
-
-
-/*! \brief Copy SIP request, parse it */
-static void parse_copy(struct sip_request *dst, const struct sip_request *src)
-{
- memset(dst, 0, sizeof(*dst));
- memcpy(dst->data, src->data, sizeof(dst->data));
- dst->len = src->len;
- parse_request(dst);
-}
-
-/*! \brief add a blank line if no body */
-static void add_blank(struct sip_request *req)
-{
- if (!req->lines) {
- /* Add extra empty return. add_header() reserves 4 bytes so cannot be truncated */
- snprintf(req->data + req->len, sizeof(req->data) - req->len, "\r\n");
- req->len += strlen(req->data + req->len);
- }
-}
-
-/*! \brief Transmit response on SIP request*/
-static int send_response(struct sip_pvt *p, struct sip_request *req, enum xmittype reliable, int seqno)
-{
- int res;
-
- add_blank(req);
- if (sip_debug_test_pvt(p)) {
- const struct sockaddr_in *dst = sip_real_dst(p);
-
- ast_verbose("\n<--- %sTransmitting (%s) to %s:%d --->\n%s\n<------------>\n",
- reliable ? "Reliably " : "", sip_nat_mode(p),
- ast_inet_ntoa(dst->sin_addr),
- ntohs(dst->sin_port), req->data);
- }
- if (!ast_test_flag(&p->flags[0], SIP_NO_HISTORY)) {
- struct sip_request tmp;
- parse_copy(&tmp, req);
- append_history(p, reliable ? "TxRespRel" : "TxResp", "%s / %s - %s", tmp.data, get_header(&tmp, "CSeq"),
- (tmp.method == SIP_RESPONSE || tmp.method == SIP_UNKNOWN) ? tmp.rlPart2 : sip_methods[tmp.method].text);
- }
- res = (reliable) ?
- __sip_reliable_xmit(p, seqno, 1, req->data, req->len, (reliable == XMIT_CRITICAL), req->method) :
- __sip_xmit(p, req->data, req->len);
- if (res > 0)
- return 0;
- return res;
-}
-
-/*! \brief Send SIP Request to the other part of the dialogue */
-static int send_request(struct sip_pvt *p, struct sip_request *req, enum xmittype reliable, int seqno)
-{
- int res;
-
- add_blank(req);
- if (sip_debug_test_pvt(p)) {
- if (ast_test_flag(&p->flags[0], SIP_NAT_ROUTE))
- ast_verbose("%sTransmitting (NAT) to %s:%d:\n%s\n---\n", reliable ? "Reliably " : "", ast_inet_ntoa(p->recv.sin_addr), ntohs(p->recv.sin_port), req->data);
- else
- ast_verbose("%sTransmitting (no NAT) to %s:%d:\n%s\n---\n", reliable ? "Reliably " : "", ast_inet_ntoa(p->sa.sin_addr), ntohs(p->sa.sin_port), req->data);
- }
- if (!ast_test_flag(&p->flags[0], SIP_NO_HISTORY)) {
- struct sip_request tmp;
- parse_copy(&tmp, req);
- append_history(p, reliable ? "TxReqRel" : "TxReq", "%s / %s - %s", tmp.data, get_header(&tmp, "CSeq"), sip_methods[tmp.method].text);
- }
- res = (reliable) ?
- __sip_reliable_xmit(p, seqno, 0, req->data, req->len, (reliable == XMIT_CRITICAL), req->method) :
- __sip_xmit(p, req->data, req->len);
- return res;
-}
-
-/*! \brief Locate closing quote in a string, skipping escaped quotes.
- * optionally with a limit on the search.
- * start must be past the first quote.
- */
-static const char *find_closing_quote(const char *start, const char *lim)
-{
- char last_char = '\0';
- const char *s;
- for (s = start; *s && s != lim; last_char = *s++) {
- if (*s == '"' && last_char != '\\')
- break;
- }
- return s;
-}
-
-/*! \brief Pick out text in brackets from character string
- \return pointer to terminated stripped string
- \param tmp input string that will be modified
- Examples:
-
- "foo" <bar> valid input, returns bar
- foo returns the whole string
- < "foo ... > returns the string between brackets
- < "foo... bogus (missing closing bracket), returns the whole string
- XXX maybe should still skip the opening bracket
- */
-static char *get_in_brackets(char *tmp)
-{
- const char *parse = tmp;
- char *first_bracket;
-
- /*
- * Skip any quoted text until we find the part in brackets.
- * On any error give up and return the full string.
- */
- while ( (first_bracket = strchr(parse, '<')) ) {
- char *first_quote = strchr(parse, '"');
-
- if (!first_quote || first_quote > first_bracket)
- break; /* no need to look at quoted part */
- /* the bracket is within quotes, so ignore it */
- parse = find_closing_quote(first_quote + 1, NULL);
- if (!*parse) { /* not found, return full string ? */
- /* XXX or be robust and return in-bracket part ? */
- ast_log(LOG_WARNING, "No closing quote found in '%s'\n", tmp);
- break;
- }
- parse++;
- }
- if (first_bracket) {
- char *second_bracket = strchr(first_bracket + 1, '>');
- if (second_bracket) {
- *second_bracket = '\0';
- tmp = first_bracket + 1;
- } else {
- ast_log(LOG_WARNING, "No closing bracket found in '%s'\n", tmp);
- }
- }
- return tmp;
-}
-
-/*! \brief Send SIP MESSAGE text within a call
- Called from PBX core sendtext() application */
-static int sip_sendtext(struct ast_channel *ast, const char *text)
-{
- struct sip_pvt *p = ast->tech_pvt;
- int debug = sip_debug_test_pvt(p);
-
- if (debug)
- ast_verbose("Sending text %s on %s\n", text, ast->name);
- if (!p)
- return -1;
- if (ast_strlen_zero(text))
- return 0;
- if (debug)
- ast_verbose("Really sending text %s on %s\n", text, ast->name);
- transmit_message_with_text(p, text);
- return 0;
-}
-
-/*! \brief Update peer object in realtime storage
- If the Asterisk system name is set in asterisk.conf, we will use
- that name and store that in the "regserver" field in the sippeers
- table to facilitate multi-server setups.
-*/
-static void realtime_update_peer(const char *peername, struct sockaddr_in *sin, const char *username, const char *fullcontact, int expirey)
-{
- char port[10];
- char ipaddr[INET_ADDRSTRLEN];
- char regseconds[20];
-
- char *sysname = ast_config_AST_SYSTEM_NAME;
- char *syslabel = NULL;
-
- time_t nowtime = time(NULL) + expirey;
- const char *fc = fullcontact ? "fullcontact" : NULL;
-
- snprintf(regseconds, sizeof(regseconds), "%d", (int)nowtime); /* Expiration time */
- ast_copy_string(ipaddr, ast_inet_ntoa(sin->sin_addr), sizeof(ipaddr));
- snprintf(port, sizeof(port), "%d", ntohs(sin->sin_port));
-
- if (ast_strlen_zero(sysname)) /* No system name, disable this */
- sysname = NULL;
- else if (ast_test_flag(&global_flags[1], SIP_PAGE2_RTSAVE_SYSNAME))
- syslabel = "regserver";
-
- if (fc)
- ast_update_realtime("sippeers", "name", peername, "ipaddr", ipaddr,
- "port", port, "regseconds", regseconds,
- "username", username, fc, fullcontact, syslabel, sysname, NULL); /* note fc and syslabel _can_ be NULL */
- else
- ast_update_realtime("sippeers", "name", peername, "ipaddr", ipaddr,
- "port", port, "regseconds", regseconds,
- "username", username, syslabel, sysname, NULL); /* note syslabel _can_ be NULL */
-}
-
-/*! \brief Automatically add peer extension to dial plan */
-static void register_peer_exten(struct sip_peer *peer, int onoff)
-{
- char multi[256];
- char *stringp, *ext, *context;
-
- /* XXX note that global_regcontext is both a global 'enable' flag and
- * the name of the global regexten context, if not specified
- * individually.
- */
- if (ast_strlen_zero(global_regcontext))
- return;
-
- ast_copy_string(multi, S_OR(peer->regexten, peer->name), sizeof(multi));
- stringp = multi;
- while ((ext = strsep(&stringp, "&"))) {
- if ((context = strchr(ext, '@'))) {
- *context++ = '\0'; /* split ext@context */
- if (!ast_context_find(context)) {
- ast_log(LOG_WARNING, "Context %s must exist in regcontext= in sip.conf!\n", context);
- continue;
- }
- } else {
- context = global_regcontext;
- }
- if (onoff) {
- if (!ast_exists_extension(NULL, context, ext, 1, NULL)) {
- ast_add_extension(context, 1, ext, 1, NULL, NULL, "Noop",
- ast_strdup(peer->name), ast_free, "SIP");
- }
- } else {
- ast_context_remove_extension(context, ext, 1, NULL);
- }
- }
-}
-
-/*! \brief Destroy peer object from memory */
-static void sip_destroy_peer(struct sip_peer *peer)
-{
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Destroying SIP peer %s\n", peer->name);
-
- /* Delete it, it needs to disappear */
- if (peer->call)
- sip_destroy(peer->call);
-
- if (peer->mwipvt) /* We have an active subscription, delete it */
- sip_destroy(peer->mwipvt);
-
- if (peer->chanvars) {
- ast_variables_destroy(peer->chanvars);
- peer->chanvars = NULL;
- }
-
- register_peer_exten(peer, FALSE);
- ast_free_ha(peer->ha);
- if (ast_test_flag(&peer->flags[1], SIP_PAGE2_SELFDESTRUCT))
- apeerobjs--;
- else if (ast_test_flag(&peer->flags[0], SIP_REALTIME))
- rpeerobjs--;
- else
- speerobjs--;
- clear_realm_authentication(peer->auth);
- peer->auth = NULL;
- free(peer);
-}
-
-/*! \brief Update peer data in database (if used) */
-static void update_peer(struct sip_peer *p, int expiry)
-{
- int rtcachefriends = ast_test_flag(&p->flags[1], SIP_PAGE2_RTCACHEFRIENDS);
- if (ast_test_flag(&global_flags[1], SIP_PAGE2_RTUPDATE) &&
- (ast_test_flag(&p->flags[0], SIP_REALTIME) || rtcachefriends)) {
- realtime_update_peer(p->name, &p->addr, p->username, rtcachefriends ? p->fullcontact : NULL, expiry);
- }
-}
-
-
-/*! \brief realtime_peer: Get peer from realtime storage
- * Checks the "sippeers" realtime family from extconfig.conf
- * \todo Consider adding check of port address when matching here to follow the same
- * algorithm as for static peers. Will we break anything by adding that?
-*/
-static struct sip_peer *realtime_peer(const char *newpeername, struct sockaddr_in *sin, int devstate_only)
-{
- struct sip_peer *peer=NULL;
- struct ast_variable *var = NULL;
- struct ast_config *peerlist = NULL;
- struct ast_variable *tmp;
- struct ast_flags flags = {0};
- const char *iabuf = NULL;
- char portstring[6]; /*up to five digits plus null terminator*/
- const char *insecure;
- char *cat = NULL;
- unsigned short portnum;
-
- /* First check on peer name */
- if (newpeername) {
- var = ast_load_realtime("sippeers", "name", newpeername, "host", "dynamic", NULL);
- if (!var && sin)
- var = ast_load_realtime("sippeers", "name", newpeername, "host", ast_inet_ntoa(sin->sin_addr), NULL);
- if (!var) {
- var = ast_load_realtime("sippeers", "name", newpeername, NULL);
- /*!\note
- * If this one loaded something, then we need to ensure that the host
- * field matched. The only reason why we can't have this as a criteria
- * is because we only have the IP address and the host field might be
- * set as a name (and the reverse PTR might not match).
- */
- if (var && sin) {
- for (tmp = var; tmp; tmp = tmp->next) {
- if (!strcasecmp(tmp->name, "host")) {
- struct hostent *hp;
- struct ast_hostent ahp;
- if (!(hp = ast_gethostbyname(tmp->value, &ahp)) || (memcmp(&hp->h_addr, &sin->sin_addr, sizeof(hp->h_addr)))) {
- /* No match */
- ast_variables_destroy(var);
- var = NULL;
- }
- break;
- }
- }
- }
- }
- }
-
- if (!var && sin) { /* Then check on IP address */
- iabuf = ast_inet_ntoa(sin->sin_addr);
- portnum = ntohs(sin->sin_port);
- sprintf(portstring, "%d", portnum);
- var = ast_load_realtime("sippeers", "host", iabuf, "port", portstring, NULL); /* First check for fixed IP hosts */
- if (!var)
- var = ast_load_realtime("sippeers", "ipaddr", iabuf, "port", portstring, NULL); /* Then check for registered hosts */
- if (!var) {
- peerlist = ast_load_realtime_multientry("sippeers", "host", iabuf, NULL); /*No exact match, see if port is insecure, try host match first*/
- if(peerlist){
- while((cat = ast_category_browse(peerlist, cat)))
- {
- insecure = ast_variable_retrieve(peerlist, cat, "insecure");
- set_insecure_flags(&flags, insecure, -1);
- if(ast_test_flag(&flags, SIP_INSECURE_PORT)) {
- var = ast_category_root(peerlist, cat);
- break;
- }
- }
- }
- if(!var) {
- ast_config_destroy(peerlist);
- peerlist = NULL; /*for safety's sake*/
- cat = NULL;
- peerlist = ast_load_realtime_multientry("sippeers", "ipaddr", iabuf, NULL); /*No exact match, see if port is insecure, now try ip address match*/
- if(peerlist) {
- while((cat = ast_category_browse(peerlist, cat)))
- {
- insecure = ast_variable_retrieve(peerlist, cat, "insecure");
- set_insecure_flags(&flags, insecure, -1);
- if(ast_test_flag(&flags, SIP_INSECURE_PORT)) {
- var = ast_category_root(peerlist, cat);
- break;
- }
- }
- }
- }
- }
- }
-
- if (!var) {
- if(peerlist)
- ast_config_destroy(peerlist);
- return NULL;
- }
-
- for (tmp = var; tmp; tmp = tmp->next) {
- /* If this is type=user, then skip this object. */
- if (!strcasecmp(tmp->name, "type") &&
- !strcasecmp(tmp->value, "user")) {
- ast_variables_destroy(var);
- return NULL;
- } else if (!newpeername && !strcasecmp(tmp->name, "name")) {
- newpeername = tmp->value;
- }
- }
-
- if (!newpeername) { /* Did not find peer in realtime */
- ast_log(LOG_WARNING, "Cannot Determine peer name ip=%s\n", iabuf);
- if(peerlist)
- ast_config_destroy(peerlist);
- else
- ast_variables_destroy(var);
- return NULL;
- }
-
- /* Peer found in realtime, now build it in memory */
- peer = build_peer(newpeername, var, NULL, 1);
- if (!peer) {
- if(peerlist)
- ast_config_destroy(peerlist);
- else
- ast_variables_destroy(var);
- return NULL;
- }
-
- if (ast_test_flag(&global_flags[1], SIP_PAGE2_RTCACHEFRIENDS) && !devstate_only) {
- /* Cache peer */
- ast_copy_flags(&peer->flags[1],&global_flags[1], SIP_PAGE2_RTAUTOCLEAR|SIP_PAGE2_RTCACHEFRIENDS);
- if (ast_test_flag(&global_flags[1], SIP_PAGE2_RTAUTOCLEAR)) {
- if (!AST_SCHED_DEL(sched, peer->expire)) {
- struct sip_peer *peer_ptr = peer;
- ASTOBJ_UNREF(peer_ptr, sip_destroy_peer);
- }
- peer->expire = ast_sched_add(sched, (global_rtautoclear) * 1000, expire_register, ASTOBJ_REF(peer));
- if (peer->expire == -1) {
- struct sip_peer *peer_ptr = peer;
- ASTOBJ_UNREF(peer_ptr, sip_destroy_peer);
- }
- }
- ASTOBJ_CONTAINER_LINK(&peerl,peer);
- }
- ast_set_flag(&peer->flags[0], SIP_REALTIME);
- if(peerlist)
- ast_config_destroy(peerlist);
- else
- ast_variables_destroy(var);
- return peer;
-}
-
-/*! \brief Support routine for find_peer */
-static int sip_addrcmp(char *name, struct sockaddr_in *sin)
-{
- /* We know name is the first field, so we can cast */
- struct sip_peer *p = (struct sip_peer *) name;
- return !(!inaddrcmp(&p->addr, sin) ||
- (ast_test_flag(&p->flags[0], SIP_INSECURE_PORT) &&
- (p->addr.sin_addr.s_addr == sin->sin_addr.s_addr)));
-}
-
-/*! \brief Locate peer by name or ip address
- * This is used on incoming SIP message to find matching peer on ip
- or outgoing message to find matching peer on name */
-static struct sip_peer *find_peer(const char *peer, struct sockaddr_in *sin, int realtime, int devstate_only)
-{
- struct sip_peer *p = NULL;
-
- if (peer)
- p = ASTOBJ_CONTAINER_FIND(&peerl, peer);
- else
- p = ASTOBJ_CONTAINER_FIND_FULL(&peerl, sin, name, sip_addr_hashfunc, 1, sip_addrcmp);
-
- if (!p && (realtime || devstate_only))
- p = realtime_peer(peer, sin, devstate_only);
-
- return p;
-}
-
-/*! \brief Remove user object from in-memory storage */
-static void sip_destroy_user(struct sip_user *user)
-{
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Destroying user object from memory: %s\n", user->name);
- ast_free_ha(user->ha);
- if (user->chanvars) {
- ast_variables_destroy(user->chanvars);
- user->chanvars = NULL;
- }
- if (ast_test_flag(&user->flags[0], SIP_REALTIME))
- ruserobjs--;
- else
- suserobjs--;
- free(user);
-}
-
-/*! \brief Load user from realtime storage
- * Loads user from "sipusers" category in realtime (extconfig.conf)
- * Users are matched on From: user name (the domain in skipped) */
-static struct sip_user *realtime_user(const char *username)
-{
- struct ast_variable *var;
- struct ast_variable *tmp;
- struct sip_user *user = NULL;
-
- var = ast_load_realtime("sipusers", "name", username, NULL);
-
- if (!var)
- return NULL;
-
- for (tmp = var; tmp; tmp = tmp->next) {
- if (!strcasecmp(tmp->name, "type") &&
- !strcasecmp(tmp->value, "peer")) {
- ast_variables_destroy(var);
- return NULL;
- }
- }
-
- user = build_user(username, var, NULL, !ast_test_flag(&global_flags[1], SIP_PAGE2_RTCACHEFRIENDS));
-
- if (!user) { /* No user found */
- ast_variables_destroy(var);
- return NULL;
- }
-
- if (ast_test_flag(&global_flags[1], SIP_PAGE2_RTCACHEFRIENDS)) {
- ast_set_flag(&user->flags[1], SIP_PAGE2_RTCACHEFRIENDS);
- suserobjs++;
- ASTOBJ_CONTAINER_LINK(&userl,user);
- } else {
- /* Move counter from s to r... */
- suserobjs--;
- ruserobjs++;
- }
- ast_set_flag(&user->flags[0], SIP_REALTIME);
- ast_variables_destroy(var);
- return user;
-}
-
-/*! \brief Locate user by name
- * Locates user by name (From: sip uri user name part) first
- * from in-memory list (static configuration) then from
- * realtime storage (defined in extconfig.conf) */
-static struct sip_user *find_user(const char *name, int realtime)
-{
- struct sip_user *u = ASTOBJ_CONTAINER_FIND(&userl, name);
- if (!u && realtime)
- u = realtime_user(name);
- return u;
-}
-
-/*! \brief Set nat mode on the various data sockets */
-static void do_setnat(struct sip_pvt *p, int natflags)
-{
- const char *mode = natflags ? "On" : "Off";
-
- if (p->rtp) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Setting NAT on RTP to %s\n", mode);
- ast_rtp_setnat(p->rtp, natflags);
- }
- if (p->vrtp) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Setting NAT on VRTP to %s\n", mode);
- ast_rtp_setnat(p->vrtp, natflags);
- }
- if (p->udptl) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Setting NAT on UDPTL to %s\n", mode);
- ast_udptl_setnat(p->udptl, natflags);
- }
-}
-
-/*! \brief Create address structure from peer reference.
- * return -1 on error, 0 on success.
- */
-static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer)
-{
- if ((peer->addr.sin_addr.s_addr || peer->defaddr.sin_addr.s_addr) &&
- (!peer->maxms || ((peer->lastms >= 0) && (peer->lastms <= peer->maxms)))) {
- dialog->sa = (peer->addr.sin_addr.s_addr) ? peer->addr : peer->defaddr;
- dialog->recv = dialog->sa;
- } else
- return -1;
-
- 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);
- dialog->capability = peer->capability;
- if ((!ast_test_flag(&dialog->flags[1], SIP_PAGE2_VIDEOSUPPORT) || !(dialog->capability & AST_FORMAT_VIDEO_MASK)) && dialog->vrtp) {
- ast_rtp_destroy(dialog->vrtp);
- dialog->vrtp = NULL;
- }
- dialog->prefs = peer->prefs;
- if (ast_test_flag(&dialog->flags[1], SIP_PAGE2_T38SUPPORT)) {
- dialog->t38.capability = global_t38_capability;
- if (dialog->udptl) {
- if (ast_udptl_get_error_correction_scheme(dialog->udptl) == UDPTL_ERROR_CORRECTION_FEC )
- dialog->t38.capability |= T38FAX_UDP_EC_FEC;
- else if (ast_udptl_get_error_correction_scheme(dialog->udptl) == UDPTL_ERROR_CORRECTION_REDUNDANCY )
- dialog->t38.capability |= T38FAX_UDP_EC_REDUNDANCY;
- else if (ast_udptl_get_error_correction_scheme(dialog->udptl) == UDPTL_ERROR_CORRECTION_NONE )
- dialog->t38.capability |= T38FAX_UDP_EC_NONE;
- dialog->t38.capability |= T38FAX_RATE_MANAGEMENT_TRANSFERED_TCF;
- if (option_debug > 1)
- ast_log(LOG_DEBUG,"Our T38 capability (%d)\n", dialog->t38.capability);
- }
- dialog->t38.jointcapability = dialog->t38.capability;
- } else if (dialog->udptl) {
- ast_udptl_destroy(dialog->udptl);
- dialog->udptl = NULL;
- }
- do_setnat(dialog, ast_test_flag(&dialog->flags[0], SIP_NAT) & SIP_NAT_ROUTE );
-
- if (dialog->rtp) {
- ast_rtp_setdtmf(dialog->rtp, ast_test_flag(&dialog->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833);
- ast_rtp_setdtmfcompensate(dialog->rtp, ast_test_flag(&dialog->flags[1], SIP_PAGE2_RFC2833_COMPENSATE));
- ast_rtp_set_rtptimeout(dialog->rtp, peer->rtptimeout);
- ast_rtp_set_rtpholdtimeout(dialog->rtp, peer->rtpholdtimeout);
- ast_rtp_set_rtpkeepalive(dialog->rtp, peer->rtpkeepalive);
- /* Set Frame packetization */
- ast_rtp_codec_setpref(dialog->rtp, &dialog->prefs);
- dialog->autoframing = peer->autoframing;
- }
- if (dialog->vrtp) {
- ast_rtp_setdtmf(dialog->vrtp, 0);
- ast_rtp_setdtmfcompensate(dialog->vrtp, 0);
- ast_rtp_set_rtptimeout(dialog->vrtp, peer->rtptimeout);
- ast_rtp_set_rtpholdtimeout(dialog->vrtp, peer->rtpholdtimeout);
- ast_rtp_set_rtpkeepalive(dialog->vrtp, peer->rtpkeepalive);
- }
-
- ast_string_field_set(dialog, peername, peer->name);
- ast_string_field_set(dialog, authname, peer->username);
- ast_string_field_set(dialog, username, peer->username);
- ast_string_field_set(dialog, peersecret, peer->secret);
- ast_string_field_set(dialog, peermd5secret, peer->md5secret);
- ast_string_field_set(dialog, mohsuggest, peer->mohsuggest);
- ast_string_field_set(dialog, mohinterpret, peer->mohinterpret);
- ast_string_field_set(dialog, tohost, peer->tohost);
- ast_string_field_set(dialog, fullcontact, peer->fullcontact);
- if (!dialog->initreq.headers && !ast_strlen_zero(peer->fromdomain)) {
- char *tmpcall;
- char *c;
- tmpcall = ast_strdupa(dialog->callid);
- c = strchr(tmpcall, '@');
- if (c) {
- *c = '\0';
- ast_string_field_build(dialog, callid, "%s@%s", tmpcall, peer->fromdomain);
- }
- }
- if (ast_strlen_zero(dialog->tohost))
- ast_string_field_set(dialog, tohost, ast_inet_ntoa(dialog->sa.sin_addr));
- if (!ast_strlen_zero(peer->fromdomain))
- ast_string_field_set(dialog, fromdomain, peer->fromdomain);
- if (!ast_strlen_zero(peer->fromuser))
- ast_string_field_set(dialog, fromuser, peer->fromuser);
- if (!ast_strlen_zero(peer->language))
- ast_string_field_set(dialog, language, peer->language);
- dialog->maxtime = peer->maxms;
- dialog->callgroup = peer->callgroup;
- dialog->pickupgroup = peer->pickupgroup;
- dialog->peerauth = peer->auth;
- dialog->allowtransfer = peer->allowtransfer;
- /* Set timer T1 to RTT for this peer (if known by qualify=) */
- /* Minimum is settable or default to 100 ms */
- if (peer->maxms && peer->lastms)
- dialog->timer_t1 = peer->lastms < global_t1min ? global_t1min : peer->lastms;
- if ((ast_test_flag(&dialog->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833) ||
- (ast_test_flag(&dialog->flags[0], SIP_DTMF) == SIP_DTMF_AUTO))
- dialog->noncodeccapability |= AST_RTP_DTMF;
- else
- dialog->noncodeccapability &= ~AST_RTP_DTMF;
- dialog->jointnoncodeccapability = dialog->noncodeccapability;
- ast_string_field_set(dialog, context, peer->context);
- dialog->rtptimeout = peer->rtptimeout;
- if (peer->call_limit)
- ast_set_flag(&dialog->flags[0], SIP_CALL_LIMIT);
- dialog->maxcallbitrate = peer->maxcallbitrate;
-
- return 0;
-}
-
-/*! \brief create address structure from peer name
- * Or, if peer not found, find it in the global DNS
- * returns TRUE (-1) on failure, FALSE on success */
-static int create_addr(struct sip_pvt *dialog, const char *opeer)
-{
- struct hostent *hp;
- struct ast_hostent ahp;
- struct sip_peer *p;
- char *port;
- int portno;
- char host[MAXHOSTNAMELEN], *hostn;
- char peer[256];
-
- ast_copy_string(peer, opeer, sizeof(peer));
- port = strchr(peer, ':');
- if (port)
- *port++ = '\0';
- dialog->sa.sin_family = AF_INET;
- dialog->timer_t1 = 500; /* Default SIP retransmission timer T1 (RFC 3261) */
- p = find_peer(peer, NULL, 1, 0);
-
- if (p) {
- int res = create_addr_from_peer(dialog, p);
- if (port) {
- portno = atoi(port);
- dialog->sa.sin_port = dialog->recv.sin_port = htons(portno);
- }
- ASTOBJ_UNREF(p, sip_destroy_peer);
- return res;
- }
- hostn = peer;
- portno = port ? atoi(port) : STANDARD_SIP_PORT;
- if (srvlookup) {
- char service[MAXHOSTNAMELEN];
- int tportno;
- int ret;
-
- snprintf(service, sizeof(service), "_sip._udp.%s", peer);
- ret = ast_get_srv(NULL, host, sizeof(host), &tportno, service);
- if (ret > 0) {
- hostn = host;
- portno = tportno;
- }
- }
- hp = ast_gethostbyname(hostn, &ahp);
- if (!hp) {
- ast_log(LOG_WARNING, "No such host: %s\n", peer);
- return -1;
- }
- ast_string_field_set(dialog, tohost, peer);
- memcpy(&dialog->sa.sin_addr, hp->h_addr, sizeof(dialog->sa.sin_addr));
- dialog->sa.sin_port = htons(portno);
- dialog->recv = dialog->sa;
- return 0;
-}
-
-/*! \brief Scheduled congestion on a call */
-static int auto_congest(const void *nothing)
-{
- struct sip_pvt *p = (struct sip_pvt *)nothing;
-
- ast_mutex_lock(&p->lock);
- p->initid = -1;
- if (p->owner) {
- /* XXX fails on possible deadlock */
- if (!ast_channel_trylock(p->owner)) {
- ast_log(LOG_NOTICE, "Auto-congesting %s\n", p->owner->name);
- append_history(p, "Cong", "Auto-congesting (timer)");
- ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
- ast_channel_unlock(p->owner);
- }
- }
- ast_mutex_unlock(&p->lock);
- return 0;
-}
-
-
-/*! \brief Initiate SIP call from PBX
- * used from the dial() application */
-static int sip_call(struct ast_channel *ast, char *dest, int timeout)
-{
- int res, xmitres = 0;
- struct sip_pvt *p;
- struct varshead *headp;
- struct ast_var_t *current;
- const char *referer = NULL; /* SIP refererer */
-
- p = ast->tech_pvt;
- if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
- ast_log(LOG_WARNING, "sip_call called on %s, neither down nor reserved\n", ast->name);
- return -1;
- }
-
- /* Check whether there is vxml_url, distinctive ring variables */
- headp=&ast->varshead;
- AST_LIST_TRAVERSE(headp,current,entries) {
- /* Check whether there is a VXML_URL variable */
- if (!p->options->vxml_url && !strcasecmp(ast_var_name(current), "VXML_URL")) {
- p->options->vxml_url = ast_var_value(current);
- } else if (!p->options->uri_options && !strcasecmp(ast_var_name(current), "SIP_URI_OPTIONS")) {
- p->options->uri_options = ast_var_value(current);
- } else if (!p->options->distinctive_ring && !strcasecmp(ast_var_name(current), "ALERT_INFO")) {
- /* Check whether there is a ALERT_INFO variable */
- p->options->distinctive_ring = ast_var_value(current);
- } else if (!p->options->addsipheaders && !strncasecmp(ast_var_name(current), "SIPADDHEADER", strlen("SIPADDHEADER"))) {
- /* Check whether there is a variable with a name starting with SIPADDHEADER */
- p->options->addsipheaders = 1;
- } else if (!strcasecmp(ast_var_name(current), "SIPTRANSFER")) {
- /* This is a transfered call */
- p->options->transfer = 1;
- } else if (!strcasecmp(ast_var_name(current), "SIPTRANSFER_REFERER")) {
- /* This is the referer */
- referer = ast_var_value(current);
- } else if (!strcasecmp(ast_var_name(current), "SIPTRANSFER_REPLACES")) {
- /* We're replacing a call. */
- p->options->replaces = ast_var_value(current);
- } else if (!strcasecmp(ast_var_name(current), "T38CALL")) {
- p->t38.state = T38_LOCAL_DIRECT;
- if (option_debug)
- ast_log(LOG_DEBUG,"T38State change to %d on channel %s\n", p->t38.state, ast->name);
- }
-
- }
-
- res = 0;
- ast_set_flag(&p->flags[0], SIP_OUTGOING);
-
- if (p->options->transfer) {
- char buf[SIPBUFSIZE/2];
-
- if (referer) {
- if (sipdebug && option_debug > 2)
- ast_log(LOG_DEBUG, "Call for %s transfered by %s\n", p->username, referer);
- snprintf(buf, sizeof(buf)-1, "-> %s (via %s)", p->cid_name, referer);
- } else
- snprintf(buf, sizeof(buf)-1, "-> %s", p->cid_name);
- ast_string_field_set(p, cid_name, buf);
- }
- if (option_debug)
- ast_log(LOG_DEBUG, "Outgoing Call for %s\n", p->username);
-
- res = update_call_counter(p, INC_CALL_RINGING);
- if ( res != -1 ) {
- p->callingpres = ast->cid.cid_pres;
- p->jointcapability = ast_translate_available_formats(p->capability, p->prefcodec);
- p->jointnoncodeccapability = p->noncodeccapability;
-
- /* If there are no audio formats left to offer, punt */
- if (!(p->jointcapability & AST_FORMAT_AUDIO_MASK)) {
- ast_log(LOG_WARNING, "No audio format found to offer. Cancelling call to %s\n", p->username);
- res = -1;
- } else {
- p->t38.jointcapability = p->t38.capability;
- if (option_debug > 1)
- ast_log(LOG_DEBUG,"Our T38 capability (%d), joint T38 capability (%d)\n", p->t38.capability, p->t38.jointcapability);
- xmitres = transmit_invite(p, SIP_INVITE, 1, 2);
- if (xmitres == XMIT_ERROR)
- return -1; /* Transmission error */
-
- p->invitestate = INV_CALLING;
-
- /* Initialize auto-congest time */
- AST_SCHED_DEL(sched, p->initid);
- p->initid = ast_sched_add(sched, p->maxtime ? (p->maxtime * 4) : SIP_TRANS_TIMEOUT, auto_congest, p);
- }
- } else {
- ast->hangupcause = AST_CAUSE_USER_BUSY;
- }
- return res;
-}
-
-/*! \brief Destroy registry object
- Objects created with the register= statement in static configuration */
-static void sip_registry_destroy(struct sip_registry *reg)
-{
- /* Really delete */
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Destroying registry entry for %s@%s\n", reg->username, reg->hostname);
-
- if (reg->call) {
- /* Clear registry before destroying to ensure
- we don't get reentered trying to grab the registry lock */
- reg->call->registry = NULL;
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Destroying active SIP dialog for registry %s@%s\n", reg->username, reg->hostname);
- sip_destroy(reg->call);
- }
- AST_SCHED_DEL(sched, reg->expire);
- AST_SCHED_DEL(sched, reg->timeout);
- ast_string_field_free_memory(reg);
- regobjs--;
- free(reg);
-
-}
-
-/*! \brief Execute destruction of SIP dialog structure, release memory */
-static int __sip_destroy(struct sip_pvt *p, int lockowner)
-{
- struct sip_pvt *cur, *prev = NULL;
- struct sip_pkt *cp;
- struct sip_request *req;
-
- /* We absolutely cannot destroy the rtp struct while a bridge is active or we WILL crash */
- if (p->rtp && ast_rtp_get_bridged(p->rtp)) {
- ast_verbose("Bridge still active. Delaying destroy of SIP dialog '%s' Method: %s\n", p->callid, sip_methods[p->method].text);
- return -1;
- }
-
- if (p->vrtp && ast_rtp_get_bridged(p->vrtp)) {
- ast_verbose("Bridge still active. Delaying destroy of SIP dialog '%s' Method: %s\n", p->callid, sip_methods[p->method].text);
- return -1;
- }
-
- if (sip_debug_test_pvt(p) || option_debug > 2)
- ast_verbose("Really destroying SIP dialog '%s' Method: %s\n", p->callid, sip_methods[p->method].text);
-
- if (ast_test_flag(&p->flags[0], SIP_INC_COUNT) || ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD)) {
- update_call_counter(p, DEC_CALL_LIMIT);
- if (option_debug > 1)
- ast_log(LOG_DEBUG, "This call did not properly clean up call limits. Call ID %s\n", p->callid);
- }
-
- /* Unlink us from the owner if we have one */
- if (p->owner) {
- if (lockowner)
- ast_channel_lock(p->owner);
- if (option_debug)
- ast_log(LOG_DEBUG, "Detaching from %s\n", p->owner->name);
- p->owner->tech_pvt = NULL;
- /* Make sure that the channel knows its backend is going away */
- p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
- if (lockowner)
- ast_channel_unlock(p->owner);
- /* Give the channel a chance to react before deallocation */
- usleep(1);
- }
-
- /* Remove link from peer to subscription of MWI */
- if (p->relatedpeer) {
- if (p->relatedpeer->mwipvt == p) {
- p->relatedpeer->mwipvt = NULL;
- }
- ASTOBJ_UNREF(p->relatedpeer, sip_destroy_peer);
- }
-
- if (dumphistory)
- sip_dump_history(p);
-
- if (p->options)
- free(p->options);
-
- if (p->stateid > -1)
- ast_extension_state_del(p->stateid, NULL);
- AST_SCHED_DEL(sched, p->initid);
- AST_SCHED_DEL(sched, p->waitid);
- AST_SCHED_DEL(sched, p->autokillid);
- AST_SCHED_DEL(sched, p->request_queue_sched_id);
-
- if (p->rtp) {
- ast_rtp_destroy(p->rtp);
- }
- if (p->vrtp) {
- ast_rtp_destroy(p->vrtp);
- }
- if (p->udptl)
- ast_udptl_destroy(p->udptl);
- if (p->refer)
- free(p->refer);
- if (p->route) {
- free_old_route(p->route);
- p->route = NULL;
- }
- if (p->registry) {
- if (p->registry->call == p)
- p->registry->call = NULL;
- ASTOBJ_UNREF(p->registry, sip_registry_destroy);
- }
-
- /* Clear history */
- if (p->history) {
- struct sip_history *hist;
- while ( (hist = AST_LIST_REMOVE_HEAD(p->history, list)) ) {
- free(hist);
- p->history_entries--;
- }
- free(p->history);
- p->history = NULL;
- }
-
- while ((req = AST_LIST_REMOVE_HEAD(&p->request_queue, next))) {
- ast_free(req);
- }
-
- for (prev = NULL, cur = iflist; cur; prev = cur, cur = cur->next) {
- if (cur == p) {
- UNLINK(cur, iflist, prev);
- break;
- }
- }
- if (!cur) {
- ast_log(LOG_WARNING, "Trying to destroy \"%s\", not found in dialog list?!?! \n", p->callid);
- return 0;
- }
-
- /* remove all current packets in this dialog */
- while((cp = p->packets)) {
- p->packets = p->packets->next;
- AST_SCHED_DEL(sched, cp->retransid);
- free(cp);
- }
- if (p->chanvars) {
- ast_variables_destroy(p->chanvars);
- p->chanvars = NULL;
- }
- ast_mutex_destroy(&p->lock);
-
- ast_string_field_free_memory(p);
-
- free(p);
- return 0;
-}
-
-/*! \brief update_call_counter: Handle call_limit for SIP users
- * Setting a call-limit will cause calls above the limit not to be accepted.
- *
- * Remember that for a type=friend, there's one limit for the user and
- * another for the peer, not a combined call limit.
- * This will cause unexpected behaviour in subscriptions, since a "friend"
- * is *two* devices in Asterisk, not one.
- *
- * Thought: For realtime, we should propably update storage with inuse counter...
- *
- * \return 0 if call is ok (no call limit, below treshold)
- * -1 on rejection of call
- *
- */
-static int update_call_counter(struct sip_pvt *fup, int event)
-{
- char name[256];
- int *inuse = NULL, *call_limit = NULL, *inringing = NULL;
- int outgoing = ast_test_flag(&fup->flags[1], SIP_PAGE2_OUTGOING_CALL);
- struct sip_user *u = NULL;
- struct sip_peer *p = NULL;
-
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Updating call counter for %s call\n", outgoing ? "outgoing" : "incoming");
-
- /* Test if we need to check call limits, in order to avoid
- realtime lookups if we do not need it */
- if (!ast_test_flag(&fup->flags[0], SIP_CALL_LIMIT) && !ast_test_flag(&fup->flags[1], SIP_PAGE2_CALL_ONHOLD))
- return 0;
-
- ast_copy_string(name, fup->username, sizeof(name));
-
- /* Check the list of users only for incoming calls */
- if (global_limitonpeers == FALSE && !outgoing && (u = find_user(name, 1))) {
- inuse = &u->inUse;
- call_limit = &u->call_limit;
- inringing = NULL;
- } else if ( (p = find_peer(ast_strlen_zero(fup->peername) ? name : fup->peername, NULL, 1, 0) ) ) { /* Try to find peer */
- inuse = &p->inUse;
- call_limit = &p->call_limit;
- inringing = &p->inRinging;
- ast_copy_string(name, fup->peername, sizeof(name));
- }
- if (!p && !u) {
- if (option_debug > 1)
- ast_log(LOG_DEBUG, "%s is not a local device, no call limit\n", name);
- return 0;
- }
-
- switch(event) {
- /* incoming and outgoing affects the inUse counter */
- case DEC_CALL_LIMIT:
- if ( *inuse > 0 ) {
- if (ast_test_flag(&fup->flags[0], SIP_INC_COUNT)) {
- (*inuse)--;
- ast_clear_flag(&fup->flags[0], SIP_INC_COUNT);
- }
- } else {
- *inuse = 0;
- }
- if (inringing) {
- if (ast_test_flag(&fup->flags[1], SIP_PAGE2_INC_RINGING)) {
- if (*inringing > 0)
- (*inringing)--;
- else if (!ast_test_flag(&p->flags[0], SIP_REALTIME) || ast_test_flag(&p->flags[1], SIP_PAGE2_RTCACHEFRIENDS))
- ast_log(LOG_WARNING, "Inringing for peer '%s' < 0?\n", fup->peername);
- ast_clear_flag(&fup->flags[1], SIP_PAGE2_INC_RINGING);
- }
- }
- if (ast_test_flag(&fup->flags[1], SIP_PAGE2_CALL_ONHOLD) && global_notifyhold) {
- ast_clear_flag(&fup->flags[1], SIP_PAGE2_CALL_ONHOLD);
- sip_peer_hold(fup, 0);
- }
- if (option_debug > 1 || sipdebug) {
- ast_log(LOG_DEBUG, "Call %s %s '%s' removed from call limit %d\n", outgoing ? "to" : "from", u ? "user":"peer", name, *call_limit);
- }
- break;
-
- case INC_CALL_RINGING:
- case INC_CALL_LIMIT:
- if (*call_limit > 0 ) {
- if (*inuse >= *call_limit) {
- ast_log(LOG_ERROR, "Call %s %s '%s' rejected due to usage limit of %d\n", outgoing ? "to" : "from", u ? "user":"peer", name, *call_limit);
- if (u)
- ASTOBJ_UNREF(u, sip_destroy_user);
- else
- ASTOBJ_UNREF(p, sip_destroy_peer);
- return -1;
- }
- }
- if (inringing && (event == INC_CALL_RINGING)) {
- if (!ast_test_flag(&fup->flags[1], SIP_PAGE2_INC_RINGING)) {
- (*inringing)++;
- ast_set_flag(&fup->flags[1], SIP_PAGE2_INC_RINGING);
- }
- }
- /* Continue */
- (*inuse)++;
- ast_set_flag(&fup->flags[0], SIP_INC_COUNT);
- if (option_debug > 1 || sipdebug) {
- ast_log(LOG_DEBUG, "Call %s %s '%s' is %d out of %d\n", outgoing ? "to" : "from", u ? "user":"peer", name, *inuse, *call_limit);
- }
- break;
-
- case DEC_CALL_RINGING:
- if (inringing) {
- if (ast_test_flag(&fup->flags[1], SIP_PAGE2_INC_RINGING)) {
- if (*inringing > 0)
- (*inringing)--;
- else if (!ast_test_flag(&p->flags[0], SIP_REALTIME) || ast_test_flag(&p->flags[1], SIP_PAGE2_RTCACHEFRIENDS))
- ast_log(LOG_WARNING, "Inringing for peer '%s' < 0?\n", p->name);
- ast_clear_flag(&fup->flags[1], SIP_PAGE2_INC_RINGING);
- }
- }
- break;
-
- default:
- ast_log(LOG_ERROR, "update_call_counter(%s, %d) called with no event!\n", name, event);
- }
- if (p) {
- ast_device_state_changed("SIP/%s", p->name);
- ASTOBJ_UNREF(p, sip_destroy_peer);
- } else /* u must be set */
- ASTOBJ_UNREF(u, sip_destroy_user);
- return 0;
-}
-
-/*! \brief Destroy SIP call structure */
-static void sip_destroy(struct sip_pvt *p)
-{
- ast_mutex_lock(&iflock);
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Destroying SIP dialog %s\n", p->callid);
- __sip_destroy(p, 1);
- ast_mutex_unlock(&iflock);
-}
-
-/*! \brief Convert SIP hangup causes to Asterisk hangup causes */
-static int hangup_sip2cause(int cause)
-{
- /* Possible values taken from causes.h */
-
- switch(cause) {
- case 401: /* Unauthorized */
- return AST_CAUSE_CALL_REJECTED;
- case 403: /* Not found */
- return AST_CAUSE_CALL_REJECTED;
- case 404: /* Not found */
- return AST_CAUSE_UNALLOCATED;
- case 405: /* Method not allowed */
- return AST_CAUSE_INTERWORKING;
- case 407: /* Proxy authentication required */
- return AST_CAUSE_CALL_REJECTED;
- case 408: /* No reaction */
- return AST_CAUSE_NO_USER_RESPONSE;
- case 409: /* Conflict */
- return AST_CAUSE_NORMAL_TEMPORARY_FAILURE;
- case 410: /* Gone */
- return AST_CAUSE_UNALLOCATED;
- case 411: /* Length required */
- return AST_CAUSE_INTERWORKING;
- case 413: /* Request entity too large */
- return AST_CAUSE_INTERWORKING;
- case 414: /* Request URI too large */
- return AST_CAUSE_INTERWORKING;
- case 415: /* Unsupported media type */
- return AST_CAUSE_INTERWORKING;
- case 420: /* Bad extension */
- return AST_CAUSE_NO_ROUTE_DESTINATION;
- case 480: /* No answer */
- return AST_CAUSE_NO_ANSWER;
- case 481: /* No answer */
- return AST_CAUSE_INTERWORKING;
- case 482: /* Loop detected */
- return AST_CAUSE_INTERWORKING;
- case 483: /* Too many hops */
- return AST_CAUSE_NO_ANSWER;
- case 484: /* Address incomplete */
- return AST_CAUSE_INVALID_NUMBER_FORMAT;
- case 485: /* Ambigous */
- return AST_CAUSE_UNALLOCATED;
- case 486: /* Busy everywhere */
- return AST_CAUSE_BUSY;
- case 487: /* Request terminated */
- return AST_CAUSE_INTERWORKING;
- case 488: /* No codecs approved */
- return AST_CAUSE_BEARERCAPABILITY_NOTAVAIL;
- case 491: /* Request pending */
- return AST_CAUSE_INTERWORKING;
- case 493: /* Undecipherable */
- return AST_CAUSE_INTERWORKING;
- case 500: /* Server internal failure */
- return AST_CAUSE_FAILURE;
- case 501: /* Call rejected */
- return AST_CAUSE_FACILITY_REJECTED;
- case 502:
- return AST_CAUSE_DESTINATION_OUT_OF_ORDER;
- case 503: /* Service unavailable */
- return AST_CAUSE_CONGESTION;
- case 504: /* Gateway timeout */
- return AST_CAUSE_RECOVERY_ON_TIMER_EXPIRE;
- case 505: /* SIP version not supported */
- return AST_CAUSE_INTERWORKING;
- case 600: /* Busy everywhere */
- return AST_CAUSE_USER_BUSY;
- case 603: /* Decline */
- return AST_CAUSE_CALL_REJECTED;
- case 604: /* Does not exist anywhere */
- return AST_CAUSE_UNALLOCATED;
- case 606: /* Not acceptable */
- return AST_CAUSE_BEARERCAPABILITY_NOTAVAIL;
- default:
- return AST_CAUSE_NORMAL;
- }
- /* Never reached */
- return 0;
-}
-
-/*! \brief Convert Asterisk hangup causes to SIP codes
-\verbatim
- Possible values from causes.h
- AST_CAUSE_NOTDEFINED AST_CAUSE_NORMAL AST_CAUSE_BUSY
- AST_CAUSE_FAILURE AST_CAUSE_CONGESTION AST_CAUSE_UNALLOCATED
-
- In addition to these, a lot of PRI codes is defined in causes.h
- ...should we take care of them too ?
-
- Quote RFC 3398
-
- ISUP Cause value SIP response
- ---------------- ------------
- 1 unallocated number 404 Not Found
- 2 no route to network 404 Not found
- 3 no route to destination 404 Not found
- 16 normal call clearing --- (*)
- 17 user busy 486 Busy here
- 18 no user responding 408 Request Timeout
- 19 no answer from the user 480 Temporarily unavailable
- 20 subscriber absent 480 Temporarily unavailable
- 21 call rejected 403 Forbidden (+)
- 22 number changed (w/o diagnostic) 410 Gone
- 22 number changed (w/ diagnostic) 301 Moved Permanently
- 23 redirection to new destination 410 Gone
- 26 non-selected user clearing 404 Not Found (=)
- 27 destination out of order 502 Bad Gateway
- 28 address incomplete 484 Address incomplete
- 29 facility rejected 501 Not implemented
- 31 normal unspecified 480 Temporarily unavailable
-\endverbatim
-*/
-static const char *hangup_cause2sip(int cause)
-{
- switch (cause) {
- case AST_CAUSE_UNALLOCATED: /* 1 */
- case AST_CAUSE_NO_ROUTE_DESTINATION: /* 3 IAX2: Can't find extension in context */
- case AST_CAUSE_NO_ROUTE_TRANSIT_NET: /* 2 */
- return "404 Not Found";
- case AST_CAUSE_CONGESTION: /* 34 */
- case AST_CAUSE_SWITCH_CONGESTION: /* 42 */
- return "503 Service Unavailable";
- case AST_CAUSE_NO_USER_RESPONSE: /* 18 */
- return "408 Request Timeout";
- case AST_CAUSE_NO_ANSWER: /* 19 */
- case AST_CAUSE_UNREGISTERED: /* 20 */
- return "480 Temporarily unavailable";
- case AST_CAUSE_CALL_REJECTED: /* 21 */
- return "403 Forbidden";
- case AST_CAUSE_NUMBER_CHANGED: /* 22 */
- return "410 Gone";
- case AST_CAUSE_NORMAL_UNSPECIFIED: /* 31 */
- return "480 Temporarily unavailable";
- case AST_CAUSE_INVALID_NUMBER_FORMAT:
- return "484 Address incomplete";
- case AST_CAUSE_USER_BUSY:
- return "486 Busy here";
- case AST_CAUSE_FAILURE:
- return "500 Server internal failure";
- case AST_CAUSE_FACILITY_REJECTED: /* 29 */
- return "501 Not Implemented";
- case AST_CAUSE_CHAN_NOT_IMPLEMENTED:
- return "503 Service Unavailable";
- /* Used in chan_iax2 */
- case AST_CAUSE_DESTINATION_OUT_OF_ORDER:
- return "502 Bad Gateway";
- case AST_CAUSE_BEARERCAPABILITY_NOTAVAIL: /* Can't find codec to connect to host */
- return "488 Not Acceptable Here";
-
- case AST_CAUSE_NOTDEFINED:
- default:
- if (option_debug)
- ast_log(LOG_DEBUG, "AST hangup cause %d (no match found in SIP)\n", cause);
- return NULL;
- }
-
- /* Never reached */
- return 0;
-}
-
-
-/*! \brief sip_hangup: Hangup SIP call
- * Part of PBX interface, called from ast_hangup */
-static int sip_hangup(struct ast_channel *ast)
-{
- struct sip_pvt *p = ast->tech_pvt;
- int needcancel = FALSE;
- int needdestroy = 0;
- struct ast_channel *oldowner = ast;
-
- if (!p) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Asked to hangup channel that was not connected\n");
- return 0;
- }
-
- if (ast_test_flag(&p->flags[0], SIP_DEFER_BYE_ON_TRANSFER)) {
- if (ast_test_flag(&p->flags[0], SIP_INC_COUNT) || ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD)) {
- if (option_debug && sipdebug)
- ast_log(LOG_DEBUG, "update_call_counter(%s) - decrement call limit counter on hangup\n", p->username);
- update_call_counter(p, DEC_CALL_LIMIT);
- }
- if (option_debug >3)
- ast_log(LOG_DEBUG, "SIP Transfer: Not hanging up right now... Rescheduling hangup for %s.\n", p->callid);
- if (p->autokillid > -1 && sip_cancel_destroy(p))
- ast_log(LOG_WARNING, "Unable to cancel SIP destruction. Expect bad things.\n");
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- ast_clear_flag(&p->flags[0], SIP_DEFER_BYE_ON_TRANSFER); /* Really hang up next time */
- ast_clear_flag(&p->flags[0], SIP_NEEDDESTROY);
- p->owner->tech_pvt = NULL;
- p->owner = NULL; /* Owner will be gone after we return, so take it away */
- return 0;
- }
- if (option_debug) {
- if (ast_test_flag(ast, AST_FLAG_ZOMBIE) && p->refer && option_debug)
- ast_log(LOG_DEBUG, "SIP Transfer: Hanging up Zombie channel %s after transfer ... Call-ID: %s\n", ast->name, p->callid);
- else {
- if (option_debug)
- ast_log(LOG_DEBUG, "Hangup call %s, SIP callid %s)\n", ast->name, p->callid);
- }
- }
- if (option_debug && ast_test_flag(ast, AST_FLAG_ZOMBIE))
- ast_log(LOG_DEBUG, "Hanging up zombie call. Be scared.\n");
-
- ast_mutex_lock(&p->lock);
- if (ast_test_flag(&p->flags[0], SIP_INC_COUNT) || ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD)) {
- if (option_debug && sipdebug)
- ast_log(LOG_DEBUG, "update_call_counter(%s) - decrement call limit counter on hangup\n", p->username);
- update_call_counter(p, DEC_CALL_LIMIT);
- }
-
- /* Determine how to disconnect */
- if (p->owner != ast) {
- ast_log(LOG_WARNING, "Huh? We aren't the owner? Can't hangup call.\n");
- ast_mutex_unlock(&p->lock);
- return 0;
- }
- /* If the call is not UP, we need to send CANCEL instead of BYE */
- if (ast->_state == AST_STATE_RING || ast->_state == AST_STATE_RINGING || (p->invitestate < INV_COMPLETED && ast->_state != AST_STATE_UP)) {
- needcancel = TRUE;
- if (option_debug > 3)
- ast_log(LOG_DEBUG, "Hanging up channel in state %s (not UP)\n", ast_state2str(ast->_state));
- }
-
- stop_media_flows(p); /* Immediately stop RTP, VRTP and UDPTL as applicable */
-
- append_history(p, needcancel ? "Cancel" : "Hangup", "Cause %s", p->owner ? ast_cause2str(p->owner->hangupcause) : "Unknown");
-
- /* Disconnect */
- if (p->vad)
- ast_dsp_free(p->vad);
-
- p->owner = NULL;
- ast->tech_pvt = NULL;
-
- ast_module_unref(ast_module_info->self);
-
- /* Do not destroy this pvt until we have timeout or
- get an answer to the BYE or INVITE/CANCEL
- If we get no answer during retransmit period, drop the call anyway.
- (Sorry, mother-in-law, you can't deny a hangup by sending
- 603 declined to BYE...)
- */
- if (ast_test_flag(&p->flags[0], SIP_ALREADYGONE))
- needdestroy = 1; /* Set destroy flag at end of this function */
- else if (p->invitestate != INV_CALLING)
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
-
- /* Start the process if it's not already started */
- if (!ast_test_flag(&p->flags[0], SIP_ALREADYGONE) && !ast_strlen_zero(p->initreq.data)) {
- if (needcancel) { /* Outgoing call, not up */
- if (ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
- /* stop retransmitting an INVITE that has not received a response */
- __sip_pretend_ack(p);
- p->invitestate = INV_CANCELLED;
-
- /* if we can't send right now, mark it pending */
- if (p->invitestate == INV_CALLING) {
- /* We can't send anything in CALLING state */
- ast_set_flag(&p->flags[0], SIP_PENDINGBYE);
- /* Do we need a timer here if we don't hear from them at all? Yes we do or else we will get hung dialogs and those are no fun. */
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- append_history(p, "DELAY", "Not sending cancel, waiting for timeout");
- } else {
- /* Send a new request: CANCEL */
- transmit_request(p, SIP_CANCEL, p->lastinvite, XMIT_RELIABLE, FALSE);
- /* Actually don't destroy us yet, wait for the 487 on our original
- INVITE, but do set an autodestruct just in case we never get it. */
- needdestroy = 0;
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- }
- if ( p->initid != -1 ) {
- /* channel still up - reverse dec of inUse counter
- only if the channel is not auto-congested */
- update_call_counter(p, INC_CALL_LIMIT);
- }
- } else { /* Incoming call, not up */
- const char *res;
- if (ast->hangupcause && (res = hangup_cause2sip(ast->hangupcause)))
- transmit_response_reliable(p, res, &p->initreq);
- else
- transmit_response_reliable(p, "603 Declined", &p->initreq);
- p->invitestate = INV_TERMINATED;
- }
- } else { /* Call is in UP state, send BYE */
- if (!p->pendinginvite) {
- char *audioqos = "";
- char *videoqos = "";
- if (p->rtp)
- audioqos = ast_rtp_get_quality(p->rtp, NULL);
- if (p->vrtp)
- videoqos = ast_rtp_get_quality(p->vrtp, NULL);
- /* Send a hangup */
- transmit_request_with_auth(p, SIP_BYE, 0, XMIT_RELIABLE, 1);
-
- /* Get RTCP quality before end of call */
- if (!ast_test_flag(&p->flags[0], SIP_NO_HISTORY)) {
- if (p->rtp)
- append_history(p, "RTCPaudio", "Quality:%s", audioqos);
- if (p->vrtp)
- append_history(p, "RTCPvideo", "Quality:%s", videoqos);
- }
- if (p->rtp && oldowner)
- pbx_builtin_setvar_helper(oldowner, "RTPAUDIOQOS", audioqos);
- if (p->vrtp && oldowner)
- pbx_builtin_setvar_helper(oldowner, "RTPVIDEOQOS", videoqos);
- } else {
- /* Note we will need a BYE when this all settles out
- but we can't send one while we have "INVITE" outstanding. */
- ast_set_flag(&p->flags[0], SIP_PENDINGBYE);
- ast_clear_flag(&p->flags[0], SIP_NEEDREINVITE);
- AST_SCHED_DEL(sched, p->waitid);
- if (sip_cancel_destroy(p))
- ast_log(LOG_WARNING, "Unable to cancel SIP destruction. Expect bad things.\n");
- }
- }
- }
- if (needdestroy)
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- ast_mutex_unlock(&p->lock);
- return 0;
-}
-
-/*! \brief Try setting codec suggested by the SIP_CODEC channel variable */
-static void try_suggested_sip_codec(struct sip_pvt *p)
-{
- int fmt;
- const char *codec;
-
- codec = pbx_builtin_getvar_helper(p->owner, "SIP_CODEC");
- if (!codec)
- return;
-
- fmt = ast_getformatbyname(codec);
- if (fmt) {
- ast_log(LOG_NOTICE, "Changing codec to '%s' for this call because of ${SIP_CODEC} variable\n", codec);
- if (p->jointcapability & fmt) {
- p->jointcapability &= fmt;
- p->capability &= fmt;
- } else
- ast_log(LOG_NOTICE, "Ignoring ${SIP_CODEC} variable because it is not shared by both ends.\n");
- } else
- ast_log(LOG_NOTICE, "Ignoring ${SIP_CODEC} variable because of unrecognized/not configured codec (check allow/disallow in sip.conf): %s\n", codec);
- return;
-}
-
-/*! \brief sip_answer: Answer SIP call , send 200 OK on Invite
- * Part of PBX interface */
-static int sip_answer(struct ast_channel *ast)
-{
- int res = 0;
- struct sip_pvt *p = ast->tech_pvt;
-
- ast_mutex_lock(&p->lock);
- if (ast->_state != AST_STATE_UP) {
- try_suggested_sip_codec(p);
-
- ast_setstate(ast, AST_STATE_UP);
- if (option_debug)
- ast_log(LOG_DEBUG, "SIP answering channel: %s\n", ast->name);
- if (p->t38.state == T38_PEER_DIRECT) {
- p->t38.state = T38_ENABLED;
- if (option_debug > 1)
- ast_log(LOG_DEBUG,"T38State change to %d on channel %s\n", p->t38.state, ast->name);
- res = transmit_response_with_t38_sdp(p, "200 OK", &p->initreq, XMIT_CRITICAL);
- ast_set_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED);
- } else {
- res = transmit_response_with_sdp(p, "200 OK", &p->initreq, XMIT_CRITICAL);
- ast_set_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED);
- }
- }
- ast_mutex_unlock(&p->lock);
- return res;
-}
-
-/*! \brief Send frame to media channel (rtp) */
-static int sip_write(struct ast_channel *ast, struct ast_frame *frame)
-{
- struct sip_pvt *p = ast->tech_pvt;
- int res = 0;
-
- switch (frame->frametype) {
- case AST_FRAME_VOICE:
- if (!(frame->subclass & ast->nativeformats)) {
- char s1[512], s2[512], s3[512];
- ast_log(LOG_WARNING, "Asked to transmit frame type %d, while native formats is %s(%d) read/write = %s(%d)/%s(%d)\n",
- frame->subclass,
- ast_getformatname_multiple(s1, sizeof(s1) - 1, ast->nativeformats & AST_FORMAT_AUDIO_MASK),
- ast->nativeformats & AST_FORMAT_AUDIO_MASK,
- ast_getformatname_multiple(s2, sizeof(s2) - 1, ast->readformat),
- ast->readformat,
- ast_getformatname_multiple(s3, sizeof(s3) - 1, ast->writeformat),
- ast->writeformat);
- return 0;
- }
- if (p) {
- ast_mutex_lock(&p->lock);
- if (p->rtp) {
- /* If channel is not up, activate early media session */
- if ((ast->_state != AST_STATE_UP) &&
- !ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) &&
- !ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
- ast_rtp_new_source(p->rtp);
- p->invitestate = INV_EARLY_MEDIA;
- transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE);
- ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);
- }
- p->lastrtptx = time(NULL);
- res = ast_rtp_write(p->rtp, frame);
- }
- ast_mutex_unlock(&p->lock);
- }
- break;
- case AST_FRAME_VIDEO:
- if (p) {
- ast_mutex_lock(&p->lock);
- if (p->vrtp) {
- /* Activate video early media */
- if ((ast->_state != AST_STATE_UP) &&
- !ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) &&
- !ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
- p->invitestate = INV_EARLY_MEDIA;
- transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE);
- ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);
- }
- p->lastrtptx = time(NULL);
- res = ast_rtp_write(p->vrtp, frame);
- }
- ast_mutex_unlock(&p->lock);
- }
- break;
- case AST_FRAME_IMAGE:
- return 0;
- break;
- case AST_FRAME_MODEM:
- if (p) {
- ast_mutex_lock(&p->lock);
- /* UDPTL requires two-way communication, so early media is not needed here.
- we simply forget the frames if we get modem frames before the bridge is up.
- Fax will re-transmit.
- */
- if (p->udptl && ast->_state == AST_STATE_UP)
- res = ast_udptl_write(p->udptl, frame);
- ast_mutex_unlock(&p->lock);
- }
- break;
- default:
- ast_log(LOG_WARNING, "Can't send %d type frames with SIP write\n", frame->frametype);
- return 0;
- }
-
- return res;
-}
-
-/*! \brief sip_fixup: Fix up a channel: If a channel is consumed, this is called.
- Basically update any ->owner links */
-static int sip_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
-{
- int ret = -1;
- struct sip_pvt *p;
-
- if (newchan && ast_test_flag(newchan, AST_FLAG_ZOMBIE) && option_debug)
- ast_log(LOG_DEBUG, "New channel is zombie\n");
- if (oldchan && ast_test_flag(oldchan, AST_FLAG_ZOMBIE) && option_debug)
- ast_log(LOG_DEBUG, "Old channel is zombie\n");
-
- if (!newchan || !newchan->tech_pvt) {
- if (!newchan)
- ast_log(LOG_WARNING, "No new channel! Fixup of %s failed.\n", oldchan->name);
- else
- ast_log(LOG_WARNING, "No SIP tech_pvt! Fixup of %s failed.\n", oldchan->name);
- return -1;
- }
- p = newchan->tech_pvt;
-
- if (!p) {
- ast_log(LOG_WARNING, "No pvt after masquerade. Strange things may happen\n");
- return -1;
- }
-
- ast_mutex_lock(&p->lock);
- append_history(p, "Masq", "Old channel: %s\n", oldchan->name);
- append_history(p, "Masq (cont)", "...new owner: %s\n", newchan->name);
- if (p->owner != oldchan)
- ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
- else {
- p->owner = newchan;
- /* Re-invite RTP back to Asterisk. Needed if channel is masqueraded out of a native
- RTP bridge (i.e., RTP not going through Asterisk): RTP bridge code might not be
- able to do this if the masquerade happens before the bridge breaks (e.g., AMI
- redirect of both channels). Note that a channel can not be masqueraded *into*
- a native bridge. So there is no danger that this breaks a native bridge that
- should stay up. */
- sip_set_rtp_peer(newchan, NULL, NULL, 0, 0);
- ret = 0;
- }
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "SIP Fixup: New owner for dialogue %s: %s (Old parent: %s)\n", p->callid, p->owner->name, oldchan->name);
-
- ast_mutex_unlock(&p->lock);
- return ret;
-}
-
-static int sip_senddigit_begin(struct ast_channel *ast, char digit)
-{
- struct sip_pvt *p = ast->tech_pvt;
- int res = 0;
-
- ast_mutex_lock(&p->lock);
- switch (ast_test_flag(&p->flags[0], SIP_DTMF)) {
- case SIP_DTMF_INBAND:
- res = -1; /* Tell Asterisk to generate inband indications */
- break;
- case SIP_DTMF_RFC2833:
- if (p->rtp)
- ast_rtp_senddigit_begin(p->rtp, digit);
- break;
- default:
- break;
- }
- ast_mutex_unlock(&p->lock);
-
- return res;
-}
-
-/*! \brief Send DTMF character on SIP channel
- within one call, we're able to transmit in many methods simultaneously */
-static int sip_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration)
-{
- struct sip_pvt *p = ast->tech_pvt;
- int res = 0;
-
- ast_mutex_lock(&p->lock);
- switch (ast_test_flag(&p->flags[0], SIP_DTMF)) {
- case SIP_DTMF_INFO:
- transmit_info_with_digit(p, digit, duration);
- break;
- case SIP_DTMF_RFC2833:
- if (p->rtp)
- ast_rtp_senddigit_end(p->rtp, digit);
- break;
- case SIP_DTMF_INBAND:
- res = -1; /* Tell Asterisk to stop inband indications */
- break;
- }
- ast_mutex_unlock(&p->lock);
-
- return res;
-}
-
-/*! \brief Transfer SIP call */
-static int sip_transfer(struct ast_channel *ast, const char *dest)
-{
- struct sip_pvt *p = ast->tech_pvt;
- int res;
-
- if (dest == NULL) /* functions below do not take a NULL */
- dest = "";
- ast_mutex_lock(&p->lock);
- if (ast->_state == AST_STATE_RING)
- res = sip_sipredirect(p, dest);
- else
- res = transmit_refer(p, dest);
- ast_mutex_unlock(&p->lock);
- return res;
-}
-
-/*! \brief Play indication to user
- * With SIP a lot of indications is sent as messages, letting the device play
- the indication - busy signal, congestion etc
- \return -1 to force ast_indicate to send indication in audio, 0 if SIP can handle the indication by sending a message
-*/
-static int sip_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
-{
- struct sip_pvt *p = ast->tech_pvt;
- int res = 0;
-
- ast_mutex_lock(&p->lock);
- switch(condition) {
- case AST_CONTROL_RINGING:
- if (ast->_state == AST_STATE_RING) {
- p->invitestate = INV_EARLY_MEDIA;
- if (!ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) ||
- (ast_test_flag(&p->flags[0], SIP_PROG_INBAND) == SIP_PROG_INBAND_NEVER)) {
- /* Send 180 ringing if out-of-band seems reasonable */
- transmit_response(p, "180 Ringing", &p->initreq);
- ast_set_flag(&p->flags[0], SIP_RINGING);
- if (ast_test_flag(&p->flags[0], SIP_PROG_INBAND) != SIP_PROG_INBAND_YES)
- break;
- } else {
- /* Well, if it's not reasonable, just send in-band */
- }
- }
- res = -1;
- break;
- case AST_CONTROL_BUSY:
- if (ast->_state != AST_STATE_UP) {
- transmit_response_reliable(p, "486 Busy Here", &p->initreq);
- p->invitestate = INV_COMPLETED;
- sip_alreadygone(p);
- ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
- break;
- }
- res = -1;
- break;
- case AST_CONTROL_CONGESTION:
- if (ast->_state != AST_STATE_UP) {
- transmit_response_reliable(p, "503 Service Unavailable", &p->initreq);
- p->invitestate = INV_COMPLETED;
- sip_alreadygone(p);
- ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
- break;
- }
- res = -1;
- break;
- case AST_CONTROL_PROCEEDING:
- if ((ast->_state != AST_STATE_UP) &&
- !ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) &&
- !ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
- transmit_response(p, "100 Trying", &p->initreq);
- p->invitestate = INV_PROCEEDING;
- break;
- }
- res = -1;
- break;
- case AST_CONTROL_PROGRESS:
- if ((ast->_state != AST_STATE_UP) &&
- !ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) &&
- !ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
- p->invitestate = INV_EARLY_MEDIA;
- transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE);
- ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);
- break;
- }
- res = -1;
- break;
- case AST_CONTROL_HOLD:
- ast_rtp_new_source(p->rtp);
- ast_moh_start(ast, data, p->mohinterpret);
- break;
- case AST_CONTROL_UNHOLD:
- ast_rtp_new_source(p->rtp);
- ast_moh_stop(ast);
- break;
- case AST_CONTROL_VIDUPDATE: /* Request a video frame update */
- if (p->vrtp && !ast_test_flag(&p->flags[0], SIP_NOVIDEO)) {
- transmit_info_with_vidupdate(p);
- /* ast_rtcp_send_h261fur(p->vrtp); */
- } else
- res = -1;
- break;
- case AST_CONTROL_SRCUPDATE:
- ast_rtp_new_source(p->rtp);
- break;
- case -1:
- res = -1;
- break;
- default:
- ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", condition);
- res = -1;
- break;
- }
- ast_mutex_unlock(&p->lock);
- return res;
-}
-
-
-/*! \brief Initiate a call in the SIP channel
- called from sip_request_call (calls from the pbx ) for outbound channels
- and from handle_request_invite for inbound channels
-
-*/
-static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *title)
-{
- struct ast_channel *tmp;
- struct ast_variable *v = NULL;
- int fmt;
- int what;
- int needvideo = 0, video = 0;
- char *decoded_exten;
- {
- const char *my_name; /* pick a good name */
-
- if (title)
- my_name = title;
- else if ( (my_name = strchr(i->fromdomain,':')) )
- my_name++; /* skip ':' */
- else
- my_name = i->fromdomain;
-
- ast_mutex_unlock(&i->lock);
- /* Don't hold a sip pvt lock while we allocate a channel */
- tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, i->accountcode, i->exten, i->context, i->amaflags, "SIP/%s-%08x", my_name, (int)(long) i);
-
- }
- if (!tmp) {
- ast_log(LOG_WARNING, "Unable to allocate AST channel structure for SIP channel\n");
- ast_mutex_lock(&i->lock);
- return NULL;
- }
- ast_mutex_lock(&i->lock);
-
- if (ast_test_flag(&i->flags[0], SIP_DTMF) == SIP_DTMF_INFO)
- tmp->tech = &sip_tech_info;
- else
- tmp->tech = &sip_tech;
-
- /* Select our native format based on codec preference until we receive
- something from another device to the contrary. */
- if (i->jointcapability) { /* The joint capabilities of us and peer */
- what = i->jointcapability;
- video = i->jointcapability & AST_FORMAT_VIDEO_MASK;
- } else if (i->capability) { /* Our configured capability for this peer */
- what = i->capability;
- video = i->capability & AST_FORMAT_VIDEO_MASK;
- } else {
- what = global_capability; /* Global codec support */
- video = global_capability & AST_FORMAT_VIDEO_MASK;
- }
-
- /* Set the native formats for audio and merge in video */
- tmp->nativeformats = ast_codec_choose(&i->prefs, what, 1) | video;
- if (option_debug > 2) {
- char buf[SIPBUFSIZE];
- ast_log(LOG_DEBUG, "*** Our native formats are %s \n", ast_getformatname_multiple(buf, SIPBUFSIZE, tmp->nativeformats));
- ast_log(LOG_DEBUG, "*** Joint capabilities are %s \n", ast_getformatname_multiple(buf, SIPBUFSIZE, i->jointcapability));
- ast_log(LOG_DEBUG, "*** Our capabilities are %s \n", ast_getformatname_multiple(buf, SIPBUFSIZE, i->capability));
- ast_log(LOG_DEBUG, "*** AST_CODEC_CHOOSE formats are %s \n", ast_getformatname_multiple(buf, SIPBUFSIZE, ast_codec_choose(&i->prefs, what, 1)));
- if (i->prefcodec)
- ast_log(LOG_DEBUG, "*** Our preferred formats from the incoming channel are %s \n", ast_getformatname_multiple(buf, SIPBUFSIZE, i->prefcodec));
- }
-
- /* XXX Why are we choosing a codec from the native formats?? */
- fmt = ast_best_codec(tmp->nativeformats);
-
- /* If we have a prefcodec setting, we have an inbound channel that set a
- preferred format for this call. Otherwise, we check the jointcapability
- We also check for vrtp. If it's not there, we are not allowed do any video anyway.
- */
- if (i->vrtp) {
- if (i->prefcodec)
- needvideo = i->prefcodec & AST_FORMAT_VIDEO_MASK; /* Outbound call */
- else
- needvideo = i->jointcapability & AST_FORMAT_VIDEO_MASK; /* Inbound call */
- }
-
- if (option_debug > 2) {
- if (needvideo)
- ast_log(LOG_DEBUG, "This channel can handle video! HOLLYWOOD next!\n");
- else
- ast_log(LOG_DEBUG, "This channel will not be able to handle video.\n");
- }
-
-
-
- if (ast_test_flag(&i->flags[0], SIP_DTMF) == SIP_DTMF_INBAND) {
- i->vad = ast_dsp_new();
- ast_dsp_set_features(i->vad, DSP_FEATURE_DTMF_DETECT);
- if (global_relaxdtmf)
- ast_dsp_digitmode(i->vad, DSP_DIGITMODE_DTMF | DSP_DIGITMODE_RELAXDTMF);
- }
- if (i->rtp) {
- tmp->fds[0] = ast_rtp_fd(i->rtp);
- tmp->fds[1] = ast_rtcp_fd(i->rtp);
- }
- if (needvideo && i->vrtp) {
- tmp->fds[2] = ast_rtp_fd(i->vrtp);
- tmp->fds[3] = ast_rtcp_fd(i->vrtp);
- }
- if (i->udptl) {
- tmp->fds[5] = ast_udptl_fd(i->udptl);
- }
- if (state == AST_STATE_RING)
- tmp->rings = 1;
- tmp->adsicpe = AST_ADSI_UNAVAILABLE;
- tmp->writeformat = fmt;
- tmp->rawwriteformat = fmt;
- tmp->readformat = fmt;
- tmp->rawreadformat = fmt;
- tmp->tech_pvt = i;
-
- tmp->callgroup = i->callgroup;
- tmp->pickupgroup = i->pickupgroup;
- tmp->cid.cid_pres = i->callingpres;
- if (!ast_strlen_zero(i->accountcode))
- ast_string_field_set(tmp, accountcode, i->accountcode);
- if (i->amaflags)
- tmp->amaflags = i->amaflags;
- if (!ast_strlen_zero(i->language))
- ast_string_field_set(tmp, language, i->language);
- i->owner = tmp;
- ast_module_ref(ast_module_info->self);
- ast_copy_string(tmp->context, i->context, sizeof(tmp->context));
- /*Since it is valid to have extensions in the dialplan that have unescaped characters in them
- * we should decode the uri before storing it in the channel, but leave it encoded in the sip_pvt
- * structure so that there aren't issues when forming URI's
- */
- decoded_exten = ast_strdupa(i->exten);
- ast_uri_decode(decoded_exten);
- ast_copy_string(tmp->exten, decoded_exten, sizeof(tmp->exten));
-
- /* Don't use ast_set_callerid() here because it will
- * generate an unnecessary NewCallerID event */
- tmp->cid.cid_ani = ast_strdup(i->cid_num);
- if (!ast_strlen_zero(i->rdnis))
- tmp->cid.cid_rdnis = ast_strdup(i->rdnis);
-
- if (!ast_strlen_zero(i->exten) && strcmp(i->exten, "s"))
- tmp->cid.cid_dnid = ast_strdup(i->exten);
-
- tmp->priority = 1;
- if (!ast_strlen_zero(i->uri))
- pbx_builtin_setvar_helper(tmp, "SIPURI", i->uri);
- if (!ast_strlen_zero(i->domain))
- pbx_builtin_setvar_helper(tmp, "SIPDOMAIN", i->domain);
- if (!ast_strlen_zero(i->useragent))
- pbx_builtin_setvar_helper(tmp, "SIPUSERAGENT", i->useragent);
- if (!ast_strlen_zero(i->callid))
- pbx_builtin_setvar_helper(tmp, "SIPCALLID", i->callid);
- if (i->rtp)
- ast_jb_configure(tmp, &global_jbconf);
-
- /* If the INVITE contains T.38 SDP information set the proper channel variable so a created outgoing call will also have T.38 */
- if (i->udptl && i->t38.state == T38_PEER_DIRECT)
- pbx_builtin_setvar_helper(tmp, "_T38CALL", "1");
-
- /* Set channel variables for this call from configuration */
- for (v = i->chanvars ; v ; v = v->next)
- pbx_builtin_setvar_helper(tmp, v->name, v->value);
-
- if (state != AST_STATE_DOWN && ast_pbx_start(tmp)) {
- ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
- tmp->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
- ast_hangup(tmp);
- tmp = NULL;
- }
-
- if (!ast_test_flag(&i->flags[0], SIP_NO_HISTORY))
- append_history(i, "NewChan", "Channel %s - from %s", tmp->name, i->callid);
-
- return tmp;
-}
-
-/*! \brief Reads one line of SIP message body */
-static char *get_body_by_line(const char *line, const char *name, int nameLen)
-{
- if (strncasecmp(line, name, nameLen) == 0 && line[nameLen] == '=')
- return ast_skip_blanks(line + nameLen + 1);
-
- return "";
-}
-
-/*! \brief Lookup 'name' in the SDP starting
- * at the 'start' line. Returns the matching line, and 'start'
- * is updated with the next line number.
- */
-static const char *get_sdp_iterate(int *start, struct sip_request *req, const char *name)
-{
- int len = strlen(name);
-
- while (*start < req->sdp_end) {
- const char *r = get_body_by_line(req->line[(*start)++], name, len);
- if (r[0] != '\0')
- return r;
- }
-
- return "";
-}
-
-/*! \brief Get a line from an SDP message body */
-static const char *get_sdp(struct sip_request *req, const char *name)
-{
- int dummy = 0;
-
- return get_sdp_iterate(&dummy, req, name);
-}
-
-/*! \brief Get a specific line from the message body */
-static char *get_body(struct sip_request *req, char *name)
-{
- int x;
- int len = strlen(name);
- char *r;
-
- for (x = 0; x < req->lines; x++) {
- r = get_body_by_line(req->line[x], name, len);
- if (r[0] != '\0')
- return r;
- }
-
- return "";
-}
-
-/*! \brief Find compressed SIP alias */
-static const char *find_alias(const char *name, const char *_default)
-{
- /*! \brief Structure for conversion between compressed SIP and "normal" SIP */
- static const struct cfalias {
- char * const fullname;
- char * const shortname;
- } aliases[] = {
- { "Content-Type", "c" },
- { "Content-Encoding", "e" },
- { "From", "f" },
- { "Call-ID", "i" },
- { "Contact", "m" },
- { "Content-Length", "l" },
- { "Subject", "s" },
- { "To", "t" },
- { "Supported", "k" },
- { "Refer-To", "r" },
- { "Referred-By", "b" },
- { "Allow-Events", "u" },
- { "Event", "o" },
- { "Via", "v" },
- { "Accept-Contact", "a" },
- { "Reject-Contact", "j" },
- { "Request-Disposition", "d" },
- { "Session-Expires", "x" },
- { "Identity", "y" },
- { "Identity-Info", "n" },
- };
- int x;
-
- for (x=0; x<sizeof(aliases) / sizeof(aliases[0]); x++)
- if (!strcasecmp(aliases[x].fullname, name))
- return aliases[x].shortname;
-
- return _default;
-}
-
-static const char *__get_header(const struct sip_request *req, const char *name, int *start)
-{
- int pass;
-
- /*
- * Technically you can place arbitrary whitespace both before and after the ':' in
- * a header, although RFC3261 clearly says you shouldn't before, and place just
- * one afterwards. If you shouldn't do it, what absolute idiot decided it was
- * a good idea to say you can do it, and if you can do it, why in the hell would.
- * you say you shouldn't.
- * Anyways, pedanticsipchecking controls whether we allow spaces before ':',
- * and we always allow spaces after that for compatibility.
- */
- for (pass = 0; name && pass < 2;pass++) {
- int x, len = strlen(name);
- for (x=*start; x<req->headers; x++) {
- if (!strncasecmp(req->header[x], name, len)) {
- char *r = req->header[x] + len; /* skip name */
- if (pedanticsipchecking)
- r = ast_skip_blanks(r);
-
- if (*r == ':') {
- *start = x+1;
- return ast_skip_blanks(r+1);
- }
- }
- }
- if (pass == 0) /* Try aliases */
- name = find_alias(name, NULL);
- }
-
- /* Don't return NULL, so get_header is always a valid pointer */
- return "";
-}
-
-/*! \brief Get header from SIP request */
-static const char *get_header(const struct sip_request *req, const char *name)
-{
- int start = 0;
- return __get_header(req, name, &start);
-}
-
-/*! \brief Read RTP from network */
-static struct ast_frame *sip_rtp_read(struct ast_channel *ast, struct sip_pvt *p, int *faxdetect)
-{
- /* Retrieve audio/etc from channel. Assumes p->lock is already held. */
- struct ast_frame *f;
-
- if (!p->rtp) {
- /* We have no RTP allocated for this channel */
- return &ast_null_frame;
- }
-
- switch(ast->fdno) {
- case 0:
- f = ast_rtp_read(p->rtp); /* RTP Audio */
- break;
- case 1:
- f = ast_rtcp_read(p->rtp); /* RTCP Control Channel */
- break;
- case 2:
- f = ast_rtp_read(p->vrtp); /* RTP Video */
- break;
- case 3:
- f = ast_rtcp_read(p->vrtp); /* RTCP Control Channel for video */
- break;
- case 5:
- f = ast_udptl_read(p->udptl); /* UDPTL for T.38 */
- break;
- default:
- f = &ast_null_frame;
- }
- /* Don't forward RFC2833 if we're not supposed to */
- if (f && (f->frametype == AST_FRAME_DTMF) &&
- (ast_test_flag(&p->flags[0], SIP_DTMF) != SIP_DTMF_RFC2833))
- return &ast_null_frame;
-
- /* We already hold the channel lock */
- if (!p->owner || (f && f->frametype != AST_FRAME_VOICE))
- return f;
-
- if (f && f->subclass != (p->owner->nativeformats & AST_FORMAT_AUDIO_MASK)) {
- if (!(f->subclass & p->jointcapability)) {
- if (option_debug) {
- ast_log(LOG_DEBUG, "Bogus frame of format '%s' received from '%s'!\n",
- ast_getformatname(f->subclass), p->owner->name);
- }
- return &ast_null_frame;
- }
- if (option_debug)
- ast_log(LOG_DEBUG, "Oooh, format changed to %d\n", f->subclass);
- p->owner->nativeformats = (p->owner->nativeformats & AST_FORMAT_VIDEO_MASK) | f->subclass;
- ast_set_read_format(p->owner, p->owner->readformat);
- ast_set_write_format(p->owner, p->owner->writeformat);
- }
-
- if (f && (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_INBAND) && p->vad) {
- f = ast_dsp_process(p->owner, p->vad, f);
- if (f && f->frametype == AST_FRAME_DTMF) {
- if (ast_test_flag(&p->t38.t38support, SIP_PAGE2_T38SUPPORT_UDPTL) && f->subclass == 'f') {
- if (option_debug)
- ast_log(LOG_DEBUG, "Fax CNG detected on %s\n", ast->name);
- *faxdetect = 1;
- } else if (option_debug) {
- ast_log(LOG_DEBUG, "* Detected inband DTMF '%c'\n", f->subclass);
- }
- }
- }
-
- return f;
-}
-
-/*! \brief Read SIP RTP from channel */
-static struct ast_frame *sip_read(struct ast_channel *ast)
-{
- struct ast_frame *fr;
- struct sip_pvt *p = ast->tech_pvt;
- int faxdetected = FALSE;
-
- ast_mutex_lock(&p->lock);
- fr = sip_rtp_read(ast, p, &faxdetected);
- p->lastrtprx = time(NULL);
-
- /* If we are NOT bridged to another channel, and we have detected fax tone we issue T38 re-invite to a peer */
- /* If we are bridged then it is the responsibility of the SIP device to issue T38 re-invite if it detects CNG or fax preamble */
- if (faxdetected && ast_test_flag(&p->t38.t38support, SIP_PAGE2_T38SUPPORT_UDPTL) && (p->t38.state == T38_DISABLED) && !(ast_bridged_channel(ast))) {
- if (!ast_test_flag(&p->flags[0], SIP_GOTREFER)) {
- if (!p->pendinginvite) {
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Sending reinvite on SIP (%s) for T.38 negotiation.\n",ast->name);
- p->t38.state = T38_LOCAL_REINVITE;
- transmit_reinvite_with_t38_sdp(p);
- if (option_debug > 1)
- ast_log(LOG_DEBUG, "T38 state changed to %d on channel %s\n", p->t38.state, ast->name);
- }
- } else if (!ast_test_flag(&p->flags[0], SIP_PENDINGBYE)) {
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Deferring reinvite on SIP (%s) - it will be re-negotiated for T.38\n", ast->name);
- ast_set_flag(&p->flags[0], SIP_NEEDREINVITE);
- }
- }
-
- /* Only allow audio through if they sent progress with SDP, or if the channel is actually answered */
- if (fr && fr->frametype == AST_FRAME_VOICE && p->invitestate != INV_EARLY_MEDIA && ast->_state != AST_STATE_UP) {
- fr = &ast_null_frame;
- }
-
- ast_mutex_unlock(&p->lock);
- return fr;
-}
-
-
-/*! \brief Generate 32 byte random string for callid's etc */
-static char *generate_random_string(char *buf, size_t size)
-{
- long val[4];
- int x;
-
- for (x=0; x<4; x++)
- val[x] = ast_random();
- snprintf(buf, size, "%08lx%08lx%08lx%08lx", val[0], val[1], val[2], val[3]);
-
- return buf;
-}
-
-/*! \brief Build SIP Call-ID value for a non-REGISTER transaction */
-static void build_callid_pvt(struct sip_pvt *pvt)
-{
- char buf[33];
-
- const char *host = S_OR(pvt->fromdomain, ast_inet_ntoa(pvt->ourip));
-
- ast_string_field_build(pvt, callid, "%s@%s", generate_random_string(buf, sizeof(buf)), host);
-
-}
-
-/*! \brief Build SIP Call-ID value for a REGISTER transaction */
-static void build_callid_registry(struct sip_registry *reg, struct in_addr ourip, const char *fromdomain)
-{
- char buf[33];
-
- const char *host = S_OR(fromdomain, ast_inet_ntoa(ourip));
-
- ast_string_field_build(reg, callid, "%s@%s", generate_random_string(buf, sizeof(buf)), host);
-}
-
-/*! \brief Make our SIP dialog tag */
-static void make_our_tag(char *tagbuf, size_t len)
-{
- snprintf(tagbuf, len, "as%08lx", ast_random());
-}
-
-/*! \brief Allocate SIP_PVT structure and set defaults */
-static struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *sin,
- int useglobal_nat, const int intended_method)
-{
- struct sip_pvt *p;
-
- if (!(p = ast_calloc(1, sizeof(*p))))
- return NULL;
-
- if (ast_string_field_init(p, 512)) {
- free(p);
- return NULL;
- }
-
- ast_mutex_init(&p->lock);
-
- p->method = intended_method;
- p->initid = -1;
- p->waitid = -1;
- p->autokillid = -1;
- p->request_queue_sched_id = -1;
- p->subscribed = NONE;
- p->stateid = -1;
- p->prefs = default_prefs; /* Set default codecs for this call */
-
- if (intended_method != SIP_OPTIONS) /* Peerpoke has it's own system */
- p->timer_t1 = 500; /* Default SIP retransmission timer T1 (RFC 3261) */
-
- if (sin) {
- p->sa = *sin;
- if (ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip))
- p->ourip = __ourip;
- } else
- p->ourip = __ourip;
-
- /* 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_set2_flag(&p->flags[0], !recordhistory, SIP_NO_HISTORY);
-
- p->branch = ast_random();
- make_our_tag(p->tag, sizeof(p->tag));
- p->ocseq = INITIAL_CSEQ;
-
- if (sip_methods[intended_method].need_rtp) {
- p->rtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr);
- /* If the global videosupport flag is on, we always create a RTP interface for video */
- if (ast_test_flag(&p->flags[1], SIP_PAGE2_VIDEOSUPPORT))
- p->vrtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr);
- if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT))
- p->udptl = ast_udptl_new_with_bindaddr(sched, io, 0, bindaddr.sin_addr);
- if (!p->rtp || (ast_test_flag(&p->flags[1], SIP_PAGE2_VIDEOSUPPORT) && !p->vrtp)) {
- ast_log(LOG_WARNING, "Unable to create RTP audio %s session: %s\n",
- ast_test_flag(&p->flags[1], SIP_PAGE2_VIDEOSUPPORT) ? "and video" : "", strerror(errno));
- ast_mutex_destroy(&p->lock);
- if (p->chanvars) {
- ast_variables_destroy(p->chanvars);
- p->chanvars = NULL;
- }
- free(p);
- return NULL;
- }
- ast_rtp_setdtmf(p->rtp, ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833);
- ast_rtp_setdtmfcompensate(p->rtp, ast_test_flag(&p->flags[1], SIP_PAGE2_RFC2833_COMPENSATE));
- ast_rtp_settos(p->rtp, global_tos_audio);
- ast_rtp_set_rtptimeout(p->rtp, global_rtptimeout);
- ast_rtp_set_rtpholdtimeout(p->rtp, global_rtpholdtimeout);
- ast_rtp_set_rtpkeepalive(p->rtp, global_rtpkeepalive);
- if (p->vrtp) {
- ast_rtp_settos(p->vrtp, global_tos_video);
- ast_rtp_setdtmf(p->vrtp, 0);
- ast_rtp_setdtmfcompensate(p->vrtp, 0);
- ast_rtp_set_rtptimeout(p->vrtp, global_rtptimeout);
- ast_rtp_set_rtpholdtimeout(p->vrtp, global_rtpholdtimeout);
- ast_rtp_set_rtpkeepalive(p->vrtp, global_rtpkeepalive);
- }
- if (p->udptl)
- ast_udptl_settos(p->udptl, global_tos_audio);
- p->maxcallbitrate = default_maxcallbitrate;
- p->autoframing = global_autoframing;
- ast_rtp_codec_setpref(p->rtp, &p->prefs);
- }
-
- if (useglobal_nat && sin) {
- /* Setup NAT structure according to global settings if we have an address */
- ast_copy_flags(&p->flags[0], &global_flags[0], SIP_NAT);
- p->recv = *sin;
- do_setnat(p, ast_test_flag(&p->flags[0], SIP_NAT) & SIP_NAT_ROUTE);
- }
-
- if (p->method != SIP_REGISTER)
- ast_string_field_set(p, fromdomain, default_fromdomain);
- build_via(p);
- if (!callid)
- build_callid_pvt(p);
- else
- ast_string_field_set(p, callid, callid);
- /* Assign default music on hold class */
- ast_string_field_set(p, mohinterpret, default_mohinterpret);
- ast_string_field_set(p, mohsuggest, default_mohsuggest);
- p->capability = global_capability;
- p->allowtransfer = global_allowtransfer;
- if ((ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833) ||
- (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_AUTO))
- p->noncodeccapability |= AST_RTP_DTMF;
- if (p->udptl) {
- p->t38.capability = global_t38_capability;
- if (ast_udptl_get_error_correction_scheme(p->udptl) == UDPTL_ERROR_CORRECTION_REDUNDANCY)
- p->t38.capability |= T38FAX_UDP_EC_REDUNDANCY;
- else if (ast_udptl_get_error_correction_scheme(p->udptl) == UDPTL_ERROR_CORRECTION_FEC)
- p->t38.capability |= T38FAX_UDP_EC_FEC;
- else if (ast_udptl_get_error_correction_scheme(p->udptl) == UDPTL_ERROR_CORRECTION_NONE)
- p->t38.capability |= T38FAX_UDP_EC_NONE;
- p->t38.capability |= T38FAX_RATE_MANAGEMENT_TRANSFERED_TCF;
- p->t38.jointcapability = p->t38.capability;
- }
- ast_string_field_set(p, context, default_context);
-
- AST_LIST_HEAD_INIT_NOLOCK(&p->request_queue);
-
- /* Add to active dialog list */
- ast_mutex_lock(&iflock);
- p->next = iflist;
- iflist = p;
- ast_mutex_unlock(&iflock);
- if (option_debug)
- ast_log(LOG_DEBUG, "Allocating new SIP dialog for %s - %s (%s)\n", callid ? callid : "(No Call-ID)", sip_methods[intended_method].text, p->rtp ? "With RTP" : "No RTP");
- return p;
-}
-
-/*! \brief Connect incoming SIP message to current dialog or create new dialog structure
- Called by handle_request, sipsock_read */
-static struct sip_pvt *find_call(struct sip_request *req, struct sockaddr_in *sin, const int intended_method)
-{
- struct sip_pvt *p = NULL;
- char *tag = ""; /* note, tag is never NULL */
- char totag[128];
- char fromtag[128];
- const char *callid = get_header(req, "Call-ID");
- const char *from = get_header(req, "From");
- const char *to = get_header(req, "To");
- const char *cseq = get_header(req, "Cseq");
-
- /* Call-ID, to, from and Cseq are required by RFC 3261. (Max-forwards and via too - ignored now) */
- /* get_header always returns non-NULL so we must use ast_strlen_zero() */
- if (ast_strlen_zero(callid) || ast_strlen_zero(to) ||
- ast_strlen_zero(from) || ast_strlen_zero(cseq))
- return NULL; /* Invalid packet */
-
- if (pedanticsipchecking) {
- /* In principle Call-ID's uniquely identify a call, but with a forking SIP proxy
- we need more to identify a branch - so we have to check branch, from
- and to tags to identify a call leg.
- For Asterisk to behave correctly, you need to turn on pedanticsipchecking
- in sip.conf
- */
- if (gettag(req, "To", totag, sizeof(totag)))
- ast_set_flag(req, SIP_PKT_WITH_TOTAG); /* Used in handle_request/response */
- gettag(req, "From", fromtag, sizeof(fromtag));
-
- tag = (req->method == SIP_RESPONSE) ? totag : fromtag;
-
- if (option_debug > 4 )
- ast_log(LOG_DEBUG, "= Looking for Call ID: %s (Checking %s) --From tag %s --To-tag %s \n", callid, req->method==SIP_RESPONSE ? "To" : "From", fromtag, totag);
- }
-
- ast_mutex_lock(&iflock);
- for (p = iflist; p; p = p->next) {
- /* In pedantic, we do not want packets with bad syntax to be connected to a PVT */
- int found = FALSE;
- if (ast_strlen_zero(p->callid))
- continue;
- if (req->method == SIP_REGISTER)
- found = (!strcmp(p->callid, callid));
- else {
- found = !strcmp(p->callid, callid);
- if (pedanticsipchecking && found) {
- found = ast_strlen_zero(tag) || ast_strlen_zero(p->theirtag) || !ast_test_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED) || !strcmp(p->theirtag, tag);
- }
- }
-
- if (option_debug > 4)
- ast_log(LOG_DEBUG, "= %s Their Call ID: %s Their Tag %s Our tag: %s\n", found ? "Found" : "No match", p->callid, p->theirtag, p->tag);
-
- /* If we get a new request within an existing to-tag - check the to tag as well */
- if (pedanticsipchecking && found && req->method != SIP_RESPONSE) { /* SIP Request */
- if (p->tag[0] == '\0' && totag[0]) {
- /* We have no to tag, but they have. Wrong dialog */
- found = FALSE;
- } else if (totag[0]) { /* Both have tags, compare them */
- if (strcmp(totag, p->tag)) {
- found = FALSE; /* This is not our packet */
- }
- }
- if (!found && option_debug > 4)
- ast_log(LOG_DEBUG, "= Being pedantic: This is not our match on request: Call ID: %s Ourtag <null> Totag %s Method %s\n", p->callid, totag, sip_methods[req->method].text);
- }
- if (found) {
- /* Found the call */
- ast_mutex_lock(&p->lock);
- ast_mutex_unlock(&iflock);
- return p;
- }
- }
- ast_mutex_unlock(&iflock);
-
- /* See if the method is capable of creating a dialog */
- if (sip_methods[intended_method].can_create == CAN_CREATE_DIALOG) {
- if (intended_method == SIP_REFER) {
- /* We do support REFER, but not outside of a dialog yet */
- transmit_response_using_temp(callid, sin, 1, intended_method, req, "603 Declined (no dialog)");
- } else if (intended_method == SIP_NOTIFY) {
- /* We do not support out-of-dialog NOTIFY either,
- like voicemail notification, so cancel that early */
- transmit_response_using_temp(callid, sin, 1, intended_method, req, "489 Bad event");
- } else {
- /* Ok, time to create a new SIP dialog object, a pvt */
- if ((p = sip_alloc(callid, sin, 1, intended_method))) {
- /* Ok, we've created a dialog, let's go and process it */
- ast_mutex_lock(&p->lock);
- } else {
- /* We have a memory or file/socket error (can't allocate RTP sockets or something) so we're not
- getting a dialog from sip_alloc.
-
- Without a dialog we can't retransmit and handle ACKs and all that, but at least
- send an error message.
-
- Sorry, we apologize for the inconvienience
- */
- transmit_response_using_temp(callid, sin, 1, intended_method, req, "500 Server internal error");
- if (option_debug > 3)
- ast_log(LOG_DEBUG, "Failed allocating SIP dialog, sending 500 Server internal error and giving up\n");
- }
- }
- return p;
- } else if( sip_methods[intended_method].can_create == CAN_CREATE_DIALOG_UNSUPPORTED_METHOD) {
- /* A method we do not support, let's take it on the volley */
- transmit_response_using_temp(callid, sin, 1, intended_method, req, "501 Method Not Implemented");
- } else if (intended_method != SIP_RESPONSE && intended_method != SIP_ACK) {
- /* This is a request outside of a dialog that we don't know about
- ...never reply to an ACK!
- */
- transmit_response_using_temp(callid, sin, 1, intended_method, req, "481 Call leg/transaction does not exist");
- }
- /* We do not respond to responses for dialogs that we don't know about, we just drop
- the session quickly */
-
- return p;
-}
-
-/*! \brief Parse register=> line in sip.conf and add to registry */
-static int sip_register(char *value, int lineno)
-{
- struct sip_registry *reg;
- int portnum = 0;
- char username[256] = "";
- char *hostname=NULL, *secret=NULL, *authuser=NULL;
- char *porta=NULL;
- char *contact=NULL;
-
- if (!value)
- return -1;
- ast_copy_string(username, value, sizeof(username));
- /* First split around the last '@' then parse the two components. */
- hostname = strrchr(username, '@'); /* allow @ in the first part */
- if (hostname)
- *hostname++ = '\0';
- if (ast_strlen_zero(username) || ast_strlen_zero(hostname)) {
- ast_log(LOG_WARNING, "Format for registration is user[:secret[:authuser]]@host[:port][/contact] at line %d\n", lineno);
- return -1;
- }
- /* split user[:secret[:authuser]] */
- secret = strchr(username, ':');
- if (secret) {
- *secret++ = '\0';
- authuser = strchr(secret, ':');
- if (authuser)
- *authuser++ = '\0';
- }
- /* split host[:port][/contact] */
- contact = strchr(hostname, '/');
- if (contact)
- *contact++ = '\0';
- if (ast_strlen_zero(contact))
- contact = "s";
- porta = strchr(hostname, ':');
- if (porta) {
- *porta++ = '\0';
- portnum = atoi(porta);
- if (portnum == 0) {
- ast_log(LOG_WARNING, "%s is not a valid port number at line %d\n", porta, lineno);
- return -1;
- }
- }
- if (!(reg = ast_calloc(1, sizeof(*reg)))) {
- ast_log(LOG_ERROR, "Out of memory. Can't allocate SIP registry entry\n");
- return -1;
- }
-
- if (ast_string_field_init(reg, 256)) {
- ast_log(LOG_ERROR, "Out of memory. Can't allocate SIP registry strings\n");
- free(reg);
- return -1;
- }
-
- regobjs++;
- ASTOBJ_INIT(reg);
- ast_string_field_set(reg, contact, contact);
- if (!ast_strlen_zero(username))
- ast_string_field_set(reg, username, username);
- if (hostname)
- ast_string_field_set(reg, hostname, hostname);
- if (authuser)
- ast_string_field_set(reg, authuser, authuser);
- if (secret)
- ast_string_field_set(reg, secret, secret);
- reg->expire = -1;
- reg->timeout = -1;
- reg->refresh = default_expiry;
- reg->portno = portnum;
- reg->callid_valid = FALSE;
- reg->ocseq = INITIAL_CSEQ;
- ASTOBJ_CONTAINER_LINK(&regl, reg); /* Add the new registry entry to the list */
- ASTOBJ_UNREF(reg,sip_registry_destroy);
- return 0;
-}
-
-/*! \brief Parse multiline SIP headers into one header
- This is enabled if pedanticsipchecking is enabled */
-static int lws2sws(char *msgbuf, int len)
-{
- int h = 0, t = 0;
- int lws = 0;
-
- for (; h < len;) {
- /* Eliminate all CRs */
- if (msgbuf[h] == '\r') {
- h++;
- continue;
- }
- /* Check for end-of-line */
- if (msgbuf[h] == '\n') {
- /* Check for end-of-message */
- if (h + 1 == len)
- break;
- /* Check for a continuation line */
- if (msgbuf[h + 1] == ' ' || msgbuf[h + 1] == '\t') {
- /* Merge continuation line */
- h++;
- continue;
- }
- /* Propagate LF and start new line */
- msgbuf[t++] = msgbuf[h++];
- lws = 0;
- continue;
- }
- if (msgbuf[h] == ' ' || msgbuf[h] == '\t') {
- if (lws) {
- h++;
- continue;
- }
- msgbuf[t++] = msgbuf[h++];
- lws = 1;
- continue;
- }
- msgbuf[t++] = msgbuf[h++];
- if (lws)
- lws = 0;
- }
- msgbuf[t] = '\0';
- return t;
-}
-
-/*! \brief Parse a SIP message
- \note this function is used both on incoming and outgoing packets
-*/
-static int parse_request(struct sip_request *req)
-{
- /* Divide fields by NULL's */
- char *c;
- int f = 0;
-
- c = req->data;
-
- /* First header starts immediately */
- req->header[f] = c;
- while(*c) {
- if (*c == '\n') {
- /* We've got a new header */
- *c = 0;
-
- if (sipdebug && option_debug > 3)
- ast_log(LOG_DEBUG, "Header %d: %s (%d)\n", f, req->header[f], (int) strlen(req->header[f]));
- if (ast_strlen_zero(req->header[f])) {
- /* Line by itself means we're now in content */
- c++;
- break;
- }
- if (f >= SIP_MAX_HEADERS - 1) {
- ast_log(LOG_WARNING, "Too many SIP headers. Ignoring.\n");
- } else {
- f++;
- req->header[f] = c + 1;
- }
- } else if (*c == '\r') {
- /* Ignore but eliminate \r's */
- *c = 0;
- }
- c++;
- }
-
- req->headers = f;
-
- /* Check a non-newline-terminated last header */
- if (!ast_strlen_zero(req->header[f])) {
- if (sipdebug && option_debug > 3)
- ast_log(LOG_DEBUG, "Header %d: %s (%d)\n", f, req->header[f], (int) strlen(req->header[f]));
- req->headers++;
- }
-
- /* Now we process any body content */
- f = 0;
- req->line[f] = c;
- while (*c) {
- if (*c == '\n') {
- /* We've got a new line */
- *c = 0;
- if (sipdebug && option_debug > 3)
- ast_log(LOG_DEBUG, "Line: %s (%d)\n", req->line[f], (int) strlen(req->line[f]));
- if (f == SIP_MAX_LINES - 1) {
- ast_log(LOG_WARNING, "Too many SDP lines. Ignoring.\n");
- break;
- } else {
- f++;
- req->line[f] = c + 1;
- }
- } else if (*c == '\r') {
- /* Ignore and eliminate \r's */
- *c = 0;
- }
- c++;
- }
-
- req->lines = f;
-
- /* Check a non-newline-terminated last line */
- if (!ast_strlen_zero(req->line[f])) {
- req->lines++;
- }
-
- if (*c)
- ast_log(LOG_WARNING, "Odd content, extra stuff left over ('%s')\n", c);
-
- /* Split up the first line parts */
- return determine_firstline_parts(req);
-}
-
-/*!
- \brief Determine whether a SIP message contains an SDP in its body
- \param req the SIP request to process
- \return 1 if SDP found, 0 if not found
-
- Also updates req->sdp_start and req->sdp_end to indicate where the SDP
- lives in the message body.
-*/
-static int find_sdp(struct sip_request *req)
-{
- const char *content_type;
- const char *content_length;
- const char *search;
- char *boundary;
- unsigned int x;
- int boundaryisquoted = FALSE;
- int found_application_sdp = FALSE;
- int found_end_of_headers = FALSE;
-
- content_length = get_header(req, "Content-Length");
-
- if (!ast_strlen_zero(content_length)) {
- if (sscanf(content_length, "%ud", &x) != 1) {
- ast_log(LOG_WARNING, "Invalid Content-Length: %s\n", content_length);
- return 0;
- }
-
- /* Content-Length of zero means there can't possibly be an
- SDP here, even if the Content-Type says there is */
- if (x == 0)
- return 0;
- }
-
- content_type = get_header(req, "Content-Type");
-
- /* if the body contains only SDP, this is easy */
- if (!strncasecmp(content_type, "application/sdp", 15)) {
- req->sdp_start = 0;
- req->sdp_end = req->lines;
- return req->lines ? 1 : 0;
- }
-
- /* if it's not multipart/mixed, there cannot be an SDP */
- if (strncasecmp(content_type, "multipart/mixed", 15))
- return 0;
-
- /* if there is no boundary marker, it's invalid */
- if ((search = strcasestr(content_type, ";boundary=")))
- search += 10;
- else if ((search = strcasestr(content_type, "; boundary=")))
- search += 11;
- else
- return 0;
-
- if (ast_strlen_zero(search))
- return 0;
-
- /* If the boundary is quoted with ", remove quote */
- if (*search == '\"') {
- search++;
- boundaryisquoted = TRUE;
- }
-
- /* make a duplicate of the string, with two extra characters
- at the beginning */
- boundary = ast_strdupa(search - 2);
- boundary[0] = boundary[1] = '-';
- /* Remove final quote */
- if (boundaryisquoted)
- boundary[strlen(boundary) - 1] = '\0';
-
- /* search for the boundary marker, the empty line delimiting headers from
- sdp part and the end boundry if it exists */
-
- for (x = 0; x < (req->lines ); x++) {
- if(!strncasecmp(req->line[x], boundary, strlen(boundary))){
- if(found_application_sdp && found_end_of_headers){
- req->sdp_end = x-1;
- return 1;
- }
- found_application_sdp = FALSE;
- }
- if(!strcasecmp(req->line[x], "Content-Type: application/sdp"))
- found_application_sdp = TRUE;
-
- if(strlen(req->line[x]) == 0 ){
- if(found_application_sdp && !found_end_of_headers){
- req->sdp_start = x;
- found_end_of_headers = TRUE;
- }
- }
- }
- if(found_application_sdp && found_end_of_headers) {
- req->sdp_end = x;
- return TRUE;
- }
- return FALSE;
-}
-
-/*! \brief Change hold state for a call */
-static void change_hold_state(struct sip_pvt *dialog, struct sip_request *req, int holdstate, int sendonly)
-{
- if (global_notifyhold && (!holdstate || !ast_test_flag(&dialog->flags[1], SIP_PAGE2_CALL_ONHOLD)))
- sip_peer_hold(dialog, holdstate);
- if (global_callevents)
- manager_event(EVENT_FLAG_CALL, holdstate ? "Hold" : "Unhold",
- "Channel: %s\r\n"
- "Uniqueid: %s\r\n",
- dialog->owner->name,
- dialog->owner->uniqueid);
- append_history(dialog, holdstate ? "Hold" : "Unhold", "%s", req->data);
- if (!holdstate) { /* Put off remote hold */
- ast_clear_flag(&dialog->flags[1], SIP_PAGE2_CALL_ONHOLD); /* Clear both flags */
- return;
- }
- /* No address for RTP, we're on hold */
-
- if (sendonly == 1) /* One directional hold (sendonly/recvonly) */
- ast_set_flag(&dialog->flags[1], SIP_PAGE2_CALL_ONHOLD_ONEDIR);
- else if (sendonly == 2) /* Inactive stream */
- ast_set_flag(&dialog->flags[1], SIP_PAGE2_CALL_ONHOLD_INACTIVE);
- else
- ast_set_flag(&dialog->flags[1], SIP_PAGE2_CALL_ONHOLD_ACTIVE);
- return;
-}
-
-/*! \brief Process SIP SDP offer, select formats and activate RTP channels
- If offer is rejected, we will not change any properties of the call
- Return 0 on success, a negative value on errors.
- Must be called after find_sdp().
-*/
-static int process_sdp(struct sip_pvt *p, struct sip_request *req)
-{
- const char *m; /* SDP media offer */
- const char *c;
- const char *a;
- char host[258];
- int len = -1;
- int portno = -1; /*!< RTP Audio port number */
- int vportno = -1; /*!< RTP Video port number */
- int udptlportno = -1;
- int peert38capability = 0;
- char s[256];
- int old = 0;
-
- /* Peer capability is the capability in the SDP, non codec is RFC2833 DTMF (101) */
- int peercapability = 0, peernoncodeccapability = 0;
- int vpeercapability = 0, vpeernoncodeccapability = 0;
- struct sockaddr_in sin; /*!< media socket address */
- struct sockaddr_in vsin; /*!< Video socket address */
-
- const char *codecs;
- struct hostent *hp; /*!< RTP Audio host IP */
- struct hostent *vhp = NULL; /*!< RTP video host IP */
- struct ast_hostent audiohp;
- struct ast_hostent videohp;
- int codec;
- int destiterator = 0;
- int iterator;
- int sendonly = -1;
- int numberofports;
- struct ast_rtp *newaudiortp, *newvideortp; /* Buffers for codec handling */
- int newjointcapability; /* Negotiated capability */
- int newpeercapability;
- int newnoncodeccapability;
- int numberofmediastreams = 0;
- int debug = sip_debug_test_pvt(p);
-
- int found_rtpmap_codecs[SDP_MAX_RTPMAP_CODECS];
- int last_rtpmap_codec=0;
-
- if (!p->rtp) {
- ast_log(LOG_ERROR, "Got SDP but have no RTP session allocated.\n");
- return -1;
- }
-
- /* Initialize the temporary RTP structures we use to evaluate the offer from the peer */
-#ifdef LOW_MEMORY
- newaudiortp = ast_threadstorage_get(&ts_audio_rtp, ast_rtp_alloc_size());
-#else
- newaudiortp = alloca(ast_rtp_alloc_size());
-#endif
- memset(newaudiortp, 0, ast_rtp_alloc_size());
- ast_rtp_new_init(newaudiortp);
- ast_rtp_pt_clear(newaudiortp);
-
-#ifdef LOW_MEMORY
- newvideortp = ast_threadstorage_get(&ts_video_rtp, ast_rtp_alloc_size());
-#else
- newvideortp = alloca(ast_rtp_alloc_size());
-#endif
- memset(newvideortp, 0, ast_rtp_alloc_size());
- ast_rtp_new_init(newvideortp);
- ast_rtp_pt_clear(newvideortp);
-
- /* Update our last rtprx when we receive an SDP, too */
- p->lastrtprx = p->lastrtptx = time(NULL); /* XXX why both ? */
-
-
- /* Try to find first media stream */
- m = get_sdp(req, "m");
- destiterator = req->sdp_start;
- c = get_sdp_iterate(&destiterator, req, "c");
- if (ast_strlen_zero(m) || ast_strlen_zero(c)) {
- ast_log(LOG_WARNING, "Insufficient information for SDP (m = '%s', c = '%s')\n", m, c);
- return -1;
- }
-
- /* Check for IPv4 address (not IPv6 yet) */
- if (sscanf(c, "IN IP4 %256s", host) != 1) {
- ast_log(LOG_WARNING, "Invalid host in c= line, '%s'\n", c);
- return -1;
- }
-
- /* XXX This could block for a long time, and block the main thread! XXX */
- hp = ast_gethostbyname(host, &audiohp);
- if (!hp) {
- ast_log(LOG_WARNING, "Unable to lookup host in c= line, '%s'\n", c);
- return -1;
- }
- vhp = hp; /* Copy to video address as default too */
-
- iterator = req->sdp_start;
- ast_set_flag(&p->flags[0], SIP_NOVIDEO);
-
-
- /* Find media streams in this SDP offer */
- while ((m = get_sdp_iterate(&iterator, req, "m"))[0] != '\0') {
- int x;
- int audio = FALSE;
-
- numberofports = 1;
- len = -1;
- if ((sscanf(m, "audio %d/%d RTP/AVP %n", &x, &numberofports, &len) == 2 && len > 0) ||
- (sscanf(m, "audio %d RTP/AVP %n", &x, &len) == 1 && len > 0)) {
- audio = TRUE;
- numberofmediastreams++;
- /* Found audio stream in this media definition */
- portno = x;
- /* Scan through the RTP payload types specified in a "m=" line: */
- for (codecs = m + len; !ast_strlen_zero(codecs); codecs = ast_skip_blanks(codecs + len)) {
- if (sscanf(codecs, "%d%n", &codec, &len) != 1) {
- ast_log(LOG_WARNING, "Error in codec string '%s'\n", codecs);
- return -1;
- }
- if (debug)
- ast_verbose("Found RTP audio format %d\n", codec);
- ast_rtp_set_m_type(newaudiortp, codec);
- }
- } else if ((sscanf(m, "video %d/%d RTP/AVP %n", &x, &numberofports, &len) == 2 && len > 0) ||
- (sscanf(m, "video %d RTP/AVP %n", &x, &len) == 1 && len >= 0)) {
- /* If it is not audio - is it video ? */
- ast_clear_flag(&p->flags[0], SIP_NOVIDEO);
- numberofmediastreams++;
- vportno = x;
- /* Scan through the RTP payload types specified in a "m=" line: */
- for (codecs = m + len; !ast_strlen_zero(codecs); codecs = ast_skip_blanks(codecs + len)) {
- if (sscanf(codecs, "%d%n", &codec, &len) != 1) {
- ast_log(LOG_WARNING, "Error in codec string '%s'\n", codecs);
- return -1;
- }
- if (debug)
- ast_verbose("Found RTP video format %d\n", codec);
- ast_rtp_set_m_type(newvideortp, codec);
- }
- } else if (p->udptl && ( (sscanf(m, "image %d udptl t38%n", &x, &len) == 1 && len > 0) ||
- (sscanf(m, "image %d UDPTL t38%n", &x, &len) == 1 && len >= 0) )) {
- if (debug)
- ast_verbose("Got T.38 offer in SDP in dialog %s\n", p->callid);
- udptlportno = x;
- numberofmediastreams++;
-
- if (p->owner && p->lastinvite) {
- p->t38.state = T38_PEER_REINVITE; /* T38 Offered in re-invite from remote party */
- if (option_debug > 1)
- ast_log(LOG_DEBUG, "T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>" );
- } else {
- p->t38.state = T38_PEER_DIRECT; /* T38 Offered directly from peer in first invite */
- if (option_debug > 1)
- ast_log(LOG_DEBUG, "T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
- }
- } else
- ast_log(LOG_WARNING, "Unsupported SDP media type in offer: %s\n", m);
- if (numberofports > 1)
- ast_log(LOG_WARNING, "SDP offered %d ports for media, not supported by Asterisk. Will try anyway...\n", numberofports);
-
-
- /* Check for Media-description-level-address for audio */
- c = get_sdp_iterate(&destiterator, req, "c");
- if (!ast_strlen_zero(c)) {
- if (sscanf(c, "IN IP4 %256s", host) != 1) {
- ast_log(LOG_WARNING, "Invalid secondary host in c= line, '%s'\n", c);
- } else {
- /* XXX This could block for a long time, and block the main thread! XXX */
- if (audio) {
- if ( !(hp = ast_gethostbyname(host, &audiohp))) {
- ast_log(LOG_WARNING, "Unable to lookup RTP Audio host in secondary c= line, '%s'\n", c);
- return -2;
- }
- } else if (!(vhp = ast_gethostbyname(host, &videohp))) {
- ast_log(LOG_WARNING, "Unable to lookup RTP video host in secondary c= line, '%s'\n", c);
- return -2;
- }
- }
-
- }
- }
- if (portno == -1 && vportno == -1 && udptlportno == -1)
- /* No acceptable offer found in SDP - we have no ports */
- /* Do not change RTP or VRTP if this is a re-invite */
- return -2;
-
- if (numberofmediastreams > 2)
- /* We have too many fax, audio and/or video media streams, fail this offer */
- return -3;
-
- /* RTP addresses and ports for audio and video */
- sin.sin_family = AF_INET;
- vsin.sin_family = AF_INET;
- memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
- if (vhp)
- memcpy(&vsin.sin_addr, vhp->h_addr, sizeof(vsin.sin_addr));
-
- /* Setup UDPTL port number */
- if (p->udptl) {
- if (udptlportno > 0) {
- sin.sin_port = htons(udptlportno);
- if (ast_test_flag(&p->flags[0], SIP_NAT) && ast_test_flag(&p->flags[1], SIP_PAGE2_UDPTL_DESTINATION)) {
- struct sockaddr_in peer;
- ast_rtp_get_peer(p->rtp, &peer);
- if (peer.sin_addr.s_addr) {
- memcpy(&sin.sin_addr, &peer.sin_addr, sizeof(sin.sin_addr));
- if (debug) {
- ast_log(LOG_DEBUG, "Peer T.38 UDPTL is set behind NAT and with destination, destination address now %s\n", ast_inet_ntoa(sin.sin_addr));
- }
- }
- }
- ast_udptl_set_peer(p->udptl, &sin);
- if (debug)
- ast_log(LOG_DEBUG,"Peer T.38 UDPTL is at port %s:%d\n",ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
- } else {
- ast_udptl_stop(p->udptl);
- if (debug)
- ast_log(LOG_DEBUG, "Peer doesn't provide T.38 UDPTL\n");
- }
- }
-
-
- if (p->rtp) {
- if (portno > 0) {
- sin.sin_port = htons(portno);
- ast_rtp_set_peer(p->rtp, &sin);
- if (debug)
- ast_verbose("Peer audio RTP is at port %s:%d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
- } else {
- if (udptlportno > 0) {
- if (debug)
- ast_verbose("Got T.38 Re-invite without audio. Keeping RTP active during T.38 session. Callid %s\n", p->callid);
- } else {
- ast_rtp_stop(p->rtp);
- if (debug)
- ast_verbose("Peer doesn't provide audio. Callid %s\n", p->callid);
- }
- }
- }
- /* Setup video port number */
- if (vportno != -1)
- vsin.sin_port = htons(vportno);
-
- /* Next, scan through each "a=rtpmap:" line, noting each
- * specified RTP payload type (with corresponding MIME subtype):
- */
- /* XXX This needs to be done per media stream, since it's media stream specific */
- iterator = req->sdp_start;
- while ((a = get_sdp_iterate(&iterator, req, "a"))[0] != '\0') {
- char* mimeSubtype = ast_strdupa(a); /* ensures we have enough space */
- if (option_debug > 1) {
- int breakout = FALSE;
-
- /* If we're debugging, check for unsupported sdp options */
- if (!strncasecmp(a, "rtcp:", (size_t) 5)) {
- if (debug)
- ast_verbose("Got unsupported a:rtcp in SDP offer \n");
- breakout = TRUE;
- } else if (!strncasecmp(a, "fmtp:", (size_t) 5)) {
- /* Format parameters: Not supported */
- /* Note: This is used for codec parameters, like bitrate for
- G722 and video formats for H263 and H264
- See RFC2327 for an example */
- if (debug)
- ast_verbose("Got unsupported a:fmtp in SDP offer \n");
- breakout = TRUE;
- } else if (!strncasecmp(a, "framerate:", (size_t) 10)) {
- /* Video stuff: Not supported */
- if (debug)
- ast_verbose("Got unsupported a:framerate in SDP offer \n");
- breakout = TRUE;
- } else if (!strncasecmp(a, "maxprate:", (size_t) 9)) {
- /* Video stuff: Not supported */
- if (debug)
- ast_verbose("Got unsupported a:maxprate in SDP offer \n");
- breakout = TRUE;
- } else if (!strncasecmp(a, "crypto:", (size_t) 7)) {
- /* SRTP stuff, not yet supported */
- if (debug)
- ast_verbose("Got unsupported a:crypto in SDP offer \n");
- breakout = TRUE;
- }
- if (breakout) /* We have a match, skip to next header */
- continue;
- }
- if (!strcasecmp(a, "sendonly")) {
- if (sendonly == -1)
- sendonly = 1;
- continue;
- } else if (!strcasecmp(a, "inactive")) {
- if (sendonly == -1)
- sendonly = 2;
- continue;
- } else if (!strcasecmp(a, "sendrecv")) {
- if (sendonly == -1)
- sendonly = 0;
- continue;
- } else if (strlen(a) > 5 && !strncasecmp(a, "ptime", 5)) {
- char *tmp = strrchr(a, ':');
- long int framing = 0;
- if (tmp) {
- tmp++;
- framing = strtol(tmp, NULL, 10);
- if (framing == LONG_MIN || framing == LONG_MAX) {
- framing = 0;
- if (option_debug)
- ast_log(LOG_DEBUG, "Can't read framing from SDP: %s\n", a);
- }
- }
- if (framing && p->autoframing) {
- struct ast_codec_pref *pref = ast_rtp_codec_getpref(p->rtp);
- int codec_n;
- int format = 0;
- for (codec_n = 0; codec_n < MAX_RTP_PT; codec_n++) {
- format = ast_rtp_codec_getformat(codec_n);
- if (!format) /* non-codec or not found */
- continue;
- if (option_debug)
- ast_log(LOG_DEBUG, "Setting framing for %d to %ld\n", format, framing);
- ast_codec_pref_setsize(pref, format, framing);
- }
- ast_rtp_codec_setpref(p->rtp, pref);
- }
- continue;
- } else if (sscanf(a, "rtpmap: %u %[^/]/", &codec, mimeSubtype) == 2) {
- /* We have a rtpmap to handle */
- int found = FALSE;
- /* We should propably check if this is an audio or video codec
- so we know where to look */
-
- if (last_rtpmap_codec < SDP_MAX_RTPMAP_CODECS) {
- /* Note: should really look at the 'freq' and '#chans' params too */
- if(ast_rtp_set_rtpmap_type(newaudiortp, codec, "audio", mimeSubtype,
- ast_test_flag(&p->flags[0], SIP_G726_NONSTANDARD) ? AST_RTP_OPT_G726_NONSTANDARD : 0) != -1) {
- if (debug)
- ast_verbose("Found audio description format %s for ID %d\n", mimeSubtype, codec);
- found_rtpmap_codecs[last_rtpmap_codec] = codec;
- last_rtpmap_codec++;
- found = TRUE;
-
- } else if (p->vrtp) {
- if(ast_rtp_set_rtpmap_type(newvideortp, codec, "video", mimeSubtype, 0) != -1) {
- if (debug)
- ast_verbose("Found video description format %s for ID %d\n", mimeSubtype, codec);
- found_rtpmap_codecs[last_rtpmap_codec] = codec;
- last_rtpmap_codec++;
- found = TRUE;
- }
- }
- } else {
- if (debug)
- ast_verbose("Discarded description format %s for ID %d\n", mimeSubtype, codec);
- }
-
- if (!found) {
- /* Remove this codec since it's an unknown media type for us */
- /* XXX This is buggy since the media line for audio and video can have the
- same numbers. We need to check as described above, but for testing this works... */
- ast_rtp_unset_m_type(newaudiortp, codec);
- ast_rtp_unset_m_type(newvideortp, codec);
- if (debug)
- ast_verbose("Found unknown media description format %s for ID %d\n", mimeSubtype, codec);
- }
- }
- }
-
- if (udptlportno != -1) {
- int found = 0, x;
-
- old = 0;
-
- /* Scan trough the a= lines for T38 attributes and set apropriate fileds */
- iterator = req->sdp_start;
- while ((a = get_sdp_iterate(&iterator, req, "a"))[0] != '\0') {
- if ((sscanf(a, "T38FaxMaxBuffer:%d", &x) == 1)) {
- found = 1;
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "MaxBufferSize:%d\n",x);
- } else if ((sscanf(a, "T38MaxBitRate:%d", &x) == 1) || (sscanf(a, "T38FaxMaxRate:%d", &x) == 1)) {
- found = 1;
- if (option_debug > 2)
- ast_log(LOG_DEBUG,"T38MaxBitRate: %d\n",x);
- switch (x) {
- case 14400:
- peert38capability |= T38FAX_RATE_14400 | T38FAX_RATE_12000 | T38FAX_RATE_9600 | T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400;
- break;
- case 12000:
- peert38capability |= T38FAX_RATE_12000 | T38FAX_RATE_9600 | T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400;
- break;
- case 9600:
- peert38capability |= T38FAX_RATE_9600 | T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400;
- break;
- case 7200:
- peert38capability |= T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400;
- break;
- case 4800:
- peert38capability |= T38FAX_RATE_4800 | T38FAX_RATE_2400;
- break;
- case 2400:
- peert38capability |= T38FAX_RATE_2400;
- break;
- }
- } else if ((sscanf(a, "T38FaxVersion:%d", &x) == 1)) {
- found = 1;
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "FaxVersion: %d\n",x);
- if (x == 0)
- peert38capability |= T38FAX_VERSION_0;
- else if (x == 1)
- peert38capability |= T38FAX_VERSION_1;
- } else if ((sscanf(a, "T38FaxMaxDatagram:%d", &x) == 1) || (sscanf(a, "T38MaxDatagram:%d", &x) == 1)) {
- found = 1;
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "FaxMaxDatagram: %d\n",x);
- ast_udptl_set_far_max_datagram(p->udptl, x);
- ast_udptl_set_local_max_datagram(p->udptl, x);
- } else if ((strncmp(a, "T38FaxFillBitRemoval", 20) == 0)) {
- found = 1;
- if ((sscanf(a, "T38FaxFillBitRemoval:%d", &x) == 1)) {
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "FillBitRemoval: %d\n",x);
- if (x == 1)
- peert38capability |= T38FAX_FILL_BIT_REMOVAL;
- } else {
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "FillBitRemoval\n");
- peert38capability |= T38FAX_FILL_BIT_REMOVAL;
- }
- } else if ((strncmp(a, "T38FaxTranscodingMMR", 20) == 0)) {
- found = 1;
- if ((sscanf(a, "T38FaxTranscodingMMR:%d", &x) == 1)) {
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Transcoding MMR: %d\n",x);
- if (x == 1)
- peert38capability |= T38FAX_TRANSCODING_MMR;
- } else {
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Transcoding MMR\n");
- peert38capability |= T38FAX_TRANSCODING_MMR;
- }
- } else if ((strncmp(a, "T38FaxTranscodingJBIG", 21) == 0)) {
- found = 1;
- if ((sscanf(a, "T38FaxTranscodingJBIG:%d", &x) == 1)) {
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Transcoding JBIG: %d\n",x);
- if (x == 1)
- peert38capability |= T38FAX_TRANSCODING_JBIG;
- } else {
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Transcoding JBIG\n");
- peert38capability |= T38FAX_TRANSCODING_JBIG;
- }
- } else if ((sscanf(a, "T38FaxRateManagement:%255s", s) == 1)) {
- found = 1;
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "RateManagement: %s\n", s);
- if (!strcasecmp(s, "localTCF"))
- peert38capability |= T38FAX_RATE_MANAGEMENT_LOCAL_TCF;
- else if (!strcasecmp(s, "transferredTCF"))
- peert38capability |= T38FAX_RATE_MANAGEMENT_TRANSFERED_TCF;
- } else if ((sscanf(a, "T38FaxUdpEC:%255s", s) == 1)) {
- found = 1;
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "UDP EC: %s\n", s);
- if (!strcasecmp(s, "t38UDPRedundancy")) {
- peert38capability |= T38FAX_UDP_EC_REDUNDANCY;
- ast_udptl_set_error_correction_scheme(p->udptl, UDPTL_ERROR_CORRECTION_REDUNDANCY);
- } else if (!strcasecmp(s, "t38UDPFEC")) {
- peert38capability |= T38FAX_UDP_EC_FEC;
- ast_udptl_set_error_correction_scheme(p->udptl, UDPTL_ERROR_CORRECTION_FEC);
- } else {
- peert38capability |= T38FAX_UDP_EC_NONE;
- ast_udptl_set_error_correction_scheme(p->udptl, UDPTL_ERROR_CORRECTION_NONE);
- }
- }
- }
- if (found) { /* Some cisco equipment returns nothing beside c= and m= lines in 200 OK T38 SDP */
- p->t38.peercapability = peert38capability;
- p->t38.jointcapability = (peert38capability & 255); /* Put everything beside supported speeds settings */
- peert38capability &= (T38FAX_RATE_14400 | T38FAX_RATE_12000 | T38FAX_RATE_9600 | T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400);
- p->t38.jointcapability |= (peert38capability & p->t38.capability); /* Put the lower of our's and peer's speed */
- }
- if (debug)
- ast_log(LOG_DEBUG, "Our T38 capability = (%d), peer T38 capability (%d), joint T38 capability (%d)\n",
- p->t38.capability,
- p->t38.peercapability,
- p->t38.jointcapability);
- } else {
- p->t38.state = T38_DISABLED;
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
- }
-
- /* Now gather all of the codecs that we are asked for: */
- ast_rtp_get_current_formats(newaudiortp, &peercapability, &peernoncodeccapability);
- ast_rtp_get_current_formats(newvideortp, &vpeercapability, &vpeernoncodeccapability);
-
- newjointcapability = p->capability & (peercapability | vpeercapability);
- newpeercapability = (peercapability | vpeercapability);
- newnoncodeccapability = p->noncodeccapability & peernoncodeccapability;
-
-
- if (debug) {
- /* shame on whoever coded this.... */
- char s1[SIPBUFSIZE], s2[SIPBUFSIZE], s3[SIPBUFSIZE], s4[SIPBUFSIZE];
-
- ast_verbose("Capabilities: us - %s, peer - audio=%s/video=%s, combined - %s\n",
- ast_getformatname_multiple(s1, SIPBUFSIZE, p->capability),
- ast_getformatname_multiple(s2, SIPBUFSIZE, newpeercapability),
- ast_getformatname_multiple(s3, SIPBUFSIZE, vpeercapability),
- ast_getformatname_multiple(s4, SIPBUFSIZE, newjointcapability));
-
- ast_verbose("Non-codec capabilities (dtmf): us - %s, peer - %s, combined - %s\n",
- ast_rtp_lookup_mime_multiple(s1, SIPBUFSIZE, p->noncodeccapability, 0, 0),
- ast_rtp_lookup_mime_multiple(s2, SIPBUFSIZE, peernoncodeccapability, 0, 0),
- ast_rtp_lookup_mime_multiple(s3, SIPBUFSIZE, newnoncodeccapability, 0, 0));
- }
- if (!newjointcapability) {
- /* If T.38 was not negotiated either, totally bail out... */
- if (!p->t38.jointcapability || !udptlportno) {
- ast_log(LOG_NOTICE, "No compatible codecs, not accepting this offer!\n");
- /* Do NOT Change current setting */
- return -1;
- } else {
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Have T.38 but no audio codecs, accepting offer anyway\n");
- return 0;
- }
- }
-
- /* We are now ready to change the sip session and p->rtp and p->vrtp with the offered codecs, since
- they are acceptable */
- p->jointcapability = newjointcapability; /* Our joint codec profile for this call */
- p->peercapability = newpeercapability; /* The other sides capability in latest offer */
- p->jointnoncodeccapability = newnoncodeccapability; /* DTMF capabilities */
-
- ast_rtp_pt_copy(p->rtp, newaudiortp);
- if (p->vrtp)
- ast_rtp_pt_copy(p->vrtp, newvideortp);
-
- if (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_AUTO) {
- ast_clear_flag(&p->flags[0], SIP_DTMF);
- if (newnoncodeccapability & AST_RTP_DTMF) {
- /* XXX Would it be reasonable to drop the DSP at this point? XXX */
- ast_set_flag(&p->flags[0], SIP_DTMF_RFC2833);
- /* Since RFC2833 is now negotiated we need to change some properties of the RTP stream */
- ast_rtp_setdtmf(p->rtp, 1);
- ast_rtp_setdtmfcompensate(p->rtp, ast_test_flag(&p->flags[1], SIP_PAGE2_RFC2833_COMPENSATE));
- } else {
- ast_set_flag(&p->flags[0], SIP_DTMF_INBAND);
- }
- }
-
- /* Setup audio port number */
- if (p->rtp && sin.sin_port) {
- ast_rtp_set_peer(p->rtp, &sin);
- if (debug)
- ast_verbose("Peer audio RTP is at port %s:%d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
- }
-
- /* Setup video port number */
- if (p->vrtp && vsin.sin_port) {
- ast_rtp_set_peer(p->vrtp, &vsin);
- if (debug)
- ast_verbose("Peer video RTP is at port %s:%d\n", ast_inet_ntoa(vsin.sin_addr), ntohs(vsin.sin_port));
- }
-
- /* Ok, we're going with this offer */
- if (option_debug > 1) {
- char buf[SIPBUFSIZE];
- ast_log(LOG_DEBUG, "We're settling with these formats: %s\n", ast_getformatname_multiple(buf, SIPBUFSIZE, p->jointcapability));
- }
-
- if (!p->owner) /* There's no open channel owning us so we can return here. For a re-invite or so, we proceed */
- return 0;
-
- if (option_debug > 3)
- ast_log(LOG_DEBUG, "We have an owner, now see if we need to change this call\n");
-
- if (!(p->owner->nativeformats & p->jointcapability) && (p->jointcapability & AST_FORMAT_AUDIO_MASK)) {
- if (debug) {
- char s1[SIPBUFSIZE], s2[SIPBUFSIZE];
- ast_log(LOG_DEBUG, "Oooh, we need to change our audio formats since our peer supports only %s and not %s\n",
- ast_getformatname_multiple(s1, SIPBUFSIZE, p->jointcapability),
- ast_getformatname_multiple(s2, SIPBUFSIZE, p->owner->nativeformats));
- }
- p->owner->nativeformats = ast_codec_choose(&p->prefs, p->jointcapability, 1) | (p->capability & vpeercapability);
- ast_set_read_format(p->owner, p->owner->readformat);
- ast_set_write_format(p->owner, p->owner->writeformat);
- }
-
- if (ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD) && sin.sin_addr.s_addr && (!sendonly || sendonly == -1)) {
- ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
- /* Activate a re-invite */
- ast_queue_frame(p->owner, &ast_null_frame);
- } else if (!sin.sin_addr.s_addr || (sendonly && sendonly != -1)) {
- ast_queue_control_data(p->owner, AST_CONTROL_HOLD,
- S_OR(p->mohsuggest, NULL),
- !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
- if (sendonly)
- ast_rtp_stop(p->rtp);
- /* RTCP needs to go ahead, even if we're on hold!!! */
- /* Activate a re-invite */
- ast_queue_frame(p->owner, &ast_null_frame);
- }
-
- /* Manager Hold and Unhold events must be generated, if necessary */
- if (ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD) && sin.sin_addr.s_addr && (!sendonly || sendonly == -1))
- change_hold_state(p, req, FALSE, sendonly);
- else if (!sin.sin_addr.s_addr || (sendonly && sendonly != -1))
- change_hold_state(p, req, TRUE, sendonly);
- return 0;
-}
-
-#ifdef LOW_MEMORY
-static void ts_ast_rtp_destroy(void *data)
-{
- struct ast_rtp *tmp = data;
- ast_rtp_destroy(tmp);
-}
-#endif
-
-/*! \brief Add header to SIP message */
-static int add_header(struct sip_request *req, const char *var, const char *value)
-{
- int maxlen = sizeof(req->data) - 4 - req->len; /* 4 bytes are for two \r\n ? */
-
- if (req->headers == SIP_MAX_HEADERS) {
- ast_log(LOG_WARNING, "Out of SIP header space\n");
- return -1;
- }
-
- if (req->lines) {
- ast_log(LOG_WARNING, "Can't add more headers when lines have been added\n");
- return -1;
- }
-
- if (maxlen <= 0) {
- ast_log(LOG_WARNING, "Out of space, can't add anymore (%s:%s)\n", var, value);
- return -1;
- }
-
- req->header[req->headers] = req->data + req->len;
-
- if (compactheaders)
- var = find_alias(var, var);
-
- snprintf(req->header[req->headers], maxlen, "%s: %s\r\n", var, value);
- req->len += strlen(req->header[req->headers]);
- req->headers++;
-
- return 0;
-}
-
-/*! \brief Add 'Content-Length' header to SIP message */
-static int add_header_contentLength(struct sip_request *req, int len)
-{
- char clen[10];
-
- snprintf(clen, sizeof(clen), "%d", len);
- return add_header(req, "Content-Length", clen);
-}
-
-/*! \brief Add content (not header) to SIP message */
-static int add_line(struct sip_request *req, const char *line)
-{
- if (req->lines == SIP_MAX_LINES) {
- ast_log(LOG_WARNING, "Out of SIP line space\n");
- return -1;
- }
- if (!req->lines) {
- /* Add extra empty return */
- snprintf(req->data + req->len, sizeof(req->data) - req->len, "\r\n");
- req->len += strlen(req->data + req->len);
- }
- if (req->len >= sizeof(req->data) - 4) {
- ast_log(LOG_WARNING, "Out of space, can't add anymore\n");
- return -1;
- }
- req->line[req->lines] = req->data + req->len;
- snprintf(req->line[req->lines], sizeof(req->data) - req->len, "%s", line);
- req->len += strlen(req->line[req->lines]);
- req->lines++;
- return 0;
-}
-
-/*! \brief Copy one header field from one request to another */
-static int copy_header(struct sip_request *req, const struct sip_request *orig, const char *field)
-{
- const char *tmp = get_header(orig, field);
-
- if (!ast_strlen_zero(tmp)) /* Add what we're responding to */
- return add_header(req, field, tmp);
- ast_log(LOG_NOTICE, "No field '%s' present to copy\n", field);
- return -1;
-}
-
-/*! \brief Copy all headers from one request to another */
-static int copy_all_header(struct sip_request *req, const struct sip_request *orig, const char *field)
-{
- int start = 0;
- int copied = 0;
- for (;;) {
- const char *tmp = __get_header(orig, field, &start);
-
- if (ast_strlen_zero(tmp))
- break;
- /* Add what we're responding to */
- add_header(req, field, tmp);
- copied++;
- }
- return copied ? 0 : -1;
-}
-
-/*! \brief Copy SIP VIA Headers from the request to the response
-\note If the client indicates that it wishes to know the port we received from,
- it adds ;rport without an argument to the topmost via header. We need to
- add the port number (from our point of view) to that parameter.
- We always add ;received=<ip address> to the topmost via header.
- Received: RFC 3261, rport RFC 3581 */
-static int copy_via_headers(struct sip_pvt *p, struct sip_request *req, const struct sip_request *orig, const char *field)
-{
- int copied = 0;
- int start = 0;
-
- for (;;) {
- char new[512];
- const char *oh = __get_header(orig, field, &start);
-
- if (ast_strlen_zero(oh))
- break;
-
- if (!copied) { /* Only check for empty rport in topmost via header */
- char leftmost[512], *others, *rport;
-
- /* Only work on leftmost value */
- ast_copy_string(leftmost, oh, sizeof(leftmost));
- others = strchr(leftmost, ',');
- if (others)
- *others++ = '\0';
-
- /* Find ;rport; (empty request) */
- rport = strstr(leftmost, ";rport");
- if (rport && *(rport+6) == '=')
- rport = NULL; /* We already have a parameter to rport */
-
- /* Check rport if NAT=yes or NAT=rfc3581 (which is the default setting) */
- if (rport && ((ast_test_flag(&p->flags[0], SIP_NAT) == SIP_NAT_ALWAYS) || (ast_test_flag(&p->flags[0], SIP_NAT) == SIP_NAT_RFC3581))) {
- /* We need to add received port - rport */
- char *end;
-
- rport = strstr(leftmost, ";rport");
-
- if (rport) {
- end = strchr(rport + 1, ';');
- if (end)
- memmove(rport, end, strlen(end) + 1);
- else
- *rport = '\0';
- }
-
- /* Add rport to first VIA header if requested */
- snprintf(new, sizeof(new), "%s;received=%s;rport=%d%s%s",
- leftmost, ast_inet_ntoa(p->recv.sin_addr),
- ntohs(p->recv.sin_port),
- others ? "," : "", others ? others : "");
- } else {
- /* We should *always* add a received to the topmost via */
- snprintf(new, sizeof(new), "%s;received=%s%s%s",
- leftmost, ast_inet_ntoa(p->recv.sin_addr),
- others ? "," : "", others ? others : "");
- }
- oh = new; /* the header to copy */
- } /* else add the following via headers untouched */
- add_header(req, field, oh);
- copied++;
- }
- if (!copied) {
- ast_log(LOG_NOTICE, "No header field '%s' present to copy\n", field);
- return -1;
- }
- return 0;
-}
-
-/*! \brief Add route header into request per learned route */
-static void add_route(struct sip_request *req, struct sip_route *route)
-{
- char r[SIPBUFSIZE*2], *p;
- int n, rem = sizeof(r);
-
- if (!route)
- return;
-
- p = r;
- for (;route ; route = route->next) {
- n = strlen(route->hop);
- if (rem < n+3) /* we need room for ",<route>" */
- break;
- if (p != r) { /* add a separator after fist route */
- *p++ = ',';
- --rem;
- }
- *p++ = '<';
- ast_copy_string(p, route->hop, rem); /* cannot fail */
- p += n;
- *p++ = '>';
- rem -= (n+2);
- }
- *p = '\0';
- add_header(req, "Route", r);
-}
-
-/*! \brief Set destination from SIP URI */
-static void set_destination(struct sip_pvt *p, char *uri)
-{
- char *h, *maddr, hostname[256];
- int port, hn;
- struct hostent *hp;
- struct ast_hostent ahp;
- int debug=sip_debug_test_pvt(p);
-
- /* Parse uri to h (host) and port - uri is already just the part inside the <> */
- /* general form we are expecting is sip[s]:username[:password]@host[:port][;...] */
-
- if (debug)
- ast_verbose("set_destination: Parsing <%s> for address/port to send to\n", uri);
-
- /* Find and parse hostname */
- h = strchr(uri, '@');
- if (h)
- ++h;
- else {
- h = uri;
- if (strncasecmp(h, "sip:", 4) == 0)
- h += 4;
- else if (strncasecmp(h, "sips:", 5) == 0)
- h += 5;
- }
- hn = strcspn(h, ":;>") + 1;
- if (hn > sizeof(hostname))
- hn = sizeof(hostname);
- ast_copy_string(hostname, h, hn);
- /* XXX bug here if string has been trimmed to sizeof(hostname) */
- h += hn - 1;
-
- /* Is "port" present? if not default to STANDARD_SIP_PORT */
- if (*h == ':') {
- /* Parse port */
- ++h;
- port = strtol(h, &h, 10);
- }
- else
- port = STANDARD_SIP_PORT;
-
- /* Got the hostname:port - but maybe there's a "maddr=" to override address? */
- maddr = strstr(h, "maddr=");
- if (maddr) {
- maddr += 6;
- hn = strspn(maddr, "0123456789.") + 1;
- if (hn > sizeof(hostname))
- hn = sizeof(hostname);
- ast_copy_string(hostname, maddr, hn);
- }
-
- hp = ast_gethostbyname(hostname, &ahp);
- if (hp == NULL) {
- ast_log(LOG_WARNING, "Can't find address for host '%s'\n", hostname);
- return;
- }
- p->sa.sin_family = AF_INET;
- memcpy(&p->sa.sin_addr, hp->h_addr, sizeof(p->sa.sin_addr));
- p->sa.sin_port = htons(port);
- if (debug)
- ast_verbose("set_destination: set destination to %s, port %d\n", ast_inet_ntoa(p->sa.sin_addr), port);
-}
-
-/*! \brief Initialize SIP response, based on SIP request */
-static int init_resp(struct sip_request *resp, const char *msg)
-{
- /* Initialize a response */
- memset(resp, 0, sizeof(*resp));
- resp->method = SIP_RESPONSE;
- resp->header[0] = resp->data;
- snprintf(resp->header[0], sizeof(resp->data), "SIP/2.0 %s\r\n", msg);
- resp->len = strlen(resp->header[0]);
- resp->headers++;
- return 0;
-}
-
-/*! \brief Initialize SIP request */
-static int init_req(struct sip_request *req, int sipmethod, const char *recip)
-{
- /* Initialize a request */
- memset(req, 0, sizeof(*req));
- req->method = sipmethod;
- req->header[0] = req->data;
- snprintf(req->header[0], sizeof(req->data), "%s %s SIP/2.0\r\n", sip_methods[sipmethod].text, recip);
- req->len = strlen(req->header[0]);
- req->headers++;
- return 0;
-}
-
-
-/*! \brief Prepare SIP response packet */
-static int respprep(struct sip_request *resp, struct sip_pvt *p, const char *msg, const struct sip_request *req)
-{
- char newto[256];
- const char *ot;
-
- init_resp(resp, msg);
- copy_via_headers(p, resp, req, "Via");
- if (msg[0] == '1' || msg[0] == '2')
- copy_all_header(resp, req, "Record-Route");
- copy_header(resp, req, "From");
- ot = get_header(req, "To");
- if (!strcasestr(ot, "tag=") && strncmp(msg, "100", 3)) {
- /* Add the proper tag if we don't have it already. If they have specified
- their tag, use it. Otherwise, use our own tag */
- if (!ast_strlen_zero(p->theirtag) && ast_test_flag(&p->flags[0], SIP_OUTGOING))
- snprintf(newto, sizeof(newto), "%s;tag=%s", ot, p->theirtag);
- else if (p->tag && !ast_test_flag(&p->flags[0], SIP_OUTGOING))
- snprintf(newto, sizeof(newto), "%s;tag=%s", ot, p->tag);
- else
- ast_copy_string(newto, ot, sizeof(newto));
- ot = newto;
- }
- add_header(resp, "To", ot);
- copy_header(resp, req, "Call-ID");
- copy_header(resp, req, "CSeq");
- if (!ast_strlen_zero(global_useragent))
- add_header(resp, "User-Agent", global_useragent);
- add_header(resp, "Allow", ALLOWED_METHODS);
- add_header(resp, "Supported", SUPPORTED_EXTENSIONS);
- if (msg[0] == '2' && (p->method == SIP_SUBSCRIBE || p->method == SIP_REGISTER)) {
- /* For registration responses, we also need expiry and
- contact info */
- char tmp[256];
-
- snprintf(tmp, sizeof(tmp), "%d", p->expiry);
- add_header(resp, "Expires", tmp);
- if (p->expiry) { /* Only add contact if we have an expiry time */
- char contact[SIPBUFSIZE];
- snprintf(contact, sizeof(contact), "%s;expires=%d", p->our_contact, p->expiry);
- add_header(resp, "Contact", contact); /* Not when we unregister */
- }
- } else if (msg[0] != '4' && !ast_strlen_zero(p->our_contact)) {
- add_header(resp, "Contact", p->our_contact);
- }
- return 0;
-}
-
-/*! \brief Initialize a SIP request message (not the initial one in a dialog) */
-static int reqprep(struct sip_request *req, struct sip_pvt *p, int sipmethod, int seqno, int newbranch)
-{
- struct sip_request *orig = &p->initreq;
- char stripped[80];
- char tmp[80];
- char newto[256];
- const char *c;
- const char *ot, *of;
- int is_strict = FALSE; /*!< Strict routing flag */
-
- memset(req, 0, sizeof(struct sip_request));
-
- snprintf(p->lastmsg, sizeof(p->lastmsg), "Tx: %s", sip_methods[sipmethod].text);
-
- if (!seqno) {
- p->ocseq++;
- seqno = p->ocseq;
- }
-
- if (sipmethod == SIP_CANCEL) {
- p->branch = p->invite_branch;
- build_via(p);
- } else if (newbranch) {
- p->branch ^= ast_random();
- build_via(p);
- }
-
- /* Check for strict or loose router */
- if (p->route && !ast_strlen_zero(p->route->hop) && strstr(p->route->hop,";lr") == NULL) {
- is_strict = TRUE;
- if (sipdebug)
- ast_log(LOG_DEBUG, "Strict routing enforced for session %s\n", p->callid);
- }
-
- if (sipmethod == SIP_CANCEL)
- c = p->initreq.rlPart2; /* Use original URI */
- else if (sipmethod == SIP_ACK) {
- /* Use URI from Contact: in 200 OK (if INVITE)
- (we only have the contacturi on INVITEs) */
- if (!ast_strlen_zero(p->okcontacturi))
- c = is_strict ? p->route->hop : p->okcontacturi;
- else
- c = p->initreq.rlPart2;
- } else if (!ast_strlen_zero(p->okcontacturi))
- c = is_strict ? p->route->hop : p->okcontacturi; /* Use for BYE or REINVITE */
- else if (!ast_strlen_zero(p->uri))
- c = p->uri;
- else {
- char *n;
- /* We have no URI, use To: or From: header as URI (depending on direction) */
- ast_copy_string(stripped, get_header(orig, (ast_test_flag(&p->flags[0], SIP_OUTGOING)) ? "To" : "From"),
- sizeof(stripped));
- n = get_in_brackets(stripped);
- c = strsep(&n, ";"); /* trim ; and beyond */
- }
- init_req(req, sipmethod, c);
-
- snprintf(tmp, sizeof(tmp), "%d %s", seqno, sip_methods[sipmethod].text);
-
- add_header(req, "Via", p->via);
- if (p->route) {
- set_destination(p, p->route->hop);
- add_route(req, is_strict ? p->route->next : p->route);
- }
-
- ot = get_header(orig, "To");
- of = get_header(orig, "From");
-
- /* Add tag *unless* this is a CANCEL, in which case we need to send it exactly
- as our original request, including tag (or presumably lack thereof) */
- if (!strcasestr(ot, "tag=") && sipmethod != SIP_CANCEL) {
- /* Add the proper tag if we don't have it already. If they have specified
- their tag, use it. Otherwise, use our own tag */
- if (ast_test_flag(&p->flags[0], SIP_OUTGOING) && !ast_strlen_zero(p->theirtag))
- snprintf(newto, sizeof(newto), "%s;tag=%s", ot, p->theirtag);
- else if (!ast_test_flag(&p->flags[0], SIP_OUTGOING))
- snprintf(newto, sizeof(newto), "%s;tag=%s", ot, p->tag);
- else
- snprintf(newto, sizeof(newto), "%s", ot);
- ot = newto;
- }
-
- if (ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
- add_header(req, "From", of);
- add_header(req, "To", ot);
- } else {
- add_header(req, "From", ot);
- add_header(req, "To", of);
- }
- /* Do not add Contact for MESSAGE, BYE and Cancel requests */
- if (sipmethod != SIP_BYE && sipmethod != SIP_CANCEL && sipmethod != SIP_MESSAGE)
- add_header(req, "Contact", p->our_contact);
-
- copy_header(req, orig, "Call-ID");
- add_header(req, "CSeq", tmp);
-
- if (!ast_strlen_zero(global_useragent))
- add_header(req, "User-Agent", global_useragent);
- add_header(req, "Max-Forwards", DEFAULT_MAX_FORWARDS);
-
- if (!ast_strlen_zero(p->rpid))
- add_header(req, "Remote-Party-ID", p->rpid);
-
- return 0;
-}
-
-/*! \brief Base transmit response function */
-static int __transmit_response(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable)
-{
- struct sip_request resp;
- int seqno = 0;
-
- if (reliable && (sscanf(get_header(req, "CSeq"), "%d ", &seqno) != 1)) {
- ast_log(LOG_WARNING, "Unable to determine sequence number from '%s'\n", get_header(req, "CSeq"));
- return -1;
- }
- respprep(&resp, p, msg, req);
- add_header_contentLength(&resp, 0);
- /* If we are cancelling an incoming invite for some reason, add information
- about the reason why we are doing this in clear text */
- if (p->method == SIP_INVITE && msg[0] != '1' && p->owner && p->owner->hangupcause) {
- char buf[10];
-
- add_header(&resp, "X-Asterisk-HangupCause", ast_cause2str(p->owner->hangupcause));
- snprintf(buf, sizeof(buf), "%d", p->owner->hangupcause);
- add_header(&resp, "X-Asterisk-HangupCauseCode", buf);
- }
- return send_response(p, &resp, reliable, seqno);
-}
-
-static void temp_pvt_cleanup(void *data)
-{
- struct sip_pvt *p = data;
-
- ast_string_field_free_memory(p);
-
- free(data);
-}
-
-/*! \brief Transmit response, no retransmits, using a temporary pvt structure */
-static int transmit_response_using_temp(ast_string_field callid, struct sockaddr_in *sin, int useglobal_nat, const int intended_method, const struct sip_request *req, const char *msg)
-{
- struct sip_pvt *p = NULL;
-
- if (!(p = ast_threadstorage_get(&ts_temp_pvt, sizeof(*p)))) {
- ast_log(LOG_NOTICE, "Failed to get temporary pvt\n");
- return -1;
- }
-
- /* if the structure was just allocated, initialize it */
- if (!ast_test_flag(&p->flags[0], SIP_NO_HISTORY)) {
- ast_set_flag(&p->flags[0], SIP_NO_HISTORY);
- if (ast_string_field_init(p, 512))
- return -1;
- }
-
- /* Initialize the bare minimum */
- p->method = intended_method;
-
- if (sin) {
- p->sa = *sin;
- if (ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip))
- p->ourip = __ourip;
- } else
- p->ourip = __ourip;
-
- p->branch = ast_random();
- make_our_tag(p->tag, sizeof(p->tag));
- p->ocseq = INITIAL_CSEQ;
-
- if (useglobal_nat && sin) {
- ast_copy_flags(&p->flags[0], &global_flags[0], SIP_NAT);
- p->recv = *sin;
- do_setnat(p, ast_test_flag(&p->flags[0], SIP_NAT) & SIP_NAT_ROUTE);
- }
- check_via(p, req);
-
- ast_string_field_set(p, fromdomain, default_fromdomain);
- build_via(p);
- ast_string_field_set(p, callid, callid);
-
- /* Use this temporary pvt structure to send the message */
- __transmit_response(p, msg, req, XMIT_UNRELIABLE);
-
- /* Free the string fields, but not the pool space */
- ast_string_field_reset_all(p);
-
- return 0;
-}
-
-/*! \brief Transmit response, no retransmits */
-static int transmit_response(struct sip_pvt *p, const char *msg, const struct sip_request *req)
-{
- return __transmit_response(p, msg, req, XMIT_UNRELIABLE);
-}
-
-/*! \brief Transmit response, no retransmits */
-static int transmit_response_with_unsupported(struct sip_pvt *p, const char *msg, const struct sip_request *req, const char *unsupported)
-{
- struct sip_request resp;
- respprep(&resp, p, msg, req);
- append_date(&resp);
- add_header(&resp, "Unsupported", unsupported);
- add_header_contentLength(&resp, 0);
- return send_response(p, &resp, XMIT_UNRELIABLE, 0);
-}
-
-/*! \brief Transmit response, Make sure you get an ACK
- This is only used for responses to INVITEs, where we need to make sure we get an ACK
-*/
-static int transmit_response_reliable(struct sip_pvt *p, const char *msg, const struct sip_request *req)
-{
- return __transmit_response(p, msg, req, XMIT_CRITICAL);
-}
-
-/*! \brief Append date to SIP message */
-static void append_date(struct sip_request *req)
-{
- char tmpdat[256];
- struct tm tm;
- time_t t = time(NULL);
-
- gmtime_r(&t, &tm);
- strftime(tmpdat, sizeof(tmpdat), "%a, %d %b %Y %T GMT", &tm);
- add_header(req, "Date", tmpdat);
-}
-
-/*! \brief Append date and content length before transmitting response */
-static int transmit_response_with_date(struct sip_pvt *p, const char *msg, const struct sip_request *req)
-{
- struct sip_request resp;
- respprep(&resp, p, msg, req);
- append_date(&resp);
- add_header_contentLength(&resp, 0);
- return send_response(p, &resp, XMIT_UNRELIABLE, 0);
-}
-
-/*! \brief Append Accept header, content length before transmitting response */
-static int transmit_response_with_allow(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable)
-{
- struct sip_request resp;
- respprep(&resp, p, msg, req);
- add_header(&resp, "Accept", "application/sdp");
- add_header_contentLength(&resp, 0);
- return send_response(p, &resp, reliable, 0);
-}
-
-/*! \brief Respond with authorization request */
-static int transmit_response_with_auth(struct sip_pvt *p, const char *msg, const struct sip_request *req, const char *randdata, enum xmittype reliable, const char *header, int stale)
-{
- struct sip_request resp;
- char tmp[512];
- int seqno = 0;
-
- if (reliable && (sscanf(get_header(req, "CSeq"), "%d ", &seqno) != 1)) {
- ast_log(LOG_WARNING, "Unable to determine sequence number from '%s'\n", get_header(req, "CSeq"));
- return -1;
- }
- /* Stale means that they sent us correct authentication, but
- based it on an old challenge (nonce) */
- snprintf(tmp, sizeof(tmp), "Digest algorithm=MD5, realm=\"%s\", nonce=\"%s\"%s", global_realm, randdata, stale ? ", stale=true" : "");
- respprep(&resp, p, msg, req);
- add_header(&resp, header, tmp);
- add_header_contentLength(&resp, 0);
- append_history(p, "AuthChal", "Auth challenge sent for %s - nc %d", p->username, p->noncecount);
- return send_response(p, &resp, reliable, seqno);
-}
-
-/*! \brief Add text body to SIP message */
-static int add_text(struct sip_request *req, const char *text)
-{
- /* XXX Convert \n's to \r\n's XXX */
- add_header(req, "Content-Type", "text/plain");
- add_header_contentLength(req, strlen(text));
- add_line(req, text);
- return 0;
-}
-
-/*! \brief Add DTMF INFO tone to sip message */
-/* Always adds default duration 250 ms, regardless of what came in over the line */
-static int add_digit(struct sip_request *req, char digit, unsigned int duration)
-{
- char tmp[256];
-
- snprintf(tmp, sizeof(tmp), "Signal=%c\r\nDuration=%u\r\n", digit, duration);
- add_header(req, "Content-Type", "application/dtmf-relay");
- add_header_contentLength(req, strlen(tmp));
- add_line(req, tmp);
- return 0;
-}
-
-/*! \brief add XML encoded media control with update
- \note XML: The only way to turn 0 bits of information into a few hundred. (markster) */
-static int add_vidupdate(struct sip_request *req)
-{
- const char *xml_is_a_huge_waste_of_space =
- "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\r\n"
- " <media_control>\r\n"
- " <vc_primitive>\r\n"
- " <to_encoder>\r\n"
- " <picture_fast_update>\r\n"
- " </picture_fast_update>\r\n"
- " </to_encoder>\r\n"
- " </vc_primitive>\r\n"
- " </media_control>\r\n";
- add_header(req, "Content-Type", "application/media_control+xml");
- add_header_contentLength(req, strlen(xml_is_a_huge_waste_of_space));
- add_line(req, xml_is_a_huge_waste_of_space);
- return 0;
-}
-
-/*! \brief Add codec offer to SDP offer/answer body in INVITE or 200 OK */
-static void add_codec_to_sdp(const struct sip_pvt *p, int codec, int sample_rate,
- char **m_buf, size_t *m_size, char **a_buf, size_t *a_size,
- int debug, int *min_packet_size)
-{
- int rtp_code;
- struct ast_format_list fmt;
-
-
- if (debug)
- ast_verbose("Adding codec 0x%x (%s) to SDP\n", codec, ast_getformatname(codec));
- if ((rtp_code = ast_rtp_lookup_code(p->rtp, 1, codec)) == -1)
- return;
-
- if (p->rtp) {
- struct ast_codec_pref *pref = ast_rtp_codec_getpref(p->rtp);
- fmt = ast_codec_pref_getsize(pref, codec);
- } else /* I dont see how you couldn't have p->rtp, but good to check for and error out if not there like earlier code */
- return;
- ast_build_string(m_buf, m_size, " %d", rtp_code);
- ast_build_string(a_buf, a_size, "a=rtpmap:%d %s/%d\r\n", rtp_code,
- ast_rtp_lookup_mime_subtype(1, codec,
- ast_test_flag(&p->flags[0], SIP_G726_NONSTANDARD) ? AST_RTP_OPT_G726_NONSTANDARD : 0),
- sample_rate);
- if (codec == AST_FORMAT_G729A) {
- /* Indicate that we don't support VAD (G.729 annex B) */
- ast_build_string(a_buf, a_size, "a=fmtp:%d annexb=no\r\n", rtp_code);
- } else if (codec == AST_FORMAT_G723_1) {
- /* Indicate that we don't support VAD (G.723.1 annex A) */
- ast_build_string(a_buf, a_size, "a=fmtp:%d annexa=no\r\n", rtp_code);
- } else if (codec == AST_FORMAT_ILBC) {
- /* Add information about us using only 20/30 ms packetization */
- ast_build_string(a_buf, a_size, "a=fmtp:%d mode=%d\r\n", rtp_code, fmt.cur_ms);
- }
-
- if (fmt.cur_ms && (fmt.cur_ms < *min_packet_size))
- *min_packet_size = fmt.cur_ms;
-
- /* Our first codec packetization processed cannot be less than zero */
- if ((*min_packet_size) == 0 && fmt.cur_ms)
- *min_packet_size = fmt.cur_ms;
-}
-
-/*! \brief Get Max T.38 Transmission rate from T38 capabilities */
-static int t38_get_rate(int t38cap)
-{
- int maxrate = (t38cap & (T38FAX_RATE_14400 | T38FAX_RATE_12000 | T38FAX_RATE_9600 | T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400));
-
- if (maxrate & T38FAX_RATE_14400) {
- if (option_debug > 1)
- ast_log(LOG_DEBUG, "T38MaxBitRate 14400 found\n");
- return 14400;
- } else if (maxrate & T38FAX_RATE_12000) {
- if (option_debug > 1)
- ast_log(LOG_DEBUG, "T38MaxBitRate 12000 found\n");
- return 12000;
- } else if (maxrate & T38FAX_RATE_9600) {
- if (option_debug > 1)
- ast_log(LOG_DEBUG, "T38MaxBitRate 9600 found\n");
- return 9600;
- } else if (maxrate & T38FAX_RATE_7200) {
- if (option_debug > 1)
- ast_log(LOG_DEBUG, "T38MaxBitRate 7200 found\n");
- return 7200;
- } else if (maxrate & T38FAX_RATE_4800) {
- if (option_debug > 1)
- ast_log(LOG_DEBUG, "T38MaxBitRate 4800 found\n");
- return 4800;
- } else if (maxrate & T38FAX_RATE_2400) {
- if (option_debug > 1)
- ast_log(LOG_DEBUG, "T38MaxBitRate 2400 found\n");
- return 2400;
- } else {
- if (option_debug > 1)
- ast_log(LOG_DEBUG, "Strange, T38MaxBitRate NOT found in peers T38 SDP.\n");
- return 0;
- }
-}
-
-/*! \brief Add T.38 Session Description Protocol message */
-static int add_t38_sdp(struct sip_request *resp, struct sip_pvt *p)
-{
- int len = 0;
- int x = 0;
- struct sockaddr_in udptlsin;
- char v[256] = "";
- char s[256] = "";
- char o[256] = "";
- char c[256] = "";
- char t[256] = "";
- char m_modem[256];
- char a_modem[1024];
- char *m_modem_next = m_modem;
- size_t m_modem_left = sizeof(m_modem);
- char *a_modem_next = a_modem;
- size_t a_modem_left = sizeof(a_modem);
- struct sockaddr_in udptldest = { 0, };
- int debug;
-
- debug = sip_debug_test_pvt(p);
- len = 0;
- if (!p->udptl) {
- ast_log(LOG_WARNING, "No way to add SDP without an UDPTL structure\n");
- return -1;
- }
-
- if (!p->sessionid) {
- p->sessionid = getpid();
- p->sessionversion = p->sessionid;
- } else
- p->sessionversion++;
-
- /* Our T.38 end is */
- ast_udptl_get_us(p->udptl, &udptlsin);
-
- /* Determine T.38 UDPTL destination */
- if (p->udptlredirip.sin_addr.s_addr) {
- udptldest.sin_port = p->udptlredirip.sin_port;
- udptldest.sin_addr = p->udptlredirip.sin_addr;
- } else {
- udptldest.sin_addr = p->ourip;
- udptldest.sin_port = udptlsin.sin_port;
- }
-
- if (debug)
- ast_log(LOG_DEBUG, "T.38 UDPTL is at %s port %d\n", ast_inet_ntoa(p->ourip), ntohs(udptlsin.sin_port));
-
- /* We break with the "recommendation" and send our IP, in order that our
- peer doesn't have to ast_gethostbyname() us */
-
- if (debug) {
- ast_log(LOG_DEBUG, "Our T38 capability (%d), peer T38 capability (%d), joint capability (%d)\n",
- p->t38.capability,
- p->t38.peercapability,
- p->t38.jointcapability);
- }
- snprintf(v, sizeof(v), "v=0\r\n");
- snprintf(o, sizeof(o), "o=root %d %d IN IP4 %s\r\n", p->sessionid, p->sessionversion, ast_inet_ntoa(udptldest.sin_addr));
- snprintf(s, sizeof(s), "s=session\r\n");
- snprintf(c, sizeof(c), "c=IN IP4 %s\r\n", ast_inet_ntoa(udptldest.sin_addr));
- snprintf(t, sizeof(t), "t=0 0\r\n");
- ast_build_string(&m_modem_next, &m_modem_left, "m=image %d udptl t38\r\n", ntohs(udptldest.sin_port));
-
- if ((p->t38.jointcapability & T38FAX_VERSION) == T38FAX_VERSION_0)
- ast_build_string(&a_modem_next, &a_modem_left, "a=T38FaxVersion:0\r\n");
- if ((p->t38.jointcapability & T38FAX_VERSION) == T38FAX_VERSION_1)
- ast_build_string(&a_modem_next, &a_modem_left, "a=T38FaxVersion:1\r\n");
- if ((x = t38_get_rate(p->t38.jointcapability)))
- ast_build_string(&a_modem_next, &a_modem_left, "a=T38MaxBitRate:%d\r\n",x);
- if ((p->t38.jointcapability & T38FAX_FILL_BIT_REMOVAL) == T38FAX_FILL_BIT_REMOVAL)
- ast_build_string(&a_modem_next, &a_modem_left, "a=T38FaxFillBitRemoval\r\n");
- if ((p->t38.jointcapability & T38FAX_TRANSCODING_MMR) == T38FAX_TRANSCODING_MMR)
- ast_build_string(&a_modem_next, &a_modem_left, "a=T38FaxTranscodingMMR\r\n");
- if ((p->t38.jointcapability & T38FAX_TRANSCODING_JBIG) == T38FAX_TRANSCODING_JBIG)
- ast_build_string(&a_modem_next, &a_modem_left, "a=T38FaxTranscodingJBIG\r\n");
- ast_build_string(&a_modem_next, &a_modem_left, "a=T38FaxRateManagement:%s\r\n", (p->t38.jointcapability & T38FAX_RATE_MANAGEMENT_LOCAL_TCF) ? "localTCF" : "transferredTCF");
- x = ast_udptl_get_local_max_datagram(p->udptl);
- ast_build_string(&a_modem_next, &a_modem_left, "a=T38FaxMaxBuffer:%d\r\n",x);
- ast_build_string(&a_modem_next, &a_modem_left, "a=T38FaxMaxDatagram:%d\r\n",x);
- if (p->t38.jointcapability != T38FAX_UDP_EC_NONE)
- ast_build_string(&a_modem_next, &a_modem_left, "a=T38FaxUdpEC:%s\r\n", (p->t38.jointcapability & T38FAX_UDP_EC_REDUNDANCY) ? "t38UDPRedundancy" : "t38UDPFEC");
- len = strlen(v) + strlen(s) + strlen(o) + strlen(c) + strlen(t) + strlen(m_modem) + strlen(a_modem);
- add_header(resp, "Content-Type", "application/sdp");
- add_header_contentLength(resp, len);
- add_line(resp, v);
- add_line(resp, o);
- add_line(resp, s);
- add_line(resp, c);
- add_line(resp, t);
- add_line(resp, m_modem);
- add_line(resp, a_modem);
-
- /* Update lastrtprx when we send our SDP */
- p->lastrtprx = p->lastrtptx = time(NULL);
-
- return 0;
-}
-
-
-/*! \brief Add RFC 2833 DTMF offer to SDP */
-static void add_noncodec_to_sdp(const struct sip_pvt *p, int format, int sample_rate,
- char **m_buf, size_t *m_size, char **a_buf, size_t *a_size,
- int debug)
-{
- int rtp_code;
-
- if (debug)
- ast_verbose("Adding non-codec 0x%x (%s) to SDP\n", format, ast_rtp_lookup_mime_subtype(0, format, 0));
- if ((rtp_code = ast_rtp_lookup_code(p->rtp, 0, format)) == -1)
- return;
-
- ast_build_string(m_buf, m_size, " %d", rtp_code);
- ast_build_string(a_buf, a_size, "a=rtpmap:%d %s/%d\r\n", rtp_code,
- ast_rtp_lookup_mime_subtype(0, format, 0),
- sample_rate);
- if (format == AST_RTP_DTMF)
- /* Indicate we support DTMF and FLASH... */
- ast_build_string(a_buf, a_size, "a=fmtp:%d 0-16\r\n", rtp_code);
-}
-
-/*!
- * \note G.722 actually is supposed to specified as 8 kHz, even though it is
- * really 16 kHz. Update this macro for other formats as they are added in
- * the future.
- */
-#define SDP_SAMPLE_RATE(x) 8000
-
-/*! \brief Add Session Description Protocol message */
-static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p)
-{
- int len = 0;
- int alreadysent = 0;
-
- struct sockaddr_in sin;
- struct sockaddr_in vsin;
- struct sockaddr_in dest;
- struct sockaddr_in vdest = { 0, };
-
- /* SDP fields */
- char *version = "v=0\r\n"; /* Protocol version */
- char *subject = "s=session\r\n"; /* Subject of the session */
- char owner[256]; /* Session owner/creator */
- char connection[256]; /* Connection data */
- char *stime = "t=0 0\r\n"; /* Time the session is active */
- char bandwidth[256] = ""; /* Max bitrate */
- char *hold;
- char m_audio[256]; /* Media declaration line for audio */
- char m_video[256]; /* Media declaration line for video */
- char a_audio[1024]; /* Attributes for audio */
- char a_video[1024]; /* Attributes for video */
- char *m_audio_next = m_audio;
- char *m_video_next = m_video;
- size_t m_audio_left = sizeof(m_audio);
- size_t m_video_left = sizeof(m_video);
- char *a_audio_next = a_audio;
- char *a_video_next = a_video;
- size_t a_audio_left = sizeof(a_audio);
- size_t a_video_left = sizeof(a_video);
-
- int x;
- int capability;
- int needvideo = FALSE;
- int debug = sip_debug_test_pvt(p);
- int min_audio_packet_size = 0;
- int min_video_packet_size = 0;
-
- m_video[0] = '\0'; /* Reset the video media string if it's not needed */
-
- if (!p->rtp) {
- ast_log(LOG_WARNING, "No way to add SDP without an RTP structure\n");
- return AST_FAILURE;
- }
-
- /* Set RTP Session ID and version */
- if (!p->sessionid) {
- p->sessionid = getpid();
- p->sessionversion = p->sessionid;
- } else
- p->sessionversion++;
-
- /* Get our addresses */
- ast_rtp_get_us(p->rtp, &sin);
- if (p->vrtp)
- ast_rtp_get_us(p->vrtp, &vsin);
-
- /* Is this a re-invite to move the media out, then use the original offer from caller */
- if (p->redirip.sin_addr.s_addr) {
- dest.sin_port = p->redirip.sin_port;
- dest.sin_addr = p->redirip.sin_addr;
- } else {
- dest.sin_addr = p->ourip;
- dest.sin_port = sin.sin_port;
- }
-
- capability = p->jointcapability;
-
-
- if (option_debug > 1) {
- char codecbuf[SIPBUFSIZE];
- ast_log(LOG_DEBUG, "** Our capability: %s Video flag: %s\n", ast_getformatname_multiple(codecbuf, sizeof(codecbuf), capability), ast_test_flag(&p->flags[0], SIP_NOVIDEO) ? "True" : "False");
- ast_log(LOG_DEBUG, "** Our prefcodec: %s \n", ast_getformatname_multiple(codecbuf, sizeof(codecbuf), p->prefcodec));
- }
-
-#ifdef WHEN_WE_HAVE_T38_FOR_OTHER_TRANSPORTS
- if (ast_test_flag(&p->t38.t38support, SIP_PAGE2_T38SUPPORT_RTP)) {
- ast_build_string(&m_audio_next, &m_audio_left, " %d", 191);
- ast_build_string(&a_audio_next, &a_audio_left, "a=rtpmap:%d %s/%d\r\n", 191, "t38", 8000);
- }
-#endif
-
- /* Check if we need video in this call */
- if ((capability & AST_FORMAT_VIDEO_MASK) && !ast_test_flag(&p->flags[0], SIP_NOVIDEO)) {
- if (p->vrtp) {
- needvideo = TRUE;
- if (option_debug > 1)
- ast_log(LOG_DEBUG, "This call needs video offers!\n");
- } else if (option_debug > 1)
- ast_log(LOG_DEBUG, "This call needs video offers, but there's no video support enabled!\n");
- }
-
-
- /* Ok, we need video. Let's add what we need for video and set codecs.
- Video is handled differently than audio since we can not transcode. */
- if (needvideo) {
- /* Determine video destination */
- if (p->vredirip.sin_addr.s_addr) {
- vdest.sin_addr = p->vredirip.sin_addr;
- vdest.sin_port = p->vredirip.sin_port;
- } else {
- vdest.sin_addr = p->ourip;
- vdest.sin_port = vsin.sin_port;
- }
- ast_build_string(&m_video_next, &m_video_left, "m=video %d RTP/AVP", ntohs(vdest.sin_port));
-
- /* Build max bitrate string */
- if (p->maxcallbitrate)
- snprintf(bandwidth, sizeof(bandwidth), "b=CT:%d\r\n", p->maxcallbitrate);
- if (debug)
- ast_verbose("Video is at %s port %d\n", ast_inet_ntoa(p->ourip), ntohs(vsin.sin_port));
- }
-
- if (debug)
- ast_verbose("Audio is at %s port %d\n", ast_inet_ntoa(p->ourip), ntohs(sin.sin_port));
-
- /* Start building generic SDP headers */
-
- /* We break with the "recommendation" and send our IP, in order that our
- peer doesn't have to ast_gethostbyname() us */
-
- snprintf(owner, sizeof(owner), "o=root %d %d IN IP4 %s\r\n", p->sessionid, p->sessionversion, ast_inet_ntoa(dest.sin_addr));
- snprintf(connection, sizeof(connection), "c=IN IP4 %s\r\n", ast_inet_ntoa(dest.sin_addr));
- ast_build_string(&m_audio_next, &m_audio_left, "m=audio %d RTP/AVP", ntohs(dest.sin_port));
-
- if (ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD) == SIP_PAGE2_CALL_ONHOLD_ONEDIR)
- hold = "a=recvonly\r\n";
- else if (ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD) == SIP_PAGE2_CALL_ONHOLD_INACTIVE)
- hold = "a=inactive\r\n";
- else
- hold = "a=sendrecv\r\n";
-
- /* Now, start adding audio codecs. These are added in this order:
- - First what was requested by the calling channel
- - Then preferences in order from sip.conf device config for this peer/user
- - Then other codecs in capabilities, including video
- */
-
- /* Prefer the audio codec we were requested to use, first, no matter what
- Note that p->prefcodec can include video codecs, so mask them out
- */
- if (capability & p->prefcodec) {
- int codec = p->prefcodec & AST_FORMAT_AUDIO_MASK;
-
- add_codec_to_sdp(p, codec, SDP_SAMPLE_RATE(codec),
- &m_audio_next, &m_audio_left,
- &a_audio_next, &a_audio_left,
- debug, &min_audio_packet_size);
- alreadysent |= codec;
- }
-
- /* Start by sending our preferred audio codecs */
- for (x = 0; x < 32; x++) {
- int codec;
-
- if (!(codec = ast_codec_pref_index(&p->prefs, x)))
- break;
-
- if (!(capability & codec))
- continue;
-
- if (alreadysent & codec)
- continue;
-
- add_codec_to_sdp(p, codec, SDP_SAMPLE_RATE(codec),
- &m_audio_next, &m_audio_left,
- &a_audio_next, &a_audio_left,
- debug, &min_audio_packet_size);
- alreadysent |= codec;
- }
-
- /* Now send any other common audio and video codecs, and non-codec formats: */
- for (x = 1; x <= (needvideo ? AST_FORMAT_MAX_VIDEO : AST_FORMAT_MAX_AUDIO); x <<= 1) {
- if (!(capability & x)) /* Codec not requested */
- continue;
-
- if (alreadysent & x) /* Already added to SDP */
- continue;
-
- if (x <= AST_FORMAT_MAX_AUDIO)
- add_codec_to_sdp(p, x, SDP_SAMPLE_RATE(x),
- &m_audio_next, &m_audio_left,
- &a_audio_next, &a_audio_left,
- debug, &min_audio_packet_size);
- else
- add_codec_to_sdp(p, x, 90000,
- &m_video_next, &m_video_left,
- &a_video_next, &a_video_left,
- debug, &min_video_packet_size);
- }
-
- /* Now add DTMF RFC2833 telephony-event as a codec */
- for (x = 1; x <= AST_RTP_MAX; x <<= 1) {
- if (!(p->jointnoncodeccapability & x))
- continue;
-
- add_noncodec_to_sdp(p, x, 8000,
- &m_audio_next, &m_audio_left,
- &a_audio_next, &a_audio_left,
- debug);
- }
-
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "-- Done with adding codecs to SDP\n");
-
- if (!p->owner || !ast_internal_timing_enabled(p->owner))
- ast_build_string(&a_audio_next, &a_audio_left, "a=silenceSupp:off - - - -\r\n");
-
- if (min_audio_packet_size)
- ast_build_string(&a_audio_next, &a_audio_left, "a=ptime:%d\r\n", min_audio_packet_size);
-
- if (min_video_packet_size)
- ast_build_string(&a_video_next, &a_video_left, "a=ptime:%d\r\n", min_video_packet_size);
-
- if ((m_audio_left < 2) || (m_video_left < 2) || (a_audio_left == 0) || (a_video_left == 0))
- ast_log(LOG_WARNING, "SIP SDP may be truncated due to undersized buffer!!\n");
-
- ast_build_string(&m_audio_next, &m_audio_left, "\r\n");
- if (needvideo)
- ast_build_string(&m_video_next, &m_video_left, "\r\n");
-
- len = strlen(version) + strlen(subject) + strlen(owner) + strlen(connection) + strlen(stime) + strlen(m_audio) + strlen(a_audio) + strlen(hold);
- if (needvideo) /* only if video response is appropriate */
- len += strlen(m_video) + strlen(a_video) + strlen(bandwidth) + strlen(hold);
-
- add_header(resp, "Content-Type", "application/sdp");
- add_header_contentLength(resp, len);
- add_line(resp, version);
- add_line(resp, owner);
- add_line(resp, subject);
- add_line(resp, connection);
- if (needvideo) /* only if video response is appropriate */
- add_line(resp, bandwidth);
- add_line(resp, stime);
- add_line(resp, m_audio);
- add_line(resp, a_audio);
- add_line(resp, hold);
- if (needvideo) { /* only if video response is appropriate */
- add_line(resp, m_video);
- add_line(resp, a_video);
- add_line(resp, hold); /* Repeat hold for the video stream */
- }
-
- /* Update lastrtprx when we send our SDP */
- p->lastrtprx = p->lastrtptx = time(NULL); /* XXX why both ? */
-
- if (option_debug > 2) {
- char buf[SIPBUFSIZE];
- ast_log(LOG_DEBUG, "Done building SDP. Settling with this capability: %s\n", ast_getformatname_multiple(buf, SIPBUFSIZE, capability));
- }
-
- return AST_SUCCESS;
-}
-
-/*! \brief Used for 200 OK and 183 early media */
-static int transmit_response_with_t38_sdp(struct sip_pvt *p, char *msg, struct sip_request *req, int retrans)
-{
- struct sip_request resp;
- int seqno;
-
- if (sscanf(get_header(req, "CSeq"), "%d ", &seqno) != 1) {
- ast_log(LOG_WARNING, "Unable to get seqno from '%s'\n", get_header(req, "CSeq"));
- return -1;
- }
- respprep(&resp, p, msg, req);
- if (p->udptl) {
- ast_udptl_offered_from_local(p->udptl, 0);
- add_t38_sdp(&resp, p);
- } else
- ast_log(LOG_ERROR, "Can't add SDP to response, since we have no UDPTL session allocated. Call-ID %s\n", p->callid);
- if (retrans && !p->pendinginvite)
- p->pendinginvite = seqno; /* Buggy clients sends ACK on RINGING too */
- return send_response(p, &resp, retrans, seqno);
-}
-
-/*! \brief copy SIP request (mostly used to save request for responses) */
-static void copy_request(struct sip_request *dst, const struct sip_request *src)
-{
- long offset;
- int x;
- offset = ((void *)dst) - ((void *)src);
- /* First copy stuff */
- memcpy(dst, src, sizeof(*dst));
- /* Now fix pointer arithmetic */
- for (x=0; x < src->headers; x++)
- dst->header[x] += offset;
- for (x=0; x < src->lines; x++)
- dst->line[x] += offset;
- dst->rlPart1 += offset;
- dst->rlPart2 += offset;
-}
-
-/*! \brief Used for 200 OK and 183 early media
- \return Will return XMIT_ERROR for network errors.
-*/
-static int transmit_response_with_sdp(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable)
-{
- struct sip_request resp;
- int seqno;
- if (sscanf(get_header(req, "CSeq"), "%d ", &seqno) != 1) {
- ast_log(LOG_WARNING, "Unable to get seqno from '%s'\n", get_header(req, "CSeq"));
- return -1;
- }
- respprep(&resp, p, msg, req);
- if (p->rtp) {
- if (!p->autoframing && !ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Setting framing from config on incoming call\n");
- ast_rtp_codec_setpref(p->rtp, &p->prefs);
- }
- try_suggested_sip_codec(p);
- add_sdp(&resp, p);
- } else
- ast_log(LOG_ERROR, "Can't add SDP to response, since we have no RTP session allocated. Call-ID %s\n", p->callid);
- if (reliable && !p->pendinginvite)
- p->pendinginvite = seqno; /* Buggy clients sends ACK on RINGING too */
- return send_response(p, &resp, reliable, seqno);
-}
-
-/*! \brief Parse first line of incoming SIP request */
-static int determine_firstline_parts(struct sip_request *req)
-{
- char *e = ast_skip_blanks(req->header[0]); /* there shouldn't be any */
-
- if (!*e)
- return -1;
- req->rlPart1 = e; /* method or protocol */
- e = ast_skip_nonblanks(e);
- if (*e)
- *e++ = '\0';
- /* Get URI or status code */
- e = ast_skip_blanks(e);
- if ( !*e )
- return -1;
- ast_trim_blanks(e);
-
- if (!strcasecmp(req->rlPart1, "SIP/2.0") ) { /* We have a response */
- if (strlen(e) < 3) /* status code is 3 digits */
- return -1;
- req->rlPart2 = e;
- } else { /* We have a request */
- if ( *e == '<' ) { /* XXX the spec says it must not be in <> ! */
- ast_log(LOG_WARNING, "bogus uri in <> %s\n", e);
- e++;
- if (!*e)
- return -1;
- }
- req->rlPart2 = e; /* URI */
- e = ast_skip_nonblanks(e);
- if (*e)
- *e++ = '\0';
- e = ast_skip_blanks(e);
- if (strcasecmp(e, "SIP/2.0") ) {
- ast_log(LOG_WARNING, "Bad request protocol %s\n", e);
- return -1;
- }
- }
- return 1;
-}
-
-/*! \brief Transmit reinvite with SDP
-\note A re-invite is basically a new INVITE with the same CALL-ID and TAG as the
- INVITE that opened the SIP dialogue
- We reinvite so that the audio stream (RTP) go directly between
- the SIP UAs. SIP Signalling stays with * in the path.
-*/
-static int transmit_reinvite_with_sdp(struct sip_pvt *p)
-{
- struct sip_request req;
-
- reqprep(&req, p, ast_test_flag(&p->flags[0], SIP_REINVITE_UPDATE) ? SIP_UPDATE : SIP_INVITE, 0, 1);
-
- add_header(&req, "Allow", ALLOWED_METHODS);
- add_header(&req, "Supported", SUPPORTED_EXTENSIONS);
- if (sipdebug)
- add_header(&req, "X-asterisk-Info", "SIP re-invite (External RTP bridge)");
- if (!ast_test_flag(&p->flags[0], SIP_NO_HISTORY))
- append_history(p, "ReInv", "Re-invite sent");
- add_sdp(&req, p);
- /* Use this as the basis */
- initialize_initreq(p, &req);
- p->lastinvite = p->ocseq;
- ast_set_flag(&p->flags[0], SIP_OUTGOING); /* Change direction of this dialog */
- return send_request(p, &req, XMIT_CRITICAL, p->ocseq);
-}
-
-/*! \brief Transmit reinvite with T38 SDP
- We reinvite so that the T38 processing can take place.
- SIP Signalling stays with * in the path.
-*/
-static int transmit_reinvite_with_t38_sdp(struct sip_pvt *p)
-{
- struct sip_request req;
-
- reqprep(&req, p, ast_test_flag(&p->flags[0], SIP_REINVITE_UPDATE) ? SIP_UPDATE : SIP_INVITE, 0, 1);
-
- add_header(&req, "Allow", ALLOWED_METHODS);
- add_header(&req, "Supported", SUPPORTED_EXTENSIONS);
- if (sipdebug)
- add_header(&req, "X-asterisk-info", "SIP re-invite (T38 switchover)");
- ast_udptl_offered_from_local(p->udptl, 1);
- add_t38_sdp(&req, p);
- /* Use this as the basis */
- initialize_initreq(p, &req);
- ast_set_flag(&p->flags[0], SIP_OUTGOING); /* Change direction of this dialog */
- p->lastinvite = p->ocseq;
- return send_request(p, &req, XMIT_CRITICAL, p->ocseq);
-}
-
-/*! \brief Check Contact: URI of SIP message */
-static void extract_uri(struct sip_pvt *p, struct sip_request *req)
-{
- char stripped[SIPBUFSIZE];
- char *c;
-
- ast_copy_string(stripped, get_header(req, "Contact"), sizeof(stripped));
- c = get_in_brackets(stripped);
- c = strsep(&c, ";"); /* trim ; and beyond */
- if (!ast_strlen_zero(c))
- ast_string_field_set(p, uri, c);
-}
-
-/*! \brief Build contact header - the contact header we send out */
-static void build_contact(struct sip_pvt *p)
-{
- /* Construct Contact: header */
- if (ourport != STANDARD_SIP_PORT)
- ast_string_field_build(p, our_contact, "<sip:%s%s%s:%d>", p->exten, ast_strlen_zero(p->exten) ? "" : "@", ast_inet_ntoa(p->ourip), ourport);
- else
- ast_string_field_build(p, our_contact, "<sip:%s%s%s>", p->exten, ast_strlen_zero(p->exten) ? "" : "@", ast_inet_ntoa(p->ourip));
-}
-
-/*! \brief Build the Remote Party-ID & From using callingpres options */
-static void build_rpid(struct sip_pvt *p)
-{
- int send_pres_tags = TRUE;
- const char *privacy=NULL;
- const char *screen=NULL;
- char buf[256];
- const char *clid = default_callerid;
- const char *clin = NULL;
- const char *fromdomain;
-
- if (!ast_strlen_zero(p->rpid) || !ast_strlen_zero(p->rpid_from))
- return;
-
- if (p->owner && p->owner->cid.cid_num)
- clid = p->owner->cid.cid_num;
- if (p->owner && p->owner->cid.cid_name)
- clin = p->owner->cid.cid_name;
- if (ast_strlen_zero(clin))
- clin = clid;
-
- switch (p->callingpres) {
- case AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED:
- privacy = "off";
- screen = "no";
- break;
- case AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN:
- privacy = "off";
- screen = "yes";
- break;
- case AST_PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN:
- privacy = "off";
- screen = "no";
- break;
- case AST_PRES_ALLOWED_NETWORK_NUMBER:
- privacy = "off";
- screen = "yes";
- break;
- case AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED:
- privacy = "full";
- screen = "no";
- break;
- case AST_PRES_PROHIB_USER_NUMBER_PASSED_SCREEN:
- privacy = "full";
- screen = "yes";
- break;
- case AST_PRES_PROHIB_USER_NUMBER_FAILED_SCREEN:
- privacy = "full";
- screen = "no";
- break;
- case AST_PRES_PROHIB_NETWORK_NUMBER:
- privacy = "full";
- screen = "yes";
- break;
- case AST_PRES_NUMBER_NOT_AVAILABLE:
- send_pres_tags = FALSE;
- break;
- default:
- ast_log(LOG_WARNING, "Unsupported callingpres (%d)\n", p->callingpres);
- if ((p->callingpres & AST_PRES_RESTRICTION) != AST_PRES_ALLOWED)
- privacy = "full";
- else
- privacy = "off";
- screen = "no";
- break;
- }
-
- fromdomain = S_OR(p->fromdomain, ast_inet_ntoa(p->ourip));
-
- snprintf(buf, sizeof(buf), "\"%s\" <sip:%s@%s>", clin, clid, fromdomain);
- if (send_pres_tags)
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ";privacy=%s;screen=%s", privacy, screen);
- ast_string_field_set(p, rpid, buf);
-
- ast_string_field_build(p, rpid_from, "\"%s\" <sip:%s@%s>;tag=%s", clin,
- S_OR(p->fromuser, clid),
- fromdomain, p->tag);
-}
-
-/*! \brief Initiate new SIP request to peer/user */
-static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmethod)
-{
- char invite_buf[256] = "";
- char *invite = invite_buf;
- size_t invite_max = sizeof(invite_buf);
- char from[256];
- char to[256];
- char tmp[SIPBUFSIZE/2];
- char tmp2[SIPBUFSIZE/2];
- const char *l = NULL, *n = NULL;
- const char *urioptions = "";
-
- if (ast_test_flag(&p->flags[0], SIP_USEREQPHONE)) {
- const char *s = p->username; /* being a string field, cannot be NULL */
-
- /* Test p->username against allowed characters in AST_DIGIT_ANY
- If it matches the allowed characters list, then sipuser = ";user=phone"
- If not, then sipuser = ""
- */
- /* + is allowed in first position in a tel: uri */
- if (*s == '+')
- s++;
- for (; *s; s++) {
- if (!strchr(AST_DIGIT_ANYNUM, *s) )
- break;
- }
- /* If we have only digits, add ;user=phone to the uri */
- if (!*s)
- urioptions = ";user=phone";
- }
-
-
- snprintf(p->lastmsg, sizeof(p->lastmsg), "Init: %s", sip_methods[sipmethod].text);
-
- if (p->owner) {
- l = p->owner->cid.cid_num;
- n = p->owner->cid.cid_name;
- }
- /* if we are not sending RPID and user wants his callerid restricted */
- if (!ast_test_flag(&p->flags[0], SIP_SENDRPID) &&
- ((p->callingpres & AST_PRES_RESTRICTION) != AST_PRES_ALLOWED)) {
- l = CALLERID_UNKNOWN;
- n = l;
- }
- if (ast_strlen_zero(l))
- l = default_callerid;
- if (ast_strlen_zero(n))
- n = l;
- /* Allow user to be overridden */
- if (!ast_strlen_zero(p->fromuser))
- l = p->fromuser;
- else /* Save for any further attempts */
- ast_string_field_set(p, fromuser, l);
-
- /* Allow user to be overridden */
- if (!ast_strlen_zero(p->fromname))
- n = p->fromname;
- else /* Save for any further attempts */
- ast_string_field_set(p, fromname, n);
-
- if (pedanticsipchecking) {
- ast_uri_encode(n, tmp, sizeof(tmp), 0);
- n = tmp;
- ast_uri_encode(l, tmp2, sizeof(tmp2), 0);
- l = tmp2;
- }
-
- if (ourport != STANDARD_SIP_PORT && ast_strlen_zero(p->fromdomain))
- snprintf(from, sizeof(from), "\"%s\" <sip:%s@%s:%d>;tag=%s", n, l, S_OR(p->fromdomain, ast_inet_ntoa(p->ourip)), ourport, p->tag);
- else
- snprintf(from, sizeof(from), "\"%s\" <sip:%s@%s>;tag=%s", n, l, S_OR(p->fromdomain, ast_inet_ntoa(p->ourip)), p->tag);
-
- /* If we're calling a registered SIP peer, use the fullcontact to dial to the peer */
- if (!ast_strlen_zero(p->fullcontact)) {
- /* If we have full contact, trust it */
- ast_build_string(&invite, &invite_max, "%s", p->fullcontact);
- } else {
- /* Otherwise, use the username while waiting for registration */
- ast_build_string(&invite, &invite_max, "sip:");
- if (!ast_strlen_zero(p->username)) {
- n = p->username;
- if (pedanticsipchecking) {
- ast_uri_encode(n, tmp, sizeof(tmp), 0);
- n = tmp;
- }
- ast_build_string(&invite, &invite_max, "%s@", n);
- }
- ast_build_string(&invite, &invite_max, "%s", p->tohost);
- if (ntohs(p->sa.sin_port) != STANDARD_SIP_PORT)
- ast_build_string(&invite, &invite_max, ":%d", ntohs(p->sa.sin_port));
- ast_build_string(&invite, &invite_max, "%s", urioptions);
- }
-
- /* If custom URI options have been provided, append them */
- if (p->options && !ast_strlen_zero(p->options->uri_options))
- ast_build_string(&invite, &invite_max, ";%s", p->options->uri_options);
-
- ast_string_field_set(p, uri, invite_buf);
-
- if (sipmethod == SIP_NOTIFY && !ast_strlen_zero(p->theirtag)) {
- /* If this is a NOTIFY, use the From: tag in the subscribe (RFC 3265) */
- snprintf(to, sizeof(to), "<%s%s>;tag=%s", (!strncasecmp(p->uri, "sip:", 4) ? "" : "sip:"), p->uri, p->theirtag);
- } else if (p->options && p->options->vxml_url) {
- /* If there is a VXML URL append it to the SIP URL */
- snprintf(to, sizeof(to), "<%s>;%s", p->uri, p->options->vxml_url);
- } else
- snprintf(to, sizeof(to), "<%s>", p->uri);
-
- init_req(req, sipmethod, p->uri);
- snprintf(tmp, sizeof(tmp), "%d %s", ++p->ocseq, sip_methods[sipmethod].text);
-
- add_header(req, "Via", p->via);
- /* SLD: FIXME?: do Route: here too? I think not cos this is the first request.
- * OTOH, then we won't have anything in p->route anyway */
- /* Build Remote Party-ID and From */
- if (ast_test_flag(&p->flags[0], SIP_SENDRPID) && (sipmethod == SIP_INVITE)) {
- build_rpid(p);
- add_header(req, "From", p->rpid_from);
- } else
- add_header(req, "From", from);
- add_header(req, "To", to);
- ast_string_field_set(p, exten, l);
- build_contact(p);
- add_header(req, "Contact", p->our_contact);
- add_header(req, "Call-ID", p->callid);
- add_header(req, "CSeq", tmp);
- if (!ast_strlen_zero(global_useragent))
- add_header(req, "User-Agent", global_useragent);
- add_header(req, "Max-Forwards", DEFAULT_MAX_FORWARDS);
- if (!ast_strlen_zero(p->rpid))
- add_header(req, "Remote-Party-ID", p->rpid);
-}
-
-/*! \brief Build REFER/INVITE/OPTIONS message and transmit it */
-static int transmit_invite(struct sip_pvt *p, int sipmethod, int sdp, int init)
-{
- struct sip_request req;
-
- req.method = sipmethod;
- if (init) { /* Seems like init always is 2 */
- /* Bump branch even on initial requests */
- p->branch ^= ast_random();
- p->invite_branch = p->branch;
- build_via(p);
- if (init > 1)
- initreqprep(&req, p, sipmethod);
- else
- reqprep(&req, p, sipmethod, 0, 1);
- } else
- reqprep(&req, p, sipmethod, 0, 1);
-
- if (p->options && p->options->auth)
- add_header(&req, p->options->authheader, p->options->auth);
- append_date(&req);
- if (sipmethod == SIP_REFER) { /* Call transfer */
- if (p->refer) {
- char buf[SIPBUFSIZE];
- if (!ast_strlen_zero(p->refer->refer_to))
- add_header(&req, "Refer-To", p->refer->refer_to);
- if (!ast_strlen_zero(p->refer->referred_by)) {
- snprintf(buf, sizeof(buf), "%s <%s>", p->refer->referred_by_name, p->refer->referred_by);
- add_header(&req, "Referred-By", buf);
- }
- }
- }
- /* This new INVITE is part of an attended transfer. Make sure that the
- other end knows and replace the current call with this new call */
- if (p->options && p->options->replaces && !ast_strlen_zero(p->options->replaces)) {
- add_header(&req, "Replaces", p->options->replaces);
- add_header(&req, "Require", "replaces");
- }
-
- add_header(&req, "Allow", ALLOWED_METHODS);
- add_header(&req, "Supported", SUPPORTED_EXTENSIONS);
- if (p->options && p->options->addsipheaders && p->owner) {
- struct ast_channel *chan = p->owner; /* The owner channel */
- struct varshead *headp;
-
- ast_channel_lock(chan);
-
- headp = &chan->varshead;
-
- if (!headp)
- ast_log(LOG_WARNING,"No Headp for the channel...ooops!\n");
- else {
- const struct ast_var_t *current;
- AST_LIST_TRAVERSE(headp, current, entries) {
- /* SIPADDHEADER: Add SIP header to outgoing call */
- if (!strncasecmp(ast_var_name(current), "SIPADDHEADER", strlen("SIPADDHEADER"))) {
- char *content, *end;
- const char *header = ast_var_value(current);
- char *headdup = ast_strdupa(header);
-
- /* Strip of the starting " (if it's there) */
- if (*headdup == '"')
- headdup++;
- if ((content = strchr(headdup, ':'))) {
- *content++ = '\0';
- content = ast_skip_blanks(content); /* Skip white space */
- /* Strip the ending " (if it's there) */
- end = content + strlen(content) -1;
- if (*end == '"')
- *end = '\0';
-
- add_header(&req, headdup, content);
- if (sipdebug)
- ast_log(LOG_DEBUG, "Adding SIP Header \"%s\" with content :%s: \n", headdup, content);
- }
- }
- }
- }
-
- ast_channel_unlock(chan);
- }
- if (sdp) {
- if (p->udptl && (p->t38.state == T38_LOCAL_DIRECT || p->t38.state == T38_LOCAL_REINVITE)) {
- ast_udptl_offered_from_local(p->udptl, 1);
- if (option_debug)
- ast_log(LOG_DEBUG, "T38 is in state %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
- add_t38_sdp(&req, p);
- } else if (p->rtp)
- add_sdp(&req, p);
- } else {
- add_header_contentLength(&req, 0);
- }
-
- if (!p->initreq.headers || init > 2)
- initialize_initreq(p, &req);
- p->lastinvite = p->ocseq;
- return send_request(p, &req, init ? XMIT_CRITICAL : XMIT_RELIABLE, p->ocseq);
-}
-
-/*! \brief Used in the SUBSCRIBE notification subsystem */
-static int transmit_state_notify(struct sip_pvt *p, int state, int full, int timeout)
-{
- char tmp[4000], from[256], to[256];
- char *t = tmp, *c, *mfrom, *mto;
- size_t maxbytes = sizeof(tmp);
- struct sip_request req;
- char hint[AST_MAX_EXTENSION];
- char *statestring = "terminated";
- const struct cfsubscription_types *subscriptiontype;
- enum state { NOTIFY_OPEN, NOTIFY_INUSE, NOTIFY_CLOSED } local_state = NOTIFY_OPEN;
- char *pidfstate = "--";
- char *pidfnote= "Ready";
-
- memset(from, 0, sizeof(from));
- memset(to, 0, sizeof(to));
- memset(tmp, 0, sizeof(tmp));
-
- switch (state) {
- case (AST_EXTENSION_RINGING | AST_EXTENSION_INUSE):
- statestring = (global_notifyringing) ? "early" : "confirmed";
- local_state = NOTIFY_INUSE;
- pidfstate = "busy";
- pidfnote = "Ringing";
- break;
- case AST_EXTENSION_RINGING:
- statestring = "early";
- local_state = NOTIFY_INUSE;
- pidfstate = "busy";
- pidfnote = "Ringing";
- break;
- case AST_EXTENSION_INUSE:
- statestring = "confirmed";
- local_state = NOTIFY_INUSE;
- pidfstate = "busy";
- pidfnote = "On the phone";
- break;
- case AST_EXTENSION_BUSY:
- statestring = "confirmed";
- local_state = NOTIFY_CLOSED;
- pidfstate = "busy";
- pidfnote = "On the phone";
- break;
- case AST_EXTENSION_UNAVAILABLE:
- statestring = "terminated";
- local_state = NOTIFY_CLOSED;
- pidfstate = "away";
- pidfnote = "Unavailable";
- break;
- case AST_EXTENSION_ONHOLD:
- statestring = "confirmed";
- local_state = NOTIFY_CLOSED;
- pidfstate = "busy";
- pidfnote = "On Hold";
- break;
- case AST_EXTENSION_NOT_INUSE:
- default:
- /* Default setting */
- break;
- }
-
- subscriptiontype = find_subscription_type(p->subscribed);
-
- /* Check which device/devices we are watching and if they are registered */
- if (ast_get_hint(hint, sizeof(hint), NULL, 0, NULL, p->context, p->exten)) {
- char *hint2 = hint, *individual_hint = NULL;
- int hint_count = 0, unavailable_count = 0;
-
- while ((individual_hint = strsep(&hint2, "&"))) {
- hint_count++;
-
- if (ast_device_state(individual_hint) == AST_DEVICE_UNAVAILABLE)
- unavailable_count++;
- }
-
- /* If none of the hinted devices are registered, we will
- * override notification and show no availability.
- */
- if (hint_count > 0 && hint_count == unavailable_count) {
- local_state = NOTIFY_CLOSED;
- pidfstate = "away";
- pidfnote = "Not online";
- }
- }
-
- ast_copy_string(from, get_header(&p->initreq, "From"), sizeof(from));
- c = get_in_brackets(from);
- if (strncasecmp(c, "sip:", 4)) {
- ast_log(LOG_WARNING, "Huh? Not a SIP header (%s)?\n", c);
- return -1;
- }
- mfrom = strsep(&c, ";"); /* trim ; and beyond */
-
- ast_copy_string(to, get_header(&p->initreq, "To"), sizeof(to));
- c = get_in_brackets(to);
- if (strncasecmp(c, "sip:", 4)) {
- ast_log(LOG_WARNING, "Huh? Not a SIP header (%s)?\n", c);
- return -1;
- }
- mto = strsep(&c, ";"); /* trim ; and beyond */
-
- reqprep(&req, p, SIP_NOTIFY, 0, 1);
-
-
- add_header(&req, "Event", subscriptiontype->event);
- add_header(&req, "Content-Type", subscriptiontype->mediatype);
- switch(state) {
- case AST_EXTENSION_DEACTIVATED:
- if (timeout)
- add_header(&req, "Subscription-State", "terminated;reason=timeout");
- else {
- add_header(&req, "Subscription-State", "terminated;reason=probation");
- add_header(&req, "Retry-After", "60");
- }
- break;
- case AST_EXTENSION_REMOVED:
- add_header(&req, "Subscription-State", "terminated;reason=noresource");
- break;
- default:
- if (p->expiry)
- add_header(&req, "Subscription-State", "active");
- else /* Expired */
- add_header(&req, "Subscription-State", "terminated;reason=timeout");
- }
- switch (p->subscribed) {
- case XPIDF_XML:
- case CPIM_PIDF_XML:
- ast_build_string(&t, &maxbytes, "<?xml version=\"1.0\"?>\n");
- ast_build_string(&t, &maxbytes, "<!DOCTYPE presence PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n");
- ast_build_string(&t, &maxbytes, "<presence>\n");
- ast_build_string(&t, &maxbytes, "<presentity uri=\"%s;method=SUBSCRIBE\" />\n", mfrom);
- ast_build_string(&t, &maxbytes, "<atom id=\"%s\">\n", p->exten);
- ast_build_string(&t, &maxbytes, "<address uri=\"%s;user=ip\" priority=\"0.800000\">\n", mto);
- ast_build_string(&t, &maxbytes, "<status status=\"%s\" />\n", (local_state == NOTIFY_OPEN) ? "open" : (local_state == NOTIFY_INUSE) ? "inuse" : "closed");
- ast_build_string(&t, &maxbytes, "<msnsubstatus substatus=\"%s\" />\n", (local_state == NOTIFY_OPEN) ? "online" : (local_state == NOTIFY_INUSE) ? "onthephone" : "offline");
- ast_build_string(&t, &maxbytes, "</address>\n</atom>\n</presence>\n");
- break;
- case PIDF_XML: /* Eyebeam supports this format */
- ast_build_string(&t, &maxbytes, "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n");
- ast_build_string(&t, &maxbytes, "<presence xmlns=\"urn:ietf:params:xml:ns:pidf\" \nxmlns:pp=\"urn:ietf:params:xml:ns:pidf:person\"\nxmlns:es=\"urn:ietf:params:xml:ns:pidf:rpid:status:rpid-status\"\nxmlns:ep=\"urn:ietf:params:xml:ns:pidf:rpid:rpid-person\"\nentity=\"%s\">\n", mfrom);
- ast_build_string(&t, &maxbytes, "<pp:person><status>\n");
- if (pidfstate[0] != '-')
- ast_build_string(&t, &maxbytes, "<ep:activities><ep:%s/></ep:activities>\n", pidfstate);
- ast_build_string(&t, &maxbytes, "</status></pp:person>\n");
- ast_build_string(&t, &maxbytes, "<note>%s</note>\n", pidfnote); /* Note */
- ast_build_string(&t, &maxbytes, "<tuple id=\"%s\">\n", p->exten); /* Tuple start */
- ast_build_string(&t, &maxbytes, "<contact priority=\"1\">%s</contact>\n", mto);
- if (pidfstate[0] == 'b') /* Busy? Still open ... */
- ast_build_string(&t, &maxbytes, "<status><basic>open</basic></status>\n");
- else
- ast_build_string(&t, &maxbytes, "<status><basic>%s</basic></status>\n", (local_state != NOTIFY_CLOSED) ? "open" : "closed");
- ast_build_string(&t, &maxbytes, "</tuple>\n</presence>\n");
- break;
- case DIALOG_INFO_XML: /* SNOM subscribes in this format */
- ast_build_string(&t, &maxbytes, "<?xml version=\"1.0\"?>\n");
- ast_build_string(&t, &maxbytes, "<dialog-info xmlns=\"urn:ietf:params:xml:ns:dialog-info\" version=\"%d\" state=\"%s\" entity=\"%s\">\n", p->dialogver++, full ? "full":"partial", mto);
- if ((state & AST_EXTENSION_RINGING) && global_notifyringing)
- ast_build_string(&t, &maxbytes, "<dialog id=\"%s\" direction=\"recipient\">\n", p->exten);
- else
- ast_build_string(&t, &maxbytes, "<dialog id=\"%s\">\n", p->exten);
- ast_build_string(&t, &maxbytes, "<state>%s</state>\n", statestring);
- if (state == AST_EXTENSION_ONHOLD) {
- ast_build_string(&t, &maxbytes, "<local>\n<target uri=\"%s\">\n"
- "<param pname=\"+sip.rendering\" pvalue=\"no\"/>\n"
- "</target>\n</local>\n", mto);
- }
- ast_build_string(&t, &maxbytes, "</dialog>\n</dialog-info>\n");
- break;
- case NONE:
- default:
- break;
- }
-
- if (t > tmp + sizeof(tmp))
- ast_log(LOG_WARNING, "Buffer overflow detected!! (Please file a bug report)\n");
-
- add_header_contentLength(&req, strlen(tmp));
- add_line(&req, tmp);
- p->pendinginvite = p->ocseq; /* Remember that we have a pending NOTIFY in order not to confuse the NOTIFY subsystem */
-
- return send_request(p, &req, XMIT_RELIABLE, p->ocseq);
-}
-
-/*! \brief Notify user of messages waiting in voicemail
-\note - Notification only works for registered peers with mailbox= definitions
- in sip.conf
- - We use the SIP Event package message-summary
- MIME type defaults to "application/simple-message-summary";
- */
-static int transmit_notify_with_mwi(struct sip_pvt *p, int newmsgs, int oldmsgs, char *vmexten)
-{
- struct sip_request req;
- char tmp[500];
- char *t = tmp;
- size_t maxbytes = sizeof(tmp);
-
- initreqprep(&req, p, SIP_NOTIFY);
- add_header(&req, "Event", "message-summary");
- add_header(&req, "Content-Type", default_notifymime);
-
- ast_build_string(&t, &maxbytes, "Messages-Waiting: %s\r\n", newmsgs ? "yes" : "no");
- ast_build_string(&t, &maxbytes, "Message-Account: sip:%s@%s\r\n",
- S_OR(vmexten, default_vmexten), S_OR(p->fromdomain, ast_inet_ntoa(p->ourip)));
- /* Cisco has a bug in the SIP stack where it can't accept the
- (0/0) notification. This can temporarily be disabled in
- sip.conf with the "buggymwi" option */
- ast_build_string(&t, &maxbytes, "Voice-Message: %d/%d%s\r\n", newmsgs, oldmsgs, (ast_test_flag(&p->flags[1], SIP_PAGE2_BUGGY_MWI) ? "" : " (0/0)"));
-
- if (p->subscribed) {
- if (p->expiry)
- add_header(&req, "Subscription-State", "active");
- else /* Expired */
- add_header(&req, "Subscription-State", "terminated;reason=timeout");
- }
-
- if (t > tmp + sizeof(tmp))
- ast_log(LOG_WARNING, "Buffer overflow detected!! (Please file a bug report)\n");
-
- add_header_contentLength(&req, strlen(tmp));
- add_line(&req, tmp);
-
- if (!p->initreq.headers)
- initialize_initreq(p, &req);
- return send_request(p, &req, XMIT_RELIABLE, p->ocseq);
-}
-
-/*! \brief Transmit SIP request unreliably (only used in sip_notify subsystem) */
-static int transmit_sip_request(struct sip_pvt *p, struct sip_request *req)
-{
- if (!p->initreq.headers) /* Initialize first request before sending */
- initialize_initreq(p, req);
- return send_request(p, req, XMIT_UNRELIABLE, p->ocseq);
-}
-
-/*! \brief Notify a transferring party of the status of transfer */
-static int transmit_notify_with_sipfrag(struct sip_pvt *p, int cseq, char *message, int terminate)
-{
- struct sip_request req;
- char tmp[SIPBUFSIZE/2];
-
- reqprep(&req, p, SIP_NOTIFY, 0, 1);
- snprintf(tmp, sizeof(tmp), "refer;id=%d", cseq);
- add_header(&req, "Event", tmp);
- add_header(&req, "Subscription-state", terminate ? "terminated;reason=noresource" : "active");
- add_header(&req, "Content-Type", "message/sipfrag;version=2.0");
- add_header(&req, "Allow", ALLOWED_METHODS);
- add_header(&req, "Supported", SUPPORTED_EXTENSIONS);
-
- snprintf(tmp, sizeof(tmp), "SIP/2.0 %s\r\n", message);
- add_header_contentLength(&req, strlen(tmp));
- add_line(&req, tmp);
-
- if (!p->initreq.headers)
- initialize_initreq(p, &req);
-
- p->lastnoninvite = p->ocseq;
-
- return send_request(p, &req, XMIT_RELIABLE, p->ocseq);
-}
-
-/*! \brief Convert registration state status to string */
-static char *regstate2str(enum sipregistrystate regstate)
-{
- switch(regstate) {
- case REG_STATE_FAILED:
- return "Failed";
- case REG_STATE_UNREGISTERED:
- return "Unregistered";
- case REG_STATE_REGSENT:
- return "Request Sent";
- case REG_STATE_AUTHSENT:
- return "Auth. Sent";
- case REG_STATE_REGISTERED:
- return "Registered";
- case REG_STATE_REJECTED:
- return "Rejected";
- case REG_STATE_TIMEOUT:
- return "Timeout";
- case REG_STATE_NOAUTH:
- return "No Authentication";
- default:
- return "Unknown";
- }
-}
-
-/*! \brief Update registration with SIP Proxy */
-static int sip_reregister(const void *data)
-{
- /* if we are here, we know that we need to reregister. */
- struct sip_registry *r= ASTOBJ_REF((struct sip_registry *) data);
-
- /* if we couldn't get a reference to the registry object, punt */
- if (!r)
- return 0;
-
- if (r->call && !ast_test_flag(&r->call->flags[0], SIP_NO_HISTORY))
- append_history(r->call, "RegistryRenew", "Account: %s@%s", r->username, r->hostname);
- /* Since registry's are only added/removed by the the monitor thread, this
- may be overkill to reference/dereference at all here */
- if (sipdebug)
- ast_log(LOG_NOTICE, " -- Re-registration for %s@%s\n", r->username, r->hostname);
-
- r->expire = -1;
- __sip_do_register(r);
- ASTOBJ_UNREF(r, sip_registry_destroy);
- return 0;
-}
-
-/*! \brief Register with SIP proxy */
-static int __sip_do_register(struct sip_registry *r)
-{
- int res;
-
- res = transmit_register(r, SIP_REGISTER, NULL, NULL);
- return res;
-}
-
-/*! \brief Registration timeout, register again */
-static int sip_reg_timeout(const void *data)
-{
-
- /* if we are here, our registration timed out, so we'll just do it over */
- struct sip_registry *r = ASTOBJ_REF((struct sip_registry *) data);
- struct sip_pvt *p;
- int res;
-
- /* if we couldn't get a reference to the registry object, punt */
- if (!r)
- return 0;
-
- ast_log(LOG_NOTICE, " -- Registration for '%s@%s' timed out, trying again (Attempt #%d)\n", r->username, r->hostname, r->regattempts);
- if (r->call) {
- /* Unlink us, destroy old call. Locking is not relevant here because all this happens
- in the single SIP manager thread. */
- p = r->call;
- ast_mutex_lock(&p->lock);
- if (p->registry)
- ASTOBJ_UNREF(p->registry, sip_registry_destroy);
- r->call = NULL;
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- /* Pretend to ACK anything just in case */
- __sip_pretend_ack(p);
- ast_mutex_unlock(&p->lock);
- }
- /* If we have a limit, stop registration and give up */
- if (global_regattempts_max && (r->regattempts > global_regattempts_max)) {
- /* Ok, enough is enough. Don't try any more */
- /* We could add an external notification here...
- steal it from app_voicemail :-) */
- ast_log(LOG_NOTICE, " -- Giving up forever trying to register '%s@%s'\n", r->username, r->hostname);
- r->regstate = REG_STATE_FAILED;
- } else {
- r->regstate = REG_STATE_UNREGISTERED;
- r->timeout = -1;
- res=transmit_register(r, SIP_REGISTER, NULL, NULL);
- }
- manager_event(EVENT_FLAG_SYSTEM, "Registry", "ChannelDriver: SIP\r\nUsername: %s\r\nDomain: %s\r\nStatus: %s\r\n", r->username, r->hostname, regstate2str(r->regstate));
- ASTOBJ_UNREF(r, sip_registry_destroy);
- return 0;
-}
-
-/*! \brief Transmit register to SIP proxy or UA */
-static int transmit_register(struct sip_registry *r, int sipmethod, const char *auth, const char *authheader)
-{
- struct sip_request req;
- char from[256];
- char to[256];
- char tmp[80];
- char addr[80];
- struct sip_pvt *p;
- char *fromdomain;
-
- /* exit if we are already in process with this registrar ?*/
- if ( r == NULL || ((auth==NULL) && (r->regstate==REG_STATE_REGSENT || r->regstate==REG_STATE_AUTHSENT))) {
- if (r) {
- ast_log(LOG_NOTICE, "Strange, trying to register %s@%s when registration already pending\n", r->username, r->hostname);
- }
- return 0;
- }
-
- if (r->call) { /* We have a registration */
- if (!auth) {
- ast_log(LOG_WARNING, "Already have a REGISTER going on to %s@%s?? \n", r->username, r->hostname);
- return 0;
- } else {
- p = r->call;
- make_our_tag(p->tag, sizeof(p->tag)); /* create a new local tag for every register attempt */
- ast_string_field_free(p, theirtag); /* forget their old tag, so we don't match tags when getting response */
- }
- } else {
- /* Build callid for registration if we haven't registered before */
- if (!r->callid_valid) {
- build_callid_registry(r, __ourip, default_fromdomain);
- r->callid_valid = TRUE;
- }
- /* Allocate SIP packet for registration */
- if (!(p = sip_alloc( r->callid, NULL, 0, SIP_REGISTER))) {
- ast_log(LOG_WARNING, "Unable to allocate registration transaction (memory or socket error)\n");
- return 0;
- }
- if (!ast_test_flag(&p->flags[0], SIP_NO_HISTORY))
- append_history(p, "RegistryInit", "Account: %s@%s", r->username, r->hostname);
- /* Find address to hostname */
- if (create_addr(p, r->hostname)) {
- /* we have what we hope is a temporary network error,
- * probably DNS. We need to reschedule a registration try */
- sip_destroy(p);
-
- if (r->timeout > -1)
- ast_log(LOG_WARNING, "Still have a registration timeout for %s@%s (create_addr() error), %d\n", r->username, r->hostname, r->timeout);
- else
- ast_log(LOG_WARNING, "Probably a DNS error for registration to %s@%s, trying REGISTER again (after %d seconds)\n", r->username, r->hostname, global_reg_timeout);
-
- AST_SCHED_DEL(sched, r->timeout);
- r->timeout = ast_sched_add(sched, global_reg_timeout * 1000, sip_reg_timeout, r);
- r->regattempts++;
- return 0;
- }
- /* Copy back Call-ID in case create_addr changed it */
- ast_string_field_set(r, callid, p->callid);
- if (r->portno) {
- p->sa.sin_port = htons(r->portno);
- p->recv.sin_port = htons(r->portno);
- } else /* Set registry port to the port set from the peer definition/srv or default */
- r->portno = ntohs(p->sa.sin_port);
- ast_set_flag(&p->flags[0], SIP_OUTGOING); /* Registration is outgoing call */
- r->call=p; /* Save pointer to SIP packet */
- p->registry = ASTOBJ_REF(r); /* Add pointer to registry in packet */
- if (!ast_strlen_zero(r->secret)) /* Secret (password) */
- ast_string_field_set(p, peersecret, r->secret);
- if (!ast_strlen_zero(r->md5secret))
- ast_string_field_set(p, peermd5secret, r->md5secret);
- /* User name in this realm
- - if authuser is set, use that, otherwise use username */
- if (!ast_strlen_zero(r->authuser)) {
- ast_string_field_set(p, peername, r->authuser);
- ast_string_field_set(p, authname, r->authuser);
- } else if (!ast_strlen_zero(r->username)) {
- ast_string_field_set(p, peername, r->username);
- ast_string_field_set(p, authname, r->username);
- ast_string_field_set(p, fromuser, r->username);
- }
- if (!ast_strlen_zero(r->username))
- ast_string_field_set(p, username, r->username);
- /* Save extension in packet */
- ast_string_field_set(p, exten, r->contact);
-
- /*
- check which address we should use in our contact header
- based on whether the remote host is on the external or
- internal network so we can register through nat
- */
- if (ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip))
- p->ourip = bindaddr.sin_addr;
- build_contact(p);
- }
-
- /* set up a timeout */
- if (auth == NULL) {
- if (r->timeout > -1)
- ast_log(LOG_WARNING, "Still have a registration timeout, #%d - deleting it\n", r->timeout);
- AST_SCHED_DEL(sched, r->timeout);
- r->timeout = ast_sched_add(sched, global_reg_timeout * 1000, sip_reg_timeout, r);
- if (option_debug)
- ast_log(LOG_DEBUG, "Scheduled a registration timeout for %s id #%d \n", r->hostname, r->timeout);
- }
-
- if ((fromdomain = strchr(r->username, '@'))) {
- /* the domain name is just behind '@' */
- fromdomain++ ;
- /* We have a domain in the username for registration */
- snprintf(from, sizeof(from), "<sip:%s>;tag=%s", r->username, p->tag);
- if (!ast_strlen_zero(p->theirtag))
- snprintf(to, sizeof(to), "<sip:%s>;tag=%s", r->username, p->theirtag);
- else
- snprintf(to, sizeof(to), "<sip:%s>", r->username);
-
- /* If the registration username contains '@', then the domain should be used as
- the equivalent of "fromdomain" for the registration */
- if (ast_strlen_zero(p->fromdomain)) {
- ast_string_field_set(p, fromdomain, fromdomain);
- }
- } else {
- snprintf(from, sizeof(from), "<sip:%s@%s>;tag=%s", r->username, p->tohost, p->tag);
- if (!ast_strlen_zero(p->theirtag))
- snprintf(to, sizeof(to), "<sip:%s@%s>;tag=%s", r->username, p->tohost, p->theirtag);
- else
- snprintf(to, sizeof(to), "<sip:%s@%s>", r->username, p->tohost);
- }
-
- /* Fromdomain is what we are registering to, regardless of actual
- host name from SRV */
- if (!ast_strlen_zero(p->fromdomain)) {
- if (r->portno && r->portno != STANDARD_SIP_PORT)
- snprintf(addr, sizeof(addr), "sip:%s:%d", p->fromdomain, r->portno);
- else
- snprintf(addr, sizeof(addr), "sip:%s", p->fromdomain);
- } else {
- if (r->portno && r->portno != STANDARD_SIP_PORT)
- snprintf(addr, sizeof(addr), "sip:%s:%d", r->hostname, r->portno);
- else
- snprintf(addr, sizeof(addr), "sip:%s", r->hostname);
- }
- ast_string_field_set(p, uri, addr);
-
- p->branch ^= ast_random();
-
- init_req(&req, sipmethod, addr);
-
- /* Add to CSEQ */
- snprintf(tmp, sizeof(tmp), "%u %s", ++r->ocseq, sip_methods[sipmethod].text);
- p->ocseq = r->ocseq;
-
- build_via(p);
- add_header(&req, "Via", p->via);
- add_header(&req, "From", from);
- add_header(&req, "To", to);
- add_header(&req, "Call-ID", p->callid);
- add_header(&req, "CSeq", tmp);
- if (!ast_strlen_zero(global_useragent))
- add_header(&req, "User-Agent", global_useragent);
- add_header(&req, "Max-Forwards", DEFAULT_MAX_FORWARDS);
-
-
- if (auth) /* Add auth header */
- add_header(&req, authheader, auth);
- else if (!ast_strlen_zero(r->nonce)) {
- char digest[1024];
-
- /* We have auth data to reuse, build a digest header! */
- if (sipdebug)
- ast_log(LOG_DEBUG, " >>> Re-using Auth data for %s@%s\n", r->username, r->hostname);
- ast_string_field_set(p, realm, r->realm);
- ast_string_field_set(p, nonce, r->nonce);
- ast_string_field_set(p, domain, r->domain);
- ast_string_field_set(p, opaque, r->opaque);
- ast_string_field_set(p, qop, r->qop);
- r->noncecount++;
- p->noncecount = r->noncecount;
-
- memset(digest,0,sizeof(digest));
- if(!build_reply_digest(p, sipmethod, digest, sizeof(digest)))
- add_header(&req, "Authorization", digest);
- else
- ast_log(LOG_NOTICE, "No authorization available for authentication of registration to %s@%s\n", r->username, r->hostname);
-
- }
-
- snprintf(tmp, sizeof(tmp), "%d", default_expiry);
- add_header(&req, "Expires", tmp);
- add_header(&req, "Contact", p->our_contact);
- add_header(&req, "Event", "registration");
- add_header_contentLength(&req, 0);
-
- initialize_initreq(p, &req);
- if (sip_debug_test_pvt(p))
- ast_verbose("REGISTER %d headers, %d lines\n", p->initreq.headers, p->initreq.lines);
- r->regstate = auth ? REG_STATE_AUTHSENT : REG_STATE_REGSENT;
- r->regattempts++; /* Another attempt */
- if (option_debug > 3)
- ast_verbose("REGISTER attempt %d to %s@%s\n", r->regattempts, r->username, r->hostname);
- return send_request(p, &req, XMIT_CRITICAL, p->ocseq);
-}
-
-/*! \brief Transmit text with SIP MESSAGE method */
-static int transmit_message_with_text(struct sip_pvt *p, const char *text)
-{
- struct sip_request req;
-
- reqprep(&req, p, SIP_MESSAGE, 0, 1);
- add_text(&req, text);
- return send_request(p, &req, XMIT_RELIABLE, p->ocseq);
-}
-
-/*! \brief Allocate SIP refer structure */
-static int sip_refer_allocate(struct sip_pvt *p)
-{
- p->refer = ast_calloc(1, sizeof(struct sip_refer));
- return p->refer ? 1 : 0;
-}
-
-/*! \brief Transmit SIP REFER message (initiated by the transfer() dialplan application
- \note this is currently broken as we have no way of telling the dialplan
- engine whether a transfer succeeds or fails.
- \todo Fix the transfer() dialplan function so that a transfer may fail
-*/
-static int transmit_refer(struct sip_pvt *p, const char *dest)
-{
- struct sip_request req = {
- .headers = 0,
- };
- char from[256];
- const char *of;
- char *c;
- char referto[256];
- char *ttag, *ftag;
- char *theirtag = ast_strdupa(p->theirtag);
-
- if (option_debug || sipdebug)
- ast_log(LOG_DEBUG, "SIP transfer of %s to %s\n", p->callid, dest);
-
- /* Are we transfering an inbound or outbound call ? */
- if (ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
- of = get_header(&p->initreq, "To");
- ttag = theirtag;
- ftag = p->tag;
- } else {
- of = get_header(&p->initreq, "From");
- ftag = theirtag;
- ttag = p->tag;
- }
-
- ast_copy_string(from, of, sizeof(from));
- of = get_in_brackets(from);
- ast_string_field_set(p, from, of);
- if (strncasecmp(of, "sip:", 4))
- ast_log(LOG_NOTICE, "From address missing 'sip:', using it anyway\n");
- else
- of += 4;
- /* Get just the username part */
- if ((c = strchr(dest, '@')))
- c = NULL;
- else if ((c = strchr(of, '@')))
- *c++ = '\0';
- if (c)
- snprintf(referto, sizeof(referto), "<sip:%s@%s>", dest, c);
- else
- snprintf(referto, sizeof(referto), "<sip:%s>", dest);
-
- /* save in case we get 407 challenge */
- sip_refer_allocate(p);
- ast_copy_string(p->refer->refer_to, referto, sizeof(p->refer->refer_to));
- ast_copy_string(p->refer->referred_by, p->our_contact, sizeof(p->refer->referred_by));
- p->refer->status = REFER_SENT; /* Set refer status */
-
- reqprep(&req, p, SIP_REFER, 0, 1);
-
- add_header(&req, "Refer-To", referto);
- add_header(&req, "Allow", ALLOWED_METHODS);
- add_header(&req, "Supported", SUPPORTED_EXTENSIONS);
- if (!ast_strlen_zero(p->our_contact))
- add_header(&req, "Referred-By", p->our_contact);
-
- return send_request(p, &req, XMIT_RELIABLE, p->ocseq);
- /* We should propably wait for a NOTIFY here until we ack the transfer */
- /* Maybe fork a new thread and wait for a STATUS of REFER_200OK on the refer status before returning to app_transfer */
-
- /*! \todo In theory, we should hang around and wait for a reply, before
- returning to the dial plan here. Don't know really how that would
- affect the transfer() app or the pbx, but, well, to make this
- useful we should have a STATUS code on transfer().
- */
-}
-
-
-/*! \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)
-{
- struct sip_request req;
-
- reqprep(&req, p, SIP_INFO, 0, 1);
- add_digit(&req, digit, duration);
- return send_request(p, &req, XMIT_RELIABLE, p->ocseq);
-}
-
-/*! \brief Send SIP INFO with video update request */
-static int transmit_info_with_vidupdate(struct sip_pvt *p)
-{
- struct sip_request req;
-
- reqprep(&req, p, SIP_INFO, 0, 1);
- add_vidupdate(&req);
- return send_request(p, &req, XMIT_RELIABLE, p->ocseq);
-}
-
-/*! \brief Transmit generic SIP request
- returns XMIT_ERROR if transmit failed with a critical error (don't retry)
-*/
-static int transmit_request(struct sip_pvt *p, int sipmethod, int seqno, enum xmittype reliable, int newbranch)
-{
- struct sip_request resp;
-
- if (sipmethod == SIP_ACK)
- p->invitestate = INV_CONFIRMED;
-
- reqprep(&resp, p, sipmethod, seqno, newbranch);
- add_header_contentLength(&resp, 0);
- return send_request(p, &resp, reliable, seqno ? seqno : p->ocseq);
-}
-
-/*! \brief Transmit SIP request, auth added */
-static int transmit_request_with_auth(struct sip_pvt *p, int sipmethod, int seqno, enum xmittype reliable, int newbranch)
-{
- struct sip_request resp;
-
- reqprep(&resp, p, sipmethod, seqno, newbranch);
- if (!ast_strlen_zero(p->realm)) {
- char digest[1024];
-
- memset(digest, 0, sizeof(digest));
- if(!build_reply_digest(p, sipmethod, digest, sizeof(digest))) {
- if (p->options && p->options->auth_type == PROXY_AUTH)
- add_header(&resp, "Proxy-Authorization", digest);
- else if (p->options && p->options->auth_type == WWW_AUTH)
- add_header(&resp, "Authorization", digest);
- else /* Default, to be backwards compatible (maybe being too careful, but leaving it for now) */
- add_header(&resp, "Proxy-Authorization", digest);
- } else
- ast_log(LOG_WARNING, "No authentication available for call %s\n", p->callid);
- }
- /* If we are hanging up and know a cause for that, send it in clear text to make
- debugging easier. */
- if (sipmethod == SIP_BYE && p->owner && p->owner->hangupcause) {
- char buf[10];
-
- add_header(&resp, "X-Asterisk-HangupCause", ast_cause2str(p->owner->hangupcause));
- snprintf(buf, sizeof(buf), "%d", p->owner->hangupcause);
- add_header(&resp, "X-Asterisk-HangupCauseCode", buf);
- }
-
- add_header_contentLength(&resp, 0);
- return send_request(p, &resp, reliable, seqno ? seqno : p->ocseq);
-}
-
-/*! \brief Remove registration data from realtime database or AST/DB when registration expires */
-static void destroy_association(struct sip_peer *peer)
-{
- if (!ast_test_flag(&global_flags[1], SIP_PAGE2_IGNOREREGEXPIRE)) {
- if (ast_test_flag(&peer->flags[1], SIP_PAGE2_RT_FROMCONTACT))
- ast_update_realtime("sippeers", "name", peer->name, "fullcontact", "", "ipaddr", "", "port", "", "regseconds", "0", "username", "", "regserver", "", NULL);
- else
- ast_db_del("SIP/Registry", peer->name);
- }
-}
-
-/*! \brief Expire registration of SIP peer */
-static int expire_register(const void *data)
-{
- struct sip_peer *peer = (struct sip_peer *)data;
-
- if (!peer) /* Hmmm. We have no peer. Weird. */
- return 0;
-
- memset(&peer->addr, 0, sizeof(peer->addr));
-
- destroy_association(peer); /* remove registration data from storage */
-
- manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "Peer: SIP/%s\r\nPeerStatus: Unregistered\r\nCause: Expired\r\n", peer->name);
- register_peer_exten(peer, FALSE); /* Remove regexten */
- peer->expire = -1;
- ast_device_state_changed("SIP/%s", peer->name);
-
- /* Do we need to release this peer from memory?
- Only for realtime peers and autocreated peers
- */
- if (ast_test_flag(&peer->flags[1], SIP_PAGE2_SELFDESTRUCT) ||
- ast_test_flag(&peer->flags[1], SIP_PAGE2_RTAUTOCLEAR)) {
- struct sip_peer *peer_ptr = peer_ptr;
- peer_ptr = ASTOBJ_CONTAINER_UNLINK(&peerl, peer);
- if (peer_ptr) {
- ASTOBJ_UNREF(peer_ptr, sip_destroy_peer);
- }
- }
-
- ASTOBJ_UNREF(peer, sip_destroy_peer);
-
- return 0;
-}
-
-/*! \brief Poke peer (send qualify to check if peer is alive and well) */
-static int sip_poke_peer_s(const void *data)
-{
- struct sip_peer *peer = (struct sip_peer *) data;
-
- peer->pokeexpire = -1;
-
- sip_poke_peer(peer);
-
- ASTOBJ_UNREF(peer, sip_destroy_peer);
-
- return 0;
-}
-
-/*! \brief Get registration details from Asterisk DB */
-static void reg_source_db(struct sip_peer *peer)
-{
- char data[256];
- struct in_addr in;
- int expiry;
- int port;
- char *scan, *addr, *port_str, *expiry_str, *username, *contact;
-
- if (ast_test_flag(&peer->flags[1], SIP_PAGE2_RT_FROMCONTACT))
- return;
- if (ast_db_get("SIP/Registry", peer->name, data, sizeof(data)))
- return;
-
- scan = data;
- addr = strsep(&scan, ":");
- port_str = strsep(&scan, ":");
- expiry_str = strsep(&scan, ":");
- username = strsep(&scan, ":");
- contact = scan; /* Contact include sip: and has to be the last part of the database entry as long as we use : as a separator */
-
- if (!inet_aton(addr, &in))
- return;
-
- if (port_str)
- port = atoi(port_str);
- else
- return;
-
- if (expiry_str)
- expiry = atoi(expiry_str);
- else
- return;
-
- if (username)
- ast_copy_string(peer->username, username, sizeof(peer->username));
- if (contact)
- ast_copy_string(peer->fullcontact, contact, sizeof(peer->fullcontact));
-
- if (option_debug > 1)
- ast_log(LOG_DEBUG, "SIP Seeding peer from astdb: '%s' at %s@%s:%d for %d\n",
- peer->name, peer->username, ast_inet_ntoa(in), port, expiry);
-
- memset(&peer->addr, 0, sizeof(peer->addr));
- peer->addr.sin_family = AF_INET;
- peer->addr.sin_addr = in;
- peer->addr.sin_port = htons(port);
- if (sipsock < 0) {
- /* SIP isn't up yet, so schedule a poke only, pretty soon */
- if (!AST_SCHED_DEL(sched, peer->pokeexpire)) {
- struct sip_peer *peer_ptr = peer;
- ASTOBJ_UNREF(peer_ptr, sip_destroy_peer);
- }
- peer->pokeexpire = ast_sched_add(sched, ast_random() % 5000 + 1, sip_poke_peer_s, ASTOBJ_REF(peer));
- if (peer->pokeexpire == -1) {
- struct sip_peer *peer_ptr = peer;
- ASTOBJ_UNREF(peer_ptr, sip_destroy_peer);
- }
- } else
- sip_poke_peer(peer);
- if (!AST_SCHED_DEL(sched, peer->expire)) {
- struct sip_peer *peer_ptr = peer;
- ASTOBJ_UNREF(peer_ptr, sip_destroy_peer);
- }
- peer->expire = ast_sched_add(sched, (expiry + 10) * 1000, expire_register, ASTOBJ_REF(peer));
- if (peer->expire == -1) {
- struct sip_peer *peer_ptr = peer;
- ASTOBJ_UNREF(peer_ptr, sip_destroy_peer);
- }
- register_peer_exten(peer, TRUE);
-}
-
-/*! \brief Save contact header for 200 OK on INVITE */
-static int parse_ok_contact(struct sip_pvt *pvt, struct sip_request *req)
-{
- char contact[SIPBUFSIZE];
- char *c;
-
- /* Look for brackets */
- ast_copy_string(contact, get_header(req, "Contact"), sizeof(contact));
- c = get_in_brackets(contact);
-
- /* Save full contact to call pvt for later bye or re-invite */
- ast_string_field_set(pvt, fullcontact, c);
-
- /* Save URI for later ACKs, BYE or RE-invites */
- ast_string_field_set(pvt, okcontacturi, c);
-
- /* We should return false for URI:s we can't handle,
- like sips:, tel:, mailto:,ldap: etc */
- return TRUE;
-}
-
-static int __set_address_from_contact(const char *fullcontact, struct sockaddr_in *sin)
-{
- struct hostent *hp;
- struct ast_hostent ahp;
- int port;
- char *c, *host, *pt;
- char contact_buf[256];
- char *contact;
-
- /* Work on a copy */
- ast_copy_string(contact_buf, fullcontact, sizeof(contact_buf));
- contact = contact_buf;
-
- /* Make sure it's a SIP URL */
- if (strncasecmp(contact, "sip:", 4)) {
- ast_log(LOG_NOTICE, "'%s' is not a valid SIP contact (missing sip:) trying to use anyway\n", contact);
- } else
- contact += 4;
-
- /* Ditch arguments */
- /* XXX this code is replicated also shortly below */
-
- /* Grab host */
- host = strchr(contact, '@');
- if (!host) { /* No username part */
- host = contact;
- c = NULL;
- } else {
- *host++ = '\0';
- }
- pt = strchr(host, ':');
- if (pt) {
- *pt++ = '\0';
- port = atoi(pt);
- } else
- port = STANDARD_SIP_PORT;
-
- contact = strsep(&contact, ";"); /* trim ; and beyond in username part */
- host = strsep(&host, ";"); /* trim ; and beyond in host/domain part */
-
- /* XXX This could block for a long time XXX */
- /* We should only do this if it's a name, not an IP */
- hp = ast_gethostbyname(host, &ahp);
- if (!hp) {
- ast_log(LOG_WARNING, "Invalid host name in Contact: (can't resolve in DNS) : '%s'\n", host);
- return -1;
- }
- sin->sin_family = AF_INET;
- memcpy(&sin->sin_addr, hp->h_addr, sizeof(sin->sin_addr));
- sin->sin_port = htons(port);
-
- return 0;
-}
-
-/*! \brief Change the other partys IP address based on given contact */
-static int set_address_from_contact(struct sip_pvt *pvt)
-{
- if (ast_test_flag(&pvt->flags[0], SIP_NAT_ROUTE)) {
- /* NAT: Don't trust the contact field. Just use what they came to us
- with. */
- pvt->sa = pvt->recv;
- return 0;
- }
-
- return __set_address_from_contact(pvt->fullcontact, &pvt->sa);
-}
-
-
-/*! \brief Parse contact header and save registration (peer registration) */
-static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, struct sip_peer *peer, struct sip_request *req)
-{
- char contact[SIPBUFSIZE];
- char data[SIPBUFSIZE];
- const char *expires = get_header(req, "Expires");
- int expiry = atoi(expires);
- char *curi, *n, *pt;
- int port;
- const char *useragent;
- struct hostent *hp;
- struct ast_hostent ahp;
- struct sockaddr_in oldsin, testsin;
-
- ast_copy_string(contact, get_header(req, "Contact"), sizeof(contact));
-
- if (ast_strlen_zero(expires)) { /* No expires header */
- expires = strcasestr(contact, ";expires=");
- if (expires) {
- /* XXX bug here, we overwrite the string */
- expires = strsep((char **) &expires, ";"); /* trim ; and beyond */
- if (sscanf(expires + 9, "%d", &expiry) != 1)
- expiry = default_expiry;
- } else {
- /* Nothing has been specified */
- expiry = default_expiry;
- }
- }
-
- /* Look for brackets */
- curi = contact;
- if (strchr(contact, '<') == NULL) /* No <, check for ; and strip it */
- strsep(&curi, ";"); /* This is Header options, not URI options */
- curi = get_in_brackets(contact);
-
- /* if they did not specify Contact: or Expires:, they are querying
- what we currently have stored as their contact address, so return
- it
- */
- if (ast_strlen_zero(curi) && ast_strlen_zero(expires)) {
- /* If we have an active registration, tell them when the registration is going to expire */
- if (peer->expire > -1 && !ast_strlen_zero(peer->fullcontact))
- pvt->expiry = ast_sched_when(sched, peer->expire);
- return PARSE_REGISTER_QUERY;
- } else if (!strcasecmp(curi, "*") || !expiry) { /* Unregister this peer */
- /* This means remove all registrations and return OK */
- memset(&peer->addr, 0, sizeof(peer->addr));
- if (!AST_SCHED_DEL(sched, peer->expire)) {
- struct sip_peer *peer_ptr = peer;
- ASTOBJ_UNREF(peer_ptr, sip_destroy_peer);
- }
-
- destroy_association(peer);
-
- register_peer_exten(peer, 0); /* Add extension from regexten= setting in sip.conf */
- peer->fullcontact[0] = '\0';
- peer->useragent[0] = '\0';
- peer->sipoptions = 0;
- peer->lastms = 0;
- pvt->expiry = 0;
-
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Unregistered SIP '%s'\n", peer->name);
-
- manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "Peer: SIP/%s\r\nPeerStatus: Unregistered\r\n", peer->name);
- return PARSE_REGISTER_UPDATE;
- }
-
- /* Store whatever we got as a contact from the client */
- ast_copy_string(peer->fullcontact, curi, sizeof(peer->fullcontact));
-
- /* For the 200 OK, we should use the received contact */
- ast_string_field_build(pvt, our_contact, "<%s>", curi);
-
- /* Make sure it's a SIP URL */
- if (strncasecmp(curi, "sip:", 4)) {
- ast_log(LOG_NOTICE, "'%s' is not a valid SIP contact (missing sip:) trying to use anyway\n", curi);
- } else
- curi += 4;
- /* Ditch q */
- curi = strsep(&curi, ";");
- /* Grab host */
- n = strchr(curi, '@');
- if (!n) {
- n = curi;
- curi = NULL;
- } else
- *n++ = '\0';
- pt = strchr(n, ':');
- if (pt) {
- *pt++ = '\0';
- port = atoi(pt);
- } else
- port = STANDARD_SIP_PORT;
- oldsin = peer->addr;
-
- /* Check that they're allowed to register at this IP */
- /* XXX This could block for a long time XXX */
- hp = ast_gethostbyname(n, &ahp);
- if (!hp) {
- ast_log(LOG_WARNING, "Invalid host '%s'\n", n);
- *peer->fullcontact = '\0';
- ast_string_field_set(pvt, our_contact, "");
- return PARSE_REGISTER_FAILED;
- }
- memcpy(&testsin.sin_addr, hp->h_addr, sizeof(testsin.sin_addr));
- if ( ast_apply_ha(global_contact_ha, &testsin) != AST_SENSE_ALLOW ||
- ast_apply_ha(peer->contactha, &testsin) != AST_SENSE_ALLOW) {
- ast_log(LOG_WARNING, "Host '%s' disallowed by rule\n", n);
- *peer->fullcontact = '\0';
- ast_string_field_set(pvt, our_contact, "");
- return PARSE_REGISTER_FAILED;
- }
-
- if (!ast_test_flag(&peer->flags[0], SIP_NAT_ROUTE)) {
- peer->addr.sin_family = AF_INET;
- memcpy(&peer->addr.sin_addr, hp->h_addr, sizeof(peer->addr.sin_addr));
- peer->addr.sin_port = htons(port);
- } else {
- /* Don't trust the contact field. Just use what they came to us
- with */
- peer->addr = pvt->recv;
- }
-
- /* Save SIP options profile */
- peer->sipoptions = pvt->sipoptions;
-
- if (curi && ast_strlen_zero(peer->username))
- ast_copy_string(peer->username, curi, sizeof(peer->username));
-
- if (!AST_SCHED_DEL(sched, peer->expire)) {
- struct sip_peer *peer_ptr = peer;
- ASTOBJ_UNREF(peer_ptr, sip_destroy_peer);
- }
- if (expiry > max_expiry)
- expiry = max_expiry;
- if (expiry < min_expiry)
- expiry = min_expiry;
- if (ast_test_flag(&peer->flags[0], SIP_REALTIME) && !ast_test_flag(&peer->flags[1], SIP_PAGE2_RTCACHEFRIENDS)) {
- peer->expire = -1;
- } else {
- peer->expire = ast_sched_add(sched, (expiry + 10) * 1000, expire_register, ASTOBJ_REF(peer));
- if (peer->expire == -1) {
- struct sip_peer *peer_ptr = peer;
- ASTOBJ_UNREF(peer_ptr, sip_destroy_peer);
- }
- }
- pvt->expiry = expiry;
- snprintf(data, sizeof(data), "%s:%d:%d:%s:%s", ast_inet_ntoa(peer->addr.sin_addr), ntohs(peer->addr.sin_port), expiry, peer->username, peer->fullcontact);
- if (!ast_test_flag(&peer->flags[1], SIP_PAGE2_RT_FROMCONTACT))
- ast_db_put("SIP/Registry", peer->name, data);
- manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "Peer: SIP/%s\r\nPeerStatus: Registered\r\n", peer->name);
-
- /* Is this a new IP address for us? */
- if (option_verbose > 2 && inaddrcmp(&peer->addr, &oldsin)) {
- ast_verbose(VERBOSE_PREFIX_3 "Registered SIP '%s' at %s port %d\n", peer->name, ast_inet_ntoa(peer->addr.sin_addr), ntohs(peer->addr.sin_port));
- }
- sip_poke_peer(peer);
- register_peer_exten(peer, 1);
-
- /* Save User agent */
- useragent = get_header(req, "User-Agent");
- if (strcasecmp(useragent, peer->useragent)) { /* XXX copy if they are different ? */
- ast_copy_string(peer->useragent, useragent, sizeof(peer->useragent));
- if (option_verbose > 3)
- ast_verbose(VERBOSE_PREFIX_3 "Saved useragent \"%s\" for peer %s\n", peer->useragent, peer->name);
- }
- return PARSE_REGISTER_UPDATE;
-}
-
-/*! \brief Remove route from route list */
-static void free_old_route(struct sip_route *route)
-{
- struct sip_route *next;
-
- while (route) {
- next = route->next;
- free(route);
- route = next;
- }
-}
-
-/*! \brief List all routes - mostly for debugging */
-static void list_route(struct sip_route *route)
-{
- if (!route)
- ast_verbose("list_route: no route\n");
- else {
- for (;route; route = route->next)
- ast_verbose("list_route: hop: <%s>\n", route->hop);
- }
-}
-
-/*! \brief Build route list from Record-Route header */
-static void build_route(struct sip_pvt *p, struct sip_request *req, int backwards)
-{
- struct sip_route *thishop, *head, *tail;
- int start = 0;
- int len;
- const char *rr, *contact, *c;
-
- /* Once a persistant route is set, don't fool with it */
- if (p->route && p->route_persistant) {
- if (option_debug)
- ast_log(LOG_DEBUG, "build_route: Retaining previous route: <%s>\n", p->route->hop);
- return;
- }
-
- if (p->route) {
- free_old_route(p->route);
- p->route = NULL;
- }
-
- /* We only want to create the route set the first time this is called */
- p->route_persistant = 1;
-
- /* Build a tailq, then assign it to p->route when done.
- * If backwards, we add entries from the head so they end up
- * in reverse order. However, we do need to maintain a correct
- * tail pointer because the contact is always at the end.
- */
- head = NULL;
- tail = head;
- /* 1st we pass through all the hops in any Record-Route headers */
- for (;;) {
- /* Each Record-Route header */
- rr = __get_header(req, "Record-Route", &start);
- if (*rr == '\0')
- break;
- for (; (rr = strchr(rr, '<')) ; rr += len) { /* Each route entry */
- ++rr;
- len = strcspn(rr, ">") + 1;
- /* Make a struct route */
- if ((thishop = ast_malloc(sizeof(*thishop) + len))) {
- /* ast_calloc is not needed because all fields are initialized in this block */
- ast_copy_string(thishop->hop, rr, len);
- if (option_debug > 1)
- ast_log(LOG_DEBUG, "build_route: Record-Route hop: <%s>\n", thishop->hop);
- /* Link in */
- if (backwards) {
- /* Link in at head so they end up in reverse order */
- thishop->next = head;
- head = thishop;
- /* If this was the first then it'll be the tail */
- if (!tail)
- tail = thishop;
- } else {
- thishop->next = NULL;
- /* Link in at the end */
- if (tail)
- tail->next = thishop;
- else
- head = thishop;
- tail = thishop;
- }
- }
- }
- }
-
- /* Only append the contact if we are dealing with a strict router */
- if (!head || (!ast_strlen_zero(head->hop) && strstr(head->hop,";lr") == NULL) ) {
- /* 2nd append the Contact: if there is one */
- /* Can be multiple Contact headers, comma separated values - we just take the first */
- contact = get_header(req, "Contact");
- if (!ast_strlen_zero(contact)) {
- if (option_debug > 1)
- ast_log(LOG_DEBUG, "build_route: Contact hop: %s\n", contact);
- /* Look for <: delimited address */
- c = strchr(contact, '<');
- if (c) {
- /* Take to > */
- ++c;
- len = strcspn(c, ">") + 1;
- } else {
- /* No <> - just take the lot */
- c = contact;
- len = strlen(contact) + 1;
- }
- if ((thishop = ast_malloc(sizeof(*thishop) + len))) {
- /* ast_calloc is not needed because all fields are initialized in this block */
- ast_copy_string(thishop->hop, c, len);
- thishop->next = NULL;
- /* Goes at the end */
- if (tail)
- tail->next = thishop;
- else
- head = thishop;
- }
- }
- }
-
- /* Store as new route */
- p->route = head;
-
- /* For debugging dump what we ended up with */
- if (sip_debug_test_pvt(p))
- list_route(p->route);
-}
-
-AST_THREADSTORAGE(check_auth_buf, check_auth_buf_init);
-#define CHECK_AUTH_BUF_INITLEN 256
-
-/*! \brief Check user authorization from peer definition
- Some actions, like REGISTER and INVITEs from peers require
- authentication (if peer have secret set)
- \return 0 on success, non-zero on error
-*/
-static enum check_auth_result check_auth(struct sip_pvt *p, struct sip_request *req, const char *username,
- const char *secret, const char *md5secret, int sipmethod,
- char *uri, enum xmittype reliable, int ignore)
-{
- const char *response = "407 Proxy Authentication Required";
- const char *reqheader = "Proxy-Authorization";
- const char *respheader = "Proxy-Authenticate";
- const char *authtoken;
- char a1_hash[256];
- char resp_hash[256]="";
- char *c;
- int wrongnonce = FALSE;
- int good_response;
- const char *usednonce = p->randdata;
- struct ast_dynamic_str *buf;
- int res;
-
- /* table of recognised keywords, and their value in the digest */
- enum keys { K_RESP, K_URI, K_USER, K_NONCE, K_LAST };
- struct x {
- const char *key;
- const char *s;
- } *i, keys[] = {
- [K_RESP] = { "response=", "" },
- [K_URI] = { "uri=", "" },
- [K_USER] = { "username=", "" },
- [K_NONCE] = { "nonce=", "" },
- [K_LAST] = { NULL, NULL}
- };
-
- /* Always OK if no secret */
- if (ast_strlen_zero(secret) && ast_strlen_zero(md5secret))
- return AUTH_SUCCESSFUL;
- if (sipmethod == SIP_REGISTER || sipmethod == SIP_SUBSCRIBE) {
- /* On a REGISTER, we have to use 401 and its family of headers instead of 407 and its family
- of headers -- GO SIP! Whoo hoo! Two things that do the same thing but are used in
- different circumstances! What a surprise. */
- response = "401 Unauthorized";
- reqheader = "Authorization";
- respheader = "WWW-Authenticate";
- }
- authtoken = get_header(req, reqheader);
- if (ignore && !ast_strlen_zero(p->randdata) && ast_strlen_zero(authtoken)) {
- /* This is a retransmitted invite/register/etc, don't reconstruct authentication
- information */
- if (!reliable) {
- /* Resend message if this was NOT a reliable delivery. Otherwise the
- retransmission should get it */
- transmit_response_with_auth(p, response, req, p->randdata, reliable, respheader, 0);
- /* Schedule auto destroy in 32 seconds (according to RFC 3261) */
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- }
- return AUTH_CHALLENGE_SENT;
- } else if (ast_strlen_zero(p->randdata) || ast_strlen_zero(authtoken)) {
- /* We have no auth, so issue challenge and request authentication */
- ast_string_field_build(p, randdata, "%08lx", ast_random()); /* Create nonce for challenge */
- transmit_response_with_auth(p, response, req, p->randdata, reliable, respheader, 0);
- /* Schedule auto destroy in 32 seconds */
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- return AUTH_CHALLENGE_SENT;
- }
-
- /* --- We have auth, so check it */
-
- /* Whoever came up with the authentication section of SIP can suck my %&#$&* for not putting
- an example in the spec of just what it is you're doing a hash on. */
-
- if (!(buf = ast_dynamic_str_thread_get(&check_auth_buf, CHECK_AUTH_BUF_INITLEN)))
- return AUTH_SECRET_FAILED; /*! XXX \todo need a better return code here */
-
- /* Make a copy of the response and parse it */
- res = ast_dynamic_str_thread_set(&buf, 0, &check_auth_buf, "%s", authtoken);
-
- if (res == AST_DYNSTR_BUILD_FAILED)
- return AUTH_SECRET_FAILED; /*! XXX \todo need a better return code here */
-
- c = buf->str;
-
- while(c && *(c = ast_skip_blanks(c)) ) { /* lookup for keys */
- for (i = keys; i->key != NULL; i++) {
- const char *separator = ","; /* default */
-
- if (strncasecmp(c, i->key, strlen(i->key)) != 0)
- continue;
- /* Found. Skip keyword, take text in quotes or up to the separator. */
- c += strlen(i->key);
- if (*c == '"') { /* in quotes. Skip first and look for last */
- c++;
- separator = "\"";
- }
- i->s = c;
- strsep(&c, separator);
- break;
- }
- if (i->key == NULL) /* not found, jump after space or comma */
- strsep(&c, " ,");
- }
-
- /* Verify that digest username matches the username we auth as */
- if (strcmp(username, keys[K_USER].s)) {
- ast_log(LOG_WARNING, "username mismatch, have <%s>, digest has <%s>\n",
- username, keys[K_USER].s);
- /* Oops, we're trying something here */
- return AUTH_USERNAME_MISMATCH;
- }
-
- /* Verify nonce from request matches our nonce. If not, send 401 with new nonce */
- if (strcasecmp(p->randdata, keys[K_NONCE].s)) { /* XXX it was 'n'casecmp ? */
- wrongnonce = TRUE;
- usednonce = keys[K_NONCE].s;
- }
-
- if (!ast_strlen_zero(md5secret))
- ast_copy_string(a1_hash, md5secret, sizeof(a1_hash));
- else {
- char a1[256];
- snprintf(a1, sizeof(a1), "%s:%s:%s", username, global_realm, secret);
- ast_md5_hash(a1_hash, a1);
- }
-
- /* compute the expected response to compare with what we received */
- {
- char a2[256];
- char a2_hash[256];
- char resp[256];
-
- snprintf(a2, sizeof(a2), "%s:%s", sip_methods[sipmethod].text,
- S_OR(keys[K_URI].s, uri));
- ast_md5_hash(a2_hash, a2);
- snprintf(resp, sizeof(resp), "%s:%s:%s", a1_hash, usednonce, a2_hash);
- ast_md5_hash(resp_hash, resp);
- }
-
- good_response = keys[K_RESP].s &&
- !strncasecmp(keys[K_RESP].s, resp_hash, strlen(resp_hash));
- if (wrongnonce) {
- if (good_response) {
- if (sipdebug)
- ast_log(LOG_NOTICE, "Correct auth, but based on stale nonce received from '%s'\n", get_header(req, "To"));
- /* We got working auth token, based on stale nonce . */
- ast_string_field_build(p, randdata, "%08lx", ast_random());
- transmit_response_with_auth(p, response, req, p->randdata, reliable, respheader, TRUE);
- } else {
- /* Everything was wrong, so give the device one more try with a new challenge */
- if (!ast_test_flag(req, SIP_PKT_IGNORE)) {
- if (sipdebug)
- ast_log(LOG_NOTICE, "Bad authentication received from '%s'\n", get_header(req, "To"));
- ast_string_field_build(p, randdata, "%08lx", ast_random());
- } else {
- if (sipdebug)
- ast_log(LOG_NOTICE, "Duplicate authentication received from '%s'\n", get_header(req, "To"));
- }
- transmit_response_with_auth(p, response, req, p->randdata, reliable, respheader, FALSE);
- }
-
- /* Schedule auto destroy in 32 seconds */
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- return AUTH_CHALLENGE_SENT;
- }
- if (good_response) {
- append_history(p, "AuthOK", "Auth challenge succesful for %s", username);
- return AUTH_SUCCESSFUL;
- }
-
- /* Ok, we have a bad username/secret pair */
- /* Tell the UAS not to re-send this authentication data, because
- it will continue to fail
- */
-
- return AUTH_SECRET_FAILED;
-}
-
-/*! \brief Change onhold state of a peer using a pvt structure */
-static void sip_peer_hold(struct sip_pvt *p, int hold)
-{
- struct sip_peer *peer = find_peer(p->peername, NULL, 1, 0);
-
- if (!peer)
- return;
-
- /* If they put someone on hold, increment the value... otherwise decrement it */
- if (hold)
- peer->onHold++;
- else
- peer->onHold--;
-
- /* Request device state update */
- ast_device_state_changed("SIP/%s", peer->name);
-
- return;
-}
-
-/*! \brief Callback for the devicestate notification (SUBSCRIBE) support subsystem
-\note If you add an "hint" priority to the extension in the dial plan,
- you will get notifications on device state changes */
-static int cb_extensionstate(char *context, char* exten, int state, void *data)
-{
- struct sip_pvt *p = data;
-
- ast_mutex_lock(&p->lock);
-
- switch(state) {
- case AST_EXTENSION_DEACTIVATED: /* Retry after a while */
- case AST_EXTENSION_REMOVED: /* Extension is gone */
- if (p->autokillid > -1 && sip_cancel_destroy(p)) /* Remove subscription expiry for renewals */
- ast_log(LOG_WARNING, "Unable to cancel SIP destruction. Expect bad things.\n");
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT); /* Delete subscription in 32 secs */
- ast_verbose(VERBOSE_PREFIX_2 "Extension state: Watcher for hint %s %s. Notify User %s\n", exten, state == AST_EXTENSION_DEACTIVATED ? "deactivated" : "removed", p->username);
- p->stateid = -1;
- p->subscribed = NONE;
- append_history(p, "Subscribestatus", "%s", state == AST_EXTENSION_REMOVED ? "HintRemoved" : "Deactivated");
- break;
- default: /* Tell user */
- p->laststate = state;
- break;
- }
- if (p->subscribed != NONE) { /* Only send state NOTIFY if we know the format */
- if (!p->pendinginvite) {
- transmit_state_notify(p, state, 1, FALSE);
- } else {
- /* We already have a NOTIFY sent that is not answered. Queue the state up.
- if many state changes happen meanwhile, we will only send a notification of the last one */
- ast_set_flag(&p->flags[1], SIP_PAGE2_STATECHANGEQUEUE);
- }
- }
- if (option_verbose > 1)
- ast_verbose(VERBOSE_PREFIX_1 "Extension Changed %s[%s] new state %s for Notify User %s %s\n", exten, context, ast_extension_state2str(state), p->username,
- ast_test_flag(&p->flags[1], SIP_PAGE2_STATECHANGEQUEUE) ? "(queued)" : "");
-
-
- ast_mutex_unlock(&p->lock);
-
- return 0;
-}
-
-/*! \brief Send a fake 401 Unauthorized response when the administrator
- wants to hide the names of local users/peers from fishers
- */
-static void transmit_fake_auth_response(struct sip_pvt *p, struct sip_request *req, int reliable)
-{
- ast_string_field_build(p, randdata, "%08lx", ast_random()); /* Create nonce for challenge */
- transmit_response_with_auth(p, "401 Unauthorized", req, p->randdata, reliable, "WWW-Authenticate", 0);
-}
-
-/*! \brief Verify registration of user
- - Registration is done in several steps, first a REGISTER without auth
- to get a challenge (nonce) then a second one with auth
- - Registration requests are only matched with peers that are marked as "dynamic"
- */
-static enum check_auth_result register_verify(struct sip_pvt *p, struct sockaddr_in *sin,
- struct sip_request *req, char *uri)
-{
- enum check_auth_result res = AUTH_NOT_FOUND;
- struct sip_peer *peer;
- char tmp[256];
- char *name, *c;
- char *t;
- char *domain;
-
- /* Terminate URI */
- t = uri;
- while(*t && (*t > 32) && (*t != ';'))
- t++;
- *t = '\0';
-
- ast_copy_string(tmp, get_header(req, "To"), sizeof(tmp));
- if (pedanticsipchecking)
- ast_uri_decode(tmp);
-
- c = get_in_brackets(tmp);
- c = strsep(&c, ";"); /* Ditch ;user=phone */
-
- if (!strncasecmp(c, "sip:", 4)) {
- name = c + 4;
- } else {
- name = c;
- ast_log(LOG_NOTICE, "Invalid to address: '%s' from %s (missing sip:) trying to use anyway...\n", c, ast_inet_ntoa(sin->sin_addr));
- }
-
- /* Strip off the domain name */
- if ((c = strchr(name, '@'))) {
- *c++ = '\0';
- domain = c;
- if ((c = strchr(domain, ':'))) /* Remove :port */
- *c = '\0';
- if (!AST_LIST_EMPTY(&domain_list)) {
- if (!check_sip_domain(domain, NULL, 0)) {
- transmit_response(p, "404 Not found (unknown domain)", &p->initreq);
- return AUTH_UNKNOWN_DOMAIN;
- }
- }
- }
-
- ast_string_field_set(p, exten, name);
- build_contact(p);
- peer = find_peer(name, NULL, 1, 0);
- if (!(peer && ast_apply_ha(peer->ha, sin))) {
- /* Peer fails ACL check */
- if (peer) {
- ASTOBJ_UNREF(peer, sip_destroy_peer);
- res = AUTH_ACL_FAILED;
- } else
- res = AUTH_NOT_FOUND;
- }
- if (peer) {
- /* Set Frame packetization */
- if (p->rtp) {
- ast_rtp_codec_setpref(p->rtp, &peer->prefs);
- p->autoframing = peer->autoframing;
- }
- if (!ast_test_flag(&peer->flags[1], SIP_PAGE2_DYNAMIC)) {
- ast_log(LOG_ERROR, "Peer '%s' is trying to register, but not configured as host=dynamic\n", peer->name);
- res = AUTH_PEER_NOT_DYNAMIC;
- } else {
- ast_copy_flags(&p->flags[0], &peer->flags[0], SIP_NAT);
- transmit_response(p, "100 Trying", req);
- if (!(res = check_auth(p, req, peer->name, peer->secret, peer->md5secret, SIP_REGISTER, uri, XMIT_UNRELIABLE, ast_test_flag(req, SIP_PKT_IGNORE)))) {
- if (sip_cancel_destroy(p))
- ast_log(LOG_WARNING, "Unable to cancel SIP destruction. Expect bad things.\n");
-
- /* We have a succesful registration attemp with proper authentication,
- now, update the peer */
- switch (parse_register_contact(p, peer, req)) {
- case PARSE_REGISTER_FAILED:
- ast_log(LOG_WARNING, "Failed to parse contact info\n");
- transmit_response_with_date(p, "400 Bad Request", req);
- peer->lastmsgssent = -1;
- res = 0;
- break;
- case PARSE_REGISTER_QUERY:
- transmit_response_with_date(p, "200 OK", req);
- peer->lastmsgssent = -1;
- res = 0;
- break;
- case PARSE_REGISTER_UPDATE:
- update_peer(peer, p->expiry);
- /* Say OK and ask subsystem to retransmit msg counter */
- transmit_response_with_date(p, "200 OK", req);
- if (!ast_test_flag((&peer->flags[1]), SIP_PAGE2_SUBSCRIBEMWIONLY))
- peer->lastmsgssent = -1;
- res = 0;
- break;
- }
- }
- }
- }
- if (!peer && autocreatepeer) {
- /* Create peer if we have autocreate mode enabled */
- peer = temp_peer(name);
- if (peer) {
- ASTOBJ_CONTAINER_LINK(&peerl, peer);
- if (sip_cancel_destroy(p))
- ast_log(LOG_WARNING, "Unable to cancel SIP destruction. Expect bad things.\n");
- switch (parse_register_contact(p, peer, req)) {
- case PARSE_REGISTER_FAILED:
- ast_log(LOG_WARNING, "Failed to parse contact info\n");
- transmit_response_with_date(p, "400 Bad Request", req);
- peer->lastmsgssent = -1;
- res = 0;
- break;
- case PARSE_REGISTER_QUERY:
- transmit_response_with_date(p, "200 OK", req);
- peer->lastmsgssent = -1;
- res = 0;
- break;
- case PARSE_REGISTER_UPDATE:
- /* Say OK and ask subsystem to retransmit msg counter */
- transmit_response_with_date(p, "200 OK", req);
- manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "Peer: SIP/%s\r\nPeerStatus: Registered\r\n", peer->name);
- peer->lastmsgssent = -1;
- res = 0;
- break;
- }
- }
- }
- if (!res) {
- ast_device_state_changed("SIP/%s", peer->name);
- }
- if (res < 0) {
- switch (res) {
- case AUTH_SECRET_FAILED:
- /* Wrong password in authentication. Go away, don't try again until you fixed it */
- transmit_response(p, "403 Forbidden (Bad auth)", &p->initreq);
- break;
- case AUTH_USERNAME_MISMATCH:
- /* Username and digest username does not match.
- Asterisk uses the From: username for authentication. We need the
- users to use the same authentication user name until we support
- proper authentication by digest auth name */
- transmit_response(p, "403 Authentication user name does not match account name", &p->initreq);
- break;
- case AUTH_NOT_FOUND:
- case AUTH_PEER_NOT_DYNAMIC:
- case AUTH_ACL_FAILED:
- if (global_alwaysauthreject) {
- transmit_fake_auth_response(p, &p->initreq, 1);
- } else {
- /* URI not found */
- if (res == AUTH_PEER_NOT_DYNAMIC)
- transmit_response(p, "403 Forbidden", &p->initreq);
- else
- transmit_response(p, "404 Not found", &p->initreq);
- }
- break;
- default:
- break;
- }
- }
- if (peer)
- ASTOBJ_UNREF(peer, sip_destroy_peer);
-
- return res;
-}
-
-/*! \brief Get referring dnis */
-static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq)
-{
- char tmp[256], *c, *a;
- struct sip_request *req;
-
- req = oreq;
- if (!req)
- req = &p->initreq;
- ast_copy_string(tmp, get_header(req, "Diversion"), sizeof(tmp));
- if (ast_strlen_zero(tmp))
- return 0;
- c = get_in_brackets(tmp);
- if (strncasecmp(c, "sip:", 4)) {
- ast_log(LOG_WARNING, "Huh? Not an RDNIS SIP header (%s)?\n", c);
- return -1;
- }
- c += 4;
- a = c;
- strsep(&a, "@;"); /* trim anything after @ or ; */
- if (sip_debug_test_pvt(p))
- ast_verbose("RDNIS is %s\n", c);
- ast_string_field_set(p, rdnis, c);
-
- return 0;
-}
-
-/*! \brief Find out who the call is for
- We use the INVITE uri to find out
-*/
-static int get_destination(struct sip_pvt *p, struct sip_request *oreq)
-{
- char tmp[256] = "", *uri, *a;
- char tmpf[256] = "", *from;
- struct sip_request *req;
- char *colon;
- char *decoded_uri;
-
- req = oreq;
- if (!req)
- req = &p->initreq;
-
- /* Find the request URI */
- if (req->rlPart2)
- ast_copy_string(tmp, req->rlPart2, sizeof(tmp));
-
- if (pedanticsipchecking)
- ast_uri_decode(tmp);
-
- uri = get_in_brackets(tmp);
-
- if (strncasecmp(uri, "sip:", 4)) {
- ast_log(LOG_WARNING, "Huh? Not a SIP header (%s)?\n", uri);
- return -1;
- }
- uri += 4;
-
- /* Now find the From: caller ID and name */
- ast_copy_string(tmpf, get_header(req, "From"), sizeof(tmpf));
- if (!ast_strlen_zero(tmpf)) {
- if (pedanticsipchecking)
- ast_uri_decode(tmpf);
- from = get_in_brackets(tmpf);
- } else {
- from = NULL;
- }
-
- if (!ast_strlen_zero(from)) {
- if (strncasecmp(from, "sip:", 4)) {
- ast_log(LOG_WARNING, "Huh? Not a SIP header (%s)?\n", from);
- return -1;
- }
- from += 4;
- if ((a = strchr(from, '@')))
- *a++ = '\0';
- else
- a = from; /* just a domain */
- from = strsep(&from, ";"); /* Remove userinfo options */
- a = strsep(&a, ";"); /* Remove URI options */
- ast_string_field_set(p, fromdomain, a);
- }
-
- /* Skip any options and find the domain */
-
- /* Get the target domain */
- if ((a = strchr(uri, '@'))) {
- *a++ = '\0';
- } else { /* No username part */
- a = uri;
- uri = "s"; /* Set extension to "s" */
- }
- colon = strchr(a, ':'); /* Remove :port */
- if (colon)
- *colon = '\0';
-
- uri = strsep(&uri, ";"); /* Remove userinfo options */
- a = strsep(&a, ";"); /* Remove URI options */
-
- ast_string_field_set(p, domain, a);
-
- if (!AST_LIST_EMPTY(&domain_list)) {
- char domain_context[AST_MAX_EXTENSION];
-
- domain_context[0] = '\0';
- if (!check_sip_domain(p->domain, domain_context, sizeof(domain_context))) {
- if (!allow_external_domains && (req->method == SIP_INVITE || req->method == SIP_REFER)) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Got SIP %s to non-local domain '%s'; refusing request.\n", sip_methods[req->method].text, p->domain);
- return -2;
- }
- }
- /* If we have a context defined, overwrite the original context */
- if (!ast_strlen_zero(domain_context))
- ast_string_field_set(p, context, domain_context);
- }
-
- /* If the request coming in is a subscription and subscribecontext has been specified use it */
- if (req->method == SIP_SUBSCRIBE && !ast_strlen_zero(p->subscribecontext))
- ast_string_field_set(p, context, p->subscribecontext);
-
- if (sip_debug_test_pvt(p))
- ast_verbose("Looking for %s in %s (domain %s)\n", uri, p->context, p->domain);
-
- /* If this is a subscription we actually just need to see if a hint exists for the extension */
- if (req->method == SIP_SUBSCRIBE) {
- char hint[AST_MAX_EXTENSION];
- return (ast_get_hint(hint, sizeof(hint), NULL, 0, NULL, p->context, p->exten) ? 0 : -1);
- } else {
- decoded_uri = ast_strdupa(uri);
- ast_uri_decode(decoded_uri);
- /* Check the dialplan for the username part of the request URI,
- the domain will be stored in the SIPDOMAIN variable
- Since extensions.conf can have unescaped characters, try matching a decoded
- uri in addition to the non-decoded uri
- Return 0 if we have a matching extension */
- if (ast_exists_extension(NULL, p->context, uri, 1, S_OR(p->cid_num, from)) || ast_exists_extension(NULL, p->context, decoded_uri, 1, S_OR(p->cid_num, from)) ||
- !strcmp(decoded_uri, ast_pickup_ext())) {
- if (!oreq)
- ast_string_field_set(p, exten, decoded_uri);
- return 0;
- }
- }
-
- /* Return 1 for pickup extension or overlap dialling support (if we support it) */
- if((ast_test_flag(&global_flags[1], SIP_PAGE2_ALLOWOVERLAP) &&
- ast_canmatch_extension(NULL, p->context, decoded_uri, 1, S_OR(p->cid_num, from))) ||
- !strncmp(decoded_uri, ast_pickup_ext(), strlen(decoded_uri))) {
- return 1;
- }
-
- return -1;
-}
-
-/*! \brief Lock interface lock and find matching pvt lock
-*/
-static struct sip_pvt *get_sip_pvt_byid_locked(const char *callid, const char *totag, const char *fromtag)
-{
- struct sip_pvt *sip_pvt_ptr;
-
- ast_mutex_lock(&iflock);
-
- if (option_debug > 3 && totag)
- ast_log(LOG_DEBUG, "Looking for callid %s (fromtag %s totag %s)\n", callid, fromtag ? fromtag : "<no fromtag>", totag ? totag : "<no totag>");
-
- /* Search interfaces and find the match */
- for (sip_pvt_ptr = iflist; sip_pvt_ptr; sip_pvt_ptr = sip_pvt_ptr->next) {
- if (!strcmp(sip_pvt_ptr->callid, callid)) {
- int match = 1;
-
- /* Go ahead and lock it (and its owner) before returning */
- ast_mutex_lock(&sip_pvt_ptr->lock);
-
- /* Check if tags match. If not, this is not the call we want
- (With a forking SIP proxy, several call legs share the
- call id, but have different tags)
- */
- if (pedanticsipchecking) {
- const char *pvt_fromtag, *pvt_totag;
-
- if (ast_test_flag(&sip_pvt_ptr->flags[1], SIP_PAGE2_OUTGOING_CALL)) {
- /* Outgoing call tags : from is "our", to is "their" */
- pvt_fromtag = sip_pvt_ptr->tag ;
- pvt_totag = sip_pvt_ptr->theirtag ;
- } else {
- /* Incoming call tags : from is "their", to is "our" */
- pvt_fromtag = sip_pvt_ptr->theirtag ;
- pvt_totag = sip_pvt_ptr->tag ;
- }
- if (ast_strlen_zero(fromtag) || strcmp(fromtag, pvt_fromtag) || (!ast_strlen_zero(totag) && strcmp(totag, pvt_totag)))
- match = 0;
- }
-
- if (!match) {
- ast_mutex_unlock(&sip_pvt_ptr->lock);
- continue;
- }
-
- if (option_debug > 3 && totag)
- ast_log(LOG_DEBUG, "Matched %s call - their tag is %s Our tag is %s\n",
- ast_test_flag(&sip_pvt_ptr->flags[1], SIP_PAGE2_OUTGOING_CALL) ? "OUTGOING": "INCOMING",
- sip_pvt_ptr->theirtag, sip_pvt_ptr->tag);
-
- /* deadlock avoidance... */
- while (sip_pvt_ptr->owner && ast_channel_trylock(sip_pvt_ptr->owner)) {
- DEADLOCK_AVOIDANCE(&sip_pvt_ptr->lock);
- }
- break;
- }
- }
- ast_mutex_unlock(&iflock);
- if (option_debug > 3 && !sip_pvt_ptr)
- ast_log(LOG_DEBUG, "Found no match for callid %s to-tag %s from-tag %s\n", callid, totag, fromtag);
- return sip_pvt_ptr;
-}
-
-/*! \brief Call transfer support (the REFER method)
- * Extracts Refer headers into pvt dialog structure */
-static int get_refer_info(struct sip_pvt *transferer, struct sip_request *outgoing_req)
-{
-
- const char *p_referred_by = NULL;
- char *h_refer_to = NULL;
- char *h_referred_by = NULL;
- char *refer_to;
- const char *p_refer_to;
- char *referred_by_uri = NULL;
- char *ptr;
- struct sip_request *req = NULL;
- const char *transfer_context = NULL;
- struct sip_refer *referdata;
-
-
- req = outgoing_req;
- referdata = transferer->refer;
-
- if (!req)
- req = &transferer->initreq;
-
- p_refer_to = get_header(req, "Refer-To");
- if (ast_strlen_zero(p_refer_to)) {
- ast_log(LOG_WARNING, "Refer-To Header missing. Skipping transfer.\n");
- return -2; /* Syntax error */
- }
- h_refer_to = ast_strdupa(p_refer_to);
- refer_to = get_in_brackets(h_refer_to);
- if (pedanticsipchecking)
- ast_uri_decode(refer_to);
-
- if (strncasecmp(refer_to, "sip:", 4)) {
- ast_log(LOG_WARNING, "Can't transfer to non-sip: URI. (Refer-to: %s)?\n", refer_to);
- return -3;
- }
- refer_to += 4; /* Skip sip: */
-
- /* Get referred by header if it exists */
- p_referred_by = get_header(req, "Referred-By");
- if (!ast_strlen_zero(p_referred_by)) {
- char *lessthan;
- h_referred_by = ast_strdupa(p_referred_by);
- if (pedanticsipchecking)
- ast_uri_decode(h_referred_by);
-
- /* Store referrer's caller ID name */
- ast_copy_string(referdata->referred_by_name, h_referred_by, sizeof(referdata->referred_by_name));
- if ((lessthan = strchr(referdata->referred_by_name, '<'))) {
- *(lessthan - 1) = '\0'; /* Space */
- }
-
- referred_by_uri = get_in_brackets(h_referred_by);
- if(strncasecmp(referred_by_uri, "sip:", 4)) {
- ast_log(LOG_WARNING, "Huh? Not a sip: header (Referred-by: %s). Skipping.\n", referred_by_uri);
- referred_by_uri = (char *) NULL;
- } else {
- referred_by_uri += 4; /* Skip sip: */
- }
- }
-
- /* Check for arguments in the refer_to header */
- if ((ptr = strchr(refer_to, '?'))) { /* Search for arguments */
- *ptr++ = '\0';
- if (!strncasecmp(ptr, "REPLACES=", 9)) {
- char *to = NULL, *from = NULL;
-
- /* This is an attended transfer */
- referdata->attendedtransfer = 1;
- ast_copy_string(referdata->replaces_callid, ptr+9, sizeof(referdata->replaces_callid));
- ast_uri_decode(referdata->replaces_callid);
- if ((ptr = strchr(referdata->replaces_callid, ';'))) /* Find options */ {
- *ptr++ = '\0';
- }
-
- if (ptr) {
- /* Find the different tags before we destroy the string */
- to = strcasestr(ptr, "to-tag=");
- from = strcasestr(ptr, "from-tag=");
- }
-
- /* Grab the to header */
- if (to) {
- ptr = to + 7;
- if ((to = strchr(ptr, '&')))
- *to = '\0';
- if ((to = strchr(ptr, ';')))
- *to = '\0';
- ast_copy_string(referdata->replaces_callid_totag, ptr, sizeof(referdata->replaces_callid_totag));
- }
-
- if (from) {
- ptr = from + 9;
- if ((to = strchr(ptr, '&')))
- *to = '\0';
- if ((to = strchr(ptr, ';')))
- *to = '\0';
- ast_copy_string(referdata->replaces_callid_fromtag, ptr, sizeof(referdata->replaces_callid_fromtag));
- }
-
- if (option_debug > 1) {
- if (!pedanticsipchecking)
- ast_log(LOG_DEBUG,"Attended transfer: Will use Replace-Call-ID : %s (No check of from/to tags)\n", referdata->replaces_callid );
- else
- ast_log(LOG_DEBUG,"Attended transfer: Will use Replace-Call-ID : %s F-tag: %s T-tag: %s\n", referdata->replaces_callid, referdata->replaces_callid_fromtag ? referdata->replaces_callid_fromtag : "<none>", referdata->replaces_callid_totag ? referdata->replaces_callid_totag : "<none>" );
- }
- }
- }
-
- if ((ptr = strchr(refer_to, '@'))) { /* Separate domain */
- char *urioption = NULL, *domain;
- *ptr++ = '\0';
-
- if ((urioption = strchr(ptr, ';'))) /* Separate urioptions */
- *urioption++ = '\0';
-
- domain = ptr;
- if ((ptr = strchr(domain, ':'))) /* Remove :port */
- *ptr = '\0';
-
- /* Save the domain for the dial plan */
- ast_copy_string(referdata->refer_to_domain, domain, sizeof(referdata->refer_to_domain));
- if (urioption)
- ast_copy_string(referdata->refer_to_urioption, urioption, sizeof(referdata->refer_to_urioption));
- }
-
- if ((ptr = strchr(refer_to, ';'))) /* Remove options */
- *ptr = '\0';
- ast_copy_string(referdata->refer_to, refer_to, sizeof(referdata->refer_to));
-
- if (referred_by_uri) {
- if ((ptr = strchr(referred_by_uri, ';'))) /* Remove options */
- *ptr = '\0';
- ast_copy_string(referdata->referred_by, referred_by_uri, sizeof(referdata->referred_by));
- } else {
- referdata->referred_by[0] = '\0';
- }
-
- /* Determine transfer context */
- if (transferer->owner) /* Mimic behaviour in res_features.c */
- transfer_context = pbx_builtin_getvar_helper(transferer->owner, "TRANSFER_CONTEXT");
-
- /* By default, use the context in the channel sending the REFER */
- if (ast_strlen_zero(transfer_context)) {
- transfer_context = S_OR(transferer->owner->macrocontext,
- S_OR(transferer->context, default_context));
- }
-
- ast_copy_string(referdata->refer_to_context, transfer_context, sizeof(referdata->refer_to_context));
-
- /* Either an existing extension or the parking extension */
- if (ast_exists_extension(NULL, transfer_context, refer_to, 1, NULL) ) {
- if (sip_debug_test_pvt(transferer)) {
- ast_verbose("SIP transfer to extension %s@%s by %s\n", refer_to, transfer_context, referred_by_uri);
- }
- /* We are ready to transfer to the extension */
- return 0;
- }
- if (sip_debug_test_pvt(transferer))
- ast_verbose("Failed SIP Transfer to non-existing extension %s in context %s\n n", refer_to, transfer_context);
-
- /* Failure, we can't find this extension */
- return -1;
-}
-
-
-/*! \brief Call transfer support (old way, deprecated by the IETF)--*/
-static int get_also_info(struct sip_pvt *p, struct sip_request *oreq)
-{
- char tmp[256] = "", *c, *a;
- struct sip_request *req = oreq ? oreq : &p->initreq;
- struct sip_refer *referdata = NULL;
- const char *transfer_context = NULL;
-
- if (!p->refer && !sip_refer_allocate(p))
- return -1;
-
- referdata = p->refer;
-
- ast_copy_string(tmp, get_header(req, "Also"), sizeof(tmp));
- c = get_in_brackets(tmp);
-
- if (pedanticsipchecking)
- ast_uri_decode(c);
-
- if (strncasecmp(c, "sip:", 4)) {
- ast_log(LOG_WARNING, "Huh? Not a SIP header in Also: transfer (%s)?\n", c);
- return -1;
- }
- c += 4;
- if ((a = strchr(c, ';'))) /* Remove arguments */
- *a = '\0';
-
- if ((a = strchr(c, '@'))) { /* Separate Domain */
- *a++ = '\0';
- ast_copy_string(referdata->refer_to_domain, a, sizeof(referdata->refer_to_domain));
- }
-
- if (sip_debug_test_pvt(p))
- ast_verbose("Looking for %s in %s\n", c, p->context);
-
- if (p->owner) /* Mimic behaviour in res_features.c */
- transfer_context = pbx_builtin_getvar_helper(p->owner, "TRANSFER_CONTEXT");
-
- /* By default, use the context in the channel sending the REFER */
- if (ast_strlen_zero(transfer_context)) {
- transfer_context = S_OR(p->owner->macrocontext,
- S_OR(p->context, default_context));
- }
- if (ast_exists_extension(NULL, transfer_context, c, 1, NULL)) {
- /* This is a blind transfer */
- if (option_debug)
- ast_log(LOG_DEBUG,"SIP Bye-also transfer to Extension %s@%s \n", c, transfer_context);
- ast_copy_string(referdata->refer_to, c, sizeof(referdata->refer_to));
- ast_copy_string(referdata->referred_by, "", sizeof(referdata->referred_by));
- ast_copy_string(referdata->refer_contact, "", sizeof(referdata->refer_contact));
- referdata->refer_call = NULL;
- /* Set new context */
- ast_string_field_set(p, context, transfer_context);
- return 0;
- } else if (ast_canmatch_extension(NULL, p->context, c, 1, NULL)) {
- return 1;
- }
-
- return -1;
-}
-/*! \brief check Via: header for hostname, port and rport request/answer */
-static void check_via(struct sip_pvt *p, const struct sip_request *req)
-{
- char via[512];
- char *c, *pt;
- struct hostent *hp;
- struct ast_hostent ahp;
-
- ast_copy_string(via, get_header(req, "Via"), sizeof(via));
-
- /* Work on the leftmost value of the topmost Via header */
- c = strchr(via, ',');
- if (c)
- *c = '\0';
-
- /* Check for rport */
- c = strstr(via, ";rport");
- if (c && (c[6] != '=')) /* rport query, not answer */
- ast_set_flag(&p->flags[0], SIP_NAT_ROUTE);
-
- c = strchr(via, ';');
- if (c)
- *c = '\0';
-
- c = strchr(via, ' ');
- if (c) {
- *c = '\0';
- c = ast_skip_blanks(c+1);
- if (strcasecmp(via, "SIP/2.0/UDP")) {
- ast_log(LOG_WARNING, "Don't know how to respond via '%s'\n", via);
- return;
- }
- pt = strchr(c, ':');
- if (pt)
- *pt++ = '\0'; /* remember port pointer */
- hp = ast_gethostbyname(c, &ahp);
- if (!hp) {
- ast_log(LOG_WARNING, "'%s' is not a valid host\n", c);
- return;
- }
- memset(&p->sa, 0, sizeof(p->sa));
- p->sa.sin_family = AF_INET;
- memcpy(&p->sa.sin_addr, hp->h_addr, sizeof(p->sa.sin_addr));
- p->sa.sin_port = htons(pt ? atoi(pt) : STANDARD_SIP_PORT);
-
- if (sip_debug_test_pvt(p)) {
- const struct sockaddr_in *dst = sip_real_dst(p);
- ast_verbose("Sending to %s : %d (%s)\n", ast_inet_ntoa(dst->sin_addr), ntohs(dst->sin_port), sip_nat_mode(p));
- }
- }
-}
-
-/*! \brief Get caller id name from SIP headers */
-static char *get_calleridname(const char *input, char *output, size_t outputsize)
-{
- const char *end = strchr(input,'<'); /* first_bracket */
- const char *tmp = strchr(input,'"'); /* first quote */
- int bytes = 0;
- int maxbytes = outputsize - 1;
-
- if (!end || end == input) /* we require a part in brackets */
- return NULL;
-
- end--; /* move just before "<" */
-
- if (tmp && tmp <= end) {
- /* The quote (tmp) precedes the bracket (end+1).
- * Find the matching quote and return the content.
- */
- end = strchr(tmp+1, '"');
- if (!end)
- return NULL;
- bytes = (int) (end - tmp);
- /* protect the output buffer */
- if (bytes > maxbytes)
- bytes = maxbytes;
- ast_copy_string(output, tmp + 1, bytes);
- } else {
- /* No quoted string, or it is inside brackets. */
- /* clear the empty characters in the begining*/
- input = ast_skip_blanks(input);
- /* clear the empty characters in the end */
- while(*end && *end < 33 && end > input)
- end--;
- if (end >= input) {
- bytes = (int) (end - input) + 2;
- /* protect the output buffer */
- if (bytes > maxbytes)
- bytes = maxbytes;
- ast_copy_string(output, input, bytes);
- } else
- return NULL;
- }
- return output;
-}
-
-/*! \brief Get caller id number from Remote-Party-ID header field
- * Returns true if number should be restricted (privacy setting found)
- * output is set to NULL if no number found
- */
-static int get_rpid_num(const char *input, char *output, int maxlen)
-{
- char *start;
- char *end;
-
- start = strchr(input,':');
- if (!start) {
- output[0] = '\0';
- return 0;
- }
- start++;
-
- /* we found "number" */
- ast_copy_string(output,start,maxlen);
- output[maxlen-1] = '\0';
-
- end = strchr(output,'@');
- if (end)
- *end = '\0';
- else
- output[0] = '\0';
- if (strstr(input,"privacy=full") || strstr(input,"privacy=uri"))
- return AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED;
-
- return 0;
-}
-
-
-/*! \brief Check if matching user or peer is defined
- Match user on From: user name and peer on IP/port
- This is used on first invite (not re-invites) and subscribe requests
- \return 0 on success, non-zero on failure
-*/
-static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_request *req,
- int sipmethod, char *uri, enum xmittype reliable,
- struct sockaddr_in *sin, struct sip_peer **authpeer)
-{
- struct sip_user *user = NULL;
- struct sip_peer *peer;
- char from[256], *c;
- char *of;
- char rpid_num[50];
- const char *rpid;
- enum check_auth_result res = AUTH_SUCCESSFUL;
- char *t;
- char calleridname[50];
- int debug=sip_debug_test_addr(sin);
- struct ast_variable *tmpvar = NULL, *v = NULL;
- char *uri2 = ast_strdupa(uri);
-
- /* Terminate URI */
- t = uri2;
- while (*t && *t > 32 && *t != ';')
- t++;
- *t = '\0';
- ast_copy_string(from, get_header(req, "From"), sizeof(from)); /* XXX bug in original code, overwrote string */
- if (pedanticsipchecking)
- ast_uri_decode(from);
- /* XXX here tries to map the username for invite things */
- memset(calleridname, 0, sizeof(calleridname));
- get_calleridname(from, calleridname, sizeof(calleridname));
- if (calleridname[0])
- ast_string_field_set(p, cid_name, calleridname);
-
- rpid = get_header(req, "Remote-Party-ID");
- memset(rpid_num, 0, sizeof(rpid_num));
- if (!ast_strlen_zero(rpid))
- p->callingpres = get_rpid_num(rpid, rpid_num, sizeof(rpid_num));
-
- of = get_in_brackets(from);
- if (ast_strlen_zero(p->exten)) {
- t = uri2;
- if (!strncasecmp(t, "sip:", 4))
- t+= 4;
- ast_string_field_set(p, exten, t);
- t = strchr(p->exten, '@');
- if (t)
- *t = '\0';
- if (ast_strlen_zero(p->our_contact))
- build_contact(p);
- }
- /* save the URI part of the From header */
- ast_string_field_set(p, from, of);
- if (strncasecmp(of, "sip:", 4)) {
- ast_log(LOG_NOTICE, "From address missing 'sip:', using it anyway\n");
- } else
- of += 4;
- /* Get just the username part */
- if ((c = strchr(of, '@'))) {
- char *tmp;
- *c = '\0';
- if ((c = strchr(of, ':')))
- *c = '\0';
- tmp = ast_strdupa(of);
- /* We need to be able to handle auth-headers looking like
- <sip:8164444422;phone-context=+1@1.2.3.4:5060;user=phone;tag=SDadkoa01-gK0c3bdb43>
- */
- tmp = strsep(&tmp, ";");
- if (ast_is_shrinkable_phonenumber(tmp))
- ast_shrink_phone_number(tmp);
- ast_string_field_set(p, cid_num, tmp);
- }
-
- if (!authpeer) /* If we are looking for a peer, don't check the user objects (or realtime) */
- user = find_user(of, 1);
-
- /* Find user based on user name in the from header */
- if (user && ast_apply_ha(user->ha, sin)) {
- ast_copy_flags(&p->flags[0], &user->flags[0], SIP_FLAGS_TO_COPY);
- ast_copy_flags(&p->flags[1], &user->flags[1], SIP_PAGE2_FLAGS_TO_COPY);
- if (sipmethod == SIP_INVITE) {
- /* copy channel vars */
- for (v = user->chanvars ; v ; v = v->next) {
- if ((tmpvar = ast_variable_new(v->name, v->value))) {
- tmpvar->next = p->chanvars;
- p->chanvars = tmpvar;
- }
- }
- }
- p->prefs = user->prefs;
- /* Set Frame packetization */
- if (p->rtp) {
- ast_rtp_codec_setpref(p->rtp, &p->prefs);
- p->autoframing = user->autoframing;
- }
- /* replace callerid if rpid found, and not restricted */
- if (!ast_strlen_zero(rpid_num) && ast_test_flag(&p->flags[0], SIP_TRUSTRPID)) {
- char *tmp;
- if (*calleridname)
- ast_string_field_set(p, cid_name, calleridname);
- tmp = ast_strdupa(rpid_num);
- if (ast_is_shrinkable_phonenumber(tmp))
- ast_shrink_phone_number(tmp);
- ast_string_field_set(p, cid_num, tmp);
- }
-
- do_setnat(p, ast_test_flag(&p->flags[0], SIP_NAT_ROUTE) );
-
- if (!(res = check_auth(p, req, user->name, user->secret, user->md5secret, sipmethod, uri2, reliable, ast_test_flag(req, SIP_PKT_IGNORE)))) {
- if (sip_cancel_destroy(p))
- ast_log(LOG_WARNING, "Unable to cancel SIP destruction. Expect bad things.\n");
- ast_copy_flags(&p->flags[0], &user->flags[0], SIP_FLAGS_TO_COPY);
- ast_copy_flags(&p->flags[1], &user->flags[1], SIP_PAGE2_FLAGS_TO_COPY);
- /* Copy SIP extensions profile from INVITE */
- if (p->sipoptions)
- user->sipoptions = p->sipoptions;
-
- /* If we have a call limit, set flag */
- if (user->call_limit)
- ast_set_flag(&p->flags[0], SIP_CALL_LIMIT);
- if (!ast_strlen_zero(user->context))
- ast_string_field_set(p, context, user->context);
- if (!ast_strlen_zero(user->cid_num)) {
- char *tmp = ast_strdupa(user->cid_num);
- if (ast_is_shrinkable_phonenumber(tmp))
- ast_shrink_phone_number(tmp);
- ast_string_field_set(p, cid_num, tmp);
- }
- if (!ast_strlen_zero(user->cid_name))
- ast_string_field_set(p, cid_name, user->cid_name);
- ast_string_field_set(p, username, user->name);
- ast_string_field_set(p, peername, user->name);
- ast_string_field_set(p, peersecret, user->secret);
- ast_string_field_set(p, peermd5secret, user->md5secret);
- ast_string_field_set(p, subscribecontext, user->subscribecontext);
- ast_string_field_set(p, accountcode, user->accountcode);
- ast_string_field_set(p, language, user->language);
- ast_string_field_set(p, mohsuggest, user->mohsuggest);
- ast_string_field_set(p, mohinterpret, user->mohinterpret);
- p->allowtransfer = user->allowtransfer;
- p->amaflags = user->amaflags;
- p->callgroup = user->callgroup;
- p->pickupgroup = user->pickupgroup;
- if (user->callingpres) /* User callingpres setting will override RPID header */
- p->callingpres = user->callingpres;
-
- /* Set default codec settings for this call */
- p->capability = user->capability; /* User codec choice */
- p->jointcapability = user->capability; /* Our codecs */
- if (p->peercapability) /* AND with peer's codecs */
- p->jointcapability &= p->peercapability;
- if ((ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833) ||
- (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_AUTO))
- p->noncodeccapability |= AST_RTP_DTMF;
- else
- p->noncodeccapability &= ~AST_RTP_DTMF;
- p->jointnoncodeccapability = p->noncodeccapability;
- if (p->t38.peercapability)
- p->t38.jointcapability &= p->t38.peercapability;
- p->maxcallbitrate = user->maxcallbitrate;
- /* If we do not support video, remove video from call structure */
- if ((!ast_test_flag(&p->flags[1], SIP_PAGE2_VIDEOSUPPORT) || !(p->capability & AST_FORMAT_VIDEO_MASK)) && p->vrtp) {
- ast_rtp_destroy(p->vrtp);
- p->vrtp = NULL;
- }
- }
- if (user && debug)
- ast_verbose("Found user '%s'\n", user->name);
- } else {
- if (user) {
- if (!authpeer && debug)
- ast_verbose("Found user '%s', but fails host access\n", user->name);
- ASTOBJ_UNREF(user,sip_destroy_user);
- }
- user = NULL;
- }
-
- if (!user) {
- /* If we didn't find a user match, check for peers */
- if (sipmethod == SIP_SUBSCRIBE)
- /* For subscribes, match on peer name only */
- peer = find_peer(of, NULL, 1, 0);
- else
- /* Look for peer based on the IP address we received data from */
- /* If peer is registered from this IP address or have this as a default
- IP address, this call is from the peer
- */
- peer = find_peer(NULL, &p->recv, 1, 0);
-
- if (peer) {
- /* Set Frame packetization */
- if (p->rtp) {
- ast_rtp_codec_setpref(p->rtp, &peer->prefs);
- p->autoframing = peer->autoframing;
- }
- if (debug)
- ast_verbose("Found peer '%s'\n", peer->name);
-
- /* 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);
-
- /* Copy SIP extensions profile to peer */
- if (p->sipoptions)
- peer->sipoptions = p->sipoptions;
-
- /* replace callerid if rpid found, and not restricted */
- if (!ast_strlen_zero(rpid_num) && ast_test_flag(&p->flags[0], SIP_TRUSTRPID)) {
- char *tmp = ast_strdupa(rpid_num);
- if (*calleridname)
- ast_string_field_set(p, cid_name, calleridname);
- if (ast_is_shrinkable_phonenumber(tmp))
- ast_shrink_phone_number(tmp);
- ast_string_field_set(p, cid_num, tmp);
- }
- do_setnat(p, ast_test_flag(&p->flags[0], SIP_NAT_ROUTE));
-
- ast_string_field_set(p, peersecret, peer->secret);
- ast_string_field_set(p, peermd5secret, peer->md5secret);
- ast_string_field_set(p, subscribecontext, peer->subscribecontext);
- ast_string_field_set(p, mohinterpret, peer->mohinterpret);
- ast_string_field_set(p, mohsuggest, peer->mohsuggest);
- if (peer->callingpres) /* Peer calling pres setting will override RPID */
- p->callingpres = peer->callingpres;
- if (peer->maxms && peer->lastms)
- p->timer_t1 = peer->lastms < global_t1min ? global_t1min : peer->lastms;
- if (ast_test_flag(&peer->flags[0], SIP_INSECURE_INVITE)) {
- /* Pretend there is no required authentication */
- ast_string_field_free(p, peersecret);
- ast_string_field_free(p, peermd5secret);
- }
- if (!(res = check_auth(p, req, peer->name, p->peersecret, p->peermd5secret, sipmethod, uri2, reliable, ast_test_flag(req, SIP_PKT_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);
- /* If we have a call limit, set flag */
- if (peer->call_limit)
- ast_set_flag(&p->flags[0], SIP_CALL_LIMIT);
- ast_string_field_set(p, peername, peer->name);
- ast_string_field_set(p, authname, peer->name);
-
- if (sipmethod == SIP_INVITE) {
- /* copy channel vars */
- for (v = peer->chanvars ; v ; v = v->next) {
- if ((tmpvar = ast_variable_new(v->name, v->value))) {
- tmpvar->next = p->chanvars;
- p->chanvars = tmpvar;
- }
- }
- }
- if (authpeer) {
- (*authpeer) = ASTOBJ_REF(peer); /* Add a ref to the object here, to keep it in memory a bit longer if it is realtime */
- }
-
- if (!ast_strlen_zero(peer->username)) {
- ast_string_field_set(p, username, peer->username);
- /* Use the default username for authentication on outbound calls */
- /* XXX this takes the name from the caller... can we override ? */
- ast_string_field_set(p, authname, peer->username);
- }
- if (!ast_strlen_zero(peer->cid_num)) {
- char *tmp = ast_strdupa(peer->cid_num);
- if (ast_is_shrinkable_phonenumber(tmp))
- ast_shrink_phone_number(tmp);
- ast_string_field_set(p, cid_num, tmp);
- }
- if (!ast_strlen_zero(peer->cid_name))
- ast_string_field_set(p, cid_name, peer->cid_name);
- ast_string_field_set(p, fullcontact, peer->fullcontact);
- if (!ast_strlen_zero(peer->context))
- ast_string_field_set(p, context, peer->context);
- ast_string_field_set(p, peersecret, peer->secret);
- ast_string_field_set(p, peermd5secret, peer->md5secret);
- ast_string_field_set(p, language, peer->language);
- ast_string_field_set(p, accountcode, peer->accountcode);
- p->amaflags = peer->amaflags;
- p->callgroup = peer->callgroup;
- p->pickupgroup = peer->pickupgroup;
- p->capability = peer->capability;
- p->prefs = peer->prefs;
- p->jointcapability = peer->capability;
- if (p->peercapability)
- p->jointcapability &= p->peercapability;
- p->maxcallbitrate = peer->maxcallbitrate;
- if ((!ast_test_flag(&p->flags[1], SIP_PAGE2_VIDEOSUPPORT) || !(p->capability & AST_FORMAT_VIDEO_MASK)) && p->vrtp) {
- ast_rtp_destroy(p->vrtp);
- p->vrtp = NULL;
- }
- if ((ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833) ||
- (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_AUTO))
- p->noncodeccapability |= AST_RTP_DTMF;
- else
- p->noncodeccapability &= ~AST_RTP_DTMF;
- p->jointnoncodeccapability = p->noncodeccapability;
- if (p->t38.peercapability)
- p->t38.jointcapability &= p->t38.peercapability;
- }
- ASTOBJ_UNREF(peer, sip_destroy_peer);
- } else {
- if (debug)
- ast_verbose("Found no matching peer or user for '%s:%d'\n", ast_inet_ntoa(p->recv.sin_addr), ntohs(p->recv.sin_port));
-
- /* do we allow guests? */
- if (!global_allowguest) {
- if (global_alwaysauthreject)
- res = AUTH_FAKE_AUTH; /* reject with fake authorization request */
- else
- res = AUTH_SECRET_FAILED; /* we don't want any guests, authentication will fail */
- } else if (!ast_strlen_zero(rpid_num) && ast_test_flag(&p->flags[0], SIP_TRUSTRPID)) {
- char *tmp = ast_strdupa(rpid_num);
- if (*calleridname)
- ast_string_field_set(p, cid_name, calleridname);
- if (ast_is_shrinkable_phonenumber(tmp))
- ast_shrink_phone_number(tmp);
- ast_string_field_set(p, cid_num, tmp);
- }
- }
-
- }
-
- if (user)
- ASTOBJ_UNREF(user, sip_destroy_user);
- return res;
-}
-
-/*! \brief Find user
- If we get a match, this will add a reference pointer to the user object in ASTOBJ, that needs to be unreferenced
-*/
-static int check_user(struct sip_pvt *p, struct sip_request *req, int sipmethod, char *uri, enum xmittype reliable, struct sockaddr_in *sin)
-{
- return check_user_full(p, req, sipmethod, uri, reliable, sin, NULL);
-}
-
-/*! \brief Get text out of a SIP MESSAGE packet */
-static int get_msg_text(char *buf, int len, struct sip_request *req)
-{
- int x;
- int y;
-
- buf[0] = '\0';
- y = len - strlen(buf) - 5;
- if (y < 0)
- y = 0;
- for (x=0;x<req->lines;x++) {
- strncat(buf, req->line[x], y); /* safe */
- y -= strlen(req->line[x]) + 1;
- if (y < 0)
- y = 0;
- if (y != 0)
- strcat(buf, "\n"); /* safe */
- }
- return 0;
-}
-
-
-/*! \brief Receive SIP MESSAGE method messages
-\note We only handle messages within current calls currently
- Reference: RFC 3428 */
-static void receive_message(struct sip_pvt *p, struct sip_request *req)
-{
- char buf[1024];
- struct ast_frame f;
- const char *content_type = get_header(req, "Content-Type");
-
- if (strncmp(content_type, "text/plain", strlen("text/plain"))) { /* No text/plain attachment */
- transmit_response(p, "415 Unsupported Media Type", req); /* Good enough, or? */
- if (!p->owner)
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- return;
- }
-
- if (get_msg_text(buf, sizeof(buf), req)) {
- ast_log(LOG_WARNING, "Unable to retrieve text from %s\n", p->callid);
- transmit_response(p, "202 Accepted", req);
- if (!p->owner)
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- return;
- }
-
- if (p->owner) {
- if (sip_debug_test_pvt(p))
- ast_verbose("Message received: '%s'\n", buf);
- memset(&f, 0, sizeof(f));
- f.frametype = AST_FRAME_TEXT;
- f.subclass = 0;
- f.offset = 0;
- f.data = buf;
- f.datalen = strlen(buf);
- ast_queue_frame(p->owner, &f);
- transmit_response(p, "202 Accepted", req); /* We respond 202 accepted, since we relay the message */
- } else { /* Message outside of a call, we do not support that */
- ast_log(LOG_WARNING,"Received message to %s from %s, dropped it...\n Content-Type:%s\n Message: %s\n", get_header(req,"To"), get_header(req,"From"), content_type, buf);
- transmit_response(p, "405 Method Not Allowed", req); /* Good enough, or? */
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- }
- return;
-}
-
-/*! \brief CLI Command to show calls within limits set by call_limit */
-static int sip_show_inuse(int fd, int argc, char *argv[])
-{
-#define FORMAT "%-25.25s %-15.15s %-15.15s \n"
-#define FORMAT2 "%-25.25s %-15.15s %-15.15s \n"
- char ilimits[40];
- char iused[40];
- int showall = FALSE;
-
- if (argc < 3)
- return RESULT_SHOWUSAGE;
-
- if (argc == 4 && !strcmp(argv[3],"all"))
- showall = TRUE;
-
- ast_cli(fd, FORMAT, "* User name", "In use", "Limit");
- ASTOBJ_CONTAINER_TRAVERSE(&userl, 1, do {
- ASTOBJ_RDLOCK(iterator);
- if (iterator->call_limit)
- snprintf(ilimits, sizeof(ilimits), "%d", iterator->call_limit);
- else
- ast_copy_string(ilimits, "N/A", sizeof(ilimits));
- snprintf(iused, sizeof(iused), "%d", iterator->inUse);
- if (showall || iterator->call_limit)
- ast_cli(fd, FORMAT2, iterator->name, iused, ilimits);
- ASTOBJ_UNLOCK(iterator);
- } while (0) );
-
- ast_cli(fd, FORMAT, "* Peer name", "In use", "Limit");
-
- ASTOBJ_CONTAINER_TRAVERSE(&peerl, 1, do {
- ASTOBJ_RDLOCK(iterator);
- if (iterator->call_limit)
- snprintf(ilimits, sizeof(ilimits), "%d", iterator->call_limit);
- else
- ast_copy_string(ilimits, "N/A", sizeof(ilimits));
- snprintf(iused, sizeof(iused), "%d/%d", iterator->inUse, iterator->inRinging);
- if (showall || iterator->call_limit)
- ast_cli(fd, FORMAT2, iterator->name, iused, ilimits);
- ASTOBJ_UNLOCK(iterator);
- } while (0) );
-
- return RESULT_SUCCESS;
-#undef FORMAT
-#undef FORMAT2
-}
-
-/*! \brief Convert transfer mode to text string */
-static char *transfermode2str(enum transfermodes mode)
-{
- if (mode == TRANSFER_OPENFORALL)
- return "open";
- else if (mode == TRANSFER_CLOSED)
- return "closed";
- return "strict";
-}
-
-/*! \brief Convert NAT setting to text string */
-static char *nat2str(int nat)
-{
- switch(nat) {
- case SIP_NAT_NEVER:
- return "No";
- case SIP_NAT_ROUTE:
- return "Route";
- case SIP_NAT_ALWAYS:
- return "Always";
- case SIP_NAT_RFC3581:
- return "RFC3581";
- default:
- return "Unknown";
- }
-}
-
-/*! \brief Report Peer status in character string
- * \return 0 if peer is unreachable, 1 if peer is online, -1 if unmonitored
- */
-static int peer_status(struct sip_peer *peer, char *status, int statuslen)
-{
- int res = 0;
- if (peer->maxms) {
- if (peer->lastms < 0) {
- ast_copy_string(status, "UNREACHABLE", statuslen);
- } else if (peer->lastms > peer->maxms) {
- snprintf(status, statuslen, "LAGGED (%d ms)", peer->lastms);
- res = 1;
- } else if (peer->lastms) {
- snprintf(status, statuslen, "OK (%d ms)", peer->lastms);
- res = 1;
- } else {
- ast_copy_string(status, "UNKNOWN", statuslen);
- }
- } else {
- ast_copy_string(status, "Unmonitored", statuslen);
- /* Checking if port is 0 */
- res = -1;
- }
- return res;
-}
-
-/*! \brief CLI Command 'SIP Show Users' */
-static int sip_show_users(int fd, int argc, char *argv[])
-{
- regex_t regexbuf;
- int havepattern = FALSE;
-
-#define FORMAT "%-25.25s %-15.15s %-15.15s %-15.15s %-5.5s%-10.10s\n"
-
- switch (argc) {
- case 5:
- if (!strcasecmp(argv[3], "like")) {
- if (regcomp(&regexbuf, argv[4], REG_EXTENDED | REG_NOSUB))
- return RESULT_SHOWUSAGE;
- havepattern = TRUE;
- } else
- return RESULT_SHOWUSAGE;
- case 3:
- break;
- default:
- return RESULT_SHOWUSAGE;
- }
-
- ast_cli(fd, FORMAT, "Username", "Secret", "Accountcode", "Def.Context", "ACL", "NAT");
- ASTOBJ_CONTAINER_TRAVERSE(&userl, 1, do {
- ASTOBJ_RDLOCK(iterator);
-
- if (havepattern && regexec(&regexbuf, iterator->name, 0, NULL, 0)) {
- ASTOBJ_UNLOCK(iterator);
- continue;
- }
-
- ast_cli(fd, FORMAT, iterator->name,
- iterator->secret,
- iterator->accountcode,
- iterator->context,
- iterator->ha ? "Yes" : "No",
- nat2str(ast_test_flag(&iterator->flags[0], SIP_NAT)));
- ASTOBJ_UNLOCK(iterator);
- } while (0)
- );
-
- if (havepattern)
- regfree(&regexbuf);
-
- return RESULT_SUCCESS;
-#undef FORMAT
-}
-
-static char mandescr_show_peers[] =
-"Description: Lists SIP peers in text format with details on current status.\n"
-"Variables: \n"
-" ActionID: <id> Action ID for this transaction. Will be returned.\n";
-
-/*! \brief Show SIP peers in the manager API */
-/* Inspired from chan_iax2 */
-static int manager_sip_show_peers(struct mansession *s, const struct message *m)
-{
- const char *id = astman_get_header(m,"ActionID");
- const char *a[] = {"sip", "show", "peers"};
- char idtext[256] = "";
- int total = 0;
-
- if (!ast_strlen_zero(id))
- snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id);
-
- astman_send_ack(s, m, "Peer status list will follow");
- /* List the peers in separate manager events */
- _sip_show_peers(-1, &total, s, m, 3, a);
- /* Send final confirmation */
- astman_append(s,
- "Event: PeerlistComplete\r\n"
- "ListItems: %d\r\n"
- "%s"
- "\r\n", total, idtext);
- return 0;
-}
-
-/*! \brief CLI Show Peers command */
-static int sip_show_peers(int fd, int argc, char *argv[])
-{
- return _sip_show_peers(fd, NULL, NULL, NULL, argc, (const char **) argv);
-}
-
-/*! \brief _sip_show_peers: Execute sip show peers command */
-static int _sip_show_peers(int fd, int *total, struct mansession *s, const struct message *m, int argc, const char *argv[])
-{
- regex_t regexbuf;
- int havepattern = FALSE;
-
-#define FORMAT2 "%-25.25s %-15.15s %-3.3s %-3.3s %-3.3s %-8s %-10s %-10s\n"
-#define FORMAT "%-25.25s %-15.15s %-3.3s %-3.3s %-3.3s %-8d %-10s %-10s\n"
-
- char name[256];
- int total_peers = 0;
- int peers_mon_online = 0;
- int peers_mon_offline = 0;
- int peers_unmon_offline = 0;
- int peers_unmon_online = 0;
- const char *id;
- char idtext[256] = "";
- int realtimepeers;
-
- realtimepeers = ast_check_realtime("sippeers");
-
- if (s) { /* Manager - get ActionID */
- id = astman_get_header(m,"ActionID");
- if (!ast_strlen_zero(id))
- snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id);
- }
-
- switch (argc) {
- case 5:
- if (!strcasecmp(argv[3], "like")) {
- if (regcomp(&regexbuf, argv[4], REG_EXTENDED | REG_NOSUB))
- return RESULT_SHOWUSAGE;
- havepattern = TRUE;
- } else
- return RESULT_SHOWUSAGE;
- case 3:
- break;
- default:
- return RESULT_SHOWUSAGE;
- }
-
- if (!s) /* Normal list */
- ast_cli(fd, FORMAT2, "Name/username", "Host", "Dyn", "Nat", "ACL", "Port", "Status", (realtimepeers ? "Realtime" : ""));
-
- ASTOBJ_CONTAINER_TRAVERSE(&peerl, 1, do {
- char status[20] = "";
- char srch[2000];
- char pstatus;
-
- ASTOBJ_RDLOCK(iterator);
-
- if (havepattern && regexec(&regexbuf, iterator->name, 0, NULL, 0)) {
- ASTOBJ_UNLOCK(iterator);
- continue;
- }
-
- if (!ast_strlen_zero(iterator->username) && !s)
- snprintf(name, sizeof(name), "%s/%s", iterator->name, iterator->username);
- else
- ast_copy_string(name, iterator->name, sizeof(name));
-
- pstatus = peer_status(iterator, status, sizeof(status));
- if (pstatus == 1)
- peers_mon_online++;
- else if (pstatus == 0)
- peers_mon_offline++;
- else {
- if (iterator->addr.sin_port == 0)
- peers_unmon_offline++;
- else
- peers_unmon_online++;
- }
-
- snprintf(srch, sizeof(srch), FORMAT, name,
- iterator->addr.sin_addr.s_addr ? ast_inet_ntoa(iterator->addr.sin_addr) : "(Unspecified)",
- ast_test_flag(&iterator->flags[1], SIP_PAGE2_DYNAMIC) ? " D " : " ", /* Dynamic or not? */
- ast_test_flag(&iterator->flags[0], SIP_NAT_ROUTE) ? " N " : " ", /* NAT=yes? */
- iterator->ha ? " A " : " ", /* permit/deny */
- ntohs(iterator->addr.sin_port), status,
- realtimepeers ? (ast_test_flag(&iterator->flags[0], SIP_REALTIME) ? "Cached RT":"") : "");
-
- if (!s) {/* Normal CLI list */
- ast_cli(fd, FORMAT, name,
- iterator->addr.sin_addr.s_addr ? ast_inet_ntoa(iterator->addr.sin_addr) : "(Unspecified)",
- ast_test_flag(&iterator->flags[1], SIP_PAGE2_DYNAMIC) ? " D " : " ", /* Dynamic or not? */
- ast_test_flag(&iterator->flags[0], SIP_NAT_ROUTE) ? " N " : " ", /* NAT=yes? */
- iterator->ha ? " A " : " ", /* permit/deny */
-
- ntohs(iterator->addr.sin_port), status,
- realtimepeers ? (ast_test_flag(&iterator->flags[0], SIP_REALTIME) ? "Cached RT":"") : "");
- } else { /* Manager format */
- /* The names here need to be the same as other channels */
- astman_append(s,
- "Event: PeerEntry\r\n%s"
- "Channeltype: SIP\r\n"
- "ObjectName: %s\r\n"
- "ChanObjectType: peer\r\n" /* "peer" or "user" */
- "IPaddress: %s\r\n"
- "IPport: %d\r\n"
- "Dynamic: %s\r\n"
- "Natsupport: %s\r\n"
- "VideoSupport: %s\r\n"
- "ACL: %s\r\n"
- "Status: %s\r\n"
- "RealtimeDevice: %s\r\n\r\n",
- idtext,
- iterator->name,
- iterator->addr.sin_addr.s_addr ? ast_inet_ntoa(iterator->addr.sin_addr) : "-none-",
- ntohs(iterator->addr.sin_port),
- ast_test_flag(&iterator->flags[1], SIP_PAGE2_DYNAMIC) ? "yes" : "no", /* Dynamic or not? */
- ast_test_flag(&iterator->flags[0], SIP_NAT_ROUTE) ? "yes" : "no", /* NAT=yes? */
- ast_test_flag(&iterator->flags[1], SIP_PAGE2_VIDEOSUPPORT) ? "yes" : "no", /* VIDEOSUPPORT=yes? */
- iterator->ha ? "yes" : "no", /* permit/deny */
- status,
- realtimepeers ? (ast_test_flag(&iterator->flags[0], SIP_REALTIME) ? "yes":"no") : "no");
- }
-
- ASTOBJ_UNLOCK(iterator);
-
- total_peers++;
- } while(0) );
-
- if (!s)
- ast_cli(fd, "%d sip peers [Monitored: %d online, %d offline Unmonitored: %d online, %d offline]\n",
- total_peers, peers_mon_online, peers_mon_offline, peers_unmon_online, peers_unmon_offline);
-
- if (havepattern)
- regfree(&regexbuf);
-
- if (total)
- *total = total_peers;
-
-
- return RESULT_SUCCESS;
-#undef FORMAT
-#undef FORMAT2
-}
-
-/*! \brief List all allocated SIP Objects (realtime or static) */
-static int sip_show_objects(int fd, int argc, char *argv[])
-{
- char tmp[256];
- if (argc != 3)
- return RESULT_SHOWUSAGE;
- ast_cli(fd, "-= User objects: %d static, %d realtime =-\n\n", suserobjs, ruserobjs);
- ASTOBJ_CONTAINER_DUMP(fd, tmp, sizeof(tmp), &userl);
- ast_cli(fd, "-= Peer objects: %d static, %d realtime, %d autocreate =-\n\n", speerobjs, rpeerobjs, apeerobjs);
- ASTOBJ_CONTAINER_DUMP(fd, tmp, sizeof(tmp), &peerl);
- ast_cli(fd, "-= Registry objects: %d =-\n\n", regobjs);
- ASTOBJ_CONTAINER_DUMP(fd, tmp, sizeof(tmp), &regl);
- return RESULT_SUCCESS;
-}
-/*! \brief Print call group and pickup group */
-static void print_group(int fd, ast_group_t group, int crlf)
-{
- char buf[256];
- ast_cli(fd, crlf ? "%s\r\n" : "%s\n", ast_print_group(buf, sizeof(buf), group) );
-}
-
-/*! \brief Convert DTMF mode to printable string */
-static const char *dtmfmode2str(int mode)
-{
- switch (mode) {
- case SIP_DTMF_RFC2833:
- return "rfc2833";
- case SIP_DTMF_INFO:
- return "info";
- case SIP_DTMF_INBAND:
- return "inband";
- case SIP_DTMF_AUTO:
- return "auto";
- }
- return "<error>";
-}
-
-/*! \brief Convert Insecure setting to printable string */
-static const char *insecure2str(int port, int invite)
-{
- if (port && invite)
- return "port,invite";
- else if (port)
- return "port";
- else if (invite)
- return "invite";
- else
- return "no";
-}
-
-/*! \brief Destroy disused contexts between reloads
- Only used in reload_config so the code for regcontext doesn't get ugly
-*/
-static void cleanup_stale_contexts(char *new, char *old)
-{
- char *oldcontext, *newcontext, *stalecontext, *stringp, newlist[AST_MAX_CONTEXT];
-
- while ((oldcontext = strsep(&old, "&"))) {
- stalecontext = '\0';
- ast_copy_string(newlist, new, sizeof(newlist));
- stringp = newlist;
- while ((newcontext = strsep(&stringp, "&"))) {
- if (strcmp(newcontext, oldcontext) == 0) {
- /* This is not the context you're looking for */
- stalecontext = '\0';
- break;
- } else if (strcmp(newcontext, oldcontext)) {
- stalecontext = oldcontext;
- }
-
- }
- if (stalecontext)
- ast_context_destroy(ast_context_find(stalecontext), "SIP");
- }
-}
-
-/*! \brief Remove temporary realtime objects from memory (CLI) */
-static int sip_prune_realtime(int fd, int argc, char *argv[])
-{
- struct sip_peer *peer;
- struct sip_user *user;
- int pruneuser = FALSE;
- int prunepeer = FALSE;
- int multi = FALSE;
- char *name = NULL;
- regex_t regexbuf;
-
- switch (argc) {
- case 4:
- if (!strcasecmp(argv[3], "user"))
- return RESULT_SHOWUSAGE;
- if (!strcasecmp(argv[3], "peer"))
- return RESULT_SHOWUSAGE;
- if (!strcasecmp(argv[3], "like"))
- return RESULT_SHOWUSAGE;
- if (!strcasecmp(argv[3], "all")) {
- multi = TRUE;
- pruneuser = prunepeer = TRUE;
- } else {
- pruneuser = prunepeer = TRUE;
- name = argv[3];
- }
- break;
- case 5:
- if (!strcasecmp(argv[4], "like"))
- return RESULT_SHOWUSAGE;
- if (!strcasecmp(argv[3], "all"))
- return RESULT_SHOWUSAGE;
- if (!strcasecmp(argv[3], "like")) {
- multi = TRUE;
- name = argv[4];
- pruneuser = prunepeer = TRUE;
- } else if (!strcasecmp(argv[3], "user")) {
- pruneuser = TRUE;
- if (!strcasecmp(argv[4], "all"))
- multi = TRUE;
- else
- name = argv[4];
- } else if (!strcasecmp(argv[3], "peer")) {
- prunepeer = TRUE;
- if (!strcasecmp(argv[4], "all"))
- multi = TRUE;
- else
- name = argv[4];
- } else
- return RESULT_SHOWUSAGE;
- break;
- case 6:
- if (strcasecmp(argv[4], "like"))
- return RESULT_SHOWUSAGE;
- if (!strcasecmp(argv[3], "user")) {
- pruneuser = TRUE;
- name = argv[5];
- } else if (!strcasecmp(argv[3], "peer")) {
- prunepeer = TRUE;
- name = argv[5];
- } else
- return RESULT_SHOWUSAGE;
- break;
- default:
- return RESULT_SHOWUSAGE;
- }
-
- if (multi && name) {
- if (regcomp(&regexbuf, name, REG_EXTENDED | REG_NOSUB))
- return RESULT_SHOWUSAGE;
- }
-
- if (multi) {
- if (prunepeer) {
- int pruned = 0;
-
- ASTOBJ_CONTAINER_WRLOCK(&peerl);
- ASTOBJ_CONTAINER_TRAVERSE(&peerl, 1, do {
- ASTOBJ_RDLOCK(iterator);
- if (name && regexec(&regexbuf, iterator->name, 0, NULL, 0)) {
- ASTOBJ_UNLOCK(iterator);
- continue;
- };
- if (ast_test_flag(&iterator->flags[1], SIP_PAGE2_RTCACHEFRIENDS)) {
- ASTOBJ_MARK(iterator);
- pruned++;
- }
- ASTOBJ_UNLOCK(iterator);
- } while (0) );
- if (pruned) {
- ASTOBJ_CONTAINER_PRUNE_MARKED(&peerl, sip_destroy_peer);
- ast_cli(fd, "%d peers pruned.\n", pruned);
- } else
- ast_cli(fd, "No peers found to prune.\n");
- ASTOBJ_CONTAINER_UNLOCK(&peerl);
- }
- if (pruneuser) {
- int pruned = 0;
-
- ASTOBJ_CONTAINER_WRLOCK(&userl);
- ASTOBJ_CONTAINER_TRAVERSE(&userl, 1, do {
- ASTOBJ_RDLOCK(iterator);
- if (name && regexec(&regexbuf, iterator->name, 0, NULL, 0)) {
- ASTOBJ_UNLOCK(iterator);
- continue;
- };
- if (ast_test_flag(&iterator->flags[1], SIP_PAGE2_RTCACHEFRIENDS)) {
- ASTOBJ_MARK(iterator);
- pruned++;
- }
- ASTOBJ_UNLOCK(iterator);
- } while (0) );
- if (pruned) {
- ASTOBJ_CONTAINER_PRUNE_MARKED(&userl, sip_destroy_user);
- ast_cli(fd, "%d users pruned.\n", pruned);
- } else
- ast_cli(fd, "No users found to prune.\n");
- ASTOBJ_CONTAINER_UNLOCK(&userl);
- }
- } else {
- if (prunepeer) {
- if ((peer = ASTOBJ_CONTAINER_FIND_UNLINK(&peerl, name))) {
- if (!ast_test_flag(&peer->flags[1], SIP_PAGE2_RTCACHEFRIENDS)) {
- ast_cli(fd, "Peer '%s' is not a Realtime peer, cannot be pruned.\n", name);
- ASTOBJ_CONTAINER_LINK(&peerl, peer);
- } else
- ast_cli(fd, "Peer '%s' pruned.\n", name);
- ASTOBJ_UNREF(peer, sip_destroy_peer);
- } else
- ast_cli(fd, "Peer '%s' not found.\n", name);
- }
- if (pruneuser) {
- if ((user = ASTOBJ_CONTAINER_FIND_UNLINK(&userl, name))) {
- if (!ast_test_flag(&user->flags[1], SIP_PAGE2_RTCACHEFRIENDS)) {
- ast_cli(fd, "User '%s' is not a Realtime user, cannot be pruned.\n", name);
- ASTOBJ_CONTAINER_LINK(&userl, user);
- } else
- ast_cli(fd, "User '%s' pruned.\n", name);
- ASTOBJ_UNREF(user, sip_destroy_user);
- } else
- ast_cli(fd, "User '%s' not found.\n", name);
- }
- }
-
- return RESULT_SUCCESS;
-}
-
-/*! \brief Print codec list from preference to CLI/manager */
-static void print_codec_to_cli(int fd, struct ast_codec_pref *pref)
-{
- int x, codec;
-
- for(x = 0; x < 32 ; x++) {
- codec = ast_codec_pref_index(pref, x);
- if (!codec)
- break;
- ast_cli(fd, "%s", ast_getformatname(codec));
- ast_cli(fd, ":%d", pref->framing[x]);
- if (x < 31 && ast_codec_pref_index(pref, x + 1))
- ast_cli(fd, ",");
- }
- if (!x)
- ast_cli(fd, "none");
-}
-
-/*! \brief Print domain mode to cli */
-static const char *domain_mode_to_text(const enum domain_mode mode)
-{
- switch (mode) {
- case SIP_DOMAIN_AUTO:
- return "[Automatic]";
- case SIP_DOMAIN_CONFIG:
- return "[Configured]";
- }
-
- return "";
-}
-
-/*! \brief CLI command to list local domains */
-static int sip_show_domains(int fd, int argc, char *argv[])
-{
- struct domain *d;
-#define FORMAT "%-40.40s %-20.20s %-16.16s\n"
-
- if (AST_LIST_EMPTY(&domain_list)) {
- ast_cli(fd, "SIP Domain support not enabled.\n\n");
- return RESULT_SUCCESS;
- } else {
- ast_cli(fd, FORMAT, "Our local SIP domains:", "Context", "Set by");
- AST_LIST_LOCK(&domain_list);
- AST_LIST_TRAVERSE(&domain_list, d, list)
- ast_cli(fd, FORMAT, d->domain, S_OR(d->context, "(default)"),
- domain_mode_to_text(d->mode));
- AST_LIST_UNLOCK(&domain_list);
- ast_cli(fd, "\n");
- return RESULT_SUCCESS;
- }
-}
-#undef FORMAT
-
-static char mandescr_show_peer[] =
-"Description: Show one SIP peer with details on current status.\n"
-"Variables: \n"
-" Peer: <name> The peer name you want to check.\n"
-" ActionID: <id> Optional action ID for this AMI transaction.\n";
-
-/*! \brief Show SIP peers in the manager API */
-static int manager_sip_show_peer(struct mansession *s, const struct message *m)
-{
- const char *a[4];
- const char *peer;
- int ret;
-
- peer = astman_get_header(m,"Peer");
- if (ast_strlen_zero(peer)) {
- astman_send_error(s, m, "Peer: <name> missing.");
- return 0;
- }
- a[0] = "sip";
- a[1] = "show";
- a[2] = "peer";
- a[3] = peer;
-
- ret = _sip_show_peer(1, -1, s, m, 4, a);
- astman_append(s, "\r\n\r\n" );
- return ret;
-}
-
-
-
-/*! \brief Show one peer in detail */
-static int sip_show_peer(int fd, int argc, char *argv[])
-{
- return _sip_show_peer(0, fd, NULL, NULL, argc, (const char **) argv);
-}
-
-/*! \brief Show one peer in detail (main function) */
-static int _sip_show_peer(int type, int fd, struct mansession *s, const struct message *m, int argc, const char *argv[])
-{
- char status[30] = "";
- char cbuf[256];
- struct sip_peer *peer;
- char codec_buf[512];
- struct ast_codec_pref *pref;
- struct ast_variable *v;
- struct sip_auth *auth;
- int x = 0, codec = 0, load_realtime;
- int realtimepeers;
-
- realtimepeers = ast_check_realtime("sippeers");
-
- if (argc < 4)
- return RESULT_SHOWUSAGE;
-
- load_realtime = (argc == 5 && !strcmp(argv[4], "load")) ? TRUE : FALSE;
- peer = find_peer(argv[3], NULL, load_realtime, 0);
- if (s) { /* Manager */
- if (peer) {
- const char *id = astman_get_header(m,"ActionID");
-
- astman_append(s, "Response: Success\r\n");
- if (!ast_strlen_zero(id))
- astman_append(s, "ActionID: %s\r\n",id);
- } else {
- snprintf (cbuf, sizeof(cbuf), "Peer %s not found.", argv[3]);
- astman_send_error(s, m, cbuf);
- return 0;
- }
- }
- if (peer && type==0 ) { /* Normal listing */
- ast_cli(fd,"\n\n");
- ast_cli(fd, " * Name : %s\n", peer->name);
- if (realtimepeers) { /* Realtime is enabled */
- ast_cli(fd, " Realtime peer: %s\n", ast_test_flag(&peer->flags[0], SIP_REALTIME) ? "Yes, cached" : "No");
- }
- ast_cli(fd, " Secret : %s\n", ast_strlen_zero(peer->secret)?"<Not set>":"<Set>");
- ast_cli(fd, " MD5Secret : %s\n", ast_strlen_zero(peer->md5secret)?"<Not set>":"<Set>");
- for (auth = peer->auth; auth; auth = auth->next) {
- ast_cli(fd, " Realm-auth : Realm %-15.15s User %-10.20s ", auth->realm, auth->username);
- ast_cli(fd, "%s\n", !ast_strlen_zero(auth->secret)?"<Secret set>":(!ast_strlen_zero(auth->md5secret)?"<MD5secret set>" : "<Not set>"));
- }
- ast_cli(fd, " Context : %s\n", peer->context);
- ast_cli(fd, " Subscr.Cont. : %s\n", S_OR(peer->subscribecontext, "<Not set>") );
- ast_cli(fd, " Language : %s\n", peer->language);
- if (!ast_strlen_zero(peer->accountcode))
- ast_cli(fd, " Accountcode : %s\n", peer->accountcode);
- ast_cli(fd, " AMA flags : %s\n", ast_cdr_flags2str(peer->amaflags));
- ast_cli(fd, " Transfer mode: %s\n", transfermode2str(peer->allowtransfer));
- ast_cli(fd, " CallingPres : %s\n", ast_describe_caller_presentation(peer->callingpres));
- if (!ast_strlen_zero(peer->fromuser))
- ast_cli(fd, " FromUser : %s\n", peer->fromuser);
- if (!ast_strlen_zero(peer->fromdomain))
- ast_cli(fd, " FromDomain : %s\n", peer->fromdomain);
- ast_cli(fd, " Callgroup : ");
- print_group(fd, peer->callgroup, 0);
- ast_cli(fd, " Pickupgroup : ");
- print_group(fd, peer->pickupgroup, 0);
- ast_cli(fd, " Mailbox : %s\n", peer->mailbox);
- ast_cli(fd, " VM Extension : %s\n", peer->vmexten);
- ast_cli(fd, " LastMsgsSent : %d/%d\n", (peer->lastmsgssent & 0x7fff0000) >> 16, peer->lastmsgssent & 0xffff);
- ast_cli(fd, " Call limit : %d\n", peer->call_limit);
- ast_cli(fd, " Dynamic : %s\n", (ast_test_flag(&peer->flags[1], SIP_PAGE2_DYNAMIC)?"Yes":"No"));
- ast_cli(fd, " Callerid : %s\n", ast_callerid_merge(cbuf, sizeof(cbuf), peer->cid_name, peer->cid_num, "<unspecified>"));
- ast_cli(fd, " MaxCallBR : %d kbps\n", peer->maxcallbitrate);
- ast_cli(fd, " Expire : %ld\n", ast_sched_when(sched, peer->expire));
- ast_cli(fd, " Insecure : %s\n", insecure2str(ast_test_flag(&peer->flags[0], SIP_INSECURE_PORT), ast_test_flag(&peer->flags[0], SIP_INSECURE_INVITE)));
- ast_cli(fd, " Nat : %s\n", nat2str(ast_test_flag(&peer->flags[0], SIP_NAT)));
- ast_cli(fd, " ACL : %s\n", (peer->ha?"Yes":"No"));
- ast_cli(fd, " T38 pt UDPTL : %s\n", ast_test_flag(&peer->flags[1], SIP_PAGE2_T38SUPPORT_UDPTL)?"Yes":"No");
-#ifdef WHEN_WE_HAVE_T38_FOR_OTHER_TRANSPORTS
- ast_cli(fd, " T38 pt RTP : %s\n", ast_test_flag(&peer->flags[1], SIP_PAGE2_T38SUPPORT_RTP)?"Yes":"No");
- ast_cli(fd, " T38 pt TCP : %s\n", ast_test_flag(&peer->flags[1], SIP_PAGE2_T38SUPPORT_TCP)?"Yes":"No");
-#endif
- ast_cli(fd, " CanReinvite : %s\n", ast_test_flag(&peer->flags[0], SIP_CAN_REINVITE)?"Yes":"No");
- ast_cli(fd, " PromiscRedir : %s\n", ast_test_flag(&peer->flags[0], SIP_PROMISCREDIR)?"Yes":"No");
- ast_cli(fd, " User=Phone : %s\n", ast_test_flag(&peer->flags[0], SIP_USEREQPHONE)?"Yes":"No");
- ast_cli(fd, " Video Support: %s\n", ast_test_flag(&peer->flags[1], SIP_PAGE2_VIDEOSUPPORT)?"Yes":"No");
- ast_cli(fd, " Trust RPID : %s\n", ast_test_flag(&peer->flags[0], SIP_TRUSTRPID) ? "Yes" : "No");
- ast_cli(fd, " Send RPID : %s\n", ast_test_flag(&peer->flags[0], SIP_SENDRPID) ? "Yes" : "No");
- ast_cli(fd, " Subscriptions: %s\n", ast_test_flag(&peer->flags[1], SIP_PAGE2_ALLOWSUBSCRIBE) ? "Yes" : "No");
- ast_cli(fd, " Overlap dial : %s\n", ast_test_flag(&peer->flags[1], SIP_PAGE2_ALLOWOVERLAP) ? "Yes" : "No");
-
- /* - is enumerated */
- ast_cli(fd, " DTMFmode : %s\n", dtmfmode2str(ast_test_flag(&peer->flags[0], SIP_DTMF)));
- ast_cli(fd, " LastMsg : %d\n", peer->lastmsg);
- ast_cli(fd, " ToHost : %s\n", peer->tohost);
- ast_cli(fd, " Addr->IP : %s Port %d\n", peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "(Unspecified)", ntohs(peer->addr.sin_port));
- ast_cli(fd, " Defaddr->IP : %s Port %d\n", ast_inet_ntoa(peer->defaddr.sin_addr), ntohs(peer->defaddr.sin_port));
- if (!ast_strlen_zero(global_regcontext))
- ast_cli(fd, " Reg. exten : %s\n", peer->regexten);
- ast_cli(fd, " Def. Username: %s\n", peer->username);
- ast_cli(fd, " SIP Options : ");
- if (peer->sipoptions) {
- int lastoption = -1;
- for (x=0 ; (x < (sizeof(sip_options) / sizeof(sip_options[0]))); x++) {
- if (sip_options[x].id != lastoption) {
- if (peer->sipoptions & sip_options[x].id)
- ast_cli(fd, "%s ", sip_options[x].text);
- lastoption = x;
- }
- }
- } else
- ast_cli(fd, "(none)");
-
- ast_cli(fd, "\n");
- ast_cli(fd, " Codecs : ");
- ast_getformatname_multiple(codec_buf, sizeof(codec_buf) -1, peer->capability);
- ast_cli(fd, "%s\n", codec_buf);
- ast_cli(fd, " Codec Order : (");
- print_codec_to_cli(fd, &peer->prefs);
- ast_cli(fd, ")\n");
-
- ast_cli(fd, " Auto-Framing: %s \n", peer->autoframing ? "Yes" : "No");
- ast_cli(fd, " Status : ");
- peer_status(peer, status, sizeof(status));
- ast_cli(fd, "%s\n",status);
- ast_cli(fd, " Useragent : %s\n", peer->useragent);
- ast_cli(fd, " Reg. Contact : %s\n", peer->fullcontact);
- if (peer->chanvars) {
- ast_cli(fd, " Variables :\n");
- for (v = peer->chanvars ; v ; v = v->next)
- ast_cli(fd, " %s = %s\n", v->name, v->value);
- }
- ast_cli(fd,"\n");
- ASTOBJ_UNREF(peer,sip_destroy_peer);
- } else if (peer && type == 1) { /* manager listing */
- char buf[256];
- astman_append(s, "Channeltype: SIP\r\n");
- astman_append(s, "ObjectName: %s\r\n", peer->name);
- astman_append(s, "ChanObjectType: peer\r\n");
- astman_append(s, "SecretExist: %s\r\n", ast_strlen_zero(peer->secret)?"N":"Y");
- astman_append(s, "MD5SecretExist: %s\r\n", ast_strlen_zero(peer->md5secret)?"N":"Y");
- astman_append(s, "Context: %s\r\n", peer->context);
- astman_append(s, "Language: %s\r\n", peer->language);
- if (!ast_strlen_zero(peer->accountcode))
- astman_append(s, "Accountcode: %s\r\n", peer->accountcode);
- astman_append(s, "AMAflags: %s\r\n", ast_cdr_flags2str(peer->amaflags));
- astman_append(s, "CID-CallingPres: %s\r\n", ast_describe_caller_presentation(peer->callingpres));
- if (!ast_strlen_zero(peer->fromuser))
- astman_append(s, "SIP-FromUser: %s\r\n", peer->fromuser);
- if (!ast_strlen_zero(peer->fromdomain))
- astman_append(s, "SIP-FromDomain: %s\r\n", peer->fromdomain);
- astman_append(s, "Callgroup: ");
- astman_append(s, "%s\r\n", ast_print_group(buf, sizeof(buf), peer->callgroup));
- astman_append(s, "Pickupgroup: ");
- astman_append(s, "%s\r\n", ast_print_group(buf, sizeof(buf), peer->pickupgroup));
- astman_append(s, "VoiceMailbox: %s\r\n", peer->mailbox);
- astman_append(s, "TransferMode: %s\r\n", transfermode2str(peer->allowtransfer));
- astman_append(s, "LastMsgsSent: %d\r\n", peer->lastmsgssent);
- astman_append(s, "Call-limit: %d\r\n", peer->call_limit);
- astman_append(s, "MaxCallBR: %d kbps\r\n", peer->maxcallbitrate);
- astman_append(s, "Dynamic: %s\r\n", (ast_test_flag(&peer->flags[1], SIP_PAGE2_DYNAMIC)?"Y":"N"));
- astman_append(s, "Callerid: %s\r\n", ast_callerid_merge(cbuf, sizeof(cbuf), peer->cid_name, peer->cid_num, ""));
- astman_append(s, "RegExpire: %ld seconds\r\n", ast_sched_when(sched,peer->expire));
- astman_append(s, "SIP-AuthInsecure: %s\r\n", insecure2str(ast_test_flag(&peer->flags[0], SIP_INSECURE_PORT), ast_test_flag(&peer->flags[0], SIP_INSECURE_INVITE)));
- astman_append(s, "SIP-NatSupport: %s\r\n", nat2str(ast_test_flag(&peer->flags[0], SIP_NAT)));
- astman_append(s, "ACL: %s\r\n", (peer->ha?"Y":"N"));
- astman_append(s, "SIP-CanReinvite: %s\r\n", (ast_test_flag(&peer->flags[0], SIP_CAN_REINVITE)?"Y":"N"));
- astman_append(s, "SIP-PromiscRedir: %s\r\n", (ast_test_flag(&peer->flags[0], SIP_PROMISCREDIR)?"Y":"N"));
- astman_append(s, "SIP-UserPhone: %s\r\n", (ast_test_flag(&peer->flags[0], SIP_USEREQPHONE)?"Y":"N"));
- astman_append(s, "SIP-VideoSupport: %s\r\n", (ast_test_flag(&peer->flags[1], SIP_PAGE2_VIDEOSUPPORT)?"Y":"N"));
-
- /* - is enumerated */
- astman_append(s, "SIP-DTMFmode: %s\r\n", dtmfmode2str(ast_test_flag(&peer->flags[0], SIP_DTMF)));
- astman_append(s, "SIPLastMsg: %d\r\n", peer->lastmsg);
- astman_append(s, "ToHost: %s\r\n", peer->tohost);
- astman_append(s, "Address-IP: %s\r\nAddress-Port: %d\r\n", peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "", ntohs(peer->addr.sin_port));
- astman_append(s, "Default-addr-IP: %s\r\nDefault-addr-port: %d\r\n", ast_inet_ntoa(peer->defaddr.sin_addr), ntohs(peer->defaddr.sin_port));
- astman_append(s, "Default-Username: %s\r\n", peer->username);
- if (!ast_strlen_zero(global_regcontext))
- astman_append(s, "RegExtension: %s\r\n", peer->regexten);
- astman_append(s, "Codecs: ");
- ast_getformatname_multiple(codec_buf, sizeof(codec_buf) -1, peer->capability);
- astman_append(s, "%s\r\n", codec_buf);
- astman_append(s, "CodecOrder: ");
- pref = &peer->prefs;
- for(x = 0; x < 32 ; x++) {
- codec = ast_codec_pref_index(pref,x);
- if (!codec)
- break;
- astman_append(s, "%s", ast_getformatname(codec));
- if (x < 31 && ast_codec_pref_index(pref,x+1))
- astman_append(s, ",");
- }
-
- astman_append(s, "\r\n");
- astman_append(s, "Status: ");
- peer_status(peer, status, sizeof(status));
- astman_append(s, "%s\r\n", status);
- astman_append(s, "SIP-Useragent: %s\r\n", peer->useragent);
- astman_append(s, "Reg-Contact : %s\r\n", peer->fullcontact);
- if (peer->chanvars) {
- for (v = peer->chanvars ; v ; v = v->next) {
- astman_append(s, "ChanVariable:\n");
- astman_append(s, " %s,%s\r\n", v->name, v->value);
- }
- }
-
- ASTOBJ_UNREF(peer,sip_destroy_peer);
-
- } else {
- ast_cli(fd,"Peer %s not found.\n", argv[3]);
- ast_cli(fd,"\n");
- }
-
- return RESULT_SUCCESS;
-}
-
-/*! \brief Show one user in detail */
-static int sip_show_user(int fd, int argc, char *argv[])
-{
- char cbuf[256];
- struct sip_user *user;
- struct ast_variable *v;
- int load_realtime;
-
- if (argc < 4)
- return RESULT_SHOWUSAGE;
-
- /* Load from realtime storage? */
- load_realtime = (argc == 5 && !strcmp(argv[4], "load")) ? TRUE : FALSE;
-
- user = find_user(argv[3], load_realtime);
- if (user) {
- ast_cli(fd,"\n\n");
- ast_cli(fd, " * Name : %s\n", user->name);
- ast_cli(fd, " Secret : %s\n", ast_strlen_zero(user->secret)?"<Not set>":"<Set>");
- ast_cli(fd, " MD5Secret : %s\n", ast_strlen_zero(user->md5secret)?"<Not set>":"<Set>");
- ast_cli(fd, " Context : %s\n", user->context);
- ast_cli(fd, " Language : %s\n", user->language);
- if (!ast_strlen_zero(user->accountcode))
- ast_cli(fd, " Accountcode : %s\n", user->accountcode);
- ast_cli(fd, " AMA flags : %s\n", ast_cdr_flags2str(user->amaflags));
- ast_cli(fd, " Transfer mode: %s\n", transfermode2str(user->allowtransfer));
- ast_cli(fd, " MaxCallBR : %d kbps\n", user->maxcallbitrate);
- ast_cli(fd, " CallingPres : %s\n", ast_describe_caller_presentation(user->callingpres));
- ast_cli(fd, " Call limit : %d\n", user->call_limit);
- ast_cli(fd, " Callgroup : ");
- print_group(fd, user->callgroup, 0);
- ast_cli(fd, " Pickupgroup : ");
- print_group(fd, user->pickupgroup, 0);
- ast_cli(fd, " Callerid : %s\n", ast_callerid_merge(cbuf, sizeof(cbuf), user->cid_name, user->cid_num, "<unspecified>"));
- ast_cli(fd, " ACL : %s\n", (user->ha?"Yes":"No"));
- ast_cli(fd, " Codec Order : (");
- print_codec_to_cli(fd, &user->prefs);
- ast_cli(fd, ")\n");
-
- ast_cli(fd, " Auto-Framing: %s \n", user->autoframing ? "Yes" : "No");
- if (user->chanvars) {
- ast_cli(fd, " Variables :\n");
- for (v = user->chanvars ; v ; v = v->next)
- ast_cli(fd, " %s = %s\n", v->name, v->value);
- }
- ast_cli(fd,"\n");
- ASTOBJ_UNREF(user,sip_destroy_user);
- } else {
- ast_cli(fd,"User %s not found.\n", argv[3]);
- ast_cli(fd,"\n");
- }
-
- return RESULT_SUCCESS;
-}
-
-/*! \brief Show SIP Registry (registrations with other SIP proxies */
-static int sip_show_registry(int fd, int argc, char *argv[])
-{
-#define FORMAT2 "%-30.30s %-12.12s %8.8s %-20.20s %-25.25s\n"
-#define FORMAT "%-30.30s %-12.12s %8d %-20.20s %-25.25s\n"
- char host[80];
- char tmpdat[256];
- struct tm tm;
-
-
- if (argc != 3)
- return RESULT_SHOWUSAGE;
- ast_cli(fd, FORMAT2, "Host", "Username", "Refresh", "State", "Reg.Time");
- ASTOBJ_CONTAINER_TRAVERSE(&regl, 1, do {
- ASTOBJ_RDLOCK(iterator);
- snprintf(host, sizeof(host), "%s:%d", iterator->hostname, iterator->portno ? iterator->portno : STANDARD_SIP_PORT);
- if (iterator->regtime) {
- ast_localtime(&iterator->regtime, &tm, NULL);
- strftime(tmpdat, sizeof(tmpdat), "%a, %d %b %Y %T", &tm);
- } else {
- tmpdat[0] = 0;
- }
- ast_cli(fd, FORMAT, host, iterator->username, iterator->refresh, regstate2str(iterator->regstate), tmpdat);
- ASTOBJ_UNLOCK(iterator);
- } while(0));
- return RESULT_SUCCESS;
-#undef FORMAT
-#undef FORMAT2
-}
-
-/*! \brief List global settings for the SIP channel */
-static int sip_show_settings(int fd, int argc, char *argv[])
-{
- int realtimepeers;
- int realtimeusers;
- char codec_buf[SIPBUFSIZE];
-
- realtimepeers = ast_check_realtime("sippeers");
- realtimeusers = ast_check_realtime("sipusers");
-
- if (argc != 3)
- return RESULT_SHOWUSAGE;
- ast_cli(fd, "\n\nGlobal Settings:\n");
- ast_cli(fd, "----------------\n");
- ast_cli(fd, " SIP Port: %d\n", ntohs(bindaddr.sin_port));
- ast_cli(fd, " Bindaddress: %s\n", ast_inet_ntoa(bindaddr.sin_addr));
- ast_cli(fd, " Videosupport: %s\n", ast_test_flag(&global_flags[1], SIP_PAGE2_VIDEOSUPPORT) ? "Yes" : "No");
- ast_cli(fd, " AutoCreatePeer: %s\n", autocreatepeer ? "Yes" : "No");
- ast_cli(fd, " Allow unknown access: %s\n", global_allowguest ? "Yes" : "No");
- ast_cli(fd, " Allow subscriptions: %s\n", ast_test_flag(&global_flags[1], SIP_PAGE2_ALLOWSUBSCRIBE) ? "Yes" : "No");
- ast_cli(fd, " Allow overlap dialing: %s\n", ast_test_flag(&global_flags[1], SIP_PAGE2_ALLOWOVERLAP) ? "Yes" : "No");
- ast_cli(fd, " Promsic. redir: %s\n", ast_test_flag(&global_flags[0], SIP_PROMISCREDIR) ? "Yes" : "No");
- ast_cli(fd, " SIP domain support: %s\n", AST_LIST_EMPTY(&domain_list) ? "No" : "Yes");
- ast_cli(fd, " Call to non-local dom.: %s\n", allow_external_domains ? "Yes" : "No");
- ast_cli(fd, " URI user is phone no: %s\n", ast_test_flag(&global_flags[0], SIP_USEREQPHONE) ? "Yes" : "No");
- ast_cli(fd, " Our auth realm %s\n", global_realm);
- ast_cli(fd, " Realm. auth: %s\n", authl ? "Yes": "No");
- ast_cli(fd, " Always auth rejects: %s\n", global_alwaysauthreject ? "Yes" : "No");
- ast_cli(fd, " Call limit peers only: %s\n", global_limitonpeers ? "Yes" : "No");
- ast_cli(fd, " Direct RTP setup: %s\n", global_directrtpsetup ? "Yes" : "No");
- ast_cli(fd, " User Agent: %s\n", global_useragent);
- ast_cli(fd, " MWI checking interval: %d secs\n", global_mwitime);
- ast_cli(fd, " Reg. context: %s\n", S_OR(global_regcontext, "(not set)"));
- ast_cli(fd, " Caller ID: %s\n", default_callerid);
- ast_cli(fd, " From: Domain: %s\n", default_fromdomain);
- ast_cli(fd, " Record SIP history: %s\n", recordhistory ? "On" : "Off");
- ast_cli(fd, " Call Events: %s\n", global_callevents ? "On" : "Off");
- ast_cli(fd, " IP ToS SIP: %s\n", ast_tos2str(global_tos_sip));
- ast_cli(fd, " IP ToS RTP audio: %s\n", ast_tos2str(global_tos_audio));
- ast_cli(fd, " IP ToS RTP video: %s\n", ast_tos2str(global_tos_video));
- ast_cli(fd, " T38 fax pt UDPTL: %s\n", ast_test_flag(&global_flags[1], SIP_PAGE2_T38SUPPORT_UDPTL) ? "Yes" : "No");
-#ifdef WHEN_WE_HAVE_T38_FOR_OTHER_TRANSPORTS
- ast_cli(fd, " T38 fax pt RTP: %s\n", ast_test_flag(&global_flags[1], SIP_PAGE2_T38SUPPORT_RTP) ? "Yes" : "No");
- ast_cli(fd, " T38 fax pt TCP: %s\n", ast_test_flag(&global_flags[1], SIP_PAGE2_T38SUPPORT_TCP) ? "Yes" : "No");
-#endif
- ast_cli(fd, " RFC2833 Compensation: %s\n", ast_test_flag(&global_flags[1], SIP_PAGE2_RFC2833_COMPENSATE) ? "Yes" : "No");
- if (!realtimepeers && !realtimeusers)
- ast_cli(fd, " SIP realtime: Disabled\n" );
- else
- ast_cli(fd, " SIP realtime: Enabled\n" );
-
- ast_cli(fd, "\nGlobal Signalling Settings:\n");
- ast_cli(fd, "---------------------------\n");
- ast_cli(fd, " Codecs: ");
- ast_getformatname_multiple(codec_buf, sizeof(codec_buf) -1, global_capability);
- ast_cli(fd, "%s\n", codec_buf);
- ast_cli(fd, " Codec Order: ");
- print_codec_to_cli(fd, &default_prefs);
- ast_cli(fd, "\n");
- ast_cli(fd, " T1 minimum: %d\n", global_t1min);
- ast_cli(fd, " Relax DTMF: %s\n", global_relaxdtmf ? "Yes" : "No");
- ast_cli(fd, " Compact SIP headers: %s\n", compactheaders ? "Yes" : "No");
- ast_cli(fd, " RTP Keepalive: %d %s\n", global_rtpkeepalive, global_rtpkeepalive ? "" : "(Disabled)" );
- ast_cli(fd, " RTP Timeout: %d %s\n", global_rtptimeout, global_rtptimeout ? "" : "(Disabled)" );
- ast_cli(fd, " RTP Hold Timeout: %d %s\n", global_rtpholdtimeout, global_rtpholdtimeout ? "" : "(Disabled)");
- ast_cli(fd, " MWI NOTIFY mime type: %s\n", default_notifymime);
- ast_cli(fd, " DNS SRV lookup: %s\n", srvlookup ? "Yes" : "No");
- ast_cli(fd, " Pedantic SIP support: %s\n", pedanticsipchecking ? "Yes" : "No");
- ast_cli(fd, " Reg. min duration %d secs\n", min_expiry);
- ast_cli(fd, " Reg. max duration: %d secs\n", max_expiry);
- ast_cli(fd, " Reg. default duration: %d secs\n", default_expiry);
- ast_cli(fd, " Outbound reg. timeout: %d secs\n", global_reg_timeout);
- ast_cli(fd, " Outbound reg. attempts: %d\n", global_regattempts_max);
- ast_cli(fd, " Notify ringing state: %s\n", global_notifyringing ? "Yes" : "No");
- ast_cli(fd, " Notify hold state: %s\n", global_notifyhold ? "Yes" : "No");
- ast_cli(fd, " SIP Transfer mode: %s\n", transfermode2str(global_allowtransfer));
- ast_cli(fd, " Max Call Bitrate: %d kbps\r\n", default_maxcallbitrate);
- ast_cli(fd, " Auto-Framing: %s \r\n", global_autoframing ? "Yes" : "No");
- ast_cli(fd, "\nDefault Settings:\n");
- ast_cli(fd, "-----------------\n");
- ast_cli(fd, " Context: %s\n", default_context);
- ast_cli(fd, " Nat: %s\n", nat2str(ast_test_flag(&global_flags[0], SIP_NAT)));
- ast_cli(fd, " DTMF: %s\n", dtmfmode2str(ast_test_flag(&global_flags[0], SIP_DTMF)));
- ast_cli(fd, " Qualify: %d\n", default_qualify);
- ast_cli(fd, " Use ClientCode: %s\n", ast_test_flag(&global_flags[0], SIP_USECLIENTCODE) ? "Yes" : "No");
- ast_cli(fd, " Progress inband: %s\n", (ast_test_flag(&global_flags[0], SIP_PROG_INBAND) == SIP_PROG_INBAND_NEVER) ? "Never" : (ast_test_flag(&global_flags[0], SIP_PROG_INBAND) == SIP_PROG_INBAND_NO) ? "No" : "Yes" );
- ast_cli(fd, " Language: %s\n", S_OR(default_language, "(Defaults to English)"));
- ast_cli(fd, " MOH Interpret: %s\n", default_mohinterpret);
- ast_cli(fd, " MOH Suggest: %s\n", default_mohsuggest);
- ast_cli(fd, " Voice Mail Extension: %s\n", default_vmexten);
-
-
- if (realtimepeers || realtimeusers) {
- ast_cli(fd, "\nRealtime SIP Settings:\n");
- ast_cli(fd, "----------------------\n");
- ast_cli(fd, " Realtime Peers: %s\n", realtimepeers ? "Yes" : "No");
- ast_cli(fd, " Realtime Users: %s\n", realtimeusers ? "Yes" : "No");
- ast_cli(fd, " Cache Friends: %s\n", ast_test_flag(&global_flags[1], SIP_PAGE2_RTCACHEFRIENDS) ? "Yes" : "No");
- ast_cli(fd, " Update: %s\n", ast_test_flag(&global_flags[1], SIP_PAGE2_RTUPDATE) ? "Yes" : "No");
- ast_cli(fd, " Ignore Reg. Expire: %s\n", ast_test_flag(&global_flags[1], SIP_PAGE2_IGNOREREGEXPIRE) ? "Yes" : "No");
- ast_cli(fd, " Save sys. name: %s\n", ast_test_flag(&global_flags[1], SIP_PAGE2_RTSAVE_SYSNAME) ? "Yes" : "No");
- ast_cli(fd, " Auto Clear: %d\n", global_rtautoclear);
- }
- ast_cli(fd, "\n----\n");
- return RESULT_SUCCESS;
-}
-
-/*! \brief Show subscription type in string format */
-static const char *subscription_type2str(enum subscriptiontype subtype)
-{
- int i;
-
- for (i = 1; (i < (sizeof(subscription_types) / sizeof(subscription_types[0]))); i++) {
- if (subscription_types[i].type == subtype) {
- return subscription_types[i].text;
- }
- }
- return subscription_types[0].text;
-}
-
-/*! \brief Find subscription type in array */
-static const struct cfsubscription_types *find_subscription_type(enum subscriptiontype subtype)
-{
- int i;
-
- for (i = 1; (i < (sizeof(subscription_types) / sizeof(subscription_types[0]))); i++) {
- if (subscription_types[i].type == subtype) {
- return &subscription_types[i];
- }
- }
- return &subscription_types[0];
-}
-
-/*! \brief Show active SIP channels */
-static int sip_show_channels(int fd, int argc, char *argv[])
-{
- return __sip_show_channels(fd, argc, argv, 0);
-}
-
-/*! \brief Show active SIP subscriptions */
-static int sip_show_subscriptions(int fd, int argc, char *argv[])
-{
- return __sip_show_channels(fd, argc, argv, 1);
-}
-
-/*! \brief SIP show channels CLI (main function) */
-static int __sip_show_channels(int fd, int argc, char *argv[], int subscriptions)
-{
-#define FORMAT3 "%-15.15s %-10.10s %-11.11s %-15.15s %-13.13s %-15.15s %-10.10s\n"
-#define FORMAT2 "%-15.15s %-10.10s %-11.11s %-11.11s %-15.15s %-7.7s %-15.15s\n"
-#define FORMAT "%-15.15s %-10.10s %-11.11s %5.5d/%5.5d %-15.15s %-3.3s %-3.3s %-15.15s %-10.10s\n"
- struct sip_pvt *cur;
- int numchans = 0;
- char *referstatus = NULL;
-
- if (argc != 3)
- return RESULT_SHOWUSAGE;
- ast_mutex_lock(&iflock);
- cur = iflist;
- if (!subscriptions)
- ast_cli(fd, FORMAT2, "Peer", "User/ANR", "Call ID", "Seq (Tx/Rx)", "Format", "Hold", "Last Message");
- else
- ast_cli(fd, FORMAT3, "Peer", "User", "Call ID", "Extension", "Last state", "Type", "Mailbox");
- for (; cur; cur = cur->next) {
- referstatus = "";
- if (cur->refer) { /* SIP transfer in progress */
- referstatus = referstatus2str(cur->refer->status);
- }
- if (cur->subscribed == NONE && !subscriptions) {
- char formatbuf[SIPBUFSIZE/2];
- ast_cli(fd, FORMAT, ast_inet_ntoa(cur->sa.sin_addr),
- S_OR(cur->username, S_OR(cur->cid_num, "(None)")),
- cur->callid,
- cur->ocseq, cur->icseq,
- ast_getformatname_multiple(formatbuf, sizeof(formatbuf), cur->owner ? cur->owner->nativeformats : 0),
- ast_test_flag(&cur->flags[1], SIP_PAGE2_CALL_ONHOLD) ? "Yes" : "No",
- ast_test_flag(&cur->flags[0], SIP_NEEDDESTROY) ? "(d)" : "",
- cur->lastmsg ,
- referstatus
- );
- numchans++;
- }
- if (cur->subscribed != NONE && subscriptions) {
- ast_cli(fd, FORMAT3, ast_inet_ntoa(cur->sa.sin_addr),
- S_OR(cur->username, S_OR(cur->cid_num, "(None)")),
- cur->callid,
- /* the 'complete' exten/context is hidden in the refer_to field for subscriptions */
- cur->subscribed == MWI_NOTIFICATION ? "--" : cur->subscribeuri,
- cur->subscribed == MWI_NOTIFICATION ? "<none>" : ast_extension_state2str(cur->laststate),
- subscription_type2str(cur->subscribed),
- cur->subscribed == MWI_NOTIFICATION ? (cur->relatedpeer ? cur->relatedpeer->mailbox : "<none>") : "<none>"
-);
- numchans++;
- }
- }
- ast_mutex_unlock(&iflock);
- if (!subscriptions)
- ast_cli(fd, "%d active SIP channel%s\n", numchans, (numchans != 1) ? "s" : "");
- else
- ast_cli(fd, "%d active SIP subscription%s\n", numchans, (numchans != 1) ? "s" : "");
- return RESULT_SUCCESS;
-#undef FORMAT
-#undef FORMAT2
-#undef FORMAT3
-}
-
-/*! \brief Support routine for 'sip show channel' CLI */
-static char *complete_sipch(const char *line, const char *word, int pos, int state)
-{
- int which=0;
- struct sip_pvt *cur;
- char *c = NULL;
- int wordlen = strlen(word);
-
- if (pos != 3) {
- return NULL;
- }
-
- ast_mutex_lock(&iflock);
- for (cur = iflist; cur; cur = cur->next) {
- if (!strncasecmp(word, cur->callid, wordlen) && ++which > state) {
- c = ast_strdup(cur->callid);
- break;
- }
- }
- ast_mutex_unlock(&iflock);
- return c;
-}
-
-/*! \brief Do completion on peer name */
-static char *complete_sip_peer(const char *word, int state, int flags2)
-{
- char *result = NULL;
- int wordlen = strlen(word);
- int which = 0;
-
- ASTOBJ_CONTAINER_TRAVERSE(&peerl, !result, do {
- /* locking of the object is not required because only the name and flags are being compared */
- if (!strncasecmp(word, iterator->name, wordlen) &&
- (!flags2 || ast_test_flag(&iterator->flags[1], flags2)) &&
- ++which > state)
- result = ast_strdup(iterator->name);
- } while(0) );
- return result;
-}
-
-/*! \brief Support routine for 'sip show peer' CLI */
-static char *complete_sip_show_peer(const char *line, const char *word, int pos, int state)
-{
- if (pos == 3)
- return complete_sip_peer(word, state, 0);
-
- return NULL;
-}
-
-/*! \brief Support routine for 'sip debug peer' CLI */
-static char *complete_sip_debug_peer(const char *line, const char *word, int pos, int state)
-{
- if (pos == 3)
- return complete_sip_peer(word, state, 0);
-
- return NULL;
-}
-
-/*! \brief Do completion on user name */
-static char *complete_sip_user(const char *word, int state, int flags2)
-{
- char *result = NULL;
- int wordlen = strlen(word);
- int which = 0;
-
- ASTOBJ_CONTAINER_TRAVERSE(&userl, !result, do {
- /* locking of the object is not required because only the name and flags are being compared */
- if (!strncasecmp(word, iterator->name, wordlen)) {
- if (flags2 && !ast_test_flag(&iterator->flags[1], flags2))
- continue;
- if (++which > state) {
- result = ast_strdup(iterator->name);
- }
- }
- } while(0) );
- return result;
-}
-
-/*! \brief Support routine for 'sip show user' CLI */
-static char *complete_sip_show_user(const char *line, const char *word, int pos, int state)
-{
- if (pos == 3)
- return complete_sip_user(word, state, 0);
-
- return NULL;
-}
-
-/*! \brief Support routine for 'sip notify' CLI */
-static char *complete_sipnotify(const char *line, const char *word, int pos, int state)
-{
- char *c = NULL;
-
- if (pos == 2) {
- int which = 0;
- char *cat = NULL;
- int wordlen = strlen(word);
-
- /* do completion for notify type */
-
- if (!notify_types)
- return NULL;
-
- while ( (cat = ast_category_browse(notify_types, cat)) ) {
- if (!strncasecmp(word, cat, wordlen) && ++which > state) {
- c = ast_strdup(cat);
- break;
- }
- }
- return c;
- }
-
- if (pos > 2)
- return complete_sip_peer(word, state, 0);
-
- return NULL;
-}
-
-/*! \brief Support routine for 'sip prune realtime peer' CLI */
-static char *complete_sip_prune_realtime_peer(const char *line, const char *word, int pos, int state)
-{
- if (pos == 4)
- return complete_sip_peer(word, state, SIP_PAGE2_RTCACHEFRIENDS);
- return NULL;
-}
-
-/*! \brief Support routine for 'sip prune realtime user' CLI */
-static char *complete_sip_prune_realtime_user(const char *line, const char *word, int pos, int state)
-{
- if (pos == 4)
- return complete_sip_user(word, state, SIP_PAGE2_RTCACHEFRIENDS);
-
- return NULL;
-}
-
-/*! \brief Show details of one active dialog */
-static int sip_show_channel(int fd, int argc, char *argv[])
-{
- struct sip_pvt *cur;
- size_t len;
- int found = 0;
-
- if (argc != 4)
- return RESULT_SHOWUSAGE;
- len = strlen(argv[3]);
- ast_mutex_lock(&iflock);
- for (cur = iflist; cur; cur = cur->next) {
- if (!strncasecmp(cur->callid, argv[3], len)) {
- char formatbuf[SIPBUFSIZE/2];
- ast_cli(fd,"\n");
- if (cur->subscribed != NONE)
- ast_cli(fd, " * Subscription (type: %s)\n", subscription_type2str(cur->subscribed));
- else
- ast_cli(fd, " * SIP Call\n");
- ast_cli(fd, " Curr. trans. direction: %s\n", ast_test_flag(&cur->flags[0], SIP_OUTGOING) ? "Outgoing" : "Incoming");
- ast_cli(fd, " Call-ID: %s\n", cur->callid);
- ast_cli(fd, " Owner channel ID: %s\n", cur->owner ? cur->owner->name : "<none>");
- ast_cli(fd, " Our Codec Capability: %d\n", cur->capability);
- ast_cli(fd, " Non-Codec Capability (DTMF): %d\n", cur->noncodeccapability);
- ast_cli(fd, " Their Codec Capability: %d\n", cur->peercapability);
- ast_cli(fd, " Joint Codec Capability: %d\n", cur->jointcapability);
- ast_cli(fd, " Format: %s\n", ast_getformatname_multiple(formatbuf, sizeof(formatbuf), cur->owner ? cur->owner->nativeformats : 0) );
- ast_cli(fd, " MaxCallBR: %d kbps\n", cur->maxcallbitrate);
- ast_cli(fd, " Theoretical Address: %s:%d\n", ast_inet_ntoa(cur->sa.sin_addr), ntohs(cur->sa.sin_port));
- ast_cli(fd, " Received Address: %s:%d\n", ast_inet_ntoa(cur->recv.sin_addr), ntohs(cur->recv.sin_port));
- ast_cli(fd, " SIP Transfer mode: %s\n", transfermode2str(cur->allowtransfer));
- ast_cli(fd, " NAT Support: %s\n", nat2str(ast_test_flag(&cur->flags[0], SIP_NAT)));
- ast_cli(fd, " Audio IP: %s %s\n", ast_inet_ntoa(cur->redirip.sin_addr.s_addr ? cur->redirip.sin_addr : cur->ourip), cur->redirip.sin_addr.s_addr ? "(Outside bridge)" : "(local)" );
- ast_cli(fd, " Our Tag: %s\n", cur->tag);
- ast_cli(fd, " Their Tag: %s\n", cur->theirtag);
- ast_cli(fd, " SIP User agent: %s\n", cur->useragent);
- if (!ast_strlen_zero(cur->username))
- ast_cli(fd, " Username: %s\n", cur->username);
- if (!ast_strlen_zero(cur->peername))
- ast_cli(fd, " Peername: %s\n", cur->peername);
- if (!ast_strlen_zero(cur->uri))
- ast_cli(fd, " Original uri: %s\n", cur->uri);
- if (!ast_strlen_zero(cur->cid_num))
- ast_cli(fd, " Caller-ID: %s\n", cur->cid_num);
- ast_cli(fd, " Need Destroy: %d\n", ast_test_flag(&cur->flags[0], SIP_NEEDDESTROY));
- ast_cli(fd, " Last Message: %s\n", cur->lastmsg);
- ast_cli(fd, " Promiscuous Redir: %s\n", ast_test_flag(&cur->flags[0], SIP_PROMISCREDIR) ? "Yes" : "No");
- ast_cli(fd, " Route: %s\n", cur->route ? cur->route->hop : "N/A");
- ast_cli(fd, " DTMF Mode: %s\n", dtmfmode2str(ast_test_flag(&cur->flags[0], SIP_DTMF)));
- ast_cli(fd, " SIP Options: ");
- if (cur->sipoptions) {
- int x;
- for (x=0 ; (x < (sizeof(sip_options) / sizeof(sip_options[0]))); x++) {
- if (cur->sipoptions & sip_options[x].id)
- ast_cli(fd, "%s ", sip_options[x].text);
- }
- } else
- ast_cli(fd, "(none)\n");
- ast_cli(fd, "\n\n");
- found++;
- }
- }
- ast_mutex_unlock(&iflock);
- if (!found)
- ast_cli(fd, "No such SIP Call ID starting with '%s'\n", argv[3]);
- return RESULT_SUCCESS;
-}
-
-/*! \brief Show history details of one dialog */
-static int sip_show_history(int fd, int argc, char *argv[])
-{
- struct sip_pvt *cur;
- size_t len;
- int found = 0;
-
- if (argc != 4)
- return RESULT_SHOWUSAGE;
- if (!recordhistory)
- ast_cli(fd, "\n***Note: History recording is currently DISABLED. Use 'sip history' to ENABLE.\n");
- len = strlen(argv[3]);
- ast_mutex_lock(&iflock);
- for (cur = iflist; cur; cur = cur->next) {
- if (!strncasecmp(cur->callid, argv[3], len)) {
- struct sip_history *hist;
- int x = 0;
-
- ast_cli(fd,"\n");
- if (cur->subscribed != NONE)
- ast_cli(fd, " * Subscription\n");
- else
- ast_cli(fd, " * SIP Call\n");
- if (cur->history)
- AST_LIST_TRAVERSE(cur->history, hist, list)
- ast_cli(fd, "%d. %s\n", ++x, hist->event);
- if (x == 0)
- ast_cli(fd, "Call '%s' has no history\n", cur->callid);
- found++;
- }
- }
- ast_mutex_unlock(&iflock);
- if (!found)
- ast_cli(fd, "No such SIP Call ID starting with '%s'\n", argv[3]);
- return RESULT_SUCCESS;
-}
-
-/*! \brief Dump SIP history to debug log file at end of lifespan for SIP dialog */
-static void sip_dump_history(struct sip_pvt *dialog)
-{
- int x = 0;
- struct sip_history *hist;
- static int errmsg = 0;
-
- if (!dialog)
- return;
-
- if (!option_debug && !sipdebug) {
- if (!errmsg) {
- ast_log(LOG_NOTICE, "You must have debugging enabled (SIP or Asterisk) in order to dump SIP history.\n");
- errmsg = 1;
- }
- return;
- }
-
- ast_log(LOG_DEBUG, "\n---------- SIP HISTORY for '%s' \n", dialog->callid);
- if (dialog->subscribed)
- ast_log(LOG_DEBUG, " * Subscription\n");
- else
- ast_log(LOG_DEBUG, " * SIP Call\n");
- if (dialog->history)
- AST_LIST_TRAVERSE(dialog->history, hist, list)
- ast_log(LOG_DEBUG, " %-3.3d. %s\n", ++x, hist->event);
- if (!x)
- ast_log(LOG_DEBUG, "Call '%s' has no history\n", dialog->callid);
- ast_log(LOG_DEBUG, "\n---------- END SIP HISTORY for '%s' \n", dialog->callid);
-}
-
-
-/*! \brief Receive SIP INFO Message
-\note Doesn't read the duration of the DTMF signal */
-static void handle_request_info(struct sip_pvt *p, struct sip_request *req)
-{
- char buf[1024];
- unsigned int event;
- const char *c = get_header(req, "Content-Type");
-
- /* Need to check the media/type */
- if (!strcasecmp(c, "application/dtmf-relay") ||
- !strcasecmp(c, "application/vnd.nortelnetworks.digits")) {
- unsigned int duration = 0;
-
- /* Try getting the "signal=" part */
- if (ast_strlen_zero(c = get_body(req, "Signal")) && ast_strlen_zero(c = get_body(req, "d"))) {
- ast_log(LOG_WARNING, "Unable to retrieve DTMF signal from INFO message from %s\n", p->callid);
- transmit_response(p, "200 OK", req); /* Should return error */
- return;
- } else {
- ast_copy_string(buf, c, sizeof(buf));
- }
-
- if (!ast_strlen_zero((c = get_body(req, "Duration"))))
- duration = atoi(c);
- if (!duration)
- duration = 100; /* 100 ms */
-
- if (!p->owner) { /* not a PBX call */
- transmit_response(p, "481 Call leg/transaction does not exist", req);
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- return;
- }
-
- if (ast_strlen_zero(buf)) {
- transmit_response(p, "200 OK", req);
- return;
- }
-
- if (buf[0] == '*')
- event = 10;
- else if (buf[0] == '#')
- event = 11;
- else if ((buf[0] >= 'A') && (buf[0] <= 'D'))
- event = 12 + buf[0] - 'A';
- else
- event = atoi(buf);
- if (event == 16) {
- /* send a FLASH event */
- struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_FLASH, };
- ast_queue_frame(p->owner, &f);
- if (sipdebug)
- ast_verbose("* DTMF-relay event received: FLASH\n");
- } else {
- /* send a DTMF event */
- struct ast_frame f = { AST_FRAME_DTMF, };
- if (event < 10) {
- f.subclass = '0' + event;
- } else if (event < 11) {
- f.subclass = '*';
- } else if (event < 12) {
- f.subclass = '#';
- } else if (event < 16) {
- f.subclass = 'A' + (event - 12);
- }
- f.len = duration;
- ast_queue_frame(p->owner, &f);
- if (sipdebug)
- ast_verbose("* DTMF-relay event received: %c\n", f.subclass);
- }
- transmit_response(p, "200 OK", req);
- return;
- } else if (!strcasecmp(c, "application/media_control+xml")) {
- /* Eh, we'll just assume it's a fast picture update for now */
- if (p->owner)
- ast_queue_control(p->owner, AST_CONTROL_VIDUPDATE);
- transmit_response(p, "200 OK", req);
- return;
- } else if (!ast_strlen_zero(c = get_header(req, "X-ClientCode"))) {
- /* Client code (from SNOM phone) */
- if (ast_test_flag(&p->flags[0], SIP_USECLIENTCODE)) {
- if (p->owner && p->owner->cdr)
- ast_cdr_setuserfield(p->owner, c);
- if (p->owner && ast_bridged_channel(p->owner) && ast_bridged_channel(p->owner)->cdr)
- ast_cdr_setuserfield(ast_bridged_channel(p->owner), c);
- transmit_response(p, "200 OK", req);
- } else {
- transmit_response(p, "403 Unauthorized", req);
- }
- return;
- } else if (ast_strlen_zero(c = get_header(req, "Content-Length")) || !strcasecmp(c, "0")) {
- /* This is probably just a packet making sure the signalling is still up, just send back a 200 OK */
- transmit_response(p, "200 OK", req);
- return;
- }
-
- /* Other type of INFO message, not really understood by Asterisk */
- /* if (get_msg_text(buf, sizeof(buf), req)) { */
-
- ast_log(LOG_WARNING, "Unable to parse INFO message from %s. Content %s\n", p->callid, buf);
- transmit_response(p, "415 Unsupported media type", req);
- return;
-}
-
-/*! \brief Enable SIP Debugging in CLI */
-static int sip_do_debug_ip(int fd, int argc, char *argv[])
-{
- struct hostent *hp;
- struct ast_hostent ahp;
- int port = 0;
- char *p, *arg;
-
- /* sip set debug ip <ip> */
- if (argc != 5)
- return RESULT_SHOWUSAGE;
- p = arg = argv[4];
- strsep(&p, ":");
- if (p)
- port = atoi(p);
- hp = ast_gethostbyname(arg, &ahp);
- if (hp == NULL)
- return RESULT_SHOWUSAGE;
-
- debugaddr.sin_family = AF_INET;
- memcpy(&debugaddr.sin_addr, hp->h_addr, sizeof(debugaddr.sin_addr));
- debugaddr.sin_port = htons(port);
- if (port == 0)
- ast_cli(fd, "SIP Debugging Enabled for IP: %s\n", ast_inet_ntoa(debugaddr.sin_addr));
- else
- ast_cli(fd, "SIP Debugging Enabled for IP: %s:%d\n", ast_inet_ntoa(debugaddr.sin_addr), port);
-
- ast_set_flag(&global_flags[1], SIP_PAGE2_DEBUG_CONSOLE);
-
- return RESULT_SUCCESS;
-}
-
-/*! \brief sip_do_debug_peer: Turn on SIP debugging with peer mask */
-static int sip_do_debug_peer(int fd, int argc, char *argv[])
-{
- struct sip_peer *peer;
- if (argc != 5)
- return RESULT_SHOWUSAGE;
- peer = find_peer(argv[4], NULL, 1, 0);
- if (peer) {
- if (peer->addr.sin_addr.s_addr) {
- debugaddr.sin_family = AF_INET;
- debugaddr.sin_addr = peer->addr.sin_addr;
- debugaddr.sin_port = peer->addr.sin_port;
- ast_cli(fd, "SIP Debugging Enabled for IP: %s:%d\n", ast_inet_ntoa(debugaddr.sin_addr), ntohs(debugaddr.sin_port));
- ast_set_flag(&global_flags[1], SIP_PAGE2_DEBUG_CONSOLE);
- } else
- ast_cli(fd, "Unable to get IP address of peer '%s'\n", argv[4]);
- ASTOBJ_UNREF(peer,sip_destroy_peer);
- } else
- ast_cli(fd, "No such peer '%s'\n", argv[4]);
- return RESULT_SUCCESS;
-}
-
-/*! \brief Turn on SIP debugging (CLI command) */
-static int sip_do_debug(int fd, int argc, char *argv[])
-{
- int oldsipdebug = sipdebug_console;
- if (argc != 3) {
- if (argc != 5)
- return RESULT_SHOWUSAGE;
- else if (strcmp(argv[3], "ip") == 0)
- return sip_do_debug_ip(fd, argc, argv);
- else if (strcmp(argv[3], "peer") == 0)
- return sip_do_debug_peer(fd, argc, argv);
- else
- return RESULT_SHOWUSAGE;
- }
- ast_set_flag(&global_flags[1], SIP_PAGE2_DEBUG_CONSOLE);
- memset(&debugaddr, 0, sizeof(debugaddr));
- ast_cli(fd, "SIP Debugging %senabled\n", oldsipdebug ? "re-" : "");
- return RESULT_SUCCESS;
-}
-
-static int sip_do_debug_deprecated(int fd, int argc, char *argv[])
-{
- int oldsipdebug = sipdebug_console;
- char *newargv[6] = { "sip", "set", "debug", NULL };
- if (argc != 2) {
- if (argc != 4)
- return RESULT_SHOWUSAGE;
- else if (strcmp(argv[2], "ip") == 0) {
- newargv[3] = argv[2];
- newargv[4] = argv[3];
- return sip_do_debug_ip(fd, argc + 1, newargv);
- } else if (strcmp(argv[2], "peer") == 0) {
- newargv[3] = argv[2];
- newargv[4] = argv[3];
- return sip_do_debug_peer(fd, argc + 1, newargv);
- } else
- return RESULT_SHOWUSAGE;
- }
- ast_set_flag(&global_flags[1], SIP_PAGE2_DEBUG_CONSOLE);
- memset(&debugaddr, 0, sizeof(debugaddr));
- ast_cli(fd, "SIP Debugging %senabled\n", oldsipdebug ? "re-" : "");
- return RESULT_SUCCESS;
-}
-
-/*! \brief Cli command to send SIP notify to peer */
-static int sip_notify(int fd, int argc, char *argv[])
-{
- struct ast_variable *varlist;
- int i;
-
- if (argc < 4)
- return RESULT_SHOWUSAGE;
-
- if (!notify_types) {
- ast_cli(fd, "No %s file found, or no types listed there\n", notify_config);
- return RESULT_FAILURE;
- }
-
- varlist = ast_variable_browse(notify_types, argv[2]);
-
- if (!varlist) {
- ast_cli(fd, "Unable to find notify type '%s'\n", argv[2]);
- return RESULT_FAILURE;
- }
-
- for (i = 3; i < argc; i++) {
- struct sip_pvt *p;
- struct sip_request req;
- struct ast_variable *var;
-
- if (!(p = sip_alloc(NULL, NULL, 0, SIP_NOTIFY))) {
- ast_log(LOG_WARNING, "Unable to build sip pvt data for notify (memory/socket error)\n");
- return RESULT_FAILURE;
- }
-
- if (create_addr(p, argv[i])) {
- /* Maybe they're not registered, etc. */
- sip_destroy(p);
- ast_cli(fd, "Could not create address for '%s'\n", argv[i]);
- continue;
- }
-
- initreqprep(&req, p, SIP_NOTIFY);
-
- for (var = varlist; var; var = var->next)
- add_header(&req, var->name, ast_unescape_semicolon(var->value));
-
- /* Recalculate our side, and recalculate Call ID */
- if (ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip))
- p->ourip = __ourip;
- build_via(p);
- build_callid_pvt(p);
- ast_cli(fd, "Sending NOTIFY of type '%s' to '%s'\n", argv[2], argv[i]);
- transmit_sip_request(p, &req);
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- }
-
- return RESULT_SUCCESS;
-}
-
-/*! \brief Disable SIP Debugging in CLI */
-static int sip_no_debug(int fd, int argc, char *argv[])
-{
- if (argc != 4)
- return RESULT_SHOWUSAGE;
- ast_clear_flag(&global_flags[1], SIP_PAGE2_DEBUG_CONSOLE);
- ast_cli(fd, "SIP Debugging Disabled\n");
- return RESULT_SUCCESS;
-}
-
-static int sip_no_debug_deprecated(int fd, int argc, char *argv[])
-{
- if (argc != 3)
- return RESULT_SHOWUSAGE;
- ast_clear_flag(&global_flags[1], SIP_PAGE2_DEBUG_CONSOLE);
- ast_cli(fd, "SIP Debugging Disabled\n");
- return RESULT_SUCCESS;
-}
-
-/*! \brief Enable SIP History logging (CLI) */
-static int sip_do_history(int fd, int argc, char *argv[])
-{
- if (argc != 2) {
- return RESULT_SHOWUSAGE;
- }
- recordhistory = TRUE;
- ast_cli(fd, "SIP History Recording Enabled (use 'sip show history')\n");
- return RESULT_SUCCESS;
-}
-
-/*! \brief Disable SIP History logging (CLI) */
-static int sip_no_history(int fd, int argc, char *argv[])
-{
- if (argc != 3) {
- return RESULT_SHOWUSAGE;
- }
- recordhistory = FALSE;
- ast_cli(fd, "SIP History Recording Disabled\n");
- return RESULT_SUCCESS;
-}
-
-/*! \brief Authenticate for outbound registration */
-static int do_register_auth(struct sip_pvt *p, struct sip_request *req, char *header, char *respheader)
-{
- char digest[1024];
- p->authtries++;
- memset(digest,0,sizeof(digest));
- if (reply_digest(p, req, header, SIP_REGISTER, digest, sizeof(digest))) {
- /* There's nothing to use for authentication */
- /* No digest challenge in request */
- if (sip_debug_test_pvt(p) && p->registry)
- ast_verbose("No authentication challenge, sending blank registration to domain/host name %s\n", p->registry->hostname);
- /* No old challenge */
- return -1;
- }
- if (!ast_test_flag(&p->flags[0], SIP_NO_HISTORY))
- append_history(p, "RegistryAuth", "Try: %d", p->authtries);
- if (sip_debug_test_pvt(p) && p->registry)
- ast_verbose("Responding to challenge, registration to domain/host name %s\n", p->registry->hostname);
- return transmit_register(p->registry, SIP_REGISTER, digest, respheader);
-}
-
-/*! \brief Add authentication on outbound SIP packet */
-static int do_proxy_auth(struct sip_pvt *p, struct sip_request *req, char *header, char *respheader, int sipmethod, int init)
-{
- char digest[1024];
-
- if (!p->options && !(p->options = ast_calloc(1, sizeof(*p->options))))
- return -2;
-
- p->authtries++;
- if (option_debug > 1)
- ast_log(LOG_DEBUG, "Auth attempt %d on %s\n", p->authtries, sip_methods[sipmethod].text);
- memset(digest, 0, sizeof(digest));
- if (reply_digest(p, req, header, sipmethod, digest, sizeof(digest) )) {
- /* No way to authenticate */
- return -1;
- }
- /* Now we have a reply digest */
- p->options->auth = digest;
- p->options->authheader = respheader;
- return transmit_invite(p, sipmethod, sipmethod == SIP_INVITE, init);
-}
-
-/*! \brief reply to authentication for outbound registrations
-\return Returns -1 if we have no auth
-\note This is used for register= servers in sip.conf, SIP proxies we register
- with for receiving calls from. */
-static int reply_digest(struct sip_pvt *p, struct sip_request *req, char *header, int sipmethod, char *digest, int digest_len)
-{
- char tmp[512];
- char *c;
- char oldnonce[256];
-
- /* table of recognised keywords, and places where they should be copied */
- const struct x {
- const char *key;
- int field_index;
- } *i, keys[] = {
- { "realm=", ast_string_field_index(p, realm) },
- { "nonce=", ast_string_field_index(p, nonce) },
- { "opaque=", ast_string_field_index(p, opaque) },
- { "qop=", ast_string_field_index(p, qop) },
- { "domain=", ast_string_field_index(p, domain) },
- { NULL, 0 },
- };
-
- ast_copy_string(tmp, get_header(req, header), sizeof(tmp));
- if (ast_strlen_zero(tmp))
- return -1;
- if (strncasecmp(tmp, "Digest ", strlen("Digest "))) {
- ast_log(LOG_WARNING, "missing Digest.\n");
- return -1;
- }
- c = tmp + strlen("Digest ");
- ast_copy_string(oldnonce, p->nonce, sizeof(oldnonce));
- while (c && *(c = ast_skip_blanks(c))) { /* lookup for keys */
- for (i = keys; i->key != NULL; i++) {
- char *src, *separator;
- if (strncasecmp(c, i->key, strlen(i->key)) != 0)
- continue;
- /* Found. Skip keyword, take text in quotes or up to the separator. */
- c += strlen(i->key);
- if (*c == '"') {
- src = ++c;
- separator = "\"";
- } else {
- src = c;
- separator = ",";
- }
- strsep(&c, separator); /* clear separator and move ptr */
- ast_string_field_index_set(p, i->field_index, src);
- break;
- }
- if (i->key == NULL) /* not found, try ',' */
- strsep(&c, ",");
- }
- /* Reset nonce count */
- if (strcmp(p->nonce, oldnonce))
- p->noncecount = 0;
-
- /* Save auth data for following registrations */
- if (p->registry) {
- struct sip_registry *r = p->registry;
-
- if (strcmp(r->nonce, p->nonce)) {
- ast_string_field_set(r, realm, p->realm);
- ast_string_field_set(r, nonce, p->nonce);
- ast_string_field_set(r, domain, p->domain);
- ast_string_field_set(r, opaque, p->opaque);
- ast_string_field_set(r, qop, p->qop);
- r->noncecount = 0;
- }
- }
- return build_reply_digest(p, sipmethod, digest, digest_len);
-}
-
-/*! \brief Build reply digest
-\return Returns -1 if we have no auth
-\note Build digest challenge for authentication of peers (for registration)
- and users (for calls). Also used for authentication of CANCEL and BYE
-*/
-static int build_reply_digest(struct sip_pvt *p, int method, char* digest, int digest_len)
-{
- char a1[256];
- char a2[256];
- char a1_hash[256];
- char a2_hash[256];
- char resp[256];
- char resp_hash[256];
- char uri[256];
- char opaque[256] = "";
- char cnonce[80];
- const char *username;
- const char *secret;
- const char *md5secret;
- struct sip_auth *auth = NULL; /* Realm authentication */
-
- if (!ast_strlen_zero(p->domain))
- ast_copy_string(uri, p->domain, sizeof(uri));
- else if (!ast_strlen_zero(p->uri))
- ast_copy_string(uri, p->uri, sizeof(uri));
- else
- snprintf(uri, sizeof(uri), "sip:%s@%s",p->username, ast_inet_ntoa(p->sa.sin_addr));
-
- snprintf(cnonce, sizeof(cnonce), "%08lx", ast_random());
-
- /* Check if we have separate auth credentials */
- if(!(auth = find_realm_authentication(p->peerauth, p->realm))) /* Start with peer list */
- auth = find_realm_authentication(authl, p->realm); /* If not, global list */
-
- if (auth) {
- ast_log(LOG_DEBUG, "use realm [%s] from peer [%s][%s]\n", auth->username, p->peername, p->username);
- username = auth->username;
- secret = auth->secret;
- md5secret = auth->md5secret;
- if (sipdebug)
- ast_log(LOG_DEBUG,"Using realm %s authentication for call %s\n", p->realm, p->callid);
- } else {
- /* No authentication, use peer or register= config */
- username = p->authname;
- secret = p->peersecret;
- md5secret = p->peermd5secret;
- }
- if (ast_strlen_zero(username)) /* We have no authentication */
- return -1;
-
- /* Calculate SIP digest response */
- snprintf(a1,sizeof(a1),"%s:%s:%s", username, p->realm, secret);
- snprintf(a2,sizeof(a2),"%s:%s", sip_methods[method].text, uri);
- if (!ast_strlen_zero(md5secret))
- ast_copy_string(a1_hash, md5secret, sizeof(a1_hash));
- else
- ast_md5_hash(a1_hash,a1);
- ast_md5_hash(a2_hash,a2);
-
- p->noncecount++;
- if (!ast_strlen_zero(p->qop))
- snprintf(resp,sizeof(resp),"%s:%s:%08x:%s:%s:%s", a1_hash, p->nonce, p->noncecount, cnonce, "auth", a2_hash);
- else
- snprintf(resp,sizeof(resp),"%s:%s:%s", a1_hash, p->nonce, a2_hash);
- ast_md5_hash(resp_hash, resp);
-
- /* only include the opaque string if it's set */
- if (!ast_strlen_zero(p->opaque)) {
- snprintf(opaque, sizeof(opaque), ", opaque=\"%s\"", p->opaque);
- }
-
- /* XXX We hard code our qop to "auth" for now. XXX */
- if (!ast_strlen_zero(p->qop))
- snprintf(digest, digest_len, "Digest username=\"%s\", realm=\"%s\", algorithm=MD5, uri=\"%s\", nonce=\"%s\", response=\"%s\"%s, qop=auth, cnonce=\"%s\", nc=%08x", username, p->realm, uri, p->nonce, resp_hash, opaque, cnonce, p->noncecount);
- else
- snprintf(digest, digest_len, "Digest username=\"%s\", realm=\"%s\", algorithm=MD5, uri=\"%s\", nonce=\"%s\", response=\"%s\"%s", username, p->realm, uri, p->nonce, resp_hash, opaque);
-
- append_history(p, "AuthResp", "Auth response sent for %s in realm %s - nc %d", username, p->realm, p->noncecount);
-
- return 0;
-}
-
-static char show_domains_usage[] =
-"Usage: sip show domains\n"
-" Lists all configured SIP local domains.\n"
-" Asterisk only responds to SIP messages to local domains.\n";
-
-static char notify_usage[] =
-"Usage: sip notify <type> <peer> [<peer>...]\n"
-" Send a NOTIFY message to a SIP peer or peers\n"
-" Message types are defined in sip_notify.conf\n";
-
-static char show_users_usage[] =
-"Usage: sip show users [like <pattern>]\n"
-" Lists all known SIP users.\n"
-" Optional regular expression pattern is used to filter the user list.\n";
-
-static char show_user_usage[] =
-"Usage: sip show user <name> [load]\n"
-" Shows all details on one SIP user and the current status.\n"
-" Option \"load\" forces lookup of peer in realtime storage.\n";
-
-static char show_inuse_usage[] =
-"Usage: sip show inuse [all]\n"
-" List all SIP users and peers usage counters and limits.\n"
-" Add option \"all\" to show all devices, not only those with a limit.\n";
-
-static char show_channels_usage[] =
-"Usage: sip show channels\n"
-" Lists all currently active SIP channels.\n";
-
-static char show_channel_usage[] =
-"Usage: sip show channel <channel>\n"
-" Provides detailed status on a given SIP channel.\n";
-
-static char show_history_usage[] =
-"Usage: sip show history <channel>\n"
-" Provides detailed dialog history on a given SIP channel.\n";
-
-static char show_peers_usage[] =
-"Usage: sip show peers [like <pattern>]\n"
-" Lists all known SIP peers.\n"
-" Optional regular expression pattern is used to filter the peer list.\n";
-
-static char show_peer_usage[] =
-"Usage: sip show peer <name> [load]\n"
-" Shows all details on one SIP peer and the current status.\n"
-" Option \"load\" forces lookup of peer in realtime storage.\n";
-
-static char prune_realtime_usage[] =
-"Usage: sip prune realtime [peer|user] [<name>|all|like <pattern>]\n"
-" Prunes object(s) from the cache.\n"
-" Optional regular expression pattern is used to filter the objects.\n";
-
-static char show_reg_usage[] =
-"Usage: sip show registry\n"
-" Lists all registration requests and status.\n";
-
-static char debug_usage[] =
-"Usage: sip set debug\n"
-" Enables dumping of SIP packets for debugging purposes\n\n"
-" sip set debug ip <host[:PORT]>\n"
-" Enables dumping of SIP packets to and from host.\n\n"
-" sip set debug peer <peername>\n"
-" Enables dumping of SIP packets to and from host.\n"
-" Require peer to be registered.\n";
-
-static char no_debug_usage[] =
-"Usage: sip set debug off\n"
-" Disables dumping of SIP packets for debugging purposes\n";
-
-static char no_history_usage[] =
-"Usage: sip history off\n"
-" Disables recording of SIP dialog history for debugging purposes\n";
-
-static char history_usage[] =
-"Usage: sip history\n"
-" Enables recording of SIP dialog history for debugging purposes.\n"
-"Use 'sip show history' to view the history of a call number.\n";
-
-static char sip_reload_usage[] =
-"Usage: sip reload\n"
-" Reloads SIP configuration from sip.conf\n";
-
-static char show_subscriptions_usage[] =
-"Usage: sip show subscriptions\n"
-" Lists active SIP subscriptions for extension states\n";
-
-static char show_objects_usage[] =
-"Usage: sip show objects\n"
-" Lists status of known SIP objects\n";
-
-static char show_settings_usage[] =
-"Usage: sip show settings\n"
-" Provides detailed list of the configuration of the SIP channel.\n";
-
-/*! \brief Read SIP header (dialplan function) */
-static int func_header_read(struct ast_channel *chan, char *function, char *data, char *buf, size_t len)
-{
- struct sip_pvt *p;
- const char *content = NULL;
- AST_DECLARE_APP_ARGS(args,
- AST_APP_ARG(header);
- AST_APP_ARG(number);
- );
- int i, number, start = 0;
-
- if (ast_strlen_zero(data)) {
- ast_log(LOG_WARNING, "This function requires a header name.\n");
- return -1;
- }
-
- ast_channel_lock(chan);
- if (chan->tech != &sip_tech && chan->tech != &sip_tech_info) {
- ast_log(LOG_WARNING, "This function can only be used on SIP channels.\n");
- ast_channel_unlock(chan);
- return -1;
- }
-
- AST_STANDARD_APP_ARGS(args, data);
- if (!args.number) {
- number = 1;
- } else {
- sscanf(args.number, "%d", &number);
- if (number < 1)
- number = 1;
- }
-
- p = chan->tech_pvt;
-
- /* If there is no private structure, this channel is no longer alive */
- if (!p) {
- ast_channel_unlock(chan);
- return -1;
- }
-
- for (i = 0; i < number; i++)
- content = __get_header(&p->initreq, args.header, &start);
-
- if (ast_strlen_zero(content)) {
- ast_channel_unlock(chan);
- return -1;
- }
-
- ast_copy_string(buf, content, len);
- ast_channel_unlock(chan);
-
- return 0;
-}
-
-static struct ast_custom_function sip_header_function = {
- .name = "SIP_HEADER",
- .synopsis = "Gets the specified SIP header",
- .syntax = "SIP_HEADER(<name>[,<number>])",
- .desc = "Since there are several headers (such as Via) which can occur multiple\n"
- "times, SIP_HEADER takes an optional second argument to specify which header with\n"
- "that name to retrieve. Headers start at offset 1.\n",
- .read = func_header_read,
-};
-
-/*! \brief Dial plan function to check if domain is local */
-static int func_check_sipdomain(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
-{
- if (ast_strlen_zero(data)) {
- ast_log(LOG_WARNING, "CHECKSIPDOMAIN requires an argument - A domain name\n");
- return -1;
- }
- if (check_sip_domain(data, NULL, 0))
- ast_copy_string(buf, data, len);
- else
- buf[0] = '\0';
- return 0;
-}
-
-static struct ast_custom_function checksipdomain_function = {
- .name = "CHECKSIPDOMAIN",
- .synopsis = "Checks if domain is a local domain",
- .syntax = "CHECKSIPDOMAIN(<domain|IP>)",
- .read = func_check_sipdomain,
- .desc = "This function checks if the domain in the argument is configured\n"
- "as a local SIP domain that this Asterisk server is configured to handle.\n"
- "Returns the domain name if it is locally handled, otherwise an empty string.\n"
- "Check the domain= configuration in sip.conf\n",
-};
-
-/*! \brief ${SIPPEER()} Dialplan function - reads peer data */
-static int function_sippeer(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
-{
- struct sip_peer *peer;
- char *colname;
-
- if ((colname = strchr(data, ':'))) /*! \todo Will be deprecated after 1.4 */
- *colname++ = '\0';
- else if ((colname = strchr(data, '|')))
- *colname++ = '\0';
- else
- colname = "ip";
-
- if (!(peer = find_peer(data, NULL, 1, 0)))
- return -1;
-
- if (!strcasecmp(colname, "ip")) {
- ast_copy_string(buf, peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "", len);
- } else if (!strcasecmp(colname, "status")) {
- peer_status(peer, buf, len);
- } else if (!strcasecmp(colname, "language")) {
- ast_copy_string(buf, peer->language, len);
- } else if (!strcasecmp(colname, "regexten")) {
- ast_copy_string(buf, peer->regexten, len);
- } else if (!strcasecmp(colname, "limit")) {
- snprintf(buf, len, "%d", peer->call_limit);
- } else if (!strcasecmp(colname, "curcalls")) {
- snprintf(buf, len, "%d", peer->inUse);
- } else if (!strcasecmp(colname, "accountcode")) {
- ast_copy_string(buf, peer->accountcode, len);
- } else if (!strcasecmp(colname, "useragent")) {
- ast_copy_string(buf, peer->useragent, len);
- } else if (!strcasecmp(colname, "mailbox")) {
- ast_copy_string(buf, peer->mailbox, len);
- } else if (!strcasecmp(colname, "context")) {
- ast_copy_string(buf, peer->context, len);
- } else if (!strcasecmp(colname, "expire")) {
- snprintf(buf, len, "%d", peer->expire);
- } else if (!strcasecmp(colname, "dynamic")) {
- ast_copy_string(buf, (ast_test_flag(&peer->flags[1], SIP_PAGE2_DYNAMIC) ? "yes" : "no"), len);
- } else if (!strcasecmp(colname, "callerid_name")) {
- ast_copy_string(buf, peer->cid_name, len);
- } else if (!strcasecmp(colname, "callerid_num")) {
- ast_copy_string(buf, peer->cid_num, len);
- } else if (!strcasecmp(colname, "codecs")) {
- ast_getformatname_multiple(buf, len -1, peer->capability);
- } else if (!strncasecmp(colname, "codec[", 6)) {
- char *codecnum;
- int index = 0, codec = 0;
-
- codecnum = colname + 6; /* move past the '[' */
- codecnum = strsep(&codecnum, "]"); /* trim trailing ']' if any */
- index = atoi(codecnum);
- if((codec = ast_codec_pref_index(&peer->prefs, index))) {
- ast_copy_string(buf, ast_getformatname(codec), len);
- } else {
- buf[0] = '\0';
- }
- } else {
- buf[0] = '\0';
- }
-
- ASTOBJ_UNREF(peer, sip_destroy_peer);
-
- return 0;
-}
-
-/*! \brief Structure to declare a dialplan function: SIPPEER */
-struct ast_custom_function sippeer_function = {
- .name = "SIPPEER",
- .synopsis = "Gets SIP peer information",
- .syntax = "SIPPEER(<peername>[|item])",
- .read = function_sippeer,
- .desc = "Valid items are:\n"
- "- ip (default) The IP address.\n"
- "- mailbox The configured mailbox.\n"
- "- context The configured context.\n"
- "- expire The epoch time of the next expire.\n"
- "- dynamic Is it dynamic? (yes/no).\n"
- "- callerid_name The configured Caller ID name.\n"
- "- callerid_num The configured Caller ID number.\n"
- "- codecs The configured codecs.\n"
- "- status Status (if qualify=yes).\n"
- "- regexten Registration extension\n"
- "- limit Call limit (call-limit)\n"
- "- curcalls Current amount of calls \n"
- " Only available if call-limit is set\n"
- "- language Default language for peer\n"
- "- accountcode Account code for this peer\n"
- "- useragent Current user agent id for peer\n"
- "- codec[x] Preferred codec index number 'x' (beginning with zero).\n"
- "\n"
-};
-
-/*! \brief ${SIPCHANINFO()} Dialplan function - reads sip channel data */
-static int function_sipchaninfo_read(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
-{
- struct sip_pvt *p;
-
- *buf = 0;
-
- if (!data) {
- ast_log(LOG_WARNING, "This function requires a parameter name.\n");
- return -1;
- }
-
- ast_channel_lock(chan);
- if (chan->tech != &sip_tech && chan->tech != &sip_tech_info) {
- ast_log(LOG_WARNING, "This function can only be used on SIP channels.\n");
- ast_channel_unlock(chan);
- return -1;
- }
-
- p = chan->tech_pvt;
-
- /* If there is no private structure, this channel is no longer alive */
- if (!p) {
- ast_channel_unlock(chan);
- return -1;
- }
-
- if (!strcasecmp(data, "peerip")) {
- ast_copy_string(buf, p->sa.sin_addr.s_addr ? ast_inet_ntoa(p->sa.sin_addr) : "", len);
- } else if (!strcasecmp(data, "recvip")) {
- ast_copy_string(buf, p->recv.sin_addr.s_addr ? ast_inet_ntoa(p->recv.sin_addr) : "", len);
- } else if (!strcasecmp(data, "from")) {
- ast_copy_string(buf, p->from, len);
- } else if (!strcasecmp(data, "uri")) {
- ast_copy_string(buf, p->uri, len);
- } else if (!strcasecmp(data, "useragent")) {
- ast_copy_string(buf, p->useragent, len);
- } else if (!strcasecmp(data, "peername")) {
- ast_copy_string(buf, p->peername, len);
- } else if (!strcasecmp(data, "t38passthrough")) {
- if (p->t38.state == T38_DISABLED)
- ast_copy_string(buf, "0", sizeof("0"));
- else /* T38 is offered or enabled in this call */
- ast_copy_string(buf, "1", sizeof("1"));
- } else {
- ast_channel_unlock(chan);
- return -1;
- }
- ast_channel_unlock(chan);
-
- return 0;
-}
-
-/*! \brief Structure to declare a dialplan function: SIPCHANINFO */
-static struct ast_custom_function sipchaninfo_function = {
- .name = "SIPCHANINFO",
- .synopsis = "Gets the specified SIP parameter from the current channel",
- .syntax = "SIPCHANINFO(item)",
- .read = function_sipchaninfo_read,
- .desc = "Valid items are:\n"
- "- peerip The IP address of the peer.\n"
- "- recvip The source IP address of the peer.\n"
- "- from The URI from the From: header.\n"
- "- uri The URI from the Contact: header.\n"
- "- useragent The useragent.\n"
- "- peername The name of the peer.\n"
- "- t38passthrough 1 if T38 is offered or enabled in this channel, otherwise 0\n"
-};
-
-/*! \brief Parse 302 Moved temporalily response */
-static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req)
-{
- char tmp[SIPBUFSIZE];
- char *s, *e, *uri, *t;
- char *domain;
-
- ast_copy_string(tmp, get_header(req, "Contact"), sizeof(tmp));
- if ((t = strchr(tmp, ',')))
- *t = '\0';
- s = get_in_brackets(tmp);
- uri = ast_strdupa(s);
- if (ast_test_flag(&p->flags[0], SIP_PROMISCREDIR)) {
- if (!strncasecmp(s, "sip:", 4))
- s += 4;
- e = strchr(s, ';');
- if (e)
- *e = '\0';
- if (option_debug)
- ast_log(LOG_DEBUG, "Found promiscuous redirection to 'SIP/%s'\n", s);
- if (p->owner)
- ast_string_field_build(p->owner, call_forward, "SIP/%s", s);
- } else {
- e = strchr(tmp, '@');
- if (e) {
- *e++ = '\0';
- domain = e;
- } else {
- /* No username part */
- domain = tmp;
- }
- e = strchr(s, ';'); /* Strip of parameters in the username part */
- if (e)
- *e = '\0';
- e = strchr(domain, ';'); /* Strip of parameters in the domain part */
- if (e)
- *e = '\0';
-
- if (!strncasecmp(s, "sip:", 4))
- s += 4;
- if (option_debug > 1)
- ast_log(LOG_DEBUG, "Received 302 Redirect to extension '%s' (domain %s)\n", s, domain);
- if (p->owner) {
- pbx_builtin_setvar_helper(p->owner, "SIPREDIRECTURI", uri);
- pbx_builtin_setvar_helper(p->owner, "SIPDOMAIN", domain);
- ast_string_field_set(p->owner, call_forward, s);
- }
- }
-}
-
-/*! \brief Check pending actions on SIP call */
-static void check_pendings(struct sip_pvt *p)
-{
- if (ast_test_flag(&p->flags[0], SIP_PENDINGBYE)) {
- /* if we can't BYE, then this is really a pending CANCEL */
- if (p->invitestate == INV_PROCEEDING || p->invitestate == INV_EARLY_MEDIA)
- transmit_request(p, SIP_CANCEL, p->lastinvite, XMIT_RELIABLE, FALSE);
- /* Actually don't destroy us yet, wait for the 487 on our original
- INVITE, but do set an autodestruct just in case we never get it. */
- else {
- /* We have a pending outbound invite, don't send someting
- new in-transaction */
- if (p->pendinginvite)
- return;
-
- /* Perhaps there is an SD change INVITE outstanding */
- transmit_request_with_auth(p, SIP_BYE, 0, XMIT_RELIABLE, TRUE);
- }
- ast_clear_flag(&p->flags[0], SIP_PENDINGBYE);
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- } else if (ast_test_flag(&p->flags[0], SIP_NEEDREINVITE)) {
- /* if we can't REINVITE, hold it for later */
- if (p->pendinginvite || p->invitestate == INV_CALLING || p->invitestate == INV_PROCEEDING || p->invitestate == INV_EARLY_MEDIA || p->waitid > 0) {
- if (option_debug)
- ast_log(LOG_DEBUG, "NOT Sending pending reinvite (yet) on '%s'\n", p->callid);
- } else {
- if (option_debug)
- ast_log(LOG_DEBUG, "Sending pending reinvite on '%s'\n", p->callid);
- /* Didn't get to reinvite yet, so do it now */
- transmit_reinvite_with_sdp(p);
- ast_clear_flag(&p->flags[0], SIP_NEEDREINVITE);
- }
- }
-}
-
-/*! \brief Reset the NEEDREINVITE flag after waiting when we get 491 on a Re-invite
- to avoid race conditions between asterisk servers.
- Called from the scheduler.
-*/
-static int sip_reinvite_retry(const void *data)
-{
- struct sip_pvt *p = (struct sip_pvt *) data;
-
- ast_set_flag(&p->flags[0], SIP_NEEDREINVITE);
- p->waitid = -1;
- return 0;
-}
-
-
-/*! \brief Handle SIP response to INVITE dialogue */
-static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int seqno)
-{
- int outgoing = ast_test_flag(&p->flags[0], SIP_OUTGOING);
- int res = 0;
- int xmitres = 0;
- int reinvite = (p->owner && p->owner->_state == AST_STATE_UP);
- struct ast_channel *bridgepeer = NULL;
-
- if (option_debug > 3) {
- if (reinvite)
- ast_log(LOG_DEBUG, "SIP response %d to RE-invite on %s call %s\n", resp, outgoing ? "outgoing" : "incoming", p->callid);
- else
- ast_log(LOG_DEBUG, "SIP response %d to standard invite\n", resp);
- }
-
- if (ast_test_flag(&p->flags[0], SIP_ALREADYGONE)) { /* This call is already gone */
- if (option_debug)
- ast_log(LOG_DEBUG, "Got response on call that is already terminated: %s (ignoring)\n", p->callid);
- return;
- }
-
- /* Acknowledge sequence number - This only happens on INVITE from SIP-call */
- /* Don't auto congest anymore since we've gotten something useful back */
- AST_SCHED_DEL(sched, p->initid);
-
- /* RFC3261 says we must treat every 1xx response (but not 100)
- that we don't recognize as if it was 183.
- */
- if (resp > 100 && resp < 200 && resp!=101 && resp != 180 && resp != 182 && resp != 183)
- resp = 183;
-
- /* Any response between 100 and 199 is PROCEEDING */
- if (resp >= 100 && resp < 200 && p->invitestate == INV_CALLING)
- p->invitestate = INV_PROCEEDING;
-
- /* Final response, not 200 ? */
- if (resp >= 300 && (p->invitestate == INV_CALLING || p->invitestate == INV_PROCEEDING || p->invitestate == INV_EARLY_MEDIA ))
- p->invitestate = INV_COMPLETED;
-
-
- switch (resp) {
- case 100: /* Trying */
- case 101: /* Dialog establishment */
- if (!ast_test_flag(req, SIP_PKT_IGNORE) && (p->invitestate != INV_CANCELLED) && sip_cancel_destroy(p))
- ast_log(LOG_WARNING, "Unable to cancel SIP destruction. Expect bad things.\n");
- check_pendings(p);
- break;
-
- case 180: /* 180 Ringing */
- case 182: /* 182 Queued */
- if (!ast_test_flag(req, SIP_PKT_IGNORE) && (p->invitestate != INV_CANCELLED) && sip_cancel_destroy(p))
- ast_log(LOG_WARNING, "Unable to cancel SIP destruction. Expect bad things.\n");
- if (!ast_test_flag(req, SIP_PKT_IGNORE) && p->owner) {
- ast_queue_control(p->owner, AST_CONTROL_RINGING);
- if (p->owner->_state != AST_STATE_UP) {
- ast_setstate(p->owner, AST_STATE_RINGING);
- }
- }
- if (find_sdp(req)) {
- if (p->invitestate != INV_CANCELLED)
- p->invitestate = INV_EARLY_MEDIA;
- res = process_sdp(p, req);
- if (!ast_test_flag(req, SIP_PKT_IGNORE) && p->owner) {
- /* Queue a progress frame only if we have SDP in 180 or 182 */
- ast_queue_control(p->owner, AST_CONTROL_PROGRESS);
- }
- }
- check_pendings(p);
- break;
-
- case 183: /* Session progress */
- if (!ast_test_flag(req, SIP_PKT_IGNORE) && (p->invitestate != INV_CANCELLED) && sip_cancel_destroy(p))
- ast_log(LOG_WARNING, "Unable to cancel SIP destruction. Expect bad things.\n");
- /* Ignore 183 Session progress without SDP */
- if (find_sdp(req)) {
- if (p->invitestate != INV_CANCELLED)
- p->invitestate = INV_EARLY_MEDIA;
- res = process_sdp(p, req);
- if (!ast_test_flag(req, SIP_PKT_IGNORE) && p->owner) {
- /* Queue a progress frame */
- ast_queue_control(p->owner, AST_CONTROL_PROGRESS);
- }
- }
- check_pendings(p);
- break;
-
- case 200: /* 200 OK on invite - someone's answering our call */
- if (!ast_test_flag(req, SIP_PKT_IGNORE) && (p->invitestate != INV_CANCELLED) && sip_cancel_destroy(p))
- ast_log(LOG_WARNING, "Unable to cancel SIP destruction. Expect bad things.\n");
- p->authtries = 0;
- if (find_sdp(req)) {
- if ((res = process_sdp(p, req)) && !ast_test_flag(req, SIP_PKT_IGNORE))
- if (!reinvite)
- /* This 200 OK's SDP is not acceptable, so we need to ack, then hangup */
- /* For re-invites, we try to recover */
- ast_set_flag(&p->flags[0], SIP_PENDINGBYE);
- }
-
- /* Parse contact header for continued conversation */
- /* When we get 200 OK, we know which device (and IP) to contact for this call */
- /* This is important when we have a SIP proxy between us and the phone */
- if (outgoing) {
- update_call_counter(p, DEC_CALL_RINGING);
- parse_ok_contact(p, req);
- /* Save Record-Route for any later requests we make on this dialogue */
- if (!reinvite)
- build_route(p, req, 1);
-
- if(set_address_from_contact(p)) {
- /* Bad contact - we don't know how to reach this device */
- /* We need to ACK, but then send a bye */
- if (!p->route && !ast_test_flag(req, SIP_PKT_IGNORE))
- ast_set_flag(&p->flags[0], SIP_PENDINGBYE);
- }
-
- }
-
- if (p->owner && (p->owner->_state == AST_STATE_UP) && (bridgepeer = ast_bridged_channel(p->owner))) { /* if this is a re-invite */
- struct sip_pvt *bridgepvt = NULL;
-
- if (!bridgepeer->tech) {
- ast_log(LOG_WARNING, "Ooooh.. no tech! That's REALLY bad\n");
- break;
- }
- if (bridgepeer->tech == &sip_tech || bridgepeer->tech == &sip_tech_info) {
- bridgepvt = (struct sip_pvt*)(bridgepeer->tech_pvt);
- if (bridgepvt->udptl) {
- if (p->t38.state == T38_PEER_REINVITE) {
- sip_handle_t38_reinvite(bridgepeer, p, 0);
- ast_rtp_set_rtptimers_onhold(p->rtp);
- if (p->vrtp)
- ast_rtp_set_rtptimers_onhold(p->vrtp); /* Turn off RTP timers while we send fax */
- } else if (p->t38.state == T38_DISABLED && bridgepeer && (bridgepvt->t38.state == T38_ENABLED)) {
- ast_log(LOG_WARNING, "RTP re-invite after T38 session not handled yet !\n");
- /* Insted of this we should somehow re-invite the other side of the bridge to RTP */
- /* XXXX Should we really destroy this session here, without any response at all??? */
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- }
- } else {
- if (option_debug > 1)
- ast_log(LOG_DEBUG, "Strange... The other side of the bridge does not have a udptl struct\n");
- ast_mutex_lock(&bridgepvt->lock);
- bridgepvt->t38.state = T38_DISABLED;
- ast_mutex_unlock(&bridgepvt->lock);
- if (option_debug)
- ast_log(LOG_DEBUG,"T38 state changed to %d on channel %s\n", bridgepvt->t38.state, bridgepeer->tech->type);
- p->t38.state = T38_DISABLED;
- if (option_debug > 1)
- ast_log(LOG_DEBUG,"T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
- }
- } else {
- /* Other side is not a SIP channel */
- if (option_debug > 1)
- ast_log(LOG_DEBUG, "Strange... The other side of the bridge is not a SIP channel\n");
- p->t38.state = T38_DISABLED;
- if (option_debug > 1)
- ast_log(LOG_DEBUG,"T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
- }
- }
- if ((p->t38.state == T38_LOCAL_REINVITE) || (p->t38.state == T38_LOCAL_DIRECT)) {
- /* If there was T38 reinvite and we are supposed to answer with 200 OK than this should set us to T38 negotiated mode */
- p->t38.state = T38_ENABLED;
- if (option_debug)
- ast_log(LOG_DEBUG, "T38 changed state to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
- }
-
- if (!ast_test_flag(req, SIP_PKT_IGNORE) && p->owner) {
- if (!reinvite) {
- ast_queue_control(p->owner, AST_CONTROL_ANSWER);
- } else { /* RE-invite */
- ast_queue_frame(p->owner, &ast_null_frame);
- }
- } else {
- /* It's possible we're getting an 200 OK after we've tried to disconnect
- by sending CANCEL */
- /* First send ACK, then send bye */
- if (!ast_test_flag(req, SIP_PKT_IGNORE))
- ast_set_flag(&p->flags[0], SIP_PENDINGBYE);
- }
- /* If I understand this right, the branch is different for a non-200 ACK only */
- p->invitestate = INV_TERMINATED;
- ast_set_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED);
- xmitres = transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, TRUE);
- check_pendings(p);
- break;
- case 407: /* Proxy authentication */
- case 401: /* Www auth */
- /* First we ACK */
- xmitres = transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, FALSE);
- if (p->options)
- p->options->auth_type = (resp == 401 ? WWW_AUTH : PROXY_AUTH);
-
- /* Then we AUTH */
- ast_string_field_free(p, theirtag); /* forget their old tag, so we don't match tags when getting response */
- if (!ast_test_flag(req, SIP_PKT_IGNORE)) {
- char *authenticate = (resp == 401 ? "WWW-Authenticate" : "Proxy-Authenticate");
- char *authorization = (resp == 401 ? "Authorization" : "Proxy-Authorization");
- if (p->authtries < MAX_AUTHTRIES)
- p->invitestate = INV_CALLING;
- if ((p->authtries == MAX_AUTHTRIES) || do_proxy_auth(p, req, authenticate, authorization, SIP_INVITE, 1)) {
- ast_log(LOG_NOTICE, "Failed to authenticate on INVITE to '%s'\n", get_header(&p->initreq, "From"));
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- sip_alreadygone(p);
- if (p->owner)
- ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
- }
- }
- break;
-
- case 403: /* Forbidden */
- /* First we ACK */
- xmitres = transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, FALSE);
- ast_log(LOG_WARNING, "Received response: \"Forbidden\" from '%s'\n", get_header(&p->initreq, "From"));
- if (!ast_test_flag(req, SIP_PKT_IGNORE) && p->owner)
- ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- sip_alreadygone(p);
- break;
-
- case 404: /* Not found */
- xmitres = transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, FALSE);
- if (p->owner && !ast_test_flag(req, SIP_PKT_IGNORE))
- ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
- sip_alreadygone(p);
- break;
-
- case 408: /* Request timeout */
- case 481: /* Call leg does not exist */
- /* Could be REFER caused INVITE with replaces */
- ast_log(LOG_WARNING, "Re-invite to non-existing call leg on other UA. SIP dialog '%s'. Giving up.\n", p->callid);
- xmitres = transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, FALSE);
- if (p->owner)
- ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- break;
- case 487: /* Cancelled transaction */
- /* We have sent CANCEL on an outbound INVITE
- This transaction is already scheduled to be killed by sip_hangup().
- */
- xmitres = transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, FALSE);
- if (p->owner && !ast_test_flag(req, SIP_PKT_IGNORE)) {
- ast_queue_hangup(p->owner);
- append_history(p, "Hangup", "Got 487 on CANCEL request from us. Queued AST hangup request");
- } else if (!ast_test_flag(req, SIP_PKT_IGNORE)) {
- update_call_counter(p, DEC_CALL_LIMIT);
- append_history(p, "Hangup", "Got 487 on CANCEL request from us on call without owner. Killing this dialog.");
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- sip_alreadygone(p);
- }
- break;
- case 488: /* Not acceptable here */
- xmitres = transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, FALSE);
- if (reinvite && p->udptl) {
- /* If this is a T.38 call, we should go back to
- audio. If this is an audio call - something went
- terribly wrong since we don't renegotiate codecs,
- only IP/port .
- */
- p->t38.state = T38_DISABLED;
- /* Try to reset RTP timers */
- ast_rtp_set_rtptimers_onhold(p->rtp);
- ast_log(LOG_ERROR, "Got error on T.38 re-invite. Bad configuration. Peer needs to have T.38 disabled.\n");
-
- /*! \bug Is there any way we can go back to the audio call on both
- sides here?
- */
- /* While figuring that out, hangup the call */
- if (p->owner && !ast_test_flag(req, SIP_PKT_IGNORE))
- ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- } else if (p->udptl && p->t38.state == T38_LOCAL_DIRECT) {
- /* We tried to send T.38 out in an initial INVITE and the remote side rejected it,
- right now we can't fall back to audio so totally abort.
- */
- p->t38.state = T38_DISABLED;
- /* Try to reset RTP timers */
- ast_rtp_set_rtptimers_onhold(p->rtp);
- ast_log(LOG_ERROR, "Got error on T.38 initial invite. Bailing out.\n");
-
- /* The dialog is now terminated */
- if (p->owner && !ast_test_flag(req, SIP_PKT_IGNORE))
- ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- sip_alreadygone(p);
- } else {
- /* We can't set up this call, so give up */
- if (p->owner && !ast_test_flag(req, SIP_PKT_IGNORE))
- ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- /* If there's no dialog to end, then mark p as already gone */
- if (!reinvite)
- sip_alreadygone(p);
- }
- break;
- case 491: /* Pending */
- /* we really should have to wait a while, then retransmit
- * We should support the retry-after at some point
- * At this point, we treat this as a congestion if the call is not in UP state
- */
- xmitres = transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, FALSE);
- if (p->owner && !ast_test_flag(req, SIP_PKT_IGNORE)) {
- if (p->owner->_state != AST_STATE_UP) {
- ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- } else {
- /* This is a re-invite that failed.
- * Reset the flag after a while
- */
- int wait = 3 + ast_random() % 5;
- p->waitid = ast_sched_add(sched, wait, sip_reinvite_retry, p);
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Reinvite race. Waiting %d secs before retry\n", wait);
- }
- }
- break;
-
- case 501: /* Not implemented */
- xmitres = transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, FALSE);
- if (p->owner)
- ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
- break;
- }
- if (xmitres == XMIT_ERROR)
- ast_log(LOG_WARNING, "Could not transmit message in dialog %s\n", p->callid);
-}
-
-/* \brief Handle SIP response in REFER transaction
- We've sent a REFER, now handle responses to it
- */
-static void handle_response_refer(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int seqno)
-{
- char *auth = "Proxy-Authenticate";
- char *auth2 = "Proxy-Authorization";
-
- /* If no refer structure exists, then do nothing */
- if (!p->refer)
- return;
-
- switch (resp) {
- case 202: /* Transfer accepted */
- /* We need to do something here */
- /* The transferee is now sending INVITE to target */
- p->refer->status = REFER_ACCEPTED;
- /* Now wait for next message */
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Got 202 accepted on transfer\n");
- /* We should hang along, waiting for NOTIFY's here */
- break;
-
- case 401: /* Not www-authorized on SIP method */
- case 407: /* Proxy auth */
- if (ast_strlen_zero(p->authname)) {
- ast_log(LOG_WARNING, "Asked to authenticate REFER to %s:%d but we have no matching peer or realm auth!\n",
- ast_inet_ntoa(p->recv.sin_addr), ntohs(p->recv.sin_port));
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- }
- if (resp == 401) {
- auth = "WWW-Authenticate";
- auth2 = "Authorization";
- }
- if ((p->authtries > 1) || do_proxy_auth(p, req, auth, auth2, SIP_REFER, 0)) {
- ast_log(LOG_NOTICE, "Failed to authenticate on REFER to '%s'\n", get_header(&p->initreq, "From"));
- p->refer->status = REFER_NOAUTH;
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- }
- break;
- case 481: /* Call leg does not exist */
-
- /* A transfer with Replaces did not work */
- /* OEJ: We should Set flag, cancel the REFER, go back
- to original call - but right now we can't */
- ast_log(LOG_WARNING, "Remote host can't match REFER request to call '%s'. Giving up.\n", p->callid);
- if (p->owner)
- ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- break;
-
- case 500: /* Server error */
- case 501: /* Method not implemented */
- /* Return to the current call onhold */
- /* Status flag needed to be reset */
- ast_log(LOG_NOTICE, "SIP transfer to %s failed, call miserably fails. \n", p->refer->refer_to);
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- p->refer->status = REFER_FAILED;
- break;
- case 603: /* Transfer declined */
- ast_log(LOG_NOTICE, "SIP transfer to %s declined, call miserably fails. \n", p->refer->refer_to);
- p->refer->status = REFER_FAILED;
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- break;
- }
-}
-
-/*! \brief Handle responses on REGISTER to services */
-static int handle_response_register(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int ignore, int seqno)
-{
- int expires, expires_ms;
- struct sip_registry *r;
- r=p->registry;
-
- switch (resp) {
- case 401: /* Unauthorized */
- if ((p->authtries == MAX_AUTHTRIES) || do_register_auth(p, req, "WWW-Authenticate", "Authorization")) {
- ast_log(LOG_NOTICE, "Failed to authenticate on REGISTER to '%s@%s' (Tries %d)\n", p->registry->username, p->registry->hostname, p->authtries);
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- }
- break;
- case 403: /* Forbidden */
- ast_log(LOG_WARNING, "Forbidden - wrong password on authentication for REGISTER for '%s' to '%s'\n", p->registry->username, p->registry->hostname);
- if (global_regattempts_max)
- p->registry->regattempts = global_regattempts_max+1;
- AST_SCHED_DEL(sched, r->timeout);
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- break;
- case 404: /* Not found */
- ast_log(LOG_WARNING, "Got 404 Not found on SIP register to service %s@%s, giving up\n", p->registry->username,p->registry->hostname);
- if (global_regattempts_max)
- p->registry->regattempts = global_regattempts_max+1;
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- r->call = NULL;
- AST_SCHED_DEL(sched, r->timeout);
- break;
- case 407: /* Proxy auth */
- if ((p->authtries == MAX_AUTHTRIES) || do_register_auth(p, req, "Proxy-Authenticate", "Proxy-Authorization")) {
- ast_log(LOG_NOTICE, "Failed to authenticate on REGISTER to '%s' (tries '%d')\n", get_header(&p->initreq, "From"), p->authtries);
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- }
- break;
- case 408: /* Request timeout */
- /* Got a timeout response, so reset the counter of failed responses */
- r->regattempts = 0;
- break;
- case 479: /* SER: Not able to process the URI - address is wrong in register*/
- ast_log(LOG_WARNING, "Got error 479 on register to %s@%s, giving up (check config)\n", p->registry->username,p->registry->hostname);
- if (global_regattempts_max)
- p->registry->regattempts = global_regattempts_max+1;
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- r->call = NULL;
- AST_SCHED_DEL(sched, r->timeout);
- break;
- case 200: /* 200 OK */
- if (!r) {
- ast_log(LOG_WARNING, "Got 200 OK on REGISTER, but there isn't a registry entry for '%s' (we probably already got the OK)\n", S_OR(p->peername, p->username));
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- return 0;
- }
-
- r->regstate = REG_STATE_REGISTERED;
- r->regtime = time(NULL); /* Reset time of last succesful registration */
- manager_event(EVENT_FLAG_SYSTEM, "Registry", "ChannelDriver: SIP\r\nDomain: %s\r\nStatus: %s\r\n", r->hostname, regstate2str(r->regstate));
- r->regattempts = 0;
- if (option_debug)
- ast_log(LOG_DEBUG, "Registration successful\n");
- if (r->timeout > -1) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Cancelling timeout %d\n", r->timeout);
- }
- AST_SCHED_DEL(sched, r->timeout);
- r->call = NULL;
- p->registry = NULL;
- /* Let this one hang around until we have all the responses */
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- /* ast_set_flag(&p->flags[0], SIP_NEEDDESTROY); */
-
- /* set us up for re-registering */
- /* figure out how long we got registered for */
- AST_SCHED_DEL(sched, r->expire);
- /* according to section 6.13 of RFC, contact headers override
- expires headers, so check those first */
- expires = 0;
-
- /* XXX todo: try to save the extra call */
- if (!ast_strlen_zero(get_header(req, "Contact"))) {
- const char *contact = NULL;
- const char *tmptmp = NULL;
- int start = 0;
- for(;;) {
- contact = __get_header(req, "Contact", &start);
- /* this loop ensures we get a contact header about our register request */
- if(!ast_strlen_zero(contact)) {
- if( (tmptmp=strstr(contact, p->our_contact))) {
- contact=tmptmp;
- break;
- }
- } else
- break;
- }
- tmptmp = strcasestr(contact, "expires=");
- if (tmptmp) {
- if (sscanf(tmptmp + 8, "%d;", &expires) != 1)
- expires = 0;
- }
-
- }
- if (!expires)
- expires=atoi(get_header(req, "expires"));
- if (!expires)
- expires=default_expiry;
-
- expires_ms = expires * 1000;
- if (expires <= EXPIRY_GUARD_LIMIT)
- expires_ms -= MAX((expires_ms * EXPIRY_GUARD_PCT),EXPIRY_GUARD_MIN);
- else
- expires_ms -= EXPIRY_GUARD_SECS * 1000;
- if (sipdebug)
- ast_log(LOG_NOTICE, "Outbound Registration: Expiry for %s is %d sec (Scheduling reregistration in %d s)\n", r->hostname, expires, expires_ms/1000);
-
- r->refresh= (int) expires_ms / 1000;
-
- /* Schedule re-registration before we expire */
- AST_SCHED_DEL(sched, r->expire);
- r->expire = ast_sched_add(sched, expires_ms, sip_reregister, r);
- ASTOBJ_UNREF(r, sip_registry_destroy);
- }
- return 1;
-}
-
-/*! \brief Handle qualification responses (OPTIONS) */
-static void handle_response_peerpoke(struct sip_pvt *p, int resp, struct sip_request *req)
-{
- struct sip_peer *peer = p->relatedpeer;
- int statechanged, is_reachable, was_reachable;
- int pingtime = ast_tvdiff_ms(ast_tvnow(), peer->ps);
-
- /*
- * Compute the response time to a ping (goes in peer->lastms.)
- * -1 means did not respond, 0 means unknown,
- * 1..maxms is a valid response, >maxms means late response.
- */
- if (pingtime < 1) /* zero = unknown, so round up to 1 */
- pingtime = 1;
-
- /* Now determine new state and whether it has changed.
- * Use some helper variables to simplify the writing
- * of the expressions.
- */
- was_reachable = peer->lastms > 0 && peer->lastms <= peer->maxms;
- is_reachable = pingtime <= peer->maxms;
- statechanged = peer->lastms == 0 /* yes, unknown before */
- || was_reachable != is_reachable;
-
- peer->lastms = pingtime;
- peer->call = NULL;
- if (statechanged) {
- const char *s = is_reachable ? "Reachable" : "Lagged";
-
- ast_log(LOG_NOTICE, "Peer '%s' is now %s. (%dms / %dms)\n",
- peer->name, s, pingtime, peer->maxms);
- ast_device_state_changed("SIP/%s", peer->name);
- manager_event(EVENT_FLAG_SYSTEM, "PeerStatus",
- "Peer: SIP/%s\r\nPeerStatus: %s\r\nTime: %d\r\n",
- peer->name, s, pingtime);
- }
-
- if (!AST_SCHED_DEL(sched, peer->pokeexpire)) {
- struct sip_peer *peer_ptr = peer;
- ASTOBJ_UNREF(peer_ptr, sip_destroy_peer);
- }
-
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
-
- /* Try again eventually */
- peer->pokeexpire = ast_sched_add(sched,
- is_reachable ? DEFAULT_FREQ_OK : DEFAULT_FREQ_NOTOK,
- sip_poke_peer_s, ASTOBJ_REF(peer));
-
- if (peer->pokeexpire == -1) {
- ASTOBJ_UNREF(peer, sip_destroy_peer);
- }
-}
-
-/*! \brief Immediately stop RTP, VRTP and UDPTL as applicable */
-static void stop_media_flows(struct sip_pvt *p)
-{
- /* Immediately stop RTP, VRTP and UDPTL as applicable */
- if (p->rtp)
- ast_rtp_stop(p->rtp);
- if (p->vrtp)
- ast_rtp_stop(p->vrtp);
- if (p->udptl)
- ast_udptl_stop(p->udptl);
-}
-
-/*! \brief Handle SIP response in dialogue */
-/* XXX only called by handle_request */
-static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int ignore, int seqno)
-{
- struct ast_channel *owner;
- int sipmethod;
- int res = 1;
- const char *c = get_header(req, "Cseq");
- /* GCC 4.2 complains if I try to cast c as a char * when passing it to ast_skip_nonblanks, so make a copy of it */
- char *c_copy = ast_strdupa(c);
- /* Skip the Cseq and its subsequent spaces */
- const char *msg = ast_skip_blanks(ast_skip_nonblanks(c_copy));
-
- if (!msg)
- msg = "";
-
- sipmethod = find_sip_method(msg);
-
- owner = p->owner;
- if (owner)
- owner->hangupcause = hangup_sip2cause(resp);
-
- /* Acknowledge whatever it is destined for */
- if ((resp >= 100) && (resp <= 199))
- __sip_semi_ack(p, seqno, 0, sipmethod);
- else
- __sip_ack(p, seqno, 0, sipmethod);
-
- /* If this is a NOTIFY for a subscription clear the flag that indicates that we have a NOTIFY pending */
- if (!p->owner && sipmethod == SIP_NOTIFY && p->pendinginvite)
- p->pendinginvite = 0;
-
- /* Get their tag if we haven't already */
- if (ast_strlen_zero(p->theirtag) || (resp >= 200)) {
- char tag[128];
-
- gettag(req, "To", tag, sizeof(tag));
- ast_string_field_set(p, theirtag, tag);
- }
-
- /* RFC 3261 Section 15 specifies that if we receive a 408 or 481
- * in response to a BYE, then we should end the current dialog
- * and session. It is known that at least one phone manufacturer
- * potentially will send a 404 in response to a BYE, so we'll be
- * liberal in what we accept and end the dialog and session if we
- * receive any of those responses to a BYE.
- */
- if ((resp == 404 || resp == 408 || resp == 481) && sipmethod == SIP_BYE) {
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- return;
- }
-
- if (p->relatedpeer && p->method == SIP_OPTIONS) {
- /* We don't really care what the response is, just that it replied back.
- Well, as long as it's not a 100 response... since we might
- need to hang around for something more "definitive" */
- if (resp != 100)
- handle_response_peerpoke(p, resp, req);
- } else if (ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
- switch(resp) {
- case 100: /* 100 Trying */
- case 101: /* 101 Dialog establishment */
- if (sipmethod == SIP_INVITE)
- handle_response_invite(p, resp, rest, req, seqno);
- break;
- case 183: /* 183 Session Progress */
- if (sipmethod == SIP_INVITE)
- handle_response_invite(p, resp, rest, req, seqno);
- break;
- case 180: /* 180 Ringing */
- if (sipmethod == SIP_INVITE)
- handle_response_invite(p, resp, rest, req, seqno);
- break;
- case 182: /* 182 Queued */
- if (sipmethod == SIP_INVITE)
- handle_response_invite(p, resp, rest, req, seqno);
- break;
- case 200: /* 200 OK */
- p->authtries = 0; /* Reset authentication counter */
- if (sipmethod == SIP_MESSAGE || sipmethod == SIP_INFO) {
- /* We successfully transmitted a message
- or a video update request in INFO */
- /* Nothing happens here - the message is inside a dialog */
- } else if (sipmethod == SIP_INVITE) {
- handle_response_invite(p, resp, rest, req, seqno);
- } else if (sipmethod == SIP_NOTIFY) {
- /* They got the notify, this is the end */
- if (p->owner) {
- if (!p->refer) {
- ast_log(LOG_WARNING, "Notify answer on an owned channel? - %s\n", p->owner->name);
- ast_queue_hangup(p->owner);
- } else if (option_debug > 3)
- ast_log(LOG_DEBUG, "Got OK on REFER Notify message\n");
- } else {
- if (p->subscribed == NONE)
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- if (ast_test_flag(&p->flags[1], SIP_PAGE2_STATECHANGEQUEUE)) {
- /* Ready to send the next state we have on queue */
- ast_clear_flag(&p->flags[1], SIP_PAGE2_STATECHANGEQUEUE);
- cb_extensionstate((char *)p->context, (char *)p->exten, p->laststate, (void *) p);
- }
- }
- } else if (sipmethod == SIP_REGISTER)
- res = handle_response_register(p, resp, rest, req, ignore, seqno);
- else if (sipmethod == SIP_BYE) { /* Ok, we're ready to go */
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- ast_clear_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED);
- } else if (sipmethod == SIP_SUBSCRIBE)
- ast_set_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED);
- break;
- case 202: /* Transfer accepted */
- if (sipmethod == SIP_REFER)
- handle_response_refer(p, resp, rest, req, seqno);
- break;
- case 401: /* Not www-authorized on SIP method */
- if (sipmethod == SIP_INVITE)
- handle_response_invite(p, resp, rest, req, seqno);
- else if (sipmethod == SIP_REFER)
- handle_response_refer(p, resp, rest, req, seqno);
- else if (p->registry && sipmethod == SIP_REGISTER)
- res = handle_response_register(p, resp, rest, req, ignore, seqno);
- else if (sipmethod == SIP_BYE) {
- if (ast_strlen_zero(p->authname)) {
- ast_log(LOG_WARNING, "Asked to authenticate %s, to %s:%d but we have no matching peer!\n",
- msg, ast_inet_ntoa(p->recv.sin_addr), ntohs(p->recv.sin_port));
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- } else if ((p->authtries == MAX_AUTHTRIES) || do_proxy_auth(p, req, "WWW-Authenticate", "Authorization", sipmethod, 0)) {
- ast_log(LOG_NOTICE, "Failed to authenticate on %s to '%s'\n", msg, get_header(&p->initreq, "From"));
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- /* We fail to auth bye on our own call, but still needs to tear down the call.
- Life, they call it. */
- }
- } else {
- ast_log(LOG_WARNING, "Got authentication request (401) on unknown %s to '%s'\n", sip_methods[sipmethod].text, get_header(req, "To"));
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- }
- break;
- case 403: /* Forbidden - we failed authentication */
- if (sipmethod == SIP_INVITE)
- handle_response_invite(p, resp, rest, req, seqno);
- else if (p->registry && sipmethod == SIP_REGISTER)
- res = handle_response_register(p, resp, rest, req, ignore, seqno);
- else {
- ast_log(LOG_WARNING, "Forbidden - maybe wrong password on authentication for %s\n", msg);
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- }
- break;
- case 404: /* Not found */
- if (p->registry && sipmethod == SIP_REGISTER)
- res = handle_response_register(p, resp, rest, req, ignore, seqno);
- else if (sipmethod == SIP_INVITE)
- handle_response_invite(p, resp, rest, req, seqno);
- else if (owner)
- ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
- break;
- case 407: /* Proxy auth required */
- if (sipmethod == SIP_INVITE)
- handle_response_invite(p, resp, rest, req, seqno);
- else if (sipmethod == SIP_REFER)
- handle_response_refer(p, resp, rest, req, seqno);
- else if (p->registry && sipmethod == SIP_REGISTER)
- res = handle_response_register(p, resp, rest, req, ignore, seqno);
- else if (sipmethod == SIP_BYE) {
- if (ast_strlen_zero(p->authname)) {
- ast_log(LOG_WARNING, "Asked to authenticate %s, to %s:%d but we have no matching peer!\n",
- msg, ast_inet_ntoa(p->recv.sin_addr), ntohs(p->recv.sin_port));
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- } else if ((p->authtries == MAX_AUTHTRIES) || do_proxy_auth(p, req, "Proxy-Authenticate", "Proxy-Authorization", sipmethod, 0)) {
- ast_log(LOG_NOTICE, "Failed to authenticate on %s to '%s'\n", msg, get_header(&p->initreq, "From"));
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- }
- } else /* We can't handle this, giving up in a bad way */
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
-
- break;
- case 408: /* Request timeout - terminate dialog */
- if (sipmethod == SIP_INVITE)
- handle_response_invite(p, resp, rest, req, seqno);
- else if (sipmethod == SIP_REGISTER)
- res = handle_response_register(p, resp, rest, req, ignore, seqno);
- else if (sipmethod == SIP_BYE) {
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- if (option_debug)
- ast_log(LOG_DEBUG, "Got timeout on bye. Thanks for the answer. Now, kill this call\n");
- } else {
- if (owner)
- ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- }
- break;
- case 481: /* Call leg does not exist */
- if (sipmethod == SIP_INVITE) {
- handle_response_invite(p, resp, rest, req, seqno);
- } else if (sipmethod == SIP_REFER) {
- handle_response_refer(p, resp, rest, req, seqno);
- } else if (sipmethod == SIP_BYE) {
- /* The other side has no transaction to bye,
- just assume it's all right then */
- ast_log(LOG_WARNING, "Remote host can't match request %s to call '%s'. Giving up.\n", sip_methods[sipmethod].text, p->callid);
- } else if (sipmethod == SIP_CANCEL) {
- /* The other side has no transaction to cancel,
- just assume it's all right then */
- ast_log(LOG_WARNING, "Remote host can't match request %s to call '%s'. Giving up.\n", sip_methods[sipmethod].text, p->callid);
- } else {
- ast_log(LOG_WARNING, "Remote host can't match request %s to call '%s'. Giving up.\n", sip_methods[sipmethod].text, p->callid);
- /* Guessing that this is not an important request */
- }
- break;
- case 487:
- if (sipmethod == SIP_INVITE)
- handle_response_invite(p, resp, rest, req, seqno);
- break;
- case 488: /* Not acceptable here - codec error */
- if (sipmethod == SIP_INVITE)
- handle_response_invite(p, resp, rest, req, seqno);
- break;
- case 491: /* Pending */
- if (sipmethod == SIP_INVITE)
- handle_response_invite(p, resp, rest, req, seqno);
- else {
- if (option_debug)
- ast_log(LOG_DEBUG, "Got 491 on %s, unspported. Call ID %s\n", sip_methods[sipmethod].text, p->callid);
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- }
- break;
- case 501: /* Not Implemented */
- if (sipmethod == SIP_INVITE)
- handle_response_invite(p, resp, rest, req, seqno);
- else if (sipmethod == SIP_REFER)
- handle_response_refer(p, resp, rest, req, seqno);
- else
- ast_log(LOG_WARNING, "Host '%s' does not implement '%s'\n", ast_inet_ntoa(p->sa.sin_addr), msg);
- break;
- case 603: /* Declined transfer */
- if (sipmethod == SIP_REFER) {
- handle_response_refer(p, resp, rest, req, seqno);
- break;
- }
- /* Fallthrough */
- default:
- if ((resp >= 300) && (resp < 700)) {
- /* Fatal response */
- if ((option_verbose > 2) && (resp != 487))
- ast_verbose(VERBOSE_PREFIX_3 "Got SIP response %d \"%s\" back from %s\n", resp, rest, ast_inet_ntoa(p->sa.sin_addr));
-
- if (sipmethod == SIP_INVITE)
- stop_media_flows(p); /* Immediately stop RTP, VRTP and UDPTL as applicable */
-
- /* XXX Locking issues?? XXX */
- switch(resp) {
- case 300: /* Multiple Choices */
- case 301: /* Moved permenantly */
- case 302: /* Moved temporarily */
- case 305: /* Use Proxy */
- parse_moved_contact(p, req);
- /* Fall through */
- case 486: /* Busy here */
- case 600: /* Busy everywhere */
- case 603: /* Decline */
- if (p->owner)
- ast_queue_control(p->owner, AST_CONTROL_BUSY);
- break;
- case 482: /*
- \note SIP is incapable of performing a hairpin call, which
- is yet another failure of not having a layer 2 (again, YAY
- IETF for thinking ahead). So we treat this as a call
- forward and hope we end up at the right place... */
- if (option_debug)
- ast_log(LOG_DEBUG, "Hairpin detected, setting up call forward for what it's worth\n");
- if (p->owner)
- ast_string_field_build(p->owner, call_forward,
- "Local/%s@%s", p->username, p->context);
- /* Fall through */
- case 480: /* Temporarily Unavailable */
- case 404: /* Not Found */
- case 410: /* Gone */
- case 400: /* Bad Request */
- case 500: /* Server error */
- if (sipmethod == SIP_REFER) {
- handle_response_refer(p, resp, rest, req, seqno);
- break;
- }
- /* Fall through */
- case 502: /* Bad gateway */
- case 503: /* Service Unavailable */
- case 504: /* Server Timeout */
- if (owner)
- ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
- break;
- default:
- /* Send hangup */
- if (owner && sipmethod != SIP_MESSAGE && sipmethod != SIP_INFO && sipmethod != SIP_BYE)
- ast_queue_hangup(p->owner);
- break;
- }
- /* ACK on invite */
- if (sipmethod == SIP_INVITE)
- transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, FALSE);
- if (sipmethod != SIP_MESSAGE && sipmethod != SIP_INFO)
- sip_alreadygone(p);
- if (!p->owner)
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- } else if ((resp >= 100) && (resp < 200)) {
- if (sipmethod == SIP_INVITE) {
- if (!ast_test_flag(req, SIP_PKT_IGNORE) && sip_cancel_destroy(p))
- ast_log(LOG_WARNING, "Unable to cancel SIP destruction. Expect bad things.\n");
- if (find_sdp(req))
- process_sdp(p, req);
- if (p->owner) {
- /* Queue a progress frame */
- ast_queue_control(p->owner, AST_CONTROL_PROGRESS);
- }
- }
- } else
- ast_log(LOG_NOTICE, "Dont know how to handle a %d %s response from %s\n", resp, rest, p->owner ? p->owner->name : ast_inet_ntoa(p->sa.sin_addr));
- }
- } else {
- /* Responses to OUTGOING SIP requests on INCOMING calls
- get handled here. As well as out-of-call message responses */
- if (ast_test_flag(req, SIP_PKT_DEBUG))
- ast_verbose("SIP Response message for INCOMING dialog %s arrived\n", msg);
-
- if (sipmethod == SIP_INVITE && resp == 200) {
- /* Tags in early session is replaced by the tag in 200 OK, which is
- the final reply to our INVITE */
- char tag[128];
-
- gettag(req, "To", tag, sizeof(tag));
- ast_string_field_set(p, theirtag, tag);
- }
-
- switch(resp) {
- case 200:
- if (sipmethod == SIP_INVITE) {
- handle_response_invite(p, resp, rest, req, seqno);
- } else if (sipmethod == SIP_CANCEL) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Got 200 OK on CANCEL\n");
-
- /* Wait for 487, then destroy */
- } else if (sipmethod == SIP_NOTIFY) {
- /* They got the notify, this is the end */
- if (p->owner) {
- if (p->refer) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Got 200 OK on NOTIFY for transfer\n");
- } else
- ast_log(LOG_WARNING, "Notify answer on an owned channel?\n");
- /* ast_queue_hangup(p->owner); Disabled */
- } else {
- if (!p->subscribed && !p->refer)
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- if (ast_test_flag(&p->flags[1], SIP_PAGE2_STATECHANGEQUEUE)) {
- /* Ready to send the next state we have on queue */
- ast_clear_flag(&p->flags[1], SIP_PAGE2_STATECHANGEQUEUE);
- cb_extensionstate((char *)p->context, (char *)p->exten, p->laststate, (void *) p);
- }
- }
- } else if (sipmethod == SIP_BYE)
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- else if (sipmethod == SIP_MESSAGE || sipmethod == SIP_INFO)
- /* We successfully transmitted a message or
- a video update request in INFO */
- ;
- else if (sipmethod == SIP_BYE)
- /* Ok, we're ready to go */
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- break;
- case 202: /* Transfer accepted */
- if (sipmethod == SIP_REFER)
- handle_response_refer(p, resp, rest, req, seqno);
- break;
- case 401: /* www-auth */
- case 407:
- if (sipmethod == SIP_REFER)
- handle_response_refer(p, resp, rest, req, seqno);
- else if (sipmethod == SIP_INVITE)
- handle_response_invite(p, resp, rest, req, seqno);
- else if (sipmethod == SIP_BYE) {
- char *auth, *auth2;
-
- auth = (resp == 407 ? "Proxy-Authenticate" : "WWW-Authenticate");
- auth2 = (resp == 407 ? "Proxy-Authorization" : "Authorization");
- if ((p->authtries == MAX_AUTHTRIES) || do_proxy_auth(p, req, auth, auth2, sipmethod, 0)) {
- ast_log(LOG_NOTICE, "Failed to authenticate on %s to '%s'\n", msg, get_header(&p->initreq, "From"));
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- }
- }
- break;
- case 481: /* Call leg does not exist */
- if (sipmethod == SIP_INVITE) {
- /* Re-invite failed */
- handle_response_invite(p, resp, rest, req, seqno);
- } else if (sipmethod == SIP_BYE) {
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- } else if (sipdebug) {
- ast_log (LOG_DEBUG, "Remote host can't match request %s to call '%s'. Giving up\n", sip_methods[sipmethod].text, p->callid);
- }
- break;
- case 501: /* Not Implemented */
- if (sipmethod == SIP_INVITE)
- handle_response_invite(p, resp, rest, req, seqno);
- else if (sipmethod == SIP_REFER)
- handle_response_refer(p, resp, rest, req, seqno);
- break;
- case 603: /* Declined transfer */
- if (sipmethod == SIP_REFER) {
- handle_response_refer(p, resp, rest, req, seqno);
- break;
- }
- /* Fallthrough */
- default: /* Errors without handlers */
- if ((resp >= 100) && (resp < 200)) {
- if (sipmethod == SIP_INVITE) { /* re-invite */
- if (!ast_test_flag(req, SIP_PKT_IGNORE) && sip_cancel_destroy(p))
- ast_log(LOG_WARNING, "Unable to cancel SIP destruction. Expect bad things.\n");
- }
- }
- if ((resp >= 300) && (resp < 700)) {
- if ((option_verbose > 2) && (resp != 487))
- ast_verbose(VERBOSE_PREFIX_3 "Incoming call: Got SIP response %d \"%s\" back from %s\n", resp, rest, ast_inet_ntoa(p->sa.sin_addr));
- switch(resp) {
- case 488: /* Not acceptable here - codec error */
- case 603: /* Decline */
- case 500: /* Server error */
- case 502: /* Bad gateway */
- case 503: /* Service Unavailable */
- case 504: /* Server timeout */
-
- /* re-invite failed */
- if (sipmethod == SIP_INVITE && sip_cancel_destroy(p))
- ast_log(LOG_WARNING, "Unable to cancel SIP destruction. Expect bad things.\n");
- break;
- }
- }
- break;
- }
- }
-}
-
-
-/*! \brief Park SIP call support function
- Starts in a new thread, then parks the call
- XXX Should we add a wait period after streaming audio and before hangup?? Sometimes the
- audio can't be heard before hangup
-*/
-static void *sip_park_thread(void *stuff)
-{
- struct ast_channel *transferee, *transferer; /* Chan1: The transferee, Chan2: The transferer */
- struct sip_dual *d;
- struct sip_request req;
- int ext;
- int res;
-
- d = stuff;
- transferee = d->chan1;
- transferer = d->chan2;
- copy_request(&req, &d->req);
-
- if (!transferee || !transferer) {
- ast_log(LOG_ERROR, "Missing channels for parking! Transferer %s Transferee %s\n", transferer ? "<available>" : "<missing>", transferee ? "<available>" : "<missing>" );
- return NULL;
- }
- if (option_debug > 3)
- ast_log(LOG_DEBUG, "SIP Park: Transferer channel %s, Transferee %s\n", transferer->name, transferee->name);
-
- ast_channel_lock(transferee);
- if (ast_do_masquerade(transferee)) {
- ast_log(LOG_WARNING, "Masquerade failed.\n");
- transmit_response(transferer->tech_pvt, "503 Internal error", &req);
- ast_channel_unlock(transferee);
- return NULL;
- }
- ast_channel_unlock(transferee);
-
- res = ast_park_call(transferee, transferer, 0, &ext);
-
-
-#ifdef WHEN_WE_KNOW_THAT_THE_CLIENT_SUPPORTS_MESSAGE
- if (!res) {
- transmit_message_with_text(transferer->tech_pvt, "Unable to park call.\n");
- } else {
- /* Then tell the transferer what happened */
- sprintf(buf, "Call parked on extension '%d'", ext);
- transmit_message_with_text(transferer->tech_pvt, buf);
- }
-#endif
-
- /* Any way back to the current call??? */
- /* Transmit response to the REFER request */
- transmit_response(transferer->tech_pvt, "202 Accepted", &req);
- if (!res) {
- /* Transfer succeeded */
- append_history(transferer->tech_pvt, "SIPpark","Parked call on %d", ext);
- transmit_notify_with_sipfrag(transferer->tech_pvt, d->seqno, "200 OK", TRUE);
- transferer->hangupcause = AST_CAUSE_NORMAL_CLEARING;
- ast_hangup(transferer); /* This will cause a BYE */
- if (option_debug)
- ast_log(LOG_DEBUG, "SIP Call parked on extension '%d'\n", ext);
- } else {
- transmit_notify_with_sipfrag(transferer->tech_pvt, d->seqno, "503 Service Unavailable", TRUE);
- append_history(transferer->tech_pvt, "SIPpark","Parking failed\n");
- if (option_debug)
- ast_log(LOG_DEBUG, "SIP Call parked failed \n");
- /* Do not hangup call */
- }
- free(d);
- return NULL;
-}
-
-/*! \brief Park a call using the subsystem in res_features.c
- This is executed in a separate thread
-*/
-static int sip_park(struct ast_channel *chan1, struct ast_channel *chan2, struct sip_request *req, int seqno)
-{
- struct sip_dual *d;
- struct ast_channel *transferee, *transferer;
- /* Chan2m: The transferer, chan1m: The transferee */
- pthread_t th;
-
- transferee = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, chan1->accountcode, chan1->exten, chan1->context, chan1->amaflags, "Parking/%s", chan1->name);
- transferer = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, chan2->accountcode, chan2->exten, chan2->context, chan2->amaflags, "SIPPeer/%s", chan2->name);
- if ((!transferer) || (!transferee)) {
- if (transferee) {
- transferee->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
- ast_hangup(transferee);
- }
- if (transferer) {
- transferer->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
- ast_hangup(transferer);
- }
- return -1;
- }
-
- /* Make formats okay */
- transferee->readformat = chan1->readformat;
- transferee->writeformat = chan1->writeformat;
-
- /* Prepare for taking over the channel */
- ast_channel_masquerade(transferee, chan1);
-
- /* Setup the extensions and such */
- ast_copy_string(transferee->context, chan1->context, sizeof(transferee->context));
- ast_copy_string(transferee->exten, chan1->exten, sizeof(transferee->exten));
- transferee->priority = chan1->priority;
-
- /* We make a clone of the peer channel too, so we can play
- back the announcement */
-
- /* Make formats okay */
- transferer->readformat = chan2->readformat;
- transferer->writeformat = chan2->writeformat;
-
- /* Prepare for taking over the channel. Go ahead and grab this channel
- * lock here to avoid a deadlock with callbacks into the channel driver
- * that hold the channel lock and want the pvt lock. */
- while (ast_channel_trylock(chan2)) {
- struct sip_pvt *pvt = chan2->tech_pvt;
- DEADLOCK_AVOIDANCE(&pvt->lock);
- }
- ast_channel_masquerade(transferer, chan2);
- ast_channel_unlock(chan2);
-
- /* Setup the extensions and such */
- ast_copy_string(transferer->context, chan2->context, sizeof(transferer->context));
- ast_copy_string(transferer->exten, chan2->exten, sizeof(transferer->exten));
- transferer->priority = chan2->priority;
-
- ast_channel_lock(transferer);
- if (ast_do_masquerade(transferer)) {
- ast_log(LOG_WARNING, "Masquerade failed :(\n");
- ast_channel_unlock(transferer);
- transferer->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
- ast_hangup(transferer);
- return -1;
- }
- ast_channel_unlock(transferer);
- if (!transferer || !transferee) {
- if (!transferer) {
- if (option_debug)
- ast_log(LOG_DEBUG, "No transferer channel, giving up parking\n");
- }
- if (!transferee) {
- if (option_debug)
- ast_log(LOG_DEBUG, "No transferee channel, giving up parking\n");
- }
- return -1;
- }
- if ((d = ast_calloc(1, sizeof(*d)))) {
- pthread_attr_t attr;
-
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-
- /* Save original request for followup */
- copy_request(&d->req, req);
- d->chan1 = transferee; /* Transferee */
- d->chan2 = transferer; /* Transferer */
- d->seqno = seqno;
- if (ast_pthread_create_background(&th, &attr, sip_park_thread, d) < 0) {
- /* Could not start thread */
- free(d); /* We don't need it anymore. If thread is created, d will be free'd
- by sip_park_thread() */
- pthread_attr_destroy(&attr);
- return 0;
- }
- pthread_attr_destroy(&attr);
- }
- return -1;
-}
-
-/*! \brief Turn off generator data
- XXX Does this function belong in the SIP channel?
-*/
-static void ast_quiet_chan(struct ast_channel *chan)
-{
- if (chan && chan->_state == AST_STATE_UP) {
- if (ast_test_flag(chan, AST_FLAG_MOH))
- ast_moh_stop(chan);
- else if (chan->generatordata)
- ast_deactivate_generator(chan);
- }
-}
-
-/*! \brief Attempt transfer of SIP call
- This fix for attended transfers on a local PBX */
-static int attempt_transfer(struct sip_dual *transferer, struct sip_dual *target)
-{
- int res = 0;
- struct ast_channel *peera = NULL,
- *peerb = NULL,
- *peerc = NULL,
- *peerd = NULL;
-
-
- /* We will try to connect the transferee with the target and hangup
- all channels to the transferer */
- if (option_debug > 3) {
- ast_log(LOG_DEBUG, "Sip transfer:--------------------\n");
- if (transferer->chan1)
- ast_log(LOG_DEBUG, "-- Transferer to PBX channel: %s State %s\n", transferer->chan1->name, ast_state2str(transferer->chan1->_state));
- else
- ast_log(LOG_DEBUG, "-- No transferer first channel - odd??? \n");
- if (target->chan1)
- ast_log(LOG_DEBUG, "-- Transferer to PBX second channel (target): %s State %s\n", target->chan1->name, ast_state2str(target->chan1->_state));
- else
- ast_log(LOG_DEBUG, "-- No target first channel ---\n");
- if (transferer->chan2)
- ast_log(LOG_DEBUG, "-- Bridged call to transferee: %s State %s\n", transferer->chan2->name, ast_state2str(transferer->chan2->_state));
- else
- ast_log(LOG_DEBUG, "-- No bridged call to transferee\n");
- if (target->chan2)
- ast_log(LOG_DEBUG, "-- Bridged call to transfer target: %s State %s\n", target->chan2 ? target->chan2->name : "<none>", target->chan2 ? ast_state2str(target->chan2->_state) : "(none)");
- else
- ast_log(LOG_DEBUG, "-- No target second channel ---\n");
- ast_log(LOG_DEBUG, "-- END Sip transfer:--------------------\n");
- }
- if (transferer->chan2) { /* We have a bridge on the transferer's channel */
- peera = transferer->chan1; /* Transferer - PBX -> transferee channel * the one we hangup */
- peerb = target->chan1; /* Transferer - PBX -> target channel - This will get lost in masq */
- peerc = transferer->chan2; /* Asterisk to Transferee */
- peerd = target->chan2; /* Asterisk to Target */
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "SIP transfer: Four channels to handle\n");
- } else if (target->chan2) { /* Transferer has no bridge (IVR), but transferee */
- peera = target->chan1; /* Transferer to PBX -> target channel */
- peerb = transferer->chan1; /* Transferer to IVR*/
- peerc = target->chan2; /* Asterisk to Target */
- peerd = transferer->chan2; /* Nothing */
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "SIP transfer: Three channels to handle\n");
- }
-
- if (peera && peerb && peerc && (peerb != peerc)) {
- ast_quiet_chan(peera); /* Stop generators */
- ast_quiet_chan(peerb);
- ast_quiet_chan(peerc);
- if (peerd)
- ast_quiet_chan(peerd);
-
- if (option_debug > 3)
- ast_log(LOG_DEBUG, "SIP transfer: trying to masquerade %s into %s\n", peerc->name, peerb->name);
- if (ast_channel_masquerade(peerb, peerc)) {
- ast_log(LOG_WARNING, "Failed to masquerade %s into %s\n", peerb->name, peerc->name);
- res = -1;
- } else
- ast_log(LOG_DEBUG, "SIP transfer: Succeeded to masquerade channels.\n");
- return res;
- } else {
- ast_log(LOG_NOTICE, "SIP Transfer attempted with no appropriate bridged calls to transfer\n");
- if (transferer->chan1)
- ast_softhangup_nolock(transferer->chan1, AST_SOFTHANGUP_DEV);
- if (target->chan1)
- ast_softhangup_nolock(target->chan1, AST_SOFTHANGUP_DEV);
- return -2;
- }
- return 0;
-}
-
-/*! \brief Get tag from packet
- *
- * \return Returns the pointer to the provided tag buffer,
- * or NULL if the tag was not found.
- */
-static const char *gettag(const struct sip_request *req, const char *header, char *tagbuf, int tagbufsize)
-{
- const char *thetag;
-
- if (!tagbuf)
- return NULL;
- tagbuf[0] = '\0'; /* reset the buffer */
- thetag = get_header(req, header);
- thetag = strcasestr(thetag, ";tag=");
- if (thetag) {
- thetag += 5;
- ast_copy_string(tagbuf, thetag, tagbufsize);
- return strsep(&tagbuf, ";");
- }
- return NULL;
-}
-
-/*! \brief Handle incoming notifications */
-static int handle_request_notify(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, int seqno, char *e)
-{
- /* This is mostly a skeleton for future improvements */
- /* Mostly created to return proper answers on notifications on outbound REFER's */
- int res = 0;
- const char *event = get_header(req, "Event");
- char *eventid = NULL;
- char *sep;
-
- if( (sep = strchr(event, ';')) ) { /* XXX bug here - overwriting string ? */
- *sep++ = '\0';
- eventid = sep;
- }
-
- if (option_debug > 1 && sipdebug)
- ast_log(LOG_DEBUG, "Got NOTIFY Event: %s\n", event);
-
- if (strcmp(event, "refer")) {
- /* We don't understand this event. */
- /* Here's room to implement incoming voicemail notifications :-) */
- transmit_response(p, "489 Bad event", req);
- res = -1;
- } else {
- /* Save nesting depth for now, since there might be other events we will
- support in the future */
-
- /* Handle REFER notifications */
-
- char buf[1024];
- char *cmd, *code;
- int respcode;
- int success = TRUE;
-
- /* EventID for each transfer... EventID is basically the REFER cseq
-
- We are getting notifications on a call that we transfered
- We should hangup when we are getting a 200 OK in a sipfrag
- Check if we have an owner of this event */
-
- /* Check the content type */
- if (strncasecmp(get_header(req, "Content-Type"), "message/sipfrag", strlen("message/sipfrag"))) {
- /* We need a sipfrag */
- transmit_response(p, "400 Bad request", req);
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- return -1;
- }
-
- /* Get the text of the attachment */
- if (get_msg_text(buf, sizeof(buf), req)) {
- ast_log(LOG_WARNING, "Unable to retrieve attachment from NOTIFY %s\n", p->callid);
- transmit_response(p, "400 Bad request", req);
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- return -1;
- }
-
- /*
- From the RFC...
- A minimal, but complete, implementation can respond with a single
- NOTIFY containing either the body:
- SIP/2.0 100 Trying
-
- if the subscription is pending, the body:
- SIP/2.0 200 OK
- if the reference was successful, the body:
- SIP/2.0 503 Service Unavailable
- if the reference failed, or the body:
- SIP/2.0 603 Declined
-
- if the REFER request was accepted before approval to follow the
- reference could be obtained and that approval was subsequently denied
- (see Section 2.4.7).
-
- If there are several REFERs in the same dialog, we need to
- match the ID of the event header...
- */
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "* SIP Transfer NOTIFY Attachment: \n---%s\n---\n", buf);
- cmd = ast_skip_blanks(buf);
- code = cmd;
- /* We are at SIP/2.0 */
- while(*code && (*code > 32)) { /* Search white space */
- code++;
- }
- *code++ = '\0';
- code = ast_skip_blanks(code);
- sep = code;
- sep++;
- while(*sep && (*sep > 32)) { /* Search white space */
- sep++;
- }
- *sep++ = '\0'; /* Response string */
- respcode = atoi(code);
- switch (respcode) {
- case 100: /* Trying: */
- case 101: /* dialog establishment */
- /* Don't do anything yet */
- break;
- case 183: /* Ringing: */
- /* Don't do anything yet */
- break;
- case 200: /* OK: The new call is up, hangup this call */
- /* Hangup the call that we are replacing */
- break;
- case 301: /* Moved permenantly */
- case 302: /* Moved temporarily */
- /* Do we get the header in the packet in this case? */
- success = FALSE;
- break;
- case 503: /* Service Unavailable: The new call failed */
- /* Cancel transfer, continue the call */
- success = FALSE;
- break;
- case 603: /* Declined: Not accepted */
- /* Cancel transfer, continue the current call */
- success = FALSE;
- break;
- }
- if (!success) {
- ast_log(LOG_NOTICE, "Transfer failed. Sorry. Nothing further to do with this call\n");
- }
-
- /* Confirm that we received this packet */
- transmit_response(p, "200 OK", req);
- };
-
- if (!p->lastinvite)
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
-
- return res;
-}
-
-/*! \brief Handle incoming OPTIONS request */
-static int handle_request_options(struct sip_pvt *p, struct sip_request *req)
-{
- int res;
-
-
- /* XXX Should we authenticate OPTIONS? XXX */
-
- if (p->lastinvite) {
- /* if this is a request in an active dialog, just confirm that the dialog exists. */
- transmit_response_with_allow(p, "200 OK", req, 0);
- return 0;
- }
-
- res = get_destination(p, req);
- build_contact(p);
-
- if (ast_strlen_zero(p->context))
- ast_string_field_set(p, context, default_context);
-
- if (ast_shutting_down())
- transmit_response_with_allow(p, "503 Unavailable", req, 0);
- else if (res < 0)
- transmit_response_with_allow(p, "404 Not Found", req, 0);
- else
- transmit_response_with_allow(p, "200 OK", req, 0);
-
- /* Destroy if this OPTIONS was the opening request, but not if
- it's in the middle of a normal call flow. */
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
-
- return res;
-}
-
-/*! \brief Handle the transfer part of INVITE with a replaces: header,
- meaning a target pickup or an attended transfer */
-static int handle_invite_replaces(struct sip_pvt *p, struct sip_request *req, int debug, int ignore, int seqno, struct sockaddr_in *sin)
-{
- struct ast_frame *f;
- int earlyreplace = 0;
- int oneleggedreplace = 0; /* Call with no bridge, propably IVR or voice message */
- struct ast_channel *c = p->owner; /* Our incoming call */
- struct ast_channel *replacecall = p->refer->refer_call->owner; /* The channel we're about to take over */
- struct ast_channel *targetcall; /* The bridge to the take-over target */
-
- /* Check if we're in ring state */
- if (replacecall->_state == AST_STATE_RING)
- earlyreplace = 1;
-
- /* Check if we have a bridge */
- if (!(targetcall = ast_bridged_channel(replacecall))) {
- /* We have no bridge */
- if (!earlyreplace) {
- if (option_debug > 1)
- ast_log(LOG_DEBUG, " Attended transfer attempted to replace call with no bridge (maybe ringing). Channel %s!\n", replacecall->name);
- oneleggedreplace = 1;
- }
- }
- if (option_debug > 3 && targetcall && targetcall->_state == AST_STATE_RINGING)
- ast_log(LOG_DEBUG, "SIP transfer: Target channel is in ringing state\n");
-
- if (option_debug > 3) {
- if (targetcall)
- ast_log(LOG_DEBUG, "SIP transfer: Invite Replace incoming channel should bridge to channel %s while hanging up channel %s\n", targetcall->name, replacecall->name);
- else
- ast_log(LOG_DEBUG, "SIP transfer: Invite Replace incoming channel should replace and hang up channel %s (one call leg)\n", replacecall->name);
- }
-
- if (ignore) {
- ast_log(LOG_NOTICE, "Ignoring this INVITE with replaces in a stupid way.\n");
- /* We should answer something here. If we are here, the
- call we are replacing exists, so an accepted
- can't harm */
- transmit_response_with_sdp(p, "200 OK", req, XMIT_RELIABLE);
- /* Do something more clever here */
- ast_channel_unlock(c);
- ast_mutex_unlock(&p->refer->refer_call->lock);
- return 1;
- }
- if (!c) {
- /* What to do if no channel ??? */
- ast_log(LOG_ERROR, "Unable to create new channel. Invite/replace failed.\n");
- transmit_response_reliable(p, "503 Service Unavailable", req);
- append_history(p, "Xfer", "INVITE/Replace Failed. No new channel.");
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- ast_mutex_unlock(&p->refer->refer_call->lock);
- return 1;
- }
- append_history(p, "Xfer", "INVITE/Replace received");
- /* We have three channels to play with
- channel c: New incoming call
- targetcall: Call from PBX to target
- p->refer->refer_call: SIP pvt dialog from transferer to pbx.
- replacecall: The owner of the previous
- We need to masq C into refer_call to connect to
- targetcall;
- If we are talking to internal audio stream, target call is null.
- */
-
- /* Fake call progress */
- transmit_response(p, "100 Trying", req);
- ast_setstate(c, AST_STATE_RING);
-
- /* Masquerade the new call into the referred call to connect to target call
- Targetcall is not touched by the masq */
-
- /* Answer the incoming call and set channel to UP state */
- transmit_response_with_sdp(p, "200 OK", req, XMIT_RELIABLE);
-
- ast_setstate(c, AST_STATE_UP);
-
- /* Stop music on hold and other generators */
- ast_quiet_chan(replacecall);
- ast_quiet_chan(targetcall);
- if (option_debug > 3)
- ast_log(LOG_DEBUG, "Invite/Replaces: preparing to masquerade %s into %s\n", c->name, replacecall->name);
- /* Unlock clone, but not original (replacecall) */
- if (!oneleggedreplace)
- ast_channel_unlock(c);
-
- /* Unlock PVT */
- ast_mutex_unlock(&p->refer->refer_call->lock);
-
- /* Make sure that the masq does not free our PVT for the old call */
- if (! earlyreplace && ! oneleggedreplace )
- ast_set_flag(&p->refer->refer_call->flags[0], SIP_DEFER_BYE_ON_TRANSFER); /* Delay hangup */
-
- /* Prepare the masquerade - if this does not happen, we will be gone */
- if(ast_channel_masquerade(replacecall, c))
- ast_log(LOG_ERROR, "Failed to masquerade C into Replacecall\n");
- else if (option_debug > 3)
- ast_log(LOG_DEBUG, "Invite/Replaces: Going to masquerade %s into %s\n", c->name, replacecall->name);
-
- /* The masquerade will happen as soon as someone reads a frame from the channel */
-
- /* C should now be in place of replacecall */
- /* ast_read needs to lock channel */
- ast_channel_unlock(c);
-
- if (earlyreplace || oneleggedreplace ) {
- /* Force the masq to happen */
- if ((f = ast_read(replacecall))) { /* Force the masq to happen */
- ast_frfree(f);
- f = NULL;
- if (option_debug > 3)
- ast_log(LOG_DEBUG, "Invite/Replace: Could successfully read frame from RING channel!\n");
- } else {
- ast_log(LOG_WARNING, "Invite/Replace: Could not read frame from RING channel \n");
- }
- c->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
- if (!oneleggedreplace)
- ast_channel_unlock(replacecall);
- } else { /* Bridged call, UP channel */
- if ((f = ast_read(replacecall))) { /* Force the masq to happen */
- /* Masq ok */
- ast_frfree(f);
- f = NULL;
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Invite/Replace: Could successfully read frame from channel! Masq done.\n");
- } else {
- ast_log(LOG_WARNING, "Invite/Replace: Could not read frame from channel. Transfer failed\n");
- }
- ast_channel_unlock(replacecall);
- }
- ast_mutex_unlock(&p->refer->refer_call->lock);
-
- ast_setstate(c, AST_STATE_DOWN);
- if (option_debug > 3) {
- struct ast_channel *test;
- ast_log(LOG_DEBUG, "After transfer:----------------------------\n");
- ast_log(LOG_DEBUG, " -- C: %s State %s\n", c->name, ast_state2str(c->_state));
- if (replacecall)
- ast_log(LOG_DEBUG, " -- replacecall: %s State %s\n", replacecall->name, ast_state2str(replacecall->_state));
- if (p->owner) {
- ast_log(LOG_DEBUG, " -- P->owner: %s State %s\n", p->owner->name, ast_state2str(p->owner->_state));
- test = ast_bridged_channel(p->owner);
- if (test)
- ast_log(LOG_DEBUG, " -- Call bridged to P->owner: %s State %s\n", test->name, ast_state2str(test->_state));
- else
- ast_log(LOG_DEBUG, " -- No call bridged to C->owner \n");
- } else
- ast_log(LOG_DEBUG, " -- No channel yet \n");
- ast_log(LOG_DEBUG, "End After transfer:----------------------------\n");
- }
-
- ast_channel_unlock(p->owner); /* Unlock new owner */
- if (!oneleggedreplace)
- ast_mutex_unlock(&p->lock); /* Unlock SIP structure */
-
- /* The call should be down with no ast_channel, so hang it up */
- c->tech_pvt = NULL;
- ast_hangup(c);
- return 0;
-}
-
-/*! \brief helper routine for sip_uri_cmp
- *
- * This takes the parameters from two SIP URIs and determines
- * if the URIs match. The rules for parameters *suck*. Here's a breakdown
- * 1. If a parameter appears in both URIs, then they must have the same value
- * in order for the URIs to match
- * 2. If one URI has a user, maddr, ttl, or method parameter, then the other
- * URI must also have that parameter and must have the same value
- * in order for the URIs to match
- * 3. All other headers appearing in only one URI are not considered when
- * determining if URIs match
- *
- * \param input1 Parameters from URI 1
- * \param input2 Parameters from URI 2
- * \return Return 0 if the URIs' parameters match, 1 if they do not
- */
-static int sip_uri_params_cmp(const char *input1, const char *input2)
-{
- char *params1 = ast_strdupa(input1);
- char *params2 = ast_strdupa(input2);
- char *pos1;
- char *pos2;
- int maddrmatch = 0;
- int ttlmatch = 0;
- int usermatch = 0;
- int methodmatch = 0;
-
- /*Quick optimization. If both params are zero-length, then
- * they match
- */
- if (ast_strlen_zero(params1) && ast_strlen_zero(params2)) {
- return 0;
- }
-
- pos1 = params1;
- while (!ast_strlen_zero(pos1)) {
- char *name1 = pos1;
- char *value1 = strchr(pos1, '=');
- char *semicolon1 = strchr(pos1, ';');
- int matched = 0;
- if (semicolon1) {
- *semicolon1++ = '\0';
- }
- if (!value1) {
- goto fail;
- }
- *value1++ = '\0';
- /* Checkpoint reached. We have the name and value parsed for param1
- * We have to duplicate params2 each time through the second loop
- * or else we can't search and replace the semicolons with \0 each
- * time
- */
- pos2 = ast_strdupa(params2);
- while (!ast_strlen_zero(pos2)) {
- char *name2 = pos2;
- char *value2 = strchr(pos2, '=');
- char *semicolon2 = strchr(pos2, ';');
- if (semicolon2) {
- *semicolon2++ = '\0';
- }
- if (!value2) {
- goto fail;
- }
- *value2++ = '\0';
- if (!strcasecmp(name1, name2)) {
- if (strcasecmp(value1, value2)) {
- goto fail;
- } else {
- matched = 1;
- break;
- }
- }
- pos2 = semicolon2;
- }
- /* Need to see if the parameter we're looking at is one of the 'must-match' parameters */
- if (!strcasecmp(name1, "maddr")) {
- if (matched) {
- maddrmatch = 1;
- } else {
- goto fail;
- }
- } else if (!strcasecmp(name1, "ttl")) {
- if (matched) {
- ttlmatch = 1;
- } else {
- goto fail;
- }
- } else if (!strcasecmp(name1, "user")) {
- if (matched) {
- usermatch = 1;
- } else {
- goto fail;
- }
- } else if (!strcasecmp(name1, "method")) {
- if (matched) {
- methodmatch = 1;
- } else {
- goto fail;
- }
- }
- pos1 = semicolon1;
- }
-
- /* We've made it out of that horrible O(m*n) construct and there are no
- * failures yet. We're not done yet, though, because params2 could have
- * an maddr, ttl, user, or method header and params1 did not.
- */
- pos2 = params2;
- while (!ast_strlen_zero(pos2)) {
- char *name2 = pos2;
- char *value2 = strchr(pos2, '=');
- char *semicolon2 = strchr(pos2, ';');
- if (semicolon2) {
- *semicolon2++ = '\0';
- }
- if (!value2) {
- goto fail;
- }
- *value2++ = '\0';
- if ((!strcasecmp(name2, "maddr") && !maddrmatch) ||
- (!strcasecmp(name2, "ttl") && !ttlmatch) ||
- (!strcasecmp(name2, "user") && !usermatch) ||
- (!strcasecmp(name2, "method") && !methodmatch)) {
- goto fail;
- }
- }
- return 0;
-
-fail:
- return 1;
-}
-
-/*! \brief helper routine for sip_uri_cmp
- *
- * This takes the "headers" from two SIP URIs and determines
- * if the URIs match. The rules for headers is simple. If a header
- * appears in one URI, then it must also appear in the other URI. The
- * order in which the headers appear does not matter.
- *
- * \param input1 Headers from URI 1
- * \param input2 Headers from URI 2
- * \return Return 0 if the URIs' headers match, 1 if they do not
- */
-static int sip_uri_headers_cmp(const char *input1, const char *input2)
-{
- char *headers1 = ast_strdupa(input1);
- char *headers2 = ast_strdupa(input2);
- int zerolength1 = ast_strlen_zero(headers1);
- int zerolength2 = ast_strlen_zero(headers2);
- int different = 0;
- char *header1;
-
- if ((zerolength1 && !zerolength2) ||
- (zerolength2 && !zerolength1))
- return 1;
-
- if (zerolength1 && zerolength2)
- return 0;
-
- /* At this point, we can definitively state that both inputs are
- * not zero-length. First, one more optimization. If the length
- * of the headers is not equal, then we definitely have no match
- */
- if (strlen(headers1) != strlen(headers2)) {
- return 1;
- }
-
- for (header1 = strsep(&headers1, "&"); header1; header1 = strsep(&headers1, "&")) {
- if (!strcasestr(headers2, header1)) {
- different = 1;
- break;
- }
- }
-
- return different;
-}
-
-static int sip_uri_cmp(const char *input1, const char *input2)
-{
- char *uri1 = ast_strdupa(input1);
- char *uri2 = ast_strdupa(input2);
- char *host1;
- char *host2;
- char *params1;
- char *params2;
- char *headers1;
- char *headers2;
-
- /* Strip off "sip:" from the URI. We know this is present
- * because it was checked back in parse_request()
- */
- strsep(&uri1, ":");
- strsep(&uri2, ":");
-
- if ((host1 = strchr(uri1, '@'))) {
- *host1++ = '\0';
- }
- if ((host2 = strchr(uri2, '@'))) {
- *host2++ = '\0';
- }
-
- /* Check for mismatched username and passwords. This is the
- * only case-sensitive comparison of a SIP URI
- */
- if ((host1 && !host2) ||
- (host2 && !host1) ||
- (host1 && host2 && strcmp(uri1, uri2))) {
- return 1;
- }
-
- if (!host1)
- host1 = uri1;
- if (!host2)
- host2 = uri2;
-
- /* Strip off the parameters and headers so we can compare
- * host and port
- */
-
- if ((params1 = strchr(host1, ';'))) {
- *params1++ = '\0';
- }
- if ((params2 = strchr(host2, ';'))) {
- *params2++ = '\0';
- }
-
- /* Headers come after parameters, but there may be headers without
- * parameters, thus the S_OR
- */
- if ((headers1 = strchr(S_OR(params1, host1), '?'))) {
- *headers1++ = '\0';
- }
- if ((headers2 = strchr(S_OR(params2, host2), '?'))) {
- *headers2++ = '\0';
- }
-
- /* Now the host/port are properly isolated. We can get by with a string comparison
- * because the SIP URI checking rules have some interesting exceptions that make
- * this possible. I will note 2 in particular
- * 1. hostnames which resolve to the same IP address as well as a hostname and its
- * IP address are not considered a match with SIP URI's.
- * 2. If one URI specifies a port and the other does not, then the URIs do not match.
- * This includes if one URI explicitly contains port 5060 and the other implies it
- * by not having a port specified.
- */
-
- if (strcasecmp(host1, host2)) {
- return 1;
- }
-
- /* Headers have easier rules to follow, so do those first */
- if (sip_uri_headers_cmp(headers1, headers2)) {
- return 1;
- }
-
- /* And now the parameters. Ugh */
- return sip_uri_params_cmp(params1, params2);
-}
-
-
-/*! \brief Handle incoming INVITE request
-\note If the INVITE has a Replaces header, it is part of an
- * attended transfer. If so, we do not go through the dial
- * plan but tries to find the active call and masquerade
- * into it
- */
-static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int debug, int seqno, struct sockaddr_in *sin, int *recount, char *e, int *nounlock)
-{
- int res = 1;
- int gotdest;
- const char *p_replaces;
- char *replace_id = NULL;
- const char *required;
- unsigned int required_profile = 0;
- struct ast_channel *c = NULL; /* New channel */
- int reinvite = 0;
-
- /* Find out what they support */
- if (!p->sipoptions) {
- const char *supported = get_header(req, "Supported");
- if (!ast_strlen_zero(supported))
- parse_sip_options(p, supported);
- }
-
- /* Find out what they require */
- required = get_header(req, "Require");
- if (!ast_strlen_zero(required)) {
- required_profile = parse_sip_options(NULL, required);
- if (required_profile && required_profile != SIP_OPT_REPLACES) {
- /* At this point we only support REPLACES */
- transmit_response_with_unsupported(p, "420 Bad extension (unsupported)", req, required);
- ast_log(LOG_WARNING,"Received SIP INVITE with unsupported required extension: %s\n", required);
- p->invitestate = INV_COMPLETED;
- if (!p->lastinvite)
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- return -1;
- }
- }
-
- /* Check if this is a loop */
- if (ast_test_flag(&p->flags[0], SIP_OUTGOING) && p->owner && (p->owner->_state != AST_STATE_UP)) {
- /* This is a call to ourself. Send ourselves an error code and stop
- processing immediately, as SIP really has no good mechanism for
- being able to call yourself */
- /* If pedantic is on, we need to check the tags. If they're different, this is
- in fact a forked call through a SIP proxy somewhere. */
- int different;
- if (pedanticsipchecking)
- different = sip_uri_cmp(p->initreq.rlPart2, req->rlPart2);
- else
- different = strcmp(p->initreq.rlPart2, req->rlPart2);
- if (!different) {
- transmit_response(p, "482 Loop Detected", req);
- p->invitestate = INV_COMPLETED;
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- return 0;
- } else {
- /* This is a spiral. What we need to do is to just change the outgoing INVITE
- * so that it now routes to the new Request URI. Since we created the INVITE ourselves
- * that should be all we need to do.
- */
- char *uri = ast_strdupa(req->rlPart2);
- char *at = strchr(uri, '@');
- char *peerorhost;
- if (option_debug > 2) {
- ast_log(LOG_DEBUG, "Potential spiral detected. Original RURI was %s, new RURI is %s\n", p->initreq.rlPart2, req->rlPart2);
- }
- if (at) {
- *at = '\0';
- }
- /* Parse out "sip:" */
- if ((peerorhost = strchr(uri, ':'))) {
- *peerorhost++ = '\0';
- }
- ast_string_field_free(p, theirtag);
- /* Treat this as if there were a call forward instead...
- */
- ast_string_field_set(p->owner, call_forward, peerorhost);
- ast_queue_control(p->owner, AST_CONTROL_BUSY);
- return 0;
- }
- }
-
- if (!ast_test_flag(req, SIP_PKT_IGNORE) && p->pendinginvite) {
- /* We already have a pending invite. Sorry. You are on hold. */
- transmit_response_reliable(p, "491 Request Pending", req);
- if (option_debug)
- ast_log(LOG_DEBUG, "Got INVITE on call where we already have pending INVITE, deferring that - %s\n", p->callid);
- /* Don't destroy dialog here */
- return 0;
- }
-
- p_replaces = get_header(req, "Replaces");
- if (!ast_strlen_zero(p_replaces)) {
- /* We have a replaces header */
- char *ptr;
- char *fromtag = NULL;
- char *totag = NULL;
- char *start, *to;
- int error = 0;
-
- if (p->owner) {
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "INVITE w Replaces on existing call? Refusing action. [%s]\n", p->callid);
- transmit_response_reliable(p, "400 Bad request", req); /* The best way to not not accept the transfer */
- /* Do not destroy existing call */
- return -1;
- }
-
- if (sipdebug && option_debug > 2)
- ast_log(LOG_DEBUG, "INVITE part of call transfer. Replaces [%s]\n", p_replaces);
- /* Create a buffer we can manipulate */
- replace_id = ast_strdupa(p_replaces);
- ast_uri_decode(replace_id);
-
- if (!p->refer && !sip_refer_allocate(p)) {
- transmit_response_reliable(p, "500 Server Internal Error", req);
- append_history(p, "Xfer", "INVITE/Replace Failed. Out of memory.");
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- p->invitestate = INV_COMPLETED;
- return -1;
- }
-
- /* Todo: (When we find phones that support this)
- if the replaces header contains ";early-only"
- we can only replace the call in early
- stage, not after it's up.
-
- If it's not in early mode, 486 Busy.
- */
-
- /* Skip leading whitespace */
- replace_id = ast_skip_blanks(replace_id);
-
- start = replace_id;
- while ( (ptr = strsep(&start, ";")) ) {
- ptr = ast_skip_blanks(ptr); /* XXX maybe unnecessary ? */
- if ( (to = strcasestr(ptr, "to-tag=") ) )
- totag = to + 7; /* skip the keyword */
- else if ( (to = strcasestr(ptr, "from-tag=") ) ) {
- fromtag = to + 9; /* skip the keyword */
- fromtag = strsep(&fromtag, "&"); /* trim what ? */
- }
- }
-
- if (sipdebug && option_debug > 3)
- ast_log(LOG_DEBUG,"Invite/replaces: Will use Replace-Call-ID : %s Fromtag: %s Totag: %s\n", replace_id, fromtag ? fromtag : "<no from tag>", totag ? totag : "<no to tag>");
-
-
- /* Try to find call that we are replacing
- If we have a Replaces header, we need to cancel that call if we succeed with this call
- */
- if ((p->refer->refer_call = get_sip_pvt_byid_locked(replace_id, totag, fromtag)) == NULL) {
- ast_log(LOG_NOTICE, "Supervised transfer attempted to replace non-existent call id (%s)!\n", replace_id);
- transmit_response_reliable(p, "481 Call Leg Does Not Exist (Replaces)", req);
- error = 1;
- }
-
- /* At this point, bot the pvt and the owner of the call to be replaced is locked */
-
- /* The matched call is the call from the transferer to Asterisk .
- We want to bridge the bridged part of the call to the
- incoming invite, thus taking over the refered call */
-
- if (p->refer->refer_call == p) {
- ast_log(LOG_NOTICE, "INVITE with replaces into it's own call id (%s == %s)!\n", replace_id, p->callid);
- p->refer->refer_call = NULL;
- transmit_response_reliable(p, "400 Bad request", req); /* The best way to not not accept the transfer */
- error = 1;
- }
-
- if (!error && !p->refer->refer_call->owner) {
- /* Oops, someting wrong anyway, no owner, no call */
- ast_log(LOG_NOTICE, "Supervised transfer attempted to replace non-existing call id (%s)!\n", replace_id);
- /* Check for better return code */
- transmit_response_reliable(p, "481 Call Leg Does Not Exist (Replace)", req);
- error = 1;
- }
-
- if (!error && p->refer->refer_call->owner->_state != AST_STATE_RINGING && p->refer->refer_call->owner->_state != AST_STATE_RING && p->refer->refer_call->owner->_state != AST_STATE_UP ) {
- ast_log(LOG_NOTICE, "Supervised transfer attempted to replace non-ringing or active call id (%s)!\n", replace_id);
- transmit_response_reliable(p, "603 Declined (Replaces)", req);
- error = 1;
- }
-
- if (error) { /* Give up this dialog */
- append_history(p, "Xfer", "INVITE/Replace Failed.");
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- ast_mutex_unlock(&p->lock);
- if (p->refer->refer_call) {
- ast_mutex_unlock(&p->refer->refer_call->lock);
- if (p->refer->refer_call->owner) {
- ast_channel_unlock(p->refer->refer_call->owner);
- }
- }
- p->invitestate = INV_COMPLETED;
- return -1;
- }
- }
-
-
- /* Check if this is an INVITE that sets up a new dialog or
- a re-invite in an existing dialog */
-
- if (!ast_test_flag(req, SIP_PKT_IGNORE)) {
- int newcall = (p->initreq.headers ? TRUE : FALSE);
-
- if (sip_cancel_destroy(p))
- ast_log(LOG_WARNING, "Unable to cancel SIP destruction. Expect bad things.\n");
- /* This also counts as a pending invite */
- p->pendinginvite = seqno;
- check_via(p, req);
-
- copy_request(&p->initreq, req); /* Save this INVITE as the transaction basis */
- if (!p->owner) { /* Not a re-invite */
- if (debug)
- ast_verbose("Using INVITE request as basis request - %s\n", p->callid);
- if (newcall)
- append_history(p, "Invite", "New call: %s", p->callid);
- parse_ok_contact(p, req);
- } else { /* Re-invite on existing call */
- ast_clear_flag(&p->flags[0], SIP_OUTGOING); /* This is now an inbound dialog */
- /* Handle SDP here if we already have an owner */
- if (find_sdp(req)) {
- if (process_sdp(p, req)) {
- transmit_response_reliable(p, "488 Not acceptable here", req);
- if (!p->lastinvite)
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- return -1;
- }
- } else {
- p->jointcapability = p->capability;
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Hm.... No sdp for the moment\n");
- /* Some devices signal they want to be put off hold by sending a re-invite
- *without* an SDP, which is supposed to mean "Go back to your state"
- and since they put os on remote hold, we go back to off hold */
- if (ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD))
- change_hold_state(p, req, FALSE, 0);
- }
- if (!ast_test_flag(&p->flags[0], SIP_NO_HISTORY)) /* This is a response, note what it was for */
- append_history(p, "ReInv", "Re-invite received");
- }
- } else if (debug)
- ast_verbose("Ignoring this INVITE request\n");
-
-
- if (!p->lastinvite && !ast_test_flag(req, SIP_PKT_IGNORE) && !p->owner) {
- /* This is a new invite */
- /* Handle authentication if this is our first invite */
- res = check_user(p, req, SIP_INVITE, e, XMIT_RELIABLE, sin);
- if (res == AUTH_CHALLENGE_SENT) {
- p->invitestate = INV_COMPLETED; /* Needs to restart in another INVITE transaction */
- return 0;
- }
- if (res < 0) { /* Something failed in authentication */
- if (res == AUTH_FAKE_AUTH) {
- ast_log(LOG_NOTICE, "Sending fake auth rejection for user %s\n", get_header(req, "From"));
- transmit_fake_auth_response(p, req, 1);
- } else {
- ast_log(LOG_NOTICE, "Failed to authenticate user %s\n", get_header(req, "From"));
- transmit_response_reliable(p, "403 Forbidden", req);
- }
- p->invitestate = INV_COMPLETED;
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- ast_string_field_free(p, theirtag);
- return 0;
- }
-
- /* We have a succesful authentication, process the SDP portion if there is one */
- if (find_sdp(req)) {
- if (process_sdp(p, req)) {
- /* Unacceptable codecs */
- transmit_response_reliable(p, "488 Not acceptable here", req);
- p->invitestate = INV_COMPLETED;
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- if (option_debug)
- ast_log(LOG_DEBUG, "No compatible codecs for this SIP call.\n");
- return -1;
- }
- } else { /* No SDP in invite, call control session */
- p->jointcapability = p->capability;
- if (option_debug > 1)
- ast_log(LOG_DEBUG, "No SDP in Invite, third party call control\n");
- }
-
- /* Queue NULL frame to prod ast_rtp_bridge if appropriate */
- /* This seems redundant ... see !p-owner above */
- if (p->owner)
- ast_queue_frame(p->owner, &ast_null_frame);
-
-
- /* Initialize the context if it hasn't been already */
- if (ast_strlen_zero(p->context))
- ast_string_field_set(p, context, default_context);
-
-
- /* Check number of concurrent calls -vs- incoming limit HERE */
- if (option_debug)
- ast_log(LOG_DEBUG, "Checking SIP call limits for device %s\n", p->username);
- if ((res = update_call_counter(p, INC_CALL_LIMIT))) {
- if (res < 0) {
- ast_log(LOG_NOTICE, "Failed to place call for user %s, too many calls\n", p->username);
- transmit_response_reliable(p, "480 Temporarily Unavailable (Call limit) ", req);
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- p->invitestate = INV_COMPLETED;
- }
- return 0;
- }
- gotdest = get_destination(p, NULL); /* Get destination right away */
- get_rdnis(p, NULL); /* Get redirect information */
- extract_uri(p, req); /* Get the Contact URI */
- build_contact(p); /* Build our contact header */
-
- if (p->rtp) {
- ast_rtp_setdtmf(p->rtp, ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833);
- ast_rtp_setdtmfcompensate(p->rtp, ast_test_flag(&p->flags[1], SIP_PAGE2_RFC2833_COMPENSATE));
- }
-
- if (!replace_id && gotdest) { /* No matching extension found */
- if (gotdest == 1 && ast_test_flag(&p->flags[1], SIP_PAGE2_ALLOWOVERLAP))
- transmit_response_reliable(p, "484 Address Incomplete", req);
- else {
- char *decoded_exten = ast_strdupa(p->exten);
-
- transmit_response_reliable(p, "404 Not Found", req);
- ast_uri_decode(decoded_exten);
- ast_log(LOG_NOTICE, "Call from '%s' to extension"
- " '%s' rejected because extension not found.\n",
- S_OR(p->username, p->peername), decoded_exten);
- }
- p->invitestate = INV_COMPLETED;
- update_call_counter(p, DEC_CALL_LIMIT);
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- return 0;
- } else {
- /* If no extension was specified, use the s one */
- /* Basically for calling to IP/Host name only */
- if (ast_strlen_zero(p->exten))
- ast_string_field_set(p, exten, "s");
- /* Initialize our tag */
-
- make_our_tag(p->tag, sizeof(p->tag));
- /* First invitation - create the channel */
- c = sip_new(p, AST_STATE_DOWN, S_OR(p->username, NULL));
- *recount = 1;
-
- /* Save Record-Route for any later requests we make on this dialogue */
- build_route(p, req, 0);
-
- if (c) {
- /* Pre-lock the call */
- ast_channel_lock(c);
- }
- }
- } else {
- if (option_debug > 1 && sipdebug) {
- if (!ast_test_flag(req, SIP_PKT_IGNORE))
- ast_log(LOG_DEBUG, "Got a SIP re-invite for call %s\n", p->callid);
- else
- ast_log(LOG_DEBUG, "Got a SIP re-transmit of INVITE for call %s\n", p->callid);
- }
- if (!ast_test_flag(req, SIP_PKT_IGNORE))
- reinvite = 1;
- c = p->owner;
- }
-
- if (!ast_test_flag(req, SIP_PKT_IGNORE) && p)
- p->lastinvite = seqno;
-
- if (replace_id) { /* Attended transfer or call pickup - we're the target */
- /* Go and take over the target call */
- if (sipdebug && option_debug > 3)
- ast_log(LOG_DEBUG, "Sending this call to the invite/replcaes handler %s\n", p->callid);
- return handle_invite_replaces(p, req, debug, ast_test_flag(req, SIP_PKT_IGNORE), seqno, sin);
- }
-
-
- if (c) { /* We have a call -either a new call or an old one (RE-INVITE) */
- switch(c->_state) {
- case AST_STATE_DOWN:
- if (option_debug > 1)
- ast_log(LOG_DEBUG, "%s: New call is still down.... Trying... \n", c->name);
- transmit_response(p, "100 Trying", req);
- p->invitestate = INV_PROCEEDING;
- ast_setstate(c, AST_STATE_RING);
- if (strcmp(p->exten, ast_pickup_ext())) { /* Call to extension -start pbx on this call */
- enum ast_pbx_result res;
-
- res = ast_pbx_start(c);
-
- switch(res) {
- case AST_PBX_FAILED:
- ast_log(LOG_WARNING, "Failed to start PBX :(\n");
- p->invitestate = INV_COMPLETED;
- if (ast_test_flag(req, SIP_PKT_IGNORE))
- transmit_response(p, "503 Unavailable", req);
- else
- transmit_response_reliable(p, "503 Unavailable", req);
- break;
- case AST_PBX_CALL_LIMIT:
- ast_log(LOG_WARNING, "Failed to start PBX (call limit reached) \n");
- p->invitestate = INV_COMPLETED;
- if (ast_test_flag(req, SIP_PKT_IGNORE))
- transmit_response(p, "480 Temporarily Unavailable", req);
- else
- transmit_response_reliable(p, "480 Temporarily Unavailable", req);
- break;
- case AST_PBX_SUCCESS:
- /* nothing to do */
- break;
- }
-
- if (res) {
-
- /* Unlock locks so ast_hangup can do its magic */
- ast_mutex_unlock(&c->lock);
- ast_mutex_unlock(&p->lock);
- ast_hangup(c);
- ast_mutex_lock(&p->lock);
- c = NULL;
- }
- } else { /* Pickup call in call group */
- ast_channel_unlock(c);
- *nounlock = 1;
- if (ast_pickup_call(c)) {
- ast_log(LOG_NOTICE, "Nothing to pick up for %s\n", p->callid);
- if (ast_test_flag(req, SIP_PKT_IGNORE))
- transmit_response(p, "503 Unavailable", req); /* OEJ - Right answer? */
- else
- transmit_response_reliable(p, "503 Unavailable", req);
- sip_alreadygone(p);
- /* Unlock locks so ast_hangup can do its magic */
- ast_mutex_unlock(&p->lock);
- c->hangupcause = AST_CAUSE_CALL_REJECTED;
- } else {
- ast_mutex_unlock(&p->lock);
- ast_setstate(c, AST_STATE_DOWN);
- c->hangupcause = AST_CAUSE_NORMAL_CLEARING;
- }
- p->invitestate = INV_COMPLETED;
- ast_hangup(c);
- ast_mutex_lock(&p->lock);
- c = NULL;
- }
- break;
- case AST_STATE_RING:
- transmit_response(p, "100 Trying", req);
- p->invitestate = INV_PROCEEDING;
- break;
- case AST_STATE_RINGING:
- transmit_response(p, "180 Ringing", req);
- p->invitestate = INV_PROCEEDING;
- break;
- case AST_STATE_UP:
- if (option_debug > 1)
- ast_log(LOG_DEBUG, "%s: This call is UP.... \n", c->name);
-
- transmit_response(p, "100 Trying", req);
-
- if (p->t38.state == T38_PEER_REINVITE) {
- struct ast_channel *bridgepeer = NULL;
- struct sip_pvt *bridgepvt = NULL;
-
- if ((bridgepeer = ast_bridged_channel(p->owner))) {
- /* We have a bridge, and this is re-invite to switchover to T38 so we send re-invite with T38 SDP, to other side of bridge*/
- /*! XXX: we should also check here does the other side supports t38 at all !!! XXX */
- if (bridgepeer->tech == &sip_tech || bridgepeer->tech == &sip_tech_info) {
- bridgepvt = (struct sip_pvt*)bridgepeer->tech_pvt;
- if (bridgepvt->t38.state == T38_DISABLED) {
- if (bridgepvt->udptl) { /* If everything is OK with other side's udptl struct */
- /* Send re-invite to the bridged channel */
- sip_handle_t38_reinvite(bridgepeer, p, 1);
- } else { /* Something is wrong with peers udptl struct */
- ast_log(LOG_WARNING, "Strange... The other side of the bridge don't have udptl struct\n");
- ast_mutex_lock(&bridgepvt->lock);
- bridgepvt->t38.state = T38_DISABLED;
- ast_mutex_unlock(&bridgepvt->lock);
- if (option_debug > 1)
- ast_log(LOG_DEBUG,"T38 state changed to %d on channel %s\n", bridgepvt->t38.state, bridgepeer->name);
- if (ast_test_flag(req, SIP_PKT_IGNORE))
- transmit_response(p, "488 Not acceptable here", req);
- else
- transmit_response_reliable(p, "488 Not acceptable here", req);
-
- }
- } else {
- /* The other side is already setup for T.38 most likely so we need to acknowledge this too */
- ast_set_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED);
- transmit_response_with_t38_sdp(p, "200 OK", req, XMIT_CRITICAL);
- p->t38.state = T38_ENABLED;
- if (option_debug)
- ast_log(LOG_DEBUG, "T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
- }
- } else {
- /* Other side is not a SIP channel */
- if (ast_test_flag(req, SIP_PKT_IGNORE))
- transmit_response(p, "488 Not acceptable here", req);
- else
- transmit_response_reliable(p, "488 Not acceptable here", req);
- p->t38.state = T38_DISABLED;
- if (option_debug > 1)
- ast_log(LOG_DEBUG,"T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
-
- if (!p->lastinvite) /* Only destroy if this is *not* a re-invite */
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- }
- } else {
- /* we are not bridged in a call */
- ast_set_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED);
- transmit_response_with_t38_sdp(p, "200 OK", req, XMIT_CRITICAL);
- p->t38.state = T38_ENABLED;
- if (option_debug)
- ast_log(LOG_DEBUG,"T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
- }
- } else if (p->t38.state == T38_DISABLED) { /* Channel doesn't have T38 offered or enabled */
- int sendok = TRUE;
-
- /* If we are bridged to a channel that has T38 enabled than this is a case of RTP re-invite after T38 session */
- /* so handle it here (re-invite other party to RTP) */
- struct ast_channel *bridgepeer = NULL;
- struct sip_pvt *bridgepvt = NULL;
- if ((bridgepeer = ast_bridged_channel(p->owner))) {
- if ((bridgepeer->tech == &sip_tech || bridgepeer->tech == &sip_tech_info) && !ast_check_hangup(bridgepeer)) {
- bridgepvt = (struct sip_pvt*)bridgepeer->tech_pvt;
- /* Does the bridged peer have T38 ? */
- if (bridgepvt->t38.state == T38_ENABLED) {
- ast_log(LOG_WARNING, "RTP re-invite after T38 session not handled yet !\n");
- /* Insted of this we should somehow re-invite the other side of the bridge to RTP */
- if (ast_test_flag(req, SIP_PKT_IGNORE))
- transmit_response(p, "488 Not Acceptable Here (unsupported)", req);
- else
- transmit_response_reliable(p, "488 Not Acceptable Here (unsupported)", req);
- sendok = FALSE;
- }
- /* No bridged peer with T38 enabled*/
- }
- }
- /* Respond to normal re-invite */
- if (sendok) {
- /* If this is not a re-invite or something to ignore - it's critical */
- ast_set_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED);
- transmit_response_with_sdp(p, "200 OK", req, (reinvite ? XMIT_RELIABLE : (ast_test_flag(req, SIP_PKT_IGNORE) ? XMIT_UNRELIABLE : XMIT_CRITICAL)));
- }
- }
- p->invitestate = INV_TERMINATED;
- break;
- default:
- ast_log(LOG_WARNING, "Don't know how to handle INVITE in state %d\n", c->_state);
- transmit_response(p, "100 Trying", req);
- break;
- }
- } else {
- if (p && (p->autokillid == -1)) {
- const char *msg;
-
- if (!p->jointcapability)
- msg = "488 Not Acceptable Here (codec error)";
- else {
- ast_log(LOG_NOTICE, "Unable to create/find SIP channel for this INVITE\n");
- msg = "503 Unavailable";
- }
- if (ast_test_flag(req, SIP_PKT_IGNORE))
- transmit_response(p, msg, req);
- else
- transmit_response_reliable(p, msg, req);
- p->invitestate = INV_COMPLETED;
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- }
- }
- return res;
-}
-
-/*! \brief Find all call legs and bridge transferee with target
- * called from handle_request_refer */
-static int local_attended_transfer(struct sip_pvt *transferer, struct sip_dual *current, struct sip_request *req, int seqno)
-{
- struct sip_dual target; /* Chan 1: Call from tranferer to Asterisk */
- /* Chan 2: Call from Asterisk to target */
- int res = 0;
- struct sip_pvt *targetcall_pvt;
-
- /* Check if the call ID of the replaces header does exist locally */
- if (!(targetcall_pvt = get_sip_pvt_byid_locked(transferer->refer->replaces_callid, transferer->refer->replaces_callid_totag,
- transferer->refer->replaces_callid_fromtag))) {
- if (transferer->refer->localtransfer) {
- /* We did not find the refered call. Sorry, can't accept then */
- transmit_response(transferer, "202 Accepted", req);
- /* Let's fake a response from someone else in order
- to follow the standard */
- transmit_notify_with_sipfrag(transferer, seqno, "481 Call leg/transaction does not exist", TRUE);
- append_history(transferer, "Xfer", "Refer failed");
- ast_clear_flag(&transferer->flags[0], SIP_GOTREFER);
- transferer->refer->status = REFER_FAILED;
- return -1;
- }
- /* Fall through for remote transfers that we did not find locally */
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "SIP attended transfer: Not our call - generating INVITE with replaces\n");
- return 0;
- }
-
- /* Ok, we can accept this transfer */
- transmit_response(transferer, "202 Accepted", req);
- append_history(transferer, "Xfer", "Refer accepted");
- if (!targetcall_pvt->owner) { /* No active channel */
- if (option_debug > 3)
- ast_log(LOG_DEBUG, "SIP attended transfer: Error: No owner of target call\n");
- /* Cancel transfer */
- transmit_notify_with_sipfrag(transferer, seqno, "503 Service Unavailable", TRUE);
- append_history(transferer, "Xfer", "Refer failed");
- ast_clear_flag(&transferer->flags[0], SIP_GOTREFER);
- transferer->refer->status = REFER_FAILED;
- ast_mutex_unlock(&targetcall_pvt->lock);
- ast_channel_unlock(current->chan1);
- return -1;
- }
-
- /* We have a channel, find the bridge */
- target.chan1 = targetcall_pvt->owner; /* Transferer to Asterisk */
- target.chan2 = ast_bridged_channel(targetcall_pvt->owner); /* Asterisk to target */
-
- if (!target.chan2 || !(target.chan2->_state == AST_STATE_UP || target.chan2->_state == AST_STATE_RINGING) ) {
- /* Wrong state of new channel */
- if (option_debug > 3) {
- if (target.chan2)
- ast_log(LOG_DEBUG, "SIP attended transfer: Error: Wrong state of target call: %s\n", ast_state2str(target.chan2->_state));
- else if (target.chan1->_state != AST_STATE_RING)
- ast_log(LOG_DEBUG, "SIP attended transfer: Error: No target channel\n");
- else
- ast_log(LOG_DEBUG, "SIP attended transfer: Attempting transfer in ringing state\n");
- }
- }
-
- /* Transfer */
- if (option_debug > 3 && sipdebug) {
- if (current->chan2) /* We have two bridges */
- ast_log(LOG_DEBUG, "SIP attended transfer: trying to bridge %s and %s\n", target.chan1->name, current->chan2->name);
- else /* One bridge, propably transfer of IVR/voicemail etc */
- ast_log(LOG_DEBUG, "SIP attended transfer: trying to make %s take over (masq) %s\n", target.chan1->name, current->chan1->name);
- }
-
- ast_set_flag(&transferer->flags[0], SIP_DEFER_BYE_ON_TRANSFER); /* Delay hangup */
-
- /* Perform the transfer */
- res = attempt_transfer(current, &target);
- ast_mutex_unlock(&targetcall_pvt->lock);
- if (res) {
- /* Failed transfer */
- transmit_notify_with_sipfrag(transferer, seqno, "486 Busy Here", TRUE);
- append_history(transferer, "Xfer", "Refer failed");
- transferer->refer->status = REFER_FAILED;
- if (targetcall_pvt->owner)
- ast_channel_unlock(targetcall_pvt->owner);
- /* Right now, we have to hangup, sorry. Bridge is destroyed */
- if (res != -2)
- ast_hangup(transferer->owner);
- else
- ast_clear_flag(&transferer->flags[0], SIP_DEFER_BYE_ON_TRANSFER);
- } else {
- /* Transfer succeeded! */
-
- /* Tell transferer that we're done. */
- transmit_notify_with_sipfrag(transferer, seqno, "200 OK", TRUE);
- append_history(transferer, "Xfer", "Refer succeeded");
- transferer->refer->status = REFER_200OK;
- if (targetcall_pvt->owner) {
- if (option_debug)
- ast_log(LOG_DEBUG, "SIP attended transfer: Unlocking channel %s\n", targetcall_pvt->owner->name);
- ast_channel_unlock(targetcall_pvt->owner);
- }
- }
- return 1;
-}
-
-
-/*! \brief Handle incoming REFER request */
-/*! \page SIP_REFER SIP transfer Support (REFER)
-
- REFER is used for call transfer in SIP. We get a REFER
- to place a new call with an INVITE somwhere and then
- keep the transferor up-to-date of the transfer. If the
- transfer fails, get back on line with the orginal call.
-
- - REFER can be sent outside or inside of a dialog.
- Asterisk only accepts REFER inside of a dialog.
-
- - If we get a replaces header, it is an attended transfer
-
- \par Blind transfers
- The transferor provides the transferee
- with the transfer targets contact. The signalling between
- transferer or transferee should not be cancelled, so the
- call is recoverable if the transfer target can not be reached
- by the transferee.
-
- In this case, Asterisk receives a TRANSFER from
- the transferor, thus is the transferee. We should
- try to set up a call to the contact provided
- and if that fails, re-connect the current session.
- If the new call is set up, we issue a hangup.
- In this scenario, we are following section 5.2
- in the SIP CC Transfer draft. (Transfer without
- a GRUU)
-
- \par Transfer with consultation hold
- In this case, the transferor
- talks to the transfer target before the transfer takes place.
- This is implemented with SIP hold and transfer.
- Note: The invite From: string could indicate a transfer.
- (Section 6. Transfer with consultation hold)
- The transferor places the transferee on hold, starts a call
- with the transfer target to alert them to the impending
- transfer, terminates the connection with the target, then
- proceeds with the transfer (as in Blind transfer above)
-
- \par Attended transfer
- The transferor places the transferee
- on hold, calls the transfer target to alert them,
- places the target on hold, then proceeds with the transfer
- using a Replaces header field in the Refer-to header. This
- will force the transfee to send an Invite to the target,
- with a replaces header that instructs the target to
- hangup the call between the transferor and the target.
- In this case, the Refer/to: uses the AOR address. (The same
- URI that the transferee used to establish the session with
- the transfer target (To: ). The Require: replaces header should
- be in the INVITE to avoid the wrong UA in a forked SIP proxy
- scenario to answer and have no call to replace with.
-
- The referred-by header is *NOT* required, but if we get it,
- can be copied into the INVITE to the transfer target to
- inform the target about the transferor
-
- "Any REFER request has to be appropriately authenticated.".
-
- We can't destroy dialogs, since we want the call to continue.
-
- */
-static int handle_request_refer(struct sip_pvt *p, struct sip_request *req, int debug, int ignore, int seqno, int *nounlock)
-{
- struct sip_dual current; /* Chan1: Call between asterisk and transferer */
- /* Chan2: Call between asterisk and transferee */
-
- int res = 0;
-
- if (ast_test_flag(req, SIP_PKT_DEBUG))
- ast_verbose("Call %s got a SIP call transfer from %s: (REFER)!\n", p->callid, ast_test_flag(&p->flags[0], SIP_OUTGOING) ? "callee" : "caller");
-
- if (!p->owner) {
- /* This is a REFER outside of an existing SIP dialog */
- /* We can't handle that, so decline it */
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Call %s: Declined REFER, outside of dialog...\n", p->callid);
- transmit_response(p, "603 Declined (No dialog)", req);
- if (!ast_test_flag(req, SIP_PKT_IGNORE)) {
- append_history(p, "Xfer", "Refer failed. Outside of dialog.");
- sip_alreadygone(p);
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- }
- return 0;
- }
-
-
- /* Check if transfer is allowed from this device */
- if (p->allowtransfer == TRANSFER_CLOSED ) {
- /* Transfer not allowed, decline */
- transmit_response(p, "603 Declined (policy)", req);
- append_history(p, "Xfer", "Refer failed. Allowtransfer == closed.");
- /* Do not destroy SIP session */
- return 0;
- }
-
- if(!ignore && ast_test_flag(&p->flags[0], SIP_GOTREFER)) {
- /* Already have a pending REFER */
- transmit_response(p, "491 Request pending", req);
- append_history(p, "Xfer", "Refer failed. Request pending.");
- return 0;
- }
-
- /* Allocate memory for call transfer data */
- if (!p->refer && !sip_refer_allocate(p)) {
- transmit_response(p, "500 Internal Server Error", req);
- append_history(p, "Xfer", "Refer failed. Memory allocation error.");
- return -3;
- }
-
- res = get_refer_info(p, req); /* Extract headers */
-
- p->refer->status = REFER_SENT;
-
- if (res != 0) {
- switch (res) {
- case -2: /* Syntax error */
- transmit_response(p, "400 Bad Request (Refer-to missing)", req);
- append_history(p, "Xfer", "Refer failed. Refer-to missing.");
- if (ast_test_flag(req, SIP_PKT_DEBUG) && option_debug)
- ast_log(LOG_DEBUG, "SIP transfer to black hole can't be handled (no refer-to: )\n");
- break;
- case -3:
- transmit_response(p, "603 Declined (Non sip: uri)", req);
- append_history(p, "Xfer", "Refer failed. Non SIP uri");
- if (ast_test_flag(req, SIP_PKT_DEBUG) && option_debug)
- ast_log(LOG_DEBUG, "SIP transfer to non-SIP uri denied\n");
- break;
- default:
- /* Refer-to extension not found, fake a failed transfer */
- transmit_response(p, "202 Accepted", req);
- append_history(p, "Xfer", "Refer failed. Bad extension.");
- transmit_notify_with_sipfrag(p, seqno, "404 Not found", TRUE);
- ast_clear_flag(&p->flags[0], SIP_GOTREFER);
- if (ast_test_flag(req, SIP_PKT_DEBUG) && option_debug)
- ast_log(LOG_DEBUG, "SIP transfer to bad extension: %s\n", p->refer->refer_to);
- break;
- }
- return 0;
- }
- if (ast_strlen_zero(p->context))
- ast_string_field_set(p, context, default_context);
-
- /* If we do not support SIP domains, all transfers are local */
- if (allow_external_domains && check_sip_domain(p->refer->refer_to_domain, NULL, 0)) {
- p->refer->localtransfer = 1;
- if (sipdebug && option_debug > 2)
- ast_log(LOG_DEBUG, "This SIP transfer is local : %s\n", p->refer->refer_to_domain);
- } else if (AST_LIST_EMPTY(&domain_list) || check_sip_domain(p->refer->refer_to_domain, NULL, 0)) {
- /* This PBX doesn't bother with SIP domains or domain is local, so this transfer is local */
- p->refer->localtransfer = 1;
- } else if (sipdebug && option_debug > 2)
- ast_log(LOG_DEBUG, "This SIP transfer is to a remote SIP extension (remote domain %s)\n", p->refer->refer_to_domain);
-
- /* Is this a repeat of a current request? Ignore it */
- /* Don't know what else to do right now. */
- if (ignore)
- return res;
-
- /* If this is a blind transfer, we have the following
- channels to work with:
- - chan1, chan2: The current call between transferer and transferee (2 channels)
- - target_channel: A new call from the transferee to the target (1 channel)
- We need to stay tuned to what happens in order to be able
- to bring back the call to the transferer */
-
- /* If this is a attended transfer, we should have all call legs within reach:
- - chan1, chan2: The call between the transferer and transferee (2 channels)
- - target_channel, targetcall_pvt: The call between the transferer and the target (2 channels)
- We want to bridge chan2 with targetcall_pvt!
-
- The replaces call id in the refer message points
- to the call leg between Asterisk and the transferer.
- So we need to connect the target and the transferee channel
- and hangup the two other channels silently
-
- If the target is non-local, the call ID could be on a remote
- machine and we need to send an INVITE with replaces to the
- target. We basically handle this as a blind transfer
- and let the sip_call function catch that we need replaces
- header in the INVITE.
- */
-
-
- /* Get the transferer's channel */
- current.chan1 = p->owner;
-
- /* Find the other part of the bridge (2) - transferee */
- current.chan2 = ast_bridged_channel(current.chan1);
-
- if (sipdebug && option_debug > 2)
- ast_log(LOG_DEBUG, "SIP %s transfer: Transferer channel %s, transferee channel %s\n", p->refer->attendedtransfer ? "attended" : "blind", current.chan1->name, current.chan2 ? current.chan2->name : "<none>");
-
- if (!current.chan2 && !p->refer->attendedtransfer) {
- /* No bridged channel, propably IVR or echo or similar... */
- /* Guess we should masquerade or something here */
- /* Until we figure it out, refuse transfer of such calls */
- if (sipdebug && option_debug > 2)
- ast_log(LOG_DEBUG,"Refused SIP transfer on non-bridged channel.\n");
- p->refer->status = REFER_FAILED;
- append_history(p, "Xfer", "Refer failed. Non-bridged channel.");
- transmit_response(p, "603 Declined", req);
- return -1;
- }
-
- if (current.chan2) {
- if (sipdebug && option_debug > 3)
- ast_log(LOG_DEBUG, "Got SIP transfer, applying to bridged peer '%s'\n", current.chan2->name);
-
- ast_queue_control(current.chan1, AST_CONTROL_UNHOLD);
- }
-
- ast_set_flag(&p->flags[0], SIP_GOTREFER);
-
- /* Attended transfer: Find all call legs and bridge transferee with target*/
- if (p->refer->attendedtransfer) {
- if ((res = local_attended_transfer(p, &current, req, seqno)))
- return res; /* We're done with the transfer */
- /* Fall through for remote transfers that we did not find locally */
- if (sipdebug && option_debug > 3)
- ast_log(LOG_DEBUG, "SIP attended transfer: Still not our call - generating INVITE with replaces\n");
- /* Fallthrough if we can't find the call leg internally */
- }
-
-
- /* Parking a call */
- if (p->refer->localtransfer && !strcmp(p->refer->refer_to, ast_parking_ext())) {
- /* Must release c's lock now, because it will not longer be accessible after the transfer! */
- *nounlock = 1;
- ast_channel_unlock(current.chan1);
- copy_request(&current.req, req);
- ast_clear_flag(&p->flags[0], SIP_GOTREFER);
- p->refer->status = REFER_200OK;
- append_history(p, "Xfer", "REFER to call parking.");
- if (sipdebug && option_debug > 3)
- ast_log(LOG_DEBUG, "SIP transfer to parking: trying to park %s. Parked by %s\n", current.chan2->name, current.chan1->name);
- sip_park(current.chan2, current.chan1, req, seqno);
- return res;
- }
-
- /* Blind transfers and remote attended xfers */
- transmit_response(p, "202 Accepted", req);
-
- if (current.chan1 && current.chan2) {
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "chan1->name: %s\n", current.chan1->name);
- pbx_builtin_setvar_helper(current.chan1, "BLINDTRANSFER", current.chan2->name);
- }
- if (current.chan2) {
- pbx_builtin_setvar_helper(current.chan2, "BLINDTRANSFER", current.chan1->name);
- pbx_builtin_setvar_helper(current.chan2, "SIPDOMAIN", p->refer->refer_to_domain);
- pbx_builtin_setvar_helper(current.chan2, "SIPTRANSFER", "yes");
- /* One for the new channel */
- pbx_builtin_setvar_helper(current.chan2, "_SIPTRANSFER", "yes");
- /* Attended transfer to remote host, prepare headers for the INVITE */
- if (p->refer->referred_by)
- pbx_builtin_setvar_helper(current.chan2, "_SIPTRANSFER_REFERER", p->refer->referred_by);
- }
- /* Generate a Replaces string to be used in the INVITE during attended transfer */
- if (p->refer->replaces_callid && !ast_strlen_zero(p->refer->replaces_callid)) {
- char tempheader[SIPBUFSIZE];
- snprintf(tempheader, sizeof(tempheader), "%s%s%s%s%s", p->refer->replaces_callid,
- p->refer->replaces_callid_totag ? ";to-tag=" : "",
- p->refer->replaces_callid_totag,
- p->refer->replaces_callid_fromtag ? ";from-tag=" : "",
- p->refer->replaces_callid_fromtag);
- if (current.chan2)
- pbx_builtin_setvar_helper(current.chan2, "_SIPTRANSFER_REPLACES", tempheader);
- }
- /* Must release lock now, because it will not longer
- be accessible after the transfer! */
- *nounlock = 1;
- ast_channel_unlock(current.chan1);
-
- /* Connect the call */
-
- /* FAKE ringing if not attended transfer */
- if (!p->refer->attendedtransfer)
- transmit_notify_with_sipfrag(p, seqno, "183 Ringing", FALSE);
-
- /* For blind transfer, this will lead to a new call */
- /* For attended transfer to remote host, this will lead to
- a new SIP call with a replaces header, if the dial plan allows it
- */
- if (!current.chan2) {
- /* We have no bridge, so we're talking with Asterisk somehow */
- /* We need to masquerade this call */
- /* What to do to fix this situation:
- * Set up the new call in a new channel
- * Let the new channel masq into this channel
- Please add that code here :-)
- */
- p->refer->status = REFER_FAILED;
- transmit_notify_with_sipfrag(p, seqno, "503 Service Unavailable (can't handle one-legged xfers)", TRUE);
- ast_clear_flag(&p->flags[0], SIP_GOTREFER);
- append_history(p, "Xfer", "Refer failed (only bridged calls).");
- return -1;
- }
- ast_set_flag(&p->flags[0], SIP_DEFER_BYE_ON_TRANSFER); /* Delay hangup */
-
- /* For blind transfers, move the call to the new extensions. For attended transfers on multiple
- servers - generate an INVITE with Replaces. Either way, let the dial plan decided */
- res = ast_async_goto(current.chan2, p->refer->refer_to_context, p->refer->refer_to, 1);
-
- if (!res) {
- /* Success - we have a new channel */
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "%s transfer succeeded. Telling transferer.\n", p->refer->attendedtransfer? "Attended" : "Blind");
- transmit_notify_with_sipfrag(p, seqno, "200 Ok", TRUE);
- if (p->refer->localtransfer)
- p->refer->status = REFER_200OK;
- if (p->owner)
- p->owner->hangupcause = AST_CAUSE_NORMAL_CLEARING;
- append_history(p, "Xfer", "Refer succeeded.");
- ast_clear_flag(&p->flags[0], SIP_GOTREFER);
- /* Do not hangup call, the other side do that when we say 200 OK */
- /* We could possibly implement a timer here, auto congestion */
- res = 0;
- } else {
- ast_clear_flag(&p->flags[0], SIP_DEFER_BYE_ON_TRANSFER); /* Don't delay hangup */
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "%s transfer failed. Resuming original call.\n", p->refer->attendedtransfer? "Attended" : "Blind");
- append_history(p, "Xfer", "Refer failed.");
- /* Failure of some kind */
- p->refer->status = REFER_FAILED;
- transmit_notify_with_sipfrag(p, seqno, "503 Service Unavailable", TRUE);
- ast_clear_flag(&p->flags[0], SIP_GOTREFER);
- res = -1;
- }
- return res;
-}
-
-/*! \brief Handle incoming CANCEL request */
-static int handle_request_cancel(struct sip_pvt *p, struct sip_request *req)
-{
-
- check_via(p, req);
- sip_alreadygone(p);
-
- /* At this point, we could have cancelled the invite at the same time
- as the other side sends a CANCEL. Our final reply with error code
- might not have been received by the other side before the CANCEL
- was sent, so let's just give up retransmissions and waiting for
- ACK on our error code. The call is hanging up any way. */
- if (p->invitestate == INV_TERMINATED)
- __sip_pretend_ack(p);
- else
- p->invitestate = INV_CANCELLED;
-
- if (p->owner && p->owner->_state == AST_STATE_UP) {
- /* This call is up, cancel is ignored, we need a bye */
- transmit_response(p, "200 OK", req);
- if (option_debug)
- ast_log(LOG_DEBUG, "Got CANCEL on an answered call. Ignoring... \n");
- return 0;
- }
-
- if (ast_test_flag(&p->flags[0], SIP_INC_COUNT) || ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD))
- update_call_counter(p, DEC_CALL_LIMIT);
-
- stop_media_flows(p); /* Immediately stop RTP, VRTP and UDPTL as applicable */
- if (p->owner)
- ast_queue_hangup(p->owner);
- else
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- if (p->initreq.len > 0) {
- transmit_response_reliable(p, "487 Request Terminated", &p->initreq);
- transmit_response(p, "200 OK", req);
- return 1;
- } else {
- transmit_response(p, "481 Call Leg Does Not Exist", req);
- return 0;
- }
-}
-
-static int acf_channel_read(struct ast_channel *chan, char *funcname, char *preparse, char *buf, size_t buflen)
-{
- struct ast_rtp_quality qos;
- struct sip_pvt *p = chan->tech_pvt;
- char *all = "", *parse = ast_strdupa(preparse);
- AST_DECLARE_APP_ARGS(args,
- AST_APP_ARG(param);
- AST_APP_ARG(type);
- AST_APP_ARG(field);
- );
- AST_STANDARD_APP_ARGS(args, parse);
-
- /* Sanity check */
- if (chan->tech != &sip_tech && chan->tech != &sip_tech_info) {
- ast_log(LOG_ERROR, "Cannot call %s on a non-SIP channel\n", funcname);
- return 0;
- }
-
- if (strcasecmp(args.param, "rtpqos"))
- return 0;
-
- /* Default arguments of audio,all */
- if (ast_strlen_zero(args.type))
- args.type = "audio";
- if (ast_strlen_zero(args.field))
- args.field = "all";
-
- memset(buf, 0, buflen);
- memset(&qos, 0, sizeof(qos));
-
- if (strcasecmp(args.type, "AUDIO") == 0) {
- all = ast_rtp_get_quality(p->rtp, &qos);
- } else if (strcasecmp(args.type, "VIDEO") == 0) {
- all = ast_rtp_get_quality(p->vrtp, &qos);
- }
-
- if (strcasecmp(args.field, "local_ssrc") == 0)
- snprintf(buf, buflen, "%u", qos.local_ssrc);
- else if (strcasecmp(args.field, "local_lostpackets") == 0)
- snprintf(buf, buflen, "%u", qos.local_lostpackets);
- else if (strcasecmp(args.field, "local_jitter") == 0)
- snprintf(buf, buflen, "%.0lf", qos.local_jitter * 1000.0);
- else if (strcasecmp(args.field, "local_count") == 0)
- snprintf(buf, buflen, "%u", qos.local_count);
- else if (strcasecmp(args.field, "remote_ssrc") == 0)
- snprintf(buf, buflen, "%u", qos.remote_ssrc);
- else if (strcasecmp(args.field, "remote_lostpackets") == 0)
- snprintf(buf, buflen, "%u", qos.remote_lostpackets);
- else if (strcasecmp(args.field, "remote_jitter") == 0)
- snprintf(buf, buflen, "%.0lf", qos.remote_jitter * 1000.0);
- else if (strcasecmp(args.field, "remote_count") == 0)
- snprintf(buf, buflen, "%u", qos.remote_count);
- else if (strcasecmp(args.field, "rtt") == 0)
- snprintf(buf, buflen, "%.0lf", qos.rtt * 1000.0);
- else if (strcasecmp(args.field, "all") == 0)
- ast_copy_string(buf, all, buflen);
- else {
- ast_log(LOG_WARNING, "Unrecognized argument '%s' to %s\n", preparse, funcname);
- return -1;
- }
- return 0;
-}
-
-/*! \brief Handle incoming BYE request */
-static int handle_request_bye(struct sip_pvt *p, struct sip_request *req)
-{
- struct ast_channel *c=NULL;
- int res;
- struct ast_channel *bridged_to;
-
- /* If we have an INCOMING invite that we haven't answered, terminate that transaction */
- if (p->pendinginvite && !ast_test_flag(&p->flags[0], SIP_OUTGOING) && !ast_test_flag(req, SIP_PKT_IGNORE) && !p->owner)
- transmit_response_reliable(p, "487 Request Terminated", &p->initreq);
-
- __sip_pretend_ack(p);
-
- p->invitestate = INV_TERMINATED;
-
- copy_request(&p->initreq, req);
- check_via(p, req);
- sip_alreadygone(p);
-
- /* Get RTCP quality before end of call */
- if (!ast_test_flag(&p->flags[0], SIP_NO_HISTORY) || p->owner) {
- char *audioqos, *videoqos;
- if (p->rtp) {
- audioqos = ast_rtp_get_quality(p->rtp, NULL);
- if (!ast_test_flag(&p->flags[0], SIP_NO_HISTORY))
- append_history(p, "RTCPaudio", "Quality:%s", audioqos);
- if (p->owner)
- pbx_builtin_setvar_helper(p->owner, "RTPAUDIOQOS", audioqos);
- }
- if (p->vrtp) {
- videoqos = ast_rtp_get_quality(p->vrtp, NULL);
- if (!ast_test_flag(&p->flags[0], SIP_NO_HISTORY))
- append_history(p, "RTCPvideo", "Quality:%s", videoqos);
- if (p->owner)
- pbx_builtin_setvar_helper(p->owner, "RTPVIDEOQOS", videoqos);
- }
- }
-
- stop_media_flows(p); /* Immediately stop RTP, VRTP and UDPTL as applicable */
-
- if (!ast_strlen_zero(get_header(req, "Also"))) {
- ast_log(LOG_NOTICE, "Client '%s' using deprecated BYE/Also transfer method. Ask vendor to support REFER instead\n",
- ast_inet_ntoa(p->recv.sin_addr));
- if (ast_strlen_zero(p->context))
- ast_string_field_set(p, context, default_context);
- res = get_also_info(p, req);
- if (!res) {
- c = p->owner;
- if (c) {
- bridged_to = ast_bridged_channel(c);
- if (bridged_to) {
- /* Don't actually hangup here... */
- ast_queue_control(c, AST_CONTROL_UNHOLD);
- ast_async_goto(bridged_to, p->context, p->refer->refer_to,1);
- } else
- ast_queue_hangup(p->owner);
- }
- } else {
- ast_log(LOG_WARNING, "Invalid transfer information from '%s'\n", ast_inet_ntoa(p->recv.sin_addr));
- if (p->owner)
- ast_queue_hangup(p->owner);
- }
- } else if (p->owner) {
- ast_queue_hangup(p->owner);
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Received bye, issuing owner hangup\n");
- } else {
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Received bye, no owner, selfdestruct soon.\n");
- }
- ast_clear_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED);
- transmit_response(p, "200 OK", req);
-
- return 1;
-}
-
-/*! \brief Handle incoming MESSAGE request */
-static int handle_request_message(struct sip_pvt *p, struct sip_request *req)
-{
- if (!ast_test_flag(req, SIP_PKT_IGNORE)) {
- if (ast_test_flag(req, SIP_PKT_DEBUG))
- ast_verbose("Receiving message!\n");
- receive_message(p, req);
- } else
- transmit_response(p, "202 Accepted", req);
- return 1;
-}
-
-/*! \brief Handle incoming SUBSCRIBE request */
-static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, int seqno, char *e)
-{
- int gotdest;
- int res = 0;
- int firststate = AST_EXTENSION_REMOVED;
- struct sip_peer *authpeer = NULL;
- const char *eventheader = get_header(req, "Event"); /* Get Event package name */
- const char *accept = get_header(req, "Accept");
- int resubscribe = (p->subscribed != NONE);
- char *temp, *event;
-
- if (p->initreq.headers) {
- /* We already have a dialog */
- if (p->initreq.method != SIP_SUBSCRIBE) {
- /* This is a SUBSCRIBE within another SIP dialog, which we do not support */
- /* For transfers, this could happen, but since we haven't seen it happening, let us just refuse this */
- transmit_response(p, "403 Forbidden (within dialog)", req);
- /* Do not destroy session, since we will break the call if we do */
- if (option_debug)
- ast_log(LOG_DEBUG, "Got a subscription within the context of another call, can't handle that - %s (Method %s)\n", p->callid, sip_methods[p->initreq.method].text);
- return 0;
- } else if (ast_test_flag(req, SIP_PKT_DEBUG)) {
- if (option_debug) {
- if (resubscribe)
- ast_log(LOG_DEBUG, "Got a re-subscribe on existing subscription %s\n", p->callid);
- else
- ast_log(LOG_DEBUG, "Got a new subscription %s (possibly with auth)\n", p->callid);
- }
- }
- }
-
- /* Check if we have a global disallow setting on subscriptions.
- if so, we don't have to check peer/user settings after auth, which saves a lot of processing
- */
- if (!global_allowsubscribe) {
- transmit_response(p, "403 Forbidden (policy)", req);
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- return 0;
- }
-
- if (!ast_test_flag(req, SIP_PKT_IGNORE) && !resubscribe) { /* Set up dialog, new subscription */
- const char *to = get_header(req, "To");
- char totag[128];
-
- /* Check to see if a tag was provided, if so this is actually a resubscription of a dialog we no longer know about */
- if (!ast_strlen_zero(to) && gettag(req, "To", totag, sizeof(totag))) {
- if (ast_test_flag(req, SIP_PKT_DEBUG))
- ast_verbose("Received resubscription for a dialog we no longer know about. Telling remote side to subscribe again.\n");
- transmit_response(p, "481 Subscription does not exist", req);
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- return 0;
- }
-
- /* Use this as the basis */
- if (ast_test_flag(req, SIP_PKT_DEBUG))
- ast_verbose("Creating new subscription\n");
-
- copy_request(&p->initreq, req);
- check_via(p, req);
- } else if (ast_test_flag(req, SIP_PKT_DEBUG) && ast_test_flag(req, SIP_PKT_IGNORE))
- ast_verbose("Ignoring this SUBSCRIBE request\n");
-
- /* Find parameters to Event: header value and remove them for now */
- if (ast_strlen_zero(eventheader)) {
- transmit_response(p, "489 Bad Event", req);
- if (option_debug > 1)
- ast_log(LOG_DEBUG, "Received SIP subscribe for unknown event package: <none>\n");
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- return 0;
- }
-
- if ( (strchr(eventheader, ';'))) {
- event = ast_strdupa(eventheader); /* Since eventheader is a const, we can't change it */
- temp = strchr(event, ';');
- *temp = '\0'; /* Remove any options for now */
- /* We might need to use them later :-) */
- } else
- event = (char *) eventheader; /* XXX is this legal ? */
-
- /* Handle authentication */
- res = check_user_full(p, req, SIP_SUBSCRIBE, e, 0, sin, &authpeer);
- /* if an authentication response was sent, we are done here */
- if (res == AUTH_CHALLENGE_SENT) {
- if (authpeer)
- ASTOBJ_UNREF(authpeer, sip_destroy_peer);
- return 0;
- }
- if (res < 0) {
- if (res == AUTH_FAKE_AUTH) {
- ast_log(LOG_NOTICE, "Sending fake auth rejection for user %s\n", get_header(req, "From"));
- transmit_fake_auth_response(p, req, 1);
- } else {
- ast_log(LOG_NOTICE, "Failed to authenticate user %s for SUBSCRIBE\n", get_header(req, "From"));
- transmit_response_reliable(p, "403 Forbidden", req);
- }
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- if (authpeer)
- ASTOBJ_UNREF(authpeer, sip_destroy_peer);
- return 0;
- }
-
- /* Check if this user/peer is allowed to subscribe at all */
- if (!ast_test_flag(&p->flags[1], SIP_PAGE2_ALLOWSUBSCRIBE)) {
- transmit_response(p, "403 Forbidden (policy)", req);
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- if (authpeer)
- ASTOBJ_UNREF(authpeer, sip_destroy_peer);
- return 0;
- }
-
- /* Get destination right away */
- gotdest = get_destination(p, NULL);
-
- /* Get full contact header - this needs to be used as a request URI in NOTIFY's */
- parse_ok_contact(p, req);
-
- build_contact(p);
- if (gotdest) {
- transmit_response(p, "404 Not Found", req);
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- if (authpeer)
- ASTOBJ_UNREF(authpeer, sip_destroy_peer);
- return 0;
- }
-
- /* Initialize tag for new subscriptions */
- if (ast_strlen_zero(p->tag))
- make_our_tag(p->tag, sizeof(p->tag));
-
- if (!strcmp(event, "presence") || !strcmp(event, "dialog")) { /* Presence, RFC 3842 */
- if (authpeer) /* No need for authpeer here */
- ASTOBJ_UNREF(authpeer, sip_destroy_peer);
-
- /* Header from Xten Eye-beam Accept: multipart/related, application/rlmi+xml, application/pidf+xml, application/xpidf+xml */
- /* Polycom phones only handle xpidf+xml, even if they say they can
- handle pidf+xml as well
- */
- if (strstr(p->useragent, "Polycom")) {
- p->subscribed = XPIDF_XML;
- } else if (strstr(accept, "application/pidf+xml")) {
- p->subscribed = PIDF_XML; /* RFC 3863 format */
- } else if (strstr(accept, "application/dialog-info+xml")) {
- p->subscribed = DIALOG_INFO_XML;
- /* IETF draft: draft-ietf-sipping-dialog-package-05.txt */
- } else if (strstr(accept, "application/cpim-pidf+xml")) {
- p->subscribed = CPIM_PIDF_XML; /* RFC 3863 format */
- } else if (strstr(accept, "application/xpidf+xml")) {
- p->subscribed = XPIDF_XML; /* Early pre-RFC 3863 format with MSN additions (Microsoft Messenger) */
- } else if (ast_strlen_zero(accept)) {
- if (p->subscribed == NONE) { /* if the subscribed field is not already set, and there is no accept header... */
- transmit_response(p, "489 Bad Event", req);
-
- ast_log(LOG_WARNING,"SUBSCRIBE failure: no Accept header: pvt: stateid: %d, laststate: %d, dialogver: %d, subscribecont: '%s', subscribeuri: '%s'\n",
- p->stateid, p->laststate, p->dialogver, p->subscribecontext, p->subscribeuri);
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- return 0;
- }
- /* if p->subscribed is non-zero, then accept is not obligatory; according to rfc 3265 section 3.1.3, at least.
- so, we'll just let it ride, keeping the value from a previous subscription, and not abort the subscription */
- } else {
- /* Can't find a format for events that we know about */
- char mybuf[200];
- snprintf(mybuf,sizeof(mybuf),"489 Bad Event (format %s)", accept);
- transmit_response(p, mybuf, req);
-
- ast_log(LOG_WARNING,"SUBSCRIBE failure: unrecognized format: '%s' pvt: subscribed: %d, stateid: %d, laststate: %d, dialogver: %d, subscribecont: '%s', subscribeuri: '%s'\n",
- accept, (int)p->subscribed, p->stateid, p->laststate, p->dialogver, p->subscribecontext, p->subscribeuri);
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- return 0;
- }
- } else if (!strcmp(event, "message-summary")) {
- if (!ast_strlen_zero(accept) && strcmp(accept, "application/simple-message-summary")) {
- /* Format requested that we do not support */
- transmit_response(p, "406 Not Acceptable", req);
- if (option_debug > 1)
- ast_log(LOG_DEBUG, "Received SIP mailbox subscription for unknown format: %s\n", accept);
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- if (authpeer) /* No need for authpeer here */
- ASTOBJ_UNREF(authpeer, sip_destroy_peer);
- return 0;
- }
- /* Looks like they actually want a mailbox status
- This version of Asterisk supports mailbox subscriptions
- The subscribed URI needs to exist in the dial plan
- In most devices, this is configurable to the voicemailmain extension you use
- */
- if (!authpeer || ast_strlen_zero(authpeer->mailbox)) {
- transmit_response(p, "404 Not found (no mailbox)", req);
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- ast_log(LOG_NOTICE, "Received SIP subscribe for peer without mailbox: %s\n", authpeer->name);
- if (authpeer) /* No need for authpeer here */
- ASTOBJ_UNREF(authpeer, sip_destroy_peer);
- return 0;
- }
-
- p->subscribed = MWI_NOTIFICATION;
- if (authpeer->mwipvt && authpeer->mwipvt != p) /* Destroy old PVT if this is a new one */
- /* We only allow one subscription per peer */
- sip_destroy(authpeer->mwipvt);
- authpeer->mwipvt = p; /* Link from peer to pvt */
- p->relatedpeer = ASTOBJ_REF(authpeer); /* Link from pvt to peer */
- } else { /* At this point, Asterisk does not understand the specified event */
- transmit_response(p, "489 Bad Event", req);
- if (option_debug > 1)
- ast_log(LOG_DEBUG, "Received SIP subscribe for unknown event package: %s\n", event);
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- if (authpeer) /* No need for authpeer here */
- ASTOBJ_UNREF(authpeer, sip_destroy_peer);
- return 0;
- }
-
- if (p->subscribed != MWI_NOTIFICATION && !resubscribe) {
- if (p->stateid > -1)
- ast_extension_state_del(p->stateid, cb_extensionstate);
- p->stateid = ast_extension_state_add(p->context, p->exten, cb_extensionstate, p);
- }
-
- if (!ast_test_flag(req, SIP_PKT_IGNORE) && p)
- p->lastinvite = seqno;
- if (p && !ast_test_flag(&p->flags[0], SIP_NEEDDESTROY)) {
- p->expiry = atoi(get_header(req, "Expires"));
-
- /* check if the requested expiry-time is within the approved limits from sip.conf */
- if (p->expiry > max_expiry)
- p->expiry = max_expiry;
- if (p->expiry < min_expiry && p->expiry > 0)
- p->expiry = min_expiry;
-
- if (sipdebug || option_debug > 1) {
- if (p->subscribed == MWI_NOTIFICATION && p->relatedpeer)
- ast_log(LOG_DEBUG, "Adding subscription for mailbox notification - peer %s Mailbox %s\n", p->relatedpeer->name, p->relatedpeer->mailbox);
- else
- ast_log(LOG_DEBUG, "Adding subscription for extension %s context %s for peer %s\n", p->exten, p->context, p->username);
- }
- if (p->autokillid > -1 && sip_cancel_destroy(p)) /* Remove subscription expiry for renewals */
- ast_log(LOG_WARNING, "Unable to cancel SIP destruction. Expect bad things.\n");
- if (p->expiry > 0)
- sip_scheddestroy(p, (p->expiry + 10) * 1000); /* Set timer for destruction of call at expiration */
-
- if (p->subscribed == MWI_NOTIFICATION) {
- ast_set_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED);
- transmit_response(p, "200 OK", req);
- if (p->relatedpeer) { /* Send first notification */
- ASTOBJ_WRLOCK(p->relatedpeer);
- sip_send_mwi_to_peer(p->relatedpeer);
- ASTOBJ_UNLOCK(p->relatedpeer);
- }
- } else {
- struct sip_pvt *p_old;
-
- if ((firststate = ast_extension_state(NULL, p->context, p->exten)) < 0) {
-
- ast_log(LOG_NOTICE, "Got SUBSCRIBE for extension %s@%s from %s, but there is no hint for that extension.\n", p->exten, p->context, ast_inet_ntoa(p->sa.sin_addr));
- transmit_response(p, "404 Not found", req);
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- return 0;
- }
- ast_set_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED);
- transmit_response(p, "200 OK", req);
- transmit_state_notify(p, firststate, 1, FALSE); /* Send first notification */
- append_history(p, "Subscribestatus", "%s", ast_extension_state2str(firststate));
- /* hide the 'complete' exten/context in the refer_to field for later display */
- ast_string_field_build(p, subscribeuri, "%s@%s", p->exten, p->context);
-
- /* remove any old subscription from this peer for the same exten/context,
- as the peer has obviously forgotten about it and it's wasteful to wait
- for it to expire and send NOTIFY messages to the peer only to have them
- ignored (or generate errors)
- */
- ast_mutex_lock(&iflock);
- for (p_old = iflist; p_old; p_old = p_old->next) {
- if (p_old == p)
- continue;
- if (p_old->initreq.method != SIP_SUBSCRIBE)
- continue;
- if (p_old->subscribed == NONE)
- continue;
- ast_mutex_lock(&p_old->lock);
- if (!strcmp(p_old->username, p->username)) {
- if (!strcmp(p_old->exten, p->exten) &&
- !strcmp(p_old->context, p->context)) {
- ast_set_flag(&p_old->flags[0], SIP_NEEDDESTROY);
- ast_mutex_unlock(&p_old->lock);
- break;
- }
- }
- ast_mutex_unlock(&p_old->lock);
- }
- ast_mutex_unlock(&iflock);
- }
- if (!p->expiry)
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- }
- return 1;
-}
-
-/*! \brief Handle incoming REGISTER request */
-static int handle_request_register(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, char *e)
-{
- enum check_auth_result res;
-
- /* Use this as the basis */
- if (ast_test_flag(req, SIP_PKT_DEBUG))
- ast_verbose("Using latest REGISTER request as basis request\n");
- copy_request(&p->initreq, req);
- check_via(p, req);
- if ((res = register_verify(p, sin, req, e)) < 0) {
- const char *reason;
-
- switch (res) {
- case AUTH_SECRET_FAILED:
- reason = "Wrong password";
- break;
- case AUTH_USERNAME_MISMATCH:
- reason = "Username/auth name mismatch";
- break;
- case AUTH_NOT_FOUND:
- reason = "No matching peer found";
- break;
- case AUTH_UNKNOWN_DOMAIN:
- reason = "Not a local domain";
- break;
- case AUTH_PEER_NOT_DYNAMIC:
- reason = "Peer is not supposed to register";
- break;
- case AUTH_ACL_FAILED:
- reason = "Device does not match ACL";
- break;
- default:
- reason = "Unknown failure";
- break;
- }
- ast_log(LOG_NOTICE, "Registration from '%s' failed for '%s' - %s\n",
- get_header(req, "To"), ast_inet_ntoa(sin->sin_addr),
- reason);
- append_history(p, "RegRequest", "Failed : Account %s : %s", get_header(req, "To"), reason);
- } else
- append_history(p, "RegRequest", "Succeeded : Account %s", get_header(req, "To"));
-
- if (res < 1) {
- /* Destroy the session, but keep us around for just a bit in case they don't
- get our 200 OK */
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- }
- return res;
-}
-
-/*! \brief Handle incoming SIP requests (methods)
-\note This is where all incoming requests go first */
-/* called with p and p->owner locked */
-static int handle_request(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, int *recount, int *nounlock)
-{
- /* Called with p->lock held, as well as p->owner->lock if appropriate, keeping things
- relatively static */
- const char *cmd;
- const char *cseq;
- const char *useragent;
- int seqno;
- int len;
- int ignore = FALSE;
- int respid;
- int res = 0;
- int debug = sip_debug_test_pvt(p);
- char *e;
- int error = 0;
-
- /* Get Method and Cseq */
- cseq = get_header(req, "Cseq");
- cmd = req->header[0];
-
- /* Must have Cseq */
- if (ast_strlen_zero(cmd) || ast_strlen_zero(cseq)) {
- ast_log(LOG_ERROR, "Missing Cseq. Dropping this SIP message, it's incomplete.\n");
- error = 1;
- }
- if (!error && sscanf(cseq, "%d%n", &seqno, &len) != 1) {
- ast_log(LOG_ERROR, "No seqno in '%s'. Dropping incomplete message.\n", cmd);
- error = 1;
- }
- if (error) {
- if (!p->initreq.headers) /* New call */
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY); /* Make sure we destroy this dialog */
- return -1;
- }
- /* Get the command XXX */
-
- cmd = req->rlPart1;
- e = req->rlPart2;
-
- /* Save useragent of the client */
- useragent = get_header(req, "User-Agent");
- if (!ast_strlen_zero(useragent))
- ast_string_field_set(p, useragent, useragent);
-
- /* Find out SIP method for incoming request */
- if (req->method == SIP_RESPONSE) { /* Response to our request */
- /* Response to our request -- Do some sanity checks */
- if (!p->initreq.headers) {
- if (option_debug)
- ast_log(LOG_DEBUG, "That's odd... Got a response on a call we dont know about. Cseq %d Cmd %s\n", seqno, cmd);
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- return 0;
- } else if (p->ocseq && (p->ocseq < seqno) && (seqno != p->lastnoninvite)) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Ignoring out of order response %d (expecting %d)\n", seqno, p->ocseq);
- return -1;
- } else if (p->ocseq && (p->ocseq != seqno) && (seqno != p->lastnoninvite)) {
- /* ignore means "don't do anything with it" but still have to
- respond appropriately */
- ignore = TRUE;
- ast_set_flag(req, SIP_PKT_IGNORE);
- ast_set_flag(req, SIP_PKT_IGNORE_RESP);
- append_history(p, "Ignore", "Ignoring this retransmit\n");
- } else if (e) {
- e = ast_skip_blanks(e);
- if (sscanf(e, "%d %n", &respid, &len) != 1) {
- ast_log(LOG_WARNING, "Invalid response: '%s'\n", e);
- } else {
- if (respid <= 0) {
- ast_log(LOG_WARNING, "Invalid SIP response code: '%d'\n", respid);
- return 0;
- }
- /* More SIP ridiculousness, we have to ignore bogus contacts in 100 etc responses */
- if ((respid == 200) || ((respid >= 300) && (respid <= 399)))
- extract_uri(p, req);
- handle_response(p, respid, e + len, req, ignore, seqno);
- }
- }
- return 0;
- }
-
- /* New SIP request coming in
- (could be new request in existing SIP dialog as well...)
- */
-
- p->method = req->method; /* Find out which SIP method they are using */
- if (option_debug > 3)
- ast_log(LOG_DEBUG, "**** Received %s (%d) - Command in SIP %s\n", sip_methods[p->method].text, sip_methods[p->method].id, cmd);
-
- if (p->icseq && (p->icseq > seqno) ) {
- if (p->pendinginvite && seqno == p->pendinginvite && (req->method == SIP_ACK || req->method == SIP_CANCEL)) {
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Got CANCEL or ACK on INVITE with transactions in between.\n");
- } else {
- if (option_debug)
- ast_log(LOG_DEBUG, "Ignoring too old SIP packet packet %d (expecting >= %d)\n", seqno, p->icseq);
- if (req->method != SIP_ACK)
- transmit_response(p, "503 Server error", req); /* We must respond according to RFC 3261 sec 12.2 */
- return -1;
- }
- } else if (p->icseq &&
- p->icseq == seqno &&
- req->method != SIP_ACK &&
- (p->method != SIP_CANCEL || ast_test_flag(&p->flags[0], SIP_ALREADYGONE))) {
- /* ignore means "don't do anything with it" but still have to
- respond appropriately. We do this if we receive a repeat of
- the last sequence number */
- ignore = 2;
- ast_set_flag(req, SIP_PKT_IGNORE);
- ast_set_flag(req, SIP_PKT_IGNORE_REQ);
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Ignoring SIP message because of retransmit (%s Seqno %d, ours %d)\n", sip_methods[p->method].text, p->icseq, seqno);
- }
-
- if (seqno >= p->icseq)
- /* Next should follow monotonically (but not necessarily
- incrementally -- thanks again to the genius authors of SIP --
- increasing */
- p->icseq = seqno;
-
- /* Find their tag if we haven't got it */
- if (ast_strlen_zero(p->theirtag)) {
- char tag[128];
-
- gettag(req, "From", tag, sizeof(tag));
- ast_string_field_set(p, theirtag, tag);
- }
- snprintf(p->lastmsg, sizeof(p->lastmsg), "Rx: %s", cmd);
-
- if (pedanticsipchecking) {
- /* If this is a request packet without a from tag, it's not
- correct according to RFC 3261 */
- /* Check if this a new request in a new dialog with a totag already attached to it,
- RFC 3261 - section 12.2 - and we don't want to mess with recovery */
- if (!p->initreq.headers && ast_test_flag(req, SIP_PKT_WITH_TOTAG)) {
- /* If this is a first request and it got a to-tag, it is not for us */
- if (!ast_test_flag(req, SIP_PKT_IGNORE) && req->method == SIP_INVITE) {
- transmit_response_reliable(p, "481 Call/Transaction Does Not Exist", req);
- /* Will cease to exist after ACK */
- } else if (req->method != SIP_ACK) {
- transmit_response(p, "481 Call/Transaction Does Not Exist", req);
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- }
- return res;
- }
- }
-
- if (!e && (p->method == SIP_INVITE || p->method == SIP_SUBSCRIBE || p->method == SIP_REGISTER || p->method == SIP_NOTIFY)) {
- transmit_response(p, "400 Bad request", req);
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- return -1;
- }
-
- /* Handle various incoming SIP methods in requests */
- switch (p->method) {
- case SIP_OPTIONS:
- res = handle_request_options(p, req);
- break;
- case SIP_INVITE:
- res = handle_request_invite(p, req, debug, seqno, sin, recount, e, nounlock);
- break;
- case SIP_REFER:
- res = handle_request_refer(p, req, debug, ignore, seqno, nounlock);
- break;
- case SIP_CANCEL:
- res = handle_request_cancel(p, req);
- break;
- case SIP_BYE:
- res = handle_request_bye(p, req);
- break;
- case SIP_MESSAGE:
- res = handle_request_message(p, req);
- break;
- case SIP_SUBSCRIBE:
- res = handle_request_subscribe(p, req, sin, seqno, e);
- break;
- case SIP_REGISTER:
- res = handle_request_register(p, req, sin, e);
- break;
- case SIP_INFO:
- if (ast_test_flag(req, SIP_PKT_DEBUG))
- ast_verbose("Receiving INFO!\n");
- if (!ignore)
- handle_request_info(p, req);
- else /* if ignoring, transmit response */
- transmit_response(p, "200 OK", req);
- break;
- case SIP_NOTIFY:
- res = handle_request_notify(p, req, sin, seqno, e);
- break;
- case SIP_ACK:
- /* Make sure we don't ignore this */
- if (seqno == p->pendinginvite) {
- p->invitestate = INV_TERMINATED;
- p->pendinginvite = 0;
- __sip_ack(p, seqno, FLAG_RESPONSE, 0);
- if (find_sdp(req)) {
- if (process_sdp(p, req))
- return -1;
- }
- check_pendings(p);
- }
- /* Got an ACK that we did not match. Ignore silently */
- if (!p->lastinvite && ast_strlen_zero(p->randdata))
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- break;
- default:
- transmit_response_with_allow(p, "501 Method Not Implemented", req, 0);
- ast_log(LOG_NOTICE, "Unknown SIP command '%s' from '%s'\n",
- cmd, ast_inet_ntoa(p->sa.sin_addr));
- /* If this is some new method, and we don't have a call, destroy it now */
- if (!p->initreq.headers)
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
- break;
- }
- return res;
-}
-
-static void process_request_queue(struct sip_pvt *p, int *recount, int *nounlock)
-{
- struct sip_request *req;
-
- while ((req = AST_LIST_REMOVE_HEAD(&p->request_queue, next))) {
- if (handle_request(p, req, &p->recv, recount, nounlock) == -1) {
- /* Request failed */
- if (option_debug) {
- ast_log(LOG_DEBUG, "SIP message could not be handled, bad request: %-70.70s\n", p->callid[0] ? p->callid : "<no callid>");
- }
- }
- ast_free(req);
- }
-}
-
-static int scheduler_process_request_queue(const void *data)
-{
- struct sip_pvt *p = (struct sip_pvt *) data;
- int recount = 0;
- int nounlock = 0;
- int lockretry;
-
- for (lockretry = 10; lockretry > 0; lockretry--) {
- ast_mutex_lock(&p->lock);
-
- /* lock the owner if it has one -- we may need it */
- /* because this is deadlock-prone, we need to try and unlock if failed */
- if (!p->owner || !ast_channel_trylock(p->owner)) {
- break; /* locking succeeded */
- }
-
- if (lockretry != 1) {
- ast_mutex_unlock(&p->lock);
- /* Sleep for a very short amount of time */
- usleep(1);
- }
- }
-
- if (!lockretry) {
- int retry = !AST_LIST_EMPTY(&p->request_queue);
-
- /* we couldn't get the owner lock, which is needed to process
- the queued requests, so return a non-zero value, which will
- cause the scheduler to run this request again later if there
- still requests to be processed
- */
- ast_mutex_unlock(&p->lock);
- return retry;
- };
-
- process_request_queue(p, &recount, &nounlock);
- p->request_queue_sched_id = -1;
-
- if (p->owner && !nounlock) {
- ast_channel_unlock(p->owner);
- }
- ast_mutex_unlock(&p->lock);
-
- if (recount) {
- ast_update_use_count();
- }
-
- return 0;
-}
-
-static int queue_request(struct sip_pvt *p, const struct sip_request *req)
-{
- struct sip_request *newreq;
-
- if (!(newreq = ast_calloc(1, sizeof(*newreq)))) {
- return -1;
- }
-
- copy_request(newreq, req);
- AST_LIST_INSERT_TAIL(&p->request_queue, newreq, next);
- if (p->request_queue_sched_id == -1) {
- p->request_queue_sched_id = ast_sched_add(sched, 10, scheduler_process_request_queue, p);
- }
-
- return 0;
-}
-
-/*! \brief Read data from SIP socket
-\note sipsock_read locks the owner channel while we are processing the SIP message
-\return 1 on error, 0 on success
-\note Successful messages is connected to SIP call and forwarded to handle_request()
-*/
-static int sipsock_read(int *id, int fd, short events, void *ignore)
-{
- struct sip_request req;
- struct sockaddr_in sin = { 0, };
- struct sip_pvt *p;
- int res;
- socklen_t len = sizeof(sin);
- int nounlock = 0;
- int recount = 0;
- int lockretry;
-
- memset(&req, 0, sizeof(req));
- res = recvfrom(sipsock, req.data, sizeof(req.data) - 1, 0, (struct sockaddr *)&sin, &len);
- if (res < 0) {
-#if !defined(__FreeBSD__)
- if (errno == EAGAIN)
- ast_log(LOG_NOTICE, "SIP: Received packet with bad UDP checksum\n");
- else
-#endif
- if (errno != ECONNREFUSED)
- ast_log(LOG_WARNING, "Recv error: %s\n", strerror(errno));
- return 1;
- }
- if (option_debug && res == sizeof(req.data) - 1)
- ast_log(LOG_DEBUG, "Received packet exceeds buffer. Data is possibly lost\n");
-
- req.data[res] = '\0';
- req.len = res;
- if(sip_debug_test_addr(&sin)) /* Set the debug flag early on packet level */
- ast_set_flag(&req, SIP_PKT_DEBUG);
- if (pedanticsipchecking)
- req.len = lws2sws(req.data, req.len); /* Fix multiline headers */
- if (ast_test_flag(&req, SIP_PKT_DEBUG))
- ast_verbose("\n<--- SIP read from %s:%d --->\n%s\n<------------->\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), req.data);
-
- if(parse_request(&req) == -1) /* Bad packet, can't parse */
- return 1;
-
- req.method = find_sip_method(req.rlPart1);
-
- if (ast_test_flag(&req, SIP_PKT_DEBUG))
- ast_verbose("--- (%d headers %d lines)%s ---\n", req.headers, req.lines, (req.headers + req.lines == 0) ? " Nat keepalive" : "");
-
- if (req.headers < 2) /* Must have at least two headers */
- return 1;
-
- /* Process request, with netlock held, and with usual deadlock avoidance */
- for (lockretry = 10; lockretry > 0; lockretry--) {
- ast_mutex_lock(&netlock);
-
- /* Find the active SIP dialog or create a new one */
- p = find_call(&req, &sin, req.method); /* returns p locked */
- if (p == NULL) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Invalid SIP message - rejected , no callid, len %d\n", req.len);
- ast_mutex_unlock(&netlock);
- return 1;
- }
- /* Go ahead and lock the owner if it has one -- we may need it */
- /* because this is deadlock-prone, we need to try and unlock if failed */
- if (!p->owner || !ast_channel_trylock(p->owner))
- break; /* locking succeeded */
- if (lockretry != 1) {
- ast_mutex_unlock(&p->lock);
- ast_mutex_unlock(&netlock);
- /* Sleep for a very short amount of time */
- usleep(1);
- }
- }
- p->recv = sin;
-
- if (!ast_test_flag(&p->flags[0], SIP_NO_HISTORY)) /* This is a request or response, note what it was for */
- append_history(p, "Rx", "%s / %s / %s", req.data, get_header(&req, "CSeq"), req.rlPart2);
-
- if (!lockretry) {
- if (!queue_request(p, &req)) {
- /* the request has been queued for later handling */
- ast_mutex_unlock(&p->lock);
- ast_mutex_unlock(&netlock);
- return 1;
- }
-
- /* This is unsafe, since p->owner is not locked. */
- if (p->owner)
- ast_log(LOG_ERROR, "Channel lock for %s could not be obtained, and request was unable to be queued.\n", S_OR(p->owner->name, "- no channel name ??? - "));
- ast_log(LOG_ERROR, "SIP transaction failed: %s \n", p->callid);
- if (req.method != SIP_ACK)
- transmit_response(p, "503 Server error", &req); /* We must respond according to RFC 3261 sec 12.2 */
- /* XXX We could add retry-after to make sure they come back */
- append_history(p, "LockFail", "Owner lock failed, transaction failed.");
- ast_mutex_unlock(&p->lock);
- ast_mutex_unlock(&netlock);
- return 1;
- }
-
- /* if there are queued requests on this sip_pvt, process them first, so that everything is
- handled in order
- */
- if (!AST_LIST_EMPTY(&p->request_queue)) {
- AST_SCHED_DEL(sched, p->request_queue_sched_id);
- process_request_queue(p, &recount, &nounlock);
- }
-
- if (handle_request(p, &req, &sin, &recount, &nounlock) == -1) {
- /* Request failed */
- if (option_debug)
- ast_log(LOG_DEBUG, "SIP message could not be handled, bad request: %-70.70s\n", p->callid[0] ? p->callid : "<no callid>");
- }
-
- if (p->owner && !nounlock)
- ast_channel_unlock(p->owner);
- ast_mutex_unlock(&p->lock);
- ast_mutex_unlock(&netlock);
- if (recount)
- ast_update_use_count();
-
- return 1;
-}
-
-/*! \brief Send message waiting indication to alert peer that they've got voicemail */
-static int sip_send_mwi_to_peer(struct sip_peer *peer)
-{
- /* Called with peerl lock, but releases it */
- struct sip_pvt *p;
- int newmsgs, oldmsgs;
-
- /* Do we have an IP address? If not, skip this peer */
- if (!peer->addr.sin_addr.s_addr && !peer->defaddr.sin_addr.s_addr)
- return 0;
-
- /* Check for messages */
- ast_app_inboxcount(peer->mailbox, &newmsgs, &oldmsgs);
-
- peer->lastmsgcheck = time(NULL);
-
- /* Return now if it's the same thing we told them last time */
- if (((newmsgs > 0x7fff ? 0x7fff0000 : (newmsgs << 16)) | (oldmsgs > 0xffff ? 0xffff : oldmsgs)) == peer->lastmsgssent) {
- return 0;
- }
-
-
- peer->lastmsgssent = ((newmsgs > 0x7fff ? 0x7fff0000 : (newmsgs << 16)) | (oldmsgs > 0xffff ? 0xffff : oldmsgs));
-
- if (peer->mwipvt) {
- /* Base message on subscription */
- p = peer->mwipvt;
- } else {
- /* Build temporary dialog for this message */
- if (!(p = sip_alloc(NULL, NULL, 0, SIP_NOTIFY)))
- return -1;
- if (create_addr_from_peer(p, peer)) {
- /* Maybe they're not registered, etc. */
- sip_destroy(p);
- return 0;
- }
- /* Recalculate our side, and recalculate Call ID */
- if (ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip))
- p->ourip = __ourip;
- build_via(p);
- build_callid_pvt(p);
- /* Destroy this session after 32 secs */
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- }
- /* Send MWI */
- ast_set_flag(&p->flags[0], SIP_OUTGOING);
- transmit_notify_with_mwi(p, newmsgs, oldmsgs, peer->vmexten);
- return 0;
-}
-
-/*! \brief Check whether peer needs a new MWI notification check */
-static int does_peer_need_mwi(struct sip_peer *peer)
-{
- time_t t = time(NULL);
-
- if (ast_test_flag(&peer->flags[1], SIP_PAGE2_SUBSCRIBEMWIONLY) &&
- !peer->mwipvt) { /* We don't have a subscription */
- peer->lastmsgcheck = t; /* Reset timer */
- return FALSE;
- }
-
- if (!ast_strlen_zero(peer->mailbox) && (t - peer->lastmsgcheck) > global_mwitime)
- return TRUE;
-
- return FALSE;
-}
-
-
-/*! \brief The SIP monitoring thread
-\note This thread monitors all the SIP sessions and peers that needs notification of mwi
- (and thus do not have a separate thread) indefinitely
-*/
-static void *do_monitor(void *data)
-{
- int res;
- struct sip_pvt *sip;
- struct sip_peer *peer = NULL;
- time_t t;
- int fastrestart = FALSE;
- int lastpeernum = -1;
- int curpeernum;
- int reloading;
-
- /* Add an I/O event to our SIP UDP socket */
- if (sipsock > -1)
- sipsock_read_id = ast_io_add(io, sipsock, sipsock_read, AST_IO_IN, NULL);
-
- /* From here on out, we die whenever asked */
- for(;;) {
- /* Check for a reload request */
- ast_mutex_lock(&sip_reload_lock);
- reloading = sip_reloading;
- sip_reloading = FALSE;
- ast_mutex_unlock(&sip_reload_lock);
- if (reloading) {
- if (option_verbose > 0)
- ast_verbose(VERBOSE_PREFIX_1 "Reloading SIP\n");
- sip_do_reload(sip_reloadreason);
-
- /* Change the I/O fd of our UDP socket */
- if (sipsock > -1) {
- if (sipsock_read_id)
- sipsock_read_id = ast_io_change(io, sipsock_read_id, sipsock, NULL, 0, NULL);
- else
- sipsock_read_id = ast_io_add(io, sipsock, sipsock_read, AST_IO_IN, NULL);
- } else if (sipsock_read_id) {
- ast_io_remove(io, sipsock_read_id);
- sipsock_read_id = NULL;
- }
- }
-restartsearch:
- /* Check for interfaces needing to be killed */
- ast_mutex_lock(&iflock);
- t = time(NULL);
- /* don't scan the interface list if it hasn't been a reasonable period
- of time since the last time we did it (when MWI is being sent, we can
- get back to this point every millisecond or less)
- */
- for (sip = iflist; !fastrestart && sip; sip = sip->next) {
- /*! \note If we can't get a lock on an interface, skip it and come
- * back later. Note that there is the possibility of a deadlock with
- * sip_hangup otherwise, because sip_hangup is called with the channel
- * locked first, and the iface lock is attempted second.
- */
- if (ast_mutex_trylock(&sip->lock))
- continue;
-
- /* Check RTP timeouts and kill calls if we have a timeout set and do not get RTP */
- if (sip->rtp && sip->owner &&
- (sip->owner->_state == AST_STATE_UP) &&
- !sip->redirip.sin_addr.s_addr &&
- sip->t38.state != T38_ENABLED) {
- if (sip->lastrtptx &&
- ast_rtp_get_rtpkeepalive(sip->rtp) &&
- (t > sip->lastrtptx + ast_rtp_get_rtpkeepalive(sip->rtp))) {
- /* Need to send an empty RTP packet */
- sip->lastrtptx = time(NULL);
- ast_rtp_sendcng(sip->rtp, 0);
- }
- if (sip->lastrtprx &&
- (ast_rtp_get_rtptimeout(sip->rtp) || ast_rtp_get_rtpholdtimeout(sip->rtp)) &&
- (t > sip->lastrtprx + ast_rtp_get_rtptimeout(sip->rtp))) {
- /* Might be a timeout now -- see if we're on hold */
- struct sockaddr_in sin;
- ast_rtp_get_peer(sip->rtp, &sin);
- if (sin.sin_addr.s_addr ||
- (ast_rtp_get_rtpholdtimeout(sip->rtp) &&
- (t > sip->lastrtprx + ast_rtp_get_rtpholdtimeout(sip->rtp)))) {
- /* Needs a hangup */
- if (ast_rtp_get_rtptimeout(sip->rtp)) {
- while (sip->owner && ast_channel_trylock(sip->owner)) {
- DEADLOCK_AVOIDANCE(&sip->lock);
- }
- if (sip->owner) {
- ast_log(LOG_NOTICE,
- "Disconnecting call '%s' for lack of RTP activity in %ld seconds\n",
- sip->owner->name,
- (long) (t - sip->lastrtprx));
- /* Issue a softhangup */
- ast_softhangup_nolock(sip->owner, AST_SOFTHANGUP_DEV);
- ast_channel_unlock(sip->owner);
- /* forget the timeouts for this call, since a hangup
- has already been requested and we don't want to
- repeatedly request hangups
- */
- ast_rtp_set_rtptimeout(sip->rtp, 0);
- ast_rtp_set_rtpholdtimeout(sip->rtp, 0);
- if (sip->vrtp) {
- ast_rtp_set_rtptimeout(sip->vrtp, 0);
- ast_rtp_set_rtpholdtimeout(sip->vrtp, 0);
- }
- }
- }
- }
- }
- }
- /* If we have sessions that needs to be destroyed, do it now */
- if (ast_test_flag(&sip->flags[0], SIP_NEEDDESTROY) && !sip->packets &&
- !sip->owner) {
- ast_mutex_unlock(&sip->lock);
- __sip_destroy(sip, 1);
- ast_mutex_unlock(&iflock);
- usleep(1);
- goto restartsearch;
- }
- ast_mutex_unlock(&sip->lock);
- }
- ast_mutex_unlock(&iflock);
-
- /* XXX TODO The scheduler usage in this module does not have sufficient
- * synchronization being done between running the scheduler and places
- * scheduling tasks. As it is written, any scheduled item may not run
- * any sooner than about 1 second, regardless of whether a sooner time
- * was asked for. */
-
- pthread_testcancel();
- /* Wait for sched or io */
- res = ast_sched_wait(sched);
- if ((res < 0) || (res > 1000))
- res = 1000;
- /* If we might need to send more mailboxes, don't wait long at all.*/
- if (fastrestart)
- res = 1;
- res = ast_io_wait(io, res);
- if (option_debug && res > 20)
- ast_log(LOG_DEBUG, "chan_sip: ast_io_wait ran %d all at once\n", res);
- ast_mutex_lock(&monlock);
- res = ast_sched_runq(sched);
- if (option_debug && res >= 20)
- ast_log(LOG_DEBUG, "chan_sip: ast_sched_runq ran %d all at once\n", res);
-
- /* Send MWI notifications to peers - static and cached realtime peers */
- t = time(NULL);
- fastrestart = FALSE;
- curpeernum = 0;
- peer = NULL;
- /* Find next peer that needs mwi */
- ASTOBJ_CONTAINER_TRAVERSE(&peerl, !peer, do {
- if ((curpeernum > lastpeernum) && does_peer_need_mwi(iterator)) {
- fastrestart = TRUE;
- lastpeernum = curpeernum;
- peer = ASTOBJ_REF(iterator);
- };
- curpeernum++;
- } while (0)
- );
- /* Send MWI to the peer */
- if (peer) {
- ASTOBJ_WRLOCK(peer);
- sip_send_mwi_to_peer(peer);
- ASTOBJ_UNLOCK(peer);
- ASTOBJ_UNREF(peer,sip_destroy_peer);
- } else {
- /* Reset where we come from */
- lastpeernum = -1;
- }
- ast_mutex_unlock(&monlock);
- }
- /* Never reached */
- return NULL;
-
-}
-
-/*! \brief Start the channel monitor thread */
-static int restart_monitor(void)
-{
- /* If we're supposed to be stopped -- stay stopped */
- if (monitor_thread == AST_PTHREADT_STOP)
- return 0;
- ast_mutex_lock(&monlock);
- if (monitor_thread == pthread_self()) {
- ast_mutex_unlock(&monlock);
- ast_log(LOG_WARNING, "Cannot kill myself\n");
- return -1;
- }
- if (monitor_thread != AST_PTHREADT_NULL) {
- /* Wake up the thread */
- pthread_kill(monitor_thread, SIGURG);
- } else {
- /* Start a new monitor */
- if (ast_pthread_create_background(&monitor_thread, NULL, do_monitor, NULL) < 0) {
- ast_mutex_unlock(&monlock);
- ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
- return -1;
- }
- }
- ast_mutex_unlock(&monlock);
- return 0;
-}
-
-/*! \brief React to lack of answer to Qualify poke */
-static int sip_poke_noanswer(const void *data)
-{
- struct sip_peer *peer = (struct sip_peer *)data;
-
- peer->pokeexpire = -1;
- if (peer->lastms > -1) {
- ast_log(LOG_NOTICE, "Peer '%s' is now UNREACHABLE! Last qualify: %d\n", peer->name, peer->lastms);
- manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "Peer: SIP/%s\r\nPeerStatus: Unreachable\r\nTime: %d\r\n", peer->name, -1);
- }
- if (peer->call)
- sip_destroy(peer->call);
- peer->call = NULL;
- peer->lastms = -1;
- ast_device_state_changed("SIP/%s", peer->name);
-
- /* This function gets called one place outside of the scheduler ... */
- if (!AST_SCHED_DEL(sched, peer->pokeexpire)) {
- struct sip_peer *peer_ptr = peer;
- ASTOBJ_UNREF(peer_ptr, sip_destroy_peer);
- }
-
- /* There is no need to ASTOBJ_REF() here. Just let the scheduled callback
- * inherit the reference that the current callback already has. */
- peer->pokeexpire = ast_sched_add(sched, DEFAULT_FREQ_NOTOK, sip_poke_peer_s, peer);
- if (peer->pokeexpire == -1) {
- ASTOBJ_UNREF(peer, sip_destroy_peer);
- }
-
- return 0;
-}
-
-/*! \brief Check availability of peer, also keep NAT open
-\note This is done with the interval in qualify= configuration option
- Default is 2 seconds */
-static int sip_poke_peer(struct sip_peer *peer)
-{
- struct sip_pvt *p;
- int xmitres = 0;
-
- if (!peer->maxms || !peer->addr.sin_addr.s_addr) {
- /* IF we have no IP, or this isn't to be monitored, return
- imeediately after clearing things out */
- if (!AST_SCHED_DEL(sched, peer->pokeexpire)) {
- struct sip_peer *peer_ptr = peer;
- ASTOBJ_UNREF(peer_ptr, sip_destroy_peer);
- }
- peer->lastms = 0;
- peer->call = NULL;
- return 0;
- }
- if (peer->call) {
- if (sipdebug)
- ast_log(LOG_NOTICE, "Still have a QUALIFY dialog active, deleting\n");
- sip_destroy(peer->call);
- }
- if (!(p = peer->call = sip_alloc(NULL, NULL, 0, SIP_OPTIONS)))
- return -1;
-
- p->sa = peer->addr;
- p->recv = peer->addr;
- 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);
-
- /* Send OPTIONs to peer's fullcontact */
- if (!ast_strlen_zero(peer->fullcontact))
- ast_string_field_set(p, fullcontact, peer->fullcontact);
-
- if (!ast_strlen_zero(peer->tohost))
- ast_string_field_set(p, tohost, peer->tohost);
- else
- ast_string_field_set(p, tohost, ast_inet_ntoa(peer->addr.sin_addr));
-
- /* Recalculate our side, and recalculate Call ID */
- if (ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip))
- p->ourip = __ourip;
- build_via(p);
- build_callid_pvt(p);
-
- if (!AST_SCHED_DEL(sched, peer->pokeexpire)) {
- struct sip_peer *peer_ptr = peer;
- ASTOBJ_UNREF(peer_ptr, sip_destroy_peer);
- }
-
- p->relatedpeer = ASTOBJ_REF(peer);
- ast_set_flag(&p->flags[0], SIP_OUTGOING);
-#ifdef VOCAL_DATA_HACK
- ast_copy_string(p->username, "__VOCAL_DATA_SHOULD_READ_THE_SIP_SPEC__", sizeof(p->username));
- xmitres = transmit_invite(p, SIP_INVITE, 0, 2);
-#else
- xmitres = transmit_invite(p, SIP_OPTIONS, 0, 2);
-#endif
- gettimeofday(&peer->ps, NULL);
- if (xmitres == XMIT_ERROR) {
- sip_poke_noanswer(ASTOBJ_REF(peer)); /* Immediately unreachable, network problems */
- } else {
- if (!AST_SCHED_DEL(sched, peer->pokeexpire)) {
- struct sip_peer *peer_ptr = peer;
- ASTOBJ_UNREF(peer_ptr, sip_destroy_peer);
- }
- peer->pokeexpire = ast_sched_add(sched, peer->maxms * 2, sip_poke_noanswer, ASTOBJ_REF(peer));
- if (peer->pokeexpire == -1) {
- struct sip_peer *peer_ptr = peer;
- ASTOBJ_UNREF(peer_ptr, sip_destroy_peer);
- }
- }
-
- return 0;
-}
-
-/*! \brief Part of PBX channel interface
-\note
-\par Return values:---
-
- If we have qualify on and the device is not reachable, regardless of registration
- state we return AST_DEVICE_UNAVAILABLE
-
- For peers with call limit:
- - not registered AST_DEVICE_UNAVAILABLE
- - registered, no call AST_DEVICE_NOT_INUSE
- - registered, active calls AST_DEVICE_INUSE
- - registered, call limit reached AST_DEVICE_BUSY
- - registered, onhold AST_DEVICE_ONHOLD
- - registered, ringing AST_DEVICE_RINGING
-
- For peers without call limit:
- - not registered AST_DEVICE_UNAVAILABLE
- - registered AST_DEVICE_NOT_INUSE
- - fixed IP (!dynamic) AST_DEVICE_NOT_INUSE
-
- Peers that does not have a known call and can't be reached by OPTIONS
- - unreachable AST_DEVICE_UNAVAILABLE
-
- If we return AST_DEVICE_UNKNOWN, the device state engine will try to find
- out a state by walking the channel list.
-
- The queue system (\ref app_queue.c) treats a member as "active"
- if devicestate is != AST_DEVICE_UNAVAILBALE && != AST_DEVICE_INVALID
-
- When placing a call to the queue member, queue system sets a member to busy if
- != AST_DEVICE_NOT_INUSE and != AST_DEVICE_UNKNOWN
-
-*/
-static int sip_devicestate(void *data)
-{
- char *host;
- char *tmp;
-
- struct hostent *hp;
- struct ast_hostent ahp;
- struct sip_peer *p;
-
- int res = AST_DEVICE_INVALID;
-
- /* make sure data is not null. Maybe unnecessary, but better be safe */
- host = ast_strdupa(data ? data : "");
- if ((tmp = strchr(host, '@')))
- host = tmp + 1;
-
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Checking device state for peer %s\n", host);
-
- /* If find_peer asks for a realtime peer, then this breaks rtautoclear. This
- * is because when a peer tries to autoexpire, the last thing it does is to
- * queue up an event telling the system that the devicestate has changed
- * (presumably to unavailable). If we ask for a realtime peer here, this would
- * load it BACK into memory, thus defeating the point of trying to trying to
- * clear dead hosts out of memory.
- */
- if ((p = find_peer(host, NULL, 0, 1))) {
- if (p->addr.sin_addr.s_addr || p->defaddr.sin_addr.s_addr) {
- /* we have an address for the peer */
-
- /* Check status in this order
- - Hold
- - Ringing
- - Busy (enforced only by call limit)
- - Inuse (we have a call)
- - Unreachable (qualify)
- If we don't find any of these state, report AST_DEVICE_NOT_INUSE
- for registered devices */
-
- if (p->onHold)
- /* First check for hold or ring states */
- res = AST_DEVICE_ONHOLD;
- else if (p->inRinging) {
- if (p->inRinging == p->inUse)
- res = AST_DEVICE_RINGING;
- else
- res = AST_DEVICE_RINGINUSE;
- } else if (p->call_limit && (p->inUse == p->call_limit))
- /* check call limit */
- res = AST_DEVICE_BUSY;
- else if (p->call_limit && p->inUse)
- /* Not busy, but we do have a call */
- res = AST_DEVICE_INUSE;
- else if (p->maxms && ((p->lastms > p->maxms) || (p->lastms < 0)))
- /* We don't have a call. Are we reachable at all? Requires qualify= */
- res = AST_DEVICE_UNAVAILABLE;
- else /* Default reply if we're registered and have no other data */
- res = AST_DEVICE_NOT_INUSE;
- } else {
- /* there is no address, it's unavailable */
- res = AST_DEVICE_UNAVAILABLE;
- }
- ASTOBJ_UNREF(p,sip_destroy_peer);
- } else {
- char *port = strchr(host, ':');
- if (port)
- *port = '\0';
- hp = ast_gethostbyname(host, &ahp);
- if (hp)
- res = AST_DEVICE_UNKNOWN;
- }
-
- return res;
-}
-
-/*! \brief PBX interface function -build SIP pvt structure
- SIP calls initiated by the PBX arrive here */
-static struct ast_channel *sip_request_call(const char *type, int format, void *data, int *cause)
-{
- int oldformat;
- struct sip_pvt *p;
- struct ast_channel *tmpc = NULL;
- char *ext, *host;
- char tmp[256];
- char *dest = data;
-
- oldformat = format;
- if (!(format &= ((AST_FORMAT_MAX_AUDIO << 1) - 1))) {
- ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format %s while capability is %s\n", ast_getformatname(oldformat), ast_getformatname(global_capability));
- *cause = AST_CAUSE_BEARERCAPABILITY_NOTAVAIL; /* Can't find codec to connect to host */
- return NULL;
- }
- if (option_debug)
- ast_log(LOG_DEBUG, "Asked to create a SIP channel with formats: %s\n", ast_getformatname_multiple(tmp, sizeof(tmp), oldformat));
-
- if (!(p = sip_alloc(NULL, NULL, 0, SIP_INVITE))) {
- ast_log(LOG_ERROR, "Unable to build sip pvt data for '%s' (Out of memory or socket error)\n", (char *)data);
- *cause = AST_CAUSE_SWITCH_CONGESTION;
- return NULL;
- }
-
- ast_set_flag(&p->flags[1], SIP_PAGE2_OUTGOING_CALL);
-
- if (!(p->options = ast_calloc(1, sizeof(*p->options)))) {
- sip_destroy(p);
- ast_log(LOG_ERROR, "Unable to build option SIP data structure - Out of memory\n");
- *cause = AST_CAUSE_SWITCH_CONGESTION;
- return NULL;
- }
-
- ast_copy_string(tmp, dest, sizeof(tmp));
- host = strchr(tmp, '@');
- if (host) {
- *host++ = '\0';
- ext = tmp;
- } else {
- ext = strchr(tmp, '/');
- if (ext)
- *ext++ = '\0';
- host = tmp;
- }
-
- if (create_addr(p, host)) {
- *cause = AST_CAUSE_UNREGISTERED;
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Cant create SIP call - target device not registred\n");
- sip_destroy(p);
- return NULL;
- }
- if (ast_strlen_zero(p->peername) && ext)
- ast_string_field_set(p, peername, ext);
- /* Recalculate our side, and recalculate Call ID */
- if (ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip))
- p->ourip = __ourip;
- build_via(p);
- build_callid_pvt(p);
-
- /* We have an extension to call, don't use the full contact here */
- /* This to enable dialing registered peers with extension dialling,
- like SIP/peername/extension
- SIP/peername will still use the full contact */
- if (ext) {
- ast_string_field_set(p, username, ext);
- ast_string_field_free(p, fullcontact);
- }
-#if 0
- printf("Setting up to call extension '%s' at '%s'\n", ext ? ext : "<none>", host);
-#endif
- p->prefcodec = oldformat; /* Format for this call */
- ast_mutex_lock(&p->lock);
- tmpc = sip_new(p, AST_STATE_DOWN, host); /* Place the call */
- ast_mutex_unlock(&p->lock);
- if (!tmpc)
- sip_destroy(p);
- ast_update_use_count();
- restart_monitor();
- return tmpc;
-}
-
-/*!
- * \brief Parse the "insecure" setting from sip.conf or from realtime.
- * \param flags a pointer to an ast_flags structure
- * \param value the value of the SIP insecure setting
- * \param lineno linenumber in sip.conf or -1 for realtime
- */
-static void set_insecure_flags(struct ast_flags *flags, const char *value, int lineno)
-{
- static int dep_insecure_very = 0;
- static int dep_insecure_yes = 0;
-
- if (ast_strlen_zero(value))
- return;
-
- if (!strcasecmp(value, "very")) {
- ast_set_flag(flags, SIP_INSECURE_PORT | SIP_INSECURE_INVITE);
- if(!dep_insecure_very) {
- if(lineno != -1)
- ast_log(LOG_WARNING, "insecure=very at line %d is deprecated; use insecure=port,invite instead\n", lineno);
- else
- ast_log(LOG_WARNING, "insecure=very is deprecated; use insecure=port,invite instead\n");
- dep_insecure_very = 1;
- }
- }
- else if (ast_true(value)) {
- ast_set_flag(flags, SIP_INSECURE_PORT);
- if(!dep_insecure_yes) {
- if(lineno != -1)
- ast_log(LOG_WARNING, "insecure=%s at line %d is deprecated; use insecure=port instead\n", value, lineno);
- else
- ast_log(LOG_WARNING, "insecure=%s is deprecated; use insecure=port instead\n", value);
- dep_insecure_yes = 1;
- }
- }
- else if (!ast_false(value)) {
- char buf[64];
- char *word, *next;
- ast_copy_string(buf, value, sizeof(buf));
- next = buf;
- while ((word = strsep(&next, ","))) {
- if (!strcasecmp(word, "port"))
- ast_set_flag(flags, SIP_INSECURE_PORT);
- else if (!strcasecmp(word, "invite"))
- ast_set_flag(flags, SIP_INSECURE_INVITE);
- else
- ast_log(LOG_WARNING, "Unknown insecure mode '%s' on line %d\n", value, lineno);
- }
- }
-}
-
-/*!
- \brief Handle flag-type options common to configuration of devices - users and peers
- \param flags array of two struct ast_flags
- \param mask array of two struct ast_flags
- \param v linked list of config variables to process
- \returns non-zero if any config options were handled, zero otherwise
-*/
-static int handle_common_options(struct ast_flags *flags, struct ast_flags *mask, struct ast_variable *v)
-{
- int res = 1;
-
- if (!strcasecmp(v->name, "trustrpid")) {
- ast_set_flag(&mask[0], SIP_TRUSTRPID);
- ast_set2_flag(&flags[0], ast_true(v->value), SIP_TRUSTRPID);
- } else if (!strcasecmp(v->name, "sendrpid")) {
- ast_set_flag(&mask[0], SIP_SENDRPID);
- ast_set2_flag(&flags[0], ast_true(v->value), SIP_SENDRPID);
- } else if (!strcasecmp(v->name, "g726nonstandard")) {
- ast_set_flag(&mask[0], SIP_G726_NONSTANDARD);
- ast_set2_flag(&flags[0], ast_true(v->value), SIP_G726_NONSTANDARD);
- } else if (!strcasecmp(v->name, "useclientcode")) {
- ast_set_flag(&mask[0], SIP_USECLIENTCODE);
- ast_set2_flag(&flags[0], ast_true(v->value), SIP_USECLIENTCODE);
- } else if (!strcasecmp(v->name, "dtmfmode")) {
- ast_set_flag(&mask[0], SIP_DTMF);
- ast_clear_flag(&flags[0], SIP_DTMF);
- if (!strcasecmp(v->value, "inband"))
- ast_set_flag(&flags[0], SIP_DTMF_INBAND);
- else if (!strcasecmp(v->value, "rfc2833"))
- ast_set_flag(&flags[0], SIP_DTMF_RFC2833);
- else if (!strcasecmp(v->value, "info"))
- ast_set_flag(&flags[0], SIP_DTMF_INFO);
- else if (!strcasecmp(v->value, "auto"))
- ast_set_flag(&flags[0], SIP_DTMF_AUTO);
- else {
- ast_log(LOG_WARNING, "Unknown dtmf mode '%s' on line %d, using rfc2833\n", v->value, v->lineno);
- ast_set_flag(&flags[0], SIP_DTMF_RFC2833);
- }
- } else if (!strcasecmp(v->name, "nat")) {
- ast_set_flag(&mask[0], SIP_NAT);
- ast_clear_flag(&flags[0], SIP_NAT);
- if (!strcasecmp(v->value, "never"))
- ast_set_flag(&flags[0], SIP_NAT_NEVER);
- else if (!strcasecmp(v->value, "route"))
- ast_set_flag(&flags[0], SIP_NAT_ROUTE);
- else if (ast_true(v->value))
- ast_set_flag(&flags[0], SIP_NAT_ALWAYS);
- else
- ast_set_flag(&flags[0], SIP_NAT_RFC3581);
- } else if (!strcasecmp(v->name, "canreinvite")) {
- ast_set_flag(&mask[0], SIP_REINVITE);
- ast_clear_flag(&flags[0], SIP_REINVITE);
- if(ast_true(v->value)) {
- ast_set_flag(&flags[0], SIP_CAN_REINVITE | SIP_CAN_REINVITE_NAT);
- } else if (!ast_false(v->value)) {
- char buf[64];
- char *word, *next = buf;
-
- ast_copy_string(buf, v->value, sizeof(buf));
- while ((word = strsep(&next, ","))) {
- if(!strcasecmp(word, "update")) {
- ast_set_flag(&flags[0], SIP_REINVITE_UPDATE | SIP_CAN_REINVITE);
- } else if(!strcasecmp(word, "nonat")) {
- ast_set_flag(&flags[0], SIP_CAN_REINVITE);
- ast_clear_flag(&flags[0], SIP_CAN_REINVITE_NAT);
- } else {
- ast_log(LOG_WARNING, "Unknown canreinvite mode '%s' on line %d\n", v->value, v->lineno);
- }
- }
- }
- } else if (!strcasecmp(v->name, "insecure")) {
- ast_set_flag(&mask[0], SIP_INSECURE_PORT | SIP_INSECURE_INVITE);
- ast_clear_flag(&flags[0], SIP_INSECURE_PORT | SIP_INSECURE_INVITE);
- set_insecure_flags(flags, v->value, v->lineno);
- } else if (!strcasecmp(v->name, "progressinband")) {
- ast_set_flag(&mask[0], SIP_PROG_INBAND);
- ast_clear_flag(&flags[0], SIP_PROG_INBAND);
- if (ast_true(v->value))
- ast_set_flag(&flags[0], SIP_PROG_INBAND_YES);
- else if (strcasecmp(v->value, "never"))
- ast_set_flag(&flags[0], SIP_PROG_INBAND_NO);
- } else if (!strcasecmp(v->name, "promiscredir")) {
- ast_set_flag(&mask[0], SIP_PROMISCREDIR);
- ast_set2_flag(&flags[0], ast_true(v->value), SIP_PROMISCREDIR);
- } else if (!strcasecmp(v->name, "videosupport")) {
- ast_set_flag(&mask[1], SIP_PAGE2_VIDEOSUPPORT);
- ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_VIDEOSUPPORT);
- } else if (!strcasecmp(v->name, "allowoverlap")) {
- ast_set_flag(&mask[1], SIP_PAGE2_ALLOWOVERLAP);
- ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_ALLOWOVERLAP);
- } else if (!strcasecmp(v->name, "allowsubscribe")) {
- ast_set_flag(&mask[1], SIP_PAGE2_ALLOWSUBSCRIBE);
- ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_ALLOWSUBSCRIBE);
- } else if (!strcasecmp(v->name, "t38pt_udptl")) {
- ast_set_flag(&mask[1], SIP_PAGE2_T38SUPPORT_UDPTL);
- ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_T38SUPPORT_UDPTL);
-#ifdef WHEN_WE_HAVE_T38_FOR_OTHER_TRANSPORTS
- } else if (!strcasecmp(v->name, "t38pt_rtp")) {
- ast_set_flag(&mask[1], SIP_PAGE2_T38SUPPORT_RTP);
- ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_T38SUPPORT_RTP);
- } else if (!strcasecmp(v->name, "t38pt_tcp")) {
- ast_set_flag(&mask[1], SIP_PAGE2_T38SUPPORT_TCP);
- ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_T38SUPPORT_TCP);
-#endif
- } else if (!strcasecmp(v->name, "rfc2833compensate")) {
- ast_set_flag(&mask[1], SIP_PAGE2_RFC2833_COMPENSATE);
- ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_RFC2833_COMPENSATE);
- } else if (!strcasecmp(v->name, "buggymwi")) {
- ast_set_flag(&mask[1], SIP_PAGE2_BUGGY_MWI);
- ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_BUGGY_MWI);
- } else if (!strcasecmp(v->name, "t38pt_usertpsource")) {
- ast_set_flag(&mask[1], SIP_PAGE2_UDPTL_DESTINATION);
- ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_UDPTL_DESTINATION);
- } else
- res = 0;
-
- return res;
-}
-
-/*! \brief Add SIP domain to list of domains we are responsible for */
-static int add_sip_domain(const char *domain, const enum domain_mode mode, const char *context)
-{
- struct domain *d;
-
- if (ast_strlen_zero(domain)) {
- ast_log(LOG_WARNING, "Zero length domain.\n");
- return 1;
- }
-
- if (!(d = ast_calloc(1, sizeof(*d))))
- return 0;
-
- ast_copy_string(d->domain, domain, sizeof(d->domain));
-
- if (!ast_strlen_zero(context))
- ast_copy_string(d->context, context, sizeof(d->context));
-
- d->mode = mode;
-
- AST_LIST_LOCK(&domain_list);
- AST_LIST_INSERT_TAIL(&domain_list, d, list);
- AST_LIST_UNLOCK(&domain_list);
-
- if (sipdebug)
- ast_log(LOG_DEBUG, "Added local SIP domain '%s'\n", domain);
-
- return 1;
-}
-
-/*! \brief check_sip_domain: Check if domain part of uri is local to our server */
-static int check_sip_domain(const char *domain, char *context, size_t len)
-{
- struct domain *d;
- int result = 0;
-
- AST_LIST_LOCK(&domain_list);
- AST_LIST_TRAVERSE(&domain_list, d, list) {
- if (strcasecmp(d->domain, domain))
- continue;
-
- if (len && !ast_strlen_zero(d->context))
- ast_copy_string(context, d->context, len);
-
- result = 1;
- break;
- }
- AST_LIST_UNLOCK(&domain_list);
-
- return result;
-}
-
-/*! \brief Clear our domain list (at reload) */
-static void clear_sip_domains(void)
-{
- struct domain *d;
-
- AST_LIST_LOCK(&domain_list);
- while ((d = AST_LIST_REMOVE_HEAD(&domain_list, list)))
- free(d);
- AST_LIST_UNLOCK(&domain_list);
-}
-
-
-/*! \brief Add realm authentication in list */
-static struct sip_auth *add_realm_authentication(struct sip_auth *authlist, char *configuration, int lineno)
-{
- char authcopy[256];
- char *username=NULL, *realm=NULL, *secret=NULL, *md5secret=NULL;
- char *stringp;
- struct sip_auth *a, *b, *auth;
-
- if (ast_strlen_zero(configuration))
- return authlist;
-
- if (option_debug)
- ast_log(LOG_DEBUG, "Auth config :: %s\n", configuration);
-
- ast_copy_string(authcopy, configuration, sizeof(authcopy));
- stringp = authcopy;
-
- username = stringp;
- realm = strrchr(stringp, '@');
- if (realm)
- *realm++ = '\0';
- if (ast_strlen_zero(username) || ast_strlen_zero(realm)) {
- ast_log(LOG_WARNING, "Format for authentication entry is user[:secret]@realm at line %d\n", lineno);
- return authlist;
- }
- stringp = username;
- username = strsep(&stringp, ":");
- if (username) {
- secret = strsep(&stringp, ":");
- if (!secret) {
- stringp = username;
- md5secret = strsep(&stringp,"#");
- }
- }
- if (!(auth = ast_calloc(1, sizeof(*auth))))
- return authlist;
-
- ast_copy_string(auth->realm, realm, sizeof(auth->realm));
- ast_copy_string(auth->username, username, sizeof(auth->username));
- if (secret)
- ast_copy_string(auth->secret, secret, sizeof(auth->secret));
- if (md5secret)
- ast_copy_string(auth->md5secret, md5secret, sizeof(auth->md5secret));
-
- /* find the end of the list */
- for (b = NULL, a = authlist; a ; b = a, a = a->next)
- ;
- if (b)
- b->next = auth; /* Add structure add end of list */
- else
- authlist = auth;
-
- if (option_verbose > 2)
- ast_verbose("Added authentication for realm %s\n", realm);
-
- return authlist;
-
-}
-
-/*! \brief Clear realm authentication list (at reload) */
-static int clear_realm_authentication(struct sip_auth *authlist)
-{
- struct sip_auth *a = authlist;
- struct sip_auth *b;
-
- while (a) {
- b = a;
- a = a->next;
- free(b);
- }
-
- return 1;
-}
-
-/*! \brief Find authentication for a specific realm */
-static struct sip_auth *find_realm_authentication(struct sip_auth *authlist, const char *realm)
-{
- struct sip_auth *a;
-
- for (a = authlist; a; a = a->next) {
- if (!strcasecmp(a->realm, realm))
- break;
- }
-
- return a;
-}
-
-/*! \brief Initiate a SIP user structure from configuration (configuration or realtime) */
-static struct sip_user *build_user(const char *name, struct ast_variable *v, struct ast_variable *alt, int realtime)
-{
- struct sip_user *user;
- int format;
- struct ast_ha *oldha = NULL;
- char *varname = NULL, *varval = NULL;
- struct ast_variable *tmpvar = NULL;
- struct ast_flags userflags[2] = {{(0)}};
- struct ast_flags mask[2] = {{(0)}};
-
-
- if (!(user = ast_calloc(1, sizeof(*user))))
- return NULL;
-
- suserobjs++;
- ASTOBJ_INIT(user);
- ast_copy_string(user->name, name, sizeof(user->name));
- oldha = user->ha;
- user->ha = NULL;
- ast_copy_flags(&user->flags[0], &global_flags[0], SIP_FLAGS_TO_COPY);
- ast_copy_flags(&user->flags[1], &global_flags[1], SIP_PAGE2_FLAGS_TO_COPY);
- user->capability = global_capability;
- user->allowtransfer = global_allowtransfer;
- user->maxcallbitrate = default_maxcallbitrate;
- user->autoframing = global_autoframing;
- user->prefs = default_prefs;
- /* set default context */
- strcpy(user->context, default_context);
- strcpy(user->language, default_language);
- strcpy(user->mohinterpret, default_mohinterpret);
- strcpy(user->mohsuggest, default_mohsuggest);
- /* First we walk through the v parameters list and then the alt parameters list */
- for (; v || ((v = alt) && !(alt=NULL)); v = v->next) {
- if (handle_common_options(&userflags[0], &mask[0], v))
- continue;
-
- if (!strcasecmp(v->name, "context")) {
- ast_copy_string(user->context, v->value, sizeof(user->context));
- } else if (!strcasecmp(v->name, "subscribecontext")) {
- ast_copy_string(user->subscribecontext, v->value, sizeof(user->subscribecontext));
- } else if (!strcasecmp(v->name, "setvar")) {
- varname = ast_strdupa(v->value);
- if ((varval = strchr(varname,'='))) {
- *varval++ = '\0';
- if ((tmpvar = ast_variable_new(varname, varval))) {
- tmpvar->next = user->chanvars;
- user->chanvars = tmpvar;
- }
- }
- } else if (!strcasecmp(v->name, "permit") ||
- !strcasecmp(v->name, "deny")) {
- user->ha = ast_append_ha(v->name, v->value, user->ha);
- } else if (!strcasecmp(v->name, "allowtransfer")) {
- user->allowtransfer = ast_true(v->value) ? TRANSFER_OPENFORALL : TRANSFER_CLOSED;
- } else if (!strcasecmp(v->name, "secret")) {
- ast_copy_string(user->secret, v->value, sizeof(user->secret));
- } else if (!strcasecmp(v->name, "md5secret")) {
- ast_copy_string(user->md5secret, v->value, sizeof(user->md5secret));
- } else if (!strcasecmp(v->name, "callerid")) {
- ast_callerid_split(v->value, user->cid_name, sizeof(user->cid_name), user->cid_num, sizeof(user->cid_num));
- } else if (!strcasecmp(v->name, "fullname")) {
- ast_copy_string(user->cid_name, v->value, sizeof(user->cid_name));
- } else if (!strcasecmp(v->name, "cid_number")) {
- ast_copy_string(user->cid_num, v->value, sizeof(user->cid_num));
- } else if (!strcasecmp(v->name, "callgroup")) {
- user->callgroup = ast_get_group(v->value);
- } else if (!strcasecmp(v->name, "pickupgroup")) {
- user->pickupgroup = ast_get_group(v->value);
- } else if (!strcasecmp(v->name, "language")) {
- ast_copy_string(user->language, v->value, sizeof(user->language));
- } else if (!strcasecmp(v->name, "mohinterpret")
- || !strcasecmp(v->name, "musicclass") || !strcasecmp(v->name, "musiconhold")) {
- ast_copy_string(user->mohinterpret, v->value, sizeof(user->mohinterpret));
- } else if (!strcasecmp(v->name, "mohsuggest")) {
- ast_copy_string(user->mohsuggest, v->value, sizeof(user->mohsuggest));
- } else if (!strcasecmp(v->name, "accountcode")) {
- ast_copy_string(user->accountcode, v->value, sizeof(user->accountcode));
- } else if (!strcasecmp(v->name, "call-limit")) {
- user->call_limit = atoi(v->value);
- if (user->call_limit < 0)
- user->call_limit = 0;
- } else if (!strcasecmp(v->name, "amaflags")) {
- format = ast_cdr_amaflags2int(v->value);
- if (format < 0) {
- ast_log(LOG_WARNING, "Invalid AMA Flags: %s at line %d\n", v->value, v->lineno);
- } else {
- user->amaflags = format;
- }
- } else if (!strcasecmp(v->name, "allow")) {
- ast_parse_allow_disallow(&user->prefs, &user->capability, v->value, 1);
- } else if (!strcasecmp(v->name, "disallow")) {
- ast_parse_allow_disallow(&user->prefs, &user->capability, v->value, 0);
- } else if (!strcasecmp(v->name, "autoframing")) {
- user->autoframing = ast_true(v->value);
- } else if (!strcasecmp(v->name, "callingpres")) {
- user->callingpres = ast_parse_caller_presentation(v->value);
- if (user->callingpres == -1)
- user->callingpres = atoi(v->value);
- } else if (!strcasecmp(v->name, "maxcallbitrate")) {
- user->maxcallbitrate = atoi(v->value);
- if (user->maxcallbitrate < 0)
- user->maxcallbitrate = default_maxcallbitrate;
- }
- /* We can't just report unknown options here because this may be a
- * type=friend entry. All user options are valid for a peer, but not
- * the other way around. */
- }
- ast_copy_flags(&user->flags[0], &userflags[0], mask[0].flags);
- ast_copy_flags(&user->flags[1], &userflags[1], mask[1].flags);
- if (ast_test_flag(&user->flags[1], SIP_PAGE2_ALLOWSUBSCRIBE))
- global_allowsubscribe = TRUE; /* No global ban any more */
- ast_free_ha(oldha);
- return user;
-}
-
-/*! \brief Set peer defaults before configuring specific configurations */
-static void set_peer_defaults(struct sip_peer *peer)
-{
- if (peer->expire == 0) {
- /* Don't reset expire or port time during reload
- if we have an active registration
- */
- peer->expire = -1;
- peer->pokeexpire = -1;
- peer->addr.sin_port = htons(STANDARD_SIP_PORT);
- }
- 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);
- strcpy(peer->context, default_context);
- strcpy(peer->subscribecontext, default_subscribecontext);
- strcpy(peer->language, default_language);
- strcpy(peer->mohinterpret, default_mohinterpret);
- strcpy(peer->mohsuggest, default_mohsuggest);
- peer->addr.sin_family = AF_INET;
- peer->defaddr.sin_family = AF_INET;
- peer->capability = global_capability;
- peer->maxcallbitrate = default_maxcallbitrate;
- peer->rtptimeout = global_rtptimeout;
- peer->rtpholdtimeout = global_rtpholdtimeout;
- peer->rtpkeepalive = global_rtpkeepalive;
- peer->allowtransfer = global_allowtransfer;
- peer->autoframing = global_autoframing;
- strcpy(peer->vmexten, default_vmexten);
- peer->secret[0] = '\0';
- peer->md5secret[0] = '\0';
- peer->cid_num[0] = '\0';
- peer->cid_name[0] = '\0';
- peer->fromdomain[0] = '\0';
- peer->fromuser[0] = '\0';
- peer->regexten[0] = '\0';
- peer->mailbox[0] = '\0';
- peer->callgroup = 0;
- peer->pickupgroup = 0;
- peer->maxms = default_qualify;
- peer->prefs = default_prefs;
-}
-
-/*! \brief Create temporary peer (used in autocreatepeer mode) */
-static struct sip_peer *temp_peer(const char *name)
-{
- struct sip_peer *peer;
-
- if (!(peer = ast_calloc(1, sizeof(*peer))))
- return NULL;
-
- apeerobjs++;
- ASTOBJ_INIT(peer);
- set_peer_defaults(peer);
-
- ast_copy_string(peer->name, name, sizeof(peer->name));
-
- ast_set_flag(&peer->flags[1], SIP_PAGE2_SELFDESTRUCT);
- ast_set_flag(&peer->flags[1], SIP_PAGE2_DYNAMIC);
- peer->prefs = default_prefs;
- reg_source_db(peer);
-
- return peer;
-}
-
-/*! \brief Build peer from configuration (file or realtime static/dynamic) */
-static struct sip_peer *build_peer(const char *name, struct ast_variable *v, struct ast_variable *alt, int realtime)
-{
- struct sip_peer *peer = NULL;
- struct ast_ha *oldha = NULL;
- int obproxyfound=0;
- int found=0;
- int firstpass=1;
- int format=0; /* Ama flags */
- time_t regseconds = 0;
- char *varname = NULL, *varval = NULL;
- struct ast_variable *tmpvar = NULL;
- struct ast_flags peerflags[2] = {{(0)}};
- struct ast_flags mask[2] = {{(0)}};
- char fullcontact[sizeof(peer->fullcontact)] = "";
-
- if (!realtime || ast_test_flag(&global_flags[1], SIP_PAGE2_RTCACHEFRIENDS))
- /* Note we do NOT use find_peer here, to avoid realtime recursion */
- /* We also use a case-sensitive comparison (unlike find_peer) so
- that case changes made to the peer name will be properly handled
- during reload
- */
- peer = ASTOBJ_CONTAINER_FIND_UNLINK_FULL(&peerl, name, name, 0, 0, strcmp);
-
- if (peer) {
- /* Already in the list, remove it and it will be added back (or FREE'd) */
- found = 1;
- if (!(peer->objflags & ASTOBJ_FLAG_MARKED))
- firstpass = 0;
- } else {
- if (!(peer = ast_calloc(1, sizeof(*peer))))
- return NULL;
-
- if (realtime && !ast_test_flag(&global_flags[1], SIP_PAGE2_RTCACHEFRIENDS))
- rpeerobjs++;
- else
- speerobjs++;
- ASTOBJ_INIT(peer);
- }
- /* Note that our peer HAS had its reference count incrased */
- if (firstpass) {
- peer->lastmsgssent = -1;
- oldha = peer->ha;
- peer->ha = NULL;
- set_peer_defaults(peer); /* Set peer defaults */
- }
- if (!found && name)
- ast_copy_string(peer->name, name, sizeof(peer->name));
-
- /* If we have channel variables, remove them (reload) */
- if (peer->chanvars) {
- ast_variables_destroy(peer->chanvars);
- peer->chanvars = NULL;
- /* XXX should unregister ? */
- }
-
- /* If we have realm authentication information, remove them (reload) */
- clear_realm_authentication(peer->auth);
- peer->auth = NULL;
-
- for (; v || ((v = alt) && !(alt=NULL)); v = v->next) {
- if (handle_common_options(&peerflags[0], &mask[0], v))
- continue;
- if (realtime && !strcasecmp(v->name, "regseconds")) {
- ast_get_time_t(v->value, &regseconds, 0, NULL);
- } else if (realtime && !strcasecmp(v->name, "ipaddr") && !ast_strlen_zero(v->value) ) {
- inet_aton(v->value, &(peer->addr.sin_addr));
- } else if (realtime && !strcasecmp(v->name, "name"))
- ast_copy_string(peer->name, v->value, sizeof(peer->name));
- else if (realtime && !strcasecmp(v->name, "fullcontact")) {
- /* Reconstruct field, because realtime separates our value at the ';' */
- if (!ast_strlen_zero(fullcontact)) {
- strncat(fullcontact, ";", sizeof(fullcontact) - strlen(fullcontact) - 1);
- strncat(fullcontact, v->value, sizeof(fullcontact) - strlen(fullcontact) - 1);
- } else {
- ast_copy_string(fullcontact, v->value, sizeof(fullcontact));
- ast_set_flag(&peer->flags[1], SIP_PAGE2_RT_FROMCONTACT);
- }
- } else if (!strcasecmp(v->name, "secret"))
- ast_copy_string(peer->secret, v->value, sizeof(peer->secret));
- else if (!strcasecmp(v->name, "md5secret"))
- ast_copy_string(peer->md5secret, v->value, sizeof(peer->md5secret));
- else if (!strcasecmp(v->name, "auth"))
- peer->auth = add_realm_authentication(peer->auth, v->value, v->lineno);
- else if (!strcasecmp(v->name, "callerid")) {
- ast_callerid_split(v->value, peer->cid_name, sizeof(peer->cid_name), peer->cid_num, sizeof(peer->cid_num));
- } else if (!strcasecmp(v->name, "fullname")) {
- ast_copy_string(peer->cid_name, v->value, sizeof(peer->cid_name));
- } else if (!strcasecmp(v->name, "cid_number")) {
- ast_copy_string(peer->cid_num, v->value, sizeof(peer->cid_num));
- } else if (!strcasecmp(v->name, "context")) {
- ast_copy_string(peer->context, v->value, sizeof(peer->context));
- } else if (!strcasecmp(v->name, "subscribecontext")) {
- ast_copy_string(peer->subscribecontext, v->value, sizeof(peer->subscribecontext));
- } else if (!strcasecmp(v->name, "fromdomain")) {
- ast_copy_string(peer->fromdomain, v->value, sizeof(peer->fromdomain));
- } else if (!strcasecmp(v->name, "usereqphone")) {
- ast_set2_flag(&peer->flags[0], ast_true(v->value), SIP_USEREQPHONE);
- } else if (!strcasecmp(v->name, "fromuser")) {
- ast_copy_string(peer->fromuser, v->value, sizeof(peer->fromuser));
- } else if (!strcasecmp(v->name, "host") || !strcasecmp(v->name, "outboundproxy")) {
- if (!strcasecmp(v->value, "dynamic")) {
- if (!strcasecmp(v->name, "outboundproxy") || obproxyfound) {
- ast_log(LOG_WARNING, "You can't have a dynamic outbound proxy, you big silly head at line %d.\n", v->lineno);
- } else {
- /* They'll register with us */
- if (!found || !ast_test_flag(&peer->flags[1], SIP_PAGE2_DYNAMIC)) {
- /* Initialize stuff if this is a new peer, or if it used to be
- * non-dynamic before the reload. */
- memset(&peer->addr.sin_addr, 0, 4);
- if (peer->addr.sin_port) {
- /* If we've already got a port, make it the default rather than absolute */
- peer->defaddr.sin_port = peer->addr.sin_port;
- peer->addr.sin_port = 0;
- }
- }
- ast_set_flag(&peer->flags[1], SIP_PAGE2_DYNAMIC);
- }
- } else {
- /* Non-dynamic. Make sure we become that way if we're not */
- if (!AST_SCHED_DEL(sched, peer->expire)) {
- struct sip_peer *peer_ptr = peer;
- ASTOBJ_UNREF(peer_ptr, sip_destroy_peer);
- }
- ast_clear_flag(&peer->flags[1], SIP_PAGE2_DYNAMIC);
- if (!obproxyfound || !strcasecmp(v->name, "outboundproxy")) {
- if (ast_get_ip_or_srv(&peer->addr, v->value, srvlookup ? "_sip._udp" : NULL)) {
- ASTOBJ_UNREF(peer, sip_destroy_peer);
- return NULL;
- }
- }
- if (!strcasecmp(v->name, "outboundproxy"))
- obproxyfound=1;
- else {
- ast_copy_string(peer->tohost, v->value, sizeof(peer->tohost));
- if (!peer->addr.sin_port)
- peer->addr.sin_port = htons(STANDARD_SIP_PORT);
- }
- if (global_dynamic_exclude_static) {
- global_contact_ha = ast_append_ha("deny", (char *)ast_inet_ntoa(peer->addr.sin_addr), global_contact_ha);
- }
- }
- } else if (!strcasecmp(v->name, "defaultip")) {
- if (ast_get_ip(&peer->defaddr, v->value)) {
- ASTOBJ_UNREF(peer, sip_destroy_peer);
- return NULL;
- }
- } else if (!strcasecmp(v->name, "permit") || !strcasecmp(v->name, "deny")) {
- peer->ha = ast_append_ha(v->name, v->value, peer->ha);
- } else if (!strcasecmp(v->name, "contactpermit") || !strcasecmp(v->name, "contactdeny")) {
- peer->contactha = ast_append_ha(v->name + 7, v->value, peer->contactha);
- } else if (!strcasecmp(v->name, "port")) {
- if (!realtime && ast_test_flag(&peer->flags[1], SIP_PAGE2_DYNAMIC))
- peer->defaddr.sin_port = htons(atoi(v->value));
- else
- peer->addr.sin_port = htons(atoi(v->value));
- } else if (!strcasecmp(v->name, "callingpres")) {
- peer->callingpres = ast_parse_caller_presentation(v->value);
- if (peer->callingpres == -1)
- peer->callingpres = atoi(v->value);
- } else if (!strcasecmp(v->name, "username")) {
- ast_copy_string(peer->username, v->value, sizeof(peer->username));
- } else if (!strcasecmp(v->name, "language")) {
- ast_copy_string(peer->language, v->value, sizeof(peer->language));
- } else if (!strcasecmp(v->name, "regexten")) {
- ast_copy_string(peer->regexten, v->value, sizeof(peer->regexten));
- } else if (!strcasecmp(v->name, "call-limit") || !strcasecmp(v->name, "incominglimit")) {
- peer->call_limit = atoi(v->value);
- if (peer->call_limit < 0)
- peer->call_limit = 0;
- } else if (!strcasecmp(v->name, "amaflags")) {
- format = ast_cdr_amaflags2int(v->value);
- if (format < 0) {
- ast_log(LOG_WARNING, "Invalid AMA Flags for peer: %s at line %d\n", v->value, v->lineno);
- } else {
- peer->amaflags = format;
- }
- } else if (!strcasecmp(v->name, "accountcode")) {
- ast_copy_string(peer->accountcode, v->value, sizeof(peer->accountcode));
- } else if (!strcasecmp(v->name, "mohinterpret")
- || !strcasecmp(v->name, "musicclass") || !strcasecmp(v->name, "musiconhold")) {
- ast_copy_string(peer->mohinterpret, v->value, sizeof(peer->mohinterpret));
- } else if (!strcasecmp(v->name, "mohsuggest")) {
- ast_copy_string(peer->mohsuggest, v->value, sizeof(peer->mohsuggest));
- } else if (!strcasecmp(v->name, "mailbox")) {
- ast_copy_string(peer->mailbox, v->value, sizeof(peer->mailbox));
- } else if (!strcasecmp(v->name, "hasvoicemail")) {
- /* People expect that if 'hasvoicemail' is set, that the mailbox will
- * be also set, even if not explicitly specified. */
- if (ast_true(v->value) && ast_strlen_zero(peer->mailbox)) {
- ast_copy_string(peer->mailbox, name, sizeof(peer->mailbox));
- }
- } else if (!strcasecmp(v->name, "subscribemwi")) {
- ast_set2_flag(&peer->flags[1], ast_true(v->value), SIP_PAGE2_SUBSCRIBEMWIONLY);
- } else if (!strcasecmp(v->name, "vmexten")) {
- ast_copy_string(peer->vmexten, v->value, sizeof(peer->vmexten));
- } else if (!strcasecmp(v->name, "callgroup")) {
- peer->callgroup = ast_get_group(v->value);
- } else if (!strcasecmp(v->name, "allowtransfer")) {
- peer->allowtransfer = ast_true(v->value) ? TRANSFER_OPENFORALL : TRANSFER_CLOSED;
- } else if (!strcasecmp(v->name, "pickupgroup")) {
- peer->pickupgroup = ast_get_group(v->value);
- } else if (!strcasecmp(v->name, "allow")) {
- ast_parse_allow_disallow(&peer->prefs, &peer->capability, v->value, 1);
- } else if (!strcasecmp(v->name, "disallow")) {
- ast_parse_allow_disallow(&peer->prefs, &peer->capability, v->value, 0);
- } else if (!strcasecmp(v->name, "autoframing")) {
- peer->autoframing = ast_true(v->value);
- } else if (!strcasecmp(v->name, "rtptimeout")) {
- if ((sscanf(v->value, "%d", &peer->rtptimeout) != 1) || (peer->rtptimeout < 0)) {
- ast_log(LOG_WARNING, "'%s' is not a valid RTP hold time at line %d. Using default.\n", v->value, v->lineno);
- peer->rtptimeout = global_rtptimeout;
- }
- } else if (!strcasecmp(v->name, "rtpholdtimeout")) {
- if ((sscanf(v->value, "%d", &peer->rtpholdtimeout) != 1) || (peer->rtpholdtimeout < 0)) {
- ast_log(LOG_WARNING, "'%s' is not a valid RTP hold time at line %d. Using default.\n", v->value, v->lineno);
- peer->rtpholdtimeout = global_rtpholdtimeout;
- }
- } else if (!strcasecmp(v->name, "rtpkeepalive")) {
- if ((sscanf(v->value, "%d", &peer->rtpkeepalive) != 1) || (peer->rtpkeepalive < 0)) {
- ast_log(LOG_WARNING, "'%s' is not a valid RTP keepalive time at line %d. Using default.\n", v->value, v->lineno);
- peer->rtpkeepalive = global_rtpkeepalive;
- }
- } else if (!strcasecmp(v->name, "setvar")) {
- /* Set peer channel variable */
- varname = ast_strdupa(v->value);
- if ((varval = strchr(varname, '='))) {
- *varval++ = '\0';
- if ((tmpvar = ast_variable_new(varname, varval))) {
- tmpvar->next = peer->chanvars;
- peer->chanvars = tmpvar;
- }
- }
- } else if (!strcasecmp(v->name, "qualify")) {
- if (!strcasecmp(v->value, "no")) {
- peer->maxms = 0;
- } else if (!strcasecmp(v->value, "yes")) {
- peer->maxms = default_qualify ? default_qualify : DEFAULT_MAXMS;
- } else if (sscanf(v->value, "%d", &peer->maxms) != 1) {
- ast_log(LOG_WARNING, "Qualification of peer '%s' should be 'yes', 'no', or a number of milliseconds at line %d of sip.conf\n", peer->name, v->lineno);
- peer->maxms = 0;
- }
- if (realtime && !ast_test_flag(&global_flags[1], SIP_PAGE2_RTCACHEFRIENDS) && peer->maxms > 0) {
- /* This would otherwise cause a network storm, where the
- * qualify response refreshes the peer from the database,
- * which in turn causes another qualify to be sent, ad
- * infinitum. */
- ast_log(LOG_WARNING, "Qualify is incompatible with dynamic uncached realtime. Please either turn rtcachefriends on or turn qualify off on peer '%s'\n", peer->name);
- peer->maxms = 0;
- }
- } else if (!strcasecmp(v->name, "maxcallbitrate")) {
- peer->maxcallbitrate = atoi(v->value);
- if (peer->maxcallbitrate < 0)
- peer->maxcallbitrate = default_maxcallbitrate;
- }
- }
- if (!ast_strlen_zero(fullcontact)) {
- ast_copy_string(peer->fullcontact, fullcontact, sizeof(peer->fullcontact));
- /* We have a hostname in the fullcontact, but if we don't have an
- * address listed on the entry (or if it's 'dynamic'), then we need to
- * parse the entry to obtain the IP address, so a dynamic host can be
- * contacted immediately after reload (as opposed to waiting for it to
- * register once again). */
- __set_address_from_contact(fullcontact, &peer->addr);
- }
-
- if (!ast_test_flag(&global_flags[1], SIP_PAGE2_IGNOREREGEXPIRE) && ast_test_flag(&peer->flags[1], SIP_PAGE2_DYNAMIC) && realtime) {
- time_t nowtime = time(NULL);
-
- if ((nowtime - regseconds) > 0) {
- destroy_association(peer);
- memset(&peer->addr, 0, sizeof(peer->addr));
- if (option_debug)
- ast_log(LOG_DEBUG, "Bah, we're expired (%d/%d/%d)!\n", (int)(nowtime - regseconds), (int)regseconds, (int)nowtime);
- }
- }
- ast_copy_flags(&peer->flags[0], &peerflags[0], mask[0].flags);
- ast_copy_flags(&peer->flags[1], &peerflags[1], mask[1].flags);
- if (ast_test_flag(&peer->flags[1], SIP_PAGE2_ALLOWSUBSCRIBE))
- global_allowsubscribe = TRUE; /* No global ban any more */
- if (!found && ast_test_flag(&peer->flags[1], SIP_PAGE2_DYNAMIC) && !ast_test_flag(&peer->flags[0], SIP_REALTIME))
- reg_source_db(peer);
- ASTOBJ_UNMARK(peer);
- ast_free_ha(oldha);
- return peer;
-}
-
-/*! \brief Re-read SIP.conf config file
-\note This function reloads all config data, except for
- active peers (with registrations). They will only
- change configuration data at restart, not at reload.
- SIP debug and recordhistory state will not change
- */
-static int reload_config(enum channelreloadreason reason)
-{
- struct ast_config *cfg, *ucfg;
- struct ast_variable *v;
- struct sip_peer *peer;
- struct sip_user *user;
- struct ast_hostent ahp;
- char *cat, *stringp, *context, *oldregcontext;
- char newcontexts[AST_MAX_CONTEXT], oldcontexts[AST_MAX_CONTEXT];
- struct hostent *hp;
- int format;
- struct ast_flags dummy[2];
- int auto_sip_domains = FALSE;
- struct sockaddr_in old_bindaddr = bindaddr;
- int registry_count = 0, peer_count = 0, user_count = 0;
- unsigned int temp_tos = 0;
- struct ast_flags debugflag = {0};
-
- cfg = ast_config_load(config);
-
- /* We *must* have a config file otherwise stop immediately */
- if (!cfg) {
- ast_log(LOG_NOTICE, "Unable to load config %s\n", config);
- return -1;
- }
-
- if (option_debug > 3)
- ast_log(LOG_DEBUG, "--------------- SIP reload started\n");
-
- clear_realm_authentication(authl);
- clear_sip_domains();
- authl = NULL;
-
- ast_free_ha(global_contact_ha);
- global_contact_ha = NULL;
-
- /* First, destroy all outstanding registry calls */
- /* This is needed, since otherwise active registry entries will not be destroyed */
- ASTOBJ_CONTAINER_TRAVERSE(&regl, 1, do {
- ASTOBJ_RDLOCK(iterator);
- if (iterator->call) {
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Destroying active SIP dialog for registry %s@%s\n", iterator->username, iterator->hostname);
- /* This will also remove references to the registry */
- sip_destroy(iterator->call);
- }
- ASTOBJ_UNLOCK(iterator);
-
- } while(0));
-
- /* Then, actually destroy users and registry */
- ASTOBJ_CONTAINER_DESTROYALL(&userl, sip_destroy_user);
- if (option_debug > 3)
- ast_log(LOG_DEBUG, "--------------- Done destroying user list\n");
- ASTOBJ_CONTAINER_DESTROYALL(&regl, sip_registry_destroy);
- if (option_debug > 3)
- ast_log(LOG_DEBUG, "--------------- Done destroying registry list\n");
- ASTOBJ_CONTAINER_MARKALL(&peerl);
-
- /* Initialize copy of current global_regcontext for later use in removing stale contexts */
- ast_copy_string(oldcontexts, global_regcontext, sizeof(oldcontexts));
- oldregcontext = oldcontexts;
-
- /* Clear all flags before setting default values */
- /* Preserve debugging settings for console */
- ast_copy_flags(&debugflag, &global_flags[1], SIP_PAGE2_DEBUG_CONSOLE);
- ast_clear_flag(&global_flags[0], AST_FLAGS_ALL);
- ast_clear_flag(&global_flags[1], AST_FLAGS_ALL);
- ast_copy_flags(&global_flags[1], &debugflag, SIP_PAGE2_DEBUG_CONSOLE);
-
- /* Reset IP addresses */
- memset(&bindaddr, 0, sizeof(bindaddr));
- ast_free_ha(localaddr);
- memset(&localaddr, 0, sizeof(localaddr));
- memset(&externip, 0, sizeof(externip));
- memset(&default_prefs, 0 , sizeof(default_prefs));
- outboundproxyip.sin_port = htons(STANDARD_SIP_PORT);
- outboundproxyip.sin_family = AF_INET; /* Type of address: IPv4 */
- ourport = STANDARD_SIP_PORT;
- srvlookup = DEFAULT_SRVLOOKUP;
- global_tos_sip = DEFAULT_TOS_SIP;
- global_tos_audio = DEFAULT_TOS_AUDIO;
- global_tos_video = DEFAULT_TOS_VIDEO;
- externhost[0] = '\0'; /* External host name (for behind NAT DynDNS support) */
- externexpire = 0; /* Expiration for DNS re-issuing */
- externrefresh = 10;
- memset(&outboundproxyip, 0, sizeof(outboundproxyip));
-
- /* Reset channel settings to default before re-configuring */
- allow_external_domains = DEFAULT_ALLOW_EXT_DOM; /* Allow external invites */
- global_regcontext[0] = '\0';
- expiry = DEFAULT_EXPIRY;
- global_notifyringing = DEFAULT_NOTIFYRINGING;
- global_limitonpeers = FALSE;
- global_directrtpsetup = FALSE; /* Experimental feature, disabled by default */
- global_notifyhold = FALSE;
- global_alwaysauthreject = 0;
- global_allowsubscribe = FALSE;
- ast_copy_string(global_useragent, DEFAULT_USERAGENT, sizeof(global_useragent));
- ast_copy_string(default_notifymime, DEFAULT_NOTIFYMIME, sizeof(default_notifymime));
- if (ast_strlen_zero(ast_config_AST_SYSTEM_NAME))
- ast_copy_string(global_realm, DEFAULT_REALM, sizeof(global_realm));
- else
- ast_copy_string(global_realm, ast_config_AST_SYSTEM_NAME, sizeof(global_realm));
- ast_copy_string(default_callerid, DEFAULT_CALLERID, sizeof(default_callerid));
- compactheaders = DEFAULT_COMPACTHEADERS;
- global_reg_timeout = DEFAULT_REGISTRATION_TIMEOUT;
- global_regattempts_max = 0;
- pedanticsipchecking = DEFAULT_PEDANTIC;
- global_mwitime = DEFAULT_MWITIME;
- autocreatepeer = DEFAULT_AUTOCREATEPEER;
- global_autoframing = 0;
- global_allowguest = DEFAULT_ALLOWGUEST;
- global_rtptimeout = 0;
- global_rtpholdtimeout = 0;
- global_rtpkeepalive = 0;
- global_allowtransfer = TRANSFER_OPENFORALL; /* Merrily accept all transfers by default */
- global_rtautoclear = 120;
- ast_set_flag(&global_flags[1], SIP_PAGE2_ALLOWSUBSCRIBE); /* Default for peers, users: TRUE */
- ast_set_flag(&global_flags[1], SIP_PAGE2_ALLOWOVERLAP); /* Default for peers, users: TRUE */
- ast_set_flag(&global_flags[1], SIP_PAGE2_RTUPDATE);
-
- /* Initialize some reasonable defaults at SIP reload (used both for channel and as default for peers and users */
- ast_copy_string(default_context, DEFAULT_CONTEXT, sizeof(default_context));
- default_subscribecontext[0] = '\0';
- default_language[0] = '\0';
- default_fromdomain[0] = '\0';
- default_qualify = DEFAULT_QUALIFY;
- default_maxcallbitrate = DEFAULT_MAX_CALL_BITRATE;
- ast_copy_string(default_mohinterpret, DEFAULT_MOHINTERPRET, sizeof(default_mohinterpret));
- ast_copy_string(default_mohsuggest, DEFAULT_MOHSUGGEST, sizeof(default_mohsuggest));
- ast_copy_string(default_vmexten, DEFAULT_VMEXTEN, sizeof(default_vmexten));
- ast_set_flag(&global_flags[0], SIP_DTMF_RFC2833); /*!< Default DTMF setting: RFC2833 */
- ast_set_flag(&global_flags[0], SIP_NAT_RFC3581); /*!< NAT support if requested by device with rport */
- ast_set_flag(&global_flags[0], SIP_CAN_REINVITE); /*!< Allow re-invites */
-
- /* Debugging settings, always default to off */
- dumphistory = FALSE;
- recordhistory = FALSE;
- ast_clear_flag(&global_flags[1], SIP_PAGE2_DEBUG_CONFIG);
-
- /* Misc settings for the channel */
- global_relaxdtmf = FALSE;
- global_callevents = FALSE;
- global_t1min = DEFAULT_T1MIN;
-
- global_matchexterniplocally = FALSE;
-
- /* Copy the default jb config over global_jbconf */
- memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
-
- ast_clear_flag(&global_flags[1], SIP_PAGE2_VIDEOSUPPORT);
-
- /* Read the [general] config section of sip.conf (or from realtime config) */
- for (v = ast_variable_browse(cfg, "general"); v; v = v->next) {
- if (handle_common_options(&global_flags[0], &dummy[0], v))
- continue;
- /* handle jb conf */
- if (!ast_jb_read_conf(&global_jbconf, v->name, v->value))
- continue;
-
- /* Create the interface list */
- if (!strcasecmp(v->name, "context")) {
- ast_copy_string(default_context, v->value, sizeof(default_context));
- } else if (!strcasecmp(v->name, "subscribecontext")) {
- ast_copy_string(default_subscribecontext, v->value, sizeof(default_subscribecontext));
- } else if (!strcasecmp(v->name, "allowguest")) {
- global_allowguest = ast_true(v->value) ? 1 : 0;
- } else if (!strcasecmp(v->name, "realm")) {
- ast_copy_string(global_realm, v->value, sizeof(global_realm));
- } else if (!strcasecmp(v->name, "useragent")) {
- ast_copy_string(global_useragent, v->value, sizeof(global_useragent));
- if (option_debug)
- ast_log(LOG_DEBUG, "Setting SIP channel User-Agent Name to %s\n", global_useragent);
- } else if (!strcasecmp(v->name, "allowtransfer")) {
- global_allowtransfer = ast_true(v->value) ? TRANSFER_OPENFORALL : TRANSFER_CLOSED;
- } else if (!strcasecmp(v->name, "rtcachefriends")) {
- ast_set2_flag(&global_flags[1], ast_true(v->value), SIP_PAGE2_RTCACHEFRIENDS);
- } else if (!strcasecmp(v->name, "rtsavesysname")) {
- ast_set2_flag(&global_flags[1], ast_true(v->value), SIP_PAGE2_RTSAVE_SYSNAME);
- } else if (!strcasecmp(v->name, "rtupdate")) {
- ast_set2_flag(&global_flags[1], ast_true(v->value), SIP_PAGE2_RTUPDATE);
- } else if (!strcasecmp(v->name, "ignoreregexpire")) {
- ast_set2_flag(&global_flags[1], ast_true(v->value), SIP_PAGE2_IGNOREREGEXPIRE);
- } else if (!strcasecmp(v->name, "t1min")) {
- global_t1min = atoi(v->value);
- } else if (!strcasecmp(v->name, "dynamic_exclude_static") || !strcasecmp(v->name, "dynamic_excludes_static")) {
- global_dynamic_exclude_static = ast_true(v->value);
- } else if (!strcasecmp(v->name, "contactpermit") || !strcasecmp(v->name, "contactdeny")) {
- global_contact_ha = ast_append_ha(v->name + 7, v->value, global_contact_ha);
- } else if (!strcasecmp(v->name, "rtautoclear")) {
- int i = atoi(v->value);
- if (i > 0)
- global_rtautoclear = i;
- else
- i = 0;
- ast_set2_flag(&global_flags[1], i || ast_true(v->value), SIP_PAGE2_RTAUTOCLEAR);
- } else if (!strcasecmp(v->name, "usereqphone")) {
- ast_set2_flag(&global_flags[0], ast_true(v->value), SIP_USEREQPHONE);
- } else if (!strcasecmp(v->name, "relaxdtmf")) {
- global_relaxdtmf = ast_true(v->value);
- } else if (!strcasecmp(v->name, "checkmwi")) {
- if ((sscanf(v->value, "%d", &global_mwitime) != 1) || (global_mwitime < 0)) {
- ast_log(LOG_WARNING, "'%s' is not a valid MWI time setting at line %d. Using default (10).\n", v->value, v->lineno);
- global_mwitime = DEFAULT_MWITIME;
- }
- } else if (!strcasecmp(v->name, "vmexten")) {
- ast_copy_string(default_vmexten, v->value, sizeof(default_vmexten));
- } else if (!strcasecmp(v->name, "rtptimeout")) {
- if ((sscanf(v->value, "%d", &global_rtptimeout) != 1) || (global_rtptimeout < 0)) {
- ast_log(LOG_WARNING, "'%s' is not a valid RTP hold time at line %d. Using default.\n", v->value, v->lineno);
- global_rtptimeout = 0;
- }
- } else if (!strcasecmp(v->name, "rtpholdtimeout")) {
- if ((sscanf(v->value, "%d", &global_rtpholdtimeout) != 1) || (global_rtpholdtimeout < 0)) {
- ast_log(LOG_WARNING, "'%s' is not a valid RTP hold time at line %d. Using default.\n", v->value, v->lineno);
- global_rtpholdtimeout = 0;
- }
- } else if (!strcasecmp(v->name, "rtpkeepalive")) {
- if ((sscanf(v->value, "%d", &global_rtpkeepalive) != 1) || (global_rtpkeepalive < 0)) {
- ast_log(LOG_WARNING, "'%s' is not a valid RTP keepalive time at line %d. Using default.\n", v->value, v->lineno);
- global_rtpkeepalive = 0;
- }
- } else if (!strcasecmp(v->name, "compactheaders")) {
- compactheaders = ast_true(v->value);
- } else if (!strcasecmp(v->name, "notifymimetype")) {
- ast_copy_string(default_notifymime, v->value, sizeof(default_notifymime));
- } else if (!strncasecmp(v->name, "limitonpeer", 11)) {
- global_limitonpeers = ast_true(v->value);
- } else if (!strcasecmp(v->name, "directrtpsetup")) {
- global_directrtpsetup = ast_true(v->value);
- } else if (!strcasecmp(v->name, "notifyringing")) {
- global_notifyringing = ast_true(v->value);
- } else if (!strcasecmp(v->name, "notifyhold")) {
- global_notifyhold = ast_true(v->value);
- } else if (!strcasecmp(v->name, "alwaysauthreject")) {
- global_alwaysauthreject = ast_true(v->value);
- } else if (!strcasecmp(v->name, "mohinterpret")
- || !strcasecmp(v->name, "musicclass") || !strcasecmp(v->name, "musiconhold")) {
- ast_copy_string(default_mohinterpret, v->value, sizeof(default_mohinterpret));
- } else if (!strcasecmp(v->name, "mohsuggest")) {
- ast_copy_string(default_mohsuggest, v->value, sizeof(default_mohsuggest));
- } else if (!strcasecmp(v->name, "language")) {
- ast_copy_string(default_language, v->value, sizeof(default_language));
- } else if (!strcasecmp(v->name, "regcontext")) {
- ast_copy_string(newcontexts, v->value, sizeof(newcontexts));
- stringp = newcontexts;
- /* Let's remove any contexts that are no longer defined in regcontext */
- cleanup_stale_contexts(stringp, oldregcontext);
- /* Create contexts if they don't exist already */
- while ((context = strsep(&stringp, "&"))) {
- if (!ast_context_find(context))
- ast_context_create(NULL, context,"SIP");
- }
- ast_copy_string(global_regcontext, v->value, sizeof(global_regcontext));
- } else if (!strcasecmp(v->name, "callerid")) {
- ast_copy_string(default_callerid, v->value, sizeof(default_callerid));
- } else if (!strcasecmp(v->name, "fromdomain")) {
- ast_copy_string(default_fromdomain, v->value, sizeof(default_fromdomain));
- } else if (!strcasecmp(v->name, "outboundproxy")) {
- if (ast_get_ip_or_srv(&outboundproxyip, v->value, srvlookup ? "_sip._udp" : NULL) < 0)
- ast_log(LOG_WARNING, "Unable to locate host '%s'\n", v->value);
- } else if (!strcasecmp(v->name, "outboundproxyport")) {
- /* Port needs to be after IP */
- sscanf(v->value, "%d", &format);
- outboundproxyip.sin_port = htons(format);
- } else if (!strcasecmp(v->name, "autocreatepeer")) {
- autocreatepeer = ast_true(v->value);
- } else if (!strcasecmp(v->name, "srvlookup")) {
- srvlookup = ast_true(v->value);
- } else if (!strcasecmp(v->name, "pedantic")) {
- pedanticsipchecking = ast_true(v->value);
- } else if (!strcasecmp(v->name, "maxexpirey") || !strcasecmp(v->name, "maxexpiry")) {
- max_expiry = atoi(v->value);
- if (max_expiry < 1)
- max_expiry = DEFAULT_MAX_EXPIRY;
- } else if (!strcasecmp(v->name, "minexpirey") || !strcasecmp(v->name, "minexpiry")) {
- min_expiry = atoi(v->value);
- if (min_expiry < 1)
- min_expiry = DEFAULT_MIN_EXPIRY;
- } else if (!strcasecmp(v->name, "defaultexpiry") || !strcasecmp(v->name, "defaultexpirey")) {
- default_expiry = atoi(v->value);
- if (default_expiry < 1)
- default_expiry = DEFAULT_DEFAULT_EXPIRY;
- } else if (!strcasecmp(v->name, "sipdebug")) { /* XXX maybe ast_set2_flags ? */
- if (ast_true(v->value))
- ast_set_flag(&global_flags[1], SIP_PAGE2_DEBUG_CONFIG);
- } else if (!strcasecmp(v->name, "dumphistory")) {
- dumphistory = ast_true(v->value);
- } else if (!strcasecmp(v->name, "recordhistory")) {
- recordhistory = ast_true(v->value);
- } else if (!strcasecmp(v->name, "registertimeout")) {
- global_reg_timeout = atoi(v->value);
- if (global_reg_timeout < 1)
- global_reg_timeout = DEFAULT_REGISTRATION_TIMEOUT;
- } else if (!strcasecmp(v->name, "registerattempts")) {
- global_regattempts_max = atoi(v->value);
- } else if (!strcasecmp(v->name, "bindaddr")) {
- if (!(hp = ast_gethostbyname(v->value, &ahp))) {
- ast_log(LOG_WARNING, "Invalid address: %s\n", v->value);
- } else {
- memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr));
- }
- } else if (!strcasecmp(v->name, "localnet")) {
- struct ast_ha *na;
- if (!(na = ast_append_ha("d", v->value, localaddr)))
- ast_log(LOG_WARNING, "Invalid localnet value: %s\n", v->value);
- else
- localaddr = na;
- } else if (!strcasecmp(v->name, "localmask")) {
- ast_log(LOG_WARNING, "Use of localmask is no long supported -- use localnet with mask syntax\n");
- } else if (!strcasecmp(v->name, "externip")) {
- if (!(hp = ast_gethostbyname(v->value, &ahp)))
- ast_log(LOG_WARNING, "Invalid address for externip keyword: %s\n", v->value);
- else
- memcpy(&externip.sin_addr, hp->h_addr, sizeof(externip.sin_addr));
- externexpire = 0;
- } else if (!strcasecmp(v->name, "externhost")) {
- ast_copy_string(externhost, v->value, sizeof(externhost));
- if (!(hp = ast_gethostbyname(externhost, &ahp)))
- ast_log(LOG_WARNING, "Invalid address for externhost keyword: %s\n", externhost);
- else
- memcpy(&externip.sin_addr, hp->h_addr, sizeof(externip.sin_addr));
- externexpire = time(NULL);
- } else if (!strcasecmp(v->name, "externrefresh")) {
- if (sscanf(v->value, "%d", &externrefresh) != 1) {
- ast_log(LOG_WARNING, "Invalid externrefresh value '%s', must be an integer >0 at line %d\n", v->value, v->lineno);
- externrefresh = 10;
- }
- } else if (!strcasecmp(v->name, "allow")) {
- ast_parse_allow_disallow(&default_prefs, &global_capability, v->value, 1);
- } else if (!strcasecmp(v->name, "disallow")) {
- ast_parse_allow_disallow(&default_prefs, &global_capability, v->value, 0);
- } else if (!strcasecmp(v->name, "autoframing")) {
- global_autoframing = ast_true(v->value);
- } else if (!strcasecmp(v->name, "allowexternaldomains")) {
- allow_external_domains = ast_true(v->value);
- } else if (!strcasecmp(v->name, "autodomain")) {
- auto_sip_domains = ast_true(v->value);
- } else if (!strcasecmp(v->name, "domain")) {
- char *domain = ast_strdupa(v->value);
- char *context = strchr(domain, ',');
-
- if (context)
- *context++ = '\0';
-
- if (option_debug && ast_strlen_zero(context))
- ast_log(LOG_DEBUG, "No context specified at line %d for domain '%s'\n", v->lineno, domain);
- if (ast_strlen_zero(domain))
- ast_log(LOG_WARNING, "Empty domain specified at line %d\n", v->lineno);
- else
- add_sip_domain(ast_strip(domain), SIP_DOMAIN_CONFIG, context ? ast_strip(context) : "");
- } else if (!strcasecmp(v->name, "register")) {
- if (sip_register(v->value, v->lineno) == 0)
- registry_count++;
- } else if (!strcasecmp(v->name, "tos")) {
- if (!ast_str2tos(v->value, &temp_tos)) {
- global_tos_sip = temp_tos;
- global_tos_audio = temp_tos;
- global_tos_video = temp_tos;
- ast_log(LOG_WARNING, "tos value at line %d is deprecated. See doc/ip-tos.txt for more information.\n", v->lineno);
- } else
- ast_log(LOG_WARNING, "Invalid tos value at line %d, See doc/ip-tos.txt for more information.\n", v->lineno);
- } else if (!strcasecmp(v->name, "tos_sip")) {
- if (ast_str2tos(v->value, &global_tos_sip))
- ast_log(LOG_WARNING, "Invalid tos_sip value at line %d, recommended value is 'cs3'. See doc/ip-tos.txt.\n", v->lineno);
- } else if (!strcasecmp(v->name, "tos_audio")) {
- if (ast_str2tos(v->value, &global_tos_audio))
- ast_log(LOG_WARNING, "Invalid tos_audio value at line %d, recommended value is 'ef'. See doc/ip-tos.txt.\n", v->lineno);
- } else if (!strcasecmp(v->name, "tos_video")) {
- if (ast_str2tos(v->value, &global_tos_video))
- ast_log(LOG_WARNING, "Invalid tos_video value at line %d, recommended value is 'af41'. See doc/ip-tos.txt.\n", v->lineno);
- } else if (!strcasecmp(v->name, "bindport")) {
- if (sscanf(v->value, "%d", &ourport) == 1) {
- bindaddr.sin_port = htons(ourport);
- } else {
- ast_log(LOG_WARNING, "Invalid port number '%s' at line %d of %s\n", v->value, v->lineno, config);
- }
- } else if (!strcasecmp(v->name, "qualify")) {
- if (!strcasecmp(v->value, "no")) {
- default_qualify = 0;
- } else if (!strcasecmp(v->value, "yes")) {
- default_qualify = DEFAULT_MAXMS;
- } else if (sscanf(v->value, "%d", &default_qualify) != 1) {
- ast_log(LOG_WARNING, "Qualification default should be 'yes', 'no', or a number of milliseconds at line %d of sip.conf\n", v->lineno);
- default_qualify = 0;
- }
- } else if (!strcasecmp(v->name, "callevents")) {
- global_callevents = ast_true(v->value);
- } else if (!strcasecmp(v->name, "maxcallbitrate")) {
- default_maxcallbitrate = atoi(v->value);
- if (default_maxcallbitrate < 0)
- default_maxcallbitrate = DEFAULT_MAX_CALL_BITRATE;
- } else if (!strcasecmp(v->name, "matchexterniplocally")) {
- global_matchexterniplocally = ast_true(v->value);
- }
- }
-
- if (!allow_external_domains && AST_LIST_EMPTY(&domain_list)) {
- ast_log(LOG_WARNING, "To disallow external domains, you need to configure local SIP domains.\n");
- allow_external_domains = 1;
- }
-
- /* Build list of authentication to various SIP realms, i.e. service providers */
- for (v = ast_variable_browse(cfg, "authentication"); v ; v = v->next) {
- /* Format for authentication is auth = username:password@realm */
- if (!strcasecmp(v->name, "auth"))
- authl = add_realm_authentication(authl, v->value, v->lineno);
- }
-
- ucfg = ast_config_load("users.conf");
- if (ucfg) {
- struct ast_variable *gen;
- int genhassip, genregistersip;
- const char *hassip, *registersip;
-
- genhassip = ast_true(ast_variable_retrieve(ucfg, "general", "hassip"));
- genregistersip = ast_true(ast_variable_retrieve(ucfg, "general", "registersip"));
- gen = ast_variable_browse(ucfg, "general");
- cat = ast_category_browse(ucfg, NULL);
- while (cat) {
- if (strcasecmp(cat, "general")) {
- hassip = ast_variable_retrieve(ucfg, cat, "hassip");
- registersip = ast_variable_retrieve(ucfg, cat, "registersip");
- if (ast_true(hassip) || (!hassip && genhassip)) {
- user = build_user(cat, gen, ast_variable_browse(ucfg, cat), 0);
- if (user) {
- ASTOBJ_CONTAINER_LINK(&userl,user);
- ASTOBJ_UNREF(user, sip_destroy_user);
- user_count++;
- }
- peer = build_peer(cat, gen, ast_variable_browse(ucfg, cat), 0);
- if (peer) {
- ast_device_state_changed("SIP/%s", peer->name);
- ASTOBJ_CONTAINER_LINK(&peerl,peer);
- ASTOBJ_UNREF(peer, sip_destroy_peer);
- peer_count++;
- }
- }
- if (ast_true(registersip) || (!registersip && genregistersip)) {
- char tmp[256];
- const char *host = ast_variable_retrieve(ucfg, cat, "host");
- const char *username = ast_variable_retrieve(ucfg, cat, "username");
- const char *secret = ast_variable_retrieve(ucfg, cat, "secret");
- const char *contact = ast_variable_retrieve(ucfg, cat, "contact");
- if (!host)
- host = ast_variable_retrieve(ucfg, "general", "host");
- if (!username)
- username = ast_variable_retrieve(ucfg, "general", "username");
- if (!secret)
- secret = ast_variable_retrieve(ucfg, "general", "secret");
- if (!contact)
- contact = "s";
- if (!ast_strlen_zero(username) && !ast_strlen_zero(host)) {
- if (!ast_strlen_zero(secret))
- snprintf(tmp, sizeof(tmp), "%s:%s@%s/%s", username, secret, host, contact);
- else
- snprintf(tmp, sizeof(tmp), "%s@%s/%s", username, host, contact);
- if (sip_register(tmp, 0) == 0)
- registry_count++;
- }
- }
- }
- cat = ast_category_browse(ucfg, cat);
- }
- ast_config_destroy(ucfg);
- }
-
-
- /* Load peers, users and friends */
- cat = NULL;
- while ( (cat = ast_category_browse(cfg, cat)) ) {
- const char *utype;
- if (!strcasecmp(cat, "general") || !strcasecmp(cat, "authentication"))
- continue;
- utype = ast_variable_retrieve(cfg, cat, "type");
- if (!utype) {
- ast_log(LOG_WARNING, "Section '%s' lacks type\n", cat);
- continue;
- } else {
- int is_user = 0, is_peer = 0;
- if (!strcasecmp(utype, "user"))
- is_user = 1;
- else if (!strcasecmp(utype, "friend"))
- is_user = is_peer = 1;
- else if (!strcasecmp(utype, "peer"))
- is_peer = 1;
- else {
- ast_log(LOG_WARNING, "Unknown type '%s' for '%s' in %s\n", utype, cat, "sip.conf");
- continue;
- }
- if (is_user) {
- user = build_user(cat, ast_variable_browse(cfg, cat), NULL, 0);
- if (user) {
- ASTOBJ_CONTAINER_LINK(&userl,user);
- ASTOBJ_UNREF(user, sip_destroy_user);
- user_count++;
- }
- }
- if (is_peer) {
- peer = build_peer(cat, ast_variable_browse(cfg, cat), NULL, 0);
- if (peer) {
- ASTOBJ_CONTAINER_LINK(&peerl,peer);
- ASTOBJ_UNREF(peer, sip_destroy_peer);
- peer_count++;
- }
- }
- }
- }
- if (ast_find_ourip(&__ourip, bindaddr)) {
- ast_log(LOG_WARNING, "Unable to get own IP address, SIP disabled\n");
- ast_config_destroy(cfg);
- return 0;
- }
- if (!ntohs(bindaddr.sin_port))
- bindaddr.sin_port = ntohs(STANDARD_SIP_PORT);
- bindaddr.sin_family = AF_INET;
- ast_mutex_lock(&netlock);
- if ((sipsock > -1) && (memcmp(&old_bindaddr, &bindaddr, sizeof(struct sockaddr_in)))) {
- close(sipsock);
- sipsock = -1;
- }
- if (sipsock < 0) {
- sipsock = socket(AF_INET, SOCK_DGRAM, 0);
- if (sipsock < 0) {
- ast_log(LOG_WARNING, "Unable to create SIP socket: %s\n", strerror(errno));
- ast_config_destroy(cfg);
- return -1;
- } else {
- /* Allow SIP clients on the same host to access us: */
- const int reuseFlag = 1;
-
- setsockopt(sipsock, SOL_SOCKET, SO_REUSEADDR,
- (const char*)&reuseFlag,
- sizeof reuseFlag);
-
- ast_enable_packet_fragmentation(sipsock);
-
- if (bind(sipsock, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) < 0) {
- ast_log(LOG_WARNING, "Failed to bind to %s:%d: %s\n",
- ast_inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port),
- strerror(errno));
- close(sipsock);
- sipsock = -1;
- } else {
- if (option_verbose > 1) {
- ast_verbose(VERBOSE_PREFIX_2 "SIP Listening on %s:%d\n",
- ast_inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port));
- ast_verbose(VERBOSE_PREFIX_2 "Using SIP TOS: %s\n", ast_tos2str(global_tos_sip));
- }
- if (setsockopt(sipsock, IPPROTO_IP, IP_TOS, &global_tos_sip, sizeof(global_tos_sip)))
- ast_log(LOG_WARNING, "Unable to set SIP TOS to %s\n", ast_tos2str(global_tos_sip));
- }
- }
- }
- ast_mutex_unlock(&netlock);
-
- /* Add default domains - host name, IP address and IP:port */
- /* Only do this if user added any sip domain with "localdomains" */
- /* In order to *not* break backwards compatibility */
- /* Some phones address us at IP only, some with additional port number */
- if (auto_sip_domains) {
- char temp[MAXHOSTNAMELEN];
-
- /* First our default IP address */
- if (bindaddr.sin_addr.s_addr)
- add_sip_domain(ast_inet_ntoa(bindaddr.sin_addr), SIP_DOMAIN_AUTO, NULL);
- else
- ast_log(LOG_NOTICE, "Can't add wildcard IP address to domain list, please add IP address to domain manually.\n");
-
- /* Our extern IP address, if configured */
- if (externip.sin_addr.s_addr)
- add_sip_domain(ast_inet_ntoa(externip.sin_addr), SIP_DOMAIN_AUTO, NULL);
-
- /* Extern host name (NAT traversal support) */
- if (!ast_strlen_zero(externhost))
- add_sip_domain(externhost, SIP_DOMAIN_AUTO, NULL);
-
- /* Our host name */
- if (!gethostname(temp, sizeof(temp)))
- add_sip_domain(temp, SIP_DOMAIN_AUTO, NULL);
- }
-
- /* Release configuration from memory */
- ast_config_destroy(cfg);
-
- /* Load the list of manual NOTIFY types to support */
- if (notify_types)
- ast_config_destroy(notify_types);
- notify_types = ast_config_load(notify_config);
-
- /* Done, tell the manager */
- manager_event(EVENT_FLAG_SYSTEM, "ChannelReload", "Channel: SIP\r\nReloadReason: %s\r\nRegistry_Count: %d\r\nPeer_Count: %d\r\nUser_Count: %d\r\n", channelreloadreason2txt(reason), registry_count, peer_count, user_count);
-
- return 0;
-}
-
-static struct ast_udptl *sip_get_udptl_peer(struct ast_channel *chan)
-{
- struct sip_pvt *p;
- struct ast_udptl *udptl = NULL;
-
- p = chan->tech_pvt;
- if (!p)
- return NULL;
-
- ast_mutex_lock(&p->lock);
- if (p->udptl && ast_test_flag(&p->flags[0], SIP_CAN_REINVITE))
- udptl = p->udptl;
- ast_mutex_unlock(&p->lock);
- return udptl;
-}
-
-static int sip_set_udptl_peer(struct ast_channel *chan, struct ast_udptl *udptl)
-{
- struct sip_pvt *p;
-
- p = chan->tech_pvt;
- if (!p)
- return -1;
- ast_mutex_lock(&p->lock);
- if (udptl)
- ast_udptl_get_peer(udptl, &p->udptlredirip);
- else
- memset(&p->udptlredirip, 0, sizeof(p->udptlredirip));
- if (!ast_test_flag(&p->flags[0], SIP_GOTREFER)) {
- if (!p->pendinginvite) {
- if (option_debug > 2) {
- ast_log(LOG_DEBUG, "Sending reinvite on SIP '%s' - It's UDPTL soon redirected to IP %s:%d\n", p->callid, ast_inet_ntoa(udptl ? p->udptlredirip.sin_addr : p->ourip), udptl ? ntohs(p->udptlredirip.sin_port) : 0);
- }
- transmit_reinvite_with_t38_sdp(p);
- } else if (!ast_test_flag(&p->flags[0], SIP_PENDINGBYE)) {
- if (option_debug > 2) {
- ast_log(LOG_DEBUG, "Deferring reinvite on SIP '%s' - It's UDPTL will be redirected to IP %s:%d\n", p->callid, ast_inet_ntoa(udptl ? p->udptlredirip.sin_addr : p->ourip), udptl ? ntohs(p->udptlredirip.sin_port) : 0);
- }
- ast_set_flag(&p->flags[0], SIP_NEEDREINVITE);
- }
- }
- /* Reset lastrtprx timer */
- p->lastrtprx = p->lastrtptx = time(NULL);
- ast_mutex_unlock(&p->lock);
- return 0;
-}
-
-/*! \brief Handle T38 reinvite
- \todo Make sure we don't destroy the call if we can't handle the re-invite.
- Nothing should be changed until we have processed the SDP and know that we
- can handle it.
-*/
-static int sip_handle_t38_reinvite(struct ast_channel *chan, struct sip_pvt *pvt, int reinvite)
-{
- struct sip_pvt *p;
- int flag = 0;
-
- p = chan->tech_pvt;
- if (!p || !pvt->udptl)
- return -1;
-
- /* Setup everything on the other side like offered/responded from first side */
- ast_mutex_lock(&p->lock);
-
- /*! \todo check if this is not set earlier when setting up the PVT. If not
- maybe it should move there. */
- p->t38.jointcapability = p->t38.peercapability = pvt->t38.jointcapability;
-
- ast_udptl_set_far_max_datagram(p->udptl, ast_udptl_get_local_max_datagram(pvt->udptl));
- ast_udptl_set_local_max_datagram(p->udptl, ast_udptl_get_local_max_datagram(pvt->udptl));
- ast_udptl_set_error_correction_scheme(p->udptl, ast_udptl_get_error_correction_scheme(pvt->udptl));
-
- if (reinvite) { /* If we are handling sending re-invite to the other side of the bridge */
- /*! \note The SIP_CAN_REINVITE flag is for RTP media redirects,
- not really T38 re-invites which are different. In this
- case it's used properly, to see if we can reinvite over
- NAT
- */
- if (ast_test_flag(&p->flags[0], SIP_CAN_REINVITE) && ast_test_flag(&pvt->flags[0], SIP_CAN_REINVITE)) {
- ast_udptl_get_peer(pvt->udptl, &p->udptlredirip);
- flag =1;
- } else {
- memset(&p->udptlredirip, 0, sizeof(p->udptlredirip));
- }
- if (!ast_test_flag(&p->flags[0], SIP_GOTREFER)) {
- if (!p->pendinginvite) {
- if (option_debug > 2) {
- if (flag)
- ast_log(LOG_DEBUG, "Sending reinvite on SIP '%s' - It's UDPTL soon redirected to IP %s:%d\n", p->callid, ast_inet_ntoa(p->udptlredirip.sin_addr), ntohs(p->udptlredirip.sin_port));
- else
- ast_log(LOG_DEBUG, "Sending reinvite on SIP '%s' - It's UDPTL soon redirected to us (IP %s)\n", p->callid, ast_inet_ntoa(p->ourip));
- }
- transmit_reinvite_with_t38_sdp(p);
- } else if (!ast_test_flag(&p->flags[0], SIP_PENDINGBYE)) {
- if (option_debug > 2) {
- if (flag)
- ast_log(LOG_DEBUG, "Deferring reinvite on SIP '%s' - It's UDPTL will be redirected to IP %s:%d\n", p->callid, ast_inet_ntoa(p->udptlredirip.sin_addr), ntohs(p->udptlredirip.sin_port));
- else
- ast_log(LOG_DEBUG, "Deferring reinvite on SIP '%s' - It's UDPTL will be redirected to us (IP %s)\n", p->callid, ast_inet_ntoa(p->ourip));
- }
- ast_set_flag(&p->flags[0], SIP_NEEDREINVITE);
- }
- }
- /* Reset lastrtprx timer */
- p->lastrtprx = p->lastrtptx = time(NULL);
- ast_mutex_unlock(&p->lock);
- return 0;
- } else { /* If we are handling sending 200 OK to the other side of the bridge */
- if (ast_test_flag(&p->flags[0], SIP_CAN_REINVITE) && ast_test_flag(&pvt->flags[0], SIP_CAN_REINVITE)) {
- ast_udptl_get_peer(pvt->udptl, &p->udptlredirip);
- flag = 1;
- } else {
- memset(&p->udptlredirip, 0, sizeof(p->udptlredirip));
- }
- if (option_debug > 2) {
- if (flag)
- ast_log(LOG_DEBUG, "Responding 200 OK on SIP '%s' - It's UDPTL soon redirected to IP %s:%d\n", p->callid, ast_inet_ntoa(p->udptlredirip.sin_addr), ntohs(p->udptlredirip.sin_port));
- else
- ast_log(LOG_DEBUG, "Responding 200 OK on SIP '%s' - It's UDPTL soon redirected to us (IP %s)\n", p->callid, ast_inet_ntoa(p->ourip));
- }
- pvt->t38.state = T38_ENABLED;
- p->t38.state = T38_ENABLED;
- if (option_debug > 1) {
- ast_log(LOG_DEBUG, "T38 changed state to %d on channel %s\n", pvt->t38.state, pvt->owner ? pvt->owner->name : "<none>");
- ast_log(LOG_DEBUG, "T38 changed state to %d on channel %s\n", p->t38.state, chan ? chan->name : "<none>");
- }
- transmit_response_with_t38_sdp(p, "200 OK", &p->initreq, XMIT_CRITICAL);
- p->lastrtprx = p->lastrtptx = time(NULL);
- ast_mutex_unlock(&p->lock);
- return 0;
- }
-}
-
-
-/*! \brief Returns null if we can't reinvite audio (part of RTP interface) */
-static enum ast_rtp_get_result sip_get_rtp_peer(struct ast_channel *chan, struct ast_rtp **rtp)
-{
- struct sip_pvt *p = NULL;
- enum ast_rtp_get_result res = AST_RTP_TRY_PARTIAL;
-
- if (!(p = chan->tech_pvt))
- return AST_RTP_GET_FAILED;
-
- ast_mutex_lock(&p->lock);
- if (!(p->rtp)) {
- ast_mutex_unlock(&p->lock);
- return AST_RTP_GET_FAILED;
- }
-
- *rtp = p->rtp;
-
- if (ast_rtp_getnat(*rtp) && !ast_test_flag(&p->flags[0], SIP_CAN_REINVITE_NAT))
- res = AST_RTP_TRY_PARTIAL;
- else if (ast_test_flag(&p->flags[0], SIP_CAN_REINVITE))
- res = AST_RTP_TRY_NATIVE;
- else if (ast_test_flag(&global_jbconf, AST_JB_FORCED))
- res = AST_RTP_GET_FAILED;
-
- ast_mutex_unlock(&p->lock);
-
- return res;
-}
-
-/*! \brief Returns null if we can't reinvite video (part of RTP interface) */
-static enum ast_rtp_get_result sip_get_vrtp_peer(struct ast_channel *chan, struct ast_rtp **rtp)
-{
- struct sip_pvt *p = NULL;
- enum ast_rtp_get_result res = AST_RTP_TRY_PARTIAL;
-
- if (!(p = chan->tech_pvt))
- return AST_RTP_GET_FAILED;
-
- ast_mutex_lock(&p->lock);
- if (!(p->vrtp)) {
- ast_mutex_unlock(&p->lock);
- return AST_RTP_GET_FAILED;
- }
-
- *rtp = p->vrtp;
-
- if (ast_test_flag(&p->flags[0], SIP_CAN_REINVITE))
- res = AST_RTP_TRY_NATIVE;
-
- ast_mutex_unlock(&p->lock);
-
- return res;
-}
-
-/*! \brief Set the RTP peer for this call */
-static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs, int nat_active)
-{
- struct sip_pvt *p;
- int changed = 0;
-
- p = chan->tech_pvt;
- if (!p)
- return -1;
-
- /* Disable early RTP bridge */
- if (chan->_state != AST_STATE_UP && !global_directrtpsetup) /* We are in early state */
- return 0;
-
- ast_mutex_lock(&p->lock);
- if (ast_test_flag(&p->flags[0], SIP_ALREADYGONE)) {
- /* If we're destroyed, don't bother */
- ast_mutex_unlock(&p->lock);
- return 0;
- }
-
- /* if this peer cannot handle reinvites of the media stream to devices
- that are known to be behind a NAT, then stop the process now
- */
- if (nat_active && !ast_test_flag(&p->flags[0], SIP_CAN_REINVITE_NAT)) {
- ast_mutex_unlock(&p->lock);
- return 0;
- }
-
- if (rtp) {
- changed |= ast_rtp_get_peer(rtp, &p->redirip);
- } else if (p->redirip.sin_addr.s_addr || ntohs(p->redirip.sin_port) != 0) {
- memset(&p->redirip, 0, sizeof(p->redirip));
- changed = 1;
- }
- if (vrtp) {
- changed |= ast_rtp_get_peer(vrtp, &p->vredirip);
- } else if (p->vredirip.sin_addr.s_addr || ntohs(p->vredirip.sin_port) != 0) {
- memset(&p->vredirip, 0, sizeof(p->vredirip));
- changed = 1;
- }
- if (codecs) {
- if ((p->redircodecs != codecs)) {
- p->redircodecs = codecs;
- changed = 1;
- }
- if ((p->capability & codecs) != p->capability) {
- p->jointcapability &= codecs;
- p->capability &= codecs;
- changed = 1;
- }
- }
- if (changed && !ast_test_flag(&p->flags[0], SIP_GOTREFER) && !ast_test_flag(&p->flags[0], SIP_DEFER_BYE_ON_TRANSFER)) {
- if (chan->_state != AST_STATE_UP) { /* We are in early state */
- if (!ast_test_flag(&p->flags[0], SIP_NO_HISTORY))
- append_history(p, "ExtInv", "Initial invite sent with remote bridge proposal.");
- if (option_debug)
- ast_log(LOG_DEBUG, "Early remote bridge setting SIP '%s' - Sending media to %s\n", p->callid, ast_inet_ntoa(rtp ? p->redirip.sin_addr : p->ourip));
- } else if (!p->pendinginvite) { /* We are up, and have no outstanding invite */
- if (option_debug > 2) {
- ast_log(LOG_DEBUG, "Sending reinvite on SIP '%s' - It's audio soon redirected to IP %s\n", p->callid, ast_inet_ntoa(rtp ? p->redirip.sin_addr : p->ourip));
- }
- transmit_reinvite_with_sdp(p);
- } else if (!ast_test_flag(&p->flags[0], SIP_PENDINGBYE)) {
- if (option_debug > 2) {
- ast_log(LOG_DEBUG, "Deferring reinvite on SIP '%s' - It's audio will be redirected to IP %s\n", p->callid, ast_inet_ntoa(rtp ? p->redirip.sin_addr : p->ourip));
- }
- /* We have a pending Invite. Send re-invite when we're done with the invite */
- ast_set_flag(&p->flags[0], SIP_NEEDREINVITE);
- }
- }
- /* Reset lastrtprx timer */
- p->lastrtprx = p->lastrtptx = time(NULL);
- ast_mutex_unlock(&p->lock);
- return 0;
-}
-
-static char *synopsis_dtmfmode = "Change the dtmfmode for a SIP call";
-static char *descrip_dtmfmode = "SIPDtmfMode(inband|info|rfc2833): Changes the dtmfmode for a SIP call\n";
-static char *app_dtmfmode = "SIPDtmfMode";
-
-static char *app_sipaddheader = "SIPAddHeader";
-static char *synopsis_sipaddheader = "Add a SIP header to the outbound call";
-
-static char *descrip_sipaddheader = ""
-" SIPAddHeader(Header: Content)\n"
-"Adds a header to a SIP call placed with DIAL.\n"
-"Remember to user the X-header if you are adding non-standard SIP\n"
-"headers, like \"X-Asterisk-Accountcode:\". Use this with care.\n"
-"Adding the wrong headers may jeopardize the SIP dialog.\n"
-"Always returns 0\n";
-
-
-/*! \brief Set the DTMFmode for an outbound SIP call (application) */
-static int sip_dtmfmode(struct ast_channel *chan, void *data)
-{
- struct sip_pvt *p;
- char *mode;
- if (data)
- mode = (char *)data;
- else {
- ast_log(LOG_WARNING, "This application requires the argument: info, inband, rfc2833\n");
- return 0;
- }
- ast_channel_lock(chan);
- if (chan->tech != &sip_tech && chan->tech != &sip_tech_info) {
- ast_log(LOG_WARNING, "Call this application only on SIP incoming calls\n");
- ast_channel_unlock(chan);
- return 0;
- }
- p = chan->tech_pvt;
- if (!p) {
- ast_channel_unlock(chan);
- return 0;
- }
- ast_mutex_lock(&p->lock);
- if (!strcasecmp(mode,"info")) {
- ast_clear_flag(&p->flags[0], SIP_DTMF);
- ast_set_flag(&p->flags[0], SIP_DTMF_INFO);
- p->jointnoncodeccapability &= ~AST_RTP_DTMF;
- } else if (!strcasecmp(mode,"rfc2833")) {
- ast_clear_flag(&p->flags[0], SIP_DTMF);
- ast_set_flag(&p->flags[0], SIP_DTMF_RFC2833);
- p->jointnoncodeccapability |= AST_RTP_DTMF;
- } else if (!strcasecmp(mode,"inband")) {
- ast_clear_flag(&p->flags[0], SIP_DTMF);
- ast_set_flag(&p->flags[0], SIP_DTMF_INBAND);
- p->jointnoncodeccapability &= ~AST_RTP_DTMF;
- } else
- ast_log(LOG_WARNING, "I don't know about this dtmf mode: %s\n",mode);
- if (p->rtp)
- ast_rtp_setdtmf(p->rtp, ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833);
- if (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_INBAND) {
- if (!p->vad) {
- p->vad = ast_dsp_new();
- ast_dsp_set_features(p->vad, DSP_FEATURE_DTMF_DETECT);
- }
- } else {
- if (p->vad) {
- ast_dsp_free(p->vad);
- p->vad = NULL;
- }
- }
- ast_mutex_unlock(&p->lock);
- ast_channel_unlock(chan);
- return 0;
-}
-
-/*! \brief Add a SIP header to an outbound INVITE */
-static int sip_addheader(struct ast_channel *chan, void *data)
-{
- int no = 0;
- int ok = FALSE;
- char varbuf[30];
- char *inbuf = (char *) data;
-
- if (ast_strlen_zero(inbuf)) {
- ast_log(LOG_WARNING, "This application requires the argument: Header\n");
- return 0;
- }
- ast_channel_lock(chan);
-
- /* Check for headers */
- while (!ok && no <= 50) {
- no++;
- snprintf(varbuf, sizeof(varbuf), "__SIPADDHEADER%.2d", no);
-
- /* Compare without the leading underscores */
- if( (pbx_builtin_getvar_helper(chan, (const char *) varbuf + 2) == (const char *) NULL) )
- ok = TRUE;
- }
- if (ok) {
- pbx_builtin_setvar_helper (chan, varbuf, inbuf);
- if (sipdebug)
- ast_log(LOG_DEBUG,"SIP Header added \"%s\" as %s\n", inbuf, varbuf);
- } else {
- ast_log(LOG_WARNING, "Too many SIP headers added, max 50\n");
- }
- ast_channel_unlock(chan);
- return 0;
-}
-
-/*! \brief Transfer call before connect with a 302 redirect
-\note Called by the transfer() dialplan application through the sip_transfer()
- pbx interface function if the call is in ringing state
-\todo Fix this function so that we wait for reply to the REFER and
- react to errors, denials or other issues the other end might have.
- */
-static int sip_sipredirect(struct sip_pvt *p, const char *dest)
-{
- char *cdest;
- char *extension, *host, *port;
- char tmp[80];
-
- cdest = ast_strdupa(dest);
-
- extension = strsep(&cdest, "@");
- host = strsep(&cdest, ":");
- port = strsep(&cdest, ":");
- if (ast_strlen_zero(extension)) {
- ast_log(LOG_ERROR, "Missing mandatory argument: extension\n");
- return 0;
- }
-
- /* we'll issue the redirect message here */
- if (!host) {
- char *localtmp;
- ast_copy_string(tmp, get_header(&p->initreq, "To"), sizeof(tmp));
- if (ast_strlen_zero(tmp)) {
- ast_log(LOG_ERROR, "Cannot retrieve the 'To' header from the original SIP request!\n");
- return 0;
- }
- if ((localtmp = strcasestr(tmp, "sip:")) && (localtmp = strchr(localtmp, '@'))) {
- char lhost[80], lport[80];
- memset(lhost, 0, sizeof(lhost));
- memset(lport, 0, sizeof(lport));
- localtmp++;
- /* This is okey because lhost and lport are as big as tmp */
- sscanf(localtmp, "%[^<>:; ]:%[^<>:; ]", lhost, lport);
- if (ast_strlen_zero(lhost)) {
- ast_log(LOG_ERROR, "Can't find the host address\n");
- return 0;
- }
- host = ast_strdupa(lhost);
- if (!ast_strlen_zero(lport)) {
- port = ast_strdupa(lport);
- }
- }
- }
-
- ast_string_field_build(p, our_contact, "Transfer <sip:%s@%s%s%s>", extension, host, port ? ":" : "", port ? port : "");
- transmit_response_reliable(p, "302 Moved Temporarily", &p->initreq);
-
- sip_scheddestroy(p, SIP_TRANS_TIMEOUT); /* Make sure we stop send this reply. */
- sip_alreadygone(p);
- return 0;
-}
-
-/*! \brief Return SIP UA's codec (part of the RTP interface) */
-static int sip_get_codec(struct ast_channel *chan)
-{
- struct sip_pvt *p = chan->tech_pvt;
- return p->jointcapability ? p->jointcapability : p->capability;
-}
-
-/*! \brief Send a poke to all known peers
- Space them out 100 ms apart
- XXX We might have a cool algorithm for this or use random - any suggestions?
-*/
-static void sip_poke_all_peers(void)
-{
- int ms = 0;
-
- if (!speerobjs) /* No peers, just give up */
- return;
-
- ASTOBJ_CONTAINER_TRAVERSE(&peerl, 1, do {
- ASTOBJ_WRLOCK(iterator);
- if (!AST_SCHED_DEL(sched, iterator->pokeexpire)) {
- struct sip_peer *peer_ptr = iterator;
- ASTOBJ_UNREF(peer_ptr, sip_destroy_peer);
- }
- ms += 100;
- iterator->pokeexpire = ast_sched_add(sched, ms, sip_poke_peer_s, ASTOBJ_REF(iterator));
- if (iterator->pokeexpire == -1) {
- struct sip_peer *peer_ptr = iterator;
- ASTOBJ_UNREF(peer_ptr, sip_destroy_peer);
- }
- ASTOBJ_UNLOCK(iterator);
- } while (0)
- );
-}
-
-/*! \brief Send all known registrations */
-static void sip_send_all_registers(void)
-{
- int ms;
- int regspacing;
- if (!regobjs)
- return;
- regspacing = default_expiry * 1000/regobjs;
- if (regspacing > 100)
- regspacing = 100;
- ms = regspacing;
- ASTOBJ_CONTAINER_TRAVERSE(&regl, 1, do {
- ASTOBJ_WRLOCK(iterator);
- AST_SCHED_DEL(sched, iterator->expire);
- ms += regspacing;
- iterator->expire = ast_sched_add(sched, ms, sip_reregister, iterator);
- ASTOBJ_UNLOCK(iterator);
- } while (0)
- );
-}
-
-/*! \brief Reload module */
-static int sip_do_reload(enum channelreloadreason reason)
-{
- reload_config(reason);
-
- /* Prune peers who still are supposed to be deleted */
- ASTOBJ_CONTAINER_PRUNE_MARKED(&peerl, sip_destroy_peer);
- if (option_debug > 3)
- ast_log(LOG_DEBUG, "--------------- Done destroying pruned peers\n");
-
- /* Send qualify (OPTIONS) to all peers */
- sip_poke_all_peers();
-
- /* Register with all services */
- sip_send_all_registers();
-
- if (option_debug > 3)
- ast_log(LOG_DEBUG, "--------------- SIP reload done\n");
-
- return 0;
-}
-
-/*! \brief Force reload of module from cli */
-static int sip_reload(int fd, int argc, char *argv[])
-{
- ast_mutex_lock(&sip_reload_lock);
- if (sip_reloading)
- ast_verbose("Previous SIP reload not yet done\n");
- else {
- sip_reloading = TRUE;
- if (fd)
- sip_reloadreason = CHANNEL_CLI_RELOAD;
- else
- sip_reloadreason = CHANNEL_MODULE_RELOAD;
- }
- ast_mutex_unlock(&sip_reload_lock);
- restart_monitor();
-
- return 0;
-}
-
-/*! \brief Part of Asterisk module interface */
-static int reload(void)
-{
- return sip_reload(0, 0, NULL);
-}
-
-static struct ast_cli_entry cli_sip_debug_deprecated =
- { { "sip", "debug", NULL },
- sip_do_debug_deprecated, "Enable SIP debugging",
- debug_usage };
-
-static struct ast_cli_entry cli_sip_no_debug_deprecated =
- { { "sip", "no", "debug", NULL },
- sip_no_debug_deprecated, "Disable SIP debugging",
- debug_usage };
-
-static struct ast_cli_entry cli_sip[] = {
- { { "sip", "show", "channels", NULL },
- sip_show_channels, "List active SIP channels",
- show_channels_usage },
-
- { { "sip", "show", "domains", NULL },
- sip_show_domains, "List our local SIP domains.",
- show_domains_usage },
-
- { { "sip", "show", "inuse", NULL },
- sip_show_inuse, "List all inuse/limits",
- show_inuse_usage },
-
- { { "sip", "show", "objects", NULL },
- sip_show_objects, "List all SIP object allocations",
- show_objects_usage },
-
- { { "sip", "show", "peers", NULL },
- sip_show_peers, "List defined SIP peers",
- show_peers_usage },
-
- { { "sip", "show", "registry", NULL },
- sip_show_registry, "List SIP registration status",
- show_reg_usage },
-
- { { "sip", "show", "settings", NULL },
- sip_show_settings, "Show SIP global settings",
- show_settings_usage },
-
- { { "sip", "show", "subscriptions", NULL },
- sip_show_subscriptions, "List active SIP subscriptions",
- show_subscriptions_usage },
-
- { { "sip", "show", "users", NULL },
- sip_show_users, "List defined SIP users",
- show_users_usage },
-
- { { "sip", "notify", NULL },
- sip_notify, "Send a notify packet to a SIP peer",
- notify_usage, complete_sipnotify },
-
- { { "sip", "show", "channel", NULL },
- sip_show_channel, "Show detailed SIP channel info",
- show_channel_usage, complete_sipch },
-
- { { "sip", "show", "history", NULL },
- sip_show_history, "Show SIP dialog history",
- show_history_usage, complete_sipch },
-
- { { "sip", "show", "peer", NULL },
- sip_show_peer, "Show details on specific SIP peer",
- show_peer_usage, complete_sip_show_peer },
-
- { { "sip", "show", "user", NULL },
- sip_show_user, "Show details on specific SIP user",
- show_user_usage, complete_sip_show_user },
-
- { { "sip", "prune", "realtime", NULL },
- sip_prune_realtime, "Prune cached Realtime object(s)",
- prune_realtime_usage },
-
- { { "sip", "prune", "realtime", "peer", NULL },
- sip_prune_realtime, "Prune cached Realtime peer(s)",
- prune_realtime_usage, complete_sip_prune_realtime_peer },
-
- { { "sip", "prune", "realtime", "user", NULL },
- sip_prune_realtime, "Prune cached Realtime user(s)",
- prune_realtime_usage, complete_sip_prune_realtime_user },
-
- { { "sip", "set", "debug", NULL },
- sip_do_debug, "Enable SIP debugging",
- debug_usage, NULL, &cli_sip_debug_deprecated },
-
- { { "sip", "set", "debug", "ip", NULL },
- sip_do_debug, "Enable SIP debugging on IP",
- debug_usage },
-
- { { "sip", "set", "debug", "peer", NULL },
- sip_do_debug, "Enable SIP debugging on Peername",
- debug_usage, complete_sip_debug_peer },
-
- { { "sip", "set", "debug", "off", NULL },
- sip_no_debug, "Disable SIP debugging",
- no_debug_usage, NULL, &cli_sip_no_debug_deprecated },
-
- { { "sip", "history", NULL },
- sip_do_history, "Enable SIP history",
- history_usage },
-
- { { "sip", "history", "off", NULL },
- sip_no_history, "Disable SIP history",
- no_history_usage },
-
- { { "sip", "reload", NULL },
- sip_reload, "Reload SIP configuration",
- sip_reload_usage },
-};
-
-/*! \brief PBX load module - initialization */
-static int load_module(void)
-{
- ASTOBJ_CONTAINER_INIT(&userl); /* User object list */
- ASTOBJ_CONTAINER_INIT(&peerl); /* Peer object list */
- ASTOBJ_CONTAINER_INIT(&regl); /* Registry object list */
-
- if (!(sched = sched_context_create())) {
- ast_log(LOG_ERROR, "Unable to create scheduler context\n");
- return AST_MODULE_LOAD_FAILURE;
- }
-
- if (!(io = io_context_create())) {
- ast_log(LOG_ERROR, "Unable to create I/O context\n");
- sched_context_destroy(sched);
- return AST_MODULE_LOAD_FAILURE;
- }
-
- sip_reloadreason = CHANNEL_MODULE_LOAD;
-
- if(reload_config(sip_reloadreason)) /* Load the configuration from sip.conf */
- return AST_MODULE_LOAD_DECLINE;
-
- /* Make sure we can register our sip channel type */
- if (ast_channel_register(&sip_tech)) {
- ast_log(LOG_ERROR, "Unable to register channel type 'SIP'\n");
- io_context_destroy(io);
- sched_context_destroy(sched);
- return AST_MODULE_LOAD_FAILURE;
- }
-
- /* Register all CLI functions for SIP */
- ast_cli_register_multiple(cli_sip, sizeof(cli_sip)/ sizeof(struct ast_cli_entry));
-
- /* Tell the RTP subdriver that we're here */
- ast_rtp_proto_register(&sip_rtp);
-
- /* Tell the UDPTL subdriver that we're here */
- ast_udptl_proto_register(&sip_udptl);
-
- /* Register dialplan applications */
- ast_register_application(app_dtmfmode, sip_dtmfmode, synopsis_dtmfmode, descrip_dtmfmode);
- ast_register_application(app_sipaddheader, sip_addheader, synopsis_sipaddheader, descrip_sipaddheader);
-
- /* Register dialplan functions */
- ast_custom_function_register(&sip_header_function);
- ast_custom_function_register(&sippeer_function);
- ast_custom_function_register(&sipchaninfo_function);
- ast_custom_function_register(&checksipdomain_function);
-
- /* Register manager commands */
- ast_manager_register2("SIPpeers", EVENT_FLAG_SYSTEM, manager_sip_show_peers,
- "List SIP peers (text format)", mandescr_show_peers);
- ast_manager_register2("SIPshowpeer", EVENT_FLAG_SYSTEM, manager_sip_show_peer,
- "Show SIP peer (text format)", mandescr_show_peer);
-
- sip_poke_all_peers();
- sip_send_all_registers();
-
- /* And start the monitor for the first time */
- restart_monitor();
-
- return AST_MODULE_LOAD_SUCCESS;
-}
-
-/*! \brief PBX unload module API */
-static int unload_module(void)
-{
- struct sip_pvt *p, *pl;
-
- /* First, take us out of the channel type list */
- ast_channel_unregister(&sip_tech);
-
- /* Unregister dial plan functions */
- ast_custom_function_unregister(&sipchaninfo_function);
- ast_custom_function_unregister(&sippeer_function);
- ast_custom_function_unregister(&sip_header_function);
- ast_custom_function_unregister(&checksipdomain_function);
-
- /* Unregister dial plan applications */
- ast_unregister_application(app_dtmfmode);
- ast_unregister_application(app_sipaddheader);
-
- /* Unregister CLI commands */
- ast_cli_unregister_multiple(cli_sip, sizeof(cli_sip) / sizeof(struct ast_cli_entry));
-
- /* Disconnect from the RTP subsystem */
- ast_rtp_proto_unregister(&sip_rtp);
-
- /* Disconnect from UDPTL */
- ast_udptl_proto_unregister(&sip_udptl);
-
- /* Unregister AMI actions */
- ast_manager_unregister("SIPpeers");
- ast_manager_unregister("SIPshowpeer");
-
- ast_mutex_lock(&iflock);
- /* Hangup all interfaces if they have an owner */
- for (p = iflist; p ; p = p->next) {
- if (p->owner)
- ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
- }
- ast_mutex_unlock(&iflock);
-
- ast_mutex_lock(&monlock);
- if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP) && (monitor_thread != AST_PTHREADT_NULL)) {
- pthread_cancel(monitor_thread);
- pthread_kill(monitor_thread, SIGURG);
- pthread_join(monitor_thread, NULL);
- }
- monitor_thread = AST_PTHREADT_STOP;
- ast_mutex_unlock(&monlock);
-
-restartdestroy:
- ast_mutex_lock(&iflock);
- /* Destroy all the interfaces and free their memory */
- p = iflist;
- while (p) {
- pl = p;
- p = p->next;
- if (__sip_destroy(pl, TRUE) < 0) {
- /* Something is still bridged, let it react to getting a hangup */
- iflist = p;
- ast_mutex_unlock(&iflock);
- usleep(1);
- goto restartdestroy;
- }
- }
- iflist = NULL;
- ast_mutex_unlock(&iflock);
-
- /* Free memory for local network address mask */
- ast_free_ha(localaddr);
-
- ASTOBJ_CONTAINER_DESTROYALL(&userl, sip_destroy_user);
- ASTOBJ_CONTAINER_DESTROY(&userl);
- ASTOBJ_CONTAINER_DESTROYALL(&peerl, sip_destroy_peer);
- ASTOBJ_CONTAINER_DESTROY(&peerl);
- ASTOBJ_CONTAINER_DESTROYALL(&regl, sip_registry_destroy);
- ASTOBJ_CONTAINER_DESTROY(&regl);
-
- clear_realm_authentication(authl);
- clear_sip_domains();
- close(sipsock);
- sched_context_destroy(sched);
-
- return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Session Initiation Protocol (SIP)",
- .load = load_module,
- .unload = unload_module,
- .reload = reload,
- );
diff --git a/1.4.23-rc4/channels/chan_skinny.c b/1.4.23-rc4/channels/chan_skinny.c
deleted file mode 100644
index 657163398..000000000
--- a/1.4.23-rc4/channels/chan_skinny.c
+++ /dev/null
@@ -1,5016 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 1999 - 2005, Digium, Inc.
- *
- * chan_skinny was developed by Jeremy McNamara & Florian Overkamp
- * chan_skinny was heavily modified/fixed by North Antara
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Implementation of the Skinny protocol
- *
- * \author Jeremy McNamara & Florian Overkamp & North Antara
- * \ingroup channel_drivers
- */
-
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <sys/ioctl.h>
-#include <net/if.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <netdb.h>
-#include <arpa/inet.h>
-#include <sys/signal.h>
-#include <signal.h>
-#include <ctype.h>
-
-#include "asterisk/lock.h"
-#include "asterisk/channel.h"
-#include "asterisk/config.h"
-#include "asterisk/logger.h"
-#include "asterisk/module.h"
-#include "asterisk/pbx.h"
-#include "asterisk/options.h"
-#include "asterisk/lock.h"
-#include "asterisk/sched.h"
-#include "asterisk/io.h"
-#include "asterisk/rtp.h"
-#include "asterisk/acl.h"
-#include "asterisk/callerid.h"
-#include "asterisk/cli.h"
-#include "asterisk/say.h"
-#include "asterisk/cdr.h"
-#include "asterisk/astdb.h"
-#include "asterisk/features.h"
-#include "asterisk/app.h"
-#include "asterisk/musiconhold.h"
-#include "asterisk/utils.h"
-#include "asterisk/dsp.h"
-#include "asterisk/stringfields.h"
-#include "asterisk/astobj.h"
-#include "asterisk/abstract_jb.h"
-#include "asterisk/threadstorage.h"
-
-/*************************************
- * Skinny/Asterisk Protocol Settings *
- *************************************/
-static const char tdesc[] = "Skinny Client Control Protocol (Skinny)";
-static const char config[] = "skinny.conf";
-
-static int default_capability = AST_FORMAT_ULAW | AST_FORMAT_ALAW;
-static struct ast_codec_pref default_prefs;
-
-enum skinny_codecs {
- SKINNY_CODEC_ALAW = 2,
- SKINNY_CODEC_ULAW = 4,
- SKINNY_CODEC_G723_1 = 9,
- SKINNY_CODEC_G729A = 12,
- SKINNY_CODEC_G726_32 = 82, /* XXX Which packing order does this translate to? */
- SKINNY_CODEC_H261 = 100,
- SKINNY_CODEC_H263 = 101
-};
-
-#define DEFAULT_SKINNY_PORT 2000
-#define DEFAULT_SKINNY_BACKLOG 2
-#define SKINNY_MAX_PACKET 1000
-
-static int keep_alive = 120;
-static char date_format[6] = "D-M-Y";
-static char version_id[16] = "P002F202";
-
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-#define letohl(x) (x)
-#define letohs(x) (x)
-#define htolel(x) (x)
-#define htoles(x) (x)
-#else
-#if defined(SOLARIS) || defined(__Darwin__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
-#define __bswap_16(x) \
- ((((x) & 0xff00) >> 8) | \
- (((x) & 0x00ff) << 8))
-#define __bswap_32(x) \
- ((((x) & 0xff000000) >> 24) | \
- (((x) & 0x00ff0000) >> 8) | \
- (((x) & 0x0000ff00) << 8) | \
- (((x) & 0x000000ff) << 24))
-#else
-#include <bits/byteswap.h>
-#endif
-#define letohl(x) __bswap_32(x)
-#define letohs(x) __bswap_16(x)
-#define htolel(x) __bswap_32(x)
-#define htoles(x) __bswap_16(x)
-#endif
-
-/*! Global jitterbuffer configuration - by default, jb is disabled */
-static struct ast_jb_conf default_jbconf =
-{
- .flags = 0,
- .max_size = -1,
- .resync_threshold = -1,
- .impl = ""
-};
-static struct ast_jb_conf global_jbconf;
-
-AST_THREADSTORAGE(device2str_threadbuf, device2str_threadbuf_init);
-#define DEVICE2STR_BUFSIZE 15
-
-AST_THREADSTORAGE(control2str_threadbuf, control2str_threadbuf_init);
-#define CONTROL2STR_BUFSIZE 100
-
-/*********************
- * Protocol Messages *
- *********************/
-/* message types */
-#define KEEP_ALIVE_MESSAGE 0x0000
-/* no additional struct */
-
-#define REGISTER_MESSAGE 0x0001
-struct register_message {
- char name[16];
- uint32_t userId;
- uint32_t instance;
- uint32_t ip;
- uint32_t type;
- uint32_t maxStreams;
-};
-
-#define IP_PORT_MESSAGE 0x0002
-
-#define KEYPAD_BUTTON_MESSAGE 0x0003
-struct keypad_button_message {
- uint32_t button;
- uint32_t lineInstance;
- uint32_t callReference;
-};
-
-
-#define ENBLOC_CALL_MESSAGE 0x0004
-struct enbloc_call_message {
- char calledParty[24];
-};
-
-#define STIMULUS_MESSAGE 0x0005
-struct stimulus_message {
- uint32_t stimulus;
- uint32_t stimulusInstance;
- uint32_t callreference;
-};
-
-#define OFFHOOK_MESSAGE 0x0006
-struct offhook_message {
- uint32_t unknown1;
- uint32_t unknown2;
-};
-
-#define ONHOOK_MESSAGE 0x0007
-struct onhook_message {
- uint32_t unknown1;
- uint32_t unknown2;
-};
-
-#define CAPABILITIES_RES_MESSAGE 0x0010
-struct station_capabilities {
- uint32_t codec;
- uint32_t frames;
- union {
- char res[8];
- uint32_t rate;
- } payloads;
-};
-
-#define SKINNY_MAX_CAPABILITIES 18
-
-struct capabilities_res_message {
- uint32_t count;
- struct station_capabilities caps[SKINNY_MAX_CAPABILITIES];
-};
-
-#define SPEED_DIAL_STAT_REQ_MESSAGE 0x000A
-struct speed_dial_stat_req_message {
- uint32_t speedDialNumber;
-};
-
-#define LINE_STATE_REQ_MESSAGE 0x000B
-struct line_state_req_message {
- uint32_t lineNumber;
-};
-
-#define TIME_DATE_REQ_MESSAGE 0x000D
-#define BUTTON_TEMPLATE_REQ_MESSAGE 0x000E
-#define VERSION_REQ_MESSAGE 0x000F
-#define SERVER_REQUEST_MESSAGE 0x0012
-
-#define ALARM_MESSAGE 0x0020
-struct alarm_message {
- uint32_t alarmSeverity;
- char displayMessage[80];
- uint32_t alarmParam1;
- uint32_t alarmParam2;
-};
-
-#define OPEN_RECEIVE_CHANNEL_ACK_MESSAGE 0x0022
-struct open_receive_channel_ack_message {
- uint32_t status;
- uint32_t ipAddr;
- uint32_t port;
- uint32_t passThruId;
-};
-
-#define SOFT_KEY_SET_REQ_MESSAGE 0x0025
-
-#define SOFT_KEY_EVENT_MESSAGE 0x0026
-struct soft_key_event_message {
- uint32_t softKeyEvent;
- uint32_t instance;
- uint32_t callreference;
-};
-
-#define UNREGISTER_MESSAGE 0x0027
-#define SOFT_KEY_TEMPLATE_REQ_MESSAGE 0x0028
-#define HEADSET_STATUS_MESSAGE 0x002B
-#define REGISTER_AVAILABLE_LINES_MESSAGE 0x002D
-
-#define REGISTER_ACK_MESSAGE 0x0081
-struct register_ack_message {
- uint32_t keepAlive;
- char dateTemplate[6];
- char res[2];
- uint32_t secondaryKeepAlive;
- char res2[4];
-};
-
-#define START_TONE_MESSAGE 0x0082
-struct start_tone_message {
- uint32_t tone;
- uint32_t space;
- uint32_t instance;
- uint32_t reference;
-};
-
-#define STOP_TONE_MESSAGE 0x0083
-struct stop_tone_message {
- uint32_t instance;
- uint32_t reference;
-};
-
-#define SET_RINGER_MESSAGE 0x0085
-struct set_ringer_message {
- uint32_t ringerMode;
- uint32_t unknown1; /* See notes in transmit_ringer_mode */
- uint32_t unknown2;
- uint32_t space[2];
-};
-
-#define SET_LAMP_MESSAGE 0x0086
-struct set_lamp_message {
- uint32_t stimulus;
- uint32_t stimulusInstance;
- uint32_t deviceStimulus;
-};
-
-#define SET_SPEAKER_MESSAGE 0x0088
-struct set_speaker_message {
- uint32_t mode;
-};
-
-/* XXX When do we need to use this? */
-#define SET_MICROPHONE_MESSAGE 0x0089
-struct set_microphone_message {
- uint32_t mode;
-};
-
-#define START_MEDIA_TRANSMISSION_MESSAGE 0x008A
-struct media_qualifier {
- uint32_t precedence;
- uint32_t vad;
- uint16_t packets;
- uint32_t bitRate;
-};
-
-struct start_media_transmission_message {
- uint32_t conferenceId;
- uint32_t passThruPartyId;
- uint32_t remoteIp;
- uint32_t remotePort;
- uint32_t packetSize;
- uint32_t payloadType;
- struct media_qualifier qualifier;
- uint32_t space[16];
-};
-
-#define STOP_MEDIA_TRANSMISSION_MESSAGE 0x008B
-struct stop_media_transmission_message {
- uint32_t conferenceId;
- uint32_t passThruPartyId;
- uint32_t space[3];
-};
-
-#define CALL_INFO_MESSAGE 0x008F
-struct call_info_message {
- char callingPartyName[40];
- char callingParty[24];
- char calledPartyName[40];
- char calledParty[24];
- uint32_t instance;
- uint32_t reference;
- uint32_t type;
- char originalCalledPartyName[40];
- char originalCalledParty[24];
- char lastRedirectingPartyName[40];
- char lastRedirectingParty[24];
- uint32_t originalCalledPartyRedirectReason;
- uint32_t lastRedirectingReason;
- char callingPartyVoiceMailbox[24];
- char calledPartyVoiceMailbox[24];
- char originalCalledPartyVoiceMailbox[24];
- char lastRedirectingVoiceMailbox[24];
- uint32_t space[3];
-};
-
-#define SPEED_DIAL_STAT_RES_MESSAGE 0x0091
-struct speed_dial_stat_res_message {
- uint32_t speedDialNumber;
- char speedDialDirNumber[24];
- char speedDialDisplayName[40];
-};
-
-#define LINE_STAT_RES_MESSAGE 0x0092
-struct line_stat_res_message {
- uint32_t lineNumber;
- char lineDirNumber[24];
- char lineDisplayName[24];
- uint32_t space[15];
-};
-
-#define DEFINETIMEDATE_MESSAGE 0x0094
-struct definetimedate_message {
- uint32_t year; /* since 1900 */
- uint32_t month;
- uint32_t dayofweek; /* monday = 1 */
- uint32_t day;
- uint32_t hour;
- uint32_t minute;
- uint32_t seconds;
- uint32_t milliseconds;
- uint32_t timestamp;
-};
-
-#define BUTTON_TEMPLATE_RES_MESSAGE 0x0097
-struct button_definition {
- uint8_t instanceNumber;
- uint8_t buttonDefinition;
-};
-
-struct button_definition_template {
- uint8_t buttonDefinition;
- /* for now, anything between 0xB0 and 0xCF is custom */
- /*int custom;*/
-};
-
-#define STIMULUS_REDIAL 0x01
-#define STIMULUS_SPEEDDIAL 0x02
-#define STIMULUS_HOLD 0x03
-#define STIMULUS_TRANSFER 0x04
-#define STIMULUS_FORWARDALL 0x05
-#define STIMULUS_FORWARDBUSY 0x06
-#define STIMULUS_FORWARDNOANSWER 0x07
-#define STIMULUS_DISPLAY 0x08
-#define STIMULUS_LINE 0x09
-#define STIMULUS_VOICEMAIL 0x0F
-#define STIMULUS_AUTOANSWER 0x11
-#define STIMULUS_CONFERENCE 0x7D
-#define STIMULUS_CALLPARK 0x7E
-#define STIMULUS_CALLPICKUP 0x7F
-#define STIMULUS_NONE 0xFF
-
-/* Button types */
-#define BT_REDIAL STIMULUS_REDIAL
-#define BT_SPEEDDIAL STIMULUS_SPEEDDIAL
-#define BT_HOLD STIMULUS_HOLD
-#define BT_TRANSFER STIMULUS_TRANSFER
-#define BT_FORWARDALL STIMULUS_FORWARDALL
-#define BT_FORWARDBUSY STIMULUS_FORWARDBUSY
-#define BT_FORWARDNOANSWER STIMULUS_FORWARDNOANSWER
-#define BT_DISPLAY STIMULUS_DISPLAY
-#define BT_LINE STIMULUS_LINE
-#define BT_VOICEMAIL STIMULUS_VOICEMAIL
-#define BT_AUTOANSWER STIMULUS_AUTOANSWER
-#define BT_CONFERENCE STIMULUS_CONFERENCE
-#define BT_CALLPARK STIMULUS_CALLPARK
-#define BT_CALLPICKUP STIMULUS_CALLPICKUP
-#define BT_NONE 0x00
-
-/* Custom button types - add our own between 0xB0 and 0xCF.
- This may need to be revised in the future,
- if stimuluses are ever added in this range. */
-#define BT_CUST_LINESPEEDDIAL 0xB0 /* line or speeddial */
-#define BT_CUST_HINT 0xB1 /* pipe dream */
-
-struct button_template_res_message {
- uint32_t buttonOffset;
- uint32_t buttonCount;
- uint32_t totalButtonCount;
- struct button_definition definition[42];
-};
-
-#define VERSION_RES_MESSAGE 0x0098
-struct version_res_message {
- char version[16];
-};
-
-#define DISPLAYTEXT_MESSAGE 0x0099
-struct displaytext_message {
- char text[40];
-};
-
-#define CLEAR_NOTIFY_MESSAGE 0x0115
-#define CLEAR_DISPLAY_MESSAGE 0x009A
-
-#define CAPABILITIES_REQ_MESSAGE 0x009B
-
-#define REGISTER_REJ_MESSAGE 0x009D
-struct register_rej_message {
- char errMsg[33];
-};
-
-#define SERVER_RES_MESSAGE 0x009E
-struct server_identifier {
- char serverName[48];
-};
-
-struct server_res_message {
- struct server_identifier server[5];
- uint32_t serverListenPort[5];
- uint32_t serverIpAddr[5];
-};
-
-#define RESET_MESSAGE 0x009F
-struct reset_message {
- uint32_t resetType;
-};
-
-#define KEEP_ALIVE_ACK_MESSAGE 0x0100
-
-#define OPEN_RECEIVE_CHANNEL_MESSAGE 0x0105
-struct open_receive_channel_message {
- uint32_t conferenceId;
- uint32_t partyId;
- uint32_t packets;
- uint32_t capability;
- uint32_t echo;
- uint32_t bitrate;
- uint32_t space[16];
-};
-
-#define CLOSE_RECEIVE_CHANNEL_MESSAGE 0x0106
-struct close_receive_channel_message {
- uint32_t conferenceId;
- uint32_t partyId;
- uint32_t space[2];
-};
-
-#define SOFT_KEY_TEMPLATE_RES_MESSAGE 0x0108
-
-struct soft_key_template_definition {
- char softKeyLabel[16];
- uint32_t softKeyEvent;
-};
-
-#define KEYDEF_ONHOOK 0
-#define KEYDEF_CONNECTED 1
-#define KEYDEF_ONHOLD 2
-#define KEYDEF_RINGIN 3
-#define KEYDEF_OFFHOOK 4
-#define KEYDEF_CONNWITHTRANS 5
-#define KEYDEF_DADFD 6 /* Digits After Dialing First Digit */
-#define KEYDEF_CONNWITHCONF 7
-#define KEYDEF_RINGOUT 8
-#define KEYDEF_OFFHOOKWITHFEAT 9
-#define KEYDEF_UNKNOWN 10
-
-#define SOFTKEY_NONE 0x00
-#define SOFTKEY_REDIAL 0x01
-#define SOFTKEY_NEWCALL 0x02
-#define SOFTKEY_HOLD 0x03
-#define SOFTKEY_TRNSFER 0x04
-#define SOFTKEY_CFWDALL 0x05
-#define SOFTKEY_CFWDBUSY 0x06
-#define SOFTKEY_CFWDNOANSWER 0x07
-#define SOFTKEY_BKSPC 0x08
-#define SOFTKEY_ENDCALL 0x09
-#define SOFTKEY_RESUME 0x0A
-#define SOFTKEY_ANSWER 0x0B
-#define SOFTKEY_INFO 0x0C
-#define SOFTKEY_CONFRN 0x0D
-#define SOFTKEY_PARK 0x0E
-#define SOFTKEY_JOIN 0x0F
-#define SOFTKEY_MEETME 0x10
-#define SOFTKEY_PICKUP 0x11
-#define SOFTKEY_GPICKUP 0x12
-
-struct soft_key_template_definition soft_key_template_default[] = {
- { "Redial", 0x01 },
- { "NewCall", 0x02 },
- { "Hold", 0x03 },
- { "Trnsfer", 0x04 },
- { "CFwdAll", 0x05 },
- { "CFwdBusy", 0x06 },
- { "CFwdNoAnswer", 0x07 },
- { "<<", 0x08 },
- { "EndCall", 0x09 },
- { "Resume", 0x0A },
- { "Answer", 0x0B },
- { "Info", 0x0C },
- { "Confrn", 0x0D },
- { "Park", 0x0E },
- { "Join", 0x0F },
- { "MeetMe", 0x10 },
- { "PickUp", 0x11 },
- { "GPickUp", 0x12 },
-};
-
-struct soft_key_definitions {
- const uint8_t mode;
- const uint8_t *defaults;
- const int count;
-};
-
-static const uint8_t soft_key_default_onhook[] = {
- SOFTKEY_REDIAL,
- SOFTKEY_NEWCALL,
- SOFTKEY_CFWDALL,
- SOFTKEY_CFWDBUSY,
- /*SOFTKEY_GPICKUP,
- SOFTKEY_CONFRN,*/
-};
-
-static const uint8_t soft_key_default_connected[] = {
- SOFTKEY_HOLD,
- SOFTKEY_ENDCALL,
- SOFTKEY_TRNSFER,
- SOFTKEY_PARK,
- SOFTKEY_CFWDALL,
- SOFTKEY_CFWDBUSY,
-};
-
-static const uint8_t soft_key_default_onhold[] = {
- SOFTKEY_RESUME,
- SOFTKEY_NEWCALL,
- SOFTKEY_ENDCALL,
- SOFTKEY_TRNSFER,
-};
-
-static const uint8_t soft_key_default_ringin[] = {
- SOFTKEY_ANSWER,
- SOFTKEY_ENDCALL,
- SOFTKEY_TRNSFER,
-};
-
-static const uint8_t soft_key_default_offhook[] = {
- SOFTKEY_REDIAL,
- SOFTKEY_ENDCALL,
- SOFTKEY_CFWDALL,
- SOFTKEY_CFWDBUSY,
- /*SOFTKEY_GPICKUP,*/
-};
-
-static const uint8_t soft_key_default_connwithtrans[] = {
- SOFTKEY_HOLD,
- SOFTKEY_ENDCALL,
- SOFTKEY_TRNSFER,
- SOFTKEY_PARK,
- SOFTKEY_CFWDALL,
- SOFTKEY_CFWDBUSY,
-};
-
-static const uint8_t soft_key_default_dadfd[] = {
- SOFTKEY_BKSPC,
- SOFTKEY_ENDCALL,
-};
-
-static const uint8_t soft_key_default_connwithconf[] = {
- SOFTKEY_NONE,
-};
-
-static const uint8_t soft_key_default_ringout[] = {
- SOFTKEY_NONE,
- SOFTKEY_ENDCALL,
-};
-
-static const uint8_t soft_key_default_offhookwithfeat[] = {
- SOFTKEY_REDIAL,
- SOFTKEY_ENDCALL,
-};
-
-static const uint8_t soft_key_default_unknown[] = {
- SOFTKEY_NONE,
-};
-
-static const struct soft_key_definitions soft_key_default_definitions[] = {
- {KEYDEF_ONHOOK, soft_key_default_onhook, sizeof(soft_key_default_onhook) / sizeof(uint8_t)},
- {KEYDEF_CONNECTED, soft_key_default_connected, sizeof(soft_key_default_connected) / sizeof(uint8_t)},
- {KEYDEF_ONHOLD, soft_key_default_onhold, sizeof(soft_key_default_onhold) / sizeof(uint8_t)},
- {KEYDEF_RINGIN, soft_key_default_ringin, sizeof(soft_key_default_ringin) / sizeof(uint8_t)},
- {KEYDEF_OFFHOOK, soft_key_default_offhook, sizeof(soft_key_default_offhook) / sizeof(uint8_t)},
- {KEYDEF_CONNWITHTRANS, soft_key_default_connwithtrans, sizeof(soft_key_default_connwithtrans) / sizeof(uint8_t)},
- {KEYDEF_DADFD, soft_key_default_dadfd, sizeof(soft_key_default_dadfd) / sizeof(uint8_t)},
- {KEYDEF_CONNWITHCONF, soft_key_default_connwithconf, sizeof(soft_key_default_connwithconf) / sizeof(uint8_t)},
- {KEYDEF_RINGOUT, soft_key_default_ringout, sizeof(soft_key_default_ringout) / sizeof(uint8_t)},
- {KEYDEF_OFFHOOKWITHFEAT, soft_key_default_offhookwithfeat, sizeof(soft_key_default_offhookwithfeat) / sizeof(uint8_t)},
- {KEYDEF_UNKNOWN, soft_key_default_unknown, sizeof(soft_key_default_unknown) / sizeof(uint8_t)}
-};
-
-struct soft_key_template_res_message {
- uint32_t softKeyOffset;
- uint32_t softKeyCount;
- uint32_t totalSoftKeyCount;
- struct soft_key_template_definition softKeyTemplateDefinition[32];
-};
-
-#define SOFT_KEY_SET_RES_MESSAGE 0x0109
-
-struct soft_key_set_definition {
- uint8_t softKeyTemplateIndex[16];
- uint16_t softKeyInfoIndex[16];
-};
-
-struct soft_key_set_res_message {
- uint32_t softKeySetOffset;
- uint32_t softKeySetCount;
- uint32_t totalSoftKeySetCount;
- struct soft_key_set_definition softKeySetDefinition[16];
- uint32_t res;
-};
-
-#define SELECT_SOFT_KEYS_MESSAGE 0x0110
-struct select_soft_keys_message {
- uint32_t instance;
- uint32_t reference;
- uint32_t softKeySetIndex;
- uint32_t validKeyMask;
-};
-
-#define CALL_STATE_MESSAGE 0x0111
-struct call_state_message {
- uint32_t callState;
- uint32_t lineInstance;
- uint32_t callReference;
- uint32_t space[3];
-};
-
-#define DISPLAY_PROMPT_STATUS_MESSAGE 0x0112
-struct display_prompt_status_message {
- uint32_t messageTimeout;
- char promptMessage[32];
- uint32_t lineInstance;
- uint32_t callReference;
-};
-
-#define CLEAR_PROMPT_MESSAGE 0x0113
-struct clear_prompt_message {
- uint32_t lineInstance;
- uint32_t callReference;
-};
-
-#define DISPLAY_NOTIFY_MESSAGE 0x0114
-struct display_notify_message {
- uint32_t displayTimeout;
- char displayMessage[100];
-};
-
-#define ACTIVATE_CALL_PLANE_MESSAGE 0x0116
-struct activate_call_plane_message {
- uint32_t lineInstance;
-};
-
-#define DIALED_NUMBER_MESSAGE 0x011D
-struct dialed_number_message {
- char dialedNumber[24];
- uint32_t lineInstance;
- uint32_t callReference;
-};
-
-union skinny_data {
- struct alarm_message alarm;
- struct speed_dial_stat_req_message speeddialreq;
- struct register_message reg;
- struct register_ack_message regack;
- struct register_rej_message regrej;
- struct capabilities_res_message caps;
- struct version_res_message version;
- struct button_template_res_message buttontemplate;
- struct displaytext_message displaytext;
- struct display_prompt_status_message displaypromptstatus;
- struct clear_prompt_message clearpromptstatus;
- struct definetimedate_message definetimedate;
- struct start_tone_message starttone;
- struct stop_tone_message stoptone;
- struct speed_dial_stat_res_message speeddial;
- struct line_state_req_message line;
- struct line_stat_res_message linestat;
- struct soft_key_set_res_message softkeysets;
- struct soft_key_template_res_message softkeytemplate;
- struct server_res_message serverres;
- struct reset_message reset;
- struct set_lamp_message setlamp;
- struct set_ringer_message setringer;
- struct call_state_message callstate;
- struct keypad_button_message keypad;
- struct select_soft_keys_message selectsoftkey;
- struct activate_call_plane_message activatecallplane;
- struct stimulus_message stimulus;
- struct offhook_message offhook;
- struct onhook_message onhook;
- struct set_speaker_message setspeaker;
- struct set_microphone_message setmicrophone;
- struct call_info_message callinfo;
- struct start_media_transmission_message startmedia;
- struct stop_media_transmission_message stopmedia;
- struct open_receive_channel_message openreceivechannel;
- struct open_receive_channel_ack_message openreceivechannelack;
- struct close_receive_channel_message closereceivechannel;
- struct display_notify_message displaynotify;
- struct dialed_number_message dialednumber;
- struct soft_key_event_message softkeyeventmessage;
- struct enbloc_call_message enbloccallmessage;
-};
-
-/* packet composition */
-struct skinny_req {
- int len;
- int res;
- int e;
- union skinny_data data;
-};
-
-/* XXX This is the combined size of the variables above. (len, res, e)
- If more are added, this MUST change.
- (sizeof(skinny_req) - sizeof(skinny_data)) DOES NOT WORK on all systems (amd64?). */
-int skinny_header_size = 12;
-
-/*****************************
- * Asterisk specific globals *
- *****************************/
-
-static int skinnydebug = 0;
-
-/* a hostname, portnumber, socket and such is usefull for VoIP protocols */
-static struct sockaddr_in bindaddr;
-static char ourhost[256];
-static int ourport;
-static struct in_addr __ourip;
-struct ast_hostent ahp;
-struct hostent *hp;
-static int skinnysock = -1;
-static pthread_t accept_t;
-static char context[AST_MAX_CONTEXT] = "default";
-static char language[MAX_LANGUAGE] = "";
-static char mohinterpret[MAX_MUSICCLASS] = "default";
-static char mohsuggest[MAX_MUSICCLASS] = "";
-static char cid_num[AST_MAX_EXTENSION] = "";
-static char cid_name[AST_MAX_EXTENSION] = "";
-static char linelabel[AST_MAX_EXTENSION] ="";
-static int nat = 0;
-static ast_group_t cur_callergroup = 0;
-static ast_group_t cur_pickupgroup = 0;
-static int immediate = 0;
-static int callwaiting = 0;
-static int callreturn = 0;
-static int threewaycalling = 0;
-static int mwiblink = 0;
-/* This is for flashhook transfers */
-static int transfer = 0;
-static int cancallforward = 0;
-/* static int busycount = 3;*/
-static char accountcode[AST_MAX_ACCOUNT_CODE] = "";
-static char mailbox[AST_MAX_EXTENSION];
-static int amaflags = 0;
-static int callnums = 1;
-
-#define SKINNY_DEVICE_UNKNOWN -1
-#define SKINNY_DEVICE_NONE 0
-#define SKINNY_DEVICE_30SPPLUS 1
-#define SKINNY_DEVICE_12SPPLUS 2
-#define SKINNY_DEVICE_12SP 3
-#define SKINNY_DEVICE_12 4
-#define SKINNY_DEVICE_30VIP 5
-#define SKINNY_DEVICE_7910 6
-#define SKINNY_DEVICE_7960 7
-#define SKINNY_DEVICE_7940 8
-#define SKINNY_DEVICE_7935 9
-#define SKINNY_DEVICE_ATA186 12 /* Cisco ATA-186 */
-#define SKINNY_DEVICE_7941 115
-#define SKINNY_DEVICE_7971 119
-#define SKINNY_DEVICE_7914 124 /* Expansion module */
-#define SKINNY_DEVICE_7985 302
-#define SKINNY_DEVICE_7911 307
-#define SKINNY_DEVICE_7961GE 308
-#define SKINNY_DEVICE_7941GE 309
-#define SKINNY_DEVICE_7931 348
-#define SKINNY_DEVICE_7921 365
-#define SKINNY_DEVICE_7906 369
-#define SKINNY_DEVICE_7962 404 /* Not found */
-#define SKINNY_DEVICE_7937 431
-#define SKINNY_DEVICE_7942 434
-#define SKINNY_DEVICE_7945 435
-#define SKINNY_DEVICE_7965 436
-#define SKINNY_DEVICE_7975 437
-#define SKINNY_DEVICE_7905 20000
-#define SKINNY_DEVICE_7920 30002
-#define SKINNY_DEVICE_7970 30006
-#define SKINNY_DEVICE_7912 30007
-#define SKINNY_DEVICE_7902 30008
-#define SKINNY_DEVICE_CIPC 30016 /* Cisco IP Communicator */
-#define SKINNY_DEVICE_7961 30018
-#define SKINNY_DEVICE_7936 30019
-#define SKINNY_DEVICE_SCCPGATEWAY_AN 30027 /* ??? */
-#define SKINNY_DEVICE_SCCPGATEWAY_BRI 30028 /* ??? */
-
-#define SKINNY_SPEAKERON 1
-#define SKINNY_SPEAKEROFF 2
-
-#define SKINNY_MICON 1
-#define SKINNY_MICOFF 2
-
-#define SKINNY_OFFHOOK 1
-#define SKINNY_ONHOOK 2
-#define SKINNY_RINGOUT 3
-#define SKINNY_RINGIN 4
-#define SKINNY_CONNECTED 5
-#define SKINNY_BUSY 6
-#define SKINNY_CONGESTION 7
-#define SKINNY_HOLD 8
-#define SKINNY_CALLWAIT 9
-#define SKINNY_TRANSFER 10
-#define SKINNY_PARK 11
-#define SKINNY_PROGRESS 12
-#define SKINNY_INVALID 14
-
-#define SKINNY_SILENCE 0x00
-#define SKINNY_DIALTONE 0x21
-#define SKINNY_BUSYTONE 0x23
-#define SKINNY_ALERT 0x24
-#define SKINNY_REORDER 0x25
-#define SKINNY_CALLWAITTONE 0x2D
-#define SKINNY_NOTONE 0x7F
-
-#define SKINNY_LAMP_OFF 1
-#define SKINNY_LAMP_ON 2
-#define SKINNY_LAMP_WINK 3
-#define SKINNY_LAMP_FLASH 4
-#define SKINNY_LAMP_BLINK 5
-
-#define SKINNY_RING_OFF 1
-#define SKINNY_RING_INSIDE 2
-#define SKINNY_RING_OUTSIDE 3
-#define SKINNY_RING_FEATURE 4
-
-#define TYPE_TRUNK 1
-#define TYPE_LINE 2
-
-/* Skinny rtp stream modes. Do we really need this? */
-#define SKINNY_CX_SENDONLY 0
-#define SKINNY_CX_RECVONLY 1
-#define SKINNY_CX_SENDRECV 2
-#define SKINNY_CX_CONF 3
-#define SKINNY_CX_CONFERENCE 3
-#define SKINNY_CX_MUTE 4
-#define SKINNY_CX_INACTIVE 4
-
-#if 0
-static char *skinny_cxmodes[] = {
- "sendonly",
- "recvonly",
- "sendrecv",
- "confrnce",
- "inactive"
-};
-#endif
-
-/* driver scheduler */
-static struct sched_context *sched = NULL;
-static struct io_context *io;
-
-/* Protect the monitoring thread, so only one process can kill or start it, and not
- when it's doing something critical. */
-AST_MUTEX_DEFINE_STATIC(monlock);
-/* Protect the network socket */
-AST_MUTEX_DEFINE_STATIC(netlock);
-/* Protect the session list */
-AST_MUTEX_DEFINE_STATIC(sessionlock);
-/* Protect the device list */
-AST_MUTEX_DEFINE_STATIC(devicelock);
-#if 0
-/* Protect the paging device list */
-AST_MUTEX_DEFINE_STATIC(pagingdevicelock);
-#endif
-
-/* This is the thread for the monitor which checks for input on the channels
- which are not currently in use. */
-static pthread_t monitor_thread = AST_PTHREADT_NULL;
-
-/* Wait up to 16 seconds for first digit */
-static int firstdigittimeout = 16000;
-
-/* How long to wait for following digits */
-static int gendigittimeout = 8000;
-
-/* How long to wait for an extra digit, if there is an ambiguous match */
-static int matchdigittimeout = 3000;
-
-struct skinny_subchannel {
- ast_mutex_t lock;
- struct ast_channel *owner;
- struct ast_rtp *rtp;
- struct ast_rtp *vrtp;
- unsigned int callid;
- /* time_t lastouttime; */ /* Unused */
- int progress;
- int ringing;
- int onhold;
- /* int lastout; */ /* Unused */
- int cxmode;
- int nat;
- int outgoing;
- int alreadygone;
-
- struct skinny_subchannel *next;
- struct skinny_line *parent;
-};
-
-struct skinny_line {
- ast_mutex_t lock;
- char name[80];
- char label[24]; /* Label that shows next to the line buttons */
- char accountcode[AST_MAX_ACCOUNT_CODE];
- char exten[AST_MAX_EXTENSION]; /* Extension where to start */
- char context[AST_MAX_CONTEXT];
- char language[MAX_LANGUAGE];
- char cid_num[AST_MAX_EXTENSION]; /* Caller*ID */
- char cid_name[AST_MAX_EXTENSION]; /* Caller*ID */
- char lastcallerid[AST_MAX_EXTENSION]; /* Last Caller*ID */
- char call_forward[AST_MAX_EXTENSION];
- char mailbox[AST_MAX_EXTENSION];
- char mohinterpret[MAX_MUSICCLASS];
- char mohsuggest[MAX_MUSICCLASS];
- char lastnumberdialed[AST_MAX_EXTENSION]; /* Last number that was dialed - used for redial */
- int curtone; /* Current tone being played */
- ast_group_t callgroup;
- ast_group_t pickupgroup;
- int callwaiting;
- int transfer;
- int threewaycalling;
- int mwiblink;
- int cancallforward;
- int callreturn;
- int dnd; /* How does this affect callwait? Do we just deny a skinny_request if we're dnd? */
- int hascallerid;
- int hidecallerid;
- int amaflags;
- int type;
- int instance;
- int group;
- int needdestroy;
- int capability;
- int nonCodecCapability;
- int onhooktime;
- int msgstate; /* voicemail message state */
- int immediate;
- int hookstate;
- int nat;
-
- struct ast_codec_pref prefs;
- struct skinny_subchannel *sub;
- struct skinny_line *next;
- struct skinny_device *parent;
-};
-
-struct skinny_speeddial {
- ast_mutex_t lock;
- char label[42];
- char exten[AST_MAX_EXTENSION];
- int instance;
-
- struct skinny_speeddial *next;
- struct skinny_device *parent;
-};
-
-struct skinny_addon {
- ast_mutex_t lock;
- char type[10];
-
- struct skinny_addon *next;
- struct skinny_device *parent;
-};
-
-static struct skinny_device {
- /* A device containing one or more lines */
- char name[80];
- char id[16];
- char version_id[16];
- int type;
- int registered;
- int lastlineinstance;
- int lastcallreference;
- int capability;
- int earlyrtp;
- char exten[AST_MAX_EXTENSION];
- struct sockaddr_in addr;
- struct in_addr ourip;
- struct skinny_line *lines;
- struct skinny_speeddial *speeddials;
- struct skinny_addon *addons;
- struct ast_codec_pref prefs;
- struct ast_ha *ha;
- struct skinnysession *session;
- struct skinny_device *next;
-} *devices = NULL;
-
-struct skinny_paging_device {
- char name[80];
- char id[16];
- struct skinny_device ** devices;
- struct skinny_paging_device *next;
-};
-
-static struct skinnysession {
- pthread_t t;
- ast_mutex_t lock;
- struct sockaddr_in sin;
- int fd;
- char inbuf[SKINNY_MAX_PACKET];
- char outbuf[SKINNY_MAX_PACKET];
- struct skinny_device *device;
- struct skinnysession *next;
-} *sessions = NULL;
-
-static struct ast_channel *skinny_request(const char *type, int format, void *data, int *cause);
-static int skinny_call(struct ast_channel *ast, char *dest, int timeout);
-static int skinny_hangup(struct ast_channel *ast);
-static int skinny_answer(struct ast_channel *ast);
-static struct ast_frame *skinny_read(struct ast_channel *ast);
-static int skinny_write(struct ast_channel *ast, struct ast_frame *frame);
-static int skinny_indicate(struct ast_channel *ast, int ind, const void *data, size_t datalen);
-static int skinny_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
-static int skinny_senddigit_begin(struct ast_channel *ast, char digit);
-static int skinny_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration);
-static int handle_time_date_req_message(struct skinny_req *req, struct skinnysession *s);
-
-static const struct ast_channel_tech skinny_tech = {
- .type = "Skinny",
- .description = tdesc,
- .capabilities = ((AST_FORMAT_MAX_AUDIO << 1) - 1),
- .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER,
- .requester = skinny_request,
- .call = skinny_call,
- .hangup = skinny_hangup,
- .answer = skinny_answer,
- .read = skinny_read,
- .write = skinny_write,
- .indicate = skinny_indicate,
- .fixup = skinny_fixup,
- .send_digit_begin = skinny_senddigit_begin,
- .send_digit_end = skinny_senddigit_end,
-/* .bridge = ast_rtp_bridge, */
-};
-
-static void *get_button_template(struct skinnysession *s, struct button_definition_template *btn)
-{
- struct skinny_device *d = s->device;
- struct skinny_addon *a = d->addons;
- int i;
-
- switch (d->type) {
- case SKINNY_DEVICE_30SPPLUS:
- case SKINNY_DEVICE_30VIP:
- /* 13 rows, 2 columns */
- for (i = 0; i < 4; i++)
- (btn++)->buttonDefinition = BT_LINE;
- (btn++)->buttonDefinition = BT_REDIAL;
- (btn++)->buttonDefinition = BT_VOICEMAIL;
- (btn++)->buttonDefinition = BT_CALLPARK;
- (btn++)->buttonDefinition = BT_FORWARDALL;
- (btn++)->buttonDefinition = BT_CONFERENCE;
- for (i = 0; i < 4; i++)
- (btn++)->buttonDefinition = BT_NONE;
- for (i = 0; i < 13; i++)
- (btn++)->buttonDefinition = BT_SPEEDDIAL;
-
- break;
- case SKINNY_DEVICE_12SPPLUS:
- case SKINNY_DEVICE_12SP:
- case SKINNY_DEVICE_12:
- /* 6 rows, 2 columns */
- for (i = 0; i < 2; i++)
- (btn++)->buttonDefinition = BT_LINE;
- (btn++)->buttonDefinition = BT_REDIAL;
- for (i = 0; i < 3; i++)
- (btn++)->buttonDefinition = BT_SPEEDDIAL;
- (btn++)->buttonDefinition = BT_HOLD;
- (btn++)->buttonDefinition = BT_TRANSFER;
- (btn++)->buttonDefinition = BT_FORWARDALL;
- (btn++)->buttonDefinition = BT_CALLPARK;
- (btn++)->buttonDefinition = BT_VOICEMAIL;
- (btn++)->buttonDefinition = BT_CONFERENCE;
- break;
- case SKINNY_DEVICE_7910:
- (btn++)->buttonDefinition = BT_LINE;
- (btn++)->buttonDefinition = BT_HOLD;
- (btn++)->buttonDefinition = BT_TRANSFER;
- (btn++)->buttonDefinition = BT_DISPLAY;
- (btn++)->buttonDefinition = BT_VOICEMAIL;
- (btn++)->buttonDefinition = BT_CONFERENCE;
- (btn++)->buttonDefinition = BT_FORWARDALL;
- for (i = 0; i < 2; i++)
- (btn++)->buttonDefinition = BT_SPEEDDIAL;
- (btn++)->buttonDefinition = BT_REDIAL;
- break;
- case SKINNY_DEVICE_7960:
- case SKINNY_DEVICE_7961:
- case SKINNY_DEVICE_7961GE:
- case SKINNY_DEVICE_7962:
- case SKINNY_DEVICE_7965:
- for (i = 0; i < 6; i++)
- (btn++)->buttonDefinition = BT_CUST_LINESPEEDDIAL;
- break;
- case SKINNY_DEVICE_7940:
- case SKINNY_DEVICE_7941:
- case SKINNY_DEVICE_7941GE:
- case SKINNY_DEVICE_7942:
- case SKINNY_DEVICE_7945:
- for (i = 0; i < 2; i++)
- (btn++)->buttonDefinition = BT_CUST_LINESPEEDDIAL;
- break;
- case SKINNY_DEVICE_7935:
- case SKINNY_DEVICE_7936:
- for (i = 0; i < 2; i++)
- (btn++)->buttonDefinition = BT_LINE;
- break;
- case SKINNY_DEVICE_ATA186:
- (btn++)->buttonDefinition = BT_LINE;
- break;
- case SKINNY_DEVICE_7970:
- case SKINNY_DEVICE_7971:
- case SKINNY_DEVICE_7975:
- case SKINNY_DEVICE_CIPC:
- for (i = 0; i < 8; i++)
- (btn++)->buttonDefinition = BT_CUST_LINESPEEDDIAL;
- break;
- case SKINNY_DEVICE_7985:
- /* XXX I have no idea what the buttons look like on these. */
- ast_log(LOG_WARNING, "Unsupported device type '%d (7985)' found.\n", d->type);
- break;
- case SKINNY_DEVICE_7912:
- case SKINNY_DEVICE_7911:
- case SKINNY_DEVICE_7905:
- (btn++)->buttonDefinition = BT_LINE;
- (btn++)->buttonDefinition = BT_HOLD;
- break;
- case SKINNY_DEVICE_7920:
- /* XXX I don't know if this is right. */
- for (i = 0; i < 4; i++)
- (btn++)->buttonDefinition = BT_CUST_LINESPEEDDIAL;
- break;
- case SKINNY_DEVICE_7921:
- for (i = 0; i < 6; i++)
- (btn++)->buttonDefinition = BT_CUST_LINESPEEDDIAL;
- break;
- case SKINNY_DEVICE_7902:
- ast_log(LOG_WARNING, "Unsupported device type '%d (7902)' found.\n", d->type);
- break;
- case SKINNY_DEVICE_7906:
- ast_log(LOG_WARNING, "Unsupported device type '%d (7906)' found.\n", d->type);
- break;
- case SKINNY_DEVICE_7931:
- ast_log(LOG_WARNING, "Unsupported device type '%d (7931)' found.\n", d->type);
- break;
- case SKINNY_DEVICE_7937:
- ast_log(LOG_WARNING, "Unsupported device type '%d (7937)' found.\n", d->type);
- break;
- case SKINNY_DEVICE_7914:
- ast_log(LOG_WARNING, "Unsupported device type '%d (7914)' found. Expansion module registered by itself?\n", d->type);
- break;
- case SKINNY_DEVICE_SCCPGATEWAY_AN:
- case SKINNY_DEVICE_SCCPGATEWAY_BRI:
- ast_log(LOG_WARNING, "Unsupported device type '%d (SCCP gateway)' found.\n", d->type);
- break;
- default:
- ast_log(LOG_WARNING, "Unknown device type '%d' found.\n", d->type);
- break;
- }
-
- for (a = d->addons; a; a = a->next) {
- if (!strcasecmp(a->type, "7914")) {
- for (i = 0; i < 14; i++)
- (btn++)->buttonDefinition = BT_CUST_LINESPEEDDIAL;
- } else {
- ast_log(LOG_WARNING, "Unknown addon type '%s' found. Skipping.\n", a->type);
- }
- }
-
- return btn;
-}
-
-static struct skinny_req *req_alloc(size_t size, int response_message)
-{
- struct skinny_req *req;
-
- if (!(req = ast_calloc(1, skinny_header_size + size + 4)))
- return NULL;
-
- req->len = htolel(size+4);
- req->e = htolel(response_message);
-
- return req;
-}
-
-static struct skinny_line *find_line_by_instance(struct skinny_device *d, int instance)
-{
- struct skinny_line *l;
-
- if (!instance)
- instance = 1;
-
- for (l = d->lines; l; l = l->next) {
- if (l->instance == instance)
- break;
- }
-
- if (!l) {
- ast_log(LOG_WARNING, "Could not find line with instance '%d' on device '%s'\n", instance, d->name);
- }
- return l;
-}
-
-static struct skinny_line *find_line_by_name(const char *dest)
-{
- struct skinny_line *l;
- struct skinny_device *d;
- char line[256];
- char *at;
- char *device;
-
- ast_copy_string(line, dest, sizeof(line));
- at = strchr(line, '@');
- if (!at) {
- ast_log(LOG_NOTICE, "Device '%s' has no @ (at) sign!\n", dest);
- return NULL;
- }
- *at++ = '\0';
- device = at;
- ast_mutex_lock(&devicelock);
- for (d = devices; d; d = d->next) {
- if (!strcasecmp(d->name, device)) {
- if (skinnydebug)
- ast_verbose("Found device: %s\n", d->name);
- /* Found the device */
- for (l = d->lines; l; l = l->next) {
- /* Search for the right line */
- if (!strcasecmp(l->name, line)) {
- ast_mutex_unlock(&devicelock);
- return l;
- }
- }
- }
- }
- /* Device not found */
- ast_mutex_unlock(&devicelock);
- return NULL;
-}
-
-/* It's quicker/easier to find the subchannel when we know the instance number too */
-static struct skinny_subchannel *find_subchannel_by_instance_reference(struct skinny_device *d, int instance, int reference)
-{
- struct skinny_line *l = find_line_by_instance(d, instance);
- struct skinny_subchannel *sub;
-
- if (!l) {
- return NULL;
- }
-
- if (!reference)
- sub = l->sub;
- else {
- for (sub = l->sub; sub; sub = sub->next) {
- if (sub->callid == reference)
- break;
- }
- }
-
- if (!sub) {
- ast_log(LOG_WARNING, "Could not find subchannel with reference '%d' on '%s'\n", reference, d->name);
- }
- return sub;
-}
-
-/* Find the subchannel when we only have the callid - this shouldn't happen often */
-static struct skinny_subchannel *find_subchannel_by_reference(struct skinny_device *d, int reference)
-{
- struct skinny_line *l;
- struct skinny_subchannel *sub = NULL;
-
- for (l = d->lines; l; l = l->next) {
- for (sub = l->sub; sub; sub = sub->next) {
- if (sub->callid == reference)
- break;
- }
- if (sub)
- break;
- }
-
- if (!l) {
- ast_log(LOG_WARNING, "Could not find any lines that contained a subchannel with reference '%d' on device '%s'\n", reference, d->name);
- } else {
- if (!sub) {
- ast_log(LOG_WARNING, "Could not find subchannel with reference '%d' on '%s@%s'\n", reference, l->name, d->name);
- }
- }
- return sub;
-}
-
-static struct skinny_speeddial *find_speeddial_by_instance(struct skinny_device *d, int instance)
-{
- struct skinny_speeddial *sd;
-
- for (sd = d->speeddials; sd; sd = sd->next) {
- if (sd->instance == instance)
- break;
- }
-
- if (!sd) {
- ast_log(LOG_WARNING, "Could not find speeddial with instance '%d' on device '%s'\n", instance, d->name);
- }
- return sd;
-}
-
-static int codec_skinny2ast(enum skinny_codecs skinnycodec)
-{
- switch (skinnycodec) {
- case SKINNY_CODEC_ALAW:
- return AST_FORMAT_ALAW;
- case SKINNY_CODEC_ULAW:
- return AST_FORMAT_ULAW;
- case SKINNY_CODEC_G723_1:
- return AST_FORMAT_G723_1;
- case SKINNY_CODEC_G729A:
- return AST_FORMAT_G729A;
- case SKINNY_CODEC_G726_32:
- return AST_FORMAT_G726_AAL2; /* XXX Is this right? */
- case SKINNY_CODEC_H261:
- return AST_FORMAT_H261;
- case SKINNY_CODEC_H263:
- return AST_FORMAT_H263;
- default:
- return 0;
- }
-}
-
-static int codec_ast2skinny(int astcodec)
-{
- switch (astcodec) {
- case AST_FORMAT_ALAW:
- return SKINNY_CODEC_ALAW;
- case AST_FORMAT_ULAW:
- return SKINNY_CODEC_ULAW;
- case AST_FORMAT_G723_1:
- return SKINNY_CODEC_G723_1;
- case AST_FORMAT_G729A:
- return SKINNY_CODEC_G729A;
- case AST_FORMAT_G726_AAL2: /* XXX Is this right? */
- return SKINNY_CODEC_G726_32;
- case AST_FORMAT_H261:
- return SKINNY_CODEC_H261;
- case AST_FORMAT_H263:
- return SKINNY_CODEC_H263;
- default:
- return 0;
- }
-}
-
-
-static int skinny_register(struct skinny_req *req, struct skinnysession *s)
-{
- struct skinny_device *d;
- struct sockaddr_in sin;
- socklen_t slen;
-
- ast_mutex_lock(&devicelock);
- for (d = devices; d; d = d->next) {
- if (!strcasecmp(req->data.reg.name, d->id)
- && ast_apply_ha(d->ha, &(s->sin))) {
- s->device = d;
- d->type = letohl(req->data.reg.type);
- if (ast_strlen_zero(d->version_id)) {
- ast_copy_string(d->version_id, version_id, sizeof(d->version_id));
- }
- d->registered = 1;
- d->session = s;
-
- slen = sizeof(sin);
- if (getsockname(s->fd, (struct sockaddr *)&sin, &slen)) {
- ast_log(LOG_WARNING, "Cannot get socket name\n");
- sin.sin_addr = __ourip;
- }
- d->ourip = sin.sin_addr;
- break;
- }
- }
- ast_mutex_unlock(&devicelock);
- if (!d) {
- return 0;
- }
- return 1;
-}
-
-static int skinny_unregister(struct skinny_req *req, struct skinnysession *s)
-{
- struct skinny_device *d;
-
- d = s->device;
-
- if (d) {
- d->session = NULL;
- d->registered = 0;
- }
-
- return -1; /* main loop will destroy the session */
-}
-
-static int transmit_response(struct skinnysession *s, struct skinny_req *req)
-{
- int res = 0;
-
- if (!s) {
- ast_log(LOG_WARNING, "Asked to transmit to a non-existant session!\n");
- return -1;
- }
-
- ast_mutex_lock(&s->lock);
-
- if (skinnydebug)
- ast_log(LOG_VERBOSE, "writing packet type %04X (%d bytes) to socket %d\n", letohl(req->e), letohl(req->len)+8, s->fd);
-
- if (letohl(req->len > SKINNY_MAX_PACKET) || letohl(req->len < 0)) {
- ast_log(LOG_WARNING, "transmit_response: the length of the request is out of bounds\n");
- ast_mutex_unlock(&s->lock);
- return -1;
- }
-
- memset(s->outbuf,0,sizeof(s->outbuf));
- memcpy(s->outbuf, req, skinny_header_size);
- memcpy(s->outbuf+skinny_header_size, &req->data, letohl(req->len));
-
- res = write(s->fd, s->outbuf, letohl(req->len)+8);
-
- if (res != letohl(req->len)+8) {
- ast_log(LOG_WARNING, "Transmit: write only sent %d out of %d bytes: %s\n", res, letohl(req->len)+8, strerror(errno));
- if (res == -1) {
- if (skinnydebug)
- ast_log(LOG_WARNING, "Transmit: Skinny Client was lost, unregistering\n");
- skinny_unregister(NULL, s);
- }
-
- }
-
- ast_mutex_unlock(&s->lock);
- return 1;
-}
-
-static void transmit_speaker_mode(struct skinnysession *s, int mode)
-{
- struct skinny_req *req;
-
- if (!(req = req_alloc(sizeof(struct set_speaker_message), SET_SPEAKER_MESSAGE)))
- return;
-
- req->data.setspeaker.mode = htolel(mode);
- transmit_response(s, req);
-}
-/*
-static void transmit_microphone_mode(struct skinnysession *s, int mode)
-{
- struct skinny_req *req;
-
- if (!(req = req_alloc(sizeof(struct set_microphone_message), SET_MICROPHONE_MESSAGE)))
- return;
-
- req->data.setmicrophone.mode = htolel(mode);
- transmit_response(s, req);
-}
-*/
-
-static void transmit_callinfo(struct skinnysession *s, const char *fromname, const char *fromnum, const char *toname, const char *tonum, int instance, int callid, int calltype)
-{
- struct skinny_req *req;
-
- if (!(req = req_alloc(sizeof(struct call_info_message), CALL_INFO_MESSAGE)))
- return;
-
- if (skinnydebug)
- ast_verbose("Setting Callinfo to %s(%s) from %s(%s) on %s(%d)\n", fromname, fromnum, toname, tonum, s->device->name, instance);
-
- if (fromname) {
- ast_copy_string(req->data.callinfo.callingPartyName, fromname, sizeof(req->data.callinfo.callingPartyName));
- }
- if (fromnum) {
- ast_copy_string(req->data.callinfo.callingParty, fromnum, sizeof(req->data.callinfo.callingParty));
- }
- if (toname) {
- ast_copy_string(req->data.callinfo.calledPartyName, toname, sizeof(req->data.callinfo.calledPartyName));
- }
- if (tonum) {
- ast_copy_string(req->data.callinfo.calledParty, tonum, sizeof(req->data.callinfo.calledParty));
- }
- req->data.callinfo.instance = htolel(instance);
- req->data.callinfo.reference = htolel(callid);
- req->data.callinfo.type = htolel(calltype);
- transmit_response(s, req);
-}
-
-static void transmit_connect(struct skinnysession *s, struct skinny_subchannel *sub)
-{
- struct skinny_req *req;
- struct skinny_line *l = sub->parent;
- struct ast_format_list fmt;
-
- if (!(req = req_alloc(sizeof(struct open_receive_channel_message), OPEN_RECEIVE_CHANNEL_MESSAGE)))
- return;
-
- fmt = ast_codec_pref_getsize(&l->prefs, ast_best_codec(l->capability));
-
- req->data.openreceivechannel.conferenceId = htolel(sub->callid);
- req->data.openreceivechannel.partyId = htolel(sub->callid);
- req->data.openreceivechannel.packets = htolel(fmt.cur_ms);
- req->data.openreceivechannel.capability = htolel(codec_ast2skinny(fmt.bits));
- req->data.openreceivechannel.echo = htolel(0);
- req->data.openreceivechannel.bitrate = htolel(0);
- transmit_response(s, req);
-}
-
-static void transmit_tone(struct skinnysession *s, int tone, int instance, int reference)
-{
- struct skinny_req *req;
-
- if (tone == SKINNY_NOTONE) {
- /* This is bad, mmm'kay? */
- return;
- }
-
- if (tone > 0) {
- if (!(req = req_alloc(sizeof(struct start_tone_message), START_TONE_MESSAGE)))
- return;
- req->data.starttone.tone = htolel(tone);
- req->data.starttone.instance = htolel(instance);
- req->data.starttone.reference = htolel(reference);
- } else {
- if (!(req = req_alloc(sizeof(struct stop_tone_message), STOP_TONE_MESSAGE)))
- return;
- req->data.stoptone.instance = htolel(instance);
- req->data.stoptone.reference = htolel(reference);
- }
-
- if (tone > 0) {
- req->data.starttone.tone = htolel(tone);
- }
- transmit_response(s, req);
-}
-
-static void transmit_selectsoftkeys(struct skinnysession *s, int instance, int callid, int softkey)
-{
- struct skinny_req *req;
-
- if (!(req = req_alloc(sizeof(struct select_soft_keys_message), SELECT_SOFT_KEYS_MESSAGE)))
- return;
-
- req->data.selectsoftkey.instance = htolel(instance);
- req->data.selectsoftkey.reference = htolel(callid);
- req->data.selectsoftkey.softKeySetIndex = htolel(softkey);
- req->data.selectsoftkey.validKeyMask = htolel(0xFFFFFFFF);
- transmit_response(s, req);
-}
-
-static void transmit_lamp_indication(struct skinnysession *s, int stimulus, int instance, int indication)
-{
- struct skinny_req *req;
-
- if (!(req = req_alloc(sizeof(struct set_lamp_message), SET_LAMP_MESSAGE)))
- return;
-
- req->data.setlamp.stimulus = htolel(stimulus);
- req->data.setlamp.stimulusInstance = htolel(instance);
- req->data.setlamp.deviceStimulus = htolel(indication);
- transmit_response(s, req);
-}
-
-static void transmit_ringer_mode(struct skinnysession *s, int mode)
-{
- struct skinny_req *req;
-
- if (skinnydebug)
- ast_verbose("Setting ringer mode to '%d'.\n", mode);
-
- if (!(req = req_alloc(sizeof(struct set_ringer_message), SET_RINGER_MESSAGE)))
- return;
-
- req->data.setringer.ringerMode = htolel(mode);
- /* XXX okay, I don't quite know what this is, but here's what happens (on a 7960).
- Note: The phone will always show as ringing on the display.
-
- 1: phone will audibly ring over and over
- 2: phone will audibly ring only once
- any other value, will NOT cause the phone to audibly ring
- */
- req->data.setringer.unknown1 = htolel(1);
- /* XXX the value here doesn't seem to change anything. Must be higher than 0.
- Perhaps a packet capture can shed some light on this. */
- req->data.setringer.unknown2 = htolel(1);
- transmit_response(s, req);
-}
-
-static void transmit_displaymessage(struct skinnysession *s, const char *text, int instance, int reference)
-{
- struct skinny_req *req;
-
- if (text == 0) {
- if (!(req = req_alloc(0, CLEAR_DISPLAY_MESSAGE)))
- return;
-
- req->data.clearpromptstatus.lineInstance = instance;
- req->data.clearpromptstatus.callReference = reference;
-
- if (skinnydebug)
- ast_verbose("Clearing Display\n");
- } else {
- if (!(req = req_alloc(sizeof(struct displaytext_message), DISPLAYTEXT_MESSAGE)))
- return;
-
- ast_copy_string(req->data.displaytext.text, text, sizeof(req->data.displaytext.text));
- if (skinnydebug)
- ast_verbose("Displaying message '%s'\n", req->data.displaytext.text);
- }
-
- transmit_response(s, req);
-}
-
-static void transmit_displaynotify(struct skinnysession *s, const char *text, int t)
-{
- struct skinny_req *req;
-
- if (!(req = req_alloc(sizeof(struct display_notify_message), DISPLAY_NOTIFY_MESSAGE)))
- return;
-
- ast_copy_string(req->data.displaynotify.displayMessage, text, sizeof(req->data.displaynotify.displayMessage));
- req->data.displaynotify.displayTimeout = htolel(t);
-
- if (skinnydebug)
- ast_verbose("Displaying notify '%s'\n", text);
-
- transmit_response(s, req);
-}
-
-static void transmit_displaypromptstatus(struct skinnysession *s, const char *text, int t, int instance, int callid)
-{
- struct skinny_req *req;
-
- if (text == 0) {
- if (!(req = req_alloc(sizeof(struct clear_prompt_message), CLEAR_PROMPT_MESSAGE)))
- return;
-
- req->data.clearpromptstatus.lineInstance = htolel(instance);
- req->data.clearpromptstatus.callReference = htolel(callid);
-
- if (skinnydebug)
- ast_verbose("Clearing Prompt\n");
- } else {
- if (!(req = req_alloc(sizeof(struct display_prompt_status_message), DISPLAY_PROMPT_STATUS_MESSAGE)))
- return;
-
- ast_copy_string(req->data.displaypromptstatus.promptMessage, text, sizeof(req->data.displaypromptstatus.promptMessage));
- req->data.displaypromptstatus.messageTimeout = htolel(t);
- req->data.displaypromptstatus.lineInstance = htolel(instance);
- req->data.displaypromptstatus.callReference = htolel(callid);
-
- if (skinnydebug)
- ast_verbose("Displaying Prompt Status '%s'\n", text);
- }
-
- transmit_response(s, req);
-}
-
-static void transmit_dialednumber(struct skinnysession *s, const char *text, int instance, int callid)
-{
- struct skinny_req *req;
-
- if (!(req = req_alloc(sizeof(struct dialed_number_message), DIALED_NUMBER_MESSAGE)))
- return;
-
- ast_copy_string(req->data.dialednumber.dialedNumber, text, sizeof(req->data.dialednumber.dialedNumber));
- req->data.dialednumber.lineInstance = htolel(instance);
- req->data.dialednumber.callReference = htolel(callid);
-
- transmit_response(s, req);
-}
-
-static void transmit_callstate(struct skinnysession *s, int instance, int state, unsigned callid)
-{
- struct skinny_req *req;
-
- if (state == SKINNY_ONHOOK) {
- if (!(req = req_alloc(sizeof(struct close_receive_channel_message), CLOSE_RECEIVE_CHANNEL_MESSAGE)))
- return;
-
- req->data.closereceivechannel.conferenceId = htolel(callid);
- req->data.closereceivechannel.partyId = htolel(callid);
- transmit_response(s, req);
-
- if (!(req = req_alloc(sizeof(struct stop_media_transmission_message), STOP_MEDIA_TRANSMISSION_MESSAGE)))
- return;
-
- req->data.stopmedia.conferenceId = htolel(callid);
- req->data.stopmedia.passThruPartyId = htolel(callid);
- transmit_response(s, req);
-
- transmit_speaker_mode(s, SKINNY_SPEAKEROFF);
-
- transmit_displaypromptstatus(s, NULL, 0, instance, callid);
- }
-
- if (!(req = req_alloc(sizeof(struct call_state_message), CALL_STATE_MESSAGE)))
- return;
-
- req->data.callstate.callState = htolel(state);
- req->data.callstate.lineInstance = htolel(instance);
- req->data.callstate.callReference = htolel(callid);
- transmit_response(s, req);
-
- if (state == SKINNY_ONHOOK) {
- transmit_selectsoftkeys(s, 0, 0, KEYDEF_ONHOOK);
- }
-
- if (state == SKINNY_OFFHOOK || state == SKINNY_ONHOOK) {
- if (!(req = req_alloc(sizeof(struct activate_call_plane_message), ACTIVATE_CALL_PLANE_MESSAGE)))
- return;
-
- req->data.activatecallplane.lineInstance = htolel(instance);
- transmit_response(s, req);
- }
-}
-
-/*
-static int has_voicemail(struct skinny_line *l)
-{
- return ast_app_has_voicemail(l->mailbox, NULL);
-}
-*/
-
-static void do_housekeeping(struct skinnysession *s)
-{
-/*
- int new;
- int old;
- struct skinny_device *d = s->device;
- struct skinny_line *l;
-*/
-
- /* Update time on device */
- handle_time_date_req_message(NULL, s);
-
-/*
- for (l = d->lines; l; l = l->next) {
- if (has_voicemail(l)) {
- if (skinnydebug)
- ast_verbose("Checking for voicemail Skinny %s@%s\n", l->name, d->name);
- ast_app_inboxcount(l->mailbox, &new, &old);
- if (skinnydebug)
- ast_verbose("Skinny %s@%s has voicemail!\n", l->name, d->name);
- transmit_lamp_indication(s, STIMULUS_VOICEMAIL, l->instance, l->mwiblink?SKINNY_LAMP_BLINK:SKINNY_LAMP_ON);
- } else {
- transmit_lamp_indication(s, STIMULUS_VOICEMAIL, l->instance, SKINNY_LAMP_OFF);
- }
- }
-*/
-}
-
-/* I do not believe skinny can deal with video.
- Anyone know differently? */
-/* Yes, it can. Currently 7985 and Cisco VT Advantage do video. */
-static enum ast_rtp_get_result skinny_get_vrtp_peer(struct ast_channel *c, struct ast_rtp **rtp)
-{
- struct skinny_subchannel *sub = NULL;
-
- if (!(sub = c->tech_pvt) || !(sub->vrtp))
- return AST_RTP_GET_FAILED;
-
- *rtp = sub->vrtp;
-
- return AST_RTP_TRY_NATIVE;
-}
-
-static enum ast_rtp_get_result skinny_get_rtp_peer(struct ast_channel *c, struct ast_rtp **rtp)
-{
- struct skinny_subchannel *sub = NULL;
-
- if (!(sub = c->tech_pvt) || !(sub->rtp))
- return AST_RTP_GET_FAILED;
-
- *rtp = sub->rtp;
-
- return AST_RTP_TRY_NATIVE;
-}
-
-static int skinny_set_rtp_peer(struct ast_channel *c, struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs, int nat_active)
-{
- struct skinny_subchannel *sub;
- sub = c->tech_pvt;
- if (sub) {
- /* transmit_modify_with_sdp(sub, rtp); @@FIXME@@ if needed */
- return 0;
- }
- return -1;
-}
-
-static struct ast_rtp_protocol skinny_rtp = {
- .type = "Skinny",
- .get_rtp_info = skinny_get_rtp_peer,
- .get_vrtp_info = skinny_get_vrtp_peer,
- .set_rtp_peer = skinny_set_rtp_peer,
-};
-
-static int skinny_do_debug(int fd, int argc, char *argv[])
-{
- if (argc != 3) {
- return RESULT_SHOWUSAGE;
- }
- skinnydebug = 1;
- ast_cli(fd, "Skinny Debugging Enabled\n");
- return RESULT_SUCCESS;
-}
-
-static int skinny_no_debug(int fd, int argc, char *argv[])
-{
- if (argc != 4) {
- return RESULT_SHOWUSAGE;
- }
- skinnydebug = 0;
- ast_cli(fd, "Skinny Debugging Disabled\n");
- return RESULT_SUCCESS;
-}
-
-static char *complete_skinny_reset(const char *line, const char *word, int pos, int state)
-{
- struct skinny_device *d;
-
- char *result = NULL;
- int wordlen = strlen(word);
- int which = 0;
-
- if (pos == 2) {
- for (d = devices; d && !result; d = d->next) {
- if (!strncasecmp(word, d->id, wordlen) && ++which > state)
- result = ast_strdup(d->id);
- }
- }
-
- return result;
-}
-
-static int skinny_reset_device(int fd, int argc, char *argv[])
-{
- struct skinny_device *d;
- struct skinny_req *req;
-
- if (argc < 3 || argc > 4) {
- return RESULT_SHOWUSAGE;
- }
- ast_mutex_lock(&devicelock);
-
- for (d = devices; d; d = d->next) {
- int fullrestart = 0;
- if (!strcasecmp(argv[2], d->id) || !strcasecmp(argv[2], "all")) {
- if (!(d->session))
- continue;
-
- if (!(req = req_alloc(sizeof(struct reset_message), RESET_MESSAGE)))
- continue;
-
- if (argc == 4 && !strcasecmp(argv[3], "restart"))
- fullrestart = 1;
-
- if (fullrestart)
- req->data.reset.resetType = 2;
- else
- req->data.reset.resetType = 1;
-
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "%s device %s.\n", (fullrestart) ? "Restarting" : "Resetting", d->id);
- transmit_response(d->session, req);
- }
- }
- ast_mutex_unlock(&devicelock);
- return RESULT_SUCCESS;
-}
-
-static char *device2str(int type)
-{
- char *tmp;
-
- switch (type) {
- case SKINNY_DEVICE_NONE:
- return "No Device";
- case SKINNY_DEVICE_30SPPLUS:
- return "30SP Plus";
- case SKINNY_DEVICE_12SPPLUS:
- return "12SP Plus";
- case SKINNY_DEVICE_12SP:
- return "12SP";
- case SKINNY_DEVICE_12:
- return "12";
- case SKINNY_DEVICE_30VIP:
- return "30VIP";
- case SKINNY_DEVICE_7910:
- return "7910";
- case SKINNY_DEVICE_7960:
- return "7960";
- case SKINNY_DEVICE_7940:
- return "7940";
- case SKINNY_DEVICE_7935:
- return "7935";
- case SKINNY_DEVICE_ATA186:
- return "ATA186";
- case SKINNY_DEVICE_7941:
- return "7941";
- case SKINNY_DEVICE_7971:
- return "7971";
- case SKINNY_DEVICE_7914:
- return "7914";
- case SKINNY_DEVICE_7985:
- return "7985";
- case SKINNY_DEVICE_7911:
- return "7911";
- case SKINNY_DEVICE_7961GE:
- return "7961GE";
- case SKINNY_DEVICE_7941GE:
- return "7941GE";
- case SKINNY_DEVICE_7931:
- return "7931";
- case SKINNY_DEVICE_7921:
- return "7921";
- case SKINNY_DEVICE_7906:
- return "7906";
- case SKINNY_DEVICE_7962:
- return "7962";
- case SKINNY_DEVICE_7937:
- return "7937";
- case SKINNY_DEVICE_7942:
- return "7942";
- case SKINNY_DEVICE_7945:
- return "7945";
- case SKINNY_DEVICE_7965:
- return "7965";
- case SKINNY_DEVICE_7975:
- return "7975";
- case SKINNY_DEVICE_7905:
- return "7905";
- case SKINNY_DEVICE_7920:
- return "7920";
- case SKINNY_DEVICE_7970:
- return "7970";
- case SKINNY_DEVICE_7912:
- return "7912";
- case SKINNY_DEVICE_7902:
- return "7902";
- case SKINNY_DEVICE_CIPC:
- return "IP Communicator";
- case SKINNY_DEVICE_7961:
- return "7961";
- case SKINNY_DEVICE_7936:
- return "7936";
- case SKINNY_DEVICE_SCCPGATEWAY_AN:
- return "SCCPGATEWAY_AN";
- case SKINNY_DEVICE_SCCPGATEWAY_BRI:
- return "SCCPGATEWAY_BRI";
- case SKINNY_DEVICE_UNKNOWN:
- return "Unknown";
- default:
- if (!(tmp = ast_threadstorage_get(&device2str_threadbuf, DEVICE2STR_BUFSIZE)))
- return "Unknown";
- snprintf(tmp, DEVICE2STR_BUFSIZE, "UNKNOWN-%d", type);
- return tmp;
- }
-}
-
-static int skinny_show_devices(int fd, int argc, char *argv[])
-{
- struct skinny_device *d;
- struct skinny_line *l;
- int numlines = 0;
-
- if (argc != 3) {
- return RESULT_SHOWUSAGE;
- }
- ast_mutex_lock(&devicelock);
-
- ast_cli(fd, "Name DeviceId IP Type R NL\n");
- ast_cli(fd, "-------------------- ---------------- --------------- --------------- - --\n");
- for (d = devices; d; d = d->next) {
- numlines = 0;
- for (l = d->lines; l; l = l->next) {
- numlines++;
- }
-
- ast_cli(fd, "%-20s %-16s %-15s %-15s %c %2d\n",
- d->name,
- d->id,
- d->session?ast_inet_ntoa(d->session->sin.sin_addr):"",
- device2str(d->type),
- d->registered?'Y':'N',
- numlines);
- }
- ast_mutex_unlock(&devicelock);
- return RESULT_SUCCESS;
-}
-
-static int skinny_show_lines(int fd, int argc, char *argv[])
-{
- struct skinny_device *d;
- struct skinny_line *l;
-
- if (argc != 3) {
- return RESULT_SHOWUSAGE;
- }
- ast_mutex_lock(&devicelock);
-
- ast_cli(fd, "Device Name Instance Name Label \n");
- ast_cli(fd, "-------------------- -------- -------------------- --------------------\n");
- for (d = devices; d; d = d->next) {
- for (l = d->lines; l; l = l->next) {
- ast_cli(fd, "%-20s %8d %-20s %-20s\n",
- d->name,
- l->instance,
- l->name,
- l->label);
- }
- }
-
- ast_mutex_unlock(&devicelock);
- return RESULT_SUCCESS;
-}
-
-static char show_devices_usage[] =
-"Usage: skinny show devices\n"
-" Lists all devices known to the Skinny subsystem.\n";
-
-static char show_lines_usage[] =
-"Usage: skinny show lines\n"
-" Lists all lines known to the Skinny subsystem.\n";
-
-static char debug_usage[] =
-"Usage: skinny set debug\n"
-" Enables dumping of Skinny packets for debugging purposes\n";
-
-static char no_debug_usage[] =
-"Usage: skinny set debug off\n"
-" Disables dumping of Skinny packets for debugging purposes\n";
-
-static char reset_usage[] =
-"Usage: skinny reset <DeviceId|all> [restart]\n"
-" Causes a Skinny device to reset itself, optionally with a full restart\n";
-
-static struct ast_cli_entry cli_skinny[] = {
- { { "skinny", "show", "devices", NULL },
- skinny_show_devices, "List defined Skinny devices",
- show_devices_usage },
-
- { { "skinny", "show", "lines", NULL },
- skinny_show_lines, "List defined Skinny lines per device",
- show_lines_usage },
-
- { { "skinny", "set", "debug", NULL },
- skinny_do_debug, "Enable Skinny debugging",
- debug_usage },
-
- { { "skinny", "set", "debug", "off", NULL },
- skinny_no_debug, "Disable Skinny debugging",
- no_debug_usage },
-
- { { "skinny", "reset", NULL },
- skinny_reset_device, "Reset Skinny device(s)",
- reset_usage, complete_skinny_reset },
-};
-
-#if 0
-static struct skinny_paging_device *build_paging_device(const char *cat, struct ast_variable *v)
-{
- return NULL;
-}
-#endif
-
-static struct skinny_device *build_device(const char *cat, struct ast_variable *v)
-{
- struct skinny_device *d;
- struct skinny_line *l;
- struct skinny_speeddial *sd;
- struct skinny_addon *a;
- int lineInstance = 1;
- int speeddialInstance = 1;
- int y = 0;
-
- if (!(d = ast_calloc(1, sizeof(struct skinny_device)))) {
- return NULL;
- } else {
- ast_copy_string(d->name, cat, sizeof(d->name));
- d->lastlineinstance = 1;
- d->capability = default_capability;
- d->prefs = default_prefs;
- d->earlyrtp = 1;
- while(v) {
- if (!strcasecmp(v->name, "host")) {
- if (ast_get_ip(&d->addr, v->value)) {
- free(d);
- return NULL;
- }
- } else if (!strcasecmp(v->name, "port")) {
- d->addr.sin_port = htons(atoi(v->value));
- } else if (!strcasecmp(v->name, "device")) {
- ast_copy_string(d->id, v->value, sizeof(d->id));
- } else if (!strcasecmp(v->name, "permit") || !strcasecmp(v->name, "deny")) {
- d->ha = ast_append_ha(v->name, v->value, d->ha);
- } else if (!strcasecmp(v->name, "context")) {
- ast_copy_string(context, v->value, sizeof(context));
- } else if (!strcasecmp(v->name, "allow")) {
- ast_parse_allow_disallow(&d->prefs, &d->capability, v->value, 1);
- } else if (!strcasecmp(v->name, "disallow")) {
- ast_parse_allow_disallow(&d->prefs, &d->capability, v->value, 0);
- } else if (!strcasecmp(v->name, "version")) {
- ast_copy_string(d->version_id, v->value, sizeof(d->version_id));
- } else if (!strcasecmp(v->name, "earlyrtp")) {
- d->earlyrtp = ast_true(v->value);
- } else if (!strcasecmp(v->name, "nat")) {
- nat = ast_true(v->value);
- } else if (!strcasecmp(v->name, "callerid")) {
- if (!strcasecmp(v->value, "asreceived")) {
- cid_num[0] = '\0';
- cid_name[0] = '\0';
- } else {
- ast_callerid_split(v->value, cid_name, sizeof(cid_name), cid_num, sizeof(cid_num));
- }
- } else if (!strcasecmp(v->name, "language")) {
- ast_copy_string(language, v->value, sizeof(language));
- } else if (!strcasecmp(v->name, "accountcode")) {
- ast_copy_string(accountcode, v->value, sizeof(accountcode));
- } else if (!strcasecmp(v->name, "amaflags")) {
- y = ast_cdr_amaflags2int(v->value);
- if (y < 0) {
- ast_log(LOG_WARNING, "Invalid AMA flags: %s at line %d\n", v->value, v->lineno);
- } else {
- amaflags = y;
- }
- } else if (!strcasecmp(v->name, "mohinterpret") || !strcasecmp(v->name, "musiconhold")) {
- ast_copy_string(mohinterpret, v->value, sizeof(mohinterpret));
- } else if (!strcasecmp(v->name, "mohsuggest")) {
- ast_copy_string(mohsuggest, v->value, sizeof(mohsuggest));
- } else if (!strcasecmp(v->name, "callgroup")) {
- cur_callergroup = ast_get_group(v->value);
- } else if (!strcasecmp(v->name, "pickupgroup")) {
- cur_pickupgroup = ast_get_group(v->value);
- } else if (!strcasecmp(v->name, "immediate")) {
- immediate = ast_true(v->value);
- } else if (!strcasecmp(v->name, "cancallforward")) {
- cancallforward = ast_true(v->value);
- } else if (!strcasecmp(v->name, "mailbox")) {
- ast_copy_string(mailbox, v->value, sizeof(mailbox));
- } else if (!strcasecmp(v->name, "hasvoicemail")) {
- if (ast_true(v->value) && ast_strlen_zero(mailbox)) {
- ast_copy_string(mailbox, cat, sizeof(mailbox));
- }
- } else if (!strcasecmp(v->name, "callreturn")) {
- callreturn = ast_true(v->value);
- } else if (!strcasecmp(v->name, "callwaiting")) {
- callwaiting = ast_true(v->value);
- } else if (!strcasecmp(v->name, "transfer")) {
- transfer = ast_true(v->value);
- } else if (!strcasecmp(v->name, "threewaycalling")) {
- threewaycalling = ast_true(v->value);
- } else if (!strcasecmp(v->name, "mwiblink")) {
- mwiblink = ast_true(v->value);
- } else if (!strcasecmp(v->name, "linelabel")) {
- ast_copy_string(linelabel, v->value, sizeof(linelabel));
- } else if (!strcasecmp(v->name, "speeddial")) {
- if (!(sd = ast_calloc(1, sizeof(struct skinny_speeddial)))) {
- return NULL;
- } else {
- char *stringp, *exten, *label;
- stringp = v->value;
- exten = strsep(&stringp, ",");
- label = strsep(&stringp, ",");
- ast_mutex_init(&sd->lock);
- ast_copy_string(sd->exten, exten, sizeof(sd->exten));
- if (label)
- ast_copy_string(sd->label, label, sizeof(sd->label));
- else
- ast_copy_string(sd->label, exten, sizeof(sd->label));
- sd->instance = speeddialInstance++;
-
- sd->parent = d;
-
- sd->next = d->speeddials;
- d->speeddials = sd;
- }
- } else if (!strcasecmp(v->name, "addon")) {
- if (!(a = ast_calloc(1, sizeof(struct skinny_addon)))) {
- return NULL;
- } else {
- ast_mutex_init(&a->lock);
- ast_copy_string(a->type, v->value, sizeof(a->type));
-
- a->next = d->addons;
- d->addons = a;
- }
- } else if (!strcasecmp(v->name, "trunk") || !strcasecmp(v->name, "line")) {
- if (!(l = ast_calloc(1, sizeof(struct skinny_line)))) {
- return NULL;
- } else {
- ast_mutex_init(&l->lock);
- ast_copy_string(l->name, v->value, sizeof(l->name));
-
- /* XXX Should we check for uniqueness?? XXX */
- ast_copy_string(l->context, context, sizeof(l->context));
- ast_copy_string(l->cid_num, cid_num, sizeof(l->cid_num));
- ast_copy_string(l->cid_name, cid_name, sizeof(l->cid_name));
- ast_copy_string(l->label, linelabel, sizeof(l->label));
- ast_copy_string(l->language, language, sizeof(l->language));
- ast_copy_string(l->mohinterpret, mohinterpret, sizeof(l->mohinterpret));
- ast_copy_string(l->mohsuggest, mohsuggest, sizeof(l->mohsuggest));
- ast_copy_string(l->mailbox, mailbox, sizeof(l->mailbox));
- if (!ast_strlen_zero(mailbox)) {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Setting mailbox '%s' on %s@%s\n", mailbox, d->name, l->name);
- }
- l->msgstate = -1;
- l->capability = d->capability;
- l->prefs = d->prefs;
- l->parent = d;
- if (!strcasecmp(v->name, "trunk")) {
- l->type = TYPE_TRUNK;
- } else {
- l->type = TYPE_LINE;
- }
- l->immediate = immediate;
- l->callgroup = cur_callergroup;
- l->pickupgroup = cur_pickupgroup;
- l->callreturn = callreturn;
- l->cancallforward = cancallforward;
- l->callwaiting = callwaiting;
- l->transfer = transfer;
- l->threewaycalling = threewaycalling;
- l->mwiblink = mwiblink;
- l->onhooktime = time(NULL);
- l->instance = lineInstance++;
- /* ASSUME we're onhook at this point */
- l->hookstate = SKINNY_ONHOOK;
- l->nat = nat;
-
- l->next = d->lines;
- d->lines = l;
- }
- } else {
- ast_log(LOG_WARNING, "Don't know keyword '%s' at line %d\n", v->name, v->lineno);
- }
- v = v->next;
- }
-
- if (!d->lines) {
- ast_log(LOG_ERROR, "A Skinny device must have at least one line!\n");
- return NULL;
- }
- if (/*d->addr.sin_addr.s_addr && */!ntohs(d->addr.sin_port)) {
- d->addr.sin_port = htons(DEFAULT_SKINNY_PORT);
- }
-#if 0
- /* I don't think we need this anymore at all, since d->ourip is set in skinny_register now */
- if (d->addr.sin_addr.s_addr) {
- /* XXX See note above, in 'host' option. */
- if (ast_ouraddrfor(&d->addr.sin_addr, &d->ourip)) {
- d->ourip = __ourip;
- }
- } else {
- d->ourip = __ourip;
- }
-#endif
- }
- return d;
-}
-
-static void start_rtp(struct skinny_subchannel *sub)
-{
- struct skinny_line *l = sub->parent;
- struct skinny_device *d = l->parent;
- int hasvideo = 0;
-
- ast_mutex_lock(&sub->lock);
- /* Allocate the RTP */
- sub->rtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr);
- if (hasvideo)
- sub->vrtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr);
-
- if (sub->rtp && sub->owner) {
- sub->owner->fds[0] = ast_rtp_fd(sub->rtp);
- sub->owner->fds[1] = ast_rtcp_fd(sub->rtp);
- }
- if (hasvideo && sub->vrtp && sub->owner) {
- sub->owner->fds[2] = ast_rtp_fd(sub->vrtp);
- sub->owner->fds[3] = ast_rtcp_fd(sub->vrtp);
- }
- if (sub->rtp) {
- ast_rtp_setnat(sub->rtp, l->nat);
- }
- if (sub->vrtp) {
- ast_rtp_setnat(sub->vrtp, l->nat);
- }
- /* Set Frame packetization */
- if (sub->rtp)
- ast_rtp_codec_setpref(sub->rtp, &l->prefs);
-
- /* Create the RTP connection */
- transmit_connect(d->session, sub);
- ast_mutex_unlock(&sub->lock);
-}
-
-static void *skinny_newcall(void *data)
-{
- struct ast_channel *c = data;
- struct skinny_subchannel *sub = c->tech_pvt;
- struct skinny_line *l = sub->parent;
- struct skinny_device *d = l->parent;
- struct skinnysession *s = d->session;
- int res = 0;
-
- ast_copy_string(l->lastnumberdialed, c->exten, sizeof(l->lastnumberdialed));
- ast_set_callerid(c,
- l->hidecallerid ? "" : l->cid_num,
- l->hidecallerid ? "" : l->cid_name,
- c->cid.cid_ani ? NULL : l->cid_num);
- ast_setstate(c, AST_STATE_RING);
- if (!sub->rtp) {
- start_rtp(sub);
- }
- res = ast_pbx_run(c);
- if (res) {
- ast_log(LOG_WARNING, "PBX exited non-zero\n");
- transmit_tone(s, SKINNY_REORDER, l->instance, sub->callid);
- }
- return NULL;
-}
-
-static void *skinny_ss(void *data)
-{
- struct ast_channel *c = data;
- struct skinny_subchannel *sub = c->tech_pvt;
- struct skinny_line *l = sub->parent;
- struct skinny_device *d = l->parent;
- struct skinnysession *s = d->session;
- int len = 0;
- int timeout = firstdigittimeout;
- int res = 0;
- int getforward=0;
- int loop_pause = 100;
-
- if (option_verbose > 2)
- ast_verbose( VERBOSE_PREFIX_3 "Starting simple switch on '%s@%s'\n", l->name, d->name);
- len = strlen(d->exten);
-
- while (len < AST_MAX_EXTENSION-1) {
-
- res = 1; /* Assume we will get a digit */
- while (strlen(d->exten) == len) {
- ast_safe_sleep(c, loop_pause);
- timeout -= loop_pause;
- if (timeout <= 0){
- res = 0;
- break;
- }
- }
-
- len = strlen(d->exten);
-
- if (!ast_ignore_pattern(c->context, d->exten)) {
- transmit_tone(s, SKINNY_SILENCE, l->instance, sub->callid);
- }
-
- if (ast_exists_extension(c, c->context, d->exten, 1, l->cid_num)) {
- if (!res || !ast_matchmore_extension(c, c->context, d->exten, 1, l->cid_num)) {
- if (getforward) {
- /* Record this as the forwarding extension */
- ast_copy_string(l->call_forward, d->exten, sizeof(l->call_forward));
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Setting call forward to '%s' on channel %s\n",
- l->call_forward, c->name);
- transmit_tone(s, SKINNY_DIALTONE, l->instance, sub->callid);
- if (res) {
- break;
- }
- ast_safe_sleep(c, 500);
- ast_indicate(c, -1);
- ast_safe_sleep(c, 1000);
- memset(d->exten, 0, sizeof(d->exten));
- transmit_tone(s, SKINNY_DIALTONE, l->instance, sub->callid);
- len = 0;
- getforward = 0;
- } else {
- ast_copy_string(c->exten, d->exten, sizeof(c->exten));
- ast_copy_string(l->lastnumberdialed, d->exten, sizeof(l->lastnumberdialed));
- memset (d->exten, 0, sizeof(d->exten));
- skinny_newcall(c);
- return NULL;
- }
- } else {
- /* It's a match, but they just typed a digit, and there is an ambiguous match,
- so just set the timeout to matchdigittimeout and wait some more */
- timeout = matchdigittimeout;
- }
- } else if (res == 0) {
- ast_log(LOG_DEBUG, "Not enough digits (and no ambiguous match)...\n");
- memset(d->exten, 0, sizeof(d->exten));
- transmit_tone(s, SKINNY_REORDER, l->instance, sub->callid);
- if (sub->owner && sub->owner->_state != AST_STATE_UP) {
- ast_indicate(c, -1);
- ast_hangup(c);
- }
- return NULL;
- } else if (!ast_canmatch_extension(c, c->context, d->exten, 1, c->cid.cid_num) &&
- ((d->exten[0] != '*') || (!ast_strlen_zero(d->exten) > 2))) {
- ast_log(LOG_WARNING, "Can't match [%s] from '%s' in context %s\n", d->exten, c->cid.cid_num ? c->cid.cid_num : "<Unknown Caller>", c->context);
- memset(d->exten, 0, sizeof(d->exten));
- transmit_tone(s, SKINNY_REORDER, l->instance, sub->callid);
- /* hang out for 3 seconds to let congestion play */
- ast_safe_sleep(c, 3000);
- break;
- }
- if (!timeout) {
- timeout = gendigittimeout;
- }
- if (len && !ast_ignore_pattern(c->context, d->exten)) {
- ast_indicate(c, -1);
- }
- }
- if (c)
- ast_hangup(c);
-
- memset(d->exten, 0, sizeof(d->exten));
- return NULL;
-}
-
-
-
-static int skinny_call(struct ast_channel *ast, char *dest, int timeout)
-{
- int res = 0;
- int tone = 0;
- struct skinny_subchannel *sub = ast->tech_pvt;
- struct skinny_line *l = sub->parent;
- struct skinny_device *d = l->parent;
- struct skinnysession *s = d->session;
-
- if (!d->registered) {
- ast_log(LOG_ERROR, "Device not registered, cannot call %s\n", dest);
- return -1;
- }
-
- if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
- ast_log(LOG_WARNING, "skinny_call called on %s, neither down nor reserved\n", ast->name);
- return -1;
- }
-
- if (skinnydebug)
- ast_verbose(VERBOSE_PREFIX_3 "skinny_call(%s)\n", ast->name);
-
- if (l->dnd) {
- ast_queue_control(ast, AST_CONTROL_BUSY);
- return -1;
- }
-
- switch (l->hookstate) {
- case SKINNY_OFFHOOK:
- tone = SKINNY_CALLWAITTONE;
- break;
- case SKINNY_ONHOOK:
- tone = SKINNY_ALERT;
- break;
- default:
- ast_log(LOG_ERROR, "Don't know how to deal with hookstate %d\n", l->hookstate);
- break;
- }
-
- transmit_callstate(s, l->instance, SKINNY_RINGIN, sub->callid);
- transmit_selectsoftkeys(s, l->instance, sub->callid, KEYDEF_RINGIN);
- transmit_displaypromptstatus(s, "Ring-In", 0, l->instance, sub->callid);
- transmit_callinfo(s, ast->cid.cid_name, ast->cid.cid_num, l->cid_name, l->cid_num, l->instance, sub->callid, 1);
- transmit_lamp_indication(s, STIMULUS_LINE, l->instance, SKINNY_LAMP_BLINK);
- transmit_ringer_mode(s, SKINNY_RING_INSIDE);
-
- ast_setstate(ast, AST_STATE_RINGING);
- ast_queue_control(ast, AST_CONTROL_RINGING);
- sub->outgoing = 1;
- return res;
-}
-
-static int skinny_hangup(struct ast_channel *ast)
-{
- struct skinny_subchannel *sub = ast->tech_pvt;
- struct skinny_line *l;
- struct skinny_device *d;
- struct skinnysession *s;
-
- if (!sub) {
- ast_log(LOG_DEBUG, "Asked to hangup channel not connected\n");
- return 0;
- }
- l = sub->parent;
- d = l->parent;
- s = d->session;
- if (skinnydebug)
- ast_verbose("skinny_hangup(%s) on %s@%s\n", ast->name, l->name, d->name);
-
- if (d->registered) {
- if ((l->type = TYPE_LINE) && (l->hookstate == SKINNY_OFFHOOK)) {
- l->hookstate = SKINNY_ONHOOK;
- transmit_callstate(s, l->instance, SKINNY_ONHOOK, sub->callid);
- transmit_lamp_indication(s, STIMULUS_LINE, l->instance, SKINNY_LAMP_OFF);
- transmit_speaker_mode(s, SKINNY_SPEAKEROFF);
- } else if ((l->type = TYPE_LINE) && (l->hookstate == SKINNY_ONHOOK)) {
- transmit_tone(s, SKINNY_SILENCE, l->instance, sub->callid);
- transmit_callstate(s, l->instance, SKINNY_ONHOOK, sub->callid);
- transmit_ringer_mode(s, SKINNY_RING_OFF);
- transmit_lamp_indication(s, STIMULUS_LINE, l->instance, SKINNY_LAMP_OFF);
- do_housekeeping(s);
- }
- }
- ast_mutex_lock(&sub->lock);
- sub->owner = NULL;
- ast->tech_pvt = NULL;
- sub->alreadygone = 0;
- sub->outgoing = 0;
- if (sub->rtp) {
- ast_rtp_destroy(sub->rtp);
- sub->rtp = NULL;
- }
- ast_mutex_unlock(&sub->lock);
- return 0;
-}
-
-static int skinny_answer(struct ast_channel *ast)
-{
- int res = 0;
- struct skinny_subchannel *sub = ast->tech_pvt;
- struct skinny_line *l = sub->parent;
- struct skinny_device *d = l->parent;
- struct skinnysession *s = d->session;
- char exten[AST_MAX_EXTENSION] = "";
-
- ast_copy_string(exten, S_OR(ast->macroexten, ast->exten), sizeof(exten));
-
- sub->cxmode = SKINNY_CX_SENDRECV;
- if (!sub->rtp) {
- start_rtp(sub);
- }
- if (skinnydebug)
- ast_verbose("skinny_answer(%s) on %s@%s-%d\n", ast->name, l->name, d->name, sub->callid);
- if (ast->_state != AST_STATE_UP) {
- ast_setstate(ast, AST_STATE_UP);
- }
-
- transmit_tone(s, SKINNY_SILENCE, l->instance, sub->callid);
- /* order matters here...
- for some reason, transmit_callinfo must be before transmit_callstate,
- or you won't get keypad messages in some situations. */
- transmit_callinfo(s, ast->cid.cid_name, ast->cid.cid_num, exten, exten, l->instance, sub->callid, 2);
- transmit_callstate(s, l->instance, SKINNY_CONNECTED, sub->callid);
- transmit_selectsoftkeys(s, l->instance, sub->callid, KEYDEF_CONNECTED);
- transmit_dialednumber(s, exten, l->instance, sub->callid);
- transmit_displaypromptstatus(s, "Connected", 0, l->instance, sub->callid);
- return res;
-}
-
-/* Retrieve audio/etc from channel. Assumes sub->lock is already held. */
-static struct ast_frame *skinny_rtp_read(struct skinny_subchannel *sub)
-{
- struct ast_channel *ast = sub->owner;
- struct ast_frame *f;
-
- if (!sub->rtp) {
- /* We have no RTP allocated for this channel */
- return &ast_null_frame;
- }
-
- switch(ast->fdno) {
- case 0:
- f = ast_rtp_read(sub->rtp); /* RTP Audio */
- break;
- case 1:
- f = ast_rtcp_read(sub->rtp); /* RTCP Control Channel */
- break;
- case 2:
- f = ast_rtp_read(sub->vrtp); /* RTP Video */
- break;
- case 3:
- f = ast_rtcp_read(sub->vrtp); /* RTCP Control Channel for video */
- break;
-#if 0
- case 5:
- /* Not yet supported */
- f = ast_udptl_read(sub->udptl); /* UDPTL for T.38 */
- break;
-#endif
- default:
- f = &ast_null_frame;
- }
-
- if (ast) {
- /* We already hold the channel lock */
- if (f->frametype == AST_FRAME_VOICE) {
- if (f->subclass != ast->nativeformats) {
- ast_log(LOG_DEBUG, "Oooh, format changed to %d\n", f->subclass);
- ast->nativeformats = f->subclass;
- ast_set_read_format(ast, ast->readformat);
- ast_set_write_format(ast, ast->writeformat);
- }
- }
- }
- return f;
-}
-
-static struct ast_frame *skinny_read(struct ast_channel *ast)
-{
- struct ast_frame *fr;
- struct skinny_subchannel *sub = ast->tech_pvt;
- ast_mutex_lock(&sub->lock);
- fr = skinny_rtp_read(sub);
- ast_mutex_unlock(&sub->lock);
- return fr;
-}
-
-static int skinny_write(struct ast_channel *ast, struct ast_frame *frame)
-{
- struct skinny_subchannel *sub = ast->tech_pvt;
- int res = 0;
- if (frame->frametype != AST_FRAME_VOICE) {
- if (frame->frametype == AST_FRAME_IMAGE) {
- return 0;
- } else {
- ast_log(LOG_WARNING, "Can't send %d type frames with skinny_write\n", frame->frametype);
- return 0;
- }
- } else {
- if (!(frame->subclass & ast->nativeformats)) {
- ast_log(LOG_WARNING, "Asked to transmit frame type %d, while native formats is %d (read/write = %d/%d)\n",
- frame->subclass, ast->nativeformats, ast->readformat, ast->writeformat);
- return -1;
- }
- }
- if (sub) {
- ast_mutex_lock(&sub->lock);
- if (sub->rtp) {
- res = ast_rtp_write(sub->rtp, frame);
- }
- ast_mutex_unlock(&sub->lock);
- }
- return res;
-}
-
-static int skinny_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
-{
- struct skinny_subchannel *sub = newchan->tech_pvt;
- ast_log(LOG_NOTICE, "skinny_fixup(%s, %s)\n", oldchan->name, newchan->name);
- if (sub->owner != oldchan) {
- ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, sub->owner);
- return -1;
- }
- sub->owner = newchan;
- return 0;
-}
-
-static int skinny_senddigit_begin(struct ast_channel *ast, char digit)
-{
- return -1; /* Start inband indications */
-}
-
-static int skinny_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration)
-{
-#if 0
- struct skinny_subchannel *sub = ast->tech_pvt;
- struct skinny_line *l = sub->parent;
- struct skinny_device *d = l->parent;
- int tmp;
- /* not right */
- sprintf(tmp, "%d", digit);
- transmit_tone(d->session, digit, l->instance, sub->callid);
-#endif
- return -1; /* Stop inband indications */
-}
-
-static char *control2str(int ind) {
- char *tmp;
-
- switch (ind) {
- case AST_CONTROL_HANGUP:
- return "Other end has hungup";
- case AST_CONTROL_RING:
- return "Local ring";
- case AST_CONTROL_RINGING:
- return "Remote end is ringing";
- case AST_CONTROL_ANSWER:
- return "Remote end has answered";
- case AST_CONTROL_BUSY:
- return "Remote end is busy";
- case AST_CONTROL_TAKEOFFHOOK:
- return "Make it go off hook";
- case AST_CONTROL_OFFHOOK:
- return "Line is off hook";
- case AST_CONTROL_CONGESTION:
- return "Congestion (circuits busy)";
- case AST_CONTROL_FLASH:
- return "Flash hook";
- case AST_CONTROL_WINK:
- return "Wink";
- case AST_CONTROL_OPTION:
- return "Set a low-level option";
- case AST_CONTROL_RADIO_KEY:
- return "Key Radio";
- case AST_CONTROL_RADIO_UNKEY:
- return "Un-Key Radio";
- case AST_CONTROL_PROGRESS:
- return "Remote end is making Progress";
- case AST_CONTROL_PROCEEDING:
- return "Remote end is proceeding";
- case AST_CONTROL_HOLD:
- return "Hold";
- case AST_CONTROL_UNHOLD:
- return "Unhold";
- case -1:
- return "Stop tone";
- default:
- if (!(tmp = ast_threadstorage_get(&control2str_threadbuf, CONTROL2STR_BUFSIZE)))
- return "Unknown";
- snprintf(tmp, CONTROL2STR_BUFSIZE, "UNKNOWN-%d", ind);
- return tmp;
- }
-}
-
-
-static int skinny_indicate(struct ast_channel *ast, int ind, const void *data, size_t datalen)
-{
- struct skinny_subchannel *sub = ast->tech_pvt;
- struct skinny_line *l = sub->parent;
- struct skinny_device *d = l->parent;
- struct skinnysession *s = d->session;
- char exten[AST_MAX_EXTENSION] = "";
-
- if (!s) {
- ast_log(LOG_NOTICE, "Asked to indicate '%s' condition on channel %s, but session does not exist.\n", control2str(ind), ast->name);
- return -1;
- }
-
- ast_copy_string(exten, S_OR(ast->macroexten, ast->exten), sizeof(exten));
-
- if (skinnydebug)
- ast_verbose(VERBOSE_PREFIX_3 "Asked to indicate '%s' condition on channel %s\n", control2str(ind), ast->name);
- switch(ind) {
- case AST_CONTROL_RINGING:
- if (ast->_state != AST_STATE_UP) {
- if (!sub->progress) {
- if (!d->earlyrtp) {
- transmit_tone(s, SKINNY_ALERT, l->instance, sub->callid);
- }
- transmit_callstate(s, l->instance, SKINNY_RINGOUT, sub->callid);
- transmit_dialednumber(s, exten, l->instance, sub->callid);
- transmit_displaypromptstatus(s, "Ring Out", 0, l->instance, sub->callid);
- transmit_callinfo(s, ast->cid.cid_name, ast->cid.cid_num, exten, exten, l->instance, sub->callid, 2); /* 2 = outgoing from phone */
- sub->ringing = 1;
- if (!d->earlyrtp) {
- break;
- }
- }
- }
- return -1; /* Tell asterisk to provide inband signalling */
- case AST_CONTROL_BUSY:
- if (ast->_state != AST_STATE_UP) {
- if (!d->earlyrtp) {
- transmit_tone(s, SKINNY_BUSYTONE, l->instance, sub->callid);
- }
- transmit_callstate(s, l->instance, SKINNY_BUSY, sub->callid);
- sub->alreadygone = 1;
- ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
- if (!d->earlyrtp) {
- break;
- }
- }
- return -1; /* Tell asterisk to provide inband signalling */
- case AST_CONTROL_CONGESTION:
- if (ast->_state != AST_STATE_UP) {
- if (!d->earlyrtp) {
- transmit_tone(s, SKINNY_REORDER, l->instance, sub->callid);
- }
- transmit_callstate(s, l->instance, SKINNY_CONGESTION, sub->callid);
- sub->alreadygone = 1;
- ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
- if (!d->earlyrtp) {
- break;
- }
- }
- return -1; /* Tell asterisk to provide inband signalling */
- case AST_CONTROL_PROGRESS:
- if ((ast->_state != AST_STATE_UP) && !sub->progress && !sub->outgoing) {
- if (!d->earlyrtp) {
- transmit_tone(s, SKINNY_ALERT, l->instance, sub->callid);
- }
- transmit_callstate(s, l->instance, SKINNY_PROGRESS, sub->callid);
- transmit_displaypromptstatus(s, "Call Progress", 0, l->instance, sub->callid);
- transmit_callinfo(s, ast->cid.cid_name, ast->cid.cid_num, exten, exten, l->instance, sub->callid, 2); /* 2 = outgoing from phone */
- sub->progress = 1;
- if (!d->earlyrtp) {
- break;
- }
- }
- return -1; /* Tell asterisk to provide inband signalling */
- case -1: /* STOP_TONE */
- transmit_tone(s, SKINNY_SILENCE, l->instance, sub->callid);
- break;
- case AST_CONTROL_HOLD:
- ast_moh_start(ast, data, l->mohinterpret);
- break;
- case AST_CONTROL_UNHOLD:
- ast_moh_stop(ast);
- break;
- case AST_CONTROL_PROCEEDING:
- break;
- case AST_CONTROL_SRCUPDATE:
- ast_rtp_new_source(sub->rtp);
- break;
- default:
- ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", ind);
- return -1; /* Tell asterisk to provide inband signalling */
- }
- return 0;
-}
-
-static struct ast_channel *skinny_new(struct skinny_line *l, int state)
-{
- struct ast_channel *tmp;
- struct skinny_subchannel *sub;
- struct skinny_device *d = l->parent;
- int fmt;
-
- tmp = ast_channel_alloc(1, state, l->cid_num, l->cid_name, l->accountcode, l->exten, l->context, l->amaflags, "Skinny/%s@%s-%d", l->name, d->name, callnums);
- if (!tmp) {
- ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
- return NULL;
- } else {
- sub = ast_calloc(1, sizeof(struct skinny_subchannel));
- if (!sub) {
- ast_log(LOG_WARNING, "Unable to allocate Skinny subchannel\n");
- return NULL;
- } else {
- ast_mutex_init(&sub->lock);
-
- sub->owner = tmp;
- sub->callid = callnums++;
- d->lastlineinstance = l->instance;
- d->lastcallreference = sub->callid;
- sub->cxmode = SKINNY_CX_INACTIVE;
- sub->nat = l->nat;
- sub->parent = l;
- sub->onhold = 0;
-
- sub->next = l->sub;
- l->sub = sub;
- }
- tmp->tech = &skinny_tech;
- tmp->tech_pvt = sub;
- tmp->nativeformats = l->capability;
- if (!tmp->nativeformats)
- tmp->nativeformats = default_capability;
- fmt = ast_best_codec(tmp->nativeformats);
- if (skinnydebug)
- ast_verbose("skinny_new: tmp->nativeformats=%d fmt=%d\n", tmp->nativeformats, fmt);
- if (sub->rtp) {
- tmp->fds[0] = ast_rtp_fd(sub->rtp);
- }
- if (state == AST_STATE_RING) {
- tmp->rings = 1;
- }
- tmp->writeformat = fmt;
- tmp->rawwriteformat = fmt;
- tmp->readformat = fmt;
- tmp->rawreadformat = fmt;
- if (!ast_strlen_zero(l->language))
- ast_string_field_set(tmp, language, l->language);
- if (!ast_strlen_zero(l->accountcode))
- ast_string_field_set(tmp, accountcode, l->accountcode);
- if (l->amaflags)
- tmp->amaflags = l->amaflags;
-
- ast_module_ref(ast_module_info->self);
- tmp->callgroup = l->callgroup;
- tmp->pickupgroup = l->pickupgroup;
- ast_string_field_set(tmp, call_forward, l->call_forward);
- ast_copy_string(tmp->context, l->context, sizeof(tmp->context));
- ast_copy_string(tmp->exten, l->exten, sizeof(tmp->exten));
-
- /* Don't use ast_set_callerid() here because it will
- * generate a needless NewCallerID event */
- tmp->cid.cid_ani = ast_strdup(l->cid_num);
-
- tmp->priority = 1;
- tmp->adsicpe = AST_ADSI_UNAVAILABLE;
-
- if (sub->rtp)
- ast_jb_configure(tmp, &global_jbconf);
-
- if (state != AST_STATE_DOWN) {
- if (ast_pbx_start(tmp)) {
- ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
- ast_hangup(tmp);
- tmp = NULL;
- }
- }
- }
- return tmp;
-}
-
-static int skinny_hold(struct skinny_subchannel *sub)
-{
- struct skinny_line *l = sub->parent;
- struct skinny_device *d = l->parent;
- struct skinnysession *s = d->session;
- struct skinny_req *req;
-
- /* Don't try to hold a channel that doesn't exist */
- if (!sub || !sub->owner)
- return 0;
-
- /* Channel needs to be put on hold */
- if (skinnydebug)
- ast_verbose("Putting on Hold(%d)\n", l->instance);
-
- ast_queue_control_data(sub->owner, AST_CONTROL_HOLD,
- S_OR(l->mohsuggest, NULL),
- !ast_strlen_zero(l->mohsuggest) ? strlen(l->mohsuggest) + 1 : 0);
-
- if (!(req = req_alloc(sizeof(struct activate_call_plane_message), ACTIVATE_CALL_PLANE_MESSAGE)))
- return 0;
-
- req->data.activatecallplane.lineInstance = htolel(l->instance);
- transmit_response(s, req);
-
- if (!(req = req_alloc(sizeof(struct close_receive_channel_message), CLOSE_RECEIVE_CHANNEL_MESSAGE)))
- return 0;
-
- req->data.closereceivechannel.conferenceId = htolel(sub->callid);
- req->data.closereceivechannel.partyId = htolel(sub->callid);
- transmit_response(s, req);
-
- if (!(req = req_alloc(sizeof(struct stop_media_transmission_message), STOP_MEDIA_TRANSMISSION_MESSAGE)))
- return 0;
-
- req->data.stopmedia.conferenceId = htolel(sub->callid);
- req->data.stopmedia.passThruPartyId = htolel(sub->callid);
- transmit_response(s, req);
-
- transmit_lamp_indication(s, STIMULUS_LINE, l->instance, SKINNY_LAMP_BLINK);
- sub->onhold = 1;
- return 1;
-}
-
-static int skinny_unhold(struct skinny_subchannel *sub)
-{
- struct skinny_line *l = sub->parent;
- struct skinny_device *d = l->parent;
- struct skinnysession *s = d->session;
- struct skinny_req *req;
-
- /* Don't try to unhold a channel that doesn't exist */
- if (!sub || !sub->owner)
- return 0;
-
- /* Channel is on hold, so we will unhold */
- if (skinnydebug)
- ast_verbose("Taking off Hold(%d)\n", l->instance);
-
- ast_queue_control(sub->owner, AST_CONTROL_UNHOLD);
-
- if (!(req = req_alloc(sizeof(struct activate_call_plane_message), ACTIVATE_CALL_PLANE_MESSAGE)))
- return 0;
-
- req->data.activatecallplane.lineInstance = htolel(l->instance);
- transmit_response(s, req);
-
- transmit_connect(s, sub);
- transmit_lamp_indication(s, STIMULUS_LINE, l->instance, SKINNY_LAMP_ON);
- sub->onhold = 0;
- return 1;
-}
-
-static int handle_keep_alive_message(struct skinny_req *req, struct skinnysession *s)
-{
- if (!(req = req_alloc(0, KEEP_ALIVE_ACK_MESSAGE)))
- return -1;
-
- transmit_response(s, req);
- do_housekeeping(s);
- return 1;
-}
-
-static int handle_register_message(struct skinny_req *req, struct skinnysession *s)
-{
- char name[16];
- int res;
-
- memcpy(&name, req->data.reg.name, sizeof(name));
-
- res = skinny_register(req, s);
- if (!res) {
- ast_log(LOG_ERROR, "Rejecting Device %s: Device not found\n", name);
- if (!(req = req_alloc(sizeof(struct register_rej_message), REGISTER_REJ_MESSAGE)))
- return -1;
-
- snprintf(req->data.regrej.errMsg, sizeof(req->data.regrej.errMsg), "No Authority: %s", name);
- transmit_response(s, req);
- return 0;
- }
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Device '%s' successfully registered\n", name);
-
- if (!(req = req_alloc(sizeof(struct register_ack_message), REGISTER_ACK_MESSAGE)))
- return -1;
-
- req->data.regack.res[0] = '0';
- req->data.regack.res[1] = '\0';
- req->data.regack.keepAlive = htolel(keep_alive);
- memcpy(req->data.regack.dateTemplate, date_format, sizeof(req->data.regack.dateTemplate));
- req->data.regack.res2[0] = '0';
- req->data.regack.res2[1] = '\0';
- req->data.regack.secondaryKeepAlive = htolel(keep_alive);
- transmit_response(s, req);
- if (skinnydebug)
- ast_verbose("Requesting capabilities\n");
-
- if (!(req = req_alloc(0, CAPABILITIES_REQ_MESSAGE)))
- return -1;
-
- transmit_response(s, req);
-
- return res;
-}
-
-static int handle_ip_port_message(struct skinny_req *req, struct skinnysession *s)
-{
- /* no response necessary */
- return 1;
-}
-
-static int handle_keypad_button_message(struct skinny_req *req, struct skinnysession *s)
-{
- struct skinny_subchannel *sub = NULL;
- struct skinny_line *l;
- struct skinny_device *d = s->device;
- struct ast_frame f = { 0, };
- char dgt;
- int digit;
- int lineInstance;
- int callReference;
-
- digit = letohl(req->data.keypad.button);
- lineInstance = letohl(req->data.keypad.lineInstance);
- callReference = letohl(req->data.keypad.callReference);
-
- if (digit == 14) {
- dgt = '*';
- } else if (digit == 15) {
- dgt = '#';
- } else if (digit >= 0 && digit <= 9) {
- dgt = '0' + digit;
- } else {
- /* digit=10-13 (A,B,C,D ?), or
- * digit is bad value
- *
- * probably should not end up here, but set
- * value for backward compatibility, and log
- * a warning.
- */
- dgt = '0' + digit;
- ast_log(LOG_WARNING, "Unsupported digit %d\n", digit);
- }
-
- f.subclass = dgt;
-
- f.src = "skinny";
-
- if (lineInstance && callReference)
- sub = find_subchannel_by_instance_reference(d, lineInstance, callReference);
- else
- sub = find_subchannel_by_instance_reference(d, d->lastlineinstance, d->lastcallreference);
-
- if (!sub)
- return 0;
-
- l = sub->parent;
- if (sub->owner) {
- if (sub->owner->_state == 0) {
- f.frametype = AST_FRAME_DTMF_BEGIN;
- ast_queue_frame(sub->owner, &f);
- }
- /* XXX MUST queue this frame to all lines in threeway call if threeway call is active */
- f.frametype = AST_FRAME_DTMF_END;
- ast_queue_frame(sub->owner, &f);
- /* XXX This seriously needs to be fixed */
- if (sub->next && sub->next->owner) {
- if (sub->owner->_state == 0) {
- f.frametype = AST_FRAME_DTMF_BEGIN;
- ast_queue_frame(sub->next->owner, &f);
- }
- f.frametype = AST_FRAME_DTMF_END;
- ast_queue_frame(sub->next->owner, &f);
- }
- } else {
- if (skinnydebug)
- ast_verbose("No owner: %s\n", l->name);
- }
- return 1;
-}
-
-static int handle_stimulus_message(struct skinny_req *req, struct skinnysession *s)
-{
- struct skinny_device *d = s->device;
- struct skinny_line *l;
- struct skinny_subchannel *sub;
- /*struct skinny_speeddial *sd;*/
- struct ast_channel *c;
- pthread_t t;
- int event;
- int instance;
- int callreference;
- /*int res = 0;*/
-
- event = letohl(req->data.stimulus.stimulus);
- instance = letohl(req->data.stimulus.stimulusInstance);
- callreference = letohl(req->data.stimulus.callreference);
- if (skinnydebug)
- ast_verbose("callreference in handle_stimulus_message is '%d'\n", callreference);
-
- /* Note that this call should be using the passed in instance and callreference */
- sub = find_subchannel_by_instance_reference(d, d->lastlineinstance, d->lastcallreference);
-
- if (!sub) {
- l = find_line_by_instance(d, d->lastlineinstance);
- if (!l) {
- return 0;
- }
- } else {
- l = sub->parent;
- }
-
- switch(event) {
- case STIMULUS_REDIAL:
- if (skinnydebug)
- ast_verbose("Received Stimulus: Redial(%d/%d)\n", instance, callreference);
-
-#if 0
- if (ast_strlen_zero(l->lastnumberdialed)) {
- ast_log(LOG_WARNING, "Attempted redial, but no previously dialed number found.\n");
- l->hookstate = SKINNY_ONHOOK;
- transmit_speaker_mode(s, SKINNY_SPEAKEROFF);
- transmit_callstate(s, l->instance, SKINNY_ONHOOK, instance);
- break;
- }
-
- c = skinny_new(l, AST_STATE_DOWN);
- if(!c) {
- ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
- } else {
- sub = c->tech_pvt;
- transmit_callstate(s, l->instance, SKINNY_OFFHOOK, sub->callid);
- if (skinnydebug)
- ast_verbose("Attempting to Clear display on Skinny %s@%s\n", l->name, d->name);
- transmit_displaymessage(s, NULL, l->instance, sub->callid); /* clear display */
- transmit_tone(s, SKINNY_DIALTONE, l->instance, sub->callid);
- transmit_selectsoftkeys(s, l->instance, sub->callid, KEYDEF_RINGOUT);
-
- if (!ast_ignore_pattern(c->context, l->lastnumberdialed)) {
- transmit_tone(s, SKINNY_SILENCE, l->instance, sub->callid);
- }
- ast_copy_string(c->exten, l->lastnumberdialed, sizeof(c->exten));
- if (ast_pthread_create(&t, NULL, skinny_newcall, c)) {
- ast_log(LOG_WARNING, "Unable to create new call thread: %s\n", strerror(errno));
- ast_hangup(c);
- }
- }
-#endif
- break;
- case STIMULUS_SPEEDDIAL:
- if (skinnydebug)
- ast_verbose("Received Stimulus: SpeedDial(%d/%d)\n", instance, callreference);
-
-#if 0
- if (!(sd = find_speeddial_by_instance(d, instance))) {
- return 0;
- }
-
- if (ast_strlen_zero(l->lastnumberdialed)) {
- ast_log(LOG_WARNING, "Attempted redial, but no previously dialed number found.\n");
- l->hookstate = SKINNY_ONHOOK;
- transmit_speaker_mode(s, SKINNY_SPEAKEROFF);
- transmit_callstate(s, l->instance, SKINNY_ONHOOK, instance);
- break;
- }
-
- c = skinny_new(l, AST_STATE_DOWN);
- if(c) {
- sub = c->tech_pvt;
- l = sub->parent;
- transmit_callstate(s, l->instance, SKINNY_OFFHOOK, sub->callid);
- if (skinnydebug)
- ast_verbose("Attempting to Clear display on Skinny %s@%s\n", l->name, d->name);
- transmit_displaymessage(s, NULL, l->instance, sub->callid); /* clear display */
- transmit_tone(s, SKINNY_DIALTONE, l->instance, sub->callid);
- transmit_selectsoftkeys(s, l->instance, sub->callid, KEYDEF_RINGOUT);
-
- if (!ast_ignore_pattern(c->context, sd->exten)) {
- transmit_tone(s, SKINNY_SILENCE, l->instance, sub->callid);
- }
- if (ast_exists_extension(c, c->context, sd->exten, 1, l->cid_num)) {
- if (!ast_matchmore_extension(c, c->context, sd->exten, 1, l->cid_num)) {
- ast_copy_string(c->exten, sd->exten, sizeof(c->exten));
- ast_copy_string(l->lastnumberdialed, sd->exten, sizeof(l->lastnumberdialed));
- skinny_newcall(c);
- break;
- }
- }
- } else {
- ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
- }
-#endif
- break;
- case STIMULUS_HOLD:
- if (skinnydebug)
- ast_verbose("Received Stimulus: Hold(%d/%d)\n", instance, callreference);
-
- if (!sub)
- break;
-
- if (sub->onhold) {
- skinny_unhold(sub);
- } else {
- skinny_hold(sub);
- }
- break;
- case STIMULUS_TRANSFER:
- if (skinnydebug)
- ast_verbose("Received Stimulus: Transfer(%d/%d)\n", instance, callreference);
- /* XXX figure out how to transfer */
- break;
- case STIMULUS_CONFERENCE:
- if (skinnydebug)
- ast_verbose("Received Stimulus: Conference(%d/%d)\n", instance, callreference);
- /* XXX determine the best way to pull off a conference. Meetme? */
- break;
- case STIMULUS_VOICEMAIL:
- if (skinnydebug)
- ast_verbose("Received Stimulus: Voicemail(%d/%d)\n", instance, callreference);
- /* XXX Find and dial voicemail extension */
- break;
- case STIMULUS_CALLPARK:
- if (skinnydebug)
- ast_verbose("Received Stimulus: Park Call(%d/%d)\n", instance, callreference);
- /* XXX Park the call */
- break;
- case STIMULUS_FORWARDALL:
- if (skinnydebug)
- ast_verbose("Received Stimulus: Forward All(%d/%d)\n", instance, callreference);
- /* Why is DND under FORWARDALL? */
- /* Because it's the same thing. */
-
- /* Do not disturb */
- if (l->dnd != 0){
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Disabling DND on %s@%s\n", l->name, d->name);
- l->dnd = 0;
- transmit_lamp_indication(s, STIMULUS_FORWARDALL, 1, SKINNY_LAMP_ON);
- transmit_displaynotify(s, "DnD disabled", 10);
- } else {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Enabling DND on %s@%s\n", l->name, d->name);
- l->dnd = 1;
- transmit_lamp_indication(s, STIMULUS_FORWARDALL, 1, SKINNY_LAMP_OFF);
- transmit_displaynotify(s, "DnD enabled", 10);
- }
- break;
- case STIMULUS_FORWARDBUSY:
- if (skinnydebug)
- ast_verbose("Received Stimulus: Forward Busy (%d/%d)\n", instance, callreference);
- break;
- case STIMULUS_FORWARDNOANSWER:
- if (skinnydebug)
- ast_verbose("Received Stimulus: Forward No Answer (%d/%d)\n", instance, callreference);
- break;
- case STIMULUS_DISPLAY:
- /* Not sure what this is */
- if (skinnydebug)
- ast_verbose("Received Stimulus: Display(%d/%d)\n", instance, callreference);
- break;
- case STIMULUS_LINE:
- if (skinnydebug)
- ast_verbose("Received Stimulus: Line(%d/%d)\n", instance, callreference);
-
- l = find_line_by_instance(s->device, instance);
-
- if (!l) {
- return 0;
- }
-
- /* turn the speaker on */
- transmit_speaker_mode(s, SKINNY_SPEAKERON);
- transmit_ringer_mode(s, SKINNY_RING_OFF);
- transmit_lamp_indication(s, STIMULUS_LINE, l->instance, SKINNY_LAMP_ON);
-
- l->hookstate = SKINNY_OFFHOOK;
-
- if (sub && sub->outgoing) {
- /* We're answering a ringing call */
- ast_queue_control(sub->owner, AST_CONTROL_ANSWER);
- transmit_callstate(s, l->instance, SKINNY_OFFHOOK, sub->callid);
- transmit_tone(s, SKINNY_SILENCE, l->instance, sub->callid);
- transmit_callstate(s, l->instance, SKINNY_CONNECTED, sub->callid);
- transmit_displaypromptstatus(s, "Connected", 0, l->instance, sub->callid);
- transmit_selectsoftkeys(s, l->instance, sub->callid, KEYDEF_CONNECTED);
- start_rtp(sub);
- ast_setstate(sub->owner, AST_STATE_UP);
- } else {
- if (sub && sub->owner) {
- ast_log(LOG_DEBUG, "Current subchannel [%s] already has owner\n", sub->owner->name);
- } else {
- c = skinny_new(l, AST_STATE_DOWN);
- if(c) {
- sub = c->tech_pvt;
- transmit_callstate(s, l->instance, SKINNY_OFFHOOK, sub->callid);
- if (skinnydebug)
- ast_verbose("Attempting to Clear display on Skinny %s@%s\n", l->name, d->name);
- transmit_displaymessage(s, NULL, l->instance, sub->callid); /* clear display */
- transmit_tone(s, SKINNY_DIALTONE, l->instance, sub->callid);
- transmit_selectsoftkeys(s, l->instance, sub->callid, KEYDEF_OFFHOOK);
-
- /* start the switch thread */
- if (ast_pthread_create(&t, NULL, skinny_ss, c)) {
- ast_log(LOG_WARNING, "Unable to create switch thread: %s\n", strerror(errno));
- ast_hangup(c);
- }
- } else {
- ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
- }
- }
- }
- break;
- default:
- if (skinnydebug)
- ast_verbose("RECEIVED UNKNOWN STIMULUS: %d(%d/%d)\n", event, instance, callreference);
- break;
- }
- return 1;
-}
-
-static int handle_offhook_message(struct skinny_req *req, struct skinnysession *s)
-{
- struct skinny_device *d = s->device;
- struct skinny_line *l;
- struct skinny_subchannel *sub;
- struct ast_channel *c;
- pthread_t t;
- int unknown1;
- int unknown2;
-
- unknown1 = letohl(req->data.offhook.unknown1);
- unknown2 = letohl(req->data.offhook.unknown2);
-
- sub = find_subchannel_by_instance_reference(d, d->lastlineinstance, d->lastcallreference);
-
- if (!sub) {
- l = find_line_by_instance(d, d->lastlineinstance);
- if (!l) {
- return 0;
- }
- } else {
- l = sub->parent;
- }
-
- transmit_ringer_mode(s, SKINNY_RING_OFF);
- l->hookstate = SKINNY_OFFHOOK;
-
- if (sub && sub->onhold) {
- return 1;
- }
-
- transmit_lamp_indication(s, STIMULUS_LINE, l->instance, SKINNY_LAMP_ON);
-
- if (sub && sub->outgoing) {
- /* We're answering a ringing call */
- ast_queue_control(sub->owner, AST_CONTROL_ANSWER);
- transmit_callstate(s, l->instance, SKINNY_OFFHOOK, sub->callid);
- transmit_tone(s, SKINNY_SILENCE, l->instance, sub->callid);
- transmit_callstate(s, l->instance, SKINNY_CONNECTED, sub->callid);
- transmit_selectsoftkeys(s, l->instance, sub->callid, KEYDEF_CONNECTED);
- start_rtp(sub);
- ast_setstate(sub->owner, AST_STATE_UP);
- } else {
- if (sub && sub->owner) {
- ast_log(LOG_DEBUG, "Current sub [%s] already has owner\n", sub->owner->name);
- } else {
- c = skinny_new(l, AST_STATE_DOWN);
- if(c) {
- sub = c->tech_pvt;
- transmit_callstate(s, l->instance, SKINNY_OFFHOOK, sub->callid);
- if (skinnydebug)
- ast_verbose("Attempting to Clear display on Skinny %s@%s\n", l->name, d->name);
- transmit_displaymessage(s, NULL, l->instance, sub->callid); /* clear display */
- transmit_tone(s, SKINNY_DIALTONE, l->instance, sub->callid);
- transmit_selectsoftkeys(s, l->instance, sub->callid, KEYDEF_OFFHOOK);
-
- /* start the switch thread */
- if (ast_pthread_create(&t, NULL, skinny_ss, c)) {
- ast_log(LOG_WARNING, "Unable to create switch thread: %s\n", strerror(errno));
- ast_hangup(c);
- }
- } else {
- ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
- }
- }
- }
- return 1;
-}
-
-static int handle_onhook_message(struct skinny_req *req, struct skinnysession *s)
-{
- struct skinny_device *d = s->device;
- struct skinny_line *l;
- struct skinny_subchannel *sub;
- int unknown1;
- int unknown2;
-
- unknown1 = letohl(req->data.onhook.unknown1);
- unknown2 = letohl(req->data.onhook.unknown2);
-
- sub = find_subchannel_by_instance_reference(d, d->lastlineinstance, d->lastcallreference);
-
- if (!sub) {
- return 0;
- }
- l = sub->parent;
-
- if (l->hookstate == SKINNY_ONHOOK) {
- /* Something else already put us back on hook */
- return 0;
- }
- l->hookstate = SKINNY_ONHOOK;
-
- if (sub->onhold) {
- return 0;
- }
-
- sub->cxmode = SKINNY_CX_RECVONLY;
- transmit_callstate(s, l->instance, l->hookstate, sub->callid);
- if (skinnydebug)
- ast_verbose("Skinny %s@%s went on hook\n", l->name, d->name);
- if (l->transfer && (sub->owner && sub->next && sub->next->owner) && ((!sub->outgoing) || (sub->next && !sub->next->outgoing))) {
- /* We're allowed to transfer, we have two active calls and
- we made at least one of the calls. Let's try and transfer */
-
-#if 0
- if ((res = attempt_transfer(p)) < 0) {
- if (sub->next && sub->next->owner) {
- sub->next->alreadygone = 1;
- ast_queue_hangup(sub->next->owner,1);
- }
- } else if (res) {
- ast_log(LOG_WARNING, "Transfer attempt failed\n");
- return 0;
- }
-#endif
- } else {
- /* Hangup the current call */
- /* If there is another active call, skinny_hangup will ring the phone with the other call */
- if (sub->owner) {
- sub->alreadygone = 1;
- ast_queue_hangup(sub->owner);
- } else {
- ast_log(LOG_WARNING, "Skinny(%s@%s-%d) channel already destroyed\n",
- l->name, d->name, sub->callid);
- }
- }
- if ((l->hookstate == SKINNY_ONHOOK) && (sub->next && !sub->next->rtp)) {
- do_housekeeping(s);
- }
- return 1;
-}
-
-static int handle_capabilities_res_message(struct skinny_req *req, struct skinnysession *s)
-{
- struct skinny_device *d = s->device;
- struct skinny_line *l;
- uint32_t count = 0;
- int codecs = 0;
- int i;
-
- count = letohl(req->data.caps.count);
- if (count > SKINNY_MAX_CAPABILITIES) {
- count = SKINNY_MAX_CAPABILITIES;
- ast_log(LOG_WARNING, "Received more capabilities than we can handle (%d). Ignoring the rest.\n", SKINNY_MAX_CAPABILITIES);
- }
-
- for (i = 0; i < count; i++) {
- int acodec = 0;
- int scodec = 0;
- scodec = letohl(req->data.caps.caps[i].codec);
- acodec = codec_skinny2ast(scodec);
- if (skinnydebug)
- ast_verbose("Adding codec capability '%d (%d)'\n", acodec, scodec);
- codecs |= acodec;
- }
-
- d->capability &= codecs;
- ast_verbose("Device capability set to '%d'\n", d->capability);
- for (l = d->lines; l; l = l->next) {
- ast_mutex_lock(&l->lock);
- l->capability = d->capability;
- ast_mutex_unlock(&l->lock);
- }
-
- return 1;
-}
-
-static int handle_speed_dial_stat_req_message(struct skinny_req *req, struct skinnysession *s)
-{
- struct skinny_device *d = s->device;
- struct skinny_speeddial *sd;
- int instance;
-
- instance = letohl(req->data.speeddialreq.speedDialNumber);
-
- sd = find_speeddial_by_instance(d, instance);
-
- if (!sd) {
- return 0;
- }
-
- if (!(req = req_alloc(sizeof(struct speed_dial_stat_res_message), SPEED_DIAL_STAT_RES_MESSAGE)))
- return -1;
-
- req->data.speeddialreq.speedDialNumber = htolel(instance);
- ast_copy_string(req->data.speeddial.speedDialDirNumber, sd->exten, sizeof(req->data.speeddial.speedDialDirNumber));
- ast_copy_string(req->data.speeddial.speedDialDisplayName, sd->label, sizeof(req->data.speeddial.speedDialDisplayName));
-
- transmit_response(s, req);
- return 1;
-}
-
-static int handle_line_state_req_message(struct skinny_req *req, struct skinnysession *s)
-{
- struct skinny_device *d = s->device;
- struct skinny_line *l;
- int instance;
-
- instance = letohl(req->data.line.lineNumber);
-
- ast_mutex_lock(&devicelock);
-
- l = find_line_by_instance(d, instance);
-
- if (!l) {
- return 0;
- }
-
- ast_mutex_unlock(&devicelock);
-
- if (!(req = req_alloc(sizeof(struct line_stat_res_message), LINE_STAT_RES_MESSAGE)))
- return -1;
-
- req->data.linestat.lineNumber = letohl(instance);
- memcpy(req->data.linestat.lineDirNumber, l->name,
- sizeof(req->data.linestat.lineDirNumber));
- memcpy(req->data.linestat.lineDisplayName, l->label,
- sizeof(req->data.linestat.lineDisplayName));
- transmit_response(s,req);
- return 1;
-}
-
-static int handle_time_date_req_message(struct skinny_req *req, struct skinnysession *s)
-{
- time_t timer;
- struct tm *cmtime;
-
- if (!(req = req_alloc(sizeof(struct definetimedate_message), DEFINETIMEDATE_MESSAGE)))
- return -1;
-
- timer = time(NULL);
- cmtime = localtime(&timer);
- req->data.definetimedate.year = htolel(cmtime->tm_year+1900);
- req->data.definetimedate.month = htolel(cmtime->tm_mon+1);
- req->data.definetimedate.dayofweek = htolel(cmtime->tm_wday);
- req->data.definetimedate.day = htolel(cmtime->tm_mday);
- req->data.definetimedate.hour = htolel(cmtime->tm_hour);
- req->data.definetimedate.minute = htolel(cmtime->tm_min);
- req->data.definetimedate.seconds = htolel(cmtime->tm_sec);
- req->data.definetimedate.milliseconds = htolel(0);
- req->data.definetimedate.timestamp = htolel(timer);
- transmit_response(s, req);
- return 1;
-}
-
-static int handle_button_template_req_message(struct skinny_req *req, struct skinnysession *s)
-{
- struct skinny_device *d = s->device;
- struct skinny_line *l;
- int i;
-
- struct skinny_speeddial *sd;
- struct button_definition_template btn[42];
- int lineInstance = 1;
- int speeddialInstance = 1;
- int buttonCount = 0;
-
- if (!(req = req_alloc(sizeof(struct button_template_res_message), BUTTON_TEMPLATE_RES_MESSAGE)))
- return -1;
-
- memset(&btn, 0, sizeof(btn));
-
- get_button_template(s, btn);
-
- for (i=0; i<42; i++) {
- int btnSet = 0;
- switch (btn[i].buttonDefinition) {
- case BT_CUST_LINESPEEDDIAL:
- /* assume failure */
- req->data.buttontemplate.definition[i].buttonDefinition = BT_NONE;
- req->data.buttontemplate.definition[i].instanceNumber = htolel(0);
-
- for (l = d->lines; l; l = l->next) {
- if (l->instance == lineInstance) {
- ast_verbose("Adding button: %d, %d\n", BT_LINE, lineInstance);
- req->data.buttontemplate.definition[i].buttonDefinition = BT_LINE;
- req->data.buttontemplate.definition[i].instanceNumber = htolel(lineInstance);
- lineInstance++;
- buttonCount++;
- btnSet = 1;
- break;
- }
- }
-
- if (!btnSet) {
- for (sd = d->speeddials; sd; sd = sd->next) {
- if (sd->instance == speeddialInstance) {
- ast_verbose("Adding button: %d, %d\n", BT_SPEEDDIAL, speeddialInstance);
- req->data.buttontemplate.definition[i].buttonDefinition = BT_SPEEDDIAL;
- req->data.buttontemplate.definition[i].instanceNumber = htolel(speeddialInstance);
- speeddialInstance++;
- buttonCount++;
- btnSet = 1;
- break;
- }
- }
- }
- break;
- case BT_LINE:
- req->data.buttontemplate.definition[i].buttonDefinition = htolel(BT_NONE);
- req->data.buttontemplate.definition[i].instanceNumber = htolel(0);
-
- for (l = d->lines; l; l = l->next) {
- if (l->instance == lineInstance) {
- ast_verbose("Adding button: %d, %d\n", BT_LINE, lineInstance);
- req->data.buttontemplate.definition[i].buttonDefinition = BT_LINE;
- req->data.buttontemplate.definition[i].instanceNumber = htolel(lineInstance);
- lineInstance++;
- buttonCount++;
- btnSet = 1;
- break;
- }
- }
- break;
- case BT_SPEEDDIAL:
- req->data.buttontemplate.definition[i].buttonDefinition = BT_NONE;
- req->data.buttontemplate.definition[i].instanceNumber = 0;
-
- for (sd = d->speeddials; sd; sd = sd->next) {
- if (sd->instance == speeddialInstance) {
- ast_verbose("Adding button: %d, %d\n", BT_SPEEDDIAL, speeddialInstance);
- req->data.buttontemplate.definition[i].buttonDefinition = BT_SPEEDDIAL;
- req->data.buttontemplate.definition[i].instanceNumber = htolel(speeddialInstance);
- speeddialInstance++;
- buttonCount++;
- btnSet = 1;
- break;
- }
- }
- break;
- case BT_CUST_HINT:
- break;
- case BT_NONE:
- break;
- default:
- ast_verbose("Adding button: %d, %d\n", btn[i].buttonDefinition, 0);
- req->data.buttontemplate.definition[i].buttonDefinition = htolel(btn[i].buttonDefinition);
- req->data.buttontemplate.definition[i].instanceNumber = htolel(0);
- buttonCount++;
- btnSet = 1;
- break;
- }
- }
-
- req->data.buttontemplate.buttonOffset = htolel(0);
- req->data.buttontemplate.buttonCount = htolel(buttonCount);
- req->data.buttontemplate.totalButtonCount = htolel(buttonCount);
-
- if (skinnydebug)
- ast_verbose("Sending %d template to %s\n",
- d->type,
- d->name);
- transmit_response(s, req);
- return 1;
-}
-
-static int handle_version_req_message(struct skinny_req *req, struct skinnysession *s)
-{
- struct skinny_device *d = s->device;
- if (!(req = req_alloc(sizeof(struct version_res_message), VERSION_RES_MESSAGE)))
- return -1;
-
- ast_copy_string(req->data.version.version, d->version_id, sizeof(req->data.version.version));
- transmit_response(s, req);
- return 1;
-}
-
-static int handle_server_request_message(struct skinny_req *req, struct skinnysession *s)
-{
- struct skinny_device *d = s->device;
- if (!(req = req_alloc(sizeof(struct server_res_message), SERVER_RES_MESSAGE)))
- return -1;
-
- memcpy(req->data.serverres.server[0].serverName, ourhost,
- sizeof(req->data.serverres.server[0].serverName));
- req->data.serverres.serverListenPort[0] = htolel(ourport);
- req->data.serverres.serverIpAddr[0] = htolel(d->ourip.s_addr);
- transmit_response(s, req);
- return 1;
-}
-
-static int handle_alarm_message(struct skinny_req *req, struct skinnysession *s)
-{
- /* no response necessary */
- if (skinnydebug)
- ast_verbose("Received Alarm Message: %s\n", req->data.alarm.displayMessage);
-
- return 1;
-}
-
-static int handle_open_receive_channel_ack_message(struct skinny_req *req, struct skinnysession *s)
-{
- struct skinny_device *d = s->device;
- struct skinny_line *l;
- struct skinny_subchannel *sub;
- struct ast_format_list fmt;
- struct sockaddr_in sin;
- struct sockaddr_in us;
- uint32_t addr;
- int port;
- int status;
- int passthruid;
-
- status = letohl(req->data.openreceivechannelack.status);
- if (status) {
- ast_log(LOG_ERROR, "Open Receive Channel Failure\n");
- return 0;
- }
- addr = letohl(req->data.openreceivechannelack.ipAddr);
- port = letohl(req->data.openreceivechannelack.port);
- passthruid = letohl(req->data.openreceivechannelack.passThruId);
-
- sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = addr;
- sin.sin_port = htons(port);
-
- sub = find_subchannel_by_reference(d, passthruid);
-
- if (!sub)
- return 0;
-
- l = sub->parent;
-
- if (sub->rtp) {
- ast_rtp_set_peer(sub->rtp, &sin);
- ast_rtp_get_us(sub->rtp, &us);
- } else {
- ast_log(LOG_ERROR, "No RTP structure, this is very bad\n");
- return 0;
- }
-
- if (skinnydebug) {
- ast_verbose("ipaddr = %s:%d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
- ast_verbose("ourip = %s:%d\n", ast_inet_ntoa(d->ourip), ntohs(us.sin_port));
- }
-
- if (!(req = req_alloc(sizeof(struct start_media_transmission_message), START_MEDIA_TRANSMISSION_MESSAGE)))
- return -1;
-
- fmt = ast_codec_pref_getsize(&l->prefs, ast_best_codec(l->capability));
-
- if (skinnydebug)
- ast_verbose("Setting payloadType to '%d' (%d ms)\n", fmt.bits, fmt.cur_ms);
-
- req->data.startmedia.conferenceId = htolel(sub->callid);
- req->data.startmedia.passThruPartyId = htolel(sub->callid);
- req->data.startmedia.remoteIp = htolel(d->ourip.s_addr);
- req->data.startmedia.remotePort = htolel(ntohs(us.sin_port));
- req->data.startmedia.packetSize = htolel(fmt.cur_ms);
- req->data.startmedia.payloadType = htolel(codec_ast2skinny(fmt.bits));
- req->data.startmedia.qualifier.precedence = htolel(127);
- req->data.startmedia.qualifier.vad = htolel(0);
- req->data.startmedia.qualifier.packets = htolel(0);
- req->data.startmedia.qualifier.bitRate = htolel(0);
- transmit_response(s, req);
-
- return 1;
-}
-
-static int handle_enbloc_call_message(struct skinny_req *req, struct skinnysession *s)
-{
- struct skinny_device *d = s->device;
- struct skinny_line *l;
- struct skinny_subchannel *sub = NULL;
- struct ast_channel *c;
- pthread_t t;
-
- if (skinnydebug)
- ast_verbose("Received Enbloc Call: %s\n", req->data.enbloccallmessage.calledParty);
-
- sub = find_subchannel_by_instance_reference(d, d->lastlineinstance, d->lastcallreference);
-
- if (!sub) {
- l = find_line_by_instance(d, d->lastlineinstance);
- if (!l) {
- return 0;
- }
- } else {
- l = sub->parent;
- }
-
- c = skinny_new(l, AST_STATE_DOWN);
-
- if(!c) {
- ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
- } else {
- l->hookstate = SKINNY_OFFHOOK;
-
- sub = c->tech_pvt;
- transmit_callstate(s, l->instance, SKINNY_OFFHOOK, sub->callid);
- if (skinnydebug)
- ast_verbose("Attempting to Clear display on Skinny %s@%s\n", l->name, d->name);
- transmit_displaymessage(s, NULL, l->instance, sub->callid); /* clear display */
- transmit_tone(s, SKINNY_DIALTONE, l->instance, sub->callid);
-
- if (!ast_ignore_pattern(c->context, req->data.enbloccallmessage.calledParty)) {
- transmit_tone(s, SKINNY_SILENCE, l->instance, sub->callid);
- }
- ast_copy_string(c->exten, req->data.enbloccallmessage.calledParty, sizeof(c->exten));
- if (ast_pthread_create(&t, NULL, skinny_newcall, c)) {
- ast_log(LOG_WARNING, "Unable to create new call thread: %s\n", strerror(errno));
- ast_hangup(c);
- }
- }
-
- return 1;
-}
-
-
-static int handle_soft_key_set_req_message(struct skinny_req *req, struct skinnysession *s)
-{
- int i;
- int x;
- int y;
- const struct soft_key_definitions *softkeymode = soft_key_default_definitions;
-
- if (!(req = req_alloc(sizeof(struct soft_key_set_res_message), SOFT_KEY_SET_RES_MESSAGE)))
- return -1;
-
- req->data.softkeysets.softKeySetOffset = htolel(0);
- req->data.softkeysets.softKeySetCount = htolel(11);
- req->data.softkeysets.totalSoftKeySetCount = htolel(11);
- for (x = 0; x < sizeof(soft_key_default_definitions) / sizeof(struct soft_key_definitions); x++) {
- const uint8_t *defaults = softkeymode->defaults;
- /* XXX I wanted to get the size of the array dynamically, but that wasn't wanting to work.
- This will have to do for now. */
- for (y = 0; y < softkeymode->count; y++) {
- for (i = 0; i < (sizeof(soft_key_template_default) / sizeof(struct soft_key_template_definition)); i++) {
- if (defaults[y] == i+1) {
- req->data.softkeysets.softKeySetDefinition[softkeymode->mode].softKeyTemplateIndex[y] = htolel(i+1);
- req->data.softkeysets.softKeySetDefinition[softkeymode->mode].softKeyInfoIndex[y] = htolel(i+301);
- }
- }
- }
- softkeymode++;
- }
- transmit_response(s,req);
- transmit_selectsoftkeys(s, 0, 0, KEYDEF_ONHOOK);
- return 1;
-}
-
-static int handle_soft_key_event_message(struct skinny_req *req, struct skinnysession *s)
-{
- struct skinny_device *d = s->device;
- struct skinny_line *l;
- struct skinny_subchannel *sub = NULL;
- struct ast_channel *c;
- pthread_t t;
- int event;
- int instance;
- int callreference;
-
- event = letohl(req->data.softkeyeventmessage.softKeyEvent);
- instance = letohl(req->data.softkeyeventmessage.instance);
- callreference = letohl(req->data.softkeyeventmessage.callreference);
-
- if (instance) {
- l = find_line_by_instance(d, instance);
- if (callreference) {
- sub = find_subchannel_by_instance_reference(d, instance, callreference);
- } else {
- sub = find_subchannel_by_instance_reference(d, instance, d->lastcallreference);
- }
- } else {
- l = find_line_by_instance(d, d->lastlineinstance);
- }
-
- if (!l) {
- if (skinnydebug)
- ast_verbose("Received Softkey Event: %d(%d/%d)\n", event, instance, callreference);
- return 0;
- }
-
- switch(event) {
- case SOFTKEY_NONE:
- if (skinnydebug)
- ast_verbose("Received Softkey Event: None(%d/%d)\n", instance, callreference);
- break;
- case SOFTKEY_REDIAL:
- if (skinnydebug)
- ast_verbose("Received Softkey Event: Redial(%d/%d)\n", instance, callreference);
-
-#if 0
- if (!sub || !sub->owner) {
- c = skinny_new(l, AST_STATE_DOWN);
- } else {
- c = sub->owner;
- }
-
- if(!c) {
- ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
- } else {
- sub = c->tech_pvt;
- transmit_callstate(s, l->instance, SKINNY_OFFHOOK, sub->callid);
- if (skinnydebug)
- ast_verbose("Attempting to Clear display on Skinny %s@%s\n", l->name, d->name);
- transmit_displaymessage(s, NULL, l->instance, sub->callid); /* clear display */
- transmit_tone(s, SKINNY_DIALTONE, l->instance, sub->callid);
- transmit_selectsoftkeys(s, l->instance, sub->callid, KEYDEF_RINGOUT);
-
- if (!ast_ignore_pattern(c->context, l->lastnumberdialed)) {
- transmit_tone(s, SKINNY_SILENCE, l->instance, sub->callid);
- }
- ast_copy_string(c->exten, l->lastnumberdialed, sizeof(c->exten));
- if (ast_pthread_create(&t, NULL, skinny_newcall, c)) {
- ast_log(LOG_WARNING, "Unable to create new call thread: %s\n", strerror(errno));
- ast_hangup(c);
- }
- }
-#endif
- break;
- case SOFTKEY_NEWCALL: /* Actually the DIAL softkey */
- if (skinnydebug)
- ast_verbose("Received Softkey Event: New Call(%d/%d)\n", instance, callreference);
-
- if (!sub || !sub->owner) {
- c = skinny_new(l, AST_STATE_DOWN);
- } else {
- c = sub->owner;
- }
-
- if (!c) {
- ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
- } else {
- sub = c->tech_pvt;
- if (l->hookstate == SKINNY_ONHOOK) {
- l->hookstate = SKINNY_OFFHOOK;
- transmit_speaker_mode(s, SKINNY_SPEAKERON);
- transmit_callstate(s, l->instance, SKINNY_OFFHOOK, sub->callid);
- }
-
- if (skinnydebug)
- ast_verbose("Attempting to Clear display on Skinny %s@%s\n", l->name, d->name);
- transmit_displaymessage(s, NULL, l->instance, sub->callid); /* clear display */
- transmit_tone(s, SKINNY_DIALTONE, l->instance, sub->callid);
- transmit_selectsoftkeys(s, l->instance, sub->callid, KEYDEF_OFFHOOK);
-
- /* start the switch thread */
- if (ast_pthread_create(&t, NULL, skinny_ss, c)) {
- ast_log(LOG_WARNING, "Unable to create switch thread: %s\n", strerror(errno));
- ast_hangup(c);
- }
- }
- break;
- case SOFTKEY_HOLD:
- if (skinnydebug)
- ast_verbose("Received Softkey Event: Hold(%d/%d)\n", instance, callreference);
-
- if (sub) {
- if (sub->onhold) {
- skinny_unhold(sub);
- } else {
- skinny_hold(sub);
- }
- }
-
- break;
- case SOFTKEY_TRNSFER:
- if (skinnydebug)
- ast_verbose("Received Softkey Event: Transfer(%d/%d)\n", instance, callreference);
- /* XXX figure out how to transfer */
- break;
- case SOFTKEY_CFWDALL:
- if (skinnydebug)
- ast_verbose("Received Softkey Event: Forward All(%d/%d)\n", instance, callreference);
-
- /* Do not disturb */
- if (l->dnd != 0){
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Disabling DND on %s@%s\n", l->name, d->name);
- l->dnd = 0;
- transmit_lamp_indication(s, STIMULUS_FORWARDALL, 1, SKINNY_LAMP_ON);
- transmit_displaynotify(s, "DnD disabled", 10);
- } else {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Enabling DND on %s@%s\n", l->name, d->name);
- l->dnd = 1;
- transmit_lamp_indication(s, STIMULUS_FORWARDALL, 1, SKINNY_LAMP_OFF);
- transmit_displaynotify(s, "DnD enabled", 10);
- }
- break;
- case SOFTKEY_CFWDBUSY:
- if (skinnydebug)
- ast_verbose("Received Softkey Event: Forward Busy (%d/%d)\n", instance, callreference);
- break;
- case SOFTKEY_CFWDNOANSWER:
- if (skinnydebug)
- ast_verbose("Received Softkey Event: Forward No Answer (%d/%d)\n", instance, callreference);
- break;
- case SOFTKEY_BKSPC:
- if (skinnydebug)
- ast_verbose("Received Softkey Event: Backspace(%d/%d)\n", instance, callreference);
- break;
- case SOFTKEY_ENDCALL:
- if (skinnydebug)
- ast_verbose("Received Softkey Event: End Call(%d/%d)\n", instance, callreference);
-
- if (l->hookstate == SKINNY_ONHOOK) {
- /* Something else already put us back on hook */
- break;
- }
- if (sub) {
- sub->cxmode = SKINNY_CX_RECVONLY;
- l->hookstate = SKINNY_ONHOOK;
- transmit_callstate(s, l->instance, l->hookstate, sub->callid);
- if (skinnydebug)
- ast_verbose("Skinny %s@%s went on hook\n", l->name, d->name);
- if (l->transfer && (sub->owner && sub->next && sub->next->owner) && ((!sub->outgoing) || (sub->next && !sub->next->outgoing))) {
- /* We're allowed to transfer, we have two active calls and
- we made at least one of the calls. Let's try and transfer */
-
-#if 0
- if ((res = attempt_transfer(p)) < 0) {
- if (sub->next && sub->next->owner) {
- sub->next->alreadygone = 1;
- ast_queue_hangup(sub->next->owner, 1);
- }
- } else if (res) {
- ast_log(LOG_WARNING, "Transfer attempt failed\n");
- break;
- }
-#endif
- } else {
- /* Hangup the current call */
- /* If there is another active call, skinny_hangup will ring the phone with the other call */
- if (sub->owner) {
- sub->alreadygone = 1;
- ast_queue_hangup(sub->owner);
- } else {
- ast_log(LOG_WARNING, "Skinny(%s@%s-%d) channel already destroyed\n",
- l->name, d->name, sub->callid);
- }
- }
- if ((l->hookstate == SKINNY_ONHOOK) && (sub->next && !sub->next->rtp)) {
- do_housekeeping(s);
- }
- }
- break;
- case SOFTKEY_RESUME:
- if (skinnydebug)
- ast_verbose("Received Softkey Event: Resume(%d/%d)\n", instance, callreference);
- break;
- case SOFTKEY_ANSWER:
- if (skinnydebug)
- ast_verbose("Received Softkey Event: Answer(%d/%d)\n", instance, callreference);
-
- transmit_ringer_mode(s,SKINNY_RING_OFF);
- transmit_lamp_indication(s, STIMULUS_LINE, l->instance, SKINNY_LAMP_ON);
-
- l->hookstate = SKINNY_OFFHOOK;
-
- if (sub && sub->outgoing) {
- /* We're answering a ringing call */
- ast_queue_control(sub->owner, AST_CONTROL_ANSWER);
- transmit_callstate(s, l->instance, SKINNY_OFFHOOK, sub->callid);
- transmit_tone(s, SKINNY_SILENCE, l->instance, sub->callid);
- transmit_callstate(s, l->instance, SKINNY_CONNECTED, sub->callid);
- transmit_selectsoftkeys(s, l->instance, sub->callid, KEYDEF_CONNECTED);
- start_rtp(sub);
- ast_setstate(sub->owner, AST_STATE_UP);
- }
- break;
- case SOFTKEY_INFO:
- if (skinnydebug)
- ast_verbose("Received Softkey Event: Info(%d/%d)\n", instance, callreference);
- break;
- case SOFTKEY_CONFRN:
- if (skinnydebug)
- ast_verbose("Received Softkey Event: Conference(%d/%d)\n", instance, callreference);
- /* XXX determine the best way to pull off a conference. Meetme? */
- break;
- case SOFTKEY_PARK:
- if (skinnydebug)
- ast_verbose("Received Softkey Event: Park Call(%d/%d)\n", instance, callreference);
- /* XXX Park the call */
- break;
- case SOFTKEY_JOIN:
- if (skinnydebug)
- ast_verbose("Received Softkey Event: Join(%d/%d)\n", instance, callreference);
- break;
- case SOFTKEY_MEETME:
- /* XXX How is this different from CONFRN? */
- if (skinnydebug)
- ast_verbose("Received Softkey Event: Meetme(%d/%d)\n", instance, callreference);
- break;
- case SOFTKEY_PICKUP:
- if (skinnydebug)
- ast_verbose("Received Softkey Event: Pickup(%d/%d)\n", instance, callreference);
- break;
- case SOFTKEY_GPICKUP:
- if (skinnydebug)
- ast_verbose("Received Softkey Event: Group Pickup(%d/%d)\n", instance, callreference);
- break;
- default:
- if (skinnydebug)
- ast_verbose("Received unknown Softkey Event: %d(%d/%d)\n", event, instance, callreference);
- break;
- }
- return 1;
-}
-
-static int handle_unregister_message(struct skinny_req *req, struct skinnysession *s)
-{
- return skinny_unregister(req, s);
-}
-
-static int handle_soft_key_template_req_message(struct skinny_req *req, struct skinnysession *s)
-{
- if (!(req = req_alloc(sizeof(struct soft_key_template_res_message), SOFT_KEY_TEMPLATE_RES_MESSAGE)))
- return -1;
-
- req->data.softkeytemplate.softKeyOffset = htolel(0);
- req->data.softkeytemplate.softKeyCount = htolel(sizeof(soft_key_template_default) / sizeof(struct soft_key_template_definition));
- req->data.softkeytemplate.totalSoftKeyCount = htolel(sizeof(soft_key_template_default) / sizeof(struct soft_key_template_definition));
- memcpy(req->data.softkeytemplate.softKeyTemplateDefinition,
- soft_key_template_default,
- sizeof(soft_key_template_default));
- transmit_response(s,req);
- return 1;
-}
-
-static int handle_headset_status_message(struct skinny_req *req, struct skinnysession *s)
-{
- /* XXX umm...okay? Why do I care? */
- return 1;
-}
-
-static int handle_register_available_lines_message(struct skinny_req *req, struct skinnysession *s)
-{
- /* XXX I have no clue what this is for, but my phone was sending it, so... */
- return 1;
-}
-
-static int handle_message(struct skinny_req *req, struct skinnysession *s)
-{
- int res = 0;
- struct skinny_device *d = s->device;
- struct skinny_subchannel *sub;
- int lineInstance;
- int callReference;
-
- if ((!s->device) && (letohl(req->e) != REGISTER_MESSAGE && letohl(req->e) != ALARM_MESSAGE)) {
- ast_log(LOG_WARNING, "Client sent message #%d without first registering.\n", req->e);
- free(req);
- return 0;
- }
-
- switch(letohl(req->e)) {
- case KEEP_ALIVE_MESSAGE:
- res = handle_keep_alive_message(req, s);
- break;
- case REGISTER_MESSAGE:
- if (skinnydebug)
- ast_verbose("Device %s is attempting to register\n", req->data.reg.name);
-
- res = handle_register_message(req, s);
- break;
- case IP_PORT_MESSAGE:
- res = handle_ip_port_message(req, s);
- break;
- case KEYPAD_BUTTON_MESSAGE:
- if (skinnydebug)
- ast_verbose("Collected digit: [%d]\n", letohl(req->data.keypad.button));
-
- lineInstance = letohl(req->data.keypad.lineInstance);
- callReference = letohl(req->data.keypad.callReference);
-
- sub = find_subchannel_by_instance_reference(d, lineInstance, callReference);
-
- if (sub && (sub->owner && sub->owner->_state < AST_STATE_UP)) {
- char dgt;
- int digit = letohl(req->data.keypad.button);
- size_t len;
-
- if (digit == 14) {
- dgt = '*';
- } else if (digit == 15) {
- dgt = '#';
- } else if (digit >= 0 && digit <= 9) {
- dgt = '0' + digit;
- } else {
- /* digit=10-13 (A,B,C,D ?), or
- * digit is bad value
- *
- * probably should not end up here, but set
- * value for backward compatibility, and log
- * a warning.
- */
- dgt = '0' + digit;
- ast_log(LOG_WARNING, "Unsupported digit %d\n", digit);
- }
-
- len = strlen(d->exten);
- if (len < sizeof(d->exten) - 1) {
- d->exten[len] = dgt;
- d->exten[len+1] = '\0';
- } else {
- ast_log(LOG_WARNING, "Dropping digit with value %d because digit queue is full\n", dgt);
- }
- } else
- res = handle_keypad_button_message(req, s);
- break;
- case ENBLOC_CALL_MESSAGE:
- res = handle_enbloc_call_message(req, s);
- break;
- case STIMULUS_MESSAGE:
- res = handle_stimulus_message(req, s);
- break;
- case OFFHOOK_MESSAGE:
- res = handle_offhook_message(req, s);
- break;
- case ONHOOK_MESSAGE:
- res = handle_onhook_message(req, s);
- break;
- case CAPABILITIES_RES_MESSAGE:
- if (skinnydebug)
- ast_verbose("Received CapabilitiesRes\n");
-
- res = handle_capabilities_res_message(req, s);
- break;
- case SPEED_DIAL_STAT_REQ_MESSAGE:
- if (skinnydebug)
- ast_verbose("Received SpeedDialStatRequest\n");
-
- res = handle_speed_dial_stat_req_message(req, s);
- break;
- case LINE_STATE_REQ_MESSAGE:
- if (skinnydebug)
- ast_verbose("Received LineStatRequest\n");
- res = handle_line_state_req_message(req, s);
- break;
- case TIME_DATE_REQ_MESSAGE:
- if (skinnydebug)
- ast_verbose("Received Time/Date Request\n");
-
- res = handle_time_date_req_message(req, s);
- break;
- case BUTTON_TEMPLATE_REQ_MESSAGE:
- if (skinnydebug)
- ast_verbose("Buttontemplate requested\n");
-
- res = handle_button_template_req_message(req, s);
- break;
- case VERSION_REQ_MESSAGE:
- if (skinnydebug)
- ast_verbose("Version Request\n");
-
- res = handle_version_req_message(req, s);
- break;
- case SERVER_REQUEST_MESSAGE:
- if (skinnydebug)
- ast_verbose("Received Server Request\n");
-
- res = handle_server_request_message(req, s);
- break;
- case ALARM_MESSAGE:
- res = handle_alarm_message(req, s);
- break;
- case OPEN_RECEIVE_CHANNEL_ACK_MESSAGE:
- if (skinnydebug)
- ast_verbose("Received Open Receive Channel Ack\n");
-
- res = handle_open_receive_channel_ack_message(req, s);
- break;
- case SOFT_KEY_SET_REQ_MESSAGE:
- if (skinnydebug)
- ast_verbose("Received SoftKeySetReq\n");
-
- res = handle_soft_key_set_req_message(req, s);
- break;
- case SOFT_KEY_EVENT_MESSAGE:
- res = handle_soft_key_event_message(req, s);
- break;
- case UNREGISTER_MESSAGE:
- if (skinnydebug)
- ast_verbose("Received Unregister Request\n");
-
- res = handle_unregister_message(req, s);
- break;
- case SOFT_KEY_TEMPLATE_REQ_MESSAGE:
- if (skinnydebug)
- ast_verbose("Received SoftKey Template Request\n");
-
- res = handle_soft_key_template_req_message(req, s);
- break;
- case HEADSET_STATUS_MESSAGE:
- res = handle_headset_status_message(req, s);
- break;
- case REGISTER_AVAILABLE_LINES_MESSAGE:
- res = handle_register_available_lines_message(req, s);
- break;
- default:
- if (skinnydebug)
- ast_verbose("RECEIVED UNKNOWN MESSAGE TYPE: %x\n", letohl(req->e));
- break;
- }
- if (res >= 0 && req)
- free(req);
- return res;
-}
-
-static void destroy_session(struct skinnysession *s)
-{
- struct skinnysession *cur, *prev = NULL;
- ast_mutex_lock(&sessionlock);
- cur = sessions;
- while(cur) {
- if (cur == s) {
- break;
- }
- prev = cur;
- cur = cur->next;
- }
- if (cur) {
- if (prev) {
- prev->next = cur->next;
- } else {
- sessions = cur->next;
- }
- if (s->fd > -1) {
- close(s->fd);
- }
- ast_mutex_destroy(&s->lock);
- free(s);
- } else {
- ast_log(LOG_WARNING, "Trying to delete nonexistent session %p?\n", s);
- }
- ast_mutex_unlock(&sessionlock);
-}
-
-static int get_input(struct skinnysession *s)
-{
- int res;
- int dlen = 0;
- struct pollfd fds[1];
-
- fds[0].fd = s->fd;
- fds[0].events = POLLIN;
- fds[0].revents = 0;
- res = poll(fds, 1, (keep_alive * 1100)); /* If nothing has happen, client is dead */
- /* we add 10% to the keep_alive to deal */
- /* with network delays, etc */
- if (res < 0) {
- if (errno != EINTR) {
- ast_log(LOG_WARNING, "Select returned error: %s\n", strerror(errno));
- return res;
- }
- } else if (res == 0) {
- if (skinnydebug)
- ast_verbose("Skinny Client was lost, unregistering\n");
- skinny_unregister(NULL, s);
- return -1;
- }
-
- if (fds[0].revents) {
- ast_mutex_lock(&s->lock);
- memset(s->inbuf,0,sizeof(s->inbuf));
- res = read(s->fd, s->inbuf, 4);
- if (res < 0) {
- ast_log(LOG_WARNING, "read() returned error: %s\n", strerror(errno));
-
- if (skinnydebug)
- ast_verbose("Skinny Client was lost, unregistering\n");
-
- skinny_unregister(NULL,s);
- ast_mutex_unlock(&s->lock);
- return res;
- } else if (res != 4) {
- ast_log(LOG_WARNING, "Skinny Client sent less data than expected. Expected 4 but got %d.\n", res);
- ast_mutex_unlock(&s->lock);
-
- if (res == 0) {
- if (skinnydebug)
- ast_verbose("Skinny Client was lost, unregistering\n");
- skinny_unregister(NULL, s);
- }
-
- return -1;
- }
-
- dlen = letohl(*(int *)s->inbuf);
- if (dlen < 4) {
- ast_log(LOG_WARNING, "Skinny Client sent invalid data.\n");
- ast_mutex_unlock(&s->lock);
- return -1;
- }
- if (dlen+8 > sizeof(s->inbuf)) {
- dlen = sizeof(s->inbuf) - 8;
- }
- *(int *)s->inbuf = htolel(dlen);
-
- res = read(s->fd, s->inbuf+4, dlen+4);
- ast_mutex_unlock(&s->lock);
- if (res < 0) {
- ast_log(LOG_WARNING, "read() returned error: %s\n", strerror(errno));
- return res;
- } else if (res != (dlen+4)) {
- ast_log(LOG_WARNING, "Skinny Client sent less data than expected.\n");
- return -1;
- }
- return res;
- }
- return 0;
-}
-
-static struct skinny_req *skinny_req_parse(struct skinnysession *s)
-{
- struct skinny_req *req;
-
- if (!(req = ast_calloc(1, SKINNY_MAX_PACKET)))
- return NULL;
-
- ast_mutex_lock(&s->lock);
- memcpy(req, s->inbuf, skinny_header_size);
- memcpy(&req->data, s->inbuf+skinny_header_size, letohl(*(int*)(s->inbuf))-4);
-
- ast_mutex_unlock(&s->lock);
-
- if (letohl(req->e) < 0) {
- ast_log(LOG_ERROR, "Event Message is NULL from socket %d, This is bad\n", s->fd);
- free(req);
- return NULL;
- }
-
- return req;
-}
-
-static void *skinny_session(void *data)
-{
- int res;
- struct skinny_req *req;
- struct skinnysession *s = data;
-
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Starting Skinny session from %s\n", ast_inet_ntoa(s->sin.sin_addr));
-
- for (;;) {
- res = get_input(s);
- if (res < 0) {
- break;
- }
-
- if (res > 0)
- {
- if (!(req = skinny_req_parse(s))) {
- destroy_session(s);
- return NULL;
- }
-
- res = handle_message(req, s);
- if (res < 0) {
- destroy_session(s);
- return NULL;
- }
- }
- }
- ast_log(LOG_NOTICE, "Skinny Session returned: %s\n", strerror(errno));
-
- if (s)
- destroy_session(s);
-
- return 0;
-}
-
-static void *accept_thread(void *ignore)
-{
- int as;
- struct sockaddr_in sin;
- socklen_t sinlen;
- struct skinnysession *s;
- struct protoent *p;
- int arg = 1;
- pthread_attr_t attr;
- pthread_t tcp_thread;
-
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-
- for (;;) {
- sinlen = sizeof(sin);
- as = accept(skinnysock, (struct sockaddr *)&sin, &sinlen);
- if (as < 0) {
- ast_log(LOG_NOTICE, "Accept returned -1: %s\n", strerror(errno));
- continue;
- }
- p = getprotobyname("tcp");
- if(p) {
- if( setsockopt(as, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) {
- ast_log(LOG_WARNING, "Failed to set Skinny tcp connection to TCP_NODELAY mode: %s\n", strerror(errno));
- }
- }
- if (!(s = ast_calloc(1, sizeof(struct skinnysession))))
- continue;
-
- memcpy(&s->sin, &sin, sizeof(sin));
- ast_mutex_init(&s->lock);
- s->fd = as;
- ast_mutex_lock(&sessionlock);
- s->next = sessions;
- sessions = s;
- ast_mutex_unlock(&sessionlock);
-
- if (ast_pthread_create(&tcp_thread, &attr, skinny_session, s)) {
- destroy_session(s);
- }
- }
- if (skinnydebug)
- ast_verbose("killing accept thread\n");
- close(as);
- pthread_attr_destroy(&attr);
- return 0;
-}
-
-static void *do_monitor(void *data)
-{
- int res;
-
- /* This thread monitors all the interfaces which are not yet in use
- (and thus do not have a separate thread) indefinitely */
- /* From here on out, we die whenever asked */
- for(;;) {
- pthread_testcancel();
- /* Wait for sched or io */
- res = ast_sched_wait(sched);
- if ((res < 0) || (res > 1000)) {
- res = 1000;
- }
- res = ast_io_wait(io, res);
- ast_mutex_lock(&monlock);
- if (res >= 0) {
- ast_sched_runq(sched);
- }
- ast_mutex_unlock(&monlock);
- }
- /* Never reached */
- return NULL;
-
-}
-
-static int restart_monitor(void)
-{
- /* If we're supposed to be stopped -- stay stopped */
- if (monitor_thread == AST_PTHREADT_STOP)
- return 0;
-
- ast_mutex_lock(&monlock);
- if (monitor_thread == pthread_self()) {
- ast_mutex_unlock(&monlock);
- ast_log(LOG_WARNING, "Cannot kill myself\n");
- return -1;
- }
- if (monitor_thread != AST_PTHREADT_NULL) {
- /* Wake up the thread */
- pthread_kill(monitor_thread, SIGURG);
- } else {
- /* Start a new monitor */
- if (ast_pthread_create_background(&monitor_thread, NULL, do_monitor, NULL) < 0) {
- ast_mutex_unlock(&monlock);
- ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
- return -1;
- }
- }
- ast_mutex_unlock(&monlock);
- return 0;
-}
-
-static struct ast_channel *skinny_request(const char *type, int format, void *data, int *cause)
-{
- int oldformat;
-
- struct skinny_line *l;
- struct ast_channel *tmpc = NULL;
- char tmp[256];
- char *dest = data;
-
- oldformat = format;
-
- if (!(format &= ((AST_FORMAT_MAX_AUDIO << 1) - 1))) {
- ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", format);
- return NULL;
- }
-
- ast_copy_string(tmp, dest, sizeof(tmp));
- if (ast_strlen_zero(tmp)) {
- ast_log(LOG_NOTICE, "Skinny channels require a device\n");
- return NULL;
- }
- l = find_line_by_name(tmp);
- if (!l) {
- ast_log(LOG_NOTICE, "No available lines on: %s\n", dest);
- return NULL;
- }
- if (option_verbose > 2) {
- ast_verbose(VERBOSE_PREFIX_3 "skinny_request(%s)\n", tmp);
- }
- tmpc = skinny_new(l, AST_STATE_DOWN);
- if (!tmpc) {
- ast_log(LOG_WARNING, "Unable to make channel for '%s'\n", tmp);
- }
- restart_monitor();
- return tmpc;
-}
-
-static int reload_config(void)
-{
- int on = 1;
- struct ast_config *cfg;
- struct ast_variable *v;
- char *cat;
- struct skinny_device *d;
- int oldport = ntohs(bindaddr.sin_port);
-
- if (gethostname(ourhost, sizeof(ourhost))) {
- ast_log(LOG_WARNING, "Unable to get hostname, Skinny disabled\n");
- return 0;
- }
- cfg = ast_config_load(config);
-
- /* We *must* have a config file otherwise stop immediately */
- if (!cfg) {
- ast_log(LOG_NOTICE, "Unable to load config %s, Skinny disabled\n", config);
- return -1;
- }
- memset(&bindaddr, 0, sizeof(bindaddr));
- memset(&default_prefs, 0, sizeof(default_prefs));
-
- /* Copy the default jb config over global_jbconf */
- memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
-
- /* load the general section */
- v = ast_variable_browse(cfg, "general");
- while (v) {
- /* handle jb conf */
- if (!ast_jb_read_conf(&global_jbconf, v->name, v->value)) {
- v = v->next;
- continue;
- }
-
- /* Create the interface list */
- if (!strcasecmp(v->name, "bindaddr")) {
- if (!(hp = ast_gethostbyname(v->value, &ahp))) {
- ast_log(LOG_WARNING, "Invalid address: %s\n", v->value);
- } else {
- memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr));
- }
- } else if (!strcasecmp(v->name, "keepalive")) {
- keep_alive = atoi(v->value);
- } else if (!strcasecmp(v->name, "dateformat")) {
- memcpy(date_format, v->value, sizeof(date_format));
- } else if (!strcasecmp(v->name, "allow")) {
- ast_parse_allow_disallow(&default_prefs, &default_capability, v->value, 1);
- } else if (!strcasecmp(v->name, "disallow")) {
- ast_parse_allow_disallow(&default_prefs, &default_capability, v->value, 0);
- } else if (!strcasecmp(v->name, "bindport") || !strcasecmp(v->name, "port")) {
- if (sscanf(v->value, "%d", &ourport) == 1) {
- bindaddr.sin_port = htons(ourport);
- } else {
- ast_log(LOG_WARNING, "Invalid bindport '%s' at line %d of %s\n", v->value, v->lineno, config);
- }
- if (!strcasecmp(v->name, "port")) { /*! \todo Remove 'port' option after 1.4 */
- ast_log(LOG_WARNING, "Option 'port' at line %d of %s has been deprecated. Please use 'bindport' instead.\n", v->lineno, config);
- }
- }
- v = v->next;
- }
-
- if (ntohl(bindaddr.sin_addr.s_addr)) {
- __ourip = bindaddr.sin_addr;
- } else {
- hp = ast_gethostbyname(ourhost, &ahp);
- if (!hp) {
- ast_log(LOG_WARNING, "Unable to get our IP address, Skinny disabled\n");
- ast_config_destroy(cfg);
- return 0;
- }
- memcpy(&__ourip, hp->h_addr, sizeof(__ourip));
- }
- if (!ntohs(bindaddr.sin_port)) {
- bindaddr.sin_port = ntohs(DEFAULT_SKINNY_PORT);
- }
- bindaddr.sin_family = AF_INET;
-
- /* load the device sections */
- cat = ast_category_browse(cfg, NULL);
- while(cat) {
- if (!strcasecmp(cat, "general")) {
- /* Nothing to do */
-#if 0
- } else if (!strncasecmp(cat, "paging-", 7)) {
- p = build_paging_device(cat, ast_variable_browse(cfg, cat));
- if (p) {
- }
-#endif
- } else {
- d = build_device(cat, ast_variable_browse(cfg, cat));
- if (d) {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Added device '%s'\n", d->name);
- ast_mutex_lock(&devicelock);
- d->next = devices;
- devices = d;
- ast_mutex_unlock(&devicelock);
- }
- }
- cat = ast_category_browse(cfg, cat);
- }
- ast_mutex_lock(&netlock);
- if ((skinnysock > -1) && (ntohs(bindaddr.sin_port) != oldport)) {
- close(skinnysock);
- skinnysock = -1;
- }
- if (skinnysock < 0) {
- skinnysock = socket(AF_INET, SOCK_STREAM, 0);
- if(setsockopt(skinnysock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
- ast_log(LOG_ERROR, "Set Socket Options failed: errno %d, %s\n", errno, strerror(errno));
- ast_config_destroy(cfg);
- ast_mutex_unlock(&netlock);
- return 0;
- }
- if (skinnysock < 0) {
- ast_log(LOG_WARNING, "Unable to create Skinny socket: %s\n", strerror(errno));
- } else {
- if (bind(skinnysock, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) < 0) {
- ast_log(LOG_WARNING, "Failed to bind to %s:%d: %s\n",
- ast_inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port),
- strerror(errno));
- close(skinnysock);
- skinnysock = -1;
- ast_config_destroy(cfg);
- ast_mutex_unlock(&netlock);
- return 0;
- }
- if (listen(skinnysock,DEFAULT_SKINNY_BACKLOG)) {
- ast_log(LOG_WARNING, "Failed to start listening to %s:%d: %s\n",
- ast_inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port),
- strerror(errno));
- close(skinnysock);
- skinnysock = -1;
- ast_config_destroy(cfg);
- ast_mutex_unlock(&netlock);
- return 0;
- }
- if (option_verbose > 1)
- ast_verbose(VERBOSE_PREFIX_2 "Skinny listening on %s:%d\n",
- ast_inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port));
- ast_pthread_create_background(&accept_t,NULL, accept_thread, NULL);
- }
- }
- ast_mutex_unlock(&netlock);
- ast_config_destroy(cfg);
- return 1;
-}
-
-static void delete_devices(void)
-{
- struct skinny_device *d, *dlast;
- struct skinny_line *l, *llast;
- struct skinny_speeddial *sd, *sdlast;
- struct skinny_addon *a, *alast;
-
- ast_mutex_lock(&devicelock);
-
- /* Delete all devices */
- for (d=devices;d;) {
- /* Delete all lines for this device */
- for (l=d->lines;l;) {
- llast = l;
- l = l->next;
- ast_mutex_destroy(&llast->lock);
- free(llast);
- }
- /* Delete all speeddials for this device */
- for (sd=d->speeddials;sd;) {
- sdlast = sd;
- sd = sd->next;
- ast_mutex_destroy(&sdlast->lock);
- free(sdlast);
- }
- /* Delete all addons for this device */
- for (a=d->addons;a;) {
- alast = a;
- a = a->next;
- ast_mutex_destroy(&alast->lock);
- free(alast);
- }
- dlast = d;
- d = d->next;
- free(dlast);
- }
- devices=NULL;
- ast_mutex_unlock(&devicelock);
-}
-
-#if 0
-/*
- * XXX This never worked properly anyways.
- * Let's get rid of it, until we can fix it.
- */
-static int reload(void)
-{
- delete_devices();
- reload_config();
- restart_monitor();
- return 0;
-}
-#endif
-
-static int load_module(void)
-{
- int res = 0;
-
- for (; res < (sizeof(soft_key_template_default) / sizeof(soft_key_template_default[0])); res++) {
- soft_key_template_default[res].softKeyEvent = htolel(soft_key_template_default[res].softKeyEvent);
- }
- /* load and parse config */
- res = reload_config();
- if (res == -1) {
- return AST_MODULE_LOAD_DECLINE;
- }
-
- /* Make sure we can register our skinny channel type */
- if (ast_channel_register(&skinny_tech)) {
- ast_log(LOG_ERROR, "Unable to register channel class 'Skinny'\n");
- return -1;
- }
-
- ast_rtp_proto_register(&skinny_rtp);
- ast_cli_register_multiple(cli_skinny, sizeof(cli_skinny) / sizeof(struct ast_cli_entry));
- sched = sched_context_create();
- if (!sched) {
- ast_log(LOG_WARNING, "Unable to create schedule context\n");
- }
- io = io_context_create();
- if (!io) {
- ast_log(LOG_WARNING, "Unable to create I/O context\n");
- }
- /* And start the monitor for the first time */
- restart_monitor();
-
- return res;
-}
-
-static int unload_module(void)
-{
- struct skinnysession *s, *slast;
- struct skinny_device *d;
- struct skinny_line *l;
- struct skinny_subchannel *sub;
-
- ast_mutex_lock(&sessionlock);
- /* Destroy all the interfaces and free their memory */
- s = sessions;
- while(s) {
- slast = s;
- s = s->next;
- for (d = slast->device; d; d = d->next) {
- for (l = d->lines; l; l = l->next) {
- ast_mutex_lock(&l->lock);
- for (sub = l->sub; sub; sub = sub->next) {
- ast_mutex_lock(&sub->lock);
- if (sub->owner) {
- sub->alreadygone = 1;
- ast_softhangup(sub->owner, AST_SOFTHANGUP_APPUNLOAD);
- }
- ast_mutex_unlock(&sub->lock);
- }
- ast_mutex_unlock(&l->lock);
- }
- }
- if (slast->fd > -1)
- close(slast->fd);
- ast_mutex_destroy(&slast->lock);
- free(slast);
- }
- sessions = NULL;
- ast_mutex_unlock(&sessionlock);
-
- delete_devices();
-
- ast_mutex_lock(&monlock);
- if ((monitor_thread != AST_PTHREADT_NULL) && (monitor_thread != AST_PTHREADT_STOP)) {
- pthread_cancel(monitor_thread);
- pthread_kill(monitor_thread, SIGURG);
- pthread_join(monitor_thread, NULL);
- }
- monitor_thread = AST_PTHREADT_STOP;
- ast_mutex_unlock(&monlock);
-
- ast_mutex_lock(&netlock);
- if (accept_t && (accept_t != AST_PTHREADT_STOP)) {
- pthread_cancel(accept_t);
- pthread_kill(accept_t, SIGURG);
- pthread_join(accept_t, NULL);
- }
- accept_t = AST_PTHREADT_STOP;
- ast_mutex_unlock(&netlock);
-
- ast_rtp_proto_unregister(&skinny_rtp);
- ast_channel_unregister(&skinny_tech);
- ast_cli_unregister_multiple(cli_skinny, sizeof(cli_skinny) / sizeof(struct ast_cli_entry));
-
- close(skinnysock);
- if (sched)
- sched_context_destroy(sched);
-
- return 0;
-}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Skinny Client Control Protocol (Skinny)",
- .load = load_module,
- .unload = unload_module,
- );
diff --git a/1.4.23-rc4/channels/chan_vpb.cc b/1.4.23-rc4/channels/chan_vpb.cc
deleted file mode 100644
index 56467a6ce..000000000
--- a/1.4.23-rc4/channels/chan_vpb.cc
+++ /dev/null
@@ -1,2905 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2003, Paul Bagyenda
- * Paul Bagyenda <bagyenda@dsmagic.com>
- * Copyright (C) 2004 - 2005, Ben Kramer
- * Ben Kramer <ben@voicetronix.com.au>
- *
- * Daniel Bichara <daniel@bichara.com.br> - Brazilian CallerID detection (c)2004
- *
- * Welber Silveira - welberms@magiclink.com.br - (c)2004
- * Copying CLID string to propper structure after detection
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief VoiceTronix Interface driver
- *
- * \ingroup channel_drivers
- */
-
-/*** MODULEINFO
- <depend>vpbapi</depend>
- ***/
-
-#include <vpbapi.h>
-
-extern "C" {
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
-#include <stdio.h>
-#include <string.h>
-
-#include "asterisk/lock.h"
-#include "asterisk/utils.h"
-#include "asterisk/channel.h"
-#include "asterisk/config.h"
-#include "asterisk/logger.h"
-#include "asterisk/module.h"
-#include "asterisk/pbx.h"
-#include "asterisk/options.h"
-#include "asterisk/callerid.h"
-#include "asterisk/dsp.h"
-#include "asterisk/features.h"
-#include "asterisk/musiconhold.h"
-}
-
-#include <sys/socket.h>
-#include <sys/time.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <arpa/inet.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <ctype.h>
-
-#include <assert.h>
-
-#ifdef pthread_create
-#undef pthread_create
-#endif
-
-#define DEFAULT_GAIN 0
-#define DEFAULT_ECHO_CANCEL 1
-
-#define VPB_SAMPLES 160
-#define VPB_MAX_BUF VPB_SAMPLES*4 + AST_FRIENDLY_OFFSET
-
-#define VPB_NULL_EVENT 200
-
-#define VPB_WAIT_TIMEOUT 4000
-
-#define MAX_VPB_GAIN 12.0
-#define MIN_VPB_GAIN -12.0
-
-#define DTMF_CALLERID
-#define DTMF_CID_START 'D'
-#define DTMF_CID_STOP 'C'
-
-/**/
-#if defined(__cplusplus) || defined(c_plusplus)
- extern "C" {
-#endif
-/**/
-
-static const char desc[] = "VoiceTronix V6PCI/V12PCI/V4PCI API Support";
-static const char tdesc[] = "Standard VoiceTronix API Driver";
-static const char config[] = "vpb.conf";
-
-/* Backwards compatibility from trunk */
-#define ast_verb(level, ...) do { \
- if (option_verbose >= level) { \
- if (level >= 4) \
- ast_verbose(VERBOSE_PREFIX_4 __VA_ARGS__); \
- else if (level == 3) \
- ast_verbose(VERBOSE_PREFIX_3 __VA_ARGS__); \
- else if (level == 2) \
- ast_verbose(VERBOSE_PREFIX_2 __VA_ARGS__); \
- else if (level == 1) \
- ast_verbose(VERBOSE_PREFIX_1 __VA_ARGS__); \
- else \
- ast_verbose(__VA_ARGS__); \
- } \
-} while (0)
-
-#define ast_debug(level, ...) do { \
- if (option_debug >= (level)) \
- ast_log(LOG_DEBUG, __VA_ARGS__); \
-} while (0)
-
-/* Default context for dialtone mode */
-static char context[AST_MAX_EXTENSION] = "default";
-
-/* Default language */
-static char language[MAX_LANGUAGE] = "";
-
-static int gruntdetect_timeout = 3600000; /* Grunt detect timeout is 1hr. */
-
-static const int prefformat = AST_FORMAT_SLINEAR;
-
-/* Protect the interface list (of vpb_pvt's) */
-AST_MUTEX_DEFINE_STATIC(iflock);
-
-/* Protect the monitoring thread, so only one process can kill or start it, and not
- when it's doing something critical. */
-AST_MUTEX_DEFINE_STATIC(monlock);
-
-/* This is the thread for the monitor which checks for input on the channels
- which are not currently in use. */
-static pthread_t monitor_thread;
-
-static int mthreadactive = -1; /* Flag for monitoring monitorthread.*/
-
-
-static int restart_monitor(void);
-
-/* The private structures of the VPB channels are
- linked for selecting outgoing channels */
-
-#define MODE_DIALTONE 1
-#define MODE_IMMEDIATE 2
-#define MODE_FXO 3
-
-/* Pick a country or add your own! */
-/* These are the tones that are played to the user */
-#define TONES_AU
-/* #define TONES_USA */
-
-#ifdef TONES_AU
-static VPB_TONE Dialtone = {440, 440, 440, -10, -10, -10, 5000, 0 };
-static VPB_TONE Busytone = {470, 0, 0, -10, -100, -100, 5000, 0 };
-static VPB_TONE Ringbacktone = {400, 50, 440, -10, -10, -10, 1400, 800 };
-#endif
-#ifdef TONES_USA
-static VPB_TONE Dialtone = {350, 440, 0, -16, -16, -100, 10000, 0};
-static VPB_TONE Busytone = {480, 620, 0, -10, -10, -100, 500, 500};
-static VPB_TONE Ringbacktone = {440, 480, 0, -20, -20, -100, 2000, 4000};
-#endif
-
-/* grunt tone defn's */
-#if 0
-static VPB_DETECT toned_grunt = { 3, VPB_GRUNT, 1, 2000, 3000, 0, 0, -40, 0, 0, 0, 40, { { VPB_DELAY, 1000, 0, 0 }, { VPB_RISING, 0, 40, 0 }, { 0, 100, 0, 0 } } };
-#endif
-static VPB_DETECT toned_ungrunt = { 2, VPB_GRUNT, 1, 2000, 1, 0, 0, -40, 0, 0, 30, 40, { { 0, 0, 0, 0 } } };
-
-/* Use loop polarity detection for CID */
-static int UsePolarityCID=0;
-
-/* Use loop drop detection */
-static int UseLoopDrop=1;
-
-/* To use or not to use Native bridging */
-static int UseNativeBridge=1;
-
-/* Use Asterisk Indication or VPB */
-static int use_ast_ind=0;
-
-/* Use Asterisk DTMF detection or VPB */
-static int use_ast_dtmfdet=0;
-
-static int relaxdtmf=0;
-
-/* Use Asterisk DTMF play back or VPB */
-static int use_ast_dtmf=0;
-
-/* Break for DTMF on native bridge ? */
-static int break_for_dtmf=1;
-
-/* Set EC suppression threshold */
-static short ec_supp_threshold=-1;
-
-/* Inter Digit Delay for collecting DTMF's */
-static int dtmf_idd = 3000;
-
-#define TIMER_PERIOD_RINGBACK 2000
-#define TIMER_PERIOD_BUSY 700
-#define TIMER_PERIOD_RING 4000
-static int timer_period_ring = TIMER_PERIOD_RING;
-
-#define VPB_EVENTS_ALL (VPB_MRING|VPB_MDIGIT|VPB_MDTMF|VPB_MTONEDETECT|VPB_MTIMEREXP \
- |VPB_MSTATION_OFFHOOK|VPB_MSTATION_ONHOOK \
- |VPB_MRING_OFF|VPB_MDROP|VPB_MSTATION_FLASH)
-#define VPB_EVENTS_NODROP (VPB_MRING|VPB_MDIGIT|VPB_MDTMF|VPB_MTONEDETECT|VPB_MTIMEREXP \
- |VPB_MSTATION_OFFHOOK|VPB_MSTATION_ONHOOK \
- |VPB_MRING_OFF|VPB_MSTATION_FLASH)
-#define VPB_EVENTS_NODTMF (VPB_MRING|VPB_MDIGIT|VPB_MTONEDETECT|VPB_MTIMEREXP \
- |VPB_MSTATION_OFFHOOK|VPB_MSTATION_ONHOOK \
- |VPB_MRING_OFF|VPB_MDROP|VPB_MSTATION_FLASH)
-#define VPB_EVENTS_STAT (VPB_MRING|VPB_MDIGIT|VPB_MDTMF|VPB_MTONEDETECT|VPB_MTIMEREXP \
- |VPB_MSTATION_OFFHOOK|VPB_MSTATION_ONHOOK \
- |VPB_MRING_OFF|VPB_MSTATION_FLASH)
-
-
-/* Dialing parameters for Australia */
-/* #define DIAL_WITH_CALL_PROGRESS */
-VPB_TONE_MAP DialToneMap[] = { { VPB_BUSY, VPB_CALL_DISCONNECT, 0 },
- { VPB_DIAL, VPB_CALL_DIALTONE, 0 },
- { VPB_RINGBACK, VPB_CALL_RINGBACK, 0 },
- { VPB_BUSY, VPB_CALL_BUSY, 0 },
- { VPB_GRUNT, VPB_CALL_GRUNT, 0 },
- { 0, 0, 1 } };
-#define VPB_DIALTONE_WAIT 2000 /* Wait up to 2s for a dialtone */
-#define VPB_RINGWAIT 4000 /* Wait up to 4s for ring tone after dialing */
-#define VPB_CONNECTED_WAIT 4000 /* If no ring tone detected for 4s then consider call connected */
-#define TIMER_PERIOD_NOANSWER 120000 /* Let it ring for 120s before deciding theres noone there */
-
-#define MAX_BRIDGES_V4PCI 2
-#define MAX_BRIDGES_V12PCI 128
-
-/* port states */
-#define VPB_STATE_ONHOOK 0
-#define VPB_STATE_OFFHOOK 1
-#define VPB_STATE_DIALLING 2
-#define VPB_STATE_JOINED 3
-#define VPB_STATE_GETDTMF 4
-#define VPB_STATE_PLAYDIAL 5
-#define VPB_STATE_PLAYBUSY 6
-#define VPB_STATE_PLAYRING 7
-
-#define VPB_GOT_RXHWG 1
-#define VPB_GOT_TXHWG 2
-#define VPB_GOT_RXSWG 4
-#define VPB_GOT_TXSWG 8
-
-typedef struct {
- int inuse;
- struct ast_channel *c0, *c1, **rc;
- struct ast_frame **fo;
- int flags;
- ast_mutex_t lock;
- ast_cond_t cond;
- int endbridge;
-} vpb_bridge_t;
-
-static vpb_bridge_t * bridges;
-static int max_bridges = MAX_BRIDGES_V4PCI;
-
-AST_MUTEX_DEFINE_STATIC(bridge_lock);
-
-typedef enum {
- vpb_model_unknown = 0,
- vpb_model_v4pci,
- vpb_model_v12pci
-} vpb_model_t;
-
-static struct vpb_pvt {
-
- ast_mutex_t owner_lock; /* Protect blocks that expect ownership to remain the same */
- struct ast_channel *owner; /* Channel who owns us, possibly NULL */
-
- int golock; /* Got owner lock ? */
-
- int mode; /* fxo/imediate/dialtone*/
- int handle; /* Handle for vpb interface */
-
- int state; /* used to keep port state (internal to driver) */
-
- int group; /* Which group this port belongs to */
- ast_group_t callgroup; /* Call group */
- ast_group_t pickupgroup; /* Pickup group */
-
-
- char dev[256]; /* Device name, eg vpb/1-1 */
- vpb_model_t vpb_model; /* card model */
-
- struct ast_frame f, fr; /* Asterisk frame interface */
- char buf[VPB_MAX_BUF]; /* Static buffer for reading frames */
-
- int dialtone; /* NOT USED */
- float txgain, rxgain; /* Hardware gain control */
- float txswgain, rxswgain; /* Software gain control */
-
- int wantdtmf; /* Waiting for DTMF. */
- char context[AST_MAX_EXTENSION]; /* The context for this channel */
-
- char ext[AST_MAX_EXTENSION]; /* DTMF buffer for the ext[ens] */
- char language[MAX_LANGUAGE]; /* language being used */
- char callerid[AST_MAX_EXTENSION]; /* CallerId used for directly connected phone */
- int callerid_type; /* Caller ID type: 0=>none 1=>vpb 2=>AstV23 3=>AstBell */
- char cid_num[AST_MAX_EXTENSION];
- char cid_name[AST_MAX_EXTENSION];
-
- int dtmf_caller_pos; /* DTMF CallerID detection (Brazil)*/
-
- int lastoutput; /* Holds the last Audio format output'ed */
- int lastinput; /* Holds the last Audio format input'ed */
- int last_ignore_dtmf;
-
- void *busy_timer; /* Void pointer for busy vpb_timer */
- int busy_timer_id; /* unique timer ID for busy timer */
-
- void *ringback_timer; /* Void pointer for ringback vpb_timer */
- int ringback_timer_id; /* unique timer ID for ringback timer */
-
- void *ring_timer; /* Void pointer for ring vpb_timer */
- int ring_timer_id; /* unique timer ID for ring timer */
-
- void *dtmfidd_timer; /* Void pointer for DTMF IDD vpb_timer */
- int dtmfidd_timer_id; /* unique timer ID for DTMF IDD timer */
-
- struct ast_dsp *vad; /* AST Voice Activation Detection dsp */
-
- struct timeval lastgrunt; /* time stamp of last grunt event */
-
- ast_mutex_t lock; /* This one just protects bridge ptr below */
- vpb_bridge_t *bridge;
-
- int stopreads; /* Stop reading...*/
- int read_state; /* Read state */
- int chuck_count; /* a count of packets weve chucked away!*/
- pthread_t readthread; /* For monitoring read channel. One per owned channel. */
-
- ast_mutex_t record_lock; /* This one prevents reentering a record_buf block */
- ast_mutex_t play_lock; /* This one prevents reentering a play_buf block */
- int play_buf_time; /* How long the last play_buf took */
- struct timeval lastplay; /* Last play time */
-
- ast_mutex_t play_dtmf_lock;
- char play_dtmf[16];
-
- int faxhandled; /* has a fax tone been handled ? */
-
- struct vpb_pvt *next; /* Next channel in list */
-
-} *iflist = NULL;
-
-static struct ast_channel *vpb_new(struct vpb_pvt *i, enum ast_channel_state state, const char *context);
-static void *do_chanreads(void *pvt);
-static struct ast_channel *vpb_request(const char *type, int format, void *data, int *cause);
-static int vpb_digit_begin(struct ast_channel *ast, char digit);
-static int vpb_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
-static int vpb_call(struct ast_channel *ast, char *dest, int timeout);
-static int vpb_hangup(struct ast_channel *ast);
-static int vpb_answer(struct ast_channel *ast);
-static struct ast_frame *vpb_read(struct ast_channel *ast);
-static int vpb_write(struct ast_channel *ast, struct ast_frame *frame);
-static enum ast_bridge_result ast_vpb_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms);
-static int vpb_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
-static int vpb_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
-
-static struct ast_channel_tech vpb_tech = {
- type: "vpb",
- description: tdesc,
- capabilities: AST_FORMAT_SLINEAR,
- properties: 0,
- requester: vpb_request,
- devicestate: NULL,
- send_digit_begin: vpb_digit_begin,
- send_digit_end: vpb_digit_end,
- call: vpb_call,
- hangup: vpb_hangup,
- answer: vpb_answer,
- read: vpb_read,
- write: vpb_write,
- send_text: NULL,
- send_image: NULL,
- send_html: NULL,
- exception: NULL,
- bridge: ast_vpb_bridge,
- indicate: vpb_indicate,
- fixup: vpb_fixup,
- setoption: NULL,
- queryoption: NULL,
- transfer: NULL,
- write_video: NULL,
- bridged_channel: NULL
-};
-
-static struct ast_channel_tech vpb_tech_indicate = {
- type: "vpb",
- description: tdesc,
- capabilities: AST_FORMAT_SLINEAR,
- properties: 0,
- requester: vpb_request,
- devicestate: NULL,
- send_digit_begin: vpb_digit_begin,
- send_digit_end: vpb_digit_end,
- call: vpb_call,
- hangup: vpb_hangup,
- answer: vpb_answer,
- read: vpb_read,
- write: vpb_write,
- send_text: NULL,
- send_image: NULL,
- send_html: NULL,
- exception: NULL,
- bridge: ast_vpb_bridge,
- indicate: NULL,
- fixup: vpb_fixup,
- setoption: NULL,
- queryoption: NULL,
- transfer: NULL,
- write_video: NULL,
- bridged_channel: NULL
-};
-
-/* Can't get ast_vpb_bridge() working on v4pci without either a horrible
-* high pitched feedback noise or bad hiss noise depending on gain settings
-* Get asterisk to do the bridging
-*/
-#define BAD_V4PCI_BRIDGE
-
-/* This one enables a half duplex bridge which may be required to prevent high pitched
- * feedback when getting asterisk to do the bridging and when using certain gain settings.
- */
-/* #define HALF_DUPLEX_BRIDGE */
-
-/* This is the Native bridge code, which Asterisk will try before using its own bridging code */
-static enum ast_bridge_result ast_vpb_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms)
-{
- struct vpb_pvt *p0 = (struct vpb_pvt *)c0->tech_pvt;
- struct vpb_pvt *p1 = (struct vpb_pvt *)c1->tech_pvt;
- int i;
- int res;
- struct ast_channel *cs[3];
- struct ast_channel *who;
- struct ast_frame *f;
-
- cs[0] = c0;
- cs[1] = c1;
-
- #ifdef BAD_V4PCI_BRIDGE
- if (p0->vpb_model==vpb_model_v4pci)
- return AST_BRIDGE_FAILED_NOWARN;
- #endif
- if ( UseNativeBridge != 1){
- return AST_BRIDGE_FAILED_NOWARN;
- }
-
-/*
- ast_mutex_lock(&p0->lock);
- ast_mutex_lock(&p1->lock);
-*/
-
- /* Bridge channels, check if we can. I believe we always can, so find a slot.*/
-
- ast_mutex_lock(&bridge_lock);
- for (i = 0; i < max_bridges; i++)
- if (!bridges[i].inuse)
- break;
- if (i < max_bridges) {
- bridges[i].inuse = 1;
- bridges[i].endbridge = 0;
- bridges[i].flags = flags;
- bridges[i].rc = rc;
- bridges[i].fo = fo;
- bridges[i].c0 = c0;
- bridges[i].c1 = c1;
- }
- ast_mutex_unlock(&bridge_lock);
-
- if (i == max_bridges) {
- ast_log(LOG_WARNING, "%s: vpb_bridge: Failed to bridge %s and %s!\n", p0->dev, c0->name, c1->name);
- ast_mutex_unlock(&p0->lock);
- ast_mutex_unlock(&p1->lock);
- return AST_BRIDGE_FAILED_NOWARN;
- } else {
- /* Set bridge pointers. You don't want to take these locks while holding bridge lock.*/
- ast_mutex_lock(&p0->lock);
- p0->bridge = &bridges[i];
- ast_mutex_unlock(&p0->lock);
-
- ast_mutex_lock(&p1->lock);
- p1->bridge = &bridges[i];
- ast_mutex_unlock(&p1->lock);
-
- ast_verb(2, "%s: vpb_bridge: Bridging call entered with [%s, %s]\n", p0->dev, c0->name, c1->name);
- }
-
- ast_verb(3, "Native bridging %s and %s\n", c0->name, c1->name);
-
- #ifdef HALF_DUPLEX_BRIDGE
-
- ast_debug(2, "%s: vpb_bridge: Starting half-duplex bridge [%s, %s]\n", p0->dev, c0->name, c1->name);
-
- int dir = 0;
-
- memset(p0->buf, 0, sizeof(p0->buf));
- memset(p1->buf, 0, sizeof(p1->buf));
-
- vpb_record_buf_start(p0->handle, VPB_ALAW);
- vpb_record_buf_start(p1->handle, VPB_ALAW);
-
- vpb_play_buf_start(p0->handle, VPB_ALAW);
- vpb_play_buf_start(p1->handle, VPB_ALAW);
-
- while (!bridges[i].endbridge) {
- struct vpb_pvt *from, *to;
- if (++dir % 2) {
- from = p0;
- to = p1;
- } else {
- from = p1;
- to = p0;
- }
- vpb_record_buf_sync(from->handle, from->buf, VPB_SAMPLES);
- vpb_play_buf_sync(to->handle, from->buf, VPB_SAMPLES);
- }
-
- vpb_record_buf_finish(p0->handle);
- vpb_record_buf_finish(p1->handle);
-
- vpb_play_buf_finish(p0->handle);
- vpb_play_buf_finish(p1->handle);
-
- ast_debug(2, "%s: vpb_bridge: Finished half-duplex bridge [%s, %s]\n", p0->dev, c0->name, c1->name);
-
- res = VPB_OK;
-
- #else
-
- res = vpb_bridge(p0->handle, p1->handle, VPB_BRIDGE_ON);
- if (res == VPB_OK) {
- /* pthread_cond_wait(&bridges[i].cond, &bridges[i].lock);*/ /* Wait for condition signal. */
- while (!bridges[i].endbridge) {
- /* Are we really ment to be doing nothing ?!?! */
- who = ast_waitfor_n(cs, 2, &timeoutms);
- if (!who) {
- if (!timeoutms) {
- res = AST_BRIDGE_RETRY;
- break;
- }
- ast_debug(1, "%s: vpb_bridge: Empty frame read...\n", p0->dev);
- /* check for hangup / whentohangup */
- if (ast_check_hangup(c0) || ast_check_hangup(c1))
- break;
- continue;
- }
- f = ast_read(who);
- if (!f || ((f->frametype == AST_FRAME_DTMF) &&
- (((who == c0) && (flags & AST_BRIDGE_DTMF_CHANNEL_0)) ||
- ((who == c1) && (flags & AST_BRIDGE_DTMF_CHANNEL_1))))) {
- *fo = f;
- *rc = who;
- ast_debug(1, "%s: vpb_bridge: Got a [%s]\n", p0->dev, f ? "digit" : "hangup");
-#if 0
- if ((c0->tech_pvt == pvt0) && (!ast_check_hangup(c0))) {
- if (pr0->set_rtp_peer(c0, NULL, NULL, 0))
- ast_log(LOG_WARNING, "Channel '%s' failed to revert\n", c0->name);
- }
- if ((c1->tech_pvt == pvt1) && (!ast_check_hangup(c1))) {
- if (pr1->set_rtp_peer(c1, NULL, NULL, 0))
- ast_log(LOG_WARNING, "Channel '%s' failed to revert back\n", c1->name);
- }
- /* That's all we needed */
- return 0;
-#endif
- /* Check if we need to break */
- if (break_for_dtmf) {
- break;
- } else if ((f->frametype == AST_FRAME_DTMF) && ((f->subclass == '#') || (f->subclass == '*'))) {
- break;
- }
- } else {
- if ((f->frametype == AST_FRAME_DTMF) ||
- (f->frametype == AST_FRAME_VOICE) ||
- (f->frametype == AST_FRAME_VIDEO))
- {
- /* Forward voice or DTMF frames if they happen upon us */
- /* Actually I dont think we want to forward on any frames!
- if (who == c0) {
- ast_write(c1, f);
- } else if (who == c1) {
- ast_write(c0, f);
- }
- */
- }
- ast_frfree(f);
- }
- /* Swap priority not that it's a big deal at this point */
- cs[2] = cs[0];
- cs[0] = cs[1];
- cs[1] = cs[2];
- };
- vpb_bridge(p0->handle, p1->handle, VPB_BRIDGE_OFF);
- }
-
- #endif
-
- ast_mutex_lock(&bridge_lock);
- bridges[i].inuse = 0;
- ast_mutex_unlock(&bridge_lock);
-
- p0->bridge = NULL;
- p1->bridge = NULL;
-
-
- ast_verb(2, "Bridging call done with [%s, %s] => %d\n", c0->name, c1->name, res);
-
-/*
- ast_mutex_unlock(&p0->lock);
- ast_mutex_unlock(&p1->lock);
-*/
- return (res == VPB_OK) ? AST_BRIDGE_COMPLETE : AST_BRIDGE_FAILED;
-}
-
-/* Caller ID can be located in different positions between the rings depending on your Telco
- * Australian (Telstra) callerid starts 700ms after 1st ring and finishes 1.5s after first ring
- * Use ANALYSE_CID to record rings and determine location of callerid
- */
-/* #define ANALYSE_CID */
-#define RING_SKIP 300
-#define CID_MSECS 2000
-
-static void get_callerid(struct vpb_pvt *p)
-{
- short buf[CID_MSECS*8]; /* 8kHz sampling rate */
- struct timeval cid_record_time;
- int rc;
- struct ast_channel *owner = p->owner;
-/*
- char callerid[AST_MAX_EXTENSION] = "";
-*/
-#ifdef ANALYSE_CID
- void * ws;
- char * file="cidsams.wav";
-#endif
-
-
- if (ast_mutex_trylock(&p->record_lock) == 0) {
-
- cid_record_time = ast_tvnow();
- ast_verb(4, "CID record - start\n");
-
- /* Skip any trailing ringtone */
- if (UsePolarityCID != 1){
- vpb_sleep(RING_SKIP);
- }
-
- ast_verb(4, "CID record - skipped %dms trailing ring\n",
- ast_tvdiff_ms(ast_tvnow(), cid_record_time));
- cid_record_time = ast_tvnow();
-
- /* Record bit between the rings which contains the callerid */
- vpb_record_buf_start(p->handle, VPB_LINEAR);
- rc = vpb_record_buf_sync(p->handle, (char*)buf, sizeof(buf));
- vpb_record_buf_finish(p->handle);
-#ifdef ANALYSE_CID
- vpb_wave_open_write(&ws, file, VPB_LINEAR);
- vpb_wave_write(ws, (char *)buf, sizeof(buf));
- vpb_wave_close_write(ws);
-#endif
-
- ast_verb(4, "CID record - recorded %dms between rings\n",
- ast_tvdiff_ms(ast_tvnow(), cid_record_time));
-
- ast_mutex_unlock(&p->record_lock);
-
- if (rc != VPB_OK) {
- ast_log(LOG_ERROR, "Failed to record caller id sample on %s\n", p->dev);
- return;
- }
-
- VPB_CID *cli_struct = new VPB_CID;
- cli_struct->ra_cldn[0] = 0;
- cli_struct->ra_cn[0] = 0;
- /* This decodes FSK 1200baud type callerid */
- if ((rc = vpb_cid_decode2(cli_struct, buf, CID_MSECS * 8)) == VPB_OK ) {
- /*
- if (owner->cid.cid_num)
- ast_free(owner->cid.cid_num);
- owner->cid.cid_num=NULL;
- if (owner->cid.cid_name)
- ast_free(owner->cid.cid_name);
- owner->cid.cid_name=NULL;
- */
-
- if (cli_struct->ra_cldn[0] == '\0') {
- /*
- owner->cid.cid_num = ast_strdup(cli_struct->cldn);
- owner->cid.cid_name = ast_strdup(cli_struct->cn);
- */
- if (owner) {
- ast_set_callerid(owner, cli_struct->cldn, cli_struct->cn, cli_struct->cldn);
- } else {
- strcpy(p->cid_num, cli_struct->cldn);
- strcpy(p->cid_name, cli_struct->cn);
- }
- ast_verb(4, "CID record - got [%s] [%s]\n", owner->cid.cid_num, owner->cid.cid_name);
- snprintf(p->callerid, sizeof(p->callerid), "%s %s", cli_struct->cldn, cli_struct->cn);
- } else {
- ast_log(LOG_ERROR, "CID record - No caller id avalable on %s \n", p->dev);
- }
-
- } else {
- ast_log(LOG_ERROR, "CID record - Failed to decode caller id on %s - %d\n", p->dev, rc);
- ast_copy_string(p->callerid, "unknown", sizeof(p->callerid));
- }
- delete cli_struct;
-
- } else
- ast_log(LOG_ERROR, "CID record - Failed to set record mode for caller id on %s\n", p->dev);
-}
-
-static void get_callerid_ast(struct vpb_pvt *p)
-{
- struct callerid_state *cs;
- char buf[1024];
- char *name = NULL, *number = NULL;
- int flags;
- int rc = 0, vrc;
- int sam_count = 0;
- struct ast_channel *owner = p->owner;
- int which_cid;
-/*
- float old_gain;
-*/
-#ifdef ANALYSE_CID
- void * ws;
- char * file = "cidsams.wav";
-#endif
-
- if (p->callerid_type == 1) {
- ast_verb(4, "Collected caller ID already\n");
- return;
- }
- else if (p->callerid_type == 2 ) {
- which_cid = CID_SIG_V23;
- ast_verb(4, "Collecting Caller ID v23...\n");
- }
- else if (p->callerid_type == 3) {
- which_cid = CID_SIG_BELL;
- ast_verb(4, "Collecting Caller ID bell...\n");
- } else {
- ast_verb(4, "Caller ID disabled\n");
- return;
- }
-/* vpb_sleep(RING_SKIP); */
-/* vpb_record_get_gain(p->handle, &old_gain); */
- cs = callerid_new(which_cid);
- if (cs) {
-#ifdef ANALYSE_CID
- vpb_wave_open_write(&ws, file, VPB_MULAW);
- vpb_record_set_gain(p->handle, 3.0);
- vpb_record_set_hw_gain(p->handle, 12.0);
-#endif
- vpb_record_buf_start(p->handle, VPB_MULAW);
- while ((rc == 0) && (sam_count < 8000 * 3)) {
- vrc = vpb_record_buf_sync(p->handle, (char*)buf, sizeof(buf));
- if (vrc != VPB_OK)
- ast_log(LOG_ERROR, "%s: Caller ID couldn't read audio buffer!\n", p->dev);
- rc = callerid_feed(cs, (unsigned char *)buf, sizeof(buf), AST_FORMAT_ULAW);
-#ifdef ANALYSE_CID
- vpb_wave_write(ws, (char *)buf, sizeof(buf));
-#endif
- sam_count += sizeof(buf);
- ast_verb(4, "Collecting Caller ID samples [%d][%d]...\n", sam_count, rc);
- }
- vpb_record_buf_finish(p->handle);
-#ifdef ANALYSE_CID
- vpb_wave_close_write(ws);
-#endif
- if (rc == 1) {
- callerid_get(cs, &name, &number, &flags);
- ast_debug(1, "%s: Caller ID name [%s] number [%s] flags [%d]\n", p->dev, name, number, flags);
- } else {
- ast_log(LOG_ERROR, "%s: Failed to decode Caller ID \n", p->dev);
- }
-/* vpb_record_set_gain(p->handle, old_gain); */
-/* vpb_record_set_hw_gain(p->handle,6.0); */
- } else {
- ast_log(LOG_ERROR, "%s: Failed to create Caller ID struct\n", p->dev);
- }
- if (owner->cid.cid_num) {
- ast_free(owner->cid.cid_num);
- owner->cid.cid_num = NULL;
- }
- if (owner->cid.cid_name) {
- ast_free(owner->cid.cid_name);
- owner->cid.cid_name = NULL;
- }
- if (number)
- ast_shrink_phone_number(number);
- ast_set_callerid(owner,
- number, name,
- owner->cid.cid_ani ? NULL : number);
- if (!ast_strlen_zero(name)){
- snprintf(p->callerid, sizeof(p->callerid), "%s %s", number, name);
- } else {
- ast_copy_string(p->callerid, number, sizeof(p->callerid));
- }
- if (cs)
- callerid_free(cs);
-}
-
-/* Terminate any tones we are presently playing */
-static void stoptone(int handle)
-{
- int ret;
- VPB_EVENT je;
- while (vpb_playtone_state(handle) != VPB_OK) {
- vpb_tone_terminate(handle);
- ret = vpb_get_event_ch_async(handle, &je);
- if ((ret == VPB_OK) && (je.type != VPB_DIALEND)) {
- ast_verb(4, "Stop tone collected a wrong event!![%d]\n", je.type);
-/* vpb_put_event(&je); */
- }
- vpb_sleep(10);
- }
-}
-
-/* Safe vpb_playtone_async */
-static int playtone( int handle, VPB_TONE *tone)
-{
- int ret = VPB_OK;
- stoptone(handle);
- ast_verb(4, "[%02d]: Playing tone\n", handle);
- ret = vpb_playtone_async(handle, tone);
- return ret;
-}
-
-static inline int monitor_handle_owned(struct vpb_pvt *p, VPB_EVENT *e)
-{
- struct ast_frame f = {AST_FRAME_CONTROL}; /* default is control, Clear rest. */
- int endbridge = 0;
- int res = 0;
-
- ast_verb(4, "%s: handle_owned: got event: [%d=>%d]\n", p->dev, e->type, e->data);
-
- f.src = "vpb";
- switch (e->type) {
- case VPB_RING:
- if (p->mode == MODE_FXO) {
- f.subclass = AST_CONTROL_RING;
- vpb_timer_stop(p->ring_timer);
- vpb_timer_start(p->ring_timer);
- } else
- f.frametype = AST_FRAME_NULL; /* ignore ring on station port. */
- break;
-
- case VPB_RING_OFF:
- f.frametype = AST_FRAME_NULL;
- break;
-
- case VPB_TIMEREXP:
- if (e->data == p->busy_timer_id) {
- playtone(p->handle, &Busytone);
- p->state = VPB_STATE_PLAYBUSY;
- vpb_timer_stop(p->busy_timer);
- vpb_timer_start(p->busy_timer);
- f.frametype = AST_FRAME_NULL;
- } else if (e->data == p->ringback_timer_id) {
- playtone(p->handle, &Ringbacktone);
- vpb_timer_stop(p->ringback_timer);
- vpb_timer_start(p->ringback_timer);
- f.frametype = AST_FRAME_NULL;
- } else if (e->data == p->ring_timer_id) {
- /* We didnt get another ring in time! */
- if (p->owner->_state != AST_STATE_UP) {
- /* Assume caller has hung up */
- vpb_timer_stop(p->ring_timer);
- f.subclass = AST_CONTROL_HANGUP;
- } else {
- vpb_timer_stop(p->ring_timer);
- f.frametype = AST_FRAME_NULL;
- }
-
- } else {
- f.frametype = AST_FRAME_NULL; /* Ignore. */
- }
- break;
-
- case VPB_DTMF_DOWN:
- case VPB_DTMF:
- if (use_ast_dtmfdet) {
- f.frametype = AST_FRAME_NULL;
- } else if (p->owner->_state == AST_STATE_UP) {
- f.frametype = AST_FRAME_DTMF;
- f.subclass = e->data;
- } else
- f.frametype = AST_FRAME_NULL;
- break;
-
- case VPB_TONEDETECT:
- if (e->data == VPB_BUSY || e->data == VPB_BUSY_308 || e->data == VPB_BUSY_AUST ) {
- ast_debug(4, "%s: handle_owned: got event: BUSY\n", p->dev);
- if (p->owner->_state == AST_STATE_UP) {
- f.subclass = AST_CONTROL_HANGUP;
- } else {
- f.subclass = AST_CONTROL_BUSY;
- }
- } else if (e->data == VPB_FAX) {
- if (!p->faxhandled) {
- if (strcmp(p->owner->exten, "fax")) {
- const char *target_context = S_OR(p->owner->macrocontext, p->owner->context);
-
- if (ast_exists_extension(p->owner, target_context, "fax", 1, p->owner->cid.cid_num)) {
- ast_verb(3, "Redirecting %s to fax extension\n", p->owner->name);
- /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
- pbx_builtin_setvar_helper(p->owner, "FAXEXTEN", p->owner->exten);
- if (ast_async_goto(p->owner, target_context, "fax", 1)) {
- ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", p->owner->name, target_context);
- }
- } else {
- ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n");
- }
- } else {
- ast_debug(1, "Already in a fax extension, not redirecting\n");
- }
- } else {
- ast_debug(1, "Fax already handled\n");
- }
- } else if (e->data == VPB_GRUNT) {
- if (ast_tvdiff_ms(ast_tvnow(), p->lastgrunt) > gruntdetect_timeout) {
- /* Nothing heard on line for a very long time
- * Timeout connection */
- ast_verb(3, "grunt timeout\n");
- ast_log(LOG_NOTICE, "%s: Line hangup due of lack of conversation\n", p->dev);
- f.subclass = AST_CONTROL_HANGUP;
- } else {
- p->lastgrunt = ast_tvnow();
- f.frametype = AST_FRAME_NULL;
- }
- } else {
- f.frametype = AST_FRAME_NULL;
- }
- break;
-
- case VPB_CALLEND:
- #ifdef DIAL_WITH_CALL_PROGRESS
- if (e->data == VPB_CALL_CONNECTED) {
- f.subclass = AST_CONTROL_ANSWER;
- } else if (e->data == VPB_CALL_NO_DIAL_TONE || e->data == VPB_CALL_NO_RING_BACK) {
- f.subclass = AST_CONTROL_CONGESTION;
- } else if (e->data == VPB_CALL_NO_ANSWER || e->data == VPB_CALL_BUSY) {
- f.subclass = AST_CONTROL_BUSY;
- } else if (e->data == VPB_CALL_DISCONNECTED) {
- f.subclass = AST_CONTROL_HANGUP;
- }
- #else
- ast_log(LOG_NOTICE, "%s: Got call progress callback but blind dialing \n", p->dev);
- f.frametype = AST_FRAME_NULL;
- #endif
- break;
-
- case VPB_STATION_OFFHOOK:
- f.subclass = AST_CONTROL_ANSWER;
- break;
-
- case VPB_DROP:
- if ((p->mode == MODE_FXO) && (UseLoopDrop)) { /* ignore loop drop on stations */
- if (p->owner->_state == AST_STATE_UP) {
- f.subclass = AST_CONTROL_HANGUP;
- } else {
- f.frametype = AST_FRAME_NULL;
- }
- }
- break;
- case VPB_LOOP_ONHOOK:
- if (p->owner->_state == AST_STATE_UP) {
- f.subclass = AST_CONTROL_HANGUP;
- } else {
- f.frametype = AST_FRAME_NULL;
- }
- break;
- case VPB_STATION_ONHOOK:
- f.subclass = AST_CONTROL_HANGUP;
- break;
-
- case VPB_STATION_FLASH:
- f.subclass = AST_CONTROL_FLASH;
- break;
-
- /* Called when dialing has finished and ringing starts
- * No indication that call has really been answered when using blind dialing
- */
- case VPB_DIALEND:
- if (p->state < 5) {
- f.subclass = AST_CONTROL_ANSWER;
- ast_verb(2, "%s: Dialend\n", p->dev);
- } else {
- f.frametype = AST_FRAME_NULL;
- }
- break;
-
-/* case VPB_PLAY_UNDERFLOW:
- f.frametype = AST_FRAME_NULL;
- vpb_reset_play_fifo_alarm(p->handle);
- break;
-
- case VPB_RECORD_OVERFLOW:
- f.frametype = AST_FRAME_NULL;
- vpb_reset_record_fifo_alarm(p->handle);
- break;
-*/
- default:
- f.frametype = AST_FRAME_NULL;
- break;
- }
-
-/*
- ast_verb(4, "%s: LOCKING in handle_owned [%d]\n", p->dev,res);
- res = ast_mutex_lock(&p->lock);
- ast_verb(4, "%s: LOCKING count[%d] owner[%d] \n", p->dev, p->lock.__m_count,p->lock.__m_owner);
-*/
- if (p->bridge) { /* Check what happened, see if we need to report it. */
- switch (f.frametype) {
- case AST_FRAME_DTMF:
- if ( !(p->bridge->c0 == p->owner &&
- (p->bridge->flags & AST_BRIDGE_DTMF_CHANNEL_0) ) &&
- !(p->bridge->c1 == p->owner &&
- (p->bridge->flags & AST_BRIDGE_DTMF_CHANNEL_1) )) {
- /* Kill bridge, this is interesting. */
- endbridge = 1;
- }
- break;
-
- case AST_FRAME_CONTROL:
- if (!(p->bridge->flags & AST_BRIDGE_IGNORE_SIGS)) {
- #if 0
- if (f.subclass == AST_CONTROL_BUSY ||
- f.subclass == AST_CONTROL_CONGESTION ||
- f.subclass == AST_CONTROL_HANGUP ||
- f.subclass == AST_CONTROL_FLASH)
- #endif
- endbridge = 1;
- }
- break;
-
- default:
- break;
- }
-
- if (endbridge) {
- if (p->bridge->fo) {
- *p->bridge->fo = ast_frisolate(&f);
- }
-
- if (p->bridge->rc) {
- *p->bridge->rc = p->owner;
- }
-
- ast_mutex_lock(&p->bridge->lock);
- p->bridge->endbridge = 1;
- ast_cond_signal(&p->bridge->cond);
- ast_mutex_unlock(&p->bridge->lock);
- }
- }
-
- if (endbridge) {
- res = ast_mutex_unlock(&p->lock);
-/*
- ast_verb(4, "%s: unLOCKING in handle_owned [%d]\n", p->dev,res);
-*/
- return 0;
- }
-
- ast_verb(4, "%s: handle_owned: Prepared frame type[%d]subclass[%d], bridge=%p owner=[%s]\n",
- p->dev, f.frametype, f.subclass, (void *)p->bridge, p->owner->name);
-
- /* Trylock used here to avoid deadlock that can occur if we
- * happen to be in here handling an event when hangup is called
- * Problem is that hangup holds p->owner->lock
- */
- if ((f.frametype >= 0) && (f.frametype != AST_FRAME_NULL) && (p->owner)) {
- if (ast_channel_trylock(p->owner) == 0) {
- ast_queue_frame(p->owner, &f);
- ast_channel_unlock(p->owner);
- ast_verb(4, "%s: handled_owned: Queued Frame to [%s]\n", p->dev, p->owner->name);
- } else {
- ast_verbose("%s: handled_owned: Missed event %d/%d \n",
- p->dev, f.frametype, f.subclass);
- }
- }
- res = ast_mutex_unlock(&p->lock);
-/*
- ast_verb(4, "%s: unLOCKING in handle_owned [%d]\n", p->dev,res);
-*/
-
- return 0;
-}
-
-static inline int monitor_handle_notowned(struct vpb_pvt *p, VPB_EVENT *e)
-{
- char s[2] = {0};
- struct ast_channel *owner = p->owner;
- char cid_num[256];
- char cid_name[256];
-/*
- struct ast_channel *c;
-*/
-
- char str[VPB_MAX_STR];
-
- vpb_translate_event(e, str);
- ast_verb(4, "%s: handle_notowned: mode=%d, event[%d][%s]=[%d]\n", p->dev, p->mode, e->type,str, e->data);
-
- switch (e->type) {
- case VPB_LOOP_ONHOOK:
- case VPB_LOOP_POLARITY:
- if (UsePolarityCID == 1) {
- ast_verb(4, "Polarity reversal\n");
- if (p->callerid_type == 1) {
- ast_verb(4, "Using VPB Caller ID\n");
- get_callerid(p); /* UK CID before 1st ring*/
- }
-/* get_callerid_ast(p); */ /* Caller ID using the ast functions */
- }
- break;
- case VPB_RING:
- if (p->mode == MODE_FXO) /* FXO port ring, start * */ {
- vpb_new(p, AST_STATE_RING, p->context);
- if (UsePolarityCID != 1) {
- if (p->callerid_type == 1) {
- ast_verb(4, "Using VPB Caller ID\n");
- get_callerid(p); /* Australian CID only between 1st and 2nd ring */
- }
- get_callerid_ast(p); /* Caller ID using the ast functions */
- } else {
- ast_log(LOG_ERROR, "Setting caller ID: %s %s\n", p->cid_num, p->cid_name);
- ast_set_callerid(p->owner, p->cid_num, p->cid_name, p->cid_num);
- p->cid_num[0] = 0;
- p->cid_name[0] = 0;
- }
-
- vpb_timer_stop(p->ring_timer);
- vpb_timer_start(p->ring_timer);
- }
- break;
-
- case VPB_RING_OFF:
- break;
-
- case VPB_STATION_OFFHOOK:
- if (p->mode == MODE_IMMEDIATE) {
- vpb_new(p,AST_STATE_RING, p->context);
- } else {
- ast_verb(4, "%s: handle_notowned: playing dialtone\n", p->dev);
- playtone(p->handle, &Dialtone);
- p->state = VPB_STATE_PLAYDIAL;
- p->wantdtmf = 1;
- p->ext[0] = 0; /* Just to be sure & paranoid.*/
- }
- break;
-
- case VPB_DIALEND:
- if (p->mode == MODE_DIALTONE) {
- if (p->state == VPB_STATE_PLAYDIAL) {
- playtone(p->handle, &Dialtone);
- p->wantdtmf = 1;
- p->ext[0] = 0; /* Just to be sure & paranoid. */
- }
-#if 0
- /* These are not needed as they have timers to restart them */
- else if (p->state == VPB_STATE_PLAYBUSY) {
- playtone(p->handle, &Busytone);
- p->wantdtmf = 1;
- p->ext[0] = 0;
- } else if (p->state == VPB_STATE_PLAYRING) {
- playtone(p->handle, &Ringbacktone);
- p->wantdtmf = 1;
- p->ext[0] = 0;
- }
-#endif
- } else {
- ast_verb(4, "%s: handle_notowned: Got a DIALEND when not really expected\n",p->dev);
- }
- break;
-
- case VPB_STATION_ONHOOK: /* clear ext */
- stoptone(p->handle);
- p->wantdtmf = 1 ;
- p->ext[0] = 0;
- p->state = VPB_STATE_ONHOOK;
- break;
- case VPB_TIMEREXP:
- if (e->data == p->dtmfidd_timer_id) {
- if (ast_exists_extension(NULL, p->context, p->ext, 1, p->callerid)){
- ast_verb(4, "%s: handle_notowned: DTMF IDD timer out, matching on [%s] in [%s]\n", p->dev, p->ext, p->context);
-
- vpb_new(p, AST_STATE_RING, p->context);
- }
- } else if (e->data == p->ring_timer_id) {
- /* We didnt get another ring in time! */
- if (p->owner) {
- if (p->owner->_state != AST_STATE_UP) {
- /* Assume caller has hung up */
- vpb_timer_stop(p->ring_timer);
- }
- } else {
- /* No owner any more, Assume caller has hung up */
- vpb_timer_stop(p->ring_timer);
- }
- }
- break;
-
- case VPB_DTMF:
- if (p->state == VPB_STATE_ONHOOK){
- /* DTMF's being passed while on-hook maybe Caller ID */
- if (p->mode == MODE_FXO) {
- if (e->data == DTMF_CID_START) { /* CallerID Start signal */
- p->dtmf_caller_pos = 0; /* Leaves the first digit out */
- memset(p->callerid, 0, sizeof(p->callerid));
- } else if (e->data == DTMF_CID_STOP) { /* CallerID End signal */
- p->callerid[p->dtmf_caller_pos] = '\0';
- ast_verb(3, " %s: DTMF CallerID %s\n", p->dev, p->callerid);
- if (owner) {
- /*
- if (owner->cid.cid_num)
- ast_free(owner->cid.cid_num);
- owner->cid.cid_num=NULL;
- if (owner->cid.cid_name)
- ast_free(owner->cid.cid_name);
- owner->cid.cid_name=NULL;
- owner->cid.cid_num = strdup(p->callerid);
- */
- cid_name[0] = '\0';
- cid_num[0] = '\0';
- ast_callerid_split(p->callerid, cid_name, sizeof(cid_name), cid_num, sizeof(cid_num));
- ast_set_callerid(owner, cid_num, cid_name, cid_num);
-
- } else {
- ast_verb(3, " %s: DTMF CallerID: no owner to assign CID \n", p->dev);
- }
- } else if (p->dtmf_caller_pos < AST_MAX_EXTENSION) {
- if (p->dtmf_caller_pos >= 0) {
- p->callerid[p->dtmf_caller_pos] = e->data;
- }
- p->dtmf_caller_pos++;
- }
- }
- break;
- }
- if (p->wantdtmf == 1) {
- stoptone(p->handle);
- p->wantdtmf = 0;
- }
- p->state = VPB_STATE_GETDTMF;
- s[0] = e->data;
- strncat(p->ext, s, sizeof(p->ext) - strlen(p->ext) - 1);
- #if 0
- if (!strcmp(p->ext, ast_pickup_ext())) {
- /* Call pickup has been dialled! */
- if (ast_pickup_call(c)) {
- /* Call pickup wasnt possible */
- }
- } else
- #endif
- if (ast_exists_extension(NULL, p->context, p->ext, 1, p->callerid)) {
- if (ast_canmatch_extension(NULL, p->context, p->ext, 1, p->callerid)) {
- ast_verb(4, "%s: handle_notowned: Multiple matches on [%s] in [%s]\n", p->dev, p->ext, p->context);
- /* Start DTMF IDD timer */
- vpb_timer_stop(p->dtmfidd_timer);
- vpb_timer_start(p->dtmfidd_timer);
- } else {
- ast_verb(4, "%s: handle_notowned: Matched on [%s] in [%s]\n", p->dev, p->ext , p->context);
- vpb_new(p, AST_STATE_UP, p->context);
- }
- } else if (!ast_canmatch_extension(NULL, p->context, p->ext, 1, p->callerid)) {
- if (ast_exists_extension(NULL, "default", p->ext, 1, p->callerid)) {
- vpb_new(p, AST_STATE_UP, "default");
- } else if (!ast_canmatch_extension(NULL, "default", p->ext, 1, p->callerid)) {
- ast_verb(4, "%s: handle_notowned: can't match anything in %s or default\n", p->dev, p->context);
- playtone(p->handle, &Busytone);
- vpb_timer_stop(p->busy_timer);
- vpb_timer_start(p->busy_timer);
- p->state = VPB_STATE_PLAYBUSY;
- }
- }
- break;
-
- default:
- /* Ignore.*/
- break;
- }
-
- ast_verb(4, "%s: handle_notowned: mode=%d, [%d=>%d]\n", p->dev, p->mode, e->type, e->data);
-
- return 0;
-}
-
-static void *do_monitor(void *unused)
-{
-
- /* Monitor thread, doesn't die until explicitly killed. */
-
- ast_verb(2, "Starting vpb monitor thread[%ld]\n", pthread_self());
-
- pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
-
- for (;;) {
- VPB_EVENT e;
- VPB_EVENT je;
- char str[VPB_MAX_STR];
- struct vpb_pvt *p;
-
- /*
- ast_verb(4, "Monitor waiting for event\n");
- */
-
- int res = vpb_get_event_sync(&e, VPB_WAIT_TIMEOUT);
- if ((res == VPB_NO_EVENTS) || (res == VPB_TIME_OUT)) {
- /*
- if (res == VPB_NO_EVENTS) {
- ast_verb(4, "No events....\n");
- } else {
- ast_verb(4, "No events, timed out....\n");
- }
- */
- continue;
- }
-
- if (res != VPB_OK) {
- ast_log(LOG_ERROR,"Monitor get event error %d\n", res );
- ast_verbose("Monitor get event error %d\n", res );
- continue;
- }
-
- str[0] = 0;
-
- p = NULL;
-
- ast_mutex_lock(&monlock);
- if (e.type == VPB_NULL_EVENT) {
- ast_verb(4, "Monitor got null event\n");
- } else {
- vpb_translate_event(&e, str);
- if (*str && *(str + 1)) {
- str[strlen(str) - 1] = '\0';
- }
-
- ast_mutex_lock(&iflock);
- for (p = iflist; p && p->handle != e.handle; p = p->next);
- ast_mutex_unlock(&iflock);
-
- if (p) {
- ast_verb(4, "%s: Event [%d=>%s]\n",
- p ? p->dev : "null", e.type, str);
- }
- }
-
- ast_mutex_unlock(&monlock);
-
- if (!p) {
- if (e.type != VPB_NULL_EVENT) {
- ast_log(LOG_WARNING, "Got event [%s][%d], no matching iface!\n", str, e.type);
- ast_verb(4, "vpb/ERR: No interface for Event [%d=>%s] \n", e.type, str);
- }
- continue;
- }
-
- /* flush the event from the channel event Q */
- vpb_get_event_ch_async(e.handle, &je);
- vpb_translate_event(&je, str);
- ast_verb(5, "%s: Flushing event [%d]=>%s\n", p->dev, je.type, str);
-
- /* Check for ownership and locks */
- if ((p->owner) && (!p->golock)) {
- /* Need to get owner lock */
- /* Safely grab both p->lock and p->owner->lock so that there
- cannot be a race with something from the other side */
- /*
- ast_mutex_lock(&p->lock);
- while (ast_mutex_trylock(&p->owner->lock)) {
- ast_mutex_unlock(&p->lock);
- usleep(1);
- ast_mutex_lock(&p->lock);
- if (!p->owner)
- break;
- }
- if (p->owner)
- p->golock = 1;
- */
- }
- /* Two scenarios: Are you owned or not. */
- if (p->owner) {
- monitor_handle_owned(p, &e);
- } else {
- monitor_handle_notowned(p, &e);
- }
- /* if ((!p->owner)&&(p->golock)) {
- ast_mutex_unlock(&p->owner->lock);
- ast_mutex_unlock(&p->lock);
- }
- */
-
- }
-
- return NULL;
-}
-
-static int restart_monitor(void)
-{
- int error = 0;
-
- /* If we're supposed to be stopped -- stay stopped */
- if (mthreadactive == -2)
- return 0;
-
- ast_verb(4, "Restarting monitor\n");
-
- ast_mutex_lock(&monlock);
- if (monitor_thread == pthread_self()) {
- ast_log(LOG_WARNING, "Cannot kill myself\n");
- error = -1;
- ast_verb(4, "Monitor trying to kill monitor\n");
- } else {
- if (mthreadactive != -1) {
- /* Why do other drivers kill the thread? No need says I, simply awake thread with event. */
- VPB_EVENT e;
- e.handle = 0;
- e.type = VPB_EVT_NONE;
- e.data = 0;
-
- ast_verb(4, "Trying to reawake monitor\n");
-
- vpb_put_event(&e);
- } else {
- /* Start a new monitor */
- int pid = ast_pthread_create(&monitor_thread, NULL, do_monitor, NULL);
- ast_verb(4, "Created new monitor thread %d\n", pid);
- if (pid < 0) {
- ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
- error = -1;
- } else {
- mthreadactive = 0; /* Started the thread!*/
- }
- }
- }
- ast_mutex_unlock(&monlock);
-
- ast_verb(4, "Monitor restarted\n");
-
- return error;
-}
-
-/* Per board config that must be called after vpb_open() */
-static void mkbrd(vpb_model_t model, int echo_cancel)
-{
- if (!bridges) {
- if (model == vpb_model_v4pci) {
- max_bridges = MAX_BRIDGES_V4PCI;
- }
- bridges = (vpb_bridge_t *)ast_calloc(1, max_bridges * sizeof(vpb_bridge_t));
- if (!bridges) {
- ast_log(LOG_ERROR, "Failed to initialize bridges\n");
- } else {
- int i;
- for (i = 0; i < max_bridges; i++) {
- ast_mutex_init(&bridges[i].lock);
- ast_cond_init(&bridges[i].cond, NULL);
- }
- }
- }
- if (!echo_cancel) {
- if (model == vpb_model_v4pci) {
- vpb_echo_canc_disable();
- ast_log(LOG_NOTICE, "Voicetronix echo cancellation OFF\n");
- } else {
- /* need to do it port by port for OpenSwitch */
- }
- } else {
- if (model == vpb_model_v4pci) {
- vpb_echo_canc_enable();
- ast_log(LOG_NOTICE, "Voicetronix echo cancellation ON\n");
- if (ec_supp_threshold > -1) {
- vpb_echo_canc_set_sup_thresh(0, &ec_supp_threshold);
- ast_log(LOG_NOTICE, "Voicetronix EC Sup Thres set\n");
- }
- } else {
- /* need to do it port by port for OpenSwitch */
- }
- }
-}
-
-static struct vpb_pvt *mkif(int board, int channel, int mode, int gains, float txgain, float rxgain,
- float txswgain, float rxswgain, int bal1, int bal2, int bal3,
- char * callerid, int echo_cancel, int group, ast_group_t callgroup, ast_group_t pickupgroup )
-{
- struct vpb_pvt *tmp;
- char buf[64];
-
- tmp = (vpb_pvt *)ast_calloc(1, sizeof(*tmp));
-
- if (!tmp)
- return NULL;
-
- tmp->handle = vpb_open(board, channel);
-
- if (tmp->handle < 0) {
- ast_log(LOG_WARNING, "Unable to create channel vpb/%d-%d: %s\n",
- board, channel, strerror(errno));
- ast_free(tmp);
- return NULL;
- }
-
- snprintf(tmp->dev, sizeof(tmp->dev), "vpb/%d-%d", board, channel);
-
- tmp->mode = mode;
-
- tmp->group = group;
- tmp->callgroup = callgroup;
- tmp->pickupgroup = pickupgroup;
-
- /* Initilize dtmf caller ID position variable */
- tmp->dtmf_caller_pos = 0;
-
- ast_copy_string(tmp->language, language, sizeof(tmp->language));
- ast_copy_string(tmp->context, context, sizeof(tmp->context));
-
- tmp->callerid_type = 0;
- if (callerid) {
- if (strcasecmp(callerid, "on") == 0) {
- tmp->callerid_type = 1;
- ast_copy_string(tmp->callerid, "unknown", sizeof(tmp->callerid));
- } else if (strcasecmp(callerid, "v23") == 0) {
- tmp->callerid_type = 2;
- ast_copy_string(tmp->callerid, "unknown", sizeof(tmp->callerid));
- } else if (strcasecmp(callerid, "bell") == 0) {
- tmp->callerid_type = 3;
- ast_copy_string(tmp->callerid, "unknown", sizeof(tmp->callerid));
- } else {
- ast_copy_string(tmp->callerid, callerid, sizeof(tmp->callerid));
- }
- } else {
- ast_copy_string(tmp->callerid, "unknown", sizeof(tmp->callerid));
- }
-
- /* check if codec balances have been set in the config file */
- if (bal3 >= 0) {
- if ((bal1>=0) && !(bal1 & 32)) bal1 |= 32;
- vpb_set_codec_reg(tmp->handle, 0x42, bal3);
- }
- if (bal1 >= 0) {
- vpb_set_codec_reg(tmp->handle, 0x32, bal1);
- }
- if (bal2 >= 0) {
- vpb_set_codec_reg(tmp->handle, 0x3a, bal2);
- }
-
- if (gains & VPB_GOT_TXHWG) {
- if (txgain > MAX_VPB_GAIN) {
- tmp->txgain = MAX_VPB_GAIN;
- } else if (txgain < MIN_VPB_GAIN) {
- tmp->txgain = MIN_VPB_GAIN;
- } else {
- tmp->txgain = txgain;
- }
-
- ast_log(LOG_NOTICE, "VPB setting Tx Hw gain to [%f]\n", tmp->txgain);
- vpb_play_set_hw_gain(tmp->handle, tmp->txgain);
- }
-
- if (gains & VPB_GOT_RXHWG) {
- if (rxgain > MAX_VPB_GAIN) {
- tmp->rxgain = MAX_VPB_GAIN;
- } else if (rxgain < MIN_VPB_GAIN) {
- tmp->rxgain = MIN_VPB_GAIN;
- } else {
- tmp->rxgain = rxgain;
- }
- ast_log(LOG_NOTICE, "VPB setting Rx Hw gain to [%f]\n", tmp->rxgain);
- vpb_record_set_hw_gain(tmp->handle, tmp->rxgain);
- }
-
- if (gains & VPB_GOT_TXSWG) {
- tmp->txswgain = txswgain;
- ast_log(LOG_NOTICE, "VPB setting Tx Sw gain to [%f]\n", tmp->txswgain);
- vpb_play_set_gain(tmp->handle, tmp->txswgain);
- }
-
- if (gains & VPB_GOT_RXSWG) {
- tmp->rxswgain = rxswgain;
- ast_log(LOG_NOTICE, "VPB setting Rx Sw gain to [%f]\n", tmp->rxswgain);
- vpb_record_set_gain(tmp->handle, tmp->rxswgain);
- }
-
- tmp->vpb_model = vpb_model_unknown;
- if (vpb_get_model(tmp->handle, buf) == VPB_OK) {
- if (strcmp(buf, "V12PCI") == 0) {
- tmp->vpb_model = vpb_model_v12pci;
- } else if (strcmp(buf, "VPB4") == 0) {
- tmp->vpb_model = vpb_model_v4pci;
- }
- }
-
- ast_mutex_init(&tmp->owner_lock);
- ast_mutex_init(&tmp->lock);
- ast_mutex_init(&tmp->record_lock);
- ast_mutex_init(&tmp->play_lock);
- ast_mutex_init(&tmp->play_dtmf_lock);
-
- /* set default read state */
- tmp->read_state = 0;
-
- tmp->golock = 0;
-
- tmp->busy_timer_id = vpb_timer_get_unique_timer_id();
- vpb_timer_open(&tmp->busy_timer, tmp->handle, tmp->busy_timer_id, TIMER_PERIOD_BUSY);
-
- tmp->ringback_timer_id = vpb_timer_get_unique_timer_id();
- vpb_timer_open(&tmp->ringback_timer, tmp->handle, tmp->ringback_timer_id, TIMER_PERIOD_RINGBACK);
-
- tmp->ring_timer_id = vpb_timer_get_unique_timer_id();
- vpb_timer_open(&tmp->ring_timer, tmp->handle, tmp->ring_timer_id, timer_period_ring);
-
- tmp->dtmfidd_timer_id = vpb_timer_get_unique_timer_id();
- vpb_timer_open(&tmp->dtmfidd_timer, tmp->handle, tmp->dtmfidd_timer_id, dtmf_idd);
-
- if (mode == MODE_FXO){
- if (use_ast_dtmfdet)
- vpb_set_event_mask(tmp->handle, VPB_EVENTS_NODTMF);
- else
- vpb_set_event_mask(tmp->handle, VPB_EVENTS_ALL);
- } else {
-/*
- if (use_ast_dtmfdet)
- vpb_set_event_mask(tmp->handle, VPB_EVENTS_NODTMF);
- else
-*/
- vpb_set_event_mask(tmp->handle, VPB_EVENTS_STAT);
- }
-
- if ((tmp->vpb_model == vpb_model_v12pci) && (echo_cancel)) {
- vpb_hostecho_on(tmp->handle);
- }
- if (use_ast_dtmfdet) {
- tmp->vad = ast_dsp_new();
- ast_dsp_set_features(tmp->vad, DSP_FEATURE_DTMF_DETECT);
- ast_dsp_digitmode(tmp->vad, DSP_DIGITMODE_DTMF);
- if (relaxdtmf)
- ast_dsp_digitmode(tmp->vad, DSP_DIGITMODE_DTMF|DSP_DIGITMODE_RELAXDTMF);
- } else {
- tmp->vad = NULL;
- }
-
- /* define grunt tone */
- vpb_settonedet(tmp->handle,&toned_ungrunt);
-
- ast_log(LOG_NOTICE,"Voicetronix %s channel %s initialized (rxsg=%f/txsg=%f/rxhg=%f/txhg=%f)(0x%x/0x%x/0x%x)\n",
- (tmp->vpb_model == vpb_model_v4pci) ? "V4PCI" :
- (tmp->vpb_model == vpb_model_v12pci) ? "V12PCI" : "[Unknown model]",
- tmp->dev, tmp->rxswgain, tmp->txswgain, tmp->rxgain, tmp->txgain, bal1, bal2, bal3);
-
- return tmp;
-}
-
-static int vpb_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
-{
- struct vpb_pvt *p = (struct vpb_pvt *)ast->tech_pvt;
- int res = 0;
- int tmp = 0;
-
- if (use_ast_ind == 1) {
- ast_verb(4, "%s: vpb_indicate called when using Ast Indications !?!\n", p->dev);
- return 0;
- }
-
- ast_verb(4, "%s: vpb_indicate [%d] state[%d]\n", p->dev, condition,ast->_state);
-/*
- if (ast->_state != AST_STATE_UP) {
- ast_verb(4, "%s: vpb_indicate Not in AST_STATE_UP\n", p->dev, condition,ast->_state);
- return res;
- }
-*/
-
-/*
- ast_verb(4, "%s: LOCKING in indicate \n", p->dev);
- ast_verb(4, "%s: LOCKING count[%d] owner[%d] \n", p->dev, p->lock.__m_count, p->lock.__m_owner);
-*/
- ast_mutex_lock(&p->lock);
- switch (condition) {
- case AST_CONTROL_BUSY:
- case AST_CONTROL_CONGESTION:
- if (ast->_state == AST_STATE_UP) {
- playtone(p->handle, &Busytone);
- p->state = VPB_STATE_PLAYBUSY;
- vpb_timer_stop(p->busy_timer);
- vpb_timer_start(p->busy_timer);
- }
- break;
- case AST_CONTROL_RINGING:
- if (ast->_state == AST_STATE_UP) {
- playtone(p->handle, &Ringbacktone);
- p->state = VPB_STATE_PLAYRING;
- ast_verb(4, "%s: vpb indicate: setting ringback timer [%d]\n", p->dev,p->ringback_timer_id);
-
- vpb_timer_stop(p->ringback_timer);
- vpb_timer_start(p->ringback_timer);
- }
- break;
- case AST_CONTROL_ANSWER:
- case -1: /* -1 means stop playing? */
- vpb_timer_stop(p->ringback_timer);
- vpb_timer_stop(p->busy_timer);
- stoptone(p->handle);
- break;
- case AST_CONTROL_HANGUP:
- if (ast->_state == AST_STATE_UP) {
- playtone(p->handle, &Busytone);
- p->state = VPB_STATE_PLAYBUSY;
- vpb_timer_stop(p->busy_timer);
- vpb_timer_start(p->busy_timer);
- }
- break;
- case AST_CONTROL_HOLD:
- ast_moh_start(ast, (const char *) data, NULL);
- break;
- case AST_CONTROL_UNHOLD:
- ast_moh_stop(ast);
- break;
- default:
- res = 0;
- break;
- }
- tmp = ast_mutex_unlock(&p->lock);
-/*
- ast_verb(4, "%s: unLOCKING in indicate [%d]\n", p->dev,tmp);
-*/
- return res;
-}
-
-static int vpb_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
-{
- struct vpb_pvt *p = (struct vpb_pvt *)newchan->tech_pvt;
- int res = 0;
-
-/*
- ast_verb(4, "%s: LOCKING in fixup \n", p->dev);
- ast_verb(4, "%s: LOCKING count[%d] owner[%d] \n", p->dev, p->lock.__m_count,p->lock.__m_owner);
-*/
- ast_mutex_lock(&p->lock);
- ast_debug(1, "New owner for channel %s is %s\n", p->dev, newchan->name);
-
- if (p->owner == oldchan) {
- p->owner = newchan;
- }
-
- if (newchan->_state == AST_STATE_RINGING){
- if (use_ast_ind == 1) {
- ast_verb(4, "%s: vpb_fixup Calling ast_indicate\n", p->dev);
- ast_indicate(newchan, AST_CONTROL_RINGING);
- } else {
- ast_verb(4, "%s: vpb_fixup Calling vpb_indicate\n", p->dev);
- vpb_indicate(newchan, AST_CONTROL_RINGING, NULL, 0);
- }
- }
-
- res = ast_mutex_unlock(&p->lock);
-/*
- ast_verb(4, "%s: unLOCKING in fixup [%d]\n", p->dev,res);
-*/
- return 0;
-}
-
-static int vpb_digit_begin(struct ast_channel *ast, char digit)
-{
- /* XXX Modify this callback to let Asterisk control the length of DTMF */
- return 0;
-}
-static int vpb_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
-{
- struct vpb_pvt *p = (struct vpb_pvt *)ast->tech_pvt;
- char s[2];
- int res = 0;
-
- if (use_ast_dtmf) {
- ast_verb(4, "%s: vpb_digit: asked to play digit[%c] but we are using asterisk dtmf play back?!\n", p->dev, digit);
- return 0;
- }
-
-/*
- ast_verb(4, "%s: LOCKING in digit \n", p->dev);
- ast_verb(4, "%s: LOCKING count[%d] owner[%d] \n", p->dev, p->lock.__m_count,p->lock.__m_owner);
-*/
- ast_mutex_lock(&p->lock);
-
-
- s[0] = digit;
- s[1] = '\0';
-
- ast_verb(4, "%s: vpb_digit: asked to play digit[%s]\n", p->dev, s);
-
- ast_mutex_lock(&p->play_dtmf_lock);
- strncat(p->play_dtmf, s, sizeof(*p->play_dtmf) - strlen(p->play_dtmf) - 1);
- ast_mutex_unlock(&p->play_dtmf_lock);
-
- res = ast_mutex_unlock(&p->lock);
-/*
- ast_verb(4, "%s: unLOCKING in digit [%d]\n", p->dev,res);
-*/
- return 0;
-}
-
-/* Places a call out of a VPB channel */
-static int vpb_call(struct ast_channel *ast, char *dest, int timeout)
-{
- struct vpb_pvt *p = (struct vpb_pvt *)ast->tech_pvt;
- int res = 0, i;
- char *s = strrchr(dest, '/');
- char dialstring[254] = "";
- int tmp = 0;
-
-/*
- ast_verb(4, "%s: LOCKING in call \n", p->dev);
- ast_verb(4, "%s: LOCKING count[%d] owner[%d] \n", p->dev, p->lock.__m_count,p->lock.__m_owner);
-*/
- ast_mutex_lock(&p->lock);
- ast_verb(4, "%s: starting call to [%s]\n", p->dev, dest);
-
- if (s)
- s = s + 1;
- else
- s = dest;
- ast_copy_string(dialstring, s, sizeof(dialstring));
- for (i = 0; dialstring[i] != '\0'; i++) {
- if ((dialstring[i] == 'w') || (dialstring[i] == 'W'))
- dialstring[i] = ',';
- else if ((dialstring[i] == 'f') || (dialstring[i] == 'F'))
- dialstring[i] = '&';
- }
-
- if (ast->_state != AST_STATE_DOWN && ast->_state != AST_STATE_RESERVED) {
- ast_log(LOG_WARNING, "vpb_call on %s neither down nor reserved!\n", ast->name);
- tmp = ast_mutex_unlock(&p->lock);
-/*
- ast_verb(4, "%s: unLOCKING in call [%d]\n", p->dev,tmp);
-*/
- return -1;
- }
- if (p->mode != MODE_FXO) /* Station port, ring it. */
- vpb_ring_station_async(p->handle, 2);
- else {
- VPB_CALL call;
- int j;
-
- /* Dial must timeout or it can leave channels unuseable */
- if (timeout == 0) {
- timeout = TIMER_PERIOD_NOANSWER;
- } else {
- timeout = timeout * 1000; /* convert from secs to ms. */
- }
-
- /* These timeouts are only used with call progress dialing */
- call.dialtones = 1; /* Number of dialtones to get outside line */
- call.dialtone_timeout = VPB_DIALTONE_WAIT; /* Wait this long for dialtone (ms) */
- call.ringback_timeout = VPB_RINGWAIT; /* Wait this long for ringing after dialing (ms) */
- call.inter_ringback_timeout = VPB_CONNECTED_WAIT; /* If ringing stops for this long consider it connected (ms) */
- call.answer_timeout = timeout; /* Time to wait for answer after ringing starts (ms) */
- memcpy(&call.tone_map, DialToneMap, sizeof(DialToneMap));
- vpb_set_call(p->handle, &call);
-
- ast_verb(2, "%s: Calling %s on %s \n",p->dev, dialstring, ast->name);
-
- ast_verb(2, "%s: Dial parms for %s %d/%dms/%dms/%dms/%dms\n", p->dev,
- ast->name, call.dialtones, call.dialtone_timeout,
- call.ringback_timeout, call.inter_ringback_timeout,
- call.answer_timeout);
- for (j = 0; !call.tone_map[j].terminate; j++) {
- ast_verb(2, "%s: Dial parms for %s tone %d->%d\n", p->dev,
- ast->name, call.tone_map[j].tone_id, call.tone_map[j].call_id);
- }
-
- ast_verb(4, "%s: Disabling Loop Drop detection\n", p->dev);
- vpb_disable_event(p->handle, VPB_MDROP);
- vpb_sethook_sync(p->handle, VPB_OFFHOOK);
- p->state = VPB_STATE_OFFHOOK;
-
- #ifndef DIAL_WITH_CALL_PROGRESS
- vpb_sleep(300);
- ast_verb(4, "%s: Enabling Loop Drop detection\n", p->dev);
- vpb_enable_event(p->handle, VPB_MDROP);
- res = vpb_dial_async(p->handle, dialstring);
- #else
- ast_verb(4, "%s: Enabling Loop Drop detection\n", p->dev);
- vpb_enable_event(p->handle, VPB_MDROP);
- res = vpb_call_async(p->handle, dialstring);
- #endif
-
- if (res != VPB_OK) {
- ast_debug(1, "Call on %s to %s failed: %d\n", ast->name, s, res);
- res = -1;
- } else
- res = 0;
- }
-
- ast_verb(3, "%s: VPB Calling %s [t=%d] on %s returned %d\n", p->dev , s, timeout, ast->name, res);
- if (res == 0) {
- ast_setstate(ast, AST_STATE_RINGING);
- ast_queue_control(ast, AST_CONTROL_RINGING);
- }
-
- if (!p->readthread) {
- ast_pthread_create(&p->readthread, NULL, do_chanreads, (void *)p);
- }
-
- tmp = ast_mutex_unlock(&p->lock);
-/*
- ast_verb(4, "%s: unLOCKING in call [%d]\n", p->dev,tmp);
-*/
- return res;
-}
-
-static int vpb_hangup(struct ast_channel *ast)
-{
- struct vpb_pvt *p = (struct vpb_pvt *)ast->tech_pvt;
- VPB_EVENT je;
- char str[VPB_MAX_STR];
- int res = 0;
-
-/*
- ast_verb(4, "%s: LOCKING in hangup \n", p->dev);
- ast_verb(4, "%s: LOCKING in hangup count[%d] owner[%d] \n", p->dev, p->lock.__m_count,p->lock.__m_owner);
- ast_verb(4, "%s: LOCKING pthread_self(%d)\n", p->dev,pthread_self());
- ast_mutex_lock(&p->lock);
-*/
- ast_verb(2, "%s: Hangup requested\n", ast->name);
-
- if (!ast->tech || !ast->tech_pvt) {
- ast_log(LOG_WARNING, "%s: channel not connected?\n", ast->name);
- res = ast_mutex_unlock(&p->lock);
-/*
- ast_verb(4, "%s: unLOCKING in hangup [%d]\n", p->dev,res);
-*/
- /* Free up ast dsp if we have one */
- if (use_ast_dtmfdet && p->vad) {
- ast_dsp_free(p->vad);
- p->vad = NULL;
- }
- return 0;
- }
-
-
-
- /* Stop record */
- p->stopreads = 1;
- if (p->readthread) {
- pthread_join(p->readthread, NULL);
- ast_verb(4, "%s: stopped record thread \n", ast->name);
- }
-
- /* Stop play */
- if (p->lastoutput != -1) {
- ast_verb(2, "%s: Ending play mode \n", ast->name);
- vpb_play_terminate(p->handle);
- ast_mutex_lock(&p->play_lock);
- vpb_play_buf_finish(p->handle);
- ast_mutex_unlock(&p->play_lock);
- }
-
- ast_verb(4, "%s: Setting state down\n", ast->name);
- ast_setstate(ast, AST_STATE_DOWN);
-
-
-/*
- ast_verb(4, "%s: LOCKING in hangup \n", p->dev);
- ast_verb(4, "%s: LOCKING in hangup count[%d] owner[%d] \n", p->dev, p->lock.__m_count,p->lock.__m_owner);
- ast_verb(4, "%s: LOCKING pthread_self(%d)\n", p->dev,pthread_self());
-*/
- ast_mutex_lock(&p->lock);
-
- if (p->mode != MODE_FXO) {
- /* station port. */
- vpb_ring_station_async(p->handle, 0);
- if (p->state != VPB_STATE_ONHOOK) {
- /* This is causing a "dial end" "play tone" loop
- playtone(p->handle, &Busytone);
- p->state = VPB_STATE_PLAYBUSY;
- ast_verb(5, "%s: Station offhook[%d], playing busy tone\n",
- ast->name,p->state);
- */
- } else {
- stoptone(p->handle);
- }
- #ifdef VPB_PRI
- vpb_setloop_async(p->handle, VPB_OFFHOOK);
- vpb_sleep(100);
- vpb_setloop_async(p->handle, VPB_ONHOOK);
- #endif
- } else {
- stoptone(p->handle); /* Terminates any dialing */
- vpb_sethook_sync(p->handle, VPB_ONHOOK);
- p->state=VPB_STATE_ONHOOK;
- }
- while (VPB_OK == vpb_get_event_ch_async(p->handle, &je)) {
- vpb_translate_event(&je, str);
- ast_verb(4, "%s: Flushing event [%d]=>%s\n", ast->name, je.type, str);
- }
-
- p->readthread = 0;
- p->lastoutput = -1;
- p->lastinput = -1;
- p->last_ignore_dtmf = 1;
- p->ext[0] = 0;
- p->dialtone = 0;
-
- p->owner = NULL;
- ast->tech_pvt = NULL;
-
- /* Free up ast dsp if we have one */
- if (use_ast_dtmfdet && p->vad) {
- ast_dsp_free(p->vad);
- p->vad = NULL;
- }
-
- ast_verb(2, "%s: Hangup complete\n", ast->name);
-
- restart_monitor();
-/*
- ast_verb(4, "%s: LOCKING in hangup count[%d] owner[%d] \n", p->dev, p->lock.__m_count,p->lock.__m_owner);
-*/
- res = ast_mutex_unlock(&p->lock);
-/*
- ast_verb(4, "%s: unLOCKING in hangup [%d]\n", p->dev,res);
- ast_verb(4, "%s: LOCKING in hangup count[%d] owner[%d] \n", p->dev, p->lock.__m_count,p->lock.__m_owner);
-*/
- return 0;
-}
-
-static int vpb_answer(struct ast_channel *ast)
-{
- struct vpb_pvt *p = (struct vpb_pvt *)ast->tech_pvt;
- int res = 0;
-/*
- VPB_EVENT je;
- int ret;
- ast_verb(4, "%s: LOCKING in answer \n", p->dev);
- ast_verb(4, "%s: LOCKING count[%d] owner[%d] \n", p->dev, p->lock.__m_count,p->lock.__m_owner);
-*/
- ast_mutex_lock(&p->lock);
-
- ast_verb(4, "%s: Answering channel\n", p->dev);
-
- if (p->mode == MODE_FXO) {
- ast_verb(4, "%s: Disabling Loop Drop detection\n", p->dev);
- vpb_disable_event(p->handle, VPB_MDROP);
- }
-
- if (ast->_state != AST_STATE_UP) {
- if (p->mode == MODE_FXO) {
- vpb_sethook_sync(p->handle, VPB_OFFHOOK);
- p->state = VPB_STATE_OFFHOOK;
-/* vpb_sleep(500);
- ret = vpb_get_event_ch_async(p->handle, &je);
- if ((ret == VPB_OK) && ((je.type != VPB_DROP)&&(je.type != VPB_RING))){
- ast_verb(4, "%s: Answer collected a wrong event!!\n", p->dev);
- vpb_put_event(&je);
- }
-*/
- }
- ast_setstate(ast, AST_STATE_UP);
-
- ast_verb(2, "%s: Answered call on %s [%s]\n", p->dev,
- ast->name, (p->mode == MODE_FXO) ? "FXO" : "FXS");
-
- ast->rings = 0;
- if (!p->readthread) {
- /* res = ast_mutex_unlock(&p->lock); */
- /* ast_verbose("%s: unLOCKING in answer [%d]\n", p->dev,res); */
- ast_pthread_create(&p->readthread, NULL, do_chanreads, (void *)p);
- } else {
- ast_verb(4, "%s: Record thread already running!!\n", p->dev);
- }
- } else {
- ast_verb(4, "%s: Answered state is up\n", p->dev);
- /* res = ast_mutex_unlock(&p->lock); */
- /* ast_verbose("%s: unLOCKING in answer [%d]\n", p->dev,res); */
- }
- vpb_sleep(500);
- if (p->mode == MODE_FXO) {
- ast_verb(4, "%s: Re-enabling Loop Drop detection\n", p->dev);
- vpb_enable_event(p->handle, VPB_MDROP);
- }
- res = ast_mutex_unlock(&p->lock);
-/*
- ast_verb(4, "%s: unLOCKING in answer [%d]\n", p->dev,res);
-*/
- return 0;
-}
-
-static struct ast_frame *vpb_read(struct ast_channel *ast)
-{
- struct vpb_pvt *p = (struct vpb_pvt *)ast->tech_pvt;
- static struct ast_frame f = { AST_FRAME_NULL };
-
- f.src = "vpb";
- ast_log(LOG_NOTICE, "%s: vpb_read: should never be called!\n", p->dev);
- ast_verbose("%s: vpb_read: should never be called!\n", p->dev);
-
- return &f;
-}
-
-static inline AudioCompress ast2vpbformat(int ast_format)
-{
- switch (ast_format) {
- case AST_FORMAT_ALAW:
- return VPB_ALAW;
- case AST_FORMAT_SLINEAR:
- return VPB_LINEAR;
- case AST_FORMAT_ULAW:
- return VPB_MULAW;
- case AST_FORMAT_ADPCM:
- return VPB_OKIADPCM;
- default:
- return VPB_RAW;
- }
-}
-
-static inline const char * ast2vpbformatname(int ast_format)
-{
- switch(ast_format) {
- case AST_FORMAT_ALAW:
- return "AST_FORMAT_ALAW:VPB_ALAW";
- case AST_FORMAT_SLINEAR:
- return "AST_FORMAT_SLINEAR:VPB_LINEAR";
- case AST_FORMAT_ULAW:
- return "AST_FORMAT_ULAW:VPB_MULAW";
- case AST_FORMAT_ADPCM:
- return "AST_FORMAT_ADPCM:VPB_OKIADPCM";
- default:
- return "UNKN:UNKN";
- }
-}
-
-static inline int astformatbits(int ast_format)
-{
- switch (ast_format) {
- case AST_FORMAT_SLINEAR:
- return 16;
- case AST_FORMAT_ADPCM:
- return 4;
- case AST_FORMAT_ALAW:
- case AST_FORMAT_ULAW:
- default:
- return 8;
- }
-}
-
-int a_gain_vector(float g, short *v, int n)
-{
- int i;
- float tmp;
- for (i = 0; i < n; i++) {
- tmp = g * v[i];
- if (tmp > 32767.0)
- tmp = 32767.0;
- if (tmp < -32768.0)
- tmp = -32768.0;
- v[i] = (short)tmp;
- }
- return i;
-}
-
-/* Writes a frame of voice data to a VPB channel */
-static int vpb_write(struct ast_channel *ast, struct ast_frame *frame)
-{
- struct vpb_pvt *p = (struct vpb_pvt *)ast->tech_pvt;
- int res = 0;
- AudioCompress fmt = VPB_RAW;
- struct timeval play_buf_time_start;
- int tdiff;
-
-/* ast_mutex_lock(&p->lock); */
- ast_verb(6, "%s: vpb_write: Writing to channel\n", p->dev);
-
- if (frame->frametype != AST_FRAME_VOICE) {
- ast_verb(4, "%s: vpb_write: Don't know how to handle from type %d\n", ast->name, frame->frametype);
-/* ast_mutex_unlock(&p->lock); */
- return 0;
- } else if (ast->_state != AST_STATE_UP) {
- ast_verb(4, "%s: vpb_write: Attempt to Write frame type[%d]subclass[%d] on not up chan(state[%d])\n",ast->name, frame->frametype, frame->subclass,ast->_state);
- p->lastoutput = -1;
-/* ast_mutex_unlock(&p->lock); */
- return 0;
- }
-/* ast_debug(1, "%s: vpb_write: Checked frame type..\n", p->dev); */
-
-
- fmt = ast2vpbformat(frame->subclass);
- if (fmt < 0) {
- ast_log(LOG_WARNING, "%s: vpb_write: Cannot handle frames of %d format!\n", ast->name, frame->subclass);
- return -1;
- }
-
- tdiff = ast_tvdiff_ms(ast_tvnow(), p->lastplay);
- ast_debug(1, "%s: vpb_write: time since last play(%d) \n", p->dev, tdiff);
- if (tdiff < (VPB_SAMPLES / 8 - 1)) {
- ast_debug(1, "%s: vpb_write: Asked to play too often (%d) (%d)\n", p->dev, tdiff, frame->datalen);
-/* return 0; */
- }
- p->lastplay = ast_tvnow();
-/*
- ast_debug(1, "%s: vpb_write: Checked frame format..\n", p->dev);
-*/
-
- ast_mutex_lock(&p->play_lock);
-
-/*
- ast_debug(1, "%s: vpb_write: Got play lock..\n", p->dev);
-*/
-
- /* Check if we have set up the play_buf */
- if (p->lastoutput == -1) {
- vpb_play_buf_start(p->handle, fmt);
- ast_verb(2, "%s: vpb_write: Starting play mode (codec=%d)[%s]\n", p->dev, fmt, ast2vpbformatname(frame->subclass));
- p->lastoutput = fmt;
- ast_mutex_unlock(&p->play_lock);
- return 0;
- } else if (p->lastoutput != fmt) {
- vpb_play_buf_finish(p->handle);
- vpb_play_buf_start(p->handle, fmt);
- ast_verb(2, "%s: vpb_write: Changed play format (%d=>%d)\n", p->dev, p->lastoutput, fmt);
- ast_mutex_unlock(&p->play_lock);
- return 0;
- }
- p->lastoutput = fmt;
-
-
-
- /* Apply extra gain ! */
- if( p->txswgain > MAX_VPB_GAIN )
- a_gain_vector(p->txswgain - MAX_VPB_GAIN , (short*)frame->data, frame->datalen / sizeof(short));
-
-/* ast_debug(1, "%s: vpb_write: Applied gain..\n", p->dev); */
-/* ast_debug(1, "%s: vpb_write: play_buf_time %d\n", p->dev, p->play_buf_time); */
-
- if ((p->read_state == 1) && (p->play_buf_time < 5)){
- play_buf_time_start = ast_tvnow();
-/* res = vpb_play_buf_sync(p->handle, (char *)frame->data, tdiff * 8 * 2); */
- res = vpb_play_buf_sync(p->handle, (char *)frame->data, frame->datalen);
- if(res == VPB_OK) {
- short * data = (short*)frame->data;
- ast_verb(6, "%s: vpb_write: Wrote chan (codec=%d) %d %d\n", p->dev, fmt, data[0], data[1]);
- }
- p->play_buf_time = ast_tvdiff_ms(ast_tvnow(), play_buf_time_start);
- } else {
- p->chuck_count++;
- ast_debug(1, "%s: vpb_write: Tossed data away, tooooo much data!![%d]\n", p->dev, p->chuck_count);
- p->play_buf_time = 0;
- }
-
- ast_mutex_unlock(&p->play_lock);
-/* ast_mutex_unlock(&p->lock); */
- ast_verb(6, "%s: vpb_write: Done Writing to channel\n", p->dev);
- return 0;
-}
-
-/* Read monitor thread function. */
-static void *do_chanreads(void *pvt)
-{
- struct vpb_pvt *p = (struct vpb_pvt *)pvt;
- struct ast_frame *fr = &p->fr;
- char *readbuf = ((char *)p->buf) + AST_FRIENDLY_OFFSET;
- int bridgerec = 0;
- int afmt, readlen, res, trycnt=0;
- AudioCompress fmt;
- int ignore_dtmf;
- const char * getdtmf_var = NULL;
-
- fr->frametype = AST_FRAME_VOICE;
- fr->src = "vpb";
- fr->mallocd = 0;
- fr->delivery.tv_sec = 0;
- fr->delivery.tv_usec = 0;
- fr->samples = VPB_SAMPLES;
- fr->offset = AST_FRIENDLY_OFFSET;
- memset(p->buf, 0, sizeof p->buf);
-
- ast_verb(3, "%s: chanreads: starting thread\n", p->dev);
- ast_mutex_lock(&p->record_lock);
-
- p->stopreads = 0;
- p->read_state = 1;
- while (!p->stopreads && p->owner) {
-
- ast_verb(5, "%s: chanreads: Starting cycle ...\n", p->dev);
- ast_verb(5, "%s: chanreads: Checking bridge \n", p->dev);
- if (p->bridge) {
- if (p->bridge->c0 == p->owner && (p->bridge->flags & AST_BRIDGE_REC_CHANNEL_0))
- bridgerec = 1;
- else if (p->bridge->c1 == p->owner && (p->bridge->flags & AST_BRIDGE_REC_CHANNEL_1))
- bridgerec = 1;
- else
- bridgerec = 0;
- } else {
- ast_verb(5, "%s: chanreads: No native bridge.\n", p->dev);
- if (p->owner->_bridge) {
- ast_verb(5, "%s: chanreads: Got Asterisk bridge with [%s].\n", p->dev, p->owner->_bridge->name);
- bridgerec = 1;
- } else {
- bridgerec = 0;
- }
- }
-
-/* if ((p->owner->_state != AST_STATE_UP) || !bridgerec) */
- if ((p->owner->_state != AST_STATE_UP)) {
- if (p->owner->_state != AST_STATE_UP) {
- ast_verb(5, "%s: chanreads: Im not up[%d]\n", p->dev, p->owner->_state);
- } else {
- ast_verb(5, "%s: chanreads: No bridgerec[%d]\n", p->dev, bridgerec);
- }
- vpb_sleep(10);
- continue;
- }
-
- /* Voicetronix DTMF detection can be triggered off ordinary speech
- * This leads to annoying beeps during the conversation
- * Avoid this problem by just setting VPB_GETDTMF when you want to listen for DTMF
- */
- /* ignore_dtmf = 1; */
- ignore_dtmf = 0; /* set this to 1 to turn this feature on */
- getdtmf_var = pbx_builtin_getvar_helper(p->owner, "VPB_GETDTMF");
- if (getdtmf_var && strcasecmp(getdtmf_var, "yes") == 0)
- ignore_dtmf = 0;
-
- if ((ignore_dtmf != p->last_ignore_dtmf) && (!use_ast_dtmfdet)){
- ast_verb(2, "%s:Now %s DTMF \n",
- p->dev, ignore_dtmf ? "ignoring" : "listening for");
- vpb_set_event_mask(p->handle, ignore_dtmf ? VPB_EVENTS_NODTMF : VPB_EVENTS_ALL );
- }
- p->last_ignore_dtmf = ignore_dtmf;
-
- /* Play DTMF digits here to avoid problem you get if playing a digit during
- * a record operation
- */
- ast_verb(6, "%s: chanreads: Checking dtmf's \n", p->dev);
- ast_mutex_lock(&p->play_dtmf_lock);
- if (p->play_dtmf[0]) {
- /* Try to ignore DTMF event we get after playing digit */
- /* This DTMF is played by asterisk and leads to an annoying trailing beep on CISCO phones */
- if (!ignore_dtmf) {
- vpb_set_event_mask(p->handle, VPB_EVENTS_NODTMF );
- }
- if (p->bridge == NULL) {
- vpb_dial_sync(p->handle, p->play_dtmf);
- ast_verb(2, "%s: chanreads: Played DTMF %s\n", p->dev, p->play_dtmf);
- } else {
- ast_verb(2, "%s: chanreads: Not playing DTMF frame on native bridge\n", p->dev);
- }
- p->play_dtmf[0] = '\0';
- ast_mutex_unlock(&p->play_dtmf_lock);
- vpb_sleep(700); /* Long enough to miss echo and DTMF event */
- if( !ignore_dtmf)
- vpb_set_event_mask(p->handle, VPB_EVENTS_ALL);
- continue;
- }
- ast_mutex_unlock(&p->play_dtmf_lock);
-
-/* afmt = (p->owner) ? p->owner->rawreadformat : AST_FORMAT_SLINEAR; */
- if (p->owner) {
- afmt = p->owner->rawreadformat;
-/* ast_debug(1,"%s: Record using owner format [%s]\n", p->dev, ast2vpbformatname(afmt)); */
- } else {
- afmt = AST_FORMAT_SLINEAR;
-/* ast_debug(1,"%s: Record using default format [%s]\n", p->dev, ast2vpbformatname(afmt)); */
- }
- fmt = ast2vpbformat(afmt);
- if (fmt < 0) {
- ast_log(LOG_WARNING, "%s: Record failure (unsupported format %d)\n", p->dev, afmt);
- return NULL;
- }
- readlen = VPB_SAMPLES * astformatbits(afmt) / 8;
-
- if (p->lastinput == -1) {
- vpb_record_buf_start(p->handle, fmt);
-/* vpb_reset_record_fifo_alarm(p->handle); */
- p->lastinput = fmt;
- ast_verb(2, "%s: Starting record mode (codec=%d)[%s]\n", p->dev, fmt, ast2vpbformatname(afmt));
- continue;
- } else if (p->lastinput != fmt) {
- vpb_record_buf_finish(p->handle);
- vpb_record_buf_start(p->handle, fmt);
- p->lastinput = fmt;
- ast_verb(2, "%s: Changed record format (%d=>%d)\n", p->dev, p->lastinput, fmt);
- continue;
- }
-
- /* Read only if up and not bridged, or a bridge for which we can read. */
- ast_verb(6, "%s: chanreads: getting buffer!\n", p->dev);
- if( (res = vpb_record_buf_sync(p->handle, readbuf, readlen) ) == VPB_OK ) {
- ast_verb(6, "%s: chanreads: got buffer!\n", p->dev);
- /* Apply extra gain ! */
- if( p->rxswgain > MAX_VPB_GAIN )
- a_gain_vector(p->rxswgain - MAX_VPB_GAIN, (short *)readbuf, readlen / sizeof(short));
- ast_verb(6, "%s: chanreads: applied gain\n", p->dev);
-
- fr->subclass = afmt;
- fr->data = readbuf;
- fr->datalen = readlen;
- fr->frametype = AST_FRAME_VOICE;
-
- if ((use_ast_dtmfdet)&&(p->vad)) {
- fr = ast_dsp_process(p->owner,p->vad,fr);
- if (fr && (fr->frametype == AST_FRAME_DTMF)) {
- ast_debug(1, "%s: chanreads: Detected DTMF '%c'\n", p->dev, fr->subclass);
- } else if (fr->subclass == 'f') {
- }
- }
- /* Using trylock here to prevent deadlock when channel is hungup
- * (ast_hangup() immediately gets lock)
- */
- if (p->owner && !p->stopreads) {
- ast_verb(6, "%s: chanreads: queueing buffer on read frame q (state[%d])\n", p->dev, p->owner->_state);
- do {
- res = ast_channel_trylock(p->owner);
- trycnt++;
- } while ((res !=0 ) && (trycnt < 300));
- if (res == 0) {
- ast_queue_frame(p->owner, fr);
- ast_channel_unlock(p->owner);
- } else {
- ast_verb(5, "%s: chanreads: Couldnt get lock after %d tries!\n", p->dev, trycnt);
- }
- trycnt = 0;
-
-/*
- res = ast_mutex_trylock(&p->owner->lock);
- if (res == 0) {
- ast_queue_frame(p->owner, fr);
- ast_mutex_unlock(&p->owner->lock);
- } else {
- if (res == EINVAL)
- ast_verb(5, "%s: chanreads: try owner->lock gave me EINVAL[%d]\n", p->dev, res);
- else if (res == EBUSY)
- ast_verb(5, "%s: chanreads: try owner->lock gave me EBUSY[%d]\n", p->dev, res);
- while (res != 0) {
- res = ast_mutex_trylock(&p->owner->lock);
- }
- if (res == 0) {
- ast_queue_frame(p->owner, fr);
- ast_mutex_unlock(&p->owner->lock);
- } else {
- if (res == EINVAL) {
- ast_verb(5, "%s: chanreads: try owner->lock gave me EINVAL[%d]\n", p->dev, res);
- } else if (res == EBUSY) {
- ast_verb(5, "%s: chanreads: try owner->lock gave me EBUSY[%d]\n", p->dev, res);
- }
- ast_verb(5, "%s: chanreads: Couldnt get lock on owner[%s][%d][%d] channel to send frame!\n", p->dev, p->owner->name, (int)p->owner->lock.__m_owner, (int)p->owner->lock.__m_count);
- }
- }
-*/
- short *data = (short *)readbuf;
- ast_verb(7, "%s: Read channel (codec=%d) %d %d\n", p->dev, fmt, data[0], data[1]);
- } else {
- ast_verb(5, "%s: p->stopreads[%d] p->owner[%p]\n", p->dev, p->stopreads, (void *)p->owner);
- }
- }
- ast_verb(5, "%s: chanreads: Finished cycle...\n", p->dev);
- }
- p->read_state = 0;
-
- /* When stopreads seen, go away! */
- vpb_record_buf_finish(p->handle);
- p->read_state = 0;
- ast_mutex_unlock(&p->record_lock);
-
- ast_verb(2, "%s: Ending record mode (%d/%s)\n",
- p->dev, p->stopreads, p->owner ? "yes" : "no");
- return NULL;
-}
-
-static struct ast_channel *vpb_new(struct vpb_pvt *me, enum ast_channel_state state, const char *context)
-{
- struct ast_channel *tmp;
- char cid_num[256];
- char cid_name[256];
-
- if (me->owner) {
- ast_log(LOG_WARNING, "Called vpb_new on owned channel (%s) ?!\n", me->dev);
- return NULL;
- }
- ast_verb(4, "%s: New call for context [%s]\n", me->dev, context);
-
- tmp = ast_channel_alloc(1, state, 0, 0, "", me->ext, me->context, 0, "%s", me->dev);
- if (tmp) {
- if (use_ast_ind == 1){
- tmp->tech = &vpb_tech_indicate;
- } else {
- tmp->tech = &vpb_tech;
- }
-
- tmp->callgroup = me->callgroup;
- tmp->pickupgroup = me->pickupgroup;
-
- /* Linear is the preferred format. Although Voicetronix supports other formats
- * they are all converted to/from linear in the vpb code. Best for us to use
- * linear since we can then adjust volume in this modules.
- */
- tmp->nativeformats = prefformat;
- tmp->rawreadformat = AST_FORMAT_SLINEAR;
- tmp->rawwriteformat = AST_FORMAT_SLINEAR;
- if (state == AST_STATE_RING) {
- tmp->rings = 1;
- cid_name[0] = '\0';
- cid_num[0] = '\0';
- ast_callerid_split(me->callerid, cid_name, sizeof(cid_name), cid_num, sizeof(cid_num));
- ast_set_callerid(tmp, cid_num, cid_name, cid_num);
- }
- tmp->tech_pvt = me;
-
- ast_copy_string(tmp->context, context, sizeof(tmp->context));
- if (!ast_strlen_zero(me->ext))
- ast_copy_string(tmp->exten, me->ext, sizeof(tmp->exten));
- else
- strcpy(tmp->exten, "s");
- if (!ast_strlen_zero(me->language))
- ast_string_field_set(tmp, language, me->language);
-
- me->owner = tmp;
-
- me->bridge = NULL;
- me->lastoutput = -1;
- me->lastinput = -1;
- me->last_ignore_dtmf = 1;
- me->readthread = 0;
- me->play_dtmf[0] = '\0';
- me->faxhandled = 0;
-
- me->lastgrunt = ast_tvnow(); /* Assume at least one grunt tone seen now. */
- me->lastplay = ast_tvnow(); /* Assume at least one grunt tone seen now. */
-
- if (state != AST_STATE_DOWN) {
- if ((me->mode != MODE_FXO) && (state != AST_STATE_UP)) {
- vpb_answer(tmp);
- }
- if (ast_pbx_start(tmp)) {
- ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
- ast_hangup(tmp);
- }
- }
- } else {
- ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
- }
- return tmp;
-}
-
-static struct ast_channel *vpb_request(const char *type, int format, void *vdata, int *cause)
-{
- int oldformat;
- struct vpb_pvt *p;
- struct ast_channel *tmp = NULL;
- char *sepstr, *data = (char *)vdata, *name;
- const char *s;
- int group = -1;
-
- oldformat = format;
- format &= prefformat;
- if (!format) {
- ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", oldformat);
- return NULL;
- }
-
- name = ast_strdup(S_OR(data, ""));
-
- sepstr = name;
- s = strsep(&sepstr, "/"); /* Handle / issues */
- if (!s)
- s = "";
- /* Check if we are looking for a group */
- if (toupper(name[0]) == 'G' || toupper(name[0]) == 'R') {
- group = atoi(name + 1);
- }
- /* Search for an unowned channel */
- ast_mutex_lock(&iflock);
- for (p = iflist; p; p = p->next) {
- if (group == -1) {
- if (strncmp(s, p->dev + 4, sizeof p->dev) == 0) {
- if (!p->owner) {
- tmp = vpb_new(p, AST_STATE_DOWN, p->context);
- break;
- }
- }
- } else {
- if ((p->group == group) && (!p->owner)) {
- tmp = vpb_new(p, AST_STATE_DOWN, p->context);
- break;
- }
- }
- }
- ast_mutex_unlock(&iflock);
-
-
- ast_verb(2, " %s requested, got: [%s]\n", name, tmp ? tmp->name : "None");
-
- ast_free(name);
-
- restart_monitor();
- return tmp;
-}
-
-static float parse_gain_value(const char *gain_type, const char *value)
-{
- float gain;
-
- /* try to scan number */
- if (sscanf(value, "%f", &gain) != 1) {
- ast_log(LOG_ERROR, "Invalid %s value '%s' in '%s' config\n", value, gain_type, config);
- return DEFAULT_GAIN;
- }
-
-
- /* percentage? */
- /*if (value[strlen(value) - 1] == '%') */
- /* return gain / (float)100; */
-
- return gain;
-}
-
-
-static int unload_module(void)
-{
- struct vpb_pvt *p;
- /* First, take us out of the channel loop */
- if (use_ast_ind == 1){
- ast_channel_unregister(&vpb_tech_indicate);
- } else {
- ast_channel_unregister(&vpb_tech);
- }
-
- ast_mutex_lock(&iflock);
- /* Hangup all interfaces if they have an owner */
- for (p = iflist; p; p = p->next) {
- if (p->owner)
- ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
- }
- iflist = NULL;
- ast_mutex_unlock(&iflock);
-
- ast_mutex_lock(&monlock);
- if (mthreadactive > -1) {
- pthread_cancel(monitor_thread);
- pthread_join(monitor_thread, NULL);
- }
- mthreadactive = -2;
- ast_mutex_unlock(&monlock);
-
- ast_mutex_lock(&iflock);
- /* Destroy all the interfaces and free their memory */
-
- while (iflist) {
- p = iflist;
- ast_mutex_destroy(&p->lock);
- pthread_cancel(p->readthread);
- ast_mutex_destroy(&p->owner_lock);
- ast_mutex_destroy(&p->record_lock);
- ast_mutex_destroy(&p->play_lock);
- ast_mutex_destroy(&p->play_dtmf_lock);
- p->readthread = 0;
-
- vpb_close(p->handle);
-
- iflist = iflist->next;
-
- ast_free(p);
- }
- iflist = NULL;
- ast_mutex_unlock(&iflock);
-
- if (bridges) {
- ast_mutex_lock(&bridge_lock);
- memset(bridges, 0, sizeof bridges);
- ast_mutex_unlock(&bridge_lock);
- ast_mutex_destroy(&bridge_lock);
- for (int i = 0; i < max_bridges; i++) {
- ast_mutex_destroy(&bridges[i].lock);
- ast_cond_destroy(&bridges[i].cond);
- }
- ast_free(bridges);
- }
-
- return 0;
-}
-
-static enum ast_module_load_result load_module()
-{
- struct ast_config *cfg;
- struct ast_variable *v;
- struct vpb_pvt *tmp;
- int board = 0, group = 0;
- ast_group_t callgroup = 0;
- ast_group_t pickupgroup = 0;
- int mode = MODE_IMMEDIATE;
- float txgain = DEFAULT_GAIN, rxgain = DEFAULT_GAIN;
- float txswgain = 0, rxswgain = 0;
- int got_gain=0;
- int first_channel = 1;
- int echo_cancel = DEFAULT_ECHO_CANCEL;
- enum ast_module_load_result error = AST_MODULE_LOAD_SUCCESS; /* Error flag */
- int bal1 = -1; /* Special value - means do not set */
- int bal2 = -1;
- int bal3 = -1;
- char * callerid = NULL;
-
- int num_cards = 0;
- try {
- num_cards = vpb_get_num_cards();
- } catch (VpbException e) {
- ast_log(LOG_ERROR, "No Voicetronix cards detected\n");
- return AST_MODULE_LOAD_DECLINE;
- }
-
- int ports_per_card[num_cards];
- for (int i = 0; i < num_cards; ++i)
- ports_per_card[i] = vpb_get_ports_per_card(i);
-
- cfg = ast_config_load(config);
-
- /* We *must* have a config file otherwise stop immediately */
- if (!cfg) {
- ast_log(LOG_ERROR, "Unable to load config %s\n", config);
- return AST_MODULE_LOAD_DECLINE;
- }
-
- ast_mutex_lock(&iflock);
- v = ast_variable_browse(cfg, "general");
- while (v){
- if (strcasecmp(v->name, "cards") == 0) {
- ast_log(LOG_NOTICE, "VPB Driver configured to use [%d] cards\n", atoi(v->value));
- } else if (strcasecmp(v->name, "indication") == 0) {
- use_ast_ind = 1;
- ast_log(LOG_NOTICE, "VPB driver using Asterisk Indication functions!\n");
- } else if (strcasecmp(v->name, "break-for-dtmf") == 0) {
- if (ast_true(v->value)) {
- break_for_dtmf = 1;
- } else {
- break_for_dtmf = 0;
- ast_log(LOG_NOTICE, "VPB driver not stopping for DTMF's in native bridge\n");
- }
- } else if (strcasecmp(v->name, "ast-dtmf") == 0) {
- use_ast_dtmf = 1;
- ast_log(LOG_NOTICE, "VPB driver using Asterisk DTMF play functions!\n");
- } else if (strcasecmp(v->name, "ast-dtmf-det") == 0) {
- use_ast_dtmfdet = 1;
- ast_log(LOG_NOTICE, "VPB driver using Asterisk DTMF detection functions!\n");
- } else if (strcasecmp(v->name, "relaxdtmf") == 0) {
- relaxdtmf = 1;
- ast_log(LOG_NOTICE, "VPB driver using Relaxed DTMF with Asterisk DTMF detections functions!\n");
- } else if (strcasecmp(v->name, "timer_period_ring") == 0) {
- timer_period_ring = atoi(v->value);
- } else if (strcasecmp(v->name, "ecsuppthres") == 0) {
- ec_supp_threshold = (short)atoi(v->value);
- } else if (strcasecmp(v->name, "dtmfidd") == 0) {
- dtmf_idd = atoi(v->value);
- ast_log(LOG_NOTICE, "VPB Driver setting DTMF IDD to [%d]ms\n", dtmf_idd);
- }
- v = v->next;
- }
-
- v = ast_variable_browse(cfg, "interfaces");
- while (v) {
- /* Create the interface list */
- if (strcasecmp(v->name, "board") == 0) {
- board = atoi(v->value);
- } else if (strcasecmp(v->name, "group") == 0) {
- group = atoi(v->value);
- } else if (strcasecmp(v->name, "callgroup") == 0) {
- callgroup = ast_get_group(v->value);
- } else if (strcasecmp(v->name, "pickupgroup") == 0) {
- pickupgroup = ast_get_group(v->value);
- } else if (strcasecmp(v->name, "usepolaritycid") == 0) {
- UsePolarityCID = atoi(v->value);
- } else if (strcasecmp(v->name, "useloopdrop") == 0) {
- UseLoopDrop = atoi(v->value);
- } else if (strcasecmp(v->name, "usenativebridge") == 0) {
- UseNativeBridge = atoi(v->value);
- } else if (strcasecmp(v->name, "channel") == 0) {
- int channel = atoi(v->value);
- if (board >= num_cards || board < 0 || channel < 0 || channel >= ports_per_card[board]) {
- ast_log(LOG_ERROR, "Invalid board/channel (%d/%d) for channel '%s'\n", board, channel, v->value);
- error = AST_MODULE_LOAD_FAILURE;
- goto done;
- }
- tmp = mkif(board, channel, mode, got_gain, txgain, rxgain, txswgain, rxswgain, bal1, bal2, bal3, callerid, echo_cancel,group,callgroup,pickupgroup);
- if (tmp) {
- if (first_channel) {
- mkbrd(tmp->vpb_model, echo_cancel);
- first_channel = 0;
- }
- tmp->next = iflist;
- iflist = tmp;
- } else {
- ast_log(LOG_ERROR, "Unable to register channel '%s'\n", v->value);
- error = AST_MODULE_LOAD_FAILURE;
- goto done;
- }
- } else if (strcasecmp(v->name, "language") == 0) {
- ast_copy_string(language, v->value, sizeof(language));
- } else if (strcasecmp(v->name, "callerid") == 0) {
- callerid = ast_strdup(v->value);
- } else if (strcasecmp(v->name, "mode") == 0) {
- if (strncasecmp(v->value, "di", 2) == 0) {
- mode = MODE_DIALTONE;
- } else if (strncasecmp(v->value, "im", 2) == 0) {
- mode = MODE_IMMEDIATE;
- } else if (strncasecmp(v->value, "fx", 2) == 0) {
- mode = MODE_FXO;
- } else {
- ast_log(LOG_WARNING, "Unknown mode: %s\n", v->value);
- }
- } else if (!strcasecmp(v->name, "context")) {
- ast_copy_string(context, v->value, sizeof(context));
- } else if (!strcasecmp(v->name, "echocancel")) {
- if (!strcasecmp(v->value, "off")) {
- echo_cancel = 0;
- }
- } else if (strcasecmp(v->name, "txgain") == 0) {
- txswgain = parse_gain_value(v->name, v->value);
- got_gain |= VPB_GOT_TXSWG;
- } else if (strcasecmp(v->name, "rxgain") == 0) {
- rxswgain = parse_gain_value(v->name, v->value);
- got_gain |= VPB_GOT_RXSWG;
- } else if (strcasecmp(v->name, "txhwgain") == 0) {
- txgain = parse_gain_value(v->name, v->value);
- got_gain |= VPB_GOT_TXHWG;
- } else if (strcasecmp(v->name, "rxhwgain") == 0) {
- rxgain = parse_gain_value(v->name, v->value);
- got_gain |= VPB_GOT_RXHWG;
- } else if (strcasecmp(v->name, "bal1") == 0) {
- bal1 = strtol(v->value, NULL, 16);
- if (bal1 < 0 || bal1 > 255) {
- ast_log(LOG_WARNING, "Bad bal1 value: %d\n", bal1);
- bal1 = -1;
- }
- } else if (strcasecmp(v->name, "bal2") == 0) {
- bal2 = strtol(v->value, NULL, 16);
- if (bal2 < 0 || bal2 > 255) {
- ast_log(LOG_WARNING, "Bad bal2 value: %d\n", bal2);
- bal2 = -1;
- }
- } else if (strcasecmp(v->name, "bal3") == 0) {
- bal3 = strtol(v->value, NULL, 16);
- if (bal3 < 0 || bal3 > 255) {
- ast_log(LOG_WARNING, "Bad bal3 value: %d\n", bal3);
- bal3 = -1;
- }
- } else if (strcasecmp(v->name, "grunttimeout") == 0) {
- gruntdetect_timeout = 1000 * atoi(v->value);
- }
- v = v->next;
- }
-
- if (gruntdetect_timeout < 1000)
- gruntdetect_timeout = 1000;
-
- done: (void)0;
- ast_mutex_unlock(&iflock);
-
- ast_config_destroy(cfg);
-
- if (use_ast_ind == 1) {
- if (error == AST_MODULE_LOAD_SUCCESS && ast_channel_register(&vpb_tech_indicate) != 0) {
- ast_log(LOG_ERROR, "Unable to register channel class 'vpb'\n");
- error = AST_MODULE_LOAD_FAILURE;
- } else {
- ast_log(LOG_NOTICE, "VPB driver Registered (w/AstIndication)\n");
- }
- } else {
- if (error == AST_MODULE_LOAD_SUCCESS && ast_channel_register(&vpb_tech) != 0) {
- ast_log(LOG_ERROR, "Unable to register channel class 'vpb'\n");
- error = AST_MODULE_LOAD_FAILURE;
- } else {
- ast_log(LOG_NOTICE, "VPB driver Registered )\n");
- }
- }
-
-
- if (error != AST_MODULE_LOAD_SUCCESS)
- unload_module();
- else
- restart_monitor(); /* And start the monitor for the first time */
-
- return error;
-}
-
-/**/
-#if defined(__cplusplus) || defined(c_plusplus)
- }
-#endif
-/**/
-
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Voicetronix API driver");
diff --git a/1.4.23-rc4/channels/gentone-ulaw.c b/1.4.23-rc4/channels/gentone-ulaw.c
deleted file mode 100644
index b290d76c7..000000000
--- a/1.4.23-rc4/channels/gentone-ulaw.c
+++ /dev/null
@@ -1,157 +0,0 @@
-/* Generate a header file for a particular
- single or double frequency */
-
-#include <stdio.h>
-#include <math.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdlib.h>
-#define CLIP 32635
-#define BIAS 0x84
-static float loudness=16384.0;
-
-static int calc_samples(int freq)
-{
- int x, samples;
- /* Calculate the number of samples at 8000hz sampling
- we need to have this wave form */
- samples = 8000;
- /* Take out common 2's up to six times */
- for (x=0;x<6;x++)
- if (!(freq % 2)) {
- freq /= 2;
- samples /= 2;
- }
- /* Take out common 5's (up to three times */
- for (x=0;x<3;x++)
- if (!(freq % 5)) {
- freq /= 5;
- samples /=5;
- }
- /* No more common factors. */
- return samples;
-}
-
-/*
-** This routine converts from linear to ulaw
-**
-** Craig Reese: IDA/Supercomputing Research Center
-** Joe Campbell: Department of Defense
-** 29 September 1989
-**
-** References:
-** 1) CCITT Recommendation G.711 (very difficult to follow)
-** 2) "A New Digital Technique for Implementation of Any
-** Continuous PCM Companding Law," Villeret, Michel,
-** et al. 1973 IEEE Int. Conf. on Communications, Vol 1,
-** 1973, pg. 11.12-11.17
-** 3) MIL-STD-188-113,"Interoperability and Performance Standards
-** for Analog-to_Digital Conversion Techniques,"
-** 17 February 1987
-**
-** Input: Signed 16 bit linear sample
-** Output: 8 bit ulaw sample
-*/
-
-#define ZEROTRAP /* turn on the trap as per the MIL-STD */
-#define BIAS 0x84 /* define the add-in bias for 16 bit samples */
-#define CLIP 32635
-
-static unsigned char linear2ulaw(short sample) {
-static int exp_lut[256] = {0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
- 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
- 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
- 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
- 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
- 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
- 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
- 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
- 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
- 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
- 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
- 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
- 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
- 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
- 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
- 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7};
- int sign, exponent, mantissa;
- unsigned char ulawbyte;
-
- /* Get the sample into sign-magnitude. */
- sign = (sample >> 8) & 0x80; /* set aside the sign */
- if (sign != 0) sample = -sample; /* get magnitude */
- if (sample > CLIP) sample = CLIP; /* clip the magnitude */
-
- /* Convert from 16 bit linear to ulaw. */
- sample = sample + BIAS;
- exponent = exp_lut[(sample >> 7) & 0xFF];
- mantissa = (sample >> (exponent + 3)) & 0x0F;
- ulawbyte = ~(sign | (exponent << 4) | mantissa);
-#ifdef ZEROTRAP
- if (ulawbyte == 0) ulawbyte = 0x02; /* optional CCITT trap */
-#endif
-
- return(ulawbyte);
-}
-
-int main(int argc, char *argv[])
-{
- FILE *f;
- int freq1, freq2;
- float wlen1, wlen2;
- float val;
- int x, samples1, samples2, samples=0;
- char fn[256];
- if (argc < 3) {
- fprintf(stderr, "Usage: gensound <name> <freq1> [freq2]\n");
- exit(1);
- }
- freq1 = atoi(argv[2]);
- if (argc > 3)
- freq2 = atoi(argv[3]);
- else
- freq2 = 0;
- wlen1 = 8000.0/(float)freq1;
- samples1 = calc_samples(freq1);
- printf("Wavelength 1 (in samples): %10.5f\n", wlen1);
- printf("Minimum samples (1): %d (%f.3 wavelengths)\n", samples1, samples1 / wlen1);
- if (freq2) {
- wlen2 = 8000.0/(float)freq2;
- samples2 = calc_samples(freq2);
- printf("Wavelength 1 (in samples): %10.5f\n", wlen2);
- printf("Minimum samples (1): %d (%f.3 wavelengths)\n", samples2, samples2 / wlen2);
- }
- samples = samples1;
- if (freq2) {
- while(samples % samples2)
- samples += samples1;
- }
- printf("Need %d samples\n", samples);
- snprintf(fn, sizeof(fn), "%s.h", argv[1]);
- if ((f = fopen(fn, "w"))) {
- if (freq2)
- fprintf(f, "/* %s: Generated from frequencies %d and %d \n"
- " by gentone. %d samples */\n", fn, freq1, freq2, samples);
- else
- fprintf(f, "/* %s: Generated from frequency %d\n"
- " by gentone. %d samples */\n", fn, freq1, samples);
- fprintf(f, "static unsigned char %s[%d] = {\n\t", argv[1], samples);
- for (x=0;x<samples;x++) {
- val = loudness * sin((freq1 * 2.0 * M_PI * x)/8000.0);
- if (freq2)
- val += loudness * sin((freq2 * 2.0 * M_PI * x)/8000.0);
- fprintf(f, "%3d, ", (int) linear2ulaw(val));
- if (!((x+1) % 8))
- fprintf(f, "\n\t");
- }
- if (x % 15)
- fprintf(f, "\n");
- fprintf(f, "};\n");
- fclose(f);
- printf("Wrote %s\n", fn);
- } else {
- fprintf(stderr, "Unable to open %s for writing\n", fn);
- return 1;
- }
- return 0;
-}
diff --git a/1.4.23-rc4/channels/gentone.c b/1.4.23-rc4/channels/gentone.c
deleted file mode 100644
index 29bd88e91..000000000
--- a/1.4.23-rc4/channels/gentone.c
+++ /dev/null
@@ -1,95 +0,0 @@
-/* Generate a header file for a particular
- single or double frequency */
-
-#include <stdio.h>
-#include <math.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdlib.h>
-#define CLIP 32635
-#define BIAS 0x84
-static float loudness=16384.0;
-
-static int calc_samples(int freq)
-{
- int x, samples;
- /* Calculate the number of samples at 8000hz sampling
- we need to have this wave form */
- samples = 8000;
- /* Take out common 2's up to six times */
- for (x=0;x<6;x++)
- if (!(freq % 2)) {
- freq /= 2;
- samples /= 2;
- }
- /* Take out common 5's (up to three times */
- for (x=0;x<3;x++)
- if (!(freq % 5)) {
- freq /= 5;
- samples /=5;
- }
- /* No more common factors. */
- return samples;
-}
-
-int main(int argc, char *argv[])
-{
- FILE *f;
- int freq1, freq2;
- float wlen1, wlen2;
- float val;
- int x, samples1, samples2=0, samples=0;
- char fn[256];
- if (argc < 3) {
- fprintf(stderr, "Usage: gensound <name> <freq1> [freq2]\n");
- exit(1);
- }
- freq1 = atoi(argv[2]);
- if (argc > 3)
- freq2 = atoi(argv[3]);
- else
- freq2 = 0;
- wlen1 = 8000.0/(float)freq1;
- samples1 = calc_samples(freq1);
- printf("Wavelength 1 (in samples): %10.5f\n", wlen1);
- printf("Minimum samples (1): %d (%f.3 wavelengths)\n", samples1, samples1 / wlen1);
- if (freq2) {
- wlen2 = 8000.0/(float)freq2;
- samples2 = calc_samples(freq2);
- printf("Wavelength 1 (in samples): %10.5f\n", wlen2);
- printf("Minimum samples (1): %d (%f.3 wavelengths)\n", samples2, samples2 / wlen2);
- }
- samples = samples1;
- if (freq2) {
- while(samples % samples2)
- samples += samples1;
- }
- printf("Need %d samples\n", samples);
- snprintf(fn, sizeof(fn), "%s.h", argv[1]);
- if ((f = fopen(fn, "w"))) {
- if (freq2)
- fprintf(f, "/* %s: Generated from frequencies %d and %d \n"
- " by gentone. %d samples */\n", fn, freq1, freq2, samples);
- else
- fprintf(f, "/* %s: Generated from frequency %d\n"
- " by gentone. %d samples */\n", fn, freq1, samples);
- fprintf(f, "static short %s[%d] = {\n\t", argv[1], samples);
- for (x=0;x<samples;x++) {
- val = loudness * sin((freq1 * 2.0 * M_PI * x)/8000.0);
- if (freq2)
- val += loudness * sin((freq2 * 2.0 * M_PI * x)/8000.0);
- fprintf(f, "%5d, ", (int)val);
- if (!((x+1) % 8))
- fprintf(f, "\n\t");
- }
- if (x % 15)
- fprintf(f, "\n");
- fprintf(f, "};\n");
- fclose(f);
- printf("Wrote %s\n", fn);
- } else {
- fprintf(stderr, "Unable to open %s for writing\n", fn);
- return 1;
- }
- return 0;
-}
diff --git a/1.4.23-rc4/channels/h323/ChangeLog b/1.4.23-rc4/channels/h323/ChangeLog
deleted file mode 100644
index ddbf08193..000000000
--- a/1.4.23-rc4/channels/h323/ChangeLog
+++ /dev/null
@@ -1,43 +0,0 @@
-Build
- -- Hold lock when creating new H.323 channel to sync the audio channels
- -- Decrement usage counter when appropriate
- -- Actually unregister everything in unload_module
- -- Add IP based authentication using 'host'in type=user's
-0.1.0
- -- Intergration into the mainline Asterisk codebase
- -- Remove reduandant debug info
- -- Add Caller*id support
- -- Inband DTMF
- -- Retool port usage (to avoid possible seg fault condition)
-0.0.6
- -- Configurable support for user-input (DTMF)
- -- Reworked Gatekeeper support
- -- Native bridging (but is still broken, help!)
- -- Locally implement a non-broken G.723.1 Capability
- -- Utilize the cleaner RTP method implemented by Mark
- -- AllowGkRouted, thanks to Panny from http://hotlinks.co.uk
- -- Clened up inbound call flow
- -- Prefix, E.164 and Gateway support
- -- Multi-homed support
- -- Killed more seg's
-0.0.5
- -- Added H.323 Alias support
- -- Clened up inbound call flow
- -- Fixed RTP port logic
- -- Stomped on possible seg fault conditions thanks to Iain Stevenson
-0.0.4
- -- Fixed one-way audio on inbound calls. Found
- race condition in monitor thread.
-
-0.0.3
- -- Changed name to chan_h323
- -- Also renamed file names to futher avoid confusion
-
-0.0.2
- -- First public offering
- -- removed most hardcoded values
- -- lots of changes to alias/exension operation
-
-0.0.1
- -- initial build, lots of hardcoded crap
- -- Proof of concept for External RTP
diff --git a/1.4.23-rc4/channels/h323/INSTALL.openh323 b/1.4.23-rc4/channels/h323/INSTALL.openh323
deleted file mode 100644
index f46c37905..000000000
--- a/1.4.23-rc4/channels/h323/INSTALL.openh323
+++ /dev/null
@@ -1,18 +0,0 @@
-To build Open H.323 see:
-
-http://www.openh323.org/build.html#unix
-
-You only need to do 'make opt'. Anything else you will be simply waisting time and HD space.
-Also, you will notice they never tell you to 'make install' so don't do it.
-
-
-On FreeBSD, the Makefiles are configured to
-locate the compiled openh323 port, if it has
-been built. Here is one way to build
-openh323 and ptlib on such that the Makefiles
-find it:
- # cd /usr/ports/net/openh323
- # make
-It is not necessary to install the port. The
-asterisk makefiles do not use any files
-installed by the port.
diff --git a/1.4.23-rc4/channels/h323/Makefile.in b/1.4.23-rc4/channels/h323/Makefile.in
deleted file mode 100644
index 083250f55..000000000
--- a/1.4.23-rc4/channels/h323/Makefile.in
+++ /dev/null
@@ -1,48 +0,0 @@
-#
-# Makefile
-#
-# Make file for OpenH323 support layer
-#
-
-.PHONY: Makefile.ast clean
-
-default:: @OPENH323_BUILD@
-
-# Verify those options with main Makefile
-STDCCFLAGS = -DNDEBUG
-STDCCFLAGS += -I../../include -include ../../include/asterisk/autoconfig.h
-STDCCFLAGS += -fPIC
-#OPTCCFLAGS +=
-CFLAGS = -pipe
-TARGET = libchanh323.a
-TARGET += Makefile.ast
-SOURCES = ast_h323.cxx compat_h323.cxx cisco-h225.cxx caps_h323.cxx
-OBJDIR = .
-OBJS =
-
-ifndef OPENH323DIR
-OPENH323DIR=@OPENH323DIR@
-endif
-
-include $(OPENH323DIR)/openh323u.mak
-
-notrace::
- $(MAKE) NOTRACE=1 opt
-
-$(SOURCES):: Makefile ../../Makefile
- touch $@
-
-libchanh323.a: $(OBJS)
- ar crv $@ $(OBJS)
-
-cisco-h225.cxx:: cisco-h225.asn
- asnparser -m CISCO_H225 -c $<
-
-Makefile.ast:
- @echo H323CFLAGS = $(STDCCFLAGS) $(OPTCCFLAGS) $(CFLAGS) >$@.tmp
- @echo H323LDFLAGS = $(CFLAGS) $(LDFLAGS) >>$@.tmp
- @echo H323LDLIBS = $(LDLIBS) $(ENDLDLIBS) $(ENDLDFLAGS) >>$@.tmp
- @if [ -r $@ ] && cmp -s $@ $@.tmp; then rm -f $@.tmp; else mv -f $@.tmp $@; fi
-
-clean::
- rm -f $(TARGET) $(OBJS) Makefile.ast *.dep
diff --git a/1.4.23-rc4/channels/h323/README b/1.4.23-rc4/channels/h323/README
deleted file mode 100644
index 875bf3668..000000000
--- a/1.4.23-rc4/channels/h323/README
+++ /dev/null
@@ -1,144 +0,0 @@
- Open H.323 Channel Driver for Asterisk
- By Jeremy McNamara
- For The NuFone Network
-
- First public release on November 10th, 2002
-
- Dependancies (based on OpenH323/PWLib ones):
- openssl-0.9.6b+
- openssl-devel-0.9.6b+
- expat-1.95+
- expat-dev-1.95+
-
-Tested with Open H.323 version v1.18.0, PWLib v1.10.0 and GCC v3.2.2. Usage of any
-other (especially prior OpenH323 v1.17.3 and PWLib v1.9.2) versions is not
-supported.
-
-NOTICE: Whatever you do, DO NOT USE distrubution specific installs
-of Open H.323 and PWLib. In fact, you should check to make sure
-your distro did not install them for you without your knowledge.
-
-
-To compile this code
---------------------
-Once PWLib and Open H.323 have been compiled per their specific build
-instructions, issue a make in the asterisk/channels/h323 directory with
-argument used to build PWLib and OpenH323 (for example, make opt), then go
-back to the Asterisk source top level directory and issue a make install.
-
-
-The most common compile error
-----------------------------
-If you receive ANYTHING that says 'undefined symbol' you are experiencing
-typical version skew. For example:
-
-libh323_linux_x86_r.so.1: undefined symbol: GetNumberValueAt__C14PAbstractArrayi
-
-You need to search and destroy every version of libh323 and libpt then
-completely recompile everything
-
-Example commands to make sure everything gets cleaned and then
-rebult in proper order:
-
-cd /path/to/pwlib
-./configure
-make clean opt
-cd /path/to/openh323
-./configure
-make clean opt
-cd /path/to/asterisk/channels/h323
-make opt
-cd /path/to/asterisk
-make install
-
-
-Most common run-time error
--------------------------
-libpt_linux_x86_r.so.1: cannot open shared object file: No such
-file or directory
-
-You have not set the LD_LIBRARY_PATH environment variable.
-
-Example environment for sh/bash:
-
-PWLIBDIR=$HOME/pwlib
-export PWLIBDIR
-OPENH323DIR=$HOME/openh323
-export OPENH323DIR
-LD_LIBRARY_PATH=$PWLIBDIR/lib:$OPENH323DIR/lib
-export LD_LIBRARY_PATH
-
-We recomend puting the above directives into your /etc/profile so
-you do not have to remember to export those values every time you
-want to recompile. Make sure to logout and log back in, so your
-envrionment can pick up the new variables.
-
-
-Upgrading Asterisk
------------------
-After you cvs update (or make update) Asterisk you have to go into
-asterisk/channels/h323 and issue a make clean all, before compiling the
-rest of asterisk. Doing this process every time you upgrade Asterisk
-will ensure a sane build.
-
-
-Dialing an H.323 channel
-------------------------
-Without a gatekeeper:
-exten => _1NXXNXXXXXX,1,Dial,H323/${EXTEN}@peer
-or
-exten => _1NXXNXXXXXX,1,Dial,H323/${EXTEN}@ip.or.hostname
-
-'peer' is defined in h323.conf as:
-
-[peer]
-type=peer
-host=1.2.3.4
-disallow=all
-allow=ulaw
-
-Using a gatekeeper:
-exten => _1NXXNXXXXXX,1,Dial,H323/${EXTEN}
-
-When using a gatekeeper you cannot utilize the type=peer features,
-since the H.323 spec states that when a Gatekeeper is part of an H.323 network,
-the Gatekeeper shall be used for all communication.
-
-
-Developer Contact
-----------------
-If you have trouble contact 'JerJer' in #Asterisk on
-irc.freenode.net and/or send reasonable debug information to support@nufone.net.
-
-If are lucky enough to segfault this code please run a
-backtrace and send the gory details. Segmentation faults are not
-tolerated, no matter what Distro you run (even debian)!
-
-a simple bt example:
-
-# /usr/sbin/asterisk -vvvgc
-...
-[chan_h323.so]
-Segmentation Fault (core dumped)
-
-# ls core.*
-core.1976
-
-# gdb /usr/sbin/asterisk core.1976
-...lots of useless garbage here...
-(gdb) bt
-
-Send whatever shows up right after the 'bt'
-
-Also, a full debug screen output is almost needed. Make sure you are
-in the full console mode (-c) and turn on 'h.323 debug' or worst case
-senerio 'h.323 trace 4'. A nice way to capture debug info is with
-script (man script).
-
-If you are motivated to update/fix this code please submit a
-disclaimer along with the patch to the Asterisk bug
-tracker: http://bugs.digium.com/
-
-
-Jeremy McNamara
-The NuFone Network
diff --git a/1.4.23-rc4/channels/h323/TODO b/1.4.23-rc4/channels/h323/TODO
deleted file mode 100644
index 1e114ca3b..000000000
--- a/1.4.23-rc4/channels/h323/TODO
+++ /dev/null
@@ -1,9 +0,0 @@
-The NuFone Network's Open H.323 Channel Driver for Asterisk
-
- TODO:
-
- - H.323 Native Bridging
-
- - Gatekeeping support (started)
-
- - Acutally implement the options for broken H.323 stacks
diff --git a/1.4.23-rc4/channels/h323/ast_h323.cxx b/1.4.23-rc4/channels/h323/ast_h323.cxx
deleted file mode 100644
index 32b674dec..000000000
--- a/1.4.23-rc4/channels/h323/ast_h323.cxx
+++ /dev/null
@@ -1,2487 +0,0 @@
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
-/*
- * ast_h323.cpp
- *
- * OpenH323 Channel Driver for ASTERISK PBX.
- * By Jeremy McNamara
- * For The NuFone Network
- *
- * chan_h323 has been derived from code created by
- * Michael Manousos and Mark Spencer
- *
- * This file is part of the chan_h323 driver for Asterisk
- *
- * chan_h323 is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * chan_h323 is distributed WITHOUT ANY WARRANTY; without even
- * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Version Info: $Id$
- */
-#include <arpa/inet.h>
-
-#include <list>
-#include <string>
-#include <algorithm>
-
-#include <ptlib.h>
-#include <h323.h>
-#include <h323pdu.h>
-#include <h323neg.h>
-#include <mediafmt.h>
-#include <lid.h>
-#ifdef H323_H450
-#include "h4501.h"
-#include "h4504.h"
-#include "h45011.h"
-#include "h450pdu.h"
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-#include "asterisk/logger.h"
-#include "asterisk/channel.h"
-#include "asterisk/astobj.h"
-#ifdef __cplusplus
-}
-#endif
-
-#include "chan_h323.h"
-#include "ast_h323.h"
-#include "cisco-h225.h"
-#include "caps_h323.h"
-
-#include <ptbuildopts.h>
-
-#if PWLIB_MAJOR * 10000 + PWLIB_MINOR * 100 + PWLIB_BUILD >= 1 * 10000 + 12 * 100 + 0
-#define SKIP_PWLIB_PIPE_BUG_WORKAROUND 1
-#endif
-
-/* PWlib Required Components */
-#define MAJOR_VERSION 1
-#define MINOR_VERSION 0
-#define BUILD_TYPE ReleaseCode
-#define BUILD_NUMBER 0
-
-/** Counter for the number of connections */
-static int channelsOpen;
-
-/**
- * We assume that only one endPoint should exist.
- * The application cannot run the h323_end_point_create() more than once
- * FIXME: Singleton this, for safety
- */
-static MyH323EndPoint *endPoint = NULL;
-
-/** PWLib entry point */
-static MyProcess *localProcess = NULL;
-
-#ifndef SKIP_PWLIB_PIPE_BUG_WORKAROUND
-static int _timerChangePipe[2];
-#endif
-
-static unsigned traceOptions = PTrace::Timestamp | PTrace::Thread | PTrace::FileAndLine;
-
-class PAsteriskLog : public PObject, public iostream {
- PCLASSINFO(PAsteriskLog, PObject);
-
- public:
- PAsteriskLog() : iostream(cout.rdbuf()) { init(&buffer); }
- ~PAsteriskLog() { flush(); }
-
- private:
- PAsteriskLog(const PAsteriskLog &) : iostream(cout.rdbuf()) { }
- PAsteriskLog & operator=(const PAsteriskLog &) { return *this; }
-
- class Buffer : public streambuf {
- public:
- virtual int overflow(int=EOF);
- virtual int underflow();
- virtual int sync();
- PString string;
- } buffer;
- friend class Buffer;
-};
-
-static PAsteriskLog *logstream = NULL;
-
-int PAsteriskLog::Buffer::overflow(int c)
-{
- if (pptr() >= epptr()) {
- int ppos = pptr() - pbase();
- char *newptr = string.GetPointer(string.GetSize() + 2000);
- setp(newptr, newptr + string.GetSize() - 1);
- pbump(ppos);
- }
- if (c != EOF) {
- *pptr() = (char)c;
- pbump(1);
- }
- return 0;
-}
-
-int PAsteriskLog::Buffer::underflow()
-{
- return EOF;
-}
-
-int PAsteriskLog::Buffer::sync()
-{
- char *str = strdup(string);
- char *s, *s1;
- char c;
-
- /* Pass each line with different ast_verbose() call */
- for (s = str; s && *s; s = s1) {
- s1 = strchr(s, '\n');
- if (!s1)
- s1 = s + strlen(s);
- else
- s1++;
- c = *s1;
- *s1 = '\0';
- ast_verbose("%s", s);
- *s1 = c;
- }
- free(str);
-
- string = PString();
- char *base = string.GetPointer(2000);
- setp(base, base + string.GetSize() - 1);
- return 0;
-}
-
-static ostream &my_endl(ostream &os)
-{
- if (logstream) {
- PTrace::SetOptions(traceOptions);
- return PTrace::End(os);
- }
- return endl(os);
-}
-
-#define cout \
- (logstream ? (PTrace::ClearOptions((unsigned)-1), PTrace::Begin(0, __FILE__, __LINE__)) : std::cout)
-#define endl my_endl
-
-/* Special class designed to call cleanup code on module destruction */
-class MyH323_Shutdown {
- public:
- MyH323_Shutdown() { };
- ~MyH323_Shutdown()
- {
- h323_end_process();
- };
-};
-
-MyProcess::MyProcess(): PProcess("The NuFone Networks",
- "H.323 Channel Driver for Asterisk",
- MAJOR_VERSION, MINOR_VERSION, BUILD_TYPE, BUILD_NUMBER)
-{
- /* Call shutdown when module being unload or asterisk has been stopped */
- static MyH323_Shutdown x;
-
- /* Fix missed one in PWLib */
- PX_firstTimeStart = FALSE;
- Resume();
-}
-
-MyProcess::~MyProcess()
-{
-#ifndef SKIP_PWLIB_PIPE_BUG_WORKAROUND
- _timerChangePipe[0] = timerChangePipe[0];
- _timerChangePipe[1] = timerChangePipe[1];
-#endif
-}
-
-void MyProcess::Main()
-{
- PTrace::Initialise(PTrace::GetLevel(), NULL, traceOptions);
- PTrace::SetStream(logstream);
-
- cout << " == Creating H.323 Endpoint" << endl;
- if (endPoint) {
- cout << " == ENDPOINT ALREADY CREATED" << endl;
- return;
- }
- endPoint = new MyH323EndPoint();
- /* Due to a bug in the H.323 recomendation/stack we should request a sane
- amount of bandwidth from the GK - this function is ignored if not using a GK
- We are requesting 128 (64k in each direction), which is the worst case codec. */
- endPoint->SetInitialBandwidth(1280);
-}
-
-void PAssertFunc(const char *msg)
-{
- ast_log(LOG_ERROR, "%s\n", msg);
- /* XXX: Probably we need to crash here */
-}
-
-
-/** MyH323EndPoint
- */
-MyH323EndPoint::MyH323EndPoint()
- : H323EndPoint()
-{
- /* Capabilities will be negotiated on per-connection basis */
- capabilities.RemoveAll();
-
- /* Reset call setup timeout to some more reasonable value than 1 minute */
- signallingChannelCallTimeout = PTimeInterval(0, 0, 10); /* 10 minutes */
-}
-
-/** The fullAddress parameter is used directly in the MakeCall method so
- * the General form for the fullAddress argument is :
- * [alias@][transport$]host[:port]
- * default values: alias = the same value as host.
- * transport = ip.
- * port = 1720.
- */
-int MyH323EndPoint::MyMakeCall(const PString & dest, PString & token, void *_callReference, void *_opts)
-{
- PString fullAddress;
- MyH323Connection * connection;
- H323Transport *transport = NULL;
- unsigned int *callReference = (unsigned int *)_callReference;
- call_options_t *opts = (call_options_t *)_opts;
-
- /* Determine whether we are using a gatekeeper or not. */
- if (GetGatekeeper()) {
- fullAddress = dest;
- if (h323debug) {
- cout << " -- Making call to " << fullAddress << " using gatekeeper." << endl;
- }
- } else {
- fullAddress = dest;
- if (h323debug) {
- cout << " -- Making call to " << fullAddress << " without gatekeeper." << endl;
- }
- /* Use bindaddr for outgoing calls too if we don't use gatekeeper */
- if (listeners.GetSize() > 0) {
- H323TransportAddress taddr = listeners[0].GetTransportAddress();
- PIPSocket::Address addr;
- WORD port;
- if (taddr.GetIpAndPort(addr, port)) {
- /* Create own transport for specific addresses only */
- if (addr) {
- if (h323debug)
- cout << "Using " << addr << " for outbound call" << endl;
- transport = new MyH323TransportTCP(*this, addr);
- if (!transport)
- cout << "Unable to create transport for outgoing call" << endl;
- }
- } else
- cout << "Unable to get address and port" << endl;
- }
- }
- if (!(connection = (MyH323Connection *)H323EndPoint::MakeCallLocked(fullAddress, token, opts, transport))) {
- if (h323debug) {
- cout << "Error making call to \"" << fullAddress << '"' << endl;
- }
- return 1;
- }
- *callReference = connection->GetCallReference();
-
- if (h323debug) {
- cout << "\t-- " << GetLocalUserName() << " is calling host " << fullAddress << endl;
- cout << "\t-- Call token is " << (const char *)token << endl;
- cout << "\t-- Call reference is " << *callReference << endl;
-#ifdef PTRACING
- cout << "\t-- DTMF Payload is " << connection->dtmfCodec << endl;
-#endif
- }
- connection->Unlock();
- return 0;
-}
-
-void MyH323EndPoint::SetEndpointTypeInfo( H225_EndpointType & info ) const
-{
- H323EndPoint::SetEndpointTypeInfo(info);
-
- if (terminalType == e_GatewayOnly){
- info.RemoveOptionalField(H225_EndpointType::e_terminal);
- info.IncludeOptionalField(H225_EndpointType::e_gateway);
- }
-
- info.m_gateway.IncludeOptionalField(H225_GatewayInfo::e_protocol);
- info.m_gateway.m_protocol.SetSize(1);
- H225_SupportedProtocols &protocol=info.m_gateway.m_protocol[0];
- protocol.SetTag(H225_SupportedProtocols::e_voice);
- PINDEX as=SupportedPrefixes.GetSize();
- ((H225_VoiceCaps &)protocol).m_supportedPrefixes.SetSize(as);
- for (PINDEX p=0; p<as; p++) {
- H323SetAliasAddress(SupportedPrefixes[p], ((H225_VoiceCaps &)protocol).m_supportedPrefixes[p].m_prefix, H225_AliasAddress::e_dialedDigits);
- }
-}
-
-void MyH323EndPoint::SetGateway(void)
-{
- terminalType = e_GatewayOnly;
-}
-
-BOOL MyH323EndPoint::ClearCall(const PString & token, H323Connection::CallEndReason reason)
-{
- if (h323debug) {
-#ifdef PTRACING
- cout << "\t-- ClearCall: Request to clear call with token " << token << ", cause " << reason << endl;
-#else
- cout << "\t-- ClearCall: Request to clear call with token " << token << ", cause [" << (int)reason << "]" << endl;
-#endif
- }
- return H323EndPoint::ClearCall(token, reason);
-}
-
-BOOL MyH323EndPoint::ClearCall(const PString & token)
-{
- if (h323debug) {
- cout << "\t-- ClearCall: Request to clear call with token " << token << endl;
- }
- return H323EndPoint::ClearCall(token, H323Connection::EndedByLocalUser);
-}
-
-void MyH323EndPoint::SendUserTone(const PString &token, char tone)
-{
- H323Connection *connection = NULL;
-
- connection = FindConnectionWithLock(token);
- if (connection != NULL) {
- connection->SendUserInputTone(tone, 500);
- connection->Unlock();
- }
-}
-
-void MyH323EndPoint::OnClosedLogicalChannel(H323Connection & connection, const H323Channel & channel)
-{
- channelsOpen--;
- if (h323debug) {
- cout << "\t\tchannelsOpen = " << channelsOpen << endl;
- }
- H323EndPoint::OnClosedLogicalChannel(connection, channel);
-}
-
-BOOL MyH323EndPoint::OnConnectionForwarded(H323Connection & connection,
- const PString & forwardParty,
- const H323SignalPDU & pdu)
-{
- if (h323debug) {
- cout << "\t-- Call Forwarded to " << forwardParty << endl;
- }
- return FALSE;
-}
-
-BOOL MyH323EndPoint::ForwardConnection(H323Connection & connection,
- const PString & forwardParty,
- const H323SignalPDU & pdu)
-{
- if (h323debug) {
- cout << "\t-- Forwarding call to " << forwardParty << endl;
- }
- return H323EndPoint::ForwardConnection(connection, forwardParty, pdu);
-}
-
-void MyH323EndPoint::OnConnectionEstablished(H323Connection & connection, const PString & estCallToken)
-{
- if (h323debug) {
- cout << "\t=-= In OnConnectionEstablished for call " << connection.GetCallReference() << endl;
- cout << "\t\t-- Connection Established with \"" << connection.GetRemotePartyName() << "\"" << endl;
- }
- on_connection_established(connection.GetCallReference(), (const char *)connection.GetCallToken());
-}
-
-/** OnConnectionCleared callback function is called upon the dropping of an established
- * H323 connection.
- */
-void MyH323EndPoint::OnConnectionCleared(H323Connection & connection, const PString & clearedCallToken)
-{
- PString remoteName = connection.GetRemotePartyName();
-
- switch (connection.GetCallEndReason()) {
- case H323Connection::EndedByCallForwarded:
- if (h323debug) {
- cout << "-- " << remoteName << " has forwarded the call" << endl;
- }
- break;
- case H323Connection::EndedByRemoteUser:
- if (h323debug) {
- cout << "-- " << remoteName << " has cleared the call" << endl;
- }
- break;
- case H323Connection::EndedByCallerAbort:
- if (h323debug) {
- cout << "-- " << remoteName << " has stopped calling" << endl;
- }
- break;
- case H323Connection::EndedByRefusal:
- if (h323debug) {
- cout << "-- " << remoteName << " did not accept your call" << endl;
- }
- break;
- case H323Connection::EndedByRemoteBusy:
- if (h323debug) {
- cout << "-- " << remoteName << " was busy" << endl;
- }
- break;
- case H323Connection::EndedByRemoteCongestion:
- if (h323debug) {
- cout << "-- Congested link to " << remoteName << endl;
- }
- break;
- case H323Connection::EndedByNoAnswer:
- if (h323debug) {
- cout << "-- " << remoteName << " did not answer your call" << endl;
- }
- break;
- case H323Connection::EndedByTransportFail:
- if (h323debug) {
- cout << "-- Call with " << remoteName << " ended abnormally" << endl;
- }
- break;
- case H323Connection::EndedByCapabilityExchange:
- if (h323debug) {
- cout << "-- Could not find common codec with " << remoteName << endl;
- }
- break;
- case H323Connection::EndedByNoAccept:
- if (h323debug) {
- cout << "-- Did not accept incoming call from " << remoteName << endl;
- }
- break;
- case H323Connection::EndedByAnswerDenied:
- if (h323debug) {
- cout << "-- Refused incoming call from " << remoteName << endl;
- }
- break;
- case H323Connection::EndedByNoUser:
- if (h323debug) {
- cout << "-- Remote endpoint could not find user: " << remoteName << endl;
- }
- break;
- case H323Connection::EndedByNoBandwidth:
- if (h323debug) {
- cout << "-- Call to " << remoteName << " aborted, insufficient bandwidth." << endl;
- }
- break;
- case H323Connection::EndedByUnreachable:
- if (h323debug) {
- cout << "-- " << remoteName << " could not be reached." << endl;
- }
- break;
- case H323Connection::EndedByHostOffline:
- if (h323debug) {
- cout << "-- " << remoteName << " is not online." << endl;
- }
- break;
- case H323Connection::EndedByNoEndPoint:
- if (h323debug) {
- cout << "-- No phone running for " << remoteName << endl;
- }
- break;
- case H323Connection::EndedByConnectFail:
- if (h323debug) {
- cout << "-- Transport error calling " << remoteName << endl;
- }
- break;
- default:
- if (h323debug) {
-#ifdef PTRACING
- cout << " -- Call with " << remoteName << " completed (" << connection.GetCallEndReason() << ")" << endl;
-#else
- cout << " -- Call with " << remoteName << " completed ([" << (int)connection.GetCallEndReason() << "])" << endl;
-#endif
- }
- }
-
- if (connection.IsEstablished()) {
- if (h323debug) {
- cout << "\t-- Call duration " << setprecision(0) << setw(5) << (PTime() - connection.GetConnectionStartTime()) << endl;
- }
- }
- /* Invoke the PBX application registered callback */
- on_connection_cleared(connection.GetCallReference(), clearedCallToken);
- return;
-}
-
-H323Connection * MyH323EndPoint::CreateConnection(unsigned callReference, void *userData, H323Transport *transport, H323SignalPDU *setupPDU)
-{
- unsigned options = 0;
- call_options_t *opts = (call_options_t *)userData;
- MyH323Connection *conn;
-
- if (opts && opts->fastStart) {
- options |= H323Connection::FastStartOptionEnable;
- } else {
- options |= H323Connection::FastStartOptionDisable;
- }
- if (opts && opts->h245Tunneling) {
- options |= H323Connection::H245TunnelingOptionEnable;
- } else {
- options |= H323Connection::H245TunnelingOptionDisable;
- }
-/* Disable until I can figure out the proper way to deal with this */
-#if 0
- if (opts->silenceSuppression) {
- options |= H323Connection::SilenceSuppresionOptionEnable;
- } else {
- options |= H323Connection::SilenceSUppressionOptionDisable;
- }
-#endif
- conn = new MyH323Connection(*this, callReference, options);
- if (conn) {
- if (opts)
- conn->SetCallOptions(opts, (setupPDU ? TRUE : FALSE));
- }
- return conn;
-}
-
-/* MyH323Connection Implementation */
-MyH323Connection::MyH323Connection(MyH323EndPoint & ep, unsigned callReference,
- unsigned options)
- : H323Connection(ep, callReference, options)
-{
- cause = -1;
- sessionId = 0;
- bridging = FALSE;
- progressSetup = progressAlert = 0;
- dtmfMode = 0;
- dtmfCodec = (RTP_DataFrame::PayloadTypes)0;
- redirect_reason = -1;
- transfer_capability = -1;
-#ifdef TUNNELLING
- tunnelOptions = remoteTunnelOptions = 0;
-#endif
- if (h323debug) {
- cout << " == New H.323 Connection created." << endl;
- }
- return;
-}
-
-MyH323Connection::~MyH323Connection()
-{
- if (h323debug) {
- cout << " == H.323 Connection deleted." << endl;
- }
- return;
-}
-
-BOOL MyH323Connection::OnReceivedProgress(const H323SignalPDU &pdu)
-{
- BOOL isInband;
- unsigned pi;
-
- if (!H323Connection::OnReceivedProgress(pdu)) {
- return FALSE;
- }
-
- if (!pdu.GetQ931().GetProgressIndicator(pi))
- pi = 0;
- if (h323debug) {
- cout << "\t- Progress Indicator: " << pi << endl;
- }
-
- switch(pi) {
- case Q931::ProgressNotEndToEndISDN:
- case Q931::ProgressInbandInformationAvailable:
- isInband = TRUE;
- break;
- default:
- isInband = FALSE;
- }
- on_progress(GetCallReference(), (const char *)GetCallToken(), isInband);
-
- return connectionState != ShuttingDownConnection;
-}
-
-BOOL MyH323Connection::MySendProgress()
-{
- /* The code taken from H323Connection::AnsweringCall() but ALWAYS send
- PROGRESS message, including slow start operations */
- H323SignalPDU progressPDU;
- H225_Progress_UUIE &prog = progressPDU.BuildProgress(*this);
-
- if (!mediaWaitForConnect) {
- if (SendFastStartAcknowledge(prog.m_fastStart))
- prog.IncludeOptionalField(H225_Progress_UUIE::e_fastStart);
- else {
- if (connectionState == ShuttingDownConnection)
- return FALSE;
-
- /* Do early H.245 start */
- earlyStart = TRUE;
- if (!h245Tunneling) {
- if (!H323Connection::StartControlChannel())
- return FALSE;
- prog.IncludeOptionalField(H225_Progress_UUIE::e_h245Address);
- controlChannel->SetUpTransportPDU(prog.m_h245Address, TRUE);
- }
- }
- }
- progressPDU.GetQ931().SetProgressIndicator(Q931::ProgressInbandInformationAvailable);
-
-#ifdef TUNNELLING
- EmbedTunneledInfo(progressPDU);
-#endif
- HandleTunnelPDU(&progressPDU);
- WriteSignalPDU(progressPDU);
-
- return TRUE;
-}
-
-H323Connection::AnswerCallResponse MyH323Connection::OnAnswerCall(const PString & caller,
- const H323SignalPDU & setupPDU,
- H323SignalPDU & connectPDU)
-{
- unsigned pi;
-
- if (h323debug) {
- cout << "\t=-= In OnAnswerCall for call " << GetCallReference() << endl;
- }
-
- if (connectionState == ShuttingDownConnection)
- return H323Connection::AnswerCallDenied;
-
- if (!setupPDU.GetQ931().GetProgressIndicator(pi)) {
- pi = 0;
- }
- if (h323debug) {
- cout << "\t\t- Progress Indicator: " << pi << endl;
- }
- if (progressAlert) {
- pi = progressAlert;
- } else if (pi == Q931::ProgressOriginNotISDN) {
- pi = Q931::ProgressInbandInformationAvailable;
- }
- if (pi && alertingPDU) {
- alertingPDU->GetQ931().SetProgressIndicator(pi);
- }
- if (h323debug) {
- cout << "\t\t- Inserting PI of " << pi << " into ALERTING message" << endl;
- }
-
-#ifdef TUNNELLING
- if (alertingPDU)
- EmbedTunneledInfo(*alertingPDU);
- EmbedTunneledInfo(connectPDU);
-#endif
-
- if (!on_answer_call(GetCallReference(), (const char *)GetCallToken())) {
- return H323Connection::AnswerCallDenied;
- }
- /* The call will be answered later with "AnsweringCall()" function.
- */
- return ((pi || (fastStartState != FastStartDisabled)) ? AnswerCallDeferredWithMedia : AnswerCallDeferred);
-}
-
-BOOL MyH323Connection::OnAlerting(const H323SignalPDU & alertingPDU, const PString & username)
-{
- if (h323debug) {
- cout << "\t=-= In OnAlerting for call " << GetCallReference()
- << ": sessionId=" << sessionId << endl;
- cout << "\t-- Ringing phone for \"" << username << "\"" << endl;
- }
-
- if (on_progress) {
- BOOL isInband;
- unsigned alertingPI;
-
- if (!alertingPDU.GetQ931().GetProgressIndicator(alertingPI)) {
- alertingPI = 0;
- }
- if (h323debug) {
- cout << "\t\t- Progress Indicator: " << alertingPI << endl;
- }
-
- switch(alertingPI) {
- case Q931::ProgressNotEndToEndISDN:
- case Q931::ProgressInbandInformationAvailable:
- isInband = TRUE;
- break;
- default:
- isInband = FALSE;
- }
- on_progress(GetCallReference(), (const char *)GetCallToken(), isInband);
- }
- on_chan_ringing(GetCallReference(), (const char *)GetCallToken() );
- return connectionState != ShuttingDownConnection;
-}
-
-void MyH323Connection::SetCallOptions(void *o, BOOL isIncoming)
-{
- call_options_t *opts = (call_options_t *)o;
-
- progressSetup = opts->progress_setup;
- progressAlert = opts->progress_alert;
- dtmfCodec = (RTP_DataFrame::PayloadTypes)opts->dtmfcodec;
- dtmfMode = opts->dtmfmode;
-
- if (isIncoming) {
- fastStartState = (opts->fastStart ? FastStartInitiate : FastStartDisabled);
- h245Tunneling = (opts->h245Tunneling ? TRUE : FALSE);
- } else {
- sourceE164 = PString(opts->cid_num);
- SetLocalPartyName(PString(opts->cid_name));
- SetDisplayName(PString(opts->cid_name));
- if (opts->redirect_reason >= 0) {
- rdnis = PString(opts->cid_rdnis);
- redirect_reason = opts->redirect_reason;
- }
- cid_presentation = opts->presentation;
- cid_ton = opts->type_of_number;
- if (opts->transfer_capability >= 0) {
- transfer_capability = opts->transfer_capability;
- }
- }
- tunnelOptions = opts->tunnelOptions;
-}
-
-void MyH323Connection::SetCallDetails(void *callDetails, const H323SignalPDU &setupPDU, BOOL isIncoming)
-{
- PString sourceE164;
- PString destE164;
- PString sourceAliases;
- PString destAliases;
- char *s, *s1;
- call_details_t *cd = (call_details_t *)callDetails;
-
- memset(cd, 0, sizeof(*cd));
- cd->call_reference = GetCallReference();
- cd->call_token = strdup((const char *)GetCallToken());
-
- sourceE164 = "";
- setupPDU.GetSourceE164(sourceE164);
- cd->call_source_e164 = strdup((const char *)sourceE164);
-
- destE164 = "";
- setupPDU.GetDestinationE164(destE164);
- cd->call_dest_e164 = strdup((const char *)destE164);
-
- /* XXX Is it possible to have this information for outgoing calls too? XXX */
- if (isIncoming) {
- PString sourceName;
- PIPSocket::Address Ip;
- WORD sourcePort;
- PString redirect_number;
- unsigned redirect_reason;
- unsigned plan, type, screening, presentation;
- Q931::InformationTransferCapability capability;
- unsigned transferRate, codingStandard, userInfoLayer1;
-
- /* Fetch presentation and type information about calling party's number */
- if (setupPDU.GetQ931().GetCallingPartyNumber(sourceName, &plan, &type, &presentation, &screening, 0, 0)) {
- /* Construct fields back */
- cd->type_of_number = (type << 4) | plan;
- cd->presentation = (presentation << 5) | screening;
- } else if (cd->call_source_e164[0]) {
- cd->type_of_number = 0; /* UNKNOWN */
- cd->presentation = 0x03; /* ALLOWED NETWORK NUMBER - Default */
- if (setupPDU.GetQ931().HasIE(Q931::UserUserIE)) {
- const H225_Setup_UUIE &setup_uuie = setupPDU.m_h323_uu_pdu.m_h323_message_body;
- if (setup_uuie.HasOptionalField(H225_Setup_UUIE::e_presentationIndicator))
- cd->presentation = (cd->presentation & 0x9f) | (((unsigned int)setup_uuie.m_presentationIndicator.GetTag()) << 5);
- if (setup_uuie.HasOptionalField(H225_Setup_UUIE::e_screeningIndicator))
- cd->presentation = (cd->presentation & 0xe0) | (((unsigned int)setup_uuie.m_screeningIndicator.GetValue()) & 0x1f);
- }
- } else {
- cd->type_of_number = 0; /* UNKNOWN */
- cd->presentation = 0x43; /* NUMBER NOT AVAILABLE */
- }
-
- sourceName = setupPDU.GetQ931().GetDisplayName();
- cd->call_source_name = strdup((const char *)sourceName);
-
- GetSignallingChannel()->GetRemoteAddress().GetIpAndPort(Ip, sourcePort);
- cd->sourceIp = strdup((const char *)Ip.AsString());
-
- if (setupPDU.GetQ931().GetRedirectingNumber(redirect_number, NULL, NULL, NULL, NULL, &redirect_reason, 0, 0, 0)) {
- cd->redirect_number = strdup((const char *)redirect_number);
- cd->redirect_reason = redirect_reason;
- }
- else
- cd->redirect_reason = -1;
-
- /* Fetch Q.931's transfer capability */
- if (((Q931 &)setupPDU.GetQ931()).GetBearerCapabilities(capability, transferRate, &codingStandard, &userInfoLayer1))
- cd->transfer_capability = ((unsigned int)capability & 0x1f) | (codingStandard << 5);
- else
- cd->transfer_capability = 0x00; /* ITU coding of Speech */
-
- /* Don't show local username as called party name */
- SetDisplayName(cd->call_dest_e164);
- }
-
- /* Convert complex strings */
- // FIXME: deal more than one source alias
- sourceAliases = setupPDU.GetSourceAliases();
- s1 = strdup((const char *)sourceAliases);
- if ((s = strchr(s1, ' ')) != NULL)
- *s = '\0';
- if ((s = strchr(s1, '\t')) != NULL)
- *s = '\0';
- cd->call_source_aliases = s1;
-
- destAliases = setupPDU.GetDestinationAlias();
- s1 = strdup((const char *)destAliases);
- if ((s = strchr(s1, ' ')) != NULL)
- *s = '\0';
- if ((s = strchr(s1, '\t')) != NULL)
- *s = '\0';
- cd->call_dest_alias = s1;
-}
-
-#ifdef TUNNELLING
-static BOOL FetchInformationElements(Q931 &q931, const PBYTEArray &data)
-{
- PINDEX offset = 0;
-
- while (offset < data.GetSize()) {
- // Get field discriminator
- int discriminator = data[offset++];
-
-#if 0
- /* Do not overwrite existing IEs */
- if (q931.HasIE((Q931::InformationElementCodes)discriminator)) {
- if ((discriminatir & 0x80) == 0)
- offset += data[offset++];
- if (offset > data.GetSize())
- return FALSE;
- continue;
- }
-#endif
-
- PBYTEArray * item = new PBYTEArray;
-
- // For discriminator with high bit set there is no data
- if ((discriminator & 0x80) == 0) {
- int len = data[offset++];
-
-#if 0 // That is not H.225 but regular Q.931 (ISDN) IEs
- if (discriminator == UserUserIE) {
- // Special case of User-user field. See 7.2.2.31/H.225.0v4.
- len <<= 8;
- len |= data[offset++];
-
- // we also have a protocol discriminator, which we ignore
- offset++;
-
- // before decrementing the length, make sure it is not zero
- if (len == 0)
- return FALSE;
-
- // adjust for protocol discriminator
- len--;
- }
-#endif
-
- if (offset + len > data.GetSize()) {
- delete item;
- return FALSE;
- }
-
- memcpy(item->GetPointer(len), (const BYTE *)data+offset, len);
- offset += len;
- }
-
- q931.SetIE((Q931::InformationElementCodes)discriminator, *item);
- delete item;
- }
- return TRUE;
-}
-
-static BOOL FetchCiscoTunneledInfo(Q931 &q931, const H323SignalPDU &pdu)
-{
- BOOL res = FALSE;
- const H225_H323_UU_PDU &uuPDU = pdu.m_h323_uu_pdu;
-
- if(uuPDU.HasOptionalField(H225_H323_UU_PDU::e_nonStandardControl)) {
- for(int i = 0; i < uuPDU.m_nonStandardControl.GetSize(); ++i) {
- const H225_NonStandardParameter &np = uuPDU.m_nonStandardControl[i];
- const H225_NonStandardIdentifier &id = np.m_nonStandardIdentifier;
- if (id.GetTag() == H225_NonStandardIdentifier::e_h221NonStandard) {
- const H225_H221NonStandard &ni = id;
- /* Check for Cisco */
- if ((ni.m_t35CountryCode == 181) && (ni.m_t35Extension == 0) && (ni.m_manufacturerCode == 18)) {
- const PBYTEArray &data = np.m_data;
- if (h323debug)
- cout << setprecision(0) << "Received non-standard Cisco extension data " << np.m_data << endl;
- CISCO_H225_H323_UU_NonStdInfo c;
- PPER_Stream strm(data);
- if (c.Decode(strm)) {
- BOOL haveIEs = FALSE;
- if (h323debug)
- cout << setprecision(0) << "H323_UU_NonStdInfo = " << c << endl;
- if (c.HasOptionalField(CISCO_H225_H323_UU_NonStdInfo::e_protoParam)) {
- FetchInformationElements(q931, c.m_protoParam.m_qsigNonStdInfo.m_rawMesg);
- haveIEs = TRUE;
- }
- if (c.HasOptionalField(CISCO_H225_H323_UU_NonStdInfo::e_commonParam)) {
- FetchInformationElements(q931, c.m_commonParam.m_redirectIEinfo.m_redirectIE);
- haveIEs = TRUE;
- }
- if (haveIEs && h323debug)
- cout << setprecision(0) << "Information elements collected:" << q931 << endl;
- res = TRUE;
- } else {
- cout << "ERROR while decoding non-standard Cisco extension" << endl;
- return FALSE;
- }
- }
- }
- }
- }
- return res;
-}
-
-static BOOL EmbedCiscoTunneledInfo(H323SignalPDU &pdu)
-{
- const static struct {
- Q931::InformationElementCodes ie;
- BOOL dontDelete;
- } codes[] = {
- { Q931::RedirectingNumberIE, },
- { Q931::FacilityIE, },
-// { Q931::CallingPartyNumberIE, TRUE },
- };
-
- BOOL res = FALSE;
- BOOL notRedirOnly = FALSE;
- Q931 tmpQ931;
- Q931 &q931 = pdu.GetQ931();
-
- for(unsigned i = 0; i < (sizeof(codes) / sizeof(codes[0])); ++i) {
- if (q931.HasIE(codes[i].ie)) {
- tmpQ931.SetIE(codes[i].ie, q931.GetIE(codes[i].ie));
- if (!codes[i].dontDelete)
- q931.RemoveIE(codes[i].ie);
- if (codes[i].ie != Q931::RedirectingNumberIE)
- notRedirOnly = TRUE;
- res = TRUE;
- }
- }
- /* Have something to embed */
- if (res) {
- PBYTEArray msg;
- if (!tmpQ931.Encode(msg))
- return FALSE;
- PBYTEArray ies(msg.GetPointer() + 5, msg.GetSize() - 5);
-
- H225_H323_UU_PDU &uuPDU = pdu.m_h323_uu_pdu;
- if(!uuPDU.HasOptionalField(H225_H323_UU_PDU::e_nonStandardControl)) {
- uuPDU.IncludeOptionalField(H225_H323_UU_PDU::e_nonStandardControl);
- uuPDU.m_nonStandardControl.SetSize(0);
- }
- H225_NonStandardParameter *np = new H225_NonStandardParameter;
- uuPDU.m_nonStandardControl.Append(np);
- H225_NonStandardIdentifier &nsi = (*np).m_nonStandardIdentifier;
- nsi.SetTag(H225_NonStandardIdentifier::e_h221NonStandard);
- H225_H221NonStandard &ns = nsi;
- ns.m_t35CountryCode = 181;
- ns.m_t35Extension = 0;
- ns.m_manufacturerCode = 18;
-
- CISCO_H225_H323_UU_NonStdInfo c;
- c.IncludeOptionalField(CISCO_H225_H323_UU_NonStdInfo::e_version);
- c.m_version = 0;
-
- if (notRedirOnly) {
- c.IncludeOptionalField(CISCO_H225_H323_UU_NonStdInfo::e_protoParam);
- CISCO_H225_QsigNonStdInfo &qsigInfo = c.m_protoParam.m_qsigNonStdInfo;
- qsigInfo.m_iei = ies[0];
- qsigInfo.m_rawMesg = ies;
- } else {
- c.IncludeOptionalField(CISCO_H225_H323_UU_NonStdInfo::e_commonParam);
- c.m_commonParam.m_redirectIEinfo.m_redirectIE = ies;
- }
- PPER_Stream stream;
- c.Encode(stream);
- stream.CompleteEncoding();
- (*np).m_data = stream;
- }
- return res;
-}
-
-static const char OID_QSIG[] = "1.3.12.9";
-
-static BOOL FetchQSIGTunneledInfo(Q931 &q931, const H323SignalPDU &pdu)
-{
- BOOL res = FALSE;
- const H225_H323_UU_PDU &uuPDU = pdu.m_h323_uu_pdu;
- if (uuPDU.HasOptionalField(H225_H323_UU_PDU::e_tunnelledSignallingMessage)) {
- const H225_H323_UU_PDU_tunnelledSignallingMessage &sig = uuPDU.m_tunnelledSignallingMessage;
- const H225_TunnelledProtocol_id &proto = sig.m_tunnelledProtocolID.m_id;
- if ((proto.GetTag() == H225_TunnelledProtocol_id::e_tunnelledProtocolObjectID) &&
- (((const PASN_ObjectId &)proto).AsString() == OID_QSIG)) {
- const H225_ArrayOf_PASN_OctetString &sigs = sig.m_messageContent;
- for(int i = 0; i < sigs.GetSize(); ++i) {
- const PASN_OctetString &msg = sigs[i];
- if (h323debug)
- cout << setprecision(0) << "Q.931 message data is " << msg << endl;
- if(!q931.Decode((const PBYTEArray &)msg)) {
- cout << "Error while decoding Q.931 message" << endl;
- return FALSE;
- }
- res = TRUE;
- if (h323debug)
- cout << setprecision(0) << "Received QSIG message " << q931 << endl;
- }
- }
- }
- return res;
-}
-
-static H225_EndpointType *GetEndpointType(H323SignalPDU &pdu)
-{
- if (!pdu.GetQ931().HasIE(Q931::UserUserIE))
- return NULL;
-
- H225_H323_UU_PDU_h323_message_body &body = pdu.m_h323_uu_pdu.m_h323_message_body;
- switch (body.GetTag()) {
- case H225_H323_UU_PDU_h323_message_body::e_setup:
- return &((H225_Setup_UUIE &)body).m_sourceInfo;
- case H225_H323_UU_PDU_h323_message_body::e_callProceeding:
- return &((H225_CallProceeding_UUIE &)body).m_destinationInfo;
- case H225_H323_UU_PDU_h323_message_body::e_connect:
- return &((H225_Connect_UUIE &)body).m_destinationInfo;
- case H225_H323_UU_PDU_h323_message_body::e_alerting:
- return &((H225_Alerting_UUIE &)body).m_destinationInfo;
- case H225_H323_UU_PDU_h323_message_body::e_facility:
- return &((H225_Facility_UUIE &)body).m_destinationInfo;
- case H225_H323_UU_PDU_h323_message_body::e_progress:
- return &((H225_Progress_UUIE &)body).m_destinationInfo;
- }
- return NULL;
-}
-
-static BOOL QSIGTunnelRequested(H323SignalPDU &pdu)
-{
- H225_EndpointType *epType = GetEndpointType(pdu);
- if (epType) {
- if (!(*epType).HasOptionalField(H225_EndpointType::e_supportedTunnelledProtocols)) {
- return FALSE;
- }
- H225_ArrayOf_TunnelledProtocol &protos = (*epType).m_supportedTunnelledProtocols;
- for (int i = 0; i < protos.GetSize(); ++i)
- {
- if ((protos[i].GetTag() == H225_TunnelledProtocol_id::e_tunnelledProtocolObjectID) &&
- (((const PASN_ObjectId &)protos[i]).AsString() == OID_QSIG)) {
- return TRUE;
- }
- }
- }
- return FALSE;
-}
-
-static BOOL EmbedQSIGTunneledInfo(H323SignalPDU &pdu)
-{
- const static Q931::InformationElementCodes codes[] =
- { Q931::RedirectingNumberIE, Q931::FacilityIE };
-
- Q931 &q931 = pdu.GetQ931();
- PBYTEArray message;
-
- q931.Encode(message);
-
- /* Remove non-standard IEs */
- for(unsigned i = 0; i < (sizeof(codes) / sizeof(codes[0])); ++i) {
- if (q931.HasIE(codes[i])) {
- q931.RemoveIE(codes[i]);
- }
- }
-
- H225_H323_UU_PDU &uuPDU = pdu.m_h323_uu_pdu;
- H225_EndpointType *epType = GetEndpointType(pdu);
- if (epType) {
- if (!(*epType).HasOptionalField(H225_EndpointType::e_supportedTunnelledProtocols)) {
- (*epType).IncludeOptionalField(H225_EndpointType::e_supportedTunnelledProtocols);
- (*epType).m_supportedTunnelledProtocols.SetSize(0);
- }
- H225_ArrayOf_TunnelledProtocol &protos = (*epType).m_supportedTunnelledProtocols;
- BOOL addQSIG = TRUE;
- for (int i = 0; i < protos.GetSize(); ++i)
- {
- if ((protos[i].GetTag() == H225_TunnelledProtocol_id::e_tunnelledProtocolObjectID) &&
- (((PASN_ObjectId &)protos[i]).AsString() == OID_QSIG)) {
- addQSIG = FALSE;
- break;
- }
- }
- if (addQSIG) {
- H225_TunnelledProtocol *proto = new H225_TunnelledProtocol;
- (*proto).m_id.SetTag(H225_TunnelledProtocol_id::e_tunnelledProtocolObjectID);
- (PASN_ObjectId &)(proto->m_id) = OID_QSIG;
- protos.Append(proto);
- }
- }
- if (!uuPDU.HasOptionalField(H225_H323_UU_PDU::e_tunnelledSignallingMessage))
- uuPDU.IncludeOptionalField(H225_H323_UU_PDU::e_tunnelledSignallingMessage);
- H225_H323_UU_PDU_tunnelledSignallingMessage &sig = uuPDU.m_tunnelledSignallingMessage;
- H225_TunnelledProtocol_id &proto = sig.m_tunnelledProtocolID.m_id;
- if ((proto.GetTag() != H225_TunnelledProtocol_id::e_tunnelledProtocolObjectID) ||
- (((const PASN_ObjectId &)proto).AsString() != OID_QSIG)) {
- proto.SetTag(H225_TunnelledProtocol_id::e_tunnelledProtocolObjectID);
- (PASN_ObjectId &)proto = OID_QSIG;
- sig.m_messageContent.SetSize(0);
- }
- PASN_OctetString *msg = new PASN_OctetString;
- sig.m_messageContent.Append(msg);
- *msg = message;
- return TRUE;
-}
-
-BOOL MyH323Connection::EmbedTunneledInfo(H323SignalPDU &pdu)
-{
- if ((tunnelOptions & H323_TUNNEL_QSIG) || (remoteTunnelOptions & H323_TUNNEL_QSIG))
- EmbedQSIGTunneledInfo(pdu);
- if ((tunnelOptions & H323_TUNNEL_CISCO) || (remoteTunnelOptions & H323_TUNNEL_CISCO))
- EmbedCiscoTunneledInfo(pdu);
-
- return TRUE;
-}
-
-/* Handle tunneled messages */
-BOOL MyH323Connection::HandleSignalPDU(H323SignalPDU &pdu)
-{
- if (pdu.GetQ931().HasIE(Q931::UserUserIE)) {
- Q931 tunneledInfo;
- const Q931 *q931Info;
-
- q931Info = NULL;
- if (FetchCiscoTunneledInfo(tunneledInfo, pdu)) {
- q931Info = &tunneledInfo;
- remoteTunnelOptions |= H323_TUNNEL_CISCO;
- }
- if (FetchQSIGTunneledInfo(tunneledInfo, pdu)) {
- q931Info = &tunneledInfo;
- remoteTunnelOptions |= H323_TUNNEL_QSIG;
- }
- if (!(remoteTunnelOptions & H323_TUNNEL_QSIG) && QSIGTunnelRequested(pdu)) {
- remoteTunnelOptions |= H323_TUNNEL_QSIG;
- }
- if (q931Info) {
- if (q931Info->HasIE(Q931::RedirectingNumberIE)) {
- pdu.GetQ931().SetIE(Q931::RedirectingNumberIE, q931Info->GetIE(Q931::RedirectingNumberIE));
- if (h323debug) {
- PString number;
- unsigned reason;
- if(q931Info->GetRedirectingNumber(number, NULL, NULL, NULL, NULL, &reason, 0, 0, 0))
- cout << "Got redirection from " << number << ", reason " << reason << endl;
- }
- }
- }
- }
-
- return H323Connection::HandleSignalPDU(pdu);
-}
-#endif
-
-BOOL MyH323Connection::OnReceivedSignalSetup(const H323SignalPDU & setupPDU)
-{
- call_details_t cd;
-
- if (h323debug) {
- cout << "\t--Received SETUP message" << endl;
- }
-
- if (connectionState == ShuttingDownConnection)
- return FALSE;
-
- SetCallDetails(&cd, setupPDU, TRUE);
-
- /* Notify Asterisk of the request */
- call_options_t *res = on_incoming_call(&cd);
-
- if (!res) {
- if (h323debug) {
- cout << "\t-- Call Failed" << endl;
- }
- return FALSE;
- }
-
- SetCallOptions(res, TRUE);
-
- /* Disable fastStart if requested by remote side */
- if (h245Tunneling && !setupPDU.m_h323_uu_pdu.m_h245Tunneling) {
- masterSlaveDeterminationProcedure->Stop();
- capabilityExchangeProcedure->Stop();
- PTRACE(3, "H225\tFast Start DISABLED!");
- h245Tunneling = FALSE;
- }
-
- return H323Connection::OnReceivedSignalSetup(setupPDU);
-}
-
-BOOL MyH323Connection::OnSendSignalSetup(H323SignalPDU & setupPDU)
-{
- call_details_t cd;
-
- if (h323debug) {
- cout << "\t-- Sending SETUP message" << endl;
- }
-
- if (connectionState == ShuttingDownConnection)
- return FALSE;
-
- if (progressSetup)
- setupPDU.GetQ931().SetProgressIndicator(progressSetup);
-
- if (redirect_reason >= 0) {
- setupPDU.GetQ931().SetRedirectingNumber(rdnis, 0, 0, 0, 0, redirect_reason);
- /* OpenH323 incorrectly fills number IE when redirecting reason is specified - fix it */
- PBYTEArray IE(setupPDU.GetQ931().GetIE(Q931::RedirectingNumberIE));
- IE[0] = IE[0] & 0x7f;
- IE[1] = IE[1] & 0x7f;
- setupPDU.GetQ931().SetIE(Q931::RedirectingNumberIE, IE);
- }
-
- if (transfer_capability)
- setupPDU.GetQ931().SetBearerCapabilities((Q931::InformationTransferCapability)(transfer_capability & 0x1f), 1, ((transfer_capability >> 5) & 3));
-
- SetCallDetails(&cd, setupPDU, FALSE);
-
- int res = on_outgoing_call(&cd);
- if (!res) {
- if (h323debug) {
- cout << "\t-- Call Failed" << endl;
- }
- return FALSE;
- }
-
- /* OpenH323 will build calling party information with default
- type and presentation information, so build it to be recorded
- by embedding routines */
- setupPDU.GetQ931().SetCallingPartyNumber(sourceE164, (cid_ton >> 4) & 0x07,
- cid_ton & 0x0f, (cid_presentation >> 5) & 0x03, cid_presentation & 0x1f);
- setupPDU.GetQ931().SetDisplayName(GetDisplayName());
-
-#ifdef TUNNELLING
- EmbedTunneledInfo(setupPDU);
-#endif
-
- return H323Connection::OnSendSignalSetup(setupPDU);
-}
-
-static BOOL BuildFastStartList(const H323Channel & channel,
- H225_ArrayOf_PASN_OctetString & array,
- H323Channel::Directions reverseDirection)
-{
- H245_OpenLogicalChannel open;
- const H323Capability & capability = channel.GetCapability();
-
- if (channel.GetDirection() != reverseDirection) {
- if (!capability.OnSendingPDU(open.m_forwardLogicalChannelParameters.m_dataType))
- return FALSE;
- }
- else {
- if (!capability.OnSendingPDU(open.m_reverseLogicalChannelParameters.m_dataType))
- return FALSE;
-
- open.m_forwardLogicalChannelParameters.m_multiplexParameters.SetTag(
- H245_OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters::e_none);
- open.m_forwardLogicalChannelParameters.m_dataType.SetTag(H245_DataType::e_nullData);
- open.IncludeOptionalField(H245_OpenLogicalChannel::e_reverseLogicalChannelParameters);
- }
-
- if (!channel.OnSendingPDU(open))
- return FALSE;
-
- PTRACE(4, "H225\tBuild fastStart:\n " << setprecision(2) << open);
- PINDEX last = array.GetSize();
- array.SetSize(last+1);
- array[last].EncodeSubType(open);
-
- PTRACE(3, "H225\tBuilt fastStart for " << capability);
- return TRUE;
-}
-
-H323Connection::CallEndReason MyH323Connection::SendSignalSetup(const PString & alias,
- const H323TransportAddress & address)
-{
- // Start the call, first state is asking gatekeeper
- connectionState = AwaitingGatekeeperAdmission;
-
- // Indicate the direction of call.
- if (alias.IsEmpty())
- remotePartyName = remotePartyAddress = address;
- else {
- remotePartyName = alias;
- remotePartyAddress = alias + '@' + address;
- }
-
- // Start building the setup PDU to get various ID's
- H323SignalPDU setupPDU;
- H225_Setup_UUIE & setup = setupPDU.BuildSetup(*this, address);
-
-#ifdef H323_H450
- h450dispatcher->AttachToSetup(setupPDU);
-#endif
-
- // Save the identifiers generated by BuildSetup
- setupPDU.GetQ931().GetCalledPartyNumber(remotePartyNumber);
-
- H323TransportAddress gatekeeperRoute = address;
-
- // Check for gatekeeper and do admission check if have one
- H323Gatekeeper * gatekeeper = endpoint.GetGatekeeper();
- H225_ArrayOf_AliasAddress newAliasAddresses;
- if (gatekeeper != NULL) {
- H323Gatekeeper::AdmissionResponse response;
- response.transportAddress = &gatekeeperRoute;
- response.aliasAddresses = &newAliasAddresses;
- if (!gkAccessTokenOID)
- response.accessTokenData = &gkAccessTokenData;
- while (!gatekeeper->AdmissionRequest(*this, response, alias.IsEmpty())) {
- PTRACE(1, "H225\tGatekeeper refused admission: "
- << (response.rejectReason == UINT_MAX
- ? PString("Transport error")
- : H225_AdmissionRejectReason(response.rejectReason).GetTagName()));
-#ifdef H323_H450
- h4502handler->onReceivedAdmissionReject(H4501_GeneralErrorList::e_notAvailable);
-#endif
-
- switch (response.rejectReason) {
- case H225_AdmissionRejectReason::e_calledPartyNotRegistered:
- return EndedByNoUser;
- case H225_AdmissionRejectReason::e_requestDenied:
- return EndedByNoBandwidth;
- case H225_AdmissionRejectReason::e_invalidPermission:
- case H225_AdmissionRejectReason::e_securityDenial:
- return EndedBySecurityDenial;
- case H225_AdmissionRejectReason::e_resourceUnavailable:
- return EndedByRemoteBusy;
- case H225_AdmissionRejectReason::e_incompleteAddress:
- if (OnInsufficientDigits())
- break;
- // Then default case
- default:
- return EndedByGatekeeper;
- }
-
- PString lastRemotePartyName = remotePartyName;
- while (lastRemotePartyName == remotePartyName) {
- Unlock(); // Release the mutex as can deadlock trying to clear call during connect.
- digitsWaitFlag.Wait();
- if (!Lock()) // Lock while checking for shutting down.
- return EndedByCallerAbort;
- }
- }
- mustSendDRQ = TRUE;
- if (response.gatekeeperRouted) {
- setup.IncludeOptionalField(H225_Setup_UUIE::e_endpointIdentifier);
- setup.m_endpointIdentifier = gatekeeper->GetEndpointIdentifier();
- gatekeeperRouted = TRUE;
- }
- }
-
-#ifdef H323_TRANSNEXUS_OSP
- // check for OSP server (if not using GK)
- if (gatekeeper == NULL) {
- OpalOSP::Provider * ospProvider = endpoint.GetOSPProvider();
- if (ospProvider != NULL) {
- OpalOSP::Transaction * transaction = new OpalOSP::Transaction();
- if (transaction->Open(*ospProvider) != 0) {
- PTRACE(1, "H225\tCannot create OSP transaction");
- return EndedByOSPRefusal;
- }
-
- OpalOSP::Transaction::DestinationInfo destInfo;
- if (!AuthoriseOSPTransaction(*transaction, destInfo)) {
- delete transaction;
- return EndedByOSPRefusal;
- }
-
- // save the transaction for use by the call
- ospTransaction = transaction;
-
- // retreive the call information
- gatekeeperRoute = destInfo.destinationAddress;
- newAliasAddresses.Append(new H225_AliasAddress(destInfo.calledNumber));
-
- // insert the token
- setup.IncludeOptionalField(H225_Setup_UUIE::e_tokens);
- destInfo.InsertToken(setup.m_tokens);
- }
- }
-#endif
-
- // Update the field e_destinationAddress in the SETUP PDU to reflect the new
- // alias received in the ACF (m_destinationInfo).
- if (newAliasAddresses.GetSize() > 0) {
- setup.IncludeOptionalField(H225_Setup_UUIE::e_destinationAddress);
- setup.m_destinationAddress = newAliasAddresses;
-
- // Update the Q.931 Information Element (if is an E.164 address)
- PString e164 = H323GetAliasAddressE164(newAliasAddresses);
- if (!e164)
- remotePartyNumber = e164;
- }
-
- if (addAccessTokenToSetup && !gkAccessTokenOID && !gkAccessTokenData.IsEmpty()) {
- PString oid1, oid2;
- PINDEX comma = gkAccessTokenOID.Find(',');
- if (comma == P_MAX_INDEX)
- oid1 = oid2 = gkAccessTokenOID;
- else {
- oid1 = gkAccessTokenOID.Left(comma);
- oid2 = gkAccessTokenOID.Mid(comma+1);
- }
- setup.IncludeOptionalField(H225_Setup_UUIE::e_tokens);
- PINDEX last = setup.m_tokens.GetSize();
- setup.m_tokens.SetSize(last+1);
- setup.m_tokens[last].m_tokenOID = oid1;
- setup.m_tokens[last].IncludeOptionalField(H235_ClearToken::e_nonStandard);
- setup.m_tokens[last].m_nonStandard.m_nonStandardIdentifier = oid2;
- setup.m_tokens[last].m_nonStandard.m_data = gkAccessTokenData;
- }
-
- if (!signallingChannel->SetRemoteAddress(gatekeeperRoute)) {
- PTRACE(1, "H225\tInvalid "
- << (gatekeeperRoute != address ? "gatekeeper" : "user")
- << " supplied address: \"" << gatekeeperRoute << '"');
- connectionState = AwaitingTransportConnect;
- return EndedByConnectFail;
- }
-
- // Do the transport connect
- connectionState = AwaitingTransportConnect;
-
- // Release the mutex as can deadlock trying to clear call during connect.
- Unlock();
-
- signallingChannel->SetWriteTimeout(100);
-
- BOOL connectFailed = !signallingChannel->Connect();
-
- // Lock while checking for shutting down.
- if (!Lock())
- return EndedByCallerAbort;
-
- // See if transport connect failed, abort if so.
- if (connectFailed) {
- connectionState = NoConnectionActive;
- switch (signallingChannel->GetErrorNumber()) {
- case ENETUNREACH :
- return EndedByUnreachable;
- case ECONNREFUSED :
- return EndedByNoEndPoint;
- case ETIMEDOUT :
- return EndedByHostOffline;
- }
- return EndedByConnectFail;
- }
-
- PTRACE(3, "H225\tSending Setup PDU");
- connectionState = AwaitingSignalConnect;
-
- // Put in all the signalling addresses for link
- setup.IncludeOptionalField(H225_Setup_UUIE::e_sourceCallSignalAddress);
- signallingChannel->SetUpTransportPDU(setup.m_sourceCallSignalAddress, TRUE);
- if (!setup.HasOptionalField(H225_Setup_UUIE::e_destCallSignalAddress)) {
- setup.IncludeOptionalField(H225_Setup_UUIE::e_destCallSignalAddress);
- signallingChannel->SetUpTransportPDU(setup.m_destCallSignalAddress, FALSE);
- }
-
- // If a standard call do Fast Start (if required)
- if (setup.m_conferenceGoal.GetTag() == H225_Setup_UUIE_conferenceGoal::e_create) {
-
- // Get the local capabilities before fast start is handled
- OnSetLocalCapabilities();
-
- // Ask the application what channels to open
- PTRACE(3, "H225\tCheck for Fast start by local endpoint");
- fastStartChannels.RemoveAll();
- OnSelectLogicalChannels();
-
- // If application called OpenLogicalChannel, put in the fastStart field
- if (!fastStartChannels.IsEmpty()) {
- PTRACE(3, "H225\tFast start begun by local endpoint");
- for (PINDEX i = 0; i < fastStartChannels.GetSize(); i++)
- BuildFastStartList(fastStartChannels[i], setup.m_fastStart, H323Channel::IsReceiver);
- if (setup.m_fastStart.GetSize() > 0)
- setup.IncludeOptionalField(H225_Setup_UUIE::e_fastStart);
- }
-
- // Search the capability set and see if we have video capability
- for (PINDEX i = 0; i < localCapabilities.GetSize(); i++) {
- switch (localCapabilities[i].GetMainType()) {
- case H323Capability::e_Audio:
- case H323Capability::e_UserInput:
- break;
-
- default: // Is video or other data (eg T.120)
- setupPDU.GetQ931().SetBearerCapabilities(Q931::TransferUnrestrictedDigital, 6);
- i = localCapabilities.GetSize(); // Break out of the for loop
- break;
- }
- }
- }
-
- if (!OnSendSignalSetup(setupPDU))
- return EndedByNoAccept;
-
- // Do this again (was done when PDU was constructed) in case
- // OnSendSignalSetup() changed something.
-// setupPDU.SetQ931Fields(*this, TRUE);
- setupPDU.GetQ931().GetCalledPartyNumber(remotePartyNumber);
-
- fastStartState = FastStartDisabled;
- BOOL set_lastPDUWasH245inSETUP = FALSE;
-
- if (h245Tunneling && doH245inSETUP) {
- h245TunnelTxPDU = &setupPDU;
-
- // Try and start the master/slave and capability exchange through the tunnel
- // Note: this used to be disallowed but is now allowed as of H323v4
- BOOL ok = StartControlNegotiations();
-
- h245TunnelTxPDU = NULL;
-
- if (!ok)
- return EndedByTransportFail;
-
- if (setup.m_fastStart.GetSize() > 0) {
- // Now if fast start as well need to put this in setup specific field
- // and not the generic H.245 tunneling field
- setup.IncludeOptionalField(H225_Setup_UUIE::e_parallelH245Control);
- setup.m_parallelH245Control = setupPDU.m_h323_uu_pdu.m_h245Control;
- setupPDU.m_h323_uu_pdu.RemoveOptionalField(H225_H323_UU_PDU::e_h245Control);
- set_lastPDUWasH245inSETUP = TRUE;
- }
- }
-
- // Send the initial PDU
- setupTime = PTime();
- if (!WriteSignalPDU(setupPDU))
- return EndedByTransportFail;
-
- // WriteSignalPDU always resets lastPDUWasH245inSETUP.
- // So set it here if required
- if (set_lastPDUWasH245inSETUP)
- lastPDUWasH245inSETUP = TRUE;
-
- // Set timeout for remote party to answer the call
- signallingChannel->SetReadTimeout(endpoint.GetSignallingChannelCallTimeout());
-
- return NumCallEndReasons;
-}
-
-
-BOOL MyH323Connection::OnSendReleaseComplete(H323SignalPDU & releaseCompletePDU)
-{
- if (h323debug) {
- cout << "\t-- Sending RELEASE COMPLETE" << endl;
- }
- if (cause > 0)
- releaseCompletePDU.GetQ931().SetCause((Q931::CauseValues)cause);
-
-#ifdef TUNNELLING
- EmbedTunneledInfo(releaseCompletePDU);
-#endif
-
- return H323Connection::OnSendReleaseComplete(releaseCompletePDU);
-}
-
-BOOL MyH323Connection::OnReceivedFacility(const H323SignalPDU & pdu)
-{
- if (h323debug) {
- cout << "\t-- Received Facility message... " << endl;
- }
- return H323Connection::OnReceivedFacility(pdu);
-}
-
-void MyH323Connection::OnReceivedReleaseComplete(const H323SignalPDU & pdu)
-{
- if (h323debug) {
- cout << "\t-- Received RELEASE COMPLETE message..." << endl;
- }
- if (on_hangup)
- on_hangup(GetCallReference(), (const char *)GetCallToken(), pdu.GetQ931().GetCause());
- return H323Connection::OnReceivedReleaseComplete(pdu);
-}
-
-BOOL MyH323Connection::OnClosingLogicalChannel(H323Channel & channel)
-{
- if (h323debug) {
- cout << "\t-- Closing logical channel..." << endl;
- }
- return H323Connection::OnClosingLogicalChannel(channel);
-}
-
-void MyH323Connection::SendUserInputTone(char tone, unsigned duration, unsigned logicalChannel, unsigned rtpTimestamp)
-{
- SendUserInputModes mode = GetRealSendUserInputMode();
-// That is recursive call... Why?
-// on_receive_digit(GetCallReference(), tone, (const char *)GetCallToken());
- if ((tone != ' ') || (mode == SendUserInputAsTone) || (mode == SendUserInputAsInlineRFC2833)) {
- if (h323debug) {
- cout << "\t-- Sending user input tone (" << tone << ") to remote" << endl;
- }
- H323Connection::SendUserInputTone(tone, duration);
- }
-}
-
-void MyH323Connection::OnUserInputTone(char tone, unsigned duration, unsigned logicalChannel, unsigned rtpTimestamp)
-{
- if (dtmfMode == H323_DTMF_RFC2833) {
- if (h323debug) {
- cout << "\t-- Received user input tone (" << tone << ") from remote" << endl;
- }
- on_receive_digit(GetCallReference(), tone, (const char *)GetCallToken(), duration);
- }
-}
-
-void MyH323Connection::OnUserInputString(const PString &value)
-{
- if (h323debug) {
- cout << "\t-- Received user input string (" << value << ") from remote." << endl;
- }
- on_receive_digit(GetCallReference(), value[0], (const char *)GetCallToken(), 0);
-}
-
-void MyH323Connection::OnSendCapabilitySet(H245_TerminalCapabilitySet & pdu)
-{
- PINDEX i;
-
- H323Connection::OnSendCapabilitySet(pdu);
-
- H245_ArrayOf_CapabilityTableEntry & tables = pdu.m_capabilityTable;
- for(i = 0; i < tables.GetSize(); i++)
- {
- H245_CapabilityTableEntry & entry = tables[i];
- if (entry.HasOptionalField(H245_CapabilityTableEntry::e_capability)) {
- H245_Capability & cap = entry.m_capability;
- if (cap.GetTag() == H245_Capability::e_receiveRTPAudioTelephonyEventCapability) {
- H245_AudioTelephonyEventCapability & atec = cap;
- atec.m_dynamicRTPPayloadType = dtmfCodec;
-// on_set_rfc2833_payload(GetCallReference(), (const char *)GetCallToken(), (int)dtmfCodec);
-#ifdef PTRACING
- if (h323debug) {
- cout << "\t-- Transmitting RFC2833 on payload " <<
- atec.m_dynamicRTPPayloadType << endl;
- }
-#endif
- }
- }
- }
-}
-
-void MyH323Connection::OnSetLocalCapabilities()
-{
- if (on_setcapabilities)
- on_setcapabilities(GetCallReference(), (const char *)callToken);
-}
-
-BOOL MyH323Connection::OnReceivedCapabilitySet(const H323Capabilities & remoteCaps,
- const H245_MultiplexCapability * muxCap,
- H245_TerminalCapabilitySetReject & reject)
-{
- struct __codec__ {
- unsigned int asterisk_codec;
- unsigned int h245_cap;
- const char *oid;
- };
- static const struct __codec__ codecs[] = {
- { AST_FORMAT_G723_1, H245_AudioCapability::e_g7231 },
- { AST_FORMAT_GSM, H245_AudioCapability::e_gsmFullRate },
- { AST_FORMAT_ULAW, H245_AudioCapability::e_g711Ulaw64k },
- { AST_FORMAT_ALAW, H245_AudioCapability::e_g711Alaw64k },
- { AST_FORMAT_G729A, H245_AudioCapability::e_g729AnnexA },
- { AST_FORMAT_G729A, H245_AudioCapability::e_g729 },
-#ifdef AST_FORMAT_MODEM
- { AST_FORMAT_MODEM, H245_DataApplicationCapability_application::e_t38fax },
-#endif
- { 0 }
- };
-
-#if 0
- static const struct __codec__ vcodecs[] = {
-#ifdef HAVE_H261
- { AST_FORMAT_H261, H245_VideoCapability::e_h261VideoCapability },
-#endif
-#ifdef HAVE_H263
- { AST_FORMAT_H263, H245_VideoCapability::e_h263VideoCapability },
-#endif
-#ifdef HAVE_H264
- { AST_FORMAT_H264, H245_VideoCapability::e_genericVideoCapability, "0.0.8.241.0.0.1" },
-#endif
- { 0 }
- };
-#endif
- struct ast_codec_pref prefs;
-
- if (!H323Connection::OnReceivedCapabilitySet(remoteCaps, muxCap, reject)) {
- return FALSE;
- }
-
- const H323Capability * cap = remoteCaps.FindCapability(H323_UserInputCapability::SubTypeNames[H323_UserInputCapability::SignalToneRFC2833]);
- if (cap != NULL) {
- RTP_DataFrame::PayloadTypes pt = ((H323_UserInputCapability*)cap)->GetPayloadType();
- on_set_rfc2833_payload(GetCallReference(), (const char *)GetCallToken(), (int)pt);
- if ((dtmfMode == H323_DTMF_RFC2833) && (sendUserInputMode == SendUserInputAsTone))
- sendUserInputMode = SendUserInputAsInlineRFC2833;
-#ifdef PTRACING
- if (h323debug) {
- cout << "\t-- Inbound RFC2833 on payload " << pt << endl;
- }
-#endif
- }
- memset(&prefs, 0, sizeof(prefs));
- int peer_capabilities = 0;
- for (int i = 0; i < remoteCapabilities.GetSize(); ++i) {
- unsigned int subType = remoteCapabilities[i].GetSubType();
- if (h323debug) {
- cout << "Peer capability is " << remoteCapabilities[i] << endl;
- }
- switch(remoteCapabilities[i].GetMainType()) {
- case H323Capability::e_Audio:
- for (int x = 0; codecs[x].asterisk_codec > 0; ++x) {
- if (subType == codecs[x].h245_cap) {
- int ast_codec = codecs[x].asterisk_codec;
- int ms = 0;
- if (!(peer_capabilities & ast_codec)) {
- struct ast_format_list format;
- ast_codec_pref_append(&prefs, ast_codec);
- format = ast_codec_pref_getsize(&prefs, ast_codec);
- if ((ast_codec == AST_FORMAT_ALAW) || (ast_codec == AST_FORMAT_ULAW)) {
- ms = remoteCapabilities[i].GetTxFramesInPacket();
- if (ms > 60)
- ms = format.cur_ms;
- } else
- ms = remoteCapabilities[i].GetTxFramesInPacket() * format.inc_ms;
- ast_codec_pref_setsize(&prefs, ast_codec, ms);
- }
- if (h323debug) {
- cout << "Found peer capability " << remoteCapabilities[i] << ", Asterisk code is " << ast_codec << ", frame size (in ms) is " << ms << endl;
- }
- peer_capabilities |= ast_codec;
- }
- }
- break;
-#if 0
- case H323Capability::e_Video:
- for (int x = 0; vcodecs[x].asterisk_codec > 0; ++x) {
- if (subType == vcodecs[x].h245_cap) {
- H245_CapabilityIdentifier *cap = NULL;
- H245_GenericCapability y;
- if (vcodecs[x].oid) {
- cap = new H245_CapabilityIdentifier(H245_CapabilityIdentifier::e_standard);
- PASN_ObjectId &object_id = *cap;
- object_id = vcodecs[x].oid;
- y.m_capabilityIdentifier = *cap;
- }
- if ((subType != H245_VideoCapability::e_genericVideoCapability) ||
- (vcodecs[x].oid && ((const H323GenericVideoCapability &)remoteCapabilities[i]).IsGenericMatch((const H245_GenericCapability)y))) {
- if (h323debug) {
- cout << "Found peer video capability " << remoteCapabilities[i] << ", Asterisk code is " << vcodecs[x].asterisk_codec << endl;
- }
- peer_capabilities |= vcodecs[x].asterisk_codec;
- }
- if (cap)
- delete(cap);
- }
- }
- break;
-#endif
- default:
- break;
- }
- }
- if (h323debug) {
- char caps_str[1024], caps2_str[1024];
- ast_codec_pref_string(&prefs, caps2_str, sizeof(caps2_str));
- cout << "Peer capabilities = " << ast_getformatname_multiple(caps_str, sizeof(caps_str), peer_capabilities)
- << ", ordered list is " << caps2_str << endl;
- }
-#if 0
- redir_capabilities &= peer_capabilities;
-#endif
- if (on_setpeercapabilities)
- on_setpeercapabilities(GetCallReference(), (const char *)callToken, peer_capabilities, &prefs);
-
- return TRUE;
-}
-
-H323Channel * MyH323Connection::CreateRealTimeLogicalChannel(const H323Capability & capability,
- H323Channel::Directions dir,
- unsigned sessionID,
- const H245_H2250LogicalChannelParameters * /*param*/,
- RTP_QOS * /*param*/ )
-{
- /* Do not open tx channel when transmitter has been paused by empty TCS */
- if ((dir == H323Channel::IsTransmitter) && transmitterSidePaused)
- return NULL;
-
- return new MyH323_ExternalRTPChannel(*this, capability, dir, sessionID);
-}
-
-/** This callback function is invoked once upon creation of each
- * channel for an H323 session
- */
-BOOL MyH323Connection::OnStartLogicalChannel(H323Channel & channel)
-{
- /* Increase the count of channels we have open */
- channelsOpen++;
-
- if (h323debug) {
- cout << "\t-- Started logical channel: "
- << ((channel.GetDirection() == H323Channel::IsTransmitter) ? "sending " : ((channel.GetDirection() == H323Channel::IsReceiver) ? "receiving " : " "))
- << (const char *)(channel.GetCapability()).GetFormatName() << endl;
- cout << "\t\t-- channelsOpen = " << channelsOpen << endl;
- }
- return connectionState != ShuttingDownConnection;
-}
-
-void MyH323Connection::SetCapabilities(int cap, int dtmf_mode, void *_prefs, int pref_codec)
-{
- PINDEX lastcap = -1; /* last common capability index */
- int alreadysent = 0;
- int codec;
- int x, y;
- char caps_str[1024];
- struct ast_codec_pref *prefs = (struct ast_codec_pref *)_prefs;
- struct ast_format_list format;
- int frames_per_packet;
- int max_frames_per_packet;
-
- localCapabilities.RemoveAll();
-
- if (h323debug) {
- cout << "Setting capabilities to " << ast_getformatname_multiple(caps_str, sizeof(caps_str), cap) << endl;
- ast_codec_pref_string(prefs, caps_str, sizeof(caps_str));
- cout << "Capabilities in preference order is " << caps_str << endl;
- }
- /* Add audio codecs in preference order first, then
- audio codecs without preference as allowed by mask */
- for (y = 0, x = -1; x < 32 + 32; ++x) {
- if (x < 0)
- codec = pref_codec;
- else if (y || (!(codec = ast_codec_pref_index(prefs, x)))) {
- if (!y)
- y = 1;
- else if (y == AST_FORMAT_MAX_AUDIO)
- break;
- else
- y <<= 1;
- codec = y;
- }
- if (!(cap & codec) || (alreadysent & codec) || !(codec & AST_FORMAT_AUDIO_MASK))
- continue;
- alreadysent |= codec;
- format = ast_codec_pref_getsize(prefs, codec);
- frames_per_packet = (format.inc_ms ? format.cur_ms / format.inc_ms : format.cur_ms);
- max_frames_per_packet = (format.inc_ms ? format.max_ms / format.inc_ms : 0);
- switch(codec) {
-#if 0
- case AST_FORMAT_SPEEX:
- /* Not real sure if Asterisk acutally supports all
- of the various different bit rates so add them
- all and figure it out later*/
-
- lastcap = localCapabilities.SetCapability(0, 0, new SpeexNarrow2AudioCapability());
- lastcap = localCapabilities.SetCapability(0, 0, new SpeexNarrow3AudioCapability());
- lastcap = localCapabilities.SetCapability(0, 0, new SpeexNarrow4AudioCapability());
- lastcap = localCapabilities.SetCapability(0, 0, new SpeexNarrow5AudioCapability());
- lastcap = localCapabilities.SetCapability(0, 0, new SpeexNarrow6AudioCapability());
- break;
-#endif
- case AST_FORMAT_G729A:
- AST_G729ACapability *g729aCap;
- AST_G729Capability *g729Cap;
- lastcap = localCapabilities.SetCapability(0, 0, g729aCap = new AST_G729ACapability(frames_per_packet));
- lastcap = localCapabilities.SetCapability(0, 0, g729Cap = new AST_G729Capability(frames_per_packet));
- if (max_frames_per_packet) {
- g729aCap->SetTxFramesInPacket(max_frames_per_packet);
- g729Cap->SetTxFramesInPacket(max_frames_per_packet);
- }
- break;
- case AST_FORMAT_G723_1:
- AST_G7231Capability *g7231Cap;
- lastcap = localCapabilities.SetCapability(0, 0, g7231Cap = new AST_G7231Capability(frames_per_packet, TRUE));
- if (max_frames_per_packet)
- g7231Cap->SetTxFramesInPacket(max_frames_per_packet);
- lastcap = localCapabilities.SetCapability(0, 0, g7231Cap = new AST_G7231Capability(frames_per_packet, FALSE));
- if (max_frames_per_packet)
- g7231Cap->SetTxFramesInPacket(max_frames_per_packet);
- break;
- case AST_FORMAT_GSM:
- AST_GSM0610Capability *gsmCap;
- lastcap = localCapabilities.SetCapability(0, 0, gsmCap = new AST_GSM0610Capability(frames_per_packet));
- if (max_frames_per_packet)
- gsmCap->SetTxFramesInPacket(max_frames_per_packet);
- break;
- case AST_FORMAT_ULAW:
- AST_G711Capability *g711uCap;
- lastcap = localCapabilities.SetCapability(0, 0, g711uCap = new AST_G711Capability(format.cur_ms, H323_G711Capability::muLaw));
- if (format.max_ms)
- g711uCap->SetTxFramesInPacket(format.max_ms);
- break;
- case AST_FORMAT_ALAW:
- AST_G711Capability *g711aCap;
- lastcap = localCapabilities.SetCapability(0, 0, g711aCap = new AST_G711Capability(format.cur_ms, H323_G711Capability::ALaw));
- if (format.max_ms)
- g711aCap->SetTxFramesInPacket(format.max_ms);
- break;
- default:
- alreadysent &= ~codec;
- break;
- }
- }
-
- lastcap++;
- lastcap = localCapabilities.SetCapability(0, lastcap, new H323_UserInputCapability(H323_UserInputCapability::HookFlashH245));
-
- lastcap++;
- dtmfMode = dtmf_mode;
- if (dtmf_mode == H323_DTMF_INBAND) {
- localCapabilities.SetCapability(0, lastcap, new H323_UserInputCapability(H323_UserInputCapability::BasicString));
- sendUserInputMode = SendUserInputAsString;
- } else {
- lastcap = localCapabilities.SetCapability(0, lastcap, new H323_UserInputCapability(H323_UserInputCapability::SignalToneRFC2833));
- /* Cisco sends DTMF only through h245-alphanumeric or h245-signal, no support for RFC2833 */
- lastcap = localCapabilities.SetCapability(0, lastcap, new H323_UserInputCapability(H323_UserInputCapability::SignalToneH245));
- sendUserInputMode = SendUserInputAsTone; /* RFC2833 transmission handled at Asterisk level */
- }
-
- if (h323debug) {
- cout << "Allowed Codecs:\n\t" << setprecision(2) << localCapabilities << endl;
- }
-}
-
-BOOL MyH323Connection::StartControlChannel(const H225_TransportAddress & h245Address)
-{
- // Check that it is an IP address, all we support at the moment
- if (h245Address.GetTag() != H225_TransportAddress::e_ipAddress
-#if P_HAS_IPV6
- && h245Address.GetTag() != H225_TransportAddress::e_ip6Address
-#endif
- ) {
- PTRACE(1, "H225\tConnect of H245 failed: Unsupported transport");
- return FALSE;
- }
-
- // Already have the H245 channel up.
- if (controlChannel != NULL)
- return TRUE;
-
- PIPSocket::Address addr;
- WORD port;
- GetSignallingChannel()->GetLocalAddress().GetIpAndPort(addr, port);
- if (addr) {
- if (h323debug)
- cout << "Using " << addr << " for outbound H.245 transport" << endl;
- controlChannel = new MyH323TransportTCP(endpoint, addr);
- } else
- controlChannel = new H323TransportTCP(endpoint);
- if (!controlChannel->SetRemoteAddress(h245Address)) {
- PTRACE(1, "H225\tCould not extract H245 address");
- delete controlChannel;
- controlChannel = NULL;
- return FALSE;
- }
- if (!controlChannel->Connect()) {
- PTRACE(1, "H225\tConnect of H245 failed: " << controlChannel->GetErrorText());
- delete controlChannel;
- controlChannel = NULL;
- return FALSE;
- }
-
- controlChannel->StartControlChannel(*this);
- return TRUE;
-}
-
-/* MyH323_ExternalRTPChannel */
-MyH323_ExternalRTPChannel::MyH323_ExternalRTPChannel(MyH323Connection & connection,
- const H323Capability & capability,
- Directions direction,
- unsigned id)
- : H323_ExternalRTPChannel::H323_ExternalRTPChannel(connection, capability, direction, id)
-{
- struct rtp_info *info;
-
- /* Determine the Local (A side) IP Address and port */
- info = on_external_rtp_create(connection.GetCallReference(), (const char *)connection.GetCallToken());
- if (!info) {
- cout << "\tERROR: on_external_rtp_create failure" << endl;
- return;
- } else {
- localIpAddr = info->addr;
- localPort = info->port;
- /* tell the H.323 stack */
- SetExternalAddress(H323TransportAddress(localIpAddr, localPort), H323TransportAddress(localIpAddr, localPort + 1));
- /* clean up allocated memory */
- free(info);
- }
-
- /* Get the payload code */
- OpalMediaFormat format(capability.GetFormatName(), FALSE);
- payloadCode = format.GetPayloadType();
-}
-
-MyH323_ExternalRTPChannel::~MyH323_ExternalRTPChannel()
-{
- if (h323debug) {
- cout << "\tExternalRTPChannel Destroyed" << endl;
- }
-}
-
-BOOL MyH323_ExternalRTPChannel::Start(void)
-{
- /* Call ancestor first */
- if (!H323_ExternalRTPChannel::Start()) {
- return FALSE;
- }
-
- if (h323debug) {
- cout << "\t\tExternal RTP Session Starting" << endl;
- cout << "\t\tRTP channel id " << sessionID << " parameters:" << endl;
- }
-
- /* Collect the remote information */
- H323_ExternalRTPChannel::GetRemoteAddress(remoteIpAddr, remotePort);
-
- if (h323debug) {
- cout << "\t\t-- remoteIpAddress: " << remoteIpAddr << endl;
- cout << "\t\t-- remotePort: " << remotePort << endl;
- cout << "\t\t-- ExternalIpAddress: " << localIpAddr << endl;
- cout << "\t\t-- ExternalPort: " << localPort << endl;
- }
- /* Notify Asterisk of remote RTP information */
- on_start_rtp_channel(connection.GetCallReference(), (const char *)remoteIpAddr.AsString(), remotePort,
- (const char *)connection.GetCallToken(), (int)payloadCode);
- return TRUE;
-}
-
-BOOL MyH323_ExternalRTPChannel::OnReceivedAckPDU(const H245_H2250LogicalChannelAckParameters & param)
-{
- if (h323debug) {
- cout << " MyH323_ExternalRTPChannel::OnReceivedAckPDU" << endl;
- }
-
- if (H323_ExternalRTPChannel::OnReceivedAckPDU(param)) {
- GetRemoteAddress(remoteIpAddr, remotePort);
- if (h323debug) {
- cout << " -- remoteIpAddress: " << remoteIpAddr << endl;
- cout << " -- remotePort: " << remotePort << endl;
- }
- on_start_rtp_channel(connection.GetCallReference(), (const char *)remoteIpAddr.AsString(),
- remotePort, (const char *)connection.GetCallToken(), (int)payloadCode);
- return TRUE;
- }
- return FALSE;
-}
-
-
-/** IMPLEMENTATION OF C FUNCTIONS */
-
-/**
- * The extern "C" directive takes care for
- * the ANSI-C representation of linkable symbols
- */
-
-extern "C" {
-
-int h323_end_point_exist(void)
-{
- if (!endPoint) {
- return 0;
- }
- return 1;
-}
-
-void h323_end_point_create(void)
-{
- channelsOpen = 0;
- logstream = new PAsteriskLog();
- localProcess = new MyProcess();
- localProcess->Main();
-}
-
-void h323_gk_urq(void)
-{
- if (!h323_end_point_exist()) {
- cout << " ERROR: [h323_gk_urq] No Endpoint, this is bad" << endl;
- return;
- }
- endPoint->RemoveGatekeeper();
-}
-
-void h323_debug(int flag, unsigned level)
-{
- if (flag) {
- PTrace:: SetLevel(level);
- } else {
- PTrace:: SetLevel(0);
- }
-}
-
-/** Installs the callback functions on behalf of the PBX application */
-void h323_callback_register(setup_incoming_cb ifunc,
- setup_outbound_cb sfunc,
- on_rtp_cb rtpfunc,
- start_rtp_cb lfunc,
- clear_con_cb clfunc,
- chan_ringing_cb rfunc,
- con_established_cb efunc,
- receive_digit_cb dfunc,
- answer_call_cb acfunc,
- progress_cb pgfunc,
- rfc2833_cb dtmffunc,
- hangup_cb hangupfunc,
- setcapabilities_cb capabilityfunc,
- setpeercapabilities_cb peercapabilityfunc)
-{
- on_incoming_call = ifunc;
- on_outgoing_call = sfunc;
- on_external_rtp_create = rtpfunc;
- on_start_rtp_channel = lfunc;
- on_connection_cleared = clfunc;
- on_chan_ringing = rfunc;
- on_connection_established = efunc;
- on_receive_digit = dfunc;
- on_answer_call = acfunc;
- on_progress = pgfunc;
- on_set_rfc2833_payload = dtmffunc;
- on_hangup = hangupfunc;
- on_setcapabilities = capabilityfunc;
- on_setpeercapabilities = peercapabilityfunc;
-}
-
-/**
- * Add capability to the capability table of the end point.
- */
-int h323_set_capabilities(const char *token, int cap, int dtmf_mode, struct ast_codec_pref *prefs, int pref_codec)
-{
- MyH323Connection *conn;
-
- if (!h323_end_point_exist()) {
- cout << " ERROR: [h323_set_capablities] No Endpoint, this is bad" << endl;
- return 1;
- }
- if (!token || !*token) {
- cout << " ERROR: [h323_set_capabilities] Invalid call token specified." << endl;
- return 1;
- }
-
- PString myToken(token);
- conn = (MyH323Connection *)endPoint->FindConnectionWithLock(myToken);
- if (!conn) {
- cout << " ERROR: [h323_set_capabilities] Unable to find connection " << token << endl;
- return 1;
- }
- conn->SetCapabilities((/*conn->bridging ? conn->redir_capabilities :*/ cap), dtmf_mode, prefs, pref_codec);
- conn->Unlock();
-
- return 0;
-}
-
-/** Start the H.323 listener */
-int h323_start_listener(int listenPort, struct sockaddr_in bindaddr)
-{
-
- if (!h323_end_point_exist()) {
- cout << "ERROR: [h323_start_listener] No Endpoint, this is bad!" << endl;
- return 1;
- }
-
- PIPSocket::Address interfaceAddress(bindaddr.sin_addr);
- if (!listenPort) {
- listenPort = 1720;
- }
- /** H.323 listener */
- H323ListenerTCP *tcpListener;
- tcpListener = new H323ListenerTCP(*endPoint, interfaceAddress, (WORD)listenPort);
- if (!endPoint->StartListener(tcpListener)) {
- cout << "ERROR: Could not open H.323 listener port on " << ((H323ListenerTCP *) tcpListener)->GetListenerPort() << endl;
- delete tcpListener;
- return 1;
- }
- cout << " == H.323 listener started" << endl;
- return 0;
-};
-
-int h323_set_alias(struct oh323_alias *alias)
-{
- char *p;
- char *num;
- PString h323id(alias->name);
- PString e164(alias->e164);
- char *prefix;
-
- if (!h323_end_point_exist()) {
- cout << "ERROR: [h323_set_alias] No Endpoint, this is bad!" << endl;
- return 1;
- }
-
- cout << "== Adding alias \"" << h323id << "\" to endpoint" << endl;
- endPoint->AddAliasName(h323id);
- endPoint->RemoveAliasName(localProcess->GetUserName());
-
- if (!e164.IsEmpty()) {
- cout << "== Adding E.164 \"" << e164 << "\" to endpoint" << endl;
- endPoint->AddAliasName(e164);
- }
- if (strlen(alias->prefix)) {
- p = prefix = strdup(alias->prefix);
- while((num = strsep(&p, ",")) != (char *)NULL) {
- cout << "== Adding Prefix \"" << num << "\" to endpoint" << endl;
- endPoint->SupportedPrefixes += PString(num);
- endPoint->SetGateway();
- }
- if (prefix)
- free(prefix);
- }
- return 0;
-}
-
-void h323_set_id(char *id)
-{
- PString h323id(id);
-
- if (h323debug) {
- cout << " == Using '" << h323id << "' as our H.323ID for this call" << endl;
- }
- /* EVIL HACK */
- endPoint->SetLocalUserName(h323id);
-}
-
-void h323_show_tokens(void)
-{
- cout << "Current call tokens: " << setprecision(2) << endPoint->GetAllConnections() << endl;
-}
-
-/** Establish Gatekeeper communiations, if so configured,
- * register aliases for the H.323 endpoint to respond to.
- */
-int h323_set_gk(int gatekeeper_discover, char *gatekeeper, char *secret)
-{
- PString gkName = PString(gatekeeper);
- PString pass = PString(secret);
- H323TransportUDP *rasChannel;
-
- if (!h323_end_point_exist()) {
- cout << "ERROR: [h323_set_gk] No Endpoint, this is bad!" << endl;
- return 1;
- }
-
- if (!gatekeeper) {
- cout << "Error: Gatekeeper cannot be NULL" << endl;
- return 1;
- }
- if (strlen(secret)) {
- endPoint->SetGatekeeperPassword(pass);
- }
- if (gatekeeper_discover) {
- /* discover the gk using multicast */
- if (endPoint->DiscoverGatekeeper(new MyH323TransportUDP(*endPoint))) {
- cout << "== Using " << (endPoint->GetGatekeeper())->GetName() << " as our Gatekeeper." << endl;
- } else {
- cout << "Warning: Could not find a gatekeeper." << endl;
- return 1;
- }
- } else {
- rasChannel = new MyH323TransportUDP(*endPoint);
-
- if (!rasChannel) {
- cout << "Error: No RAS Channel, this is bad" << endl;
- return 1;
- }
- if (endPoint->SetGatekeeper(gkName, rasChannel)) {
- cout << "== Using " << (endPoint->GetGatekeeper())->GetName() << " as our Gatekeeper." << endl;
- } else {
- cout << "Error registering with gatekeeper \"" << gkName << "\". " << endl;
- /* XXX Maybe we should fire a new thread to attempt to re-register later and not kill asterisk here? */
- return 1;
- }
- }
- return 0;
-}
-
-/** Send a DTMF tone over the H323Connection with the
- * specified token.
- */
-void h323_send_tone(const char *call_token, char tone)
-{
- if (!h323_end_point_exist()) {
- cout << "ERROR: [h323_send_tone] No Endpoint, this is bad!" << endl;
- return;
- }
- PString token = PString(call_token);
- endPoint->SendUserTone(token, tone);
-}
-
-/** Make a call to the remote endpoint.
- */
-int h323_make_call(char *dest, call_details_t *cd, call_options_t *call_options)
-{
- int res;
- PString token;
- PString host(dest);
-
- if (!h323_end_point_exist()) {
- return 1;
- }
-
- res = endPoint->MyMakeCall(host, token, &cd->call_reference, call_options);
- memcpy((char *)(cd->call_token), (const unsigned char *)token, token.GetLength());
- return res;
-};
-
-int h323_clear_call(const char *call_token, int cause)
-{
- H225_ReleaseCompleteReason dummy;
- H323Connection::CallEndReason r = H323Connection::EndedByLocalUser;
- MyH323Connection *connection;
- const PString currentToken(call_token);
-
- if (!h323_end_point_exist()) {
- return 1;
- }
-
- if (cause) {
- r = H323TranslateToCallEndReason((Q931::CauseValues)(cause), dummy);
- }
-
- connection = (MyH323Connection *)endPoint->FindConnectionWithLock(currentToken);
- if (connection) {
- connection->SetCause(cause);
- connection->SetCallEndReason(r);
- connection->Unlock();
- }
- endPoint->ClearCall(currentToken, r);
- return 0;
-};
-
-/* Send Alerting PDU to H.323 caller */
-int h323_send_alerting(const char *token)
-{
- const PString currentToken(token);
- H323Connection * connection;
-
- if (h323debug) {
- cout << "\tSending alerting" << endl;
- }
- connection = endPoint->FindConnectionWithLock(currentToken);
- if (!connection) {
- cout << "No connection found for " << token << endl;
- return -1;
- }
- connection->AnsweringCall(H323Connection::AnswerCallPending);
- connection->Unlock();
- return 0;
-}
-
-/* Send Progress PDU to H.323 caller */
-int h323_send_progress(const char *token)
-{
- const PString currentToken(token);
- H323Connection * connection;
-
- connection = endPoint->FindConnectionWithLock(currentToken);
- if (!connection) {
- cout << "No connection found for " << token << endl;
- return -1;
- }
-#if 1
- ((MyH323Connection *)connection)->MySendProgress();
-#else
- connection->AnsweringCall(H323Connection::AnswerCallDeferredWithMedia);
-#endif
- connection->Unlock();
- return 0;
-}
-
-/** This function tells the h.323 stack to either
- answer or deny an incoming call */
-int h323_answering_call(const char *token, int busy)
-{
- const PString currentToken(token);
- H323Connection * connection;
-
- connection = endPoint->FindConnectionWithLock(currentToken);
-
- if (!connection) {
- cout << "No connection found for " << token << endl;
- return -1;
- }
- if (!busy) {
- if (h323debug) {
- cout << "\tAnswering call " << token << endl;
- }
- connection->AnsweringCall(H323Connection::AnswerCallNow);
- } else {
- if (h323debug) {
- cout << "\tdenying call " << token << endl;
- }
- connection->AnsweringCall(H323Connection::AnswerCallDenied);
- }
- connection->Unlock();
- return 0;
-}
-
-int h323_soft_hangup(const char *data)
-{
- PString token(data);
- BOOL result;
- cout << "Soft hangup" << endl;
- result = endPoint->ClearCall(token);
- return result;
-}
-
-/* alas, this doesn't work :( */
-void h323_native_bridge(const char *token, const char *them, char *capability)
-{
- H323Channel *channel;
- MyH323Connection *connection = (MyH323Connection *)endPoint->FindConnectionWithLock(token);
-
- if (!connection) {
- cout << "ERROR: No connection found, this is bad" << endl;
- return;
- }
-
- cout << "Native Bridge: them [" << them << "]" << endl;
-
- channel = connection->FindChannel(connection->sessionId, TRUE);
- connection->bridging = TRUE;
- connection->CloseLogicalChannelNumber(channel->GetNumber());
-
- connection->Unlock();
- return;
-
-}
-
-#undef cout
-#undef endl
-void h323_end_process(void)
-{
- if (endPoint) {
- endPoint->ClearAllCalls();
- endPoint->RemoveListener(NULL);
- delete endPoint;
- endPoint = NULL;
- }
- if (localProcess) {
- delete localProcess;
- localProcess = NULL;
-#ifndef SKIP_PWLIB_PIPE_BUG_WORKAROUND
- close(_timerChangePipe[0]);
- close(_timerChangePipe[1]);
-#endif
- }
- if (logstream) {
- PTrace::SetLevel(0);
- PTrace::SetStream(&cout);
- delete logstream;
- logstream = NULL;
- }
-}
-
-} /* extern "C" */
-
diff --git a/1.4.23-rc4/channels/h323/ast_h323.h b/1.4.23-rc4/channels/h323/ast_h323.h
deleted file mode 100644
index c4f24c529..000000000
--- a/1.4.23-rc4/channels/h323/ast_h323.h
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * ast_h323.h
- *
- * OpenH323 Channel Driver for ASTERISK PBX.
- * By Jeremy McNamara
- * For The NuFone Network
- *
- * This code has been derived from code created by
- * Michael Manousos and Mark Spencer
- *
- * This file is part of the chan_h323 driver for Asterisk
- *
- * chan_h323 is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * chan_h323 is distributed WITHOUT ANY WARRANTY; without even
- * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Version Info: $Id$
- */
-
-#ifndef AST_H323_H
-#define AST_H323_H
-
-#define VERSION(a,b,c) ((a)*10000+(b)*100+(c))
-
-class MyH323EndPoint : public H323EndPoint
-{
- PCLASSINFO(MyH323EndPoint, H323EndPoint);
-
-public:
- MyH323EndPoint();
- int MyMakeCall(const PString &, PString &, void *_callReference, void *_opts);
- BOOL ClearCall(const PString &, H323Connection::CallEndReason reason);
- BOOL ClearCall(const PString &);
-
- void OnClosedLogicalChannel(H323Connection &, const H323Channel &);
- void OnConnectionEstablished(H323Connection &, const PString &);
- void OnConnectionCleared(H323Connection &, const PString &);
- virtual H323Connection * CreateConnection(unsigned, void *, H323Transport *, H323SignalPDU *);
- void SendUserTone(const PString &, char);
- BOOL OnConnectionForwarded(H323Connection &, const PString &, const H323SignalPDU &);
- BOOL ForwardConnection(H323Connection &, const PString &, const H323SignalPDU &);
- void SetEndpointTypeInfo( H225_EndpointType & info ) const;
- void SetGateway(void);
- PStringArray SupportedPrefixes;
-};
-
-class MyH323Connection : public H323Connection
-{
- PCLASSINFO(MyH323Connection, H323Connection);
-
-public:
- MyH323Connection(MyH323EndPoint &, unsigned, unsigned);
- ~MyH323Connection();
- H323Channel * CreateRealTimeLogicalChannel(const H323Capability &,
- H323Channel::Directions,
- unsigned,
- const H245_H2250LogicalChannelParameters *,
- RTP_QOS *);
- H323Connection::AnswerCallResponse OnAnswerCall(const PString &,
- const H323SignalPDU &,
- H323SignalPDU &);
- void OnReceivedReleaseComplete(const H323SignalPDU &);
- BOOL OnAlerting(const H323SignalPDU &, const PString &);
- BOOL OnSendReleaseComplete(H323SignalPDU &);
- BOOL OnReceivedSignalSetup(const H323SignalPDU &);
- BOOL OnReceivedFacility(const H323SignalPDU &);
- BOOL OnSendSignalSetup(H323SignalPDU &);
- BOOL OnStartLogicalChannel(H323Channel &);
- BOOL OnClosingLogicalChannel(H323Channel &);
- virtual void SendUserInputTone(char tone, unsigned duration = 0, unsigned logicalChannel = 0, unsigned rtpTimestamp = 0);
- virtual void OnUserInputTone(char, unsigned, unsigned, unsigned);
- virtual void OnUserInputString(const PString &value);
- BOOL OnReceivedProgress(const H323SignalPDU &);
- BOOL MySendProgress();
- void OnSendCapabilitySet(H245_TerminalCapabilitySet &);
- void OnSetLocalCapabilities();
- void SetCapabilities(int, int, void *, int);
- BOOL OnReceivedCapabilitySet(const H323Capabilities &, const H245_MultiplexCapability *,
- H245_TerminalCapabilitySetReject &);
- void SetCause(int _cause) { cause = _cause; };
- virtual BOOL StartControlChannel(const H225_TransportAddress & h245Address);
- void SetCallOptions(void *opts, BOOL isIncoming);
- void SetCallDetails(void *callDetails, const H323SignalPDU &setupPDU, BOOL isIncoming);
- virtual H323Connection::CallEndReason SendSignalSetup(const PString&, const H323TransportAddress&);
-#ifdef TUNNELLING
- virtual BOOL HandleSignalPDU(H323SignalPDU &pdu);
- BOOL EmbedTunneledInfo(H323SignalPDU &pdu);
-#endif
-
- PString sourceAliases;
- PString destAliases;
- PString sourceE164;
- PString destE164;
- int cid_presentation;
- int cid_ton;
- PString rdnis;
- int redirect_reason;
- int transfer_capability;
-
- WORD sessionId;
- BOOL bridging;
-#ifdef TUNNELLING
- int remoteTunnelOptions;
- int tunnelOptions;
-#endif
-
- unsigned progressSetup;
- unsigned progressAlert;
- int cause;
-
- RTP_DataFrame::PayloadTypes dtmfCodec;
- int dtmfMode;
-};
-
-class MyH323_ExternalRTPChannel : public H323_ExternalRTPChannel
-{
- PCLASSINFO(MyH323_ExternalRTPChannel, H323_ExternalRTPChannel);
-
-public:
- MyH323_ExternalRTPChannel(
- MyH323Connection & connection,
- const H323Capability & capability,
- Directions direction,
- unsigned sessionID);
-
- ~MyH323_ExternalRTPChannel();
-
- /* Overrides */
- BOOL Start(void);
- BOOL OnReceivedAckPDU(const H245_H2250LogicalChannelAckParameters & param);
-
-protected:
- BYTE payloadCode;
-
- PIPSocket::Address localIpAddr;
- PIPSocket::Address remoteIpAddr;
- WORD localPort;
- WORD remotePort;
-};
-
-/**
- * The MyProcess is a necessary descendant PProcess class so that the H323EndPoint
- * objected to be created from within that class. (Solves the who owns main() problem).
- */
-class MyProcess : public PProcess
-{
- PCLASSINFO(MyProcess, PProcess);
-
-public:
- MyProcess();
- ~MyProcess();
- void Main();
-};
-
-#include "compat_h323.h"
-
-#endif /* !defined AST_H323_H */
diff --git a/1.4.23-rc4/channels/h323/caps_h323.cxx b/1.4.23-rc4/channels/h323/caps_h323.cxx
deleted file mode 100644
index a420825a3..000000000
--- a/1.4.23-rc4/channels/h323/caps_h323.cxx
+++ /dev/null
@@ -1,239 +0,0 @@
-#include <ptlib.h>
-#include <h323.h>
-#include <h245.h>
-#include "ast_h323.h"
-#include "caps_h323.h"
-
-#define DEFINE_G711_CAPABILITY(cls, code, capName) \
-class cls : public AST_G711Capability { \
- public: \
- cls() : AST_G711Capability(240, code) { } \
-}; \
-H323_REGISTER_CAPABILITY(cls, capName) \
-
-DEFINE_G711_CAPABILITY(AST_G711ALaw64Capability, H323_G711Capability::ALaw, OPAL_G711_ALAW_64K);
-DEFINE_G711_CAPABILITY(AST_G711uLaw64Capability, H323_G711Capability::muLaw, OPAL_G711_ULAW_64K);
-H323_REGISTER_CAPABILITY(AST_G7231Capability, OPAL_G7231);
-H323_REGISTER_CAPABILITY(AST_G729Capability, OPAL_G729);
-H323_REGISTER_CAPABILITY(AST_G729ACapability, OPAL_G729A);
-H323_REGISTER_CAPABILITY(AST_GSM0610Capability, OPAL_GSM0610);
-
-/*
- * Capability: G.711
- */
-AST_G711Capability::AST_G711Capability(int rx_frames, H323_G711Capability::Mode m, H323_G711Capability::Speed s)
- : H323AudioCapability(rx_frames, 30) // 240ms max, 30ms desired
-{
- mode = m;
- speed = s;
-}
-
-
-PObject * AST_G711Capability::Clone() const
-{
- return new AST_G711Capability(*this);
-}
-
-
-unsigned AST_G711Capability::GetSubType() const
-{
- static const unsigned G711SubType[2][2] = {
- { H245_AudioCapability::e_g711Alaw64k, H245_AudioCapability::e_g711Alaw56k },
- { H245_AudioCapability::e_g711Ulaw64k, H245_AudioCapability::e_g711Ulaw56k }
- };
- return G711SubType[mode][speed];
-}
-
-
-PString AST_G711Capability::GetFormatName() const
-{
- static const char * const G711Name[2][2] = {
- { OPAL_G711_ALAW_64K, OPAL_G711_ALAW_56K },
- { OPAL_G711_ULAW_64K, OPAL_G711_ULAW_56K },
- };
- return G711Name[mode][speed];
-}
-
-
-H323Codec * AST_G711Capability::CreateCodec(H323Codec::Direction direction) const
-{
- return NULL;
-}
-
-
-/*
- * Capability: G.723.1
- */
-AST_G7231Capability::AST_G7231Capability(int rx_frames, BOOL annexA_)
- : H323AudioCapability(rx_frames, 4)
-{
- annexA = annexA_;
-}
-
-PObject::Comparison AST_G7231Capability::Compare(const PObject & obj) const
-{
- Comparison result = H323AudioCapability::Compare(obj);
- if (result != EqualTo) {
- return result;
- }
- PINDEX otherAnnexA = ((const AST_G7231Capability &)obj).annexA;
- if (annexA < otherAnnexA) {
- return LessThan;
- }
- if (annexA > otherAnnexA) {
- return GreaterThan;
- }
- return EqualTo;
-}
-
-PObject * AST_G7231Capability::Clone() const
-{
- return new AST_G7231Capability(*this);
-}
-
-PString AST_G7231Capability::GetFormatName() const
-{
- return (annexA ? OPAL_G7231 "A" : OPAL_G7231);
-}
-
-unsigned AST_G7231Capability::GetSubType() const
-{
- return H245_AudioCapability::e_g7231;
-}
-
-BOOL AST_G7231Capability::OnSendingPDU(H245_AudioCapability & cap,
- unsigned packetSize) const
-{
- cap.SetTag(H245_AudioCapability::e_g7231);
- H245_AudioCapability_g7231 & g7231 = cap;
- g7231.m_maxAl_sduAudioFrames = packetSize;
- g7231.m_silenceSuppression = annexA;
- return TRUE;
-}
-
-BOOL AST_G7231Capability::OnReceivedPDU(const H245_AudioCapability & cap,
- unsigned & packetSize)
-{
- if (cap.GetTag() != H245_AudioCapability::e_g7231) {
- return FALSE;
- }
- const H245_AudioCapability_g7231 & g7231 = cap;
- packetSize = g7231.m_maxAl_sduAudioFrames;
- annexA = g7231.m_silenceSuppression;
- return TRUE;
-}
-
-H323Codec * AST_G7231Capability::CreateCodec(H323Codec::Direction direction) const
-{
- return NULL;
-}
-
-/*
- * Capability: G.729
- */
-AST_G729Capability::AST_G729Capability(int rx_frames)
- : H323AudioCapability(rx_frames, 2)
-{
-}
-
-PObject * AST_G729Capability::Clone() const
-{
- return new AST_G729Capability(*this);
-}
-
-unsigned AST_G729Capability::GetSubType() const
-{
- return H245_AudioCapability::e_g729;
-}
-
-PString AST_G729Capability::GetFormatName() const
-{
- return OPAL_G729;
-}
-
-H323Codec * AST_G729Capability::CreateCodec(H323Codec::Direction direction) const
-{
- return NULL;
-}
-
-/*
- * Capability: G.729A
- */
-AST_G729ACapability::AST_G729ACapability(int rx_frames)
- : H323AudioCapability(rx_frames, 6)
-{
-}
-
-PObject * AST_G729ACapability::Clone() const
-{
- return new AST_G729ACapability(*this);
-}
-
-unsigned AST_G729ACapability::GetSubType() const
-{
- return H245_AudioCapability::e_g729AnnexA;
-}
-
-PString AST_G729ACapability::GetFormatName() const
-{
- return OPAL_G729A;
-}
-
-H323Codec * AST_G729ACapability::CreateCodec(H323Codec::Direction direction) const
-{
- return NULL;
-}
-
-/*
- * Capability: GSM full rate
- */
-AST_GSM0610Capability::AST_GSM0610Capability(int rx_frames, int comfortNoise_, int scrambled_)
- : H323AudioCapability(rx_frames, 2)
-{
- comfortNoise = comfortNoise_;
- scrambled = scrambled_;
-}
-
-PObject * AST_GSM0610Capability::Clone() const
-{
- return new AST_GSM0610Capability(*this);
-}
-
-unsigned AST_GSM0610Capability::GetSubType() const
-{
- return H245_AudioCapability::e_gsmFullRate;
-}
-
-BOOL AST_GSM0610Capability::OnSendingPDU(H245_AudioCapability & cap,
- unsigned packetSize) const
-{
- cap.SetTag(H245_AudioCapability::e_gsmFullRate);
- H245_GSMAudioCapability & gsm = cap;
- gsm.m_audioUnitSize = packetSize * 33;
- gsm.m_comfortNoise = comfortNoise;
- gsm.m_scrambled = scrambled;
- return TRUE;
-}
-
-BOOL AST_GSM0610Capability::OnReceivedPDU(const H245_AudioCapability & cap,
- unsigned & packetSize)
-{
- if (cap.GetTag() != H245_AudioCapability::e_gsmFullRate)
- return FALSE;
- const H245_GSMAudioCapability & gsm = cap;
- packetSize = (gsm.m_audioUnitSize + 32) / 33;
- comfortNoise = gsm.m_comfortNoise;
- scrambled = gsm.m_scrambled;
-
- return TRUE;
-}
-
-PString AST_GSM0610Capability::GetFormatName() const
-{
- return OPAL_GSM0610;
-}
-
-H323Codec * AST_GSM0610Capability::CreateCodec(H323Codec::Direction direction) const
-{
- return NULL;
-}
diff --git a/1.4.23-rc4/channels/h323/caps_h323.h b/1.4.23-rc4/channels/h323/caps_h323.h
deleted file mode 100644
index be63e0230..000000000
--- a/1.4.23-rc4/channels/h323/caps_h323.h
+++ /dev/null
@@ -1,124 +0,0 @@
-#ifndef __AST_H323CAPS_H
-#define __AST_H323CAPS_H
-
-/**This class describes the G.711 codec capability.
- */
-class AST_G711Capability : public H323AudioCapability
-{
- PCLASSINFO(AST_G711Capability, H323AudioCapability);
-
-public:
- AST_G711Capability(int rx_frames = 125, H323_G711Capability::Mode _mode = H323_G711Capability::muLaw, H323_G711Capability::Speed _speed = H323_G711Capability::At64k);
- virtual PObject *Clone() const;
- virtual H323Codec * CreateCodec(H323Codec::Direction direction) const;
- virtual unsigned GetSubType() const;
- virtual PString GetFormatName() const;
-
-protected:
- H323_G711Capability::Mode mode;
- H323_G711Capability::Speed speed;
-};
-
-/**This class describes the G.723.1 codec capability.
- */
-class AST_G7231Capability : public H323AudioCapability
-{
- PCLASSINFO(AST_G7231Capability, H323AudioCapability);
-
-public:
- AST_G7231Capability(int rx_frames = 7, BOOL annexA = TRUE);
- Comparison Compare(const PObject & obj) const;
- virtual PObject * Clone() const;
- virtual H323Codec * CreateCodec(H323Codec::Direction direction) const;
- virtual unsigned GetSubType() const;
- virtual PString GetFormatName() const;
- virtual BOOL OnSendingPDU(H245_AudioCapability & pdu, unsigned packetSize) const;
- virtual BOOL OnReceivedPDU(const H245_AudioCapability & pdu, unsigned & packetSize);
-
-protected:
- BOOL annexA;
-};
-
-/**This class describes the (fake) G729 codec capability.
- */
-class AST_G729Capability : public H323AudioCapability
-{
- PCLASSINFO(AST_G729Capability, H323AudioCapability);
-
-public:
- AST_G729Capability(int rx_frames = 24);
- /* Create a copy of the object. */
- virtual PObject * Clone() const;
-
- /* Create the codec instance, allocating resources as required. */
- virtual H323Codec * CreateCodec(H323Codec::Direction direction) const;
-
- /* Get the sub-type of the capability. This is a code dependent on the
- main type of the capability.
-
- This returns one of the four possible combinations of mode and speed
- using the enum values of the protocol ASN H245_AudioCapability class. */
- virtual unsigned GetSubType() const;
-
- /* Get the name of the media data format this class represents. */
- virtual PString GetFormatName() const;
-};
-
-/* This class describes the VoiceAge G729A codec capability. */
-class AST_G729ACapability : public H323AudioCapability
-{
- PCLASSINFO(AST_G729ACapability, H323AudioCapability);
-
-public:
- /* Create a new G.729A capability. */
- AST_G729ACapability(int rx_frames = 24);
-
- /* Create a copy of the object. */
- virtual PObject * Clone() const;
- /* Create the codec instance, allocating resources as required. */
- virtual H323Codec * CreateCodec(H323Codec::Direction direction) const;
-
- /* Get the sub-type of the capability. This is a code dependent on the
- main type of the capability.
-
- This returns one of the four possible combinations of mode and speed
- using the enum values of the protocol ASN H245_AudioCapability class. */
- virtual unsigned GetSubType() const;
-
- /* Get the name of the media data format this class represents. */
- virtual PString GetFormatName() const;
-};
-
-/* This class describes the GSM-06.10 codec capability. */
-class AST_GSM0610Capability : public H323AudioCapability
-{
- PCLASSINFO(AST_GSM0610Capability, H323AudioCapability);
-
-public:
- /* Create a new GSM capability. */
- AST_GSM0610Capability(int rx_frames = 24, int comfortNoise = 0, int scrambled = 0);
-
- /* Create a copy of the object. */
- virtual PObject * Clone() const;
-
- /* Create the codec instance, allocating resources as required. */
- virtual H323Codec * CreateCodec(H323Codec::Direction direction) const;
-
- /* Get the sub-type of the capability. This is a code dependent on the
- main type of the capability.
-
- This returns one of the four possible combinations of mode and speed
- using the enum values of the protocol ASN H245_AudioCapability class. */
- virtual unsigned GetSubType() const;
-
- /* Get the name of the media data format this class represents. */
- virtual PString GetFormatName() const;
-
- BOOL OnSendingPDU(H245_AudioCapability & pdu, unsigned packetSize) const;
- BOOL OnReceivedPDU(const H245_AudioCapability & pdu, unsigned & packetSize);
-
-protected:
- int comfortNoise;
- int scrambled;
-};
-#endif /* __AST_H323CAPS_H */
diff --git a/1.4.23-rc4/channels/h323/chan_h323.h b/1.4.23-rc4/channels/h323/chan_h323.h
deleted file mode 100644
index 0fd94561f..000000000
--- a/1.4.23-rc4/channels/h323/chan_h323.h
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * chan_h323.h
- *
- * OpenH323 Channel Driver for ASTERISK PBX.
- * By Jeremy McNamara
- * For The NuFone Network
- *
- * This code has been derived from code created by
- * Michael Manousos and Mark Spencer
- *
- * This file is part of the chan_h323 driver for Asterisk
- *
- * chan_h323 is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * chan_h323 is distributed WITHOUT ANY WARRANTY; without even
- * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Version Info: $Id$
- */
-
-#include <arpa/inet.h>
-
-/*
- * Enable support for sending/reception of tunnelled Q.SIG messages and
- * some sort of IEs (especially RedirectingNumber) which Cisco CallManager
- * isn't like to pass in standard Q.931 message.
- *
- */
-#define TUNNELLING
-
-#define H323_TUNNEL_CISCO (1 << 0)
-#define H323_TUNNEL_QSIG (1 << 1)
-
-/** call_option struct holds various bits
- * of information for each call */
-typedef struct call_options {
- char cid_num[80];
- char cid_name[80];
- char cid_rdnis[80];
- int redirect_reason;
- int presentation;
- int type_of_number;
- int transfer_capability;
- int fastStart;
- int h245Tunneling;
- int silenceSuppression;
- int progress_setup;
- int progress_alert;
- int progress_audio;
- int dtmfcodec;
- int dtmfmode;
- int capability;
- int bridge;
- int nat;
- int tunnelOptions;
- struct ast_codec_pref prefs;
-} call_options_t;
-
-/* structure to hold the valid asterisk users */
-struct oh323_user {
- ASTOBJ_COMPONENTS(struct oh323_user);
-// char name[80];
- char context[80];
- char secret[80];
- char accountcode[AST_MAX_ACCOUNT_CODE];
- int amaflags;
- int host;
- struct sockaddr_in addr;
- struct ast_ha *ha;
- call_options_t options;
-};
-
-/* structure to hold the valid asterisk peers
- All peers are registered to a GK if there is one */
-struct oh323_peer {
- ASTOBJ_COMPONENTS(struct oh323_peer);
- char mailbox[80];
- int delme;
- struct sockaddr_in addr;
- struct ast_ha *ha;
- call_options_t options;
-};
-
-/* structure to hold the H.323 aliases which get registered to
- the H.323 endpoint and gatekeeper */
-struct oh323_alias {
- ASTOBJ_COMPONENTS(struct oh323_alias);
- char e164[20]; /* tells a GK to route this E.164 to this alias */
- char prefix[500]; /* tells a GK this alias supports these prefixes */
- char secret[20]; /* the H.235 password to send to the GK for authentication */
- char context[80];
-};
-
-/** call_details struct call detail records
- to asterisk for processing and used for matching up
- asterisk channels to acutal h.323 connections */
-typedef struct call_details {
- unsigned int call_reference;
- char *call_token;
- char *call_source_aliases;
- char *call_dest_alias;
- char *call_source_name;
- char *call_source_e164;
- char *call_dest_e164;
- char *redirect_number;
- int redirect_reason;
- int presentation;
- int type_of_number;
- int transfer_capability;
- char *sourceIp;
-} call_details_t;
-
-typedef struct rtp_info {
- char addr[32];
- unsigned int port;
-} rtp_info_t;
-
-/* This is a callback prototype function, called pass
- DTMF down the RTP. */
-typedef int (*receive_digit_cb)(unsigned, char, const char *, int);
-extern receive_digit_cb on_receive_digit;
-
-/* This is a callback prototype function, called to collect
- the external RTP port from Asterisk. */
-typedef rtp_info_t *(*on_rtp_cb)(unsigned, const char *);
-extern on_rtp_cb on_external_rtp_create;
-
-/* This is a callback prototype function, called to send
- the remote IP and RTP port from H.323 to Asterisk */
-typedef void (*start_rtp_cb)(unsigned int, const char *, int, const char *, int);
-extern start_rtp_cb on_start_rtp_channel;
-
-/* This is a callback that happens when call progress is
- * made, and handles inband progress */
-typedef int (*progress_cb)(unsigned, const char *, int);
-extern progress_cb on_progress;
-
-/* This is a callback prototype function, called upon
- an incoming call happens. */
-typedef call_options_t *(*setup_incoming_cb)(call_details_t *);
-extern setup_incoming_cb on_incoming_call;
-
-/* This is a callback prototype function, called upon
- an outbound call. */
-typedef int (*setup_outbound_cb)(call_details_t *);
-extern setup_outbound_cb on_outgoing_call;
-
-/* This is a callback prototype function, called when
- OnAlerting is invoked */
-typedef void (*chan_ringing_cb)(unsigned, const char *);
-extern chan_ringing_cb on_chan_ringing;
-
-/* This is a callback protoype function, called when
- OnConnectionEstablished is inovked */
-typedef void (*con_established_cb)(unsigned, const char *);
-extern con_established_cb on_connection_established;
-
-/* This is a callback prototype function, called when
- OnConnectionCleared callback is invoked */
-typedef void (*clear_con_cb)(unsigned, const char *);
-extern clear_con_cb on_connection_cleared;
-
-/* This is a callback prototype function, called when
- an H.323 call is answered */
-typedef int (*answer_call_cb)(unsigned, const char *);
-extern answer_call_cb on_answer_call;
-
-/* This is a callback prototype function, called when
- we know which RTP payload type RFC2833 will be
- transmitted */
-typedef void (*rfc2833_cb)(unsigned, const char *, int);
-extern rfc2833_cb on_set_rfc2833_payload;
-
-typedef void (*hangup_cb)(unsigned, const char *, int);
-extern hangup_cb on_hangup;
-
-typedef void (*setcapabilities_cb)(unsigned, const char *);
-extern setcapabilities_cb on_setcapabilities;
-
-typedef void (*setpeercapabilities_cb)(unsigned, const char *, int, struct ast_codec_pref *);
-extern setpeercapabilities_cb on_setpeercapabilities;
-
-/* debug flag */
-extern int h323debug;
-
-#define H323_DTMF_RFC2833 (1 << 0)
-#define H323_DTMF_INBAND (1 << 1)
-
-#ifndef BOOL
-#define BOOL int
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
- void h323_gk_urq(void);
- void h323_end_point_create(void);
- void h323_end_process(void);
- int h323_end_point_exist(void);
-
- void h323_debug(int, unsigned);
-
- /* callback function handler*/
- void h323_callback_register(setup_incoming_cb,
- setup_outbound_cb,
- on_rtp_cb,
- start_rtp_cb,
- clear_con_cb,
- chan_ringing_cb,
- con_established_cb,
- receive_digit_cb,
- answer_call_cb,
- progress_cb,
- rfc2833_cb,
- hangup_cb,
- setcapabilities_cb,
- setpeercapabilities_cb);
- int h323_set_capabilities(const char *, int, int, struct ast_codec_pref *, int);
- int h323_set_alias(struct oh323_alias *);
- int h323_set_gk(int, char *, char *);
- void h323_set_id(char *);
- void h323_show_tokens(void);
-
- /* H323 listener related funcions */
- int h323_start_listener(int, struct sockaddr_in);
-
- void h323_native_bridge(const char *, const char *, char *);
-
- /* Send a DTMF tone to remote endpoint */
- void h323_send_tone(const char *call_token, char tone);
-
- /* H323 create and destroy sessions */
- int h323_make_call(char *dest, call_details_t *cd, call_options_t *);
- int h323_clear_call(const char *, int cause);
-
- /* H.323 alerting and progress */
- int h323_send_alerting(const char *token);
- int h323_send_progress(const char *token);
- int h323_answering_call(const char *token, int);
- int h323_soft_hangup(const char *data);
- int h323_show_codec(int fd, int argc, char *argv[]);
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/1.4.23-rc4/channels/h323/cisco-h225.asn b/1.4.23-rc4/channels/h323/cisco-h225.asn
deleted file mode 100644
index 1372e67d5..000000000
--- a/1.4.23-rc4/channels/h323/cisco-h225.asn
+++ /dev/null
@@ -1,74 +0,0 @@
-CISCO-H225-MESSAGES DEFINITIONS AUTOMATIC TAGS ::=
-BEGIN
-
-H323_UU_NonStdInfo ::= SEQUENCE
-{
- version INTEGER OPTIONAL,
- protoParam ProtoParam OPTIONAL,
- commonParam CommonParam OPTIONAL,
- ...,
- dummy1 OCTET STRING OPTIONAL,
- progIndParam ProgIndParam OPTIONAL,
- callMgrParam CallMgrParam OPTIONAL,
- callSignallingParam CallSignallingParam OPTIONAL,
- dummy2 OCTET STRING OPTIONAL,
- callPreserveParam CallPreserveParam OPTIONAL
-}
-
-CommonParam ::= SEQUENCE
-{
- redirectIEinfo RedirectIEinfo,
- ...
-}
-
-RedirectIEinfo ::= SEQUENCE
-{
- redirectIE OCTET STRING,
- ...
-}
-
-ProgIndParam ::= SEQUENCE
-{
- progIndIEinfo ProgIndIEinfo,
- ...
-}
-
-ProgIndIEinfo ::= SEQUENCE
-{
- progIndIE OCTET STRING,
- ...
-}
-
-ProtoParam ::= SEQUENCE
-{
- qsigNonStdInfo QsigNonStdInfo,
- ...
-}
-
-QsigNonStdInfo ::= SEQUENCE
-{
- iei INTEGER,
- rawMesg OCTET STRING,
- ...
-}
-
-CallMgrParam ::= SEQUENCE
-{
- interclusterVersion INTEGER,
- enterpriseID OCTET STRING,
- ...
-}
-
-CallPreserveParam ::= SEQUENCE
-{
- callPreserveIE BOOLEAN,
- ...
-}
-
-CallSignallingParam ::= SEQUENCE
-{
- connectedNumber OCTET STRING (1..127) OPTIONAL,
- ...
-}
-
-END
diff --git a/1.4.23-rc4/channels/h323/cisco-h225.cxx b/1.4.23-rc4/channels/h323/cisco-h225.cxx
deleted file mode 100644
index 37adc4e87..000000000
--- a/1.4.23-rc4/channels/h323/cisco-h225.cxx
+++ /dev/null
@@ -1,853 +0,0 @@
-//
-// cisco-h225.cxx
-//
-// Code automatically generated by asnparse.
-//
-
-#ifdef P_USE_PRAGMA
-#pragma implementation "cisco-h225.h"
-#endif
-
-#include <ptlib.h>
-#include "cisco-h225.h"
-
-#define new PNEW
-
-
-#if ! H323_DISABLE_CISCO_H225
-
-//
-// RedirectIEinfo
-//
-
-CISCO_H225_RedirectIEinfo::CISCO_H225_RedirectIEinfo(unsigned tag, PASN_Object::TagClass tagClass)
- : PASN_Sequence(tag, tagClass, 0, TRUE, 0)
-{
-}
-
-
-#ifndef PASN_NOPRINTON
-void CISCO_H225_RedirectIEinfo::PrintOn(ostream & strm) const
-{
- int indent = strm.precision() + 2;
- strm << "{\n";
- strm << setw(indent+13) << "redirectIE = " << setprecision(indent) << m_redirectIE << '\n';
- strm << setw(indent-1) << setprecision(indent-2) << "}";
-}
-#endif
-
-
-PObject::Comparison CISCO_H225_RedirectIEinfo::Compare(const PObject & obj) const
-{
-#ifndef PASN_LEANANDMEAN
- PAssert(PIsDescendant(&obj, CISCO_H225_RedirectIEinfo), PInvalidCast);
-#endif
- const CISCO_H225_RedirectIEinfo & other = (const CISCO_H225_RedirectIEinfo &)obj;
-
- Comparison result;
-
- if ((result = m_redirectIE.Compare(other.m_redirectIE)) != EqualTo)
- return result;
-
- return PASN_Sequence::Compare(other);
-}
-
-
-PINDEX CISCO_H225_RedirectIEinfo::GetDataLength() const
-{
- PINDEX length = 0;
- length += m_redirectIE.GetObjectLength();
- return length;
-}
-
-
-BOOL CISCO_H225_RedirectIEinfo::Decode(PASN_Stream & strm)
-{
- if (!PreambleDecode(strm))
- return FALSE;
-
- if (!m_redirectIE.Decode(strm))
- return FALSE;
-
- return UnknownExtensionsDecode(strm);
-}
-
-
-void CISCO_H225_RedirectIEinfo::Encode(PASN_Stream & strm) const
-{
- PreambleEncode(strm);
-
- m_redirectIE.Encode(strm);
-
- UnknownExtensionsEncode(strm);
-}
-
-
-PObject * CISCO_H225_RedirectIEinfo::Clone() const
-{
-#ifndef PASN_LEANANDMEAN
- PAssert(IsClass(CISCO_H225_RedirectIEinfo::Class()), PInvalidCast);
-#endif
- return new CISCO_H225_RedirectIEinfo(*this);
-}
-
-
-//
-// ProgIndIEinfo
-//
-
-CISCO_H225_ProgIndIEinfo::CISCO_H225_ProgIndIEinfo(unsigned tag, PASN_Object::TagClass tagClass)
- : PASN_Sequence(tag, tagClass, 0, TRUE, 0)
-{
-}
-
-
-#ifndef PASN_NOPRINTON
-void CISCO_H225_ProgIndIEinfo::PrintOn(ostream & strm) const
-{
- int indent = strm.precision() + 2;
- strm << "{\n";
- strm << setw(indent+12) << "progIndIE = " << setprecision(indent) << m_progIndIE << '\n';
- strm << setw(indent-1) << setprecision(indent-2) << "}";
-}
-#endif
-
-
-PObject::Comparison CISCO_H225_ProgIndIEinfo::Compare(const PObject & obj) const
-{
-#ifndef PASN_LEANANDMEAN
- PAssert(PIsDescendant(&obj, CISCO_H225_ProgIndIEinfo), PInvalidCast);
-#endif
- const CISCO_H225_ProgIndIEinfo & other = (const CISCO_H225_ProgIndIEinfo &)obj;
-
- Comparison result;
-
- if ((result = m_progIndIE.Compare(other.m_progIndIE)) != EqualTo)
- return result;
-
- return PASN_Sequence::Compare(other);
-}
-
-
-PINDEX CISCO_H225_ProgIndIEinfo::GetDataLength() const
-{
- PINDEX length = 0;
- length += m_progIndIE.GetObjectLength();
- return length;
-}
-
-
-BOOL CISCO_H225_ProgIndIEinfo::Decode(PASN_Stream & strm)
-{
- if (!PreambleDecode(strm))
- return FALSE;
-
- if (!m_progIndIE.Decode(strm))
- return FALSE;
-
- return UnknownExtensionsDecode(strm);
-}
-
-
-void CISCO_H225_ProgIndIEinfo::Encode(PASN_Stream & strm) const
-{
- PreambleEncode(strm);
-
- m_progIndIE.Encode(strm);
-
- UnknownExtensionsEncode(strm);
-}
-
-
-PObject * CISCO_H225_ProgIndIEinfo::Clone() const
-{
-#ifndef PASN_LEANANDMEAN
- PAssert(IsClass(CISCO_H225_ProgIndIEinfo::Class()), PInvalidCast);
-#endif
- return new CISCO_H225_ProgIndIEinfo(*this);
-}
-
-
-//
-// QsigNonStdInfo
-//
-
-CISCO_H225_QsigNonStdInfo::CISCO_H225_QsigNonStdInfo(unsigned tag, PASN_Object::TagClass tagClass)
- : PASN_Sequence(tag, tagClass, 0, TRUE, 0)
-{
-}
-
-
-#ifndef PASN_NOPRINTON
-void CISCO_H225_QsigNonStdInfo::PrintOn(ostream & strm) const
-{
- int indent = strm.precision() + 2;
- strm << "{\n";
- strm << setw(indent+6) << "iei = " << setprecision(indent) << m_iei << '\n';
- strm << setw(indent+10) << "rawMesg = " << setprecision(indent) << m_rawMesg << '\n';
- strm << setw(indent-1) << setprecision(indent-2) << "}";
-}
-#endif
-
-
-PObject::Comparison CISCO_H225_QsigNonStdInfo::Compare(const PObject & obj) const
-{
-#ifndef PASN_LEANANDMEAN
- PAssert(PIsDescendant(&obj, CISCO_H225_QsigNonStdInfo), PInvalidCast);
-#endif
- const CISCO_H225_QsigNonStdInfo & other = (const CISCO_H225_QsigNonStdInfo &)obj;
-
- Comparison result;
-
- if ((result = m_iei.Compare(other.m_iei)) != EqualTo)
- return result;
- if ((result = m_rawMesg.Compare(other.m_rawMesg)) != EqualTo)
- return result;
-
- return PASN_Sequence::Compare(other);
-}
-
-
-PINDEX CISCO_H225_QsigNonStdInfo::GetDataLength() const
-{
- PINDEX length = 0;
- length += m_iei.GetObjectLength();
- length += m_rawMesg.GetObjectLength();
- return length;
-}
-
-
-BOOL CISCO_H225_QsigNonStdInfo::Decode(PASN_Stream & strm)
-{
- if (!PreambleDecode(strm))
- return FALSE;
-
- if (!m_iei.Decode(strm))
- return FALSE;
- if (!m_rawMesg.Decode(strm))
- return FALSE;
-
- return UnknownExtensionsDecode(strm);
-}
-
-
-void CISCO_H225_QsigNonStdInfo::Encode(PASN_Stream & strm) const
-{
- PreambleEncode(strm);
-
- m_iei.Encode(strm);
- m_rawMesg.Encode(strm);
-
- UnknownExtensionsEncode(strm);
-}
-
-
-PObject * CISCO_H225_QsigNonStdInfo::Clone() const
-{
-#ifndef PASN_LEANANDMEAN
- PAssert(IsClass(CISCO_H225_QsigNonStdInfo::Class()), PInvalidCast);
-#endif
- return new CISCO_H225_QsigNonStdInfo(*this);
-}
-
-
-//
-// CallMgrParam
-//
-
-CISCO_H225_CallMgrParam::CISCO_H225_CallMgrParam(unsigned tag, PASN_Object::TagClass tagClass)
- : PASN_Sequence(tag, tagClass, 0, TRUE, 0)
-{
-}
-
-
-#ifndef PASN_NOPRINTON
-void CISCO_H225_CallMgrParam::PrintOn(ostream & strm) const
-{
- int indent = strm.precision() + 2;
- strm << "{\n";
- strm << setw(indent+22) << "interclusterVersion = " << setprecision(indent) << m_interclusterVersion << '\n';
- strm << setw(indent+15) << "enterpriseID = " << setprecision(indent) << m_enterpriseID << '\n';
- strm << setw(indent-1) << setprecision(indent-2) << "}";
-}
-#endif
-
-
-PObject::Comparison CISCO_H225_CallMgrParam::Compare(const PObject & obj) const
-{
-#ifndef PASN_LEANANDMEAN
- PAssert(PIsDescendant(&obj, CISCO_H225_CallMgrParam), PInvalidCast);
-#endif
- const CISCO_H225_CallMgrParam & other = (const CISCO_H225_CallMgrParam &)obj;
-
- Comparison result;
-
- if ((result = m_interclusterVersion.Compare(other.m_interclusterVersion)) != EqualTo)
- return result;
- if ((result = m_enterpriseID.Compare(other.m_enterpriseID)) != EqualTo)
- return result;
-
- return PASN_Sequence::Compare(other);
-}
-
-
-PINDEX CISCO_H225_CallMgrParam::GetDataLength() const
-{
- PINDEX length = 0;
- length += m_interclusterVersion.GetObjectLength();
- length += m_enterpriseID.GetObjectLength();
- return length;
-}
-
-
-BOOL CISCO_H225_CallMgrParam::Decode(PASN_Stream & strm)
-{
- if (!PreambleDecode(strm))
- return FALSE;
-
- if (!m_interclusterVersion.Decode(strm))
- return FALSE;
- if (!m_enterpriseID.Decode(strm))
- return FALSE;
-
- return UnknownExtensionsDecode(strm);
-}
-
-
-void CISCO_H225_CallMgrParam::Encode(PASN_Stream & strm) const
-{
- PreambleEncode(strm);
-
- m_interclusterVersion.Encode(strm);
- m_enterpriseID.Encode(strm);
-
- UnknownExtensionsEncode(strm);
-}
-
-
-PObject * CISCO_H225_CallMgrParam::Clone() const
-{
-#ifndef PASN_LEANANDMEAN
- PAssert(IsClass(CISCO_H225_CallMgrParam::Class()), PInvalidCast);
-#endif
- return new CISCO_H225_CallMgrParam(*this);
-}
-
-
-//
-// CallPreserveParam
-//
-
-CISCO_H225_CallPreserveParam::CISCO_H225_CallPreserveParam(unsigned tag, PASN_Object::TagClass tagClass)
- : PASN_Sequence(tag, tagClass, 0, TRUE, 0)
-{
-}
-
-
-#ifndef PASN_NOPRINTON
-void CISCO_H225_CallPreserveParam::PrintOn(ostream & strm) const
-{
- int indent = strm.precision() + 2;
- strm << "{\n";
- strm << setw(indent+17) << "callPreserveIE = " << setprecision(indent) << m_callPreserveIE << '\n';
- strm << setw(indent-1) << setprecision(indent-2) << "}";
-}
-#endif
-
-
-PObject::Comparison CISCO_H225_CallPreserveParam::Compare(const PObject & obj) const
-{
-#ifndef PASN_LEANANDMEAN
- PAssert(PIsDescendant(&obj, CISCO_H225_CallPreserveParam), PInvalidCast);
-#endif
- const CISCO_H225_CallPreserveParam & other = (const CISCO_H225_CallPreserveParam &)obj;
-
- Comparison result;
-
- if ((result = m_callPreserveIE.Compare(other.m_callPreserveIE)) != EqualTo)
- return result;
-
- return PASN_Sequence::Compare(other);
-}
-
-
-PINDEX CISCO_H225_CallPreserveParam::GetDataLength() const
-{
- PINDEX length = 0;
- length += m_callPreserveIE.GetObjectLength();
- return length;
-}
-
-
-BOOL CISCO_H225_CallPreserveParam::Decode(PASN_Stream & strm)
-{
- if (!PreambleDecode(strm))
- return FALSE;
-
- if (!m_callPreserveIE.Decode(strm))
- return FALSE;
-
- return UnknownExtensionsDecode(strm);
-}
-
-
-void CISCO_H225_CallPreserveParam::Encode(PASN_Stream & strm) const
-{
- PreambleEncode(strm);
-
- m_callPreserveIE.Encode(strm);
-
- UnknownExtensionsEncode(strm);
-}
-
-
-PObject * CISCO_H225_CallPreserveParam::Clone() const
-{
-#ifndef PASN_LEANANDMEAN
- PAssert(IsClass(CISCO_H225_CallPreserveParam::Class()), PInvalidCast);
-#endif
- return new CISCO_H225_CallPreserveParam(*this);
-}
-
-
-//
-// CallSignallingParam
-//
-
-CISCO_H225_CallSignallingParam::CISCO_H225_CallSignallingParam(unsigned tag, PASN_Object::TagClass tagClass)
- : PASN_Sequence(tag, tagClass, 1, TRUE, 0)
-{
- m_connectedNumber.SetConstraints(PASN_Object::FixedConstraint, 1, 127);
-}
-
-
-#ifndef PASN_NOPRINTON
-void CISCO_H225_CallSignallingParam::PrintOn(ostream & strm) const
-{
- int indent = strm.precision() + 2;
- strm << "{\n";
- if (HasOptionalField(e_connectedNumber))
- strm << setw(indent+18) << "connectedNumber = " << setprecision(indent) << m_connectedNumber << '\n';
- strm << setw(indent-1) << setprecision(indent-2) << "}";
-}
-#endif
-
-
-PObject::Comparison CISCO_H225_CallSignallingParam::Compare(const PObject & obj) const
-{
-#ifndef PASN_LEANANDMEAN
- PAssert(PIsDescendant(&obj, CISCO_H225_CallSignallingParam), PInvalidCast);
-#endif
- const CISCO_H225_CallSignallingParam & other = (const CISCO_H225_CallSignallingParam &)obj;
-
- Comparison result;
-
- if ((result = m_connectedNumber.Compare(other.m_connectedNumber)) != EqualTo)
- return result;
-
- return PASN_Sequence::Compare(other);
-}
-
-
-PINDEX CISCO_H225_CallSignallingParam::GetDataLength() const
-{
- PINDEX length = 0;
- if (HasOptionalField(e_connectedNumber))
- length += m_connectedNumber.GetObjectLength();
- return length;
-}
-
-
-BOOL CISCO_H225_CallSignallingParam::Decode(PASN_Stream & strm)
-{
- if (!PreambleDecode(strm))
- return FALSE;
-
- if (HasOptionalField(e_connectedNumber) && !m_connectedNumber.Decode(strm))
- return FALSE;
-
- return UnknownExtensionsDecode(strm);
-}
-
-
-void CISCO_H225_CallSignallingParam::Encode(PASN_Stream & strm) const
-{
- PreambleEncode(strm);
-
- if (HasOptionalField(e_connectedNumber))
- m_connectedNumber.Encode(strm);
-
- UnknownExtensionsEncode(strm);
-}
-
-
-PObject * CISCO_H225_CallSignallingParam::Clone() const
-{
-#ifndef PASN_LEANANDMEAN
- PAssert(IsClass(CISCO_H225_CallSignallingParam::Class()), PInvalidCast);
-#endif
- return new CISCO_H225_CallSignallingParam(*this);
-}
-
-
-//
-// CommonParam
-//
-
-CISCO_H225_CommonParam::CISCO_H225_CommonParam(unsigned tag, PASN_Object::TagClass tagClass)
- : PASN_Sequence(tag, tagClass, 0, TRUE, 0)
-{
-}
-
-
-#ifndef PASN_NOPRINTON
-void CISCO_H225_CommonParam::PrintOn(ostream & strm) const
-{
- int indent = strm.precision() + 2;
- strm << "{\n";
- strm << setw(indent+17) << "redirectIEinfo = " << setprecision(indent) << m_redirectIEinfo << '\n';
- strm << setw(indent-1) << setprecision(indent-2) << "}";
-}
-#endif
-
-
-PObject::Comparison CISCO_H225_CommonParam::Compare(const PObject & obj) const
-{
-#ifndef PASN_LEANANDMEAN
- PAssert(PIsDescendant(&obj, CISCO_H225_CommonParam), PInvalidCast);
-#endif
- const CISCO_H225_CommonParam & other = (const CISCO_H225_CommonParam &)obj;
-
- Comparison result;
-
- if ((result = m_redirectIEinfo.Compare(other.m_redirectIEinfo)) != EqualTo)
- return result;
-
- return PASN_Sequence::Compare(other);
-}
-
-
-PINDEX CISCO_H225_CommonParam::GetDataLength() const
-{
- PINDEX length = 0;
- length += m_redirectIEinfo.GetObjectLength();
- return length;
-}
-
-
-BOOL CISCO_H225_CommonParam::Decode(PASN_Stream & strm)
-{
- if (!PreambleDecode(strm))
- return FALSE;
-
- if (!m_redirectIEinfo.Decode(strm))
- return FALSE;
-
- return UnknownExtensionsDecode(strm);
-}
-
-
-void CISCO_H225_CommonParam::Encode(PASN_Stream & strm) const
-{
- PreambleEncode(strm);
-
- m_redirectIEinfo.Encode(strm);
-
- UnknownExtensionsEncode(strm);
-}
-
-
-PObject * CISCO_H225_CommonParam::Clone() const
-{
-#ifndef PASN_LEANANDMEAN
- PAssert(IsClass(CISCO_H225_CommonParam::Class()), PInvalidCast);
-#endif
- return new CISCO_H225_CommonParam(*this);
-}
-
-
-//
-// ProgIndParam
-//
-
-CISCO_H225_ProgIndParam::CISCO_H225_ProgIndParam(unsigned tag, PASN_Object::TagClass tagClass)
- : PASN_Sequence(tag, tagClass, 0, TRUE, 0)
-{
-}
-
-
-#ifndef PASN_NOPRINTON
-void CISCO_H225_ProgIndParam::PrintOn(ostream & strm) const
-{
- int indent = strm.precision() + 2;
- strm << "{\n";
- strm << setw(indent+16) << "progIndIEinfo = " << setprecision(indent) << m_progIndIEinfo << '\n';
- strm << setw(indent-1) << setprecision(indent-2) << "}";
-}
-#endif
-
-
-PObject::Comparison CISCO_H225_ProgIndParam::Compare(const PObject & obj) const
-{
-#ifndef PASN_LEANANDMEAN
- PAssert(PIsDescendant(&obj, CISCO_H225_ProgIndParam), PInvalidCast);
-#endif
- const CISCO_H225_ProgIndParam & other = (const CISCO_H225_ProgIndParam &)obj;
-
- Comparison result;
-
- if ((result = m_progIndIEinfo.Compare(other.m_progIndIEinfo)) != EqualTo)
- return result;
-
- return PASN_Sequence::Compare(other);
-}
-
-
-PINDEX CISCO_H225_ProgIndParam::GetDataLength() const
-{
- PINDEX length = 0;
- length += m_progIndIEinfo.GetObjectLength();
- return length;
-}
-
-
-BOOL CISCO_H225_ProgIndParam::Decode(PASN_Stream & strm)
-{
- if (!PreambleDecode(strm))
- return FALSE;
-
- if (!m_progIndIEinfo.Decode(strm))
- return FALSE;
-
- return UnknownExtensionsDecode(strm);
-}
-
-
-void CISCO_H225_ProgIndParam::Encode(PASN_Stream & strm) const
-{
- PreambleEncode(strm);
-
- m_progIndIEinfo.Encode(strm);
-
- UnknownExtensionsEncode(strm);
-}
-
-
-PObject * CISCO_H225_ProgIndParam::Clone() const
-{
-#ifndef PASN_LEANANDMEAN
- PAssert(IsClass(CISCO_H225_ProgIndParam::Class()), PInvalidCast);
-#endif
- return new CISCO_H225_ProgIndParam(*this);
-}
-
-
-//
-// ProtoParam
-//
-
-CISCO_H225_ProtoParam::CISCO_H225_ProtoParam(unsigned tag, PASN_Object::TagClass tagClass)
- : PASN_Sequence(tag, tagClass, 0, TRUE, 0)
-{
-}
-
-
-#ifndef PASN_NOPRINTON
-void CISCO_H225_ProtoParam::PrintOn(ostream & strm) const
-{
- int indent = strm.precision() + 2;
- strm << "{\n";
- strm << setw(indent+17) << "qsigNonStdInfo = " << setprecision(indent) << m_qsigNonStdInfo << '\n';
- strm << setw(indent-1) << setprecision(indent-2) << "}";
-}
-#endif
-
-
-PObject::Comparison CISCO_H225_ProtoParam::Compare(const PObject & obj) const
-{
-#ifndef PASN_LEANANDMEAN
- PAssert(PIsDescendant(&obj, CISCO_H225_ProtoParam), PInvalidCast);
-#endif
- const CISCO_H225_ProtoParam & other = (const CISCO_H225_ProtoParam &)obj;
-
- Comparison result;
-
- if ((result = m_qsigNonStdInfo.Compare(other.m_qsigNonStdInfo)) != EqualTo)
- return result;
-
- return PASN_Sequence::Compare(other);
-}
-
-
-PINDEX CISCO_H225_ProtoParam::GetDataLength() const
-{
- PINDEX length = 0;
- length += m_qsigNonStdInfo.GetObjectLength();
- return length;
-}
-
-
-BOOL CISCO_H225_ProtoParam::Decode(PASN_Stream & strm)
-{
- if (!PreambleDecode(strm))
- return FALSE;
-
- if (!m_qsigNonStdInfo.Decode(strm))
- return FALSE;
-
- return UnknownExtensionsDecode(strm);
-}
-
-
-void CISCO_H225_ProtoParam::Encode(PASN_Stream & strm) const
-{
- PreambleEncode(strm);
-
- m_qsigNonStdInfo.Encode(strm);
-
- UnknownExtensionsEncode(strm);
-}
-
-
-PObject * CISCO_H225_ProtoParam::Clone() const
-{
-#ifndef PASN_LEANANDMEAN
- PAssert(IsClass(CISCO_H225_ProtoParam::Class()), PInvalidCast);
-#endif
- return new CISCO_H225_ProtoParam(*this);
-}
-
-
-//
-// H323_UU_NonStdInfo
-//
-
-CISCO_H225_H323_UU_NonStdInfo::CISCO_H225_H323_UU_NonStdInfo(unsigned tag, PASN_Object::TagClass tagClass)
- : PASN_Sequence(tag, tagClass, 3, TRUE, 6)
-{
-}
-
-
-#ifndef PASN_NOPRINTON
-void CISCO_H225_H323_UU_NonStdInfo::PrintOn(ostream & strm) const
-{
- int indent = strm.precision() + 2;
- strm << "{\n";
- if (HasOptionalField(e_version))
- strm << setw(indent+10) << "version = " << setprecision(indent) << m_version << '\n';
- if (HasOptionalField(e_protoParam))
- strm << setw(indent+13) << "protoParam = " << setprecision(indent) << m_protoParam << '\n';
- if (HasOptionalField(e_commonParam))
- strm << setw(indent+14) << "commonParam = " << setprecision(indent) << m_commonParam << '\n';
- if (HasOptionalField(e_dummy1))
- strm << setw(indent+9) << "dummy1 = " << setprecision(indent) << m_dummy1 << '\n';
- if (HasOptionalField(e_progIndParam))
- strm << setw(indent+15) << "progIndParam = " << setprecision(indent) << m_progIndParam << '\n';
- if (HasOptionalField(e_callMgrParam))
- strm << setw(indent+15) << "callMgrParam = " << setprecision(indent) << m_callMgrParam << '\n';
- if (HasOptionalField(e_callSignallingParam))
- strm << setw(indent+22) << "callSignallingParam = " << setprecision(indent) << m_callSignallingParam << '\n';
- if (HasOptionalField(e_dummy2))
- strm << setw(indent+9) << "dummy2 = " << setprecision(indent) << m_dummy2 << '\n';
- if (HasOptionalField(e_callPreserveParam))
- strm << setw(indent+20) << "callPreserveParam = " << setprecision(indent) << m_callPreserveParam << '\n';
- strm << setw(indent-1) << setprecision(indent-2) << "}";
-}
-#endif
-
-
-PObject::Comparison CISCO_H225_H323_UU_NonStdInfo::Compare(const PObject & obj) const
-{
-#ifndef PASN_LEANANDMEAN
- PAssert(PIsDescendant(&obj, CISCO_H225_H323_UU_NonStdInfo), PInvalidCast);
-#endif
- const CISCO_H225_H323_UU_NonStdInfo & other = (const CISCO_H225_H323_UU_NonStdInfo &)obj;
-
- Comparison result;
-
- if ((result = m_version.Compare(other.m_version)) != EqualTo)
- return result;
- if ((result = m_protoParam.Compare(other.m_protoParam)) != EqualTo)
- return result;
- if ((result = m_commonParam.Compare(other.m_commonParam)) != EqualTo)
- return result;
-
- return PASN_Sequence::Compare(other);
-}
-
-
-PINDEX CISCO_H225_H323_UU_NonStdInfo::GetDataLength() const
-{
- PINDEX length = 0;
- if (HasOptionalField(e_version))
- length += m_version.GetObjectLength();
- if (HasOptionalField(e_protoParam))
- length += m_protoParam.GetObjectLength();
- if (HasOptionalField(e_commonParam))
- length += m_commonParam.GetObjectLength();
- return length;
-}
-
-
-BOOL CISCO_H225_H323_UU_NonStdInfo::Decode(PASN_Stream & strm)
-{
- if (!PreambleDecode(strm))
- return FALSE;
-
- if (HasOptionalField(e_version) && !m_version.Decode(strm))
- return FALSE;
- if (HasOptionalField(e_protoParam) && !m_protoParam.Decode(strm))
- return FALSE;
- if (HasOptionalField(e_commonParam) && !m_commonParam.Decode(strm))
- return FALSE;
- if (!KnownExtensionDecode(strm, e_dummy1, m_dummy1))
- return FALSE;
- if (!KnownExtensionDecode(strm, e_progIndParam, m_progIndParam))
- return FALSE;
- if (!KnownExtensionDecode(strm, e_callMgrParam, m_callMgrParam))
- return FALSE;
- if (!KnownExtensionDecode(strm, e_callSignallingParam, m_callSignallingParam))
- return FALSE;
- if (!KnownExtensionDecode(strm, e_dummy2, m_dummy2))
- return FALSE;
- if (!KnownExtensionDecode(strm, e_callPreserveParam, m_callPreserveParam))
- return FALSE;
-
- return UnknownExtensionsDecode(strm);
-}
-
-
-void CISCO_H225_H323_UU_NonStdInfo::Encode(PASN_Stream & strm) const
-{
- PreambleEncode(strm);
-
- if (HasOptionalField(e_version))
- m_version.Encode(strm);
- if (HasOptionalField(e_protoParam))
- m_protoParam.Encode(strm);
- if (HasOptionalField(e_commonParam))
- m_commonParam.Encode(strm);
- KnownExtensionEncode(strm, e_dummy1, m_dummy1);
- KnownExtensionEncode(strm, e_progIndParam, m_progIndParam);
- KnownExtensionEncode(strm, e_callMgrParam, m_callMgrParam);
- KnownExtensionEncode(strm, e_callSignallingParam, m_callSignallingParam);
- KnownExtensionEncode(strm, e_dummy2, m_dummy2);
- KnownExtensionEncode(strm, e_callPreserveParam, m_callPreserveParam);
-
- UnknownExtensionsEncode(strm);
-}
-
-
-PObject * CISCO_H225_H323_UU_NonStdInfo::Clone() const
-{
-#ifndef PASN_LEANANDMEAN
- PAssert(IsClass(CISCO_H225_H323_UU_NonStdInfo::Class()), PInvalidCast);
-#endif
- return new CISCO_H225_H323_UU_NonStdInfo(*this);
-}
-
-
-#endif // if ! H323_DISABLE_CISCO_H225
-
-
-// End of cisco-h225.cxx
diff --git a/1.4.23-rc4/channels/h323/cisco-h225.h b/1.4.23-rc4/channels/h323/cisco-h225.h
deleted file mode 100644
index 7595b4b65..000000000
--- a/1.4.23-rc4/channels/h323/cisco-h225.h
+++ /dev/null
@@ -1,299 +0,0 @@
-//
-// cisco-h225.h
-//
-// Code automatically generated by asnparse.
-//
-
-#if ! H323_DISABLE_CISCO_H225
-
-#ifndef __CISCO_H225_H
-#define __CISCO_H225_H
-
-#ifdef P_USE_PRAGMA
-#pragma interface
-#endif
-
-#include <ptclib/asner.h>
-
-//
-// RedirectIEinfo
-//
-
-class CISCO_H225_RedirectIEinfo : public PASN_Sequence
-{
-#ifndef PASN_LEANANDMEAN
- PCLASSINFO(CISCO_H225_RedirectIEinfo, PASN_Sequence);
-#endif
- public:
- CISCO_H225_RedirectIEinfo(unsigned tag = UniversalSequence, TagClass tagClass = UniversalTagClass);
-
- PASN_OctetString m_redirectIE;
-
- PINDEX GetDataLength() const;
- BOOL Decode(PASN_Stream & strm);
- void Encode(PASN_Stream & strm) const;
-#ifndef PASN_NOPRINTON
- void PrintOn(ostream & strm) const;
-#endif
- Comparison Compare(const PObject & obj) const;
- PObject * Clone() const;
-};
-
-
-//
-// ProgIndIEinfo
-//
-
-class CISCO_H225_ProgIndIEinfo : public PASN_Sequence
-{
-#ifndef PASN_LEANANDMEAN
- PCLASSINFO(CISCO_H225_ProgIndIEinfo, PASN_Sequence);
-#endif
- public:
- CISCO_H225_ProgIndIEinfo(unsigned tag = UniversalSequence, TagClass tagClass = UniversalTagClass);
-
- PASN_OctetString m_progIndIE;
-
- PINDEX GetDataLength() const;
- BOOL Decode(PASN_Stream & strm);
- void Encode(PASN_Stream & strm) const;
-#ifndef PASN_NOPRINTON
- void PrintOn(ostream & strm) const;
-#endif
- Comparison Compare(const PObject & obj) const;
- PObject * Clone() const;
-};
-
-
-//
-// QsigNonStdInfo
-//
-
-class CISCO_H225_QsigNonStdInfo : public PASN_Sequence
-{
-#ifndef PASN_LEANANDMEAN
- PCLASSINFO(CISCO_H225_QsigNonStdInfo, PASN_Sequence);
-#endif
- public:
- CISCO_H225_QsigNonStdInfo(unsigned tag = UniversalSequence, TagClass tagClass = UniversalTagClass);
-
- PASN_Integer m_iei;
- PASN_OctetString m_rawMesg;
-
- PINDEX GetDataLength() const;
- BOOL Decode(PASN_Stream & strm);
- void Encode(PASN_Stream & strm) const;
-#ifndef PASN_NOPRINTON
- void PrintOn(ostream & strm) const;
-#endif
- Comparison Compare(const PObject & obj) const;
- PObject * Clone() const;
-};
-
-
-//
-// CallMgrParam
-//
-
-class CISCO_H225_CallMgrParam : public PASN_Sequence
-{
-#ifndef PASN_LEANANDMEAN
- PCLASSINFO(CISCO_H225_CallMgrParam, PASN_Sequence);
-#endif
- public:
- CISCO_H225_CallMgrParam(unsigned tag = UniversalSequence, TagClass tagClass = UniversalTagClass);
-
- PASN_Integer m_interclusterVersion;
- PASN_OctetString m_enterpriseID;
-
- PINDEX GetDataLength() const;
- BOOL Decode(PASN_Stream & strm);
- void Encode(PASN_Stream & strm) const;
-#ifndef PASN_NOPRINTON
- void PrintOn(ostream & strm) const;
-#endif
- Comparison Compare(const PObject & obj) const;
- PObject * Clone() const;
-};
-
-
-//
-// CallPreserveParam
-//
-
-class CISCO_H225_CallPreserveParam : public PASN_Sequence
-{
-#ifndef PASN_LEANANDMEAN
- PCLASSINFO(CISCO_H225_CallPreserveParam, PASN_Sequence);
-#endif
- public:
- CISCO_H225_CallPreserveParam(unsigned tag = UniversalSequence, TagClass tagClass = UniversalTagClass);
-
- PASN_Boolean m_callPreserveIE;
-
- PINDEX GetDataLength() const;
- BOOL Decode(PASN_Stream & strm);
- void Encode(PASN_Stream & strm) const;
-#ifndef PASN_NOPRINTON
- void PrintOn(ostream & strm) const;
-#endif
- Comparison Compare(const PObject & obj) const;
- PObject * Clone() const;
-};
-
-
-//
-// CallSignallingParam
-//
-
-class CISCO_H225_CallSignallingParam : public PASN_Sequence
-{
-#ifndef PASN_LEANANDMEAN
- PCLASSINFO(CISCO_H225_CallSignallingParam, PASN_Sequence);
-#endif
- public:
- CISCO_H225_CallSignallingParam(unsigned tag = UniversalSequence, TagClass tagClass = UniversalTagClass);
-
- enum OptionalFields {
- e_connectedNumber
- };
-
- PASN_OctetString m_connectedNumber;
-
- PINDEX GetDataLength() const;
- BOOL Decode(PASN_Stream & strm);
- void Encode(PASN_Stream & strm) const;
-#ifndef PASN_NOPRINTON
- void PrintOn(ostream & strm) const;
-#endif
- Comparison Compare(const PObject & obj) const;
- PObject * Clone() const;
-};
-
-
-//
-// CommonParam
-//
-
-class CISCO_H225_CommonParam : public PASN_Sequence
-{
-#ifndef PASN_LEANANDMEAN
- PCLASSINFO(CISCO_H225_CommonParam, PASN_Sequence);
-#endif
- public:
- CISCO_H225_CommonParam(unsigned tag = UniversalSequence, TagClass tagClass = UniversalTagClass);
-
- CISCO_H225_RedirectIEinfo m_redirectIEinfo;
-
- PINDEX GetDataLength() const;
- BOOL Decode(PASN_Stream & strm);
- void Encode(PASN_Stream & strm) const;
-#ifndef PASN_NOPRINTON
- void PrintOn(ostream & strm) const;
-#endif
- Comparison Compare(const PObject & obj) const;
- PObject * Clone() const;
-};
-
-
-//
-// ProgIndParam
-//
-
-class CISCO_H225_ProgIndParam : public PASN_Sequence
-{
-#ifndef PASN_LEANANDMEAN
- PCLASSINFO(CISCO_H225_ProgIndParam, PASN_Sequence);
-#endif
- public:
- CISCO_H225_ProgIndParam(unsigned tag = UniversalSequence, TagClass tagClass = UniversalTagClass);
-
- CISCO_H225_ProgIndIEinfo m_progIndIEinfo;
-
- PINDEX GetDataLength() const;
- BOOL Decode(PASN_Stream & strm);
- void Encode(PASN_Stream & strm) const;
-#ifndef PASN_NOPRINTON
- void PrintOn(ostream & strm) const;
-#endif
- Comparison Compare(const PObject & obj) const;
- PObject * Clone() const;
-};
-
-
-//
-// ProtoParam
-//
-
-class CISCO_H225_ProtoParam : public PASN_Sequence
-{
-#ifndef PASN_LEANANDMEAN
- PCLASSINFO(CISCO_H225_ProtoParam, PASN_Sequence);
-#endif
- public:
- CISCO_H225_ProtoParam(unsigned tag = UniversalSequence, TagClass tagClass = UniversalTagClass);
-
- CISCO_H225_QsigNonStdInfo m_qsigNonStdInfo;
-
- PINDEX GetDataLength() const;
- BOOL Decode(PASN_Stream & strm);
- void Encode(PASN_Stream & strm) const;
-#ifndef PASN_NOPRINTON
- void PrintOn(ostream & strm) const;
-#endif
- Comparison Compare(const PObject & obj) const;
- PObject * Clone() const;
-};
-
-
-//
-// H323_UU_NonStdInfo
-//
-
-class CISCO_H225_H323_UU_NonStdInfo : public PASN_Sequence
-{
-#ifndef PASN_LEANANDMEAN
- PCLASSINFO(CISCO_H225_H323_UU_NonStdInfo, PASN_Sequence);
-#endif
- public:
- CISCO_H225_H323_UU_NonStdInfo(unsigned tag = UniversalSequence, TagClass tagClass = UniversalTagClass);
-
- enum OptionalFields {
- e_version,
- e_protoParam,
- e_commonParam,
- e_dummy1,
- e_progIndParam,
- e_callMgrParam,
- e_callSignallingParam,
- e_dummy2,
- e_callPreserveParam
- };
-
- PASN_Integer m_version;
- CISCO_H225_ProtoParam m_protoParam;
- CISCO_H225_CommonParam m_commonParam;
- PASN_OctetString m_dummy1;
- CISCO_H225_ProgIndParam m_progIndParam;
- CISCO_H225_CallMgrParam m_callMgrParam;
- CISCO_H225_CallSignallingParam m_callSignallingParam;
- PASN_OctetString m_dummy2;
- CISCO_H225_CallPreserveParam m_callPreserveParam;
-
- PINDEX GetDataLength() const;
- BOOL Decode(PASN_Stream & strm);
- void Encode(PASN_Stream & strm) const;
-#ifndef PASN_NOPRINTON
- void PrintOn(ostream & strm) const;
-#endif
- Comparison Compare(const PObject & obj) const;
- PObject * Clone() const;
-};
-
-
-#endif // __CISCO_H225_H
-
-#endif // if ! H323_DISABLE_CISCO_H225
-
-
-// End of cisco-h225.h
diff --git a/1.4.23-rc4/channels/h323/compat_h323.cxx b/1.4.23-rc4/channels/h323/compat_h323.cxx
deleted file mode 100644
index eec7361b2..000000000
--- a/1.4.23-rc4/channels/h323/compat_h323.cxx
+++ /dev/null
@@ -1,138 +0,0 @@
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
-/*
- * ast_h323.cpp
- *
- * OpenH323 Channel Driver for ASTERISK PBX.
- * By Jeremy McNamara
- * For The NuFone Network
- *
- * chan_h323 has been derived from code created by
- * Michael Manousos and Mark Spencer
- *
- * This file is part of the chan_h323 driver for Asterisk
- *
- * chan_h323 is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * chan_h323 is distributed WITHOUT ANY WARRANTY; without even
- * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Version Info: $Id$
- */
-#include <ptlib.h>
-#include <h323.h>
-#include <transports.h>
-
-#include "ast_h323.h"
-
-#if VERSION(OPENH323_MAJOR,OPENH323_MINOR,OPENH323_BUILD) < VERSION(1,17,3)
-MyH323TransportTCP::MyH323TransportTCP(
- H323EndPoint & endpoint,
- PIPSocket::Address binding,
- BOOL listen)
- : H323TransportTCP(endpoint, binding, listen)
-{
-}
-
-BOOL MyH323TransportTCP::Connect()
-{
- if (IsListening())
- return TRUE;
-
- PTCPSocket * socket = new PTCPSocket(remotePort);
- Open(socket);
-
- channelPointerMutex.StartRead();
-
- socket->SetReadTimeout(10000/*endpoint.GetSignallingChannelConnectTimeout()*/);
-
- localPort = endpoint.GetNextTCPPort();
- WORD firstPort = localPort;
- for (;;) {
- PTRACE(4, "H323TCP\tConnecting to "
- << remoteAddress << ':' << remotePort
- << " (local port=" << localPort << ')');
- if (socket->Connect(localAddress, localPort, remoteAddress))
- break;
-
- int errnum = socket->GetErrorNumber();
- if (localPort == 0 || (errnum != EADDRINUSE && errnum != EADDRNOTAVAIL)) {
- PTRACE(1, "H323TCP\tCould not connect to "
- << remoteAddress << ':' << remotePort
- << " (local port=" << localPort << ") - "
- << socket->GetErrorText() << '(' << errnum << ')');
- channelPointerMutex.EndRead();
- return SetErrorValues(socket->GetErrorCode(), errnum);
- }
-
- localPort = endpoint.GetNextTCPPort();
- if (localPort == firstPort) {
- PTRACE(1, "H323TCP\tCould not bind to any port in range " <<
- endpoint.GetTCPPortBase() << " to " << endpoint.GetTCPPortMax());
- channelPointerMutex.EndRead();
- return SetErrorValues(socket->GetErrorCode(), errnum);
- }
- }
-
- socket->SetReadTimeout(PMaxTimeInterval);
-
- channelPointerMutex.EndRead();
-
- return OnOpen();
-}
-#endif
-
-BOOL MyH323TransportUDP::DiscoverGatekeeper(H323Gatekeeper &gk, H323RasPDU &pdu, const H323TransportAddress &address)
-{
- PThread *thd = PThread::Current();
-
- /* If we run in OpenH323's thread use it instead of creating new one */
- if (thd)
- return H323TransportUDP::DiscoverGatekeeper(gk, pdu, address);
-
- /* Make copy of arguments to pass them into thread */
- discoverGatekeeper = &gk;
- discoverPDU = &pdu;
- discoverAddress = &address;
-
- /* Assume discovery thread isn't finished */
- discoverReady = FALSE;
-
- /* Create discovery thread */
- thd = PThread::Create(PCREATE_NOTIFIER(DiscoverMain), 0,
- PThread::NoAutoDeleteThread,
- PThread::NormalPriority,
- "GkDiscovery:%x");
-
- /* Wait until discovery thread signal us its finished */
- for(;;) {
- discoverMutex.Wait();
- if (discoverReady) /* Thread has been finished */
- break;
- discoverMutex.Signal();
- }
- discoverMutex.Signal();
-
- /* Cleanup/delete thread */
- thd->WaitForTermination();
- delete thd;
-
- return discoverResult;
-}
-
-void MyH323TransportUDP::DiscoverMain(PThread &thread, INT arg)
-{
- PWaitAndSignal m(discoverMutex);
-
- discoverResult = H323TransportUDP::DiscoverGatekeeper(*discoverGatekeeper, *discoverPDU, *discoverAddress);
- discoverReady = TRUE;
-}
diff --git a/1.4.23-rc4/channels/h323/compat_h323.h b/1.4.23-rc4/channels/h323/compat_h323.h
deleted file mode 100644
index 63da8ac8c..000000000
--- a/1.4.23-rc4/channels/h323/compat_h323.h
+++ /dev/null
@@ -1,80 +0,0 @@
-#ifndef COMPAT_H323_H
-#define COMPAT_H323_H
-
-#if VERSION(OPENH323_MAJOR,OPENH323_MINOR,OPENH323_BUILD) < VERSION(1,17,3)
-/**
- * Workaround for broken (less than 1.17.3) OpenH323 stack to be able to
- * make TCP connections from specific address
- */
-class MyH323TransportTCP : public H323TransportTCP
-{
- PCLASSINFO(MyH323TransportTCP, H323TransportTCP);
-
-public:
- MyH323TransportTCP(
- H323EndPoint & endpoint, ///< H323 End Point object
- PIPSocket::Address binding = PIPSocket::GetDefaultIpAny(), ///< Local interface to use
- BOOL listen = FALSE ///< Flag for need to wait for remote to connect
- );
- /**Connect to the remote party.
- */
- virtual BOOL Connect();
-};
-#else
-#define MyH323TransportTCP H323TransportTCP
-#endif /* <VERSION(1,17,3) */
-
-class MyH323TransportUDP: public H323TransportUDP
-{
- PCLASSINFO(MyH323TransportUDP, H323TransportUDP);
-
-public:
- MyH323TransportUDP(H323EndPoint &endpoint,
- PIPSocket::Address binding = PIPSocket::GetDefaultIpAny(),
- WORD localPort = 0,
- WORD remotePort = 0): H323TransportUDP(endpoint, binding, localPort, remotePort)
- {
- }
- virtual BOOL DiscoverGatekeeper(H323Gatekeeper &,
- H323RasPDU &,
- const H323TransportAddress &);
-protected:
- PDECLARE_NOTIFIER(PThread, MyH323TransportUDP, DiscoverMain);
- H323Gatekeeper *discoverGatekeeper;
- H323RasPDU *discoverPDU;
- const H323TransportAddress *discoverAddress;
- BOOL discoverResult;
- BOOL discoverReady;
- PMutex discoverMutex;
-};
-
-template <class _Abstract_T, typename _Key_T = PString>
-class MyPFactory: public PFactory<_Abstract_T, _Key_T>
-{
-public:
- template <class _Concrete_T> class Worker: public PFactory<_Abstract_T, _Key_T>::WorkerBase
- {
- public:
- Worker(const _Key_T &_key, bool singleton = false)
- :PFactory<_Abstract_T, _Key_T>::WorkerBase(singleton), key(_key)
- {
- PFactory<_Abstract_T, _Key_T>::Register(key, this);
- }
- ~Worker()
- {
- PFactory<_Abstract_T, _Key_T>::Unregister(key);
- }
- protected:
- virtual _Abstract_T *Create(const _Key_T &) const { return new _Concrete_T; }
-
- private:
- PString key;
- };
-};
-
-#ifdef H323_REGISTER_CAPABILITY
-#undef H323_REGISTER_CAPABILITY
-#endif
-#define H323_REGISTER_CAPABILITY(cls, capName) static MyPFactory<H323Capability>::Worker<cls> cls##Factory(capName, true)
-
-#endif /* !defined AST_H323_H */
diff --git a/1.4.23-rc4/channels/h323/noexport.map b/1.4.23-rc4/channels/h323/noexport.map
deleted file mode 100644
index b51f84263..000000000
--- a/1.4.23-rc4/channels/h323/noexport.map
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- global:
- _Z11PAssertFuncPKc;
- local: *;
-}; \ No newline at end of file
diff --git a/1.4.23-rc4/channels/iax2-parser.c b/1.4.23-rc4/channels/iax2-parser.c
deleted file mode 100644
index 67bffa897..000000000
--- a/1.4.23-rc4/channels/iax2-parser.c
+++ /dev/null
@@ -1,1053 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 1999 - 2005, Digium, Inc.
- *
- * Mark Spencer <markster@digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Implementation of Inter-Asterisk eXchange Protocol, v 2
- *
- * \author Mark Spencer <markster@digium.com>
- */
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <string.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-#include "asterisk/frame.h"
-#include "asterisk/utils.h"
-#include "asterisk/unaligned.h"
-#include "asterisk/lock.h"
-#include "asterisk/threadstorage.h"
-
-#include "iax2.h"
-#include "iax2-parser.h"
-#include "iax2-provision.h"
-
-static int frames = 0;
-static int iframes = 0;
-static int oframes = 0;
-
-#if !defined(LOW_MEMORY)
-static void frame_cache_cleanup(void *data);
-
-/*! \brief A per-thread cache of iax_frame structures */
-AST_THREADSTORAGE_CUSTOM(frame_cache, frame_cache_init, frame_cache_cleanup);
-
-/*! \brief This is just so iax_frames, a list head struct for holding a list of
- * iax_frame structures, is defined. */
-AST_LIST_HEAD_NOLOCK(iax_frame_list, iax_frame);
-
-struct iax_frames {
- struct iax_frame_list list;
- size_t size;
-};
-
-#define FRAME_CACHE_MAX_SIZE 20
-#endif
-
-static void internaloutput(const char *str)
-{
- fputs(str, stdout);
-}
-
-static void internalerror(const char *str)
-{
- fprintf(stderr, "WARNING: %s", str);
-}
-
-static void (*outputf)(const char *str) = internaloutput;
-static void (*errorf)(const char *str) = internalerror;
-
-static void dump_addr(char *output, int maxlen, void *value, int len)
-{
- struct sockaddr_in sin;
- if (len == (int)sizeof(sin)) {
- memcpy(&sin, value, len);
- snprintf(output, maxlen, "IPV4 %s:%d", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
- } else {
- snprintf(output, maxlen, "Invalid Address");
- }
-}
-
-static void dump_string(char *output, int maxlen, void *value, int len)
-{
- maxlen--;
- if (maxlen > len)
- maxlen = len;
- strncpy(output, value, maxlen);
- output[maxlen] = '\0';
-}
-
-static void dump_prefs(char *output, int maxlen, void *value, int len)
-{
- struct ast_codec_pref pref;
- int total_len = 0;
-
- maxlen--;
- total_len = maxlen;
-
- if (maxlen > len)
- maxlen = len;
-
- strncpy(output, value, maxlen);
- output[maxlen] = '\0';
-
- ast_codec_pref_convert(&pref, output, total_len, 0);
- memset(output,0,total_len);
- ast_codec_pref_string(&pref, output, total_len);
-}
-
-static void dump_int(char *output, int maxlen, void *value, int len)
-{
- if (len == (int)sizeof(unsigned int))
- snprintf(output, maxlen, "%lu", (unsigned long)ntohl(get_unaligned_uint32(value)));
- else
- ast_copy_string(output, "Invalid INT", maxlen);
-}
-
-static void dump_short(char *output, int maxlen, void *value, int len)
-{
- if (len == (int)sizeof(unsigned short))
- snprintf(output, maxlen, "%d", ntohs(get_unaligned_uint16(value)));
- else
- ast_copy_string(output, "Invalid SHORT", maxlen);
-}
-
-static void dump_byte(char *output, int maxlen, void *value, int len)
-{
- if (len == (int)sizeof(unsigned char))
- snprintf(output, maxlen, "%d", *((unsigned char *)value));
- else
- ast_copy_string(output, "Invalid BYTE", maxlen);
-}
-
-static void dump_datetime(char *output, int maxlen, void *value, int len)
-{
- struct tm tm;
- unsigned long val = (unsigned long) ntohl(get_unaligned_uint32(value));
- if (len == (int)sizeof(unsigned int)) {
- tm.tm_sec = (val & 0x1f) << 1;
- tm.tm_min = (val >> 5) & 0x3f;
- tm.tm_hour = (val >> 11) & 0x1f;
- tm.tm_mday = (val >> 16) & 0x1f;
- tm.tm_mon = ((val >> 21) & 0x0f) - 1;
- tm.tm_year = ((val >> 25) & 0x7f) + 100;
- strftime(output, maxlen, "%Y-%m-%d %T", &tm);
- } else
- ast_copy_string(output, "Invalid DATETIME format!", maxlen);
-}
-
-static void dump_ipaddr(char *output, int maxlen, void *value, int len)
-{
- struct sockaddr_in sin;
- if (len == (int)sizeof(unsigned int)) {
- memcpy(&sin.sin_addr, value, len);
- snprintf(output, maxlen, "%s", ast_inet_ntoa(sin.sin_addr));
- } else
- ast_copy_string(output, "Invalid IPADDR", maxlen);
-}
-
-
-static void dump_prov_flags(char *output, int maxlen, void *value, int len)
-{
- char buf[256] = "";
- if (len == (int)sizeof(unsigned int))
- snprintf(output, maxlen, "%lu (%s)", (unsigned long)ntohl(get_unaligned_uint32(value)),
- iax_provflags2str(buf, sizeof(buf), ntohl(get_unaligned_uint32(value))));
- else
- ast_copy_string(output, "Invalid INT", maxlen);
-}
-
-static void dump_samprate(char *output, int maxlen, void *value, int len)
-{
- char tmp[256]="";
- int sr;
- if (len == (int)sizeof(unsigned short)) {
- sr = ntohs(*((unsigned short *)value));
- if (sr & IAX_RATE_8KHZ)
- strcat(tmp, ",8khz");
- if (sr & IAX_RATE_11KHZ)
- strcat(tmp, ",11.025khz");
- if (sr & IAX_RATE_16KHZ)
- strcat(tmp, ",16khz");
- if (sr & IAX_RATE_22KHZ)
- strcat(tmp, ",22.05khz");
- if (sr & IAX_RATE_44KHZ)
- strcat(tmp, ",44.1khz");
- if (sr & IAX_RATE_48KHZ)
- strcat(tmp, ",48khz");
- if (strlen(tmp))
- ast_copy_string(output, &tmp[1], maxlen);
- else
- ast_copy_string(output, "None Specified!\n", maxlen);
- } else
- ast_copy_string(output, "Invalid SHORT", maxlen);
-
-}
-
-static void dump_prov_ies(char *output, int maxlen, unsigned char *iedata, int len);
-static void dump_prov(char *output, int maxlen, void *value, int len)
-{
- dump_prov_ies(output, maxlen, value, len);
-}
-
-static struct iax2_ie {
- int ie;
- char *name;
- void (*dump)(char *output, int maxlen, void *value, int len);
-} ies[] = {
- { IAX_IE_CALLED_NUMBER, "CALLED NUMBER", dump_string },
- { IAX_IE_CALLING_NUMBER, "CALLING NUMBER", dump_string },
- { IAX_IE_CALLING_ANI, "ANI", dump_string },
- { IAX_IE_CALLING_NAME, "CALLING NAME", dump_string },
- { IAX_IE_CALLED_CONTEXT, "CALLED CONTEXT", dump_string },
- { IAX_IE_USERNAME, "USERNAME", dump_string },
- { IAX_IE_PASSWORD, "PASSWORD", dump_string },
- { IAX_IE_CAPABILITY, "CAPABILITY", dump_int },
- { IAX_IE_FORMAT, "FORMAT", dump_int },
- { IAX_IE_LANGUAGE, "LANGUAGE", dump_string },
- { IAX_IE_VERSION, "VERSION", dump_short },
- { IAX_IE_ADSICPE, "ADSICPE", dump_short },
- { IAX_IE_DNID, "DNID", dump_string },
- { IAX_IE_AUTHMETHODS, "AUTHMETHODS", dump_short },
- { IAX_IE_CHALLENGE, "CHALLENGE", dump_string },
- { IAX_IE_MD5_RESULT, "MD5 RESULT", dump_string },
- { IAX_IE_RSA_RESULT, "RSA RESULT", dump_string },
- { IAX_IE_APPARENT_ADDR, "APPARENT ADDRESS", dump_addr },
- { IAX_IE_REFRESH, "REFRESH", dump_short },
- { IAX_IE_DPSTATUS, "DIALPLAN STATUS", dump_short },
- { IAX_IE_CALLNO, "CALL NUMBER", dump_short },
- { IAX_IE_CAUSE, "CAUSE", dump_string },
- { IAX_IE_IAX_UNKNOWN, "UNKNOWN IAX CMD", dump_byte },
- { IAX_IE_MSGCOUNT, "MESSAGE COUNT", dump_short },
- { IAX_IE_AUTOANSWER, "AUTO ANSWER REQ" },
- { IAX_IE_TRANSFERID, "TRANSFER ID", dump_int },
- { IAX_IE_RDNIS, "REFERRING DNIS", dump_string },
- { IAX_IE_PROVISIONING, "PROVISIONING", dump_prov },
- { IAX_IE_AESPROVISIONING, "AES PROVISIONG" },
- { IAX_IE_DATETIME, "DATE TIME", dump_datetime },
- { IAX_IE_DEVICETYPE, "DEVICE TYPE", dump_string },
- { IAX_IE_SERVICEIDENT, "SERVICE IDENT", dump_string },
- { IAX_IE_FIRMWAREVER, "FIRMWARE VER", dump_short },
- { IAX_IE_FWBLOCKDESC, "FW BLOCK DESC", dump_int },
- { IAX_IE_FWBLOCKDATA, "FW BLOCK DATA" },
- { IAX_IE_PROVVER, "PROVISIONG VER", dump_int },
- { IAX_IE_CALLINGPRES, "CALLING PRESNTN", dump_byte },
- { IAX_IE_CALLINGTON, "CALLING TYPEOFNUM", dump_byte },
- { IAX_IE_CALLINGTNS, "CALLING TRANSITNET", dump_short },
- { IAX_IE_SAMPLINGRATE, "SAMPLINGRATE", dump_samprate },
- { IAX_IE_CAUSECODE, "CAUSE CODE", dump_byte },
- { IAX_IE_ENCRYPTION, "ENCRYPTION", dump_short },
- { IAX_IE_ENCKEY, "ENCRYPTION KEY" },
- { IAX_IE_CODEC_PREFS, "CODEC_PREFS", dump_prefs },
- { IAX_IE_RR_JITTER, "RR_JITTER", dump_int },
- { IAX_IE_RR_LOSS, "RR_LOSS", dump_int },
- { IAX_IE_RR_PKTS, "RR_PKTS", dump_int },
- { IAX_IE_RR_DELAY, "RR_DELAY", dump_short },
- { IAX_IE_RR_DROPPED, "RR_DROPPED", dump_int },
- { IAX_IE_RR_OOO, "RR_OUTOFORDER", dump_int },
-};
-
-static struct iax2_ie prov_ies[] = {
- { PROV_IE_USEDHCP, "USEDHCP" },
- { PROV_IE_IPADDR, "IPADDR", dump_ipaddr },
- { PROV_IE_SUBNET, "SUBNET", dump_ipaddr },
- { PROV_IE_GATEWAY, "GATEWAY", dump_ipaddr },
- { PROV_IE_PORTNO, "BINDPORT", dump_short },
- { PROV_IE_USER, "USERNAME", dump_string },
- { PROV_IE_PASS, "PASSWORD", dump_string },
- { PROV_IE_LANG, "LANGUAGE", dump_string },
- { PROV_IE_TOS, "TYPEOFSERVICE", dump_byte },
- { PROV_IE_FLAGS, "FLAGS", dump_prov_flags },
- { PROV_IE_FORMAT, "FORMAT", dump_int },
- { PROV_IE_AESKEY, "AESKEY" },
- { PROV_IE_SERVERIP, "SERVERIP", dump_ipaddr },
- { PROV_IE_SERVERPORT, "SERVERPORT", dump_short },
- { PROV_IE_NEWAESKEY, "NEWAESKEY" },
- { PROV_IE_PROVVER, "PROV VERSION", dump_int },
- { PROV_IE_ALTSERVER, "ALTSERVERIP", dump_ipaddr },
-};
-
-const char *iax_ie2str(int ie)
-{
- int x;
- for (x=0;x<(int)sizeof(ies) / (int)sizeof(ies[0]); x++) {
- if (ies[x].ie == ie)
- return ies[x].name;
- }
- return "Unknown IE";
-}
-
-
-static void dump_prov_ies(char *output, int maxlen, unsigned char *iedata, int len)
-{
- int ielen;
- int ie;
- int x;
- int found;
- char interp[80];
- char tmp[256];
- if (len < 2)
- return;
- strcpy(output, "\n");
- maxlen -= strlen(output); output += strlen(output);
- while(len > 2) {
- ie = iedata[0];
- ielen = iedata[1];
- if (ielen + 2> len) {
- snprintf(tmp, (int)sizeof(tmp), "Total Prov IE length of %d bytes exceeds remaining prov frame length of %d bytes\n", ielen + 2, len);
- ast_copy_string(output, tmp, maxlen);
- maxlen -= strlen(output);
- output += strlen(output);
- return;
- }
- found = 0;
- for (x=0;x<(int)sizeof(prov_ies) / (int)sizeof(prov_ies[0]); x++) {
- if (prov_ies[x].ie == ie) {
- if (prov_ies[x].dump) {
- prov_ies[x].dump(interp, (int)sizeof(interp), iedata + 2, ielen);
- snprintf(tmp, (int)sizeof(tmp), " %-15.15s : %s\n", prov_ies[x].name, interp);
- ast_copy_string(output, tmp, maxlen);
- maxlen -= strlen(output); output += strlen(output);
- } else {
- if (ielen)
- snprintf(interp, (int)sizeof(interp), "%d bytes", ielen);
- else
- strcpy(interp, "Present");
- snprintf(tmp, (int)sizeof(tmp), " %-15.15s : %s\n", prov_ies[x].name, interp);
- ast_copy_string(output, tmp, maxlen);
- maxlen -= strlen(output); output += strlen(output);
- }
- found++;
- }
- }
- if (!found) {
- snprintf(tmp, (int)sizeof(tmp), " Unknown Prov IE %03d : Present\n", ie);
- ast_copy_string(output, tmp, maxlen);
- maxlen -= strlen(output); output += strlen(output);
- }
- iedata += (2 + ielen);
- len -= (2 + ielen);
- }
-}
-
-static void dump_ies(unsigned char *iedata, int len)
-{
- int ielen;
- int ie;
- int x;
- int found;
- char interp[1024];
- char tmp[1024];
- if (len < 2)
- return;
- while(len > 2) {
- ie = iedata[0];
- ielen = iedata[1];
- if (ielen + 2> len) {
- snprintf(tmp, (int)sizeof(tmp), "Total IE length of %d bytes exceeds remaining frame length of %d bytes\n", ielen + 2, len);
- outputf(tmp);
- return;
- }
- found = 0;
- for (x=0;x<(int)sizeof(ies) / (int)sizeof(ies[0]); x++) {
- if (ies[x].ie == ie) {
- if (ies[x].dump) {
- ies[x].dump(interp, (int)sizeof(interp), iedata + 2, ielen);
- snprintf(tmp, (int)sizeof(tmp), " %-15.15s : %s\n", ies[x].name, interp);
- outputf(tmp);
- } else {
- if (ielen)
- snprintf(interp, (int)sizeof(interp), "%d bytes", ielen);
- else
- strcpy(interp, "Present");
- snprintf(tmp, (int)sizeof(tmp), " %-15.15s : %s\n", ies[x].name, interp);
- outputf(tmp);
- }
- found++;
- }
- }
- if (!found) {
- snprintf(tmp, (int)sizeof(tmp), " Unknown IE %03d : Present\n", ie);
- outputf(tmp);
- }
- iedata += (2 + ielen);
- len -= (2 + ielen);
- }
- outputf("\n");
-}
-
-void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen)
-{
- const char *frames[] = {
- "(0?)",
- "DTMF_E ",
- "VOICE ",
- "VIDEO ",
- "CONTROL",
- "NULL ",
- "IAX ",
- "TEXT ",
- "IMAGE ",
- "HTML ",
- "CNG ",
- "MODEM ",
- "DTMF_B ",
- };
- const char *iaxs[] = {
- "(0?)",
- "NEW ",
- "PING ",
- "PONG ",
- "ACK ",
- "HANGUP ",
- "REJECT ",
- "ACCEPT ",
- "AUTHREQ",
- "AUTHREP",
- "INVAL ",
- "LAGRQ ",
- "LAGRP ",
- "REGREQ ",
- "REGAUTH",
- "REGACK ",
- "REGREJ ",
- "REGREL ",
- "VNAK ",
- "DPREQ ",
- "DPREP ",
- "DIAL ",
- "TXREQ ",
- "TXCNT ",
- "TXACC ",
- "TXREADY",
- "TXREL ",
- "TXREJ ",
- "QUELCH ",
- "UNQULCH",
- "POKE ",
- "PAGE ",
- "MWI ",
- "UNSPRTD",
- "TRANSFR",
- "PROVISN",
- "FWDWNLD",
- "FWDATA ",
- "TXMEDIA"
- };
- const char *cmds[] = {
- "(0?)",
- "HANGUP ",
- "RING ",
- "RINGING",
- "ANSWER ",
- "BUSY ",
- "TKOFFHK",
- "OFFHOOK",
- "CONGSTN",
- "FLASH ",
- "WINK ",
- "OPTION ",
- "RDKEY ",
- "RDUNKEY",
- "PROGRES",
- "PROCDNG",
- "HOLD ",
- "UNHOLD ",
- "VIDUPDT", };
- struct ast_iax2_full_hdr *fh;
- char retries[20];
- char class2[20];
- char subclass2[20];
- const char *class;
- const char *subclass;
- char *dir;
- char tmp[512];
-
- switch(rx) {
- case 0:
- dir = "Tx";
- break;
- case 2:
- dir = "TE";
- break;
- case 3:
- dir = "RD";
- break;
- default:
- dir = "Rx";
- break;
- }
- if (f) {
- fh = f->data;
- snprintf(retries, sizeof(retries), "%03d", f->retries);
- } else {
- fh = fhi;
- if (ntohs(fh->dcallno) & IAX_FLAG_RETRANS)
- strcpy(retries, "Yes");
- else
- strcpy(retries, " No");
- }
- if (!(ntohs(fh->scallno) & IAX_FLAG_FULL)) {
- /* Don't mess with mini-frames */
- return;
- }
- if (fh->type >= (int)sizeof(frames)/(int)sizeof(frames[0])) {
- snprintf(class2, sizeof(class2), "(%d?)", fh->type);
- class = class2;
- } else {
- class = frames[(int)fh->type];
- }
- if (fh->type == AST_FRAME_DTMF_BEGIN || fh->type == AST_FRAME_DTMF_END) {
- sprintf(subclass2, "%c", fh->csub);
- subclass = subclass2;
- } else if (fh->type == AST_FRAME_IAX) {
- if (fh->csub >= (int)sizeof(iaxs)/(int)sizeof(iaxs[0])) {
- snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub);
- subclass = subclass2;
- } else {
- subclass = iaxs[(int)fh->csub];
- }
- } else if (fh->type == AST_FRAME_CONTROL) {
- if (fh->csub >= (int)sizeof(cmds)/(int)sizeof(cmds[0])) {
- snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub);
- subclass = subclass2;
- } else {
- subclass = cmds[(int)fh->csub];
- }
- } else {
- snprintf(subclass2, sizeof(subclass2), "%d", fh->csub);
- subclass = subclass2;
- }
- snprintf(tmp, sizeof(tmp),
- "%s-Frame Retry[%s] -- OSeqno: %3.3d ISeqno: %3.3d Type: %s Subclass: %s\n",
- dir,
- retries, fh->oseqno, fh->iseqno, class, subclass);
- outputf(tmp);
- snprintf(tmp, sizeof(tmp),
- " Timestamp: %05lums SCall: %5.5d DCall: %5.5d [%s:%d]\n",
- (unsigned long)ntohl(fh->ts),
- ntohs(fh->scallno) & ~IAX_FLAG_FULL, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS,
- ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
- outputf(tmp);
- if (fh->type == AST_FRAME_IAX)
- dump_ies(fh->iedata, datalen);
-}
-
-int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, const void *data, int datalen)
-{
- char tmp[256];
- if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
- snprintf(tmp, (int)sizeof(tmp), "Out of space for ie '%s' (%d), need %d have %d\n", iax_ie2str(ie), ie, datalen, (int)sizeof(ied->buf) - ied->pos);
- errorf(tmp);
- return -1;
- }
- ied->buf[ied->pos++] = ie;
- ied->buf[ied->pos++] = datalen;
- memcpy(ied->buf + ied->pos, data, datalen);
- ied->pos += datalen;
- return 0;
-}
-
-int iax_ie_append_addr(struct iax_ie_data *ied, unsigned char ie, const struct sockaddr_in *sin)
-{
- return iax_ie_append_raw(ied, ie, sin, (int)sizeof(struct sockaddr_in));
-}
-
-int iax_ie_append_int(struct iax_ie_data *ied, unsigned char ie, unsigned int value)
-{
- unsigned int newval;
- newval = htonl(value);
- return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
-}
-
-int iax_ie_append_short(struct iax_ie_data *ied, unsigned char ie, unsigned short value)
-{
- unsigned short newval;
- newval = htons(value);
- return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
-}
-
-int iax_ie_append_str(struct iax_ie_data *ied, unsigned char ie, const char *str)
-{
- return iax_ie_append_raw(ied, ie, str, strlen(str));
-}
-
-int iax_ie_append_byte(struct iax_ie_data *ied, unsigned char ie, unsigned char dat)
-{
- return iax_ie_append_raw(ied, ie, &dat, 1);
-}
-
-int iax_ie_append(struct iax_ie_data *ied, unsigned char ie)
-{
- return iax_ie_append_raw(ied, ie, NULL, 0);
-}
-
-void iax_set_output(void (*func)(const char *))
-{
- outputf = func;
-}
-
-void iax_set_error(void (*func)(const char *))
-{
- errorf = func;
-}
-
-int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
-{
- /* Parse data into information elements */
- int len;
- int ie;
- char tmp[256];
- memset(ies, 0, (int)sizeof(struct iax_ies));
- ies->msgcount = -1;
- ies->firmwarever = -1;
- ies->calling_ton = -1;
- ies->calling_tns = -1;
- ies->calling_pres = -1;
- ies->samprate = IAX_RATE_8KHZ;
- while(datalen >= 2) {
- ie = data[0];
- len = data[1];
- if (len > datalen - 2) {
- errorf("Information element length exceeds message size\n");
- return -1;
- }
- switch(ie) {
- case IAX_IE_CALLED_NUMBER:
- ies->called_number = (char *)data + 2;
- break;
- case IAX_IE_CALLING_NUMBER:
- ies->calling_number = (char *)data + 2;
- break;
- case IAX_IE_CALLING_ANI:
- ies->calling_ani = (char *)data + 2;
- break;
- case IAX_IE_CALLING_NAME:
- ies->calling_name = (char *)data + 2;
- break;
- case IAX_IE_CALLED_CONTEXT:
- ies->called_context = (char *)data + 2;
- break;
- case IAX_IE_USERNAME:
- ies->username = (char *)data + 2;
- break;
- case IAX_IE_PASSWORD:
- ies->password = (char *)data + 2;
- break;
- case IAX_IE_CODEC_PREFS:
- ies->codec_prefs = (char *)data + 2;
- break;
- case IAX_IE_CAPABILITY:
- if (len != (int)sizeof(unsigned int)) {
- snprintf(tmp, (int)sizeof(tmp), "Expecting capability to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
- errorf(tmp);
- } else
- ies->capability = ntohl(get_unaligned_uint32(data + 2));
- break;
- case IAX_IE_FORMAT:
- if (len != (int)sizeof(unsigned int)) {
- snprintf(tmp, (int)sizeof(tmp), "Expecting format to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
- errorf(tmp);
- } else
- ies->format = ntohl(get_unaligned_uint32(data + 2));
- break;
- case IAX_IE_LANGUAGE:
- ies->language = (char *)data + 2;
- break;
- case IAX_IE_VERSION:
- if (len != (int)sizeof(unsigned short)) {
- snprintf(tmp, (int)sizeof(tmp), "Expecting version to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
- errorf(tmp);
- } else
- ies->version = ntohs(get_unaligned_uint16(data + 2));
- break;
- case IAX_IE_ADSICPE:
- if (len != (int)sizeof(unsigned short)) {
- snprintf(tmp, (int)sizeof(tmp), "Expecting adsicpe to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
- errorf(tmp);
- } else
- ies->adsicpe = ntohs(get_unaligned_uint16(data + 2));
- break;
- case IAX_IE_SAMPLINGRATE:
- if (len != (int)sizeof(unsigned short)) {
- snprintf(tmp, (int)sizeof(tmp), "Expecting samplingrate to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
- errorf(tmp);
- } else
- ies->samprate = ntohs(get_unaligned_uint16(data + 2));
- break;
- case IAX_IE_DNID:
- ies->dnid = (char *)data + 2;
- break;
- case IAX_IE_RDNIS:
- ies->rdnis = (char *)data + 2;
- break;
- case IAX_IE_AUTHMETHODS:
- if (len != (int)sizeof(unsigned short)) {
- snprintf(tmp, (int)sizeof(tmp), "Expecting authmethods to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
- errorf(tmp);
- } else
- ies->authmethods = ntohs(get_unaligned_uint16(data + 2));
- break;
- case IAX_IE_ENCRYPTION:
- if (len != (int)sizeof(unsigned short)) {
- snprintf(tmp, (int)sizeof(tmp), "Expecting encryption to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
- errorf(tmp);
- } else
- ies->encmethods = ntohs(get_unaligned_uint16(data + 2));
- break;
- case IAX_IE_CHALLENGE:
- ies->challenge = (char *)data + 2;
- break;
- case IAX_IE_MD5_RESULT:
- ies->md5_result = (char *)data + 2;
- break;
- case IAX_IE_RSA_RESULT:
- ies->rsa_result = (char *)data + 2;
- break;
- case IAX_IE_APPARENT_ADDR:
- ies->apparent_addr = ((struct sockaddr_in *)(data + 2));
- break;
- case IAX_IE_REFRESH:
- if (len != (int)sizeof(unsigned short)) {
- snprintf(tmp, (int)sizeof(tmp), "Expecting refresh to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
- errorf(tmp);
- } else
- ies->refresh = ntohs(get_unaligned_uint16(data + 2));
- break;
- case IAX_IE_DPSTATUS:
- if (len != (int)sizeof(unsigned short)) {
- snprintf(tmp, (int)sizeof(tmp), "Expecting dpstatus to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
- errorf(tmp);
- } else
- ies->dpstatus = ntohs(get_unaligned_uint16(data + 2));
- break;
- case IAX_IE_CALLNO:
- if (len != (int)sizeof(unsigned short)) {
- snprintf(tmp, (int)sizeof(tmp), "Expecting callno to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
- errorf(tmp);
- } else
- ies->callno = ntohs(get_unaligned_uint16(data + 2));
- break;
- case IAX_IE_CAUSE:
- ies->cause = (char *)data + 2;
- break;
- case IAX_IE_CAUSECODE:
- if (len != 1) {
- snprintf(tmp, (int)sizeof(tmp), "Expecting causecode to be single byte but was %d\n", len);
- errorf(tmp);
- } else {
- ies->causecode = data[2];
- }
- break;
- case IAX_IE_IAX_UNKNOWN:
- if (len == 1)
- ies->iax_unknown = data[2];
- else {
- snprintf(tmp, (int)sizeof(tmp), "Expected single byte Unknown command, but was %d long\n", len);
- errorf(tmp);
- }
- break;
- case IAX_IE_MSGCOUNT:
- if (len != (int)sizeof(unsigned short)) {
- snprintf(tmp, (int)sizeof(tmp), "Expecting msgcount to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
- errorf(tmp);
- } else
- ies->msgcount = ntohs(get_unaligned_uint16(data + 2));
- break;
- case IAX_IE_AUTOANSWER:
- ies->autoanswer = 1;
- break;
- case IAX_IE_MUSICONHOLD:
- ies->musiconhold = 1;
- break;
- case IAX_IE_TRANSFERID:
- if (len != (int)sizeof(unsigned int)) {
- snprintf(tmp, (int)sizeof(tmp), "Expecting transferid to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
- errorf(tmp);
- } else
- ies->transferid = ntohl(get_unaligned_uint32(data + 2));
- break;
- case IAX_IE_DATETIME:
- if (len != (int)sizeof(unsigned int)) {
- snprintf(tmp, (int)sizeof(tmp), "Expecting date/time to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
- errorf(tmp);
- } else
- ies->datetime = ntohl(get_unaligned_uint32(data + 2));
- break;
- case IAX_IE_FIRMWAREVER:
- if (len != (int)sizeof(unsigned short)) {
- snprintf(tmp, (int)sizeof(tmp), "Expecting firmwarever to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
- errorf(tmp);
- } else
- ies->firmwarever = ntohs(get_unaligned_uint16(data + 2));
- break;
- case IAX_IE_DEVICETYPE:
- ies->devicetype = (char *)data + 2;
- break;
- case IAX_IE_SERVICEIDENT:
- ies->serviceident = (char *)data + 2;
- break;
- case IAX_IE_FWBLOCKDESC:
- if (len != (int)sizeof(unsigned int)) {
- snprintf(tmp, (int)sizeof(tmp), "Expected block desc to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
- errorf(tmp);
- } else
- ies->fwdesc = ntohl(get_unaligned_uint32(data + 2));
- break;
- case IAX_IE_FWBLOCKDATA:
- ies->fwdata = data + 2;
- ies->fwdatalen = len;
- break;
- case IAX_IE_ENCKEY:
- ies->enckey = data + 2;
- ies->enckeylen = len;
- break;
- case IAX_IE_PROVVER:
- if (len != (int)sizeof(unsigned int)) {
- snprintf(tmp, (int)sizeof(tmp), "Expected provisioning version to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
- errorf(tmp);
- } else {
- ies->provverpres = 1;
- ies->provver = ntohl(get_unaligned_uint32(data + 2));
- }
- break;
- case IAX_IE_CALLINGPRES:
- if (len == 1)
- ies->calling_pres = data[2];
- else {
- snprintf(tmp, (int)sizeof(tmp), "Expected single byte callingpres, but was %d long\n", len);
- errorf(tmp);
- }
- break;
- case IAX_IE_CALLINGTON:
- if (len == 1)
- ies->calling_ton = data[2];
- else {
- snprintf(tmp, (int)sizeof(tmp), "Expected single byte callington, but was %d long\n", len);
- errorf(tmp);
- }
- break;
- case IAX_IE_CALLINGTNS:
- if (len != (int)sizeof(unsigned short)) {
- snprintf(tmp, (int)sizeof(tmp), "Expecting callingtns to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
- errorf(tmp);
- } else
- ies->calling_tns = ntohs(get_unaligned_uint16(data + 2));
- break;
- case IAX_IE_RR_JITTER:
- if (len != (int)sizeof(unsigned int)) {
- snprintf(tmp, (int)sizeof(tmp), "Expected jitter rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
- errorf(tmp);
- } else {
- ies->rr_jitter = ntohl(get_unaligned_uint32(data + 2));
- }
- break;
- case IAX_IE_RR_LOSS:
- if (len != (int)sizeof(unsigned int)) {
- snprintf(tmp, (int)sizeof(tmp), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
- errorf(tmp);
- } else {
- ies->rr_loss = ntohl(get_unaligned_uint32(data + 2));
- }
- break;
- case IAX_IE_RR_PKTS:
- if (len != (int)sizeof(unsigned int)) {
- snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
- errorf(tmp);
- } else {
- ies->rr_pkts = ntohl(get_unaligned_uint32(data + 2));
- }
- break;
- case IAX_IE_RR_DELAY:
- if (len != (int)sizeof(unsigned short)) {
- snprintf(tmp, (int)sizeof(tmp), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
- errorf(tmp);
- } else {
- ies->rr_delay = ntohs(get_unaligned_uint16(data + 2));
- }
- break;
- case IAX_IE_RR_DROPPED:
- if (len != (int)sizeof(unsigned int)) {
- snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
- errorf(tmp);
- } else {
- ies->rr_dropped = ntohl(get_unaligned_uint32(data + 2));
- }
- break;
- case IAX_IE_RR_OOO:
- if (len != (int)sizeof(unsigned int)) {
- snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
- errorf(tmp);
- } else {
- ies->rr_ooo = ntohl(get_unaligned_uint32(data + 2));
- }
- break;
- default:
- snprintf(tmp, (int)sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", iax_ie2str(ie), ie, len);
- outputf(tmp);
- }
- /* Overwrite information element with 0, to null terminate previous portion */
- data[0] = 0;
- datalen -= (len + 2);
- data += (len + 2);
- }
- /* Null-terminate last field */
- *data = '\0';
- if (datalen) {
- errorf("Invalid information element contents, strange boundary\n");
- return -1;
- }
- return 0;
-}
-
-void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f)
-{
- fr->af.frametype = f->frametype;
- fr->af.subclass = f->subclass;
- fr->af.mallocd = 0; /* Our frame is static relative to the container */
- fr->af.datalen = f->datalen;
- fr->af.samples = f->samples;
- fr->af.offset = AST_FRIENDLY_OFFSET;
- fr->af.src = f->src;
- fr->af.delivery.tv_sec = 0;
- fr->af.delivery.tv_usec = 0;
- fr->af.data = fr->afdata;
- fr->af.len = f->len;
- if (fr->af.datalen) {
- size_t copy_len = fr->af.datalen;
- if (copy_len > fr->afdatalen) {
- ast_log(LOG_ERROR, "Losing frame data because destination buffer size '%d' bytes not big enough for '%d' bytes in the frame\n",
- (int) fr->afdatalen, (int) fr->af.datalen);
- copy_len = fr->afdatalen;
- }
-#if __BYTE_ORDER == __LITTLE_ENDIAN
- /* We need to byte-swap slinear samples from network byte order */
- if ((fr->af.frametype == AST_FRAME_VOICE) && (fr->af.subclass == AST_FORMAT_SLINEAR)) {
- /* 2 bytes / sample for SLINEAR */
- ast_swapcopy_samples(fr->af.data, f->data, copy_len / 2);
- } else
-#endif
- memcpy(fr->af.data, f->data, copy_len);
- }
-}
-
-struct iax_frame *iax_frame_new(int direction, int datalen, unsigned int cacheable)
-{
- struct iax_frame *fr = NULL;
-
-#if !defined(LOW_MEMORY)
- struct iax_frames *iax_frames;
-
- /* Attempt to get a frame from this thread's cache */
- if ((iax_frames = ast_threadstorage_get(&frame_cache, sizeof(*iax_frames)))) {
- AST_LIST_TRAVERSE_SAFE_BEGIN(&iax_frames->list, fr, list) {
- if (fr->afdatalen >= datalen) {
- size_t afdatalen = fr->afdatalen;
- AST_LIST_REMOVE_CURRENT(&iax_frames->list, list);
- iax_frames->size--;
- memset(fr, 0, sizeof(*fr));
- fr->afdatalen = afdatalen;
- break;
- }
- }
- AST_LIST_TRAVERSE_SAFE_END
- }
- if (!fr) {
- if (!(fr = ast_calloc_cache(1, sizeof(*fr) + datalen)))
- return NULL;
- fr->afdatalen = datalen;
- }
-#else
- if (!(fr = ast_calloc(1, sizeof(*fr) + datalen)))
- return NULL;
- fr->afdatalen = datalen;
-#endif
-
-
- fr->direction = direction;
- fr->retrans = -1;
- fr->cacheable = cacheable;
-
- if (fr->direction == DIRECTION_INGRESS)
- ast_atomic_fetchadd_int(&iframes, 1);
- else
- ast_atomic_fetchadd_int(&oframes, 1);
-
- ast_atomic_fetchadd_int(&frames, 1);
-
- return fr;
-}
-
-void iax_frame_free(struct iax_frame *fr)
-{
-#if !defined(LOW_MEMORY)
- struct iax_frames *iax_frames;
-#endif
-
- /* Note: does not remove from scheduler! */
- if (fr->direction == DIRECTION_INGRESS)
- ast_atomic_fetchadd_int(&iframes, -1);
- else if (fr->direction == DIRECTION_OUTGRESS)
- ast_atomic_fetchadd_int(&oframes, -1);
- else {
- errorf("Attempt to double free frame detected\n");
- return;
- }
- ast_atomic_fetchadd_int(&frames, -1);
-
-#if !defined(LOW_MEMORY)
- if (!fr->cacheable || !(iax_frames = ast_threadstorage_get(&frame_cache, sizeof(*iax_frames)))) {
- free(fr);
- return;
- }
-
- if (iax_frames->size < FRAME_CACHE_MAX_SIZE) {
- fr->direction = 0;
- AST_LIST_INSERT_HEAD(&iax_frames->list, fr, list);
- iax_frames->size++;
- return;
- }
-#endif
- free(fr);
-}
-
-#if !defined(LOW_MEMORY)
-static void frame_cache_cleanup(void *data)
-{
- struct iax_frames *frames = data;
- struct iax_frame *cur;
-
- while ((cur = AST_LIST_REMOVE_HEAD(&frames->list, list)))
- free(cur);
-
- free(frames);
-}
-#endif
-
-int iax_get_frames(void) { return frames; }
-int iax_get_iframes(void) { return iframes; }
-int iax_get_oframes(void) { return oframes; }
diff --git a/1.4.23-rc4/channels/iax2-parser.h b/1.4.23-rc4/channels/iax2-parser.h
deleted file mode 100644
index 0f3e18c00..000000000
--- a/1.4.23-rc4/channels/iax2-parser.h
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Asterisk -- A telephony toolkit for Linux.
- *
- * Implementation of Inter-Asterisk eXchange
- *
- * Copyright (C) 2003, Digium
- *
- * Mark Spencer <markster@digium.com>
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License
- */
-
-/*!\file
- * \brief Implementation of the IAX2 protocol
- */
-
-#ifndef _IAX2_PARSER_H
-#define _IAX2_PARSER_H
-
-#include "asterisk/linkedlists.h"
-
-struct iax_ies {
- char *called_number;
- char *calling_number;
- char *calling_ani;
- char *calling_name;
- int calling_ton;
- int calling_tns;
- int calling_pres;
- char *called_context;
- char *username;
- char *password;
- unsigned int capability;
- unsigned int format;
- char *codec_prefs;
- char *language;
- int version;
- unsigned short adsicpe;
- char *dnid;
- char *rdnis;
- unsigned int authmethods;
- unsigned int encmethods;
- char *challenge;
- char *md5_result;
- char *rsa_result;
- struct sockaddr_in *apparent_addr;
- unsigned short refresh;
- unsigned short dpstatus;
- unsigned short callno;
- char *cause;
- unsigned char causecode;
- unsigned char iax_unknown;
- int msgcount;
- int autoanswer;
- int musiconhold;
- unsigned int transferid;
- unsigned int datetime;
- char *devicetype;
- char *serviceident;
- int firmwarever;
- unsigned int fwdesc;
- unsigned char *fwdata;
- unsigned char fwdatalen;
- unsigned char *enckey;
- unsigned char enckeylen;
- unsigned int provver;
- unsigned short samprate;
- int provverpres;
- unsigned int rr_jitter;
- unsigned int rr_loss;
- unsigned int rr_pkts;
- unsigned short rr_delay;
- unsigned int rr_dropped;
- unsigned int rr_ooo;
-};
-
-#define DIRECTION_INGRESS 1
-#define DIRECTION_OUTGRESS 2
-
-struct iax_frame {
-#ifdef LIBIAX
- struct iax_session *session;
- struct iax_event *event;
-#else
- int sockfd;
-#endif
-
- /* /Our/ call number */
- unsigned short callno;
- /* /Their/ call number */
- unsigned short dcallno;
- /* Start of raw frame (outgoing only) */
- void *data;
- /* Length of frame (outgoing only) */
- int datalen;
- /* How many retries so far? */
- int retries;
- /* Outgoing relative timestamp (ms) */
- unsigned int ts;
- /* How long to wait before retrying */
- int retrytime;
- /* Are we received out of order? */
- unsigned int outoforder:1;
- /* Have we been sent at all yet? */
- unsigned int sentyet:1;
- /* Non-zero if should be sent to transfer peer */
- unsigned int transfer:1;
- /* Non-zero if this is the final message */
- unsigned int final:1;
- /* Ingress or outgres */
- unsigned int direction:2;
- /* Can this frame be cached? */
- unsigned int cacheable:1;
- /* Outgoing Packet sequence number */
- int oseqno;
- /* Next expected incoming packet sequence number */
- int iseqno;
- /* Retransmission ID */
- int retrans;
- /* Easy linking */
- AST_LIST_ENTRY(iax_frame) list;
- /* Actual, isolated frame header */
- struct ast_frame af;
- /*! Amount of space _allocated_ for data */
- size_t afdatalen;
- unsigned char unused[AST_FRIENDLY_OFFSET];
- unsigned char afdata[0]; /* Data for frame */
-};
-
-struct iax_ie_data {
- unsigned char buf[1024];
- int pos;
-};
-
-/* Choose a different function for output */
-void iax_set_output(void (*output)(const char *data));
-/* Choose a different function for errors */
-void iax_set_error(void (*output)(const char *data));
-void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen);
-
-const char *iax_ie2str(int ie);
-
-int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, const void *data, int datalen);
-int iax_ie_append_addr(struct iax_ie_data *ied, unsigned char ie, const struct sockaddr_in *sin);
-int iax_ie_append_int(struct iax_ie_data *ied, unsigned char ie, unsigned int value);
-int iax_ie_append_short(struct iax_ie_data *ied, unsigned char ie, unsigned short value);
-int iax_ie_append_str(struct iax_ie_data *ied, unsigned char ie, const char *str);
-int iax_ie_append_byte(struct iax_ie_data *ied, unsigned char ie, unsigned char dat);
-int iax_ie_append(struct iax_ie_data *ied, unsigned char ie);
-int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen);
-
-int iax_get_frames(void);
-int iax_get_iframes(void);
-int iax_get_oframes(void);
-
-void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f);
-struct iax_frame *iax_frame_new(int direction, int datalen, unsigned int cacheable);
-void iax_frame_free(struct iax_frame *fr);
-#endif
diff --git a/1.4.23-rc4/channels/iax2-provision.c b/1.4.23-rc4/channels/iax2-provision.c
deleted file mode 100644
index b6137a88b..000000000
--- a/1.4.23-rc4/channels/iax2-provision.c
+++ /dev/null
@@ -1,540 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 1999 - 2006, Digium, Inc.
- *
- * Mark Spencer <markster@digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief IAX Provisioning Protocol
- *
- * \author Mark Spencer <markster@digium.com>
- */
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <netinet/in_systm.h>
-#include <netinet/ip.h>
-#include <sys/socket.h>
-
-#include "asterisk/config.h"
-#include "asterisk/logger.h"
-#include "asterisk/cli.h"
-#include "asterisk/lock.h"
-#include "asterisk/frame.h"
-#include "asterisk/options.h"
-#include "asterisk/md5.h"
-#include "asterisk/astdb.h"
-#include "asterisk/utils.h"
-#include "asterisk/acl.h"
-#include "iax2.h"
-#include "iax2-provision.h"
-#include "iax2-parser.h"
-
-#ifndef IPTOS_MINCOST
-#define IPTOS_MINCOST 0x02
-#endif
-
-static int provinit = 0;
-
-struct iax_template {
- int dead;
- char name[80];
- char src[80];
- struct iax_template *next;
- char user[20];
- char pass[20];
- char lang[10];
- unsigned short port;
- unsigned int server;
- unsigned short serverport;
- unsigned int altserver;
- unsigned int flags;
- unsigned int format;
- unsigned int tos;
-} *templates;
-
-static struct iax_flag {
- char *name;
- int value;
-} iax_flags[] = {
- { "register", PROV_FLAG_REGISTER },
- { "secure", PROV_FLAG_SECURE },
- { "heartbeat", PROV_FLAG_HEARTBEAT },
- { "debug", PROV_FLAG_DEBUG },
- { "disablecid", PROV_FLAG_DIS_CALLERID },
- { "disablecw", PROV_FLAG_DIS_CALLWAIT },
- { "disablecidcw", PROV_FLAG_DIS_CIDCW },
- { "disable3way", PROV_FLAG_DIS_THREEWAY },
-};
-
-char *iax_provflags2str(char *buf, int buflen, unsigned int flags)
-{
- int x;
-
- if (!buf || buflen < 1)
- return NULL;
-
- buf[0] = '\0';
-
- for (x = 0; x < sizeof(iax_flags) / sizeof(iax_flags[0]); x++) {
- if (flags & iax_flags[x].value){
- strncat(buf, iax_flags[x].name, buflen - strlen(buf) - 1);
- strncat(buf, ",", buflen - strlen(buf) - 1);
- }
- }
-
- if (!ast_strlen_zero(buf))
- buf[strlen(buf) - 1] = '\0';
- else
- strncpy(buf, "none", buflen - 1);
-
- return buf;
-}
-
-static unsigned int iax_str2flags(const char *buf)
-{
- int x;
- int len;
- int found;
- unsigned int flags = 0;
- char *e;
- while(buf && *buf) {
- e = strchr(buf, ',');
- if (e)
- len = e - buf;
- else
- len = 0;
- found = 0;
- for (x=0;x<sizeof(iax_flags) / sizeof(iax_flags[0]); x++) {
- if ((len && !strncasecmp(iax_flags[x].name, buf, len)) ||
- (!len && !strcasecmp(iax_flags[x].name, buf))) {
- flags |= iax_flags[x].value;
- break;
- }
- }
- if (e) {
- buf = e + 1;
- while(*buf && (*buf < 33))
- buf++;
- } else
- break;
- }
- return flags;
-}
-AST_MUTEX_DEFINE_STATIC(provlock);
-
-static struct iax_template *iax_template_find(const char *s, int allowdead)
-{
- struct iax_template *cur;
- cur = templates;
- while(cur) {
- if (!strcasecmp(s, cur->name)) {
- if (!allowdead && cur->dead)
- cur = NULL;
- break;
- }
- cur = cur->next;
- }
- return cur;
-}
-
-char *iax_prov_complete_template(const char *line, const char *word, int pos, int state)
-{
- struct iax_template *c;
- int which=0;
- char *ret = NULL;
- int wordlen = strlen(word);
-
- ast_mutex_lock(&provlock);
- for (c = templates; c; c = c->next) {
- if (!strncasecmp(word, c->name, wordlen) && ++which > state) {
- ret = strdup(c->name);
- break;
- }
- }
- ast_mutex_unlock(&provlock);
-
- return ret;
-}
-
-static unsigned int prov_ver_calc(struct iax_ie_data *provdata)
-{
- struct MD5Context md5;
- unsigned int tmp[4];
- MD5Init(&md5);
- MD5Update(&md5, provdata->buf, provdata->pos);
- MD5Final((unsigned char *)tmp, &md5);
- return tmp[0] ^ tmp[1] ^ tmp[2] ^ tmp[3];
-}
-
-int iax_provision_build(struct iax_ie_data *provdata, unsigned int *signature, const char *template, int force)
-{
- struct iax_template *cur;
- unsigned int sig;
- char tmp[40];
- memset(provdata, 0, sizeof(*provdata));
- ast_mutex_lock(&provlock);
- cur = iax_template_find(template, 1);
- /* If no match, try searching for '*' */
- if (!cur)
- cur = iax_template_find("*", 1);
- if (cur) {
- /* found it -- add information elements as appropriate */
- if (force || strlen(cur->user))
- iax_ie_append_str(provdata, PROV_IE_USER, cur->user);
- if (force || strlen(cur->pass))
- iax_ie_append_str(provdata, PROV_IE_PASS, cur->pass);
- if (force || strlen(cur->lang))
- iax_ie_append_str(provdata, PROV_IE_LANG, cur->lang);
- if (force || cur->port)
- iax_ie_append_short(provdata, PROV_IE_PORTNO, cur->port);
- if (force || cur->server)
- iax_ie_append_int(provdata, PROV_IE_SERVERIP, cur->server);
- if (force || cur->serverport)
- iax_ie_append_short(provdata, PROV_IE_SERVERPORT, cur->serverport);
- if (force || cur->altserver)
- iax_ie_append_int(provdata, PROV_IE_ALTSERVER, cur->altserver);
- if (force || cur->flags)
- iax_ie_append_int(provdata, PROV_IE_FLAGS, cur->flags);
- if (force || cur->format)
- iax_ie_append_int(provdata, PROV_IE_FORMAT, cur->format);
- if (force || cur->tos)
- iax_ie_append_byte(provdata, PROV_IE_TOS, cur->tos);
-
- /* Calculate checksum of message so far */
- sig = prov_ver_calc(provdata);
- if (signature)
- *signature = sig;
- /* Store signature */
- iax_ie_append_int(provdata, PROV_IE_PROVVER, sig);
- /* Cache signature for later verification so we need not recalculate all this */
- snprintf(tmp, sizeof(tmp), "v0x%08x", sig);
- ast_db_put("iax/provisioning/cache", template, tmp);
- } else
- ast_db_put("iax/provisioning/cache", template, "u");
- ast_mutex_unlock(&provlock);
- return cur ? 0 : -1;
-}
-
-int iax_provision_version(unsigned int *version, const char *template, int force)
-{
- char tmp[80] = "";
- struct iax_ie_data ied;
- int ret=0;
- memset(&ied, 0, sizeof(ied));
-
- ast_mutex_lock(&provlock);
- ast_db_get("iax/provisioning/cache", template, tmp, sizeof(tmp));
- if (sscanf(tmp, "v%x", version) != 1) {
- if (strcmp(tmp, "u")) {
- ret = iax_provision_build(&ied, version, template, force);
- if (ret)
- ast_log(LOG_DEBUG, "Unable to create provisioning packet for '%s'\n", template);
- } else
- ret = -1;
- } else if (option_debug)
- ast_log(LOG_DEBUG, "Retrieved cached version '%s' = '%08x'\n", tmp, *version);
- ast_mutex_unlock(&provlock);
- return ret;
-}
-
-static int iax_template_parse(struct iax_template *cur, struct ast_config *cfg, const char *s, const char *def)
-{
- struct ast_variable *v;
- int foundportno = 0;
- int foundserverportno = 0;
- int x;
- struct in_addr ia;
- struct hostent *hp;
- struct ast_hostent h;
- struct iax_template *src, tmp;
- const char *t;
- if (def) {
- t = ast_variable_retrieve(cfg, s ,"template");
- src = NULL;
- if (t && strlen(t)) {
- src = iax_template_find(t, 0);
- if (!src)
- ast_log(LOG_WARNING, "Unable to find base template '%s' for creating '%s'. Trying '%s'\n", t, s, def);
- else
- def = t;
- }
- if (!src) {
- src = iax_template_find(def, 0);
- if (!src)
- ast_log(LOG_WARNING, "Unable to locate default base template '%s' for creating '%s', omitting.\n", def, s);
- }
- if (!src)
- return -1;
- ast_mutex_lock(&provlock);
- /* Backup old data */
- memcpy(&tmp, cur, sizeof(tmp));
- /* Restore from src */
- memcpy(cur, src, sizeof(tmp));
- /* Restore important headers */
- memcpy(cur->name, tmp.name, sizeof(cur->name));
- cur->dead = tmp.dead;
- cur->next = tmp.next;
- ast_mutex_unlock(&provlock);
- }
- if (def)
- strncpy(cur->src, def, sizeof(cur->src) - 1);
- else
- cur->src[0] = '\0';
- v = ast_variable_browse(cfg, s);
- while(v) {
- if (!strcasecmp(v->name, "port") || !strcasecmp(v->name, "serverport")) {
- if ((sscanf(v->value, "%d", &x) == 1) && (x > 0) && (x < 65535)) {
- if (!strcasecmp(v->name, "port")) {
- cur->port = x;
- foundportno = 1;
- } else {
- cur->serverport = x;
- foundserverportno = 1;
- }
- } else
- ast_log(LOG_WARNING, "Ignoring invalid %s '%s' for '%s' at line %d\n", v->name, v->value, s, v->lineno);
- } else if (!strcasecmp(v->name, "server") || !strcasecmp(v->name, "altserver")) {
- hp = ast_gethostbyname(v->value, &h);
- if (hp) {
- memcpy(&ia, hp->h_addr, sizeof(ia));
- if (!strcasecmp(v->name, "server"))
- cur->server = ntohl(ia.s_addr);
- else
- cur->altserver = ntohl(ia.s_addr);
- } else
- ast_log(LOG_WARNING, "Ignoring invalid %s '%s' for '%s' at line %d\n", v->name, v->value, s, v->lineno);
- } else if (!strcasecmp(v->name, "codec")) {
- if ((x = ast_getformatbyname(v->value)) > 0) {
- cur->format = x;
- } else
- ast_log(LOG_WARNING, "Ignoring invalid codec '%s' for '%s' at line %d\n", v->value, s, v->lineno);
- } else if (!strcasecmp(v->name, "tos")) {
- if (ast_str2tos(v->value, &cur->tos))
- ast_log(LOG_WARNING, "Invalid tos value at line %d, see doc/ip-tos.txt for more information.\n", v->lineno);
- } else if (!strcasecmp(v->name, "user")) {
- strncpy(cur->user, v->value, sizeof(cur->user) - 1);
- if (strcmp(cur->user, v->value))
- ast_log(LOG_WARNING, "Truncating username from '%s' to '%s' for '%s' at line %d\n", v->value, cur->user, s, v->lineno);
- } else if (!strcasecmp(v->name, "pass")) {
- strncpy(cur->pass, v->value, sizeof(cur->pass) - 1);
- if (strcmp(cur->pass, v->value))
- ast_log(LOG_WARNING, "Truncating password from '%s' to '%s' for '%s' at line %d\n", v->value, cur->pass, s, v->lineno);
- } else if (!strcasecmp(v->name, "language")) {
- strncpy(cur->lang, v->value, sizeof(cur->lang) - 1);
- if (strcmp(cur->lang, v->value))
- ast_log(LOG_WARNING, "Truncating language from '%s' to '%s' for '%s' at line %d\n", v->value, cur->lang, s, v->lineno);
- } else if (!strcasecmp(v->name, "flags")) {
- cur->flags = iax_str2flags(v->value);
- } else if (!strncasecmp(v->name, "flags", 5) && strchr(v->name, '+')) {
- cur->flags |= iax_str2flags(v->value);
- } else if (!strncasecmp(v->name, "flags", 5) && strchr(v->name, '-')) {
- cur->flags &= ~iax_str2flags(v->value);
- } else if (strcasecmp(v->name, "template")) {
- ast_log(LOG_WARNING, "Unknown keyword '%s' in definition of '%s' at line %d\n", v->name, s, v->lineno);
- }
- v = v->next;
- }
- if (!foundportno)
- cur->port = IAX_DEFAULT_PORTNO;
- if (!foundserverportno)
- cur->serverport = IAX_DEFAULT_PORTNO;
- return 0;
-}
-
-static int iax_process_template(struct ast_config *cfg, char *s, char *def)
-{
- /* Find an already existing one if there */
- struct iax_template *cur;
- int mallocd = 0;
- cur = templates;
- while(cur) {
- if (!strcasecmp(cur->name, s))
- break;
- cur = cur->next;
- }
- if (!cur) {
- mallocd = 1;
- cur = malloc(sizeof(struct iax_template));
- if (!cur) {
- ast_log(LOG_WARNING, "Out of memory!\n");
- return -1;
- }
- /* Initialize entry */
- memset(cur, 0, sizeof(*cur));
- strncpy(cur->name, s, sizeof(cur->name) - 1);
- cur->dead = 1;
- }
- if (!iax_template_parse(cur, cfg, s, def))
- cur->dead = 0;
-
- /* Link if we're mallocd */
- if (mallocd) {
- ast_mutex_lock(&provlock);
- cur->next = templates;
- templates = cur;
- ast_mutex_unlock(&provlock);
- }
- return 0;
-}
-
-static char show_provisioning_usage[] =
-"Usage: iax list provisioning [template]\n"
-" Lists all known IAX provisioning templates or a\n"
-" specific one if specified.\n";
-
-static const char *ifthere(const char *s)
-{
- if (strlen(s))
- return s;
- else
- return "<unspecified>";
-}
-
-static const char *iax_server(unsigned int addr)
-{
- struct in_addr ia;
-
- if (!addr)
- return "<unspecified>";
-
- ia.s_addr = htonl(addr);
-
- return ast_inet_ntoa(ia);
-}
-
-
-static int iax_show_provisioning(int fd, int argc, char *argv[])
-{
- struct iax_template *cur;
- char server[INET_ADDRSTRLEN];
- char alternate[INET_ADDRSTRLEN];
- char flags[80]; /* Has to be big enough for 'flags' too */
- int found = 0;
- if ((argc != 3) && (argc != 4))
- return RESULT_SHOWUSAGE;
- ast_mutex_lock(&provlock);
- for (cur = templates;cur;cur = cur->next) {
- if ((argc == 3) || (!strcasecmp(argv[3], cur->name))) {
- if (found)
- ast_cli(fd, "\n");
- ast_copy_string(server, iax_server(cur->server), sizeof(server));
- ast_copy_string(alternate, iax_server(cur->altserver), sizeof(alternate));
- ast_cli(fd, "== %s ==\n", cur->name);
- ast_cli(fd, "Base Templ: %s\n", strlen(cur->src) ? cur->src : "<none>");
- ast_cli(fd, "Username: %s\n", ifthere(cur->user));
- ast_cli(fd, "Secret: %s\n", ifthere(cur->pass));
- ast_cli(fd, "Language: %s\n", ifthere(cur->lang));
- ast_cli(fd, "Bind Port: %d\n", cur->port);
- ast_cli(fd, "Server: %s\n", server);
- ast_cli(fd, "Server Port: %d\n", cur->serverport);
- ast_cli(fd, "Alternate: %s\n", alternate);
- ast_cli(fd, "Flags: %s\n", iax_provflags2str(flags, sizeof(flags), cur->flags));
- ast_cli(fd, "Format: %s\n", ast_getformatname(cur->format));
- ast_cli(fd, "TOS: 0x%x\n", cur->tos);
- found++;
- }
- }
- ast_mutex_unlock(&provlock);
- if (!found) {
- if (argc == 3)
- ast_cli(fd, "No provisioning templates found\n");
- else
- ast_cli(fd, "No provisioning template matching '%s' found\n", argv[3]);
- }
- return RESULT_SUCCESS;
-}
-
-static struct ast_cli_entry cli_iax2_provision[] = {
- { { "iax2", "show", "provisioning", NULL },
- iax_show_provisioning, "Display iax provisioning",
- show_provisioning_usage, iax_prov_complete_template, },
-};
-
-static int iax_provision_init(void)
-{
- ast_cli_register_multiple(cli_iax2_provision, sizeof(cli_iax2_provision) / sizeof(struct ast_cli_entry));
- provinit = 1;
- return 0;
-}
-
-int iax_provision_unload(void)
-{
- provinit = 0;
- ast_cli_unregister_multiple(cli_iax2_provision, sizeof(cli_iax2_provision) / sizeof(struct ast_cli_entry));
- return 0;
-}
-
-int iax_provision_reload(void)
-{
- struct ast_config *cfg;
- struct iax_template *cur, *prev, *next;
- char *cat;
- int found = 0;
- if (!provinit)
- iax_provision_init();
- /* Mark all as dead. No need for locking */
- cur = templates;
- while(cur) {
- cur->dead = 1;
- cur = cur->next;
- }
- cfg = ast_config_load("iaxprov.conf");
- if (cfg) {
- /* Load as appropriate */
- cat = ast_category_browse(cfg, NULL);
- while(cat) {
- if (strcasecmp(cat, "general")) {
- iax_process_template(cfg, cat, found ? "default" : NULL);
- found++;
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Loaded provisioning template '%s'\n", cat);
- }
- cat = ast_category_browse(cfg, cat);
- }
- ast_config_destroy(cfg);
- } else
- ast_log(LOG_NOTICE, "No IAX provisioning configuration found, IAX provisioning disabled.\n");
- ast_mutex_lock(&provlock);
- /* Drop dead entries while locked */
- prev = NULL;
- cur = templates;
- while(cur) {
- next = cur->next;
- if (cur->dead) {
- if (prev)
- prev->next = next;
- else
- templates = next;
- free(cur);
- } else
- prev = cur;
- cur = next;
- }
- ast_mutex_unlock(&provlock);
- /* Purge cached signature DB entries */
- ast_db_deltree("iax/provisioning/cache", NULL);
- return 0;
-
-}
diff --git a/1.4.23-rc4/channels/iax2-provision.h b/1.4.23-rc4/channels/iax2-provision.h
deleted file mode 100644
index d95150253..000000000
--- a/1.4.23-rc4/channels/iax2-provision.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * IAX Provisioning Protocol
- *
- * Sub-information elements
- *
- * Copyright (C) 2003, Digium
- *
- * Mark Spencer <markster@digium.com>
- *
- */
-
-/*! \file
- * \brief IAX2 Provisioning protocol
- */
-
-#include "iax2-parser.h"
-
-#define PROV_IE_USEDHCP 1 /* Presense only */
-#define PROV_IE_IPADDR 2 /* 32-bit */
-#define PROV_IE_SUBNET 3 /* 32-bit */
-#define PROV_IE_GATEWAY 4 /* 32-bit */
-#define PROV_IE_PORTNO 5 /* 16-bit */
-#define PROV_IE_USER 6 /* < 20 bytes */
-#define PROV_IE_PASS 7 /* < 20 bytes */
-#define PROV_IE_SERVERUSER 8 /* < 20 bytes */
-#define PROV_IE_SERVERPASS 9 /* < 20 bytes */
-#define PROV_IE_LANG 10 /* < 10 bytes */
-#define PROV_IE_TOS 11 /* 8-bits */
-#define PROV_IE_FLAGS 12 /* 32-bits */
-#define PROV_IE_FORMAT 13 /* 32-bits */
-#define PROV_IE_AESKEY 14 /* 128-bits */
-#define PROV_IE_SERVERIP 15 /* 32-bits */
-#define PROV_IE_SERVERPORT 16 /* 16-bits */
-#define PROV_IE_NEWAESKEY 17 /* 128-bits */
-#define PROV_IE_PROVVER 18 /* 32-bits */
-#define PROV_IE_ALTSERVER 19 /* 32-bits */
-
-#define PROV_FLAG_REGISTER (1 << 0)
-#define PROV_FLAG_SECURE (1 << 1)
-#define PROV_FLAG_HEARTBEAT (1 << 2)
-#define PROV_FLAG_DEBUG (1 << 3)
-
-#define PROV_FLAG_DIS_CALLERID (1 << 4) /* Caller-ID Disabled */
-#define PROV_FLAG_DIS_CALLWAIT (1 << 5) /* Caller-ID / Call Waiting Disable */
-#define PROV_FLAG_DIS_CIDCW (1 << 6) /* CID/CW Disabled */
-#define PROV_FLAG_DIS_THREEWAY (1 << 7) /* Three-way calling, transfer disabled */
-
-char *iax_provflags2str(char *buf, int buflen, unsigned int flags);
-int iax_provision_reload(void);
-int iax_provision_unload(void);
-int iax_provision_build(struct iax_ie_data *provdata, unsigned int *signature, const char *template, int force);
-int iax_provision_version(unsigned int *signature, const char *template, int force);
-char *iax_prov_complete_template(const char *line, const char *word, int pos, int state);
diff --git a/1.4.23-rc4/channels/iax2.h b/1.4.23-rc4/channels/iax2.h
deleted file mode 100644
index 960dec8bb..000000000
--- a/1.4.23-rc4/channels/iax2.h
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * Asterisk -- A telephony toolkit for Linux.
- *
- * Implementation of Inter-Asterisk eXchange
- *
- * Copyright (C) 2003, Digium
- *
- * Mark Spencer <markster@linux-support.net>
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License
- */
-
-#ifndef _IAX2_H
-#define _IAX2_H
-
-/* Max version of IAX protocol we support */
-#define IAX_PROTO_VERSION 2
-
-/* NOTE: IT IS CRITICAL THAT IAX_MAX_CALLS BE A POWER OF 2. */
-#if defined(LOW_MEMORY)
-#define IAX_MAX_CALLS 2048
-#else
-#define IAX_MAX_CALLS 32768
-#endif
-
-#define IAX_FLAG_FULL 0x8000
-
-#define IAX_FLAG_RETRANS 0x8000
-
-#define IAX_FLAG_SC_LOG 0x80
-
-#define IAX_MAX_SHIFT 0x1F
-
-#define IAX_WINDOW 64
-
-/* Subclass for AST_FRAME_IAX */
-#define IAX_COMMAND_NEW 1
-#define IAX_COMMAND_PING 2
-#define IAX_COMMAND_PONG 3
-#define IAX_COMMAND_ACK 4
-#define IAX_COMMAND_HANGUP 5
-#define IAX_COMMAND_REJECT 6
-#define IAX_COMMAND_ACCEPT 7
-#define IAX_COMMAND_AUTHREQ 8
-#define IAX_COMMAND_AUTHREP 9
-#define IAX_COMMAND_INVAL 10
-#define IAX_COMMAND_LAGRQ 11
-#define IAX_COMMAND_LAGRP 12
-#define IAX_COMMAND_REGREQ 13 /* Registration request */
-#define IAX_COMMAND_REGAUTH 14 /* Registration authentication required */
-#define IAX_COMMAND_REGACK 15 /* Registration accepted */
-#define IAX_COMMAND_REGREJ 16 /* Registration rejected */
-#define IAX_COMMAND_REGREL 17 /* Force release of registration */
-#define IAX_COMMAND_VNAK 18 /* If we receive voice before valid first voice frame, send this */
-#define IAX_COMMAND_DPREQ 19 /* Request status of a dialplan entry */
-#define IAX_COMMAND_DPREP 20 /* Request status of a dialplan entry */
-#define IAX_COMMAND_DIAL 21 /* Request a dial on channel brought up TBD */
-#define IAX_COMMAND_TXREQ 22 /* Transfer Request */
-#define IAX_COMMAND_TXCNT 23 /* Transfer Connect */
-#define IAX_COMMAND_TXACC 24 /* Transfer Accepted */
-#define IAX_COMMAND_TXREADY 25 /* Transfer ready */
-#define IAX_COMMAND_TXREL 26 /* Transfer release */
-#define IAX_COMMAND_TXREJ 27 /* Transfer reject */
-#define IAX_COMMAND_QUELCH 28 /* Stop audio/video transmission */
-#define IAX_COMMAND_UNQUELCH 29 /* Resume audio/video transmission */
-#define IAX_COMMAND_POKE 30 /* Like ping, but does not require an open connection */
-#define IAX_COMMAND_PAGE 31 /* Paging description */
-#define IAX_COMMAND_MWI 32 /* Stand-alone message waiting indicator */
-#define IAX_COMMAND_UNSUPPORT 33 /* Unsupported message received */
-#define IAX_COMMAND_TRANSFER 34 /* Request remote transfer */
-#define IAX_COMMAND_PROVISION 35 /* Provision device */
-#define IAX_COMMAND_FWDOWNL 36 /* Download firmware */
-#define IAX_COMMAND_FWDATA 37 /* Firmware Data */
-#define IAX_COMMAND_TXMEDIA 38 /* Transfer media only */
-
-#define IAX_DEFAULT_REG_EXPIRE 60 /* By default require re-registration once per minute */
-
-#define IAX_LINGER_TIMEOUT 10 /* How long to wait before closing bridged call */
-
-#define IAX_DEFAULT_PORTNO 4569
-
-/* IAX Information elements */
-#define IAX_IE_CALLED_NUMBER 1 /* Number/extension being called - string */
-#define IAX_IE_CALLING_NUMBER 2 /* Calling number - string */
-#define IAX_IE_CALLING_ANI 3 /* Calling number ANI for billing - string */
-#define IAX_IE_CALLING_NAME 4 /* Name of caller - string */
-#define IAX_IE_CALLED_CONTEXT 5 /* Context for number - string */
-#define IAX_IE_USERNAME 6 /* Username (peer or user) for authentication - string */
-#define IAX_IE_PASSWORD 7 /* Password for authentication - string */
-#define IAX_IE_CAPABILITY 8 /* Actual codec capability - unsigned int */
-#define IAX_IE_FORMAT 9 /* Desired codec format - unsigned int */
-#define IAX_IE_LANGUAGE 10 /* Desired language - string */
-#define IAX_IE_VERSION 11 /* Protocol version - short */
-#define IAX_IE_ADSICPE 12 /* CPE ADSI capability - short */
-#define IAX_IE_DNID 13 /* Originally dialed DNID - string */
-#define IAX_IE_AUTHMETHODS 14 /* Authentication method(s) - short */
-#define IAX_IE_CHALLENGE 15 /* Challenge data for MD5/RSA - string */
-#define IAX_IE_MD5_RESULT 16 /* MD5 challenge result - string */
-#define IAX_IE_RSA_RESULT 17 /* RSA challenge result - string */
-#define IAX_IE_APPARENT_ADDR 18 /* Apparent address of peer - struct sockaddr_in */
-#define IAX_IE_REFRESH 19 /* When to refresh registration - short */
-#define IAX_IE_DPSTATUS 20 /* Dialplan status - short */
-#define IAX_IE_CALLNO 21 /* Call number of peer - short */
-#define IAX_IE_CAUSE 22 /* Cause - string */
-#define IAX_IE_IAX_UNKNOWN 23 /* Unknown IAX command - byte */
-#define IAX_IE_MSGCOUNT 24 /* How many messages waiting - short */
-#define IAX_IE_AUTOANSWER 25 /* Request auto-answering -- none */
-#define IAX_IE_MUSICONHOLD 26 /* Request musiconhold with QUELCH -- none or string */
-#define IAX_IE_TRANSFERID 27 /* Transfer Request Identifier -- int */
-#define IAX_IE_RDNIS 28 /* Referring DNIS -- string */
-#define IAX_IE_PROVISIONING 29 /* Provisioning info */
-#define IAX_IE_AESPROVISIONING 30 /* AES Provisioning info */
-#define IAX_IE_DATETIME 31 /* Date/Time */
-#define IAX_IE_DEVICETYPE 32 /* Device Type -- string */
-#define IAX_IE_SERVICEIDENT 33 /* Service Identifier -- string */
-#define IAX_IE_FIRMWAREVER 34 /* Firmware revision -- u16 */
-#define IAX_IE_FWBLOCKDESC 35 /* Firmware block description -- u32 */
-#define IAX_IE_FWBLOCKDATA 36 /* Firmware block of data -- raw */
-#define IAX_IE_PROVVER 37 /* Provisioning Version (u32) */
-#define IAX_IE_CALLINGPRES 38 /* Calling presentation (u8) */
-#define IAX_IE_CALLINGTON 39 /* Calling type of number (u8) */
-#define IAX_IE_CALLINGTNS 40 /* Calling transit network select (u16) */
-#define IAX_IE_SAMPLINGRATE 41 /* Supported sampling rates (u16) */
-#define IAX_IE_CAUSECODE 42 /* Hangup cause (u8) */
-#define IAX_IE_ENCRYPTION 43 /* Encryption format (u16) */
-#define IAX_IE_ENCKEY 44 /* Encryption key (raw) */
-#define IAX_IE_CODEC_PREFS 45 /* Codec Negotiation */
-
-#define IAX_IE_RR_JITTER 46 /* Received jitter (as in RFC1889) u32 */
-#define IAX_IE_RR_LOSS 47 /* Received loss (high byte loss pct, low 24 bits loss count, as in rfc1889 */
-#define IAX_IE_RR_PKTS 48 /* Received frames (total frames received) u32 */
-#define IAX_IE_RR_DELAY 49 /* Max playout delay for received frames (in ms) u16 */
-#define IAX_IE_RR_DROPPED 50 /* Dropped frames (presumably by jitterbuf) u32 */
-#define IAX_IE_RR_OOO 51 /* Frames received Out of Order u32 */
-
-
-#define IAX_AUTH_PLAINTEXT (1 << 0)
-#define IAX_AUTH_MD5 (1 << 1)
-#define IAX_AUTH_RSA (1 << 2)
-
-#define IAX_ENCRYPT_AES128 (1 << 0)
-
-#define IAX_META_TRUNK 1 /* Trunk meta-message */
-#define IAX_META_VIDEO 2 /* Video frame */
-
-#define IAX_META_TRUNK_SUPERMINI 0 /* This trunk frame contains classic supermini frames */
-#define IAX_META_TRUNK_MINI 1 /* This trunk frame contains trunked mini frames */
-
-#define IAX_RATE_8KHZ (1 << 0) /* 8khz sampling (default if absent) */
-#define IAX_RATE_11KHZ (1 << 1) /* 11.025khz sampling */
-#define IAX_RATE_16KHZ (1 << 2) /* 16khz sampling */
-#define IAX_RATE_22KHZ (1 << 3) /* 22.05khz sampling */
-#define IAX_RATE_44KHZ (1 << 4) /* 44.1khz sampling */
-#define IAX_RATE_48KHZ (1 << 5) /* 48khz sampling */
-
-#define IAX_DPSTATUS_EXISTS (1 << 0)
-#define IAX_DPSTATUS_CANEXIST (1 << 1)
-#define IAX_DPSTATUS_NONEXISTENT (1 << 2)
-#define IAX_DPSTATUS_IGNOREPAT (1 << 14)
-#define IAX_DPSTATUS_MATCHMORE (1 << 15)
-
-/* Full frames are always delivered reliably */
-struct ast_iax2_full_hdr {
- unsigned short scallno; /* Source call number -- high bit must be 1 */
- unsigned short dcallno; /* Destination call number -- high bit is 1 if retransmission */
- unsigned int ts; /* 32-bit timestamp in milliseconds (from 1st transmission) */
- unsigned char oseqno; /* Packet number (outgoing) */
- unsigned char iseqno; /* Packet number (next incoming expected) */
- unsigned char type; /* Frame type */
- unsigned char csub; /* Compressed subclass */
- unsigned char iedata[0];
-} __attribute__ ((__packed__));
-
-/* Full frames are always delivered reliably */
-struct ast_iax2_full_enc_hdr {
- unsigned short scallno; /* Source call number -- high bit must be 1 */
- unsigned short dcallno; /* Destination call number -- high bit is 1 if retransmission */
- unsigned char encdata[0];
-} __attribute__ ((__packed__));
-
-/* Mini header is used only for voice frames -- delivered unreliably */
-struct ast_iax2_mini_hdr {
- unsigned short callno; /* Source call number -- high bit must be 0, rest must be non-zero */
- unsigned short ts; /* 16-bit Timestamp (high 16 bits from last ast_iax2_full_hdr) */
- /* Frametype implicitly VOICE_FRAME */
- /* subclass implicit from last ast_iax2_full_hdr */
- unsigned char data[0];
-} __attribute__ ((__packed__));
-
-/* Mini header is used only for voice frames -- delivered unreliably */
-struct ast_iax2_mini_enc_hdr {
- unsigned short callno; /* Source call number -- high bit must be 0, rest must be non-zero */
- unsigned char encdata[0];
-} __attribute__ ((__packed__));
-
-struct ast_iax2_meta_hdr {
- unsigned short zeros; /* Zeros field -- must be zero */
- unsigned char metacmd; /* Meta command */
- unsigned char cmddata; /* Command Data */
- unsigned char data[0];
-} __attribute__ ((__packed__));
-
-struct ast_iax2_video_hdr {
- unsigned short zeros; /* Zeros field -- must be zero */
- unsigned short callno; /* Video call number */
- unsigned short ts; /* Timestamp and mark if present */
- unsigned char data[0];
-} __attribute__ ((__packed__));
-
-struct ast_iax2_meta_trunk_hdr {
- unsigned int ts; /* 32-bit timestamp for all messages */
- unsigned char data[0];
-} __attribute__ ((__packed__));
-
-struct ast_iax2_meta_trunk_entry {
- unsigned short callno; /* Call number */
- unsigned short len; /* Length of data for this callno */
-} __attribute__ ((__packed__));
-
-/* When trunktimestamps are used, we use this format instead */
-struct ast_iax2_meta_trunk_mini {
- unsigned short len;
- struct ast_iax2_mini_hdr mini; /* this is an actual miniframe */
-} __attribute__ ((__packed__));
-
-#define IAX_FIRMWARE_MAGIC 0x69617879
-
-struct ast_iax2_firmware_header {
- unsigned int magic; /* Magic number */
- unsigned short version; /* Software version */
- unsigned char devname[16]; /* Device */
- unsigned int datalen; /* Data length of file beyond header */
- unsigned char chksum[16]; /* Checksum of all data */
- unsigned char data[0];
-} __attribute__ ((__packed__));
-#endif
diff --git a/1.4.23-rc4/channels/misdn/Makefile b/1.4.23-rc4/channels/misdn/Makefile
deleted file mode 100644
index e277636e6..000000000
--- a/1.4.23-rc4/channels/misdn/Makefile
+++ /dev/null
@@ -1,17 +0,0 @@
-#
-# Makefile for chan_misdn support
-#
-ifneq ($(wildcard /usr/include/linux/mISDNdsp.h),)
-CFLAGS+=-DMISDN_1_2
-endif
-
-all:
-
-%.o: %.c
- $(CC) $(CFLAGS) -c -o $@ $<
-
-portinfo: portinfo.o
- $(CC) -o $@ $^ -lisdnnet -lmISDN -lpthread
-
-clean:
- rm -rf *.a *.o *.so portinfo *.i
diff --git a/1.4.23-rc4/channels/misdn/chan_misdn_config.h b/1.4.23-rc4/channels/misdn/chan_misdn_config.h
deleted file mode 100644
index f675704c0..000000000
--- a/1.4.23-rc4/channels/misdn/chan_misdn_config.h
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Chan_Misdn -- Channel Driver for Asterisk
- *
- * Interface to mISDN
- *
- * Copyright (C) 2004, Christian Richter
- *
- * Christian Richter <crich@beronet.com>
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License
- */
-
-
-
-#ifndef CHAN_MISDN_CONFIG_H
-#define CHAN_MISDN_CONFIG_H
-
-#define BUFFERSIZE 512
-
-enum misdn_cfg_elements {
-
- /* port config items */
- MISDN_CFG_FIRST = 0,
- MISDN_CFG_GROUPNAME, /* char[] */
- MISDN_CFG_ALLOWED_BEARERS, /* char[] */
- MISDN_CFG_FAR_ALERTING, /* int (bool) */
- MISDN_CFG_RXGAIN, /* int */
- MISDN_CFG_TXGAIN, /* int */
- MISDN_CFG_TE_CHOOSE_CHANNEL, /* int (bool) */
- MISDN_CFG_PMP_L1_CHECK, /* int (bool) */
- MISDN_CFG_REJECT_CAUSE, /* int */
- MISDN_CFG_ALARM_BLOCK, /* int (bool) */
- MISDN_CFG_HDLC, /* int (bool) */
- MISDN_CFG_CONTEXT, /* char[] */
- MISDN_CFG_LANGUAGE, /* char[] */
- MISDN_CFG_MUSICCLASS, /* char[] */
- MISDN_CFG_CALLERID, /* char[] */
- MISDN_CFG_METHOD, /* char[] */
- MISDN_CFG_DIALPLAN, /* int */
- MISDN_CFG_LOCALDIALPLAN, /* int */
- MISDN_CFG_CPNDIALPLAN, /* int */
- MISDN_CFG_NATPREFIX, /* char[] */
- MISDN_CFG_INTERNATPREFIX, /* char[] */
- MISDN_CFG_PRES, /* int */
- MISDN_CFG_SCREEN, /* int */
- MISDN_CFG_ALWAYS_IMMEDIATE, /* int (bool) */
- MISDN_CFG_NODIALTONE, /* int (bool) */
- MISDN_CFG_IMMEDIATE, /* int (bool) */
- MISDN_CFG_SENDDTMF, /* int (bool) */
- MISDN_CFG_ASTDTMF, /* int (bool) */
- MISDN_CFG_HOLD_ALLOWED, /* int (bool) */
- MISDN_CFG_EARLY_BCONNECT, /* int (bool) */
- MISDN_CFG_INCOMING_EARLY_AUDIO, /* int (bool) */
- MISDN_CFG_ECHOCANCEL, /* int */
-#ifdef MISDN_1_2
- MISDN_CFG_PIPELINE, /* char[] */
-#endif
-
-#ifdef WITH_BEROEC
- MISDN_CFG_BNECHOCANCEL,
- MISDN_CFG_BNEC_ANTIHOWL,
- MISDN_CFG_BNEC_NLP,
- MISDN_CFG_BNEC_ZEROCOEFF,
- MISDN_CFG_BNEC_TD,
- MISDN_CFG_BNEC_ADAPT,
-#endif
- MISDN_CFG_NEED_MORE_INFOS, /* bool */
- MISDN_CFG_NOAUTORESPOND_ON_SETUP, /* bool */
- MISDN_CFG_NTTIMEOUT, /* bool */
- MISDN_CFG_BRIDGING, /* bool */
- MISDN_CFG_JITTERBUFFER, /* int */
- MISDN_CFG_JITTERBUFFER_UPPER_THRESHOLD, /* int */
- MISDN_CFG_CALLGROUP, /* ast_group_t */
- MISDN_CFG_PICKUPGROUP, /* ast_group_t */
- MISDN_CFG_MAX_IN, /* int */
- MISDN_CFG_MAX_OUT, /* int */
- MISDN_CFG_L1_TIMEOUT, /* int */
- MISDN_CFG_OVERLAP_DIAL, /* int (bool)*/
- MISDN_CFG_MSNS, /* char[] */
- MISDN_CFG_FAXDETECT, /* char[] */
- MISDN_CFG_FAXDETECT_CONTEXT, /* char[] */
- MISDN_CFG_FAXDETECT_TIMEOUT, /* int */
- MISDN_CFG_PTP, /* int (bool) */
- MISDN_CFG_LAST,
-
- /* general config items */
- MISDN_GEN_FIRST,
-#ifndef MISDN_1_2
- MISDN_GEN_MISDN_INIT, /* char[] */
-#endif
- MISDN_GEN_DEBUG, /* int */
- MISDN_GEN_TRACEFILE, /* char[] */
- MISDN_GEN_BRIDGING, /* int (bool) */
- MISDN_GEN_STOP_TONE, /* int (bool) */
- MISDN_GEN_APPEND_DIGITS2EXTEN, /* int (bool) */
- MISDN_GEN_DYNAMIC_CRYPT, /* int (bool) */
- MISDN_GEN_CRYPT_PREFIX, /* char[] */
- MISDN_GEN_CRYPT_KEYS, /* char[] */
- MISDN_GEN_NTKEEPCALLS, /* int (bool) */
- MISDN_GEN_NTDEBUGFLAGS, /* int */
- MISDN_GEN_NTDEBUGFILE, /* char[] */
- MISDN_GEN_LAST
-};
-
-enum misdn_cfg_method {
- METHOD_STANDARD = 0,
- METHOD_ROUND_ROBIN,
- METHOD_STANDARD_DEC
-};
-
-/* you must call misdn_cfg_init before any other function of this header file */
-int misdn_cfg_init(int max_ports);
-void misdn_cfg_reload(void);
-void misdn_cfg_destroy(void);
-
-void misdn_cfg_update_ptp( void );
-
-/* if you requst a general config element, the port value is ignored. if the requested
- * value is not available, or the buffer is too small, the buffer will be nulled (in
- * case of a char* only its first byte will be nulled). */
-void misdn_cfg_get(int port, enum misdn_cfg_elements elem, void* buf, int bufsize);
-
-/* returns the enum element for the given name, returns MISDN_CFG_FIRST if none was found */
-enum misdn_cfg_elements misdn_cfg_get_elem (char *name);
-
-/* fills the buffer with the name of the given config element */
-void misdn_cfg_get_name (enum misdn_cfg_elements elem, void *buf, int bufsize);
-
-/* fills the buffer with the description of the given config element */
-void misdn_cfg_get_desc (enum misdn_cfg_elements elem, void *buf, int bufsize, void *buf_default, int bufsize_default);
-
-/* fills the buffer with a ',' separated list of all active ports */
-void misdn_cfg_get_ports_string(char *ports);
-
-/* fills the buffer with a nice printable string representation of the config element */
-void misdn_cfg_get_config_string(int port, enum misdn_cfg_elements elem, char* buf, int bufsize);
-
-/* returns the next available port number. returns -1 if the last one was reached. */
-int misdn_cfg_get_next_port(int port);
-int misdn_cfg_get_next_port_spin(int port);
-
-int misdn_cfg_is_msn_valid(int port, char* msn);
-int misdn_cfg_is_port_valid(int port);
-int misdn_cfg_is_group_method(char *group, enum misdn_cfg_method meth);
-
-#if 0
-char *misdn_cfg_get_next_group(char *group);
-int misdn_cfg_get_next_port_in_group(int port, char *group);
-#endif
-
-#endif
diff --git a/1.4.23-rc4/channels/misdn/ie.c b/1.4.23-rc4/channels/misdn/ie.c
deleted file mode 100644
index 2e7fae998..000000000
--- a/1.4.23-rc4/channels/misdn/ie.c
+++ /dev/null
@@ -1,1422 +0,0 @@
-
-/*
- * Chan_Misdn -- Channel Driver for Asterisk
- *
- * Interface to mISDN
- *
- * Copyright (C) 2005, Christian Richter
- *
- * Christian Richter <crich@beronet.com>
- *
- * heaviliy patched from jollys ie.cpp, jolly gave me ALL
- * rights for this code, i can even have my own copyright on it.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License
- */
-
-/*
- the pointer of enc_ie_* always points to the IE itself
- if qi is not NULL (TE-mode), offset is set
-*/
-
-
-#include <string.h>
-
-#include <mISDNuser/mISDNlib.h>
-#include <mISDNuser/isdn_net.h>
-#include <mISDNuser/l3dss1.h>
-#include <mISDNuser/net_l3.h>
-
-
-
-#define MISDN_IE_DEBG 0
-
-/* support stuff */
-static void strnncpy(char *dest, char *src, int len, int dst_len)
-{
- if (len > dst_len-1)
- len = dst_len-1;
- strncpy((char *)dest, (char *)src, len);
- dest[len] = '\0';
-}
-
-
-/* IE_COMPLETE */
-static void enc_ie_complete(unsigned char **ntmode, msg_t *msg, int complete, int nt, struct misdn_bchannel *bc)
-{
- unsigned char *p;
- Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
-
- if (complete<0 || complete>1)
- {
- printf("%s: ERROR: complete(%d) is out of range.\n", __FUNCTION__, complete);
- return;
- }
-
- if (complete)
- if (MISDN_IE_DEBG) printf(" complete=%d\n", complete);
-
- if (complete)
- {
- p = msg_put(msg, 1);
- if (nt)
- {
- *ntmode = p;
- } else
- qi->QI_ELEMENT(sending_complete) = p - (unsigned char *)qi - sizeof(Q931_info_t);
-
- p[0] = IE_COMPLETE;
- }
-}
-
-static void dec_ie_complete(unsigned char *p, Q931_info_t *qi, int *complete, int nt, struct misdn_bchannel *bc)
-{
- *complete = 0;
- if (!nt)
- {
- if (qi->QI_ELEMENT(sending_complete))
- *complete = 1;
- } else
- if (p)
- *complete = 1;
-
- if (*complete)
- if (MISDN_IE_DEBG) printf(" complete=%d\n", *complete);
-}
-
-
-/* IE_BEARER */
-static void enc_ie_bearer(unsigned char **ntmode, msg_t *msg, int coding, int capability, int mode, int rate, int multi, int user, int nt, struct misdn_bchannel *bc)
-{
- unsigned char *p;
- Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
- int l;
-
- if (coding<0 || coding>3)
- {
- printf("%s: ERROR: coding(%d) is out of range.\n", __FUNCTION__, coding);
- return;
- }
- if (capability<0 || capability>31)
- {
- printf("%s: ERROR: capability(%d) is out of range.\n", __FUNCTION__, capability);
- return;
- }
- if (mode<0 || mode>3)
- {
- printf("%s: ERROR: mode(%d) is out of range.\n", __FUNCTION__, mode);
- return;
- }
- if (rate<0 || rate>31)
- {
- printf("%s: ERROR: rate(%d) is out of range.\n", __FUNCTION__, rate);
- return;
- }
- if (multi>127)
- {
- printf("%s: ERROR: multi(%d) is out of range.\n", __FUNCTION__, multi);
- return;
- }
- if (user>31)
- {
- printf("%s: ERROR: user L1(%d) is out of range.\n", __FUNCTION__, rate);
- return;
- }
- if (rate!=24 && multi>=0)
- {
- printf("%s: WARNING: multi(%d) is only possible if rate(%d) would be 24.\n", __FUNCTION__, multi, rate);
- multi = -1;
- }
-
- if (MISDN_IE_DEBG) printf(" coding=%d capability=%d mode=%d rate=%d multi=%d user=%d\n", coding, capability, mode, rate, multi, user);
-
- l = 2 + (multi>=0) + (user>=0);
- p = msg_put(msg, l+2);
- if (nt)
- *ntmode = p+1;
- else
- qi->QI_ELEMENT(bearer_capability) = p - (unsigned char *)qi - sizeof(Q931_info_t);
- p[0] = IE_BEARER;
- p[1] = l;
- p[2] = 0x80 + (coding<<5) + capability;
- p[3] = 0x80 + (mode<<5) + rate;
- if (multi >= 0)
- p[4] = 0x80 + multi;
- if (user >= 0)
- p[4+(multi>=0)] = 0xa0 + user;
-}
-
-static void dec_ie_bearer(unsigned char *p, Q931_info_t *qi, int *coding, int *capability, int *mode, int *rate, int *multi, int *user,
- int *async, int *urate, int *stopbits, int *dbits, int *parity, int nt, struct misdn_bchannel *bc)
-{
- int octet;
- *coding = -1;
- *capability = -1;
- *mode = -1;
- *rate = -1;
- *multi = -1;
- *user = -1;
- *async = -1;
- *urate = -1;
- *stopbits = -1;
- *dbits = -1;
- *parity = -1;
-
- if (!nt)
- {
- p = NULL;
-#ifdef LLC_SUPPORT
- if (qi->QI_ELEMENT(llc)) {
-
- p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(llc) + 1;
- }
-#endif
- if (qi->QI_ELEMENT(bearer_capability))
- p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(bearer_capability) + 1;
- }
- if (!p)
- return;
-
- if (p[0] < 2)
- {
- printf("%s: ERROR: IE too short (%d).\n", __FUNCTION__, p[0]);
- return;
- }
-
- *coding = (p[1]&0x60) >> 5;
- *capability = p[1] & 0x1f;
- octet = 2;
- if (!(p[1] & 0x80))
- octet++;
-
- if (p[0] < octet)
- goto done;
-
- *mode = (p[octet]&0x60) >> 5;
- *rate = p[octet] & 0x1f;
-
- octet++;
-
- if (p[0] < octet)
- goto done;
-
- if (*rate == 0x18) {
- /* Rate multiplier only present if 64Kb/s base rate */
- *multi = p[octet++] & 0x7f;
- }
-
- if (p[0] < octet)
- goto done;
-
- /* Start L1 info */
- if ((p[octet] & 0x60) == 0x20) {
- *user = p[octet] & 0x1f;
-
- if (p[0] <= octet)
- goto done;
-
- if (p[octet++] & 0x80)
- goto l2;
-
- *async = !!(p[octet] & 0x40);
- /* 0x20 is inband negotiation */
- *urate = p[octet] & 0x1f;
-
- if (p[0] <= octet)
- goto done;
-
- if (p[octet++] & 0x80)
- goto l2;
-
- /* Ignore next byte for now: Intermediate rate, NIC, flow control */
-
- if (p[0] <= octet)
- goto done;
-
- if (p[octet++] & 0x80)
- goto l2;
-
- /* And the next one. Header, multiframe, mode, assignor/ee, negotiation */
-
- if (p[0] <= octet)
- goto done;
-
- if (!p[octet++] & 0x80)
- goto l2;
-
- /* Wheee. V.110 speed information */
-
- *stopbits = (p[octet] & 0x60) >> 5;
- *dbits = (p[octet] & 0x18) >> 3;
- *parity = p[octet] & 7;
-
- octet++;
- }
- l2: /* Nobody seems to want the rest so we don't bother (yet) */
- done:
- if (MISDN_IE_DEBG) printf(" coding=%d capability=%d mode=%d rate=%d multi=%d user=%d async=%d urate=%d stopbits=%d dbits=%d parity=%d\n", *coding, *capability, *mode, *rate, *multi, *user, *async, *urate, *stopbits, *dbits, *parity);
-}
-
-
-/* IE_CALL_ID */
-#if 0
-static void enc_ie_call_id(unsigned char **ntmode, msg_t *msg, char *callid, int callid_len, int nt, struct misdn_bchannel *bc)
-{
- unsigned char *p;
- Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
- int l;
-
- char debug[25];
- int i;
-
- if (!callid || callid_len<=0)
- {
- return;
- }
- if (callid_len>8)
- {
- printf("%s: ERROR: callid_len(%d) is out of range.\n", __FUNCTION__, callid_len);
- return;
- }
-
- i = 0;
- while(i < callid_len)
- {
- if (MISDN_IE_DEBG) printf(debug+(i*3), " %02x", callid[i]);
- i++;
- }
-
- if (MISDN_IE_DEBG) printf(" callid%s\n", debug);
-
- l = callid_len;
- p = msg_put(msg, l+2);
- if (nt)
- *ntmode = p+1;
- else
- qi->QI_ELEMENT(call_id) = p - (unsigned char *)qi - sizeof(Q931_info_t);
- p[0] = IE_CALL_ID;
- p[1] = l;
- memcpy(p+2, callid, callid_len);
-}
-#endif
-
-#if 0
-static void dec_ie_call_id(unsigned char *p, Q931_info_t *qi, char *callid, int *callid_len, int nt, struct misdn_bchannel *bc)
-{
- char debug[25];
- int i;
-
- *callid_len = -1;
-
- if (!nt)
- {
- p = NULL;
- if (qi->QI_ELEMENT(call_id))
- p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(call_id) + 1;
- }
- if (!p)
- return;
- if (p[0] > 8)
- {
- printf("%s: ERROR: IE too long (%d).\n", __FUNCTION__, p[0]);
- return;
- }
-
- *callid_len = p[0];
- memcpy(callid, p+1, *callid_len);
-
- i = 0;
- while(i < *callid_len)
- {
- if (MISDN_IE_DEBG) printf(debug+(i*3), " %02x", callid[i]);
- i++;
- }
-
- if (MISDN_IE_DEBG) printf(" callid%s\n", debug);
-}
-#endif
-
-/* IE_CALLED_PN */
-static void enc_ie_called_pn(unsigned char **ntmode, msg_t *msg, int type, int plan, char *number, int nt, struct misdn_bchannel *bc)
-{
- unsigned char *p;
- Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
- int l;
-
- if (type<0 || type>7)
- {
- printf("%s: ERROR: type(%d) is out of range.\n", __FUNCTION__, type);
- return;
- }
- if (plan<0 || plan>15)
- {
- printf("%s: ERROR: plan(%d) is out of range.\n", __FUNCTION__, plan);
- return;
- }
- if (!number[0])
- {
- printf("%s: ERROR: number is not given.\n", __FUNCTION__);
- return;
- }
-
- if (MISDN_IE_DEBG) printf(" type=%d plan=%d number='%s'\n", type, plan, number);
-
- l = 1+strlen((char *)number);
- p = msg_put(msg, l+2);
- if (nt)
- *ntmode = p+1;
- else
- qi->QI_ELEMENT(called_nr) = p - (unsigned char *)qi - sizeof(Q931_info_t);
- p[0] = IE_CALLED_PN;
- p[1] = l;
- p[2] = 0x80 + (type<<4) + plan;
- strncpy((char *)p+3, (char *)number, strlen((char *)number));
-}
-
-static void dec_ie_called_pn(unsigned char *p, Q931_info_t *qi, int *type, int *plan, char *number, int number_len, int nt, struct misdn_bchannel *bc)
-{
- *type = -1;
- *plan = -1;
- *number = '\0';
-
- if (!nt)
- {
- p = NULL;
- if (qi->QI_ELEMENT(called_nr))
- p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(called_nr) + 1;
- }
- if (!p)
- return;
- if (p[0] < 2)
- {
- printf("%s: ERROR: IE too short (%d).\n", __FUNCTION__, p[0]);
- return;
- }
-
- *type = (p[1]&0x70) >> 4;
- *plan = p[1] & 0xf;
- strnncpy(number, (char *)p+2, p[0]-1, number_len);
-
- if (MISDN_IE_DEBG) printf(" type=%d plan=%d number='%s'\n", *type, *plan, number);
-}
-
-
-/* IE_CALLING_PN */
-static void enc_ie_calling_pn(unsigned char **ntmode, msg_t *msg, int type, int plan, int present, int screen, char *number, int nt, struct misdn_bchannel *bc)
-{
- unsigned char *p;
- Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
- int l;
-
- if (type<0 || type>7)
- {
- printf("%s: ERROR: type(%d) is out of range.\n", __FUNCTION__, type);
- return;
- }
- if (plan<0 || plan>15)
- {
- printf("%s: ERROR: plan(%d) is out of range.\n", __FUNCTION__, plan);
- return;
- }
- if (present>3)
- {
- printf("%s: ERROR: present(%d) is out of range.\n", __FUNCTION__, present);
- return;
- }
- if (present >= 0) if (screen<0 || screen>3)
- {
- printf("%s: ERROR: screen(%d) is out of range.\n", __FUNCTION__, screen);
- return;
- }
-
- if (MISDN_IE_DEBG) printf(" type=%d plan=%d present=%d screen=%d number='%s'\n", type, plan, present, screen, number);
-
- l = 1;
- if (number) if (number[0])
- l += strlen((char *)number);
- if (present >= 0)
- l += 1;
- p = msg_put(msg, l+2);
- if (nt)
- *ntmode = p+1;
- else
- qi->QI_ELEMENT(calling_nr) = p - (unsigned char *)qi - sizeof(Q931_info_t);
- p[0] = IE_CALLING_PN;
- p[1] = l;
- if (present >= 0)
- {
- p[2] = 0x00 + (type<<4) + plan;
- p[3] = 0x80 + (present<<5) + screen;
- if (number) if (number[0])
- strncpy((char *)p+4, (char *)number, strlen((char *)number));
- } else
- {
- p[2] = 0x80 + (type<<4) + plan;
- if (number) if (number[0])
- strncpy((char *)p+3, (char *)number, strlen((char *)number));
- }
-}
-
-static void dec_ie_calling_pn(unsigned char *p, Q931_info_t *qi, int *type, int *plan, int *present, int *screen, char *number, int number_len, int nt, struct misdn_bchannel *bc)
-{
- *type = -1;
- *plan = -1;
- *present = -1;
- *screen = -1;
- *number = '\0';
-
- if (!nt)
- {
- p = NULL;
- if (qi->QI_ELEMENT(calling_nr))
- p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(calling_nr) + 1;
- }
- if (!p)
- return;
- if (p[0] < 1)
- {
- printf("%s: ERROR: IE too short (%d).\n", __FUNCTION__, p[0]);
- return;
- }
-
- *type = (p[1]&0x70) >> 4;
- *plan = p[1] & 0xf;
- if (!(p[1] & 0x80))
- {
- if (p[0] < 2)
- {
- printf("%s: ERROR: IE too short (%d).\n", __FUNCTION__, p[0]);
- return;
- }
- *present = (p[2]&0x60) >> 5;
- *screen = p[2] & 0x3;
- strnncpy(number, (char *)p+3, p[0]-2, number_len);
- } else
- {
- strnncpy(number, (char *)p+2, p[0]-1, number_len);
- /* SPECIAL workarround for IBT software bug */
- /* if (number[0]==0x80) */
- /* strcpy((char *)number, (char *)number+1); */
- }
-
- if (MISDN_IE_DEBG) printf(" type=%d plan=%d present=%d screen=%d number='%s'\n", *type, *plan, *present, *screen, number);
-}
-
-
-/* IE_CONNECTED_PN */
-static void enc_ie_connected_pn(unsigned char **ntmode, msg_t *msg, int type, int plan, int present, int screen, char *number, int nt, struct misdn_bchannel *bc)
-{
- unsigned char *p;
- Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
- int l;
-
- if (type<0 || type>7)
- {
- printf("%s: ERROR: type(%d) is out of range.\n", __FUNCTION__, type);
- return;
- }
- if (plan<0 || plan>15)
- {
- printf("%s: ERROR: plan(%d) is out of range.\n", __FUNCTION__, plan);
- return;
- }
- if (present>3)
- {
- printf("%s: ERROR: present(%d) is out of range.\n", __FUNCTION__, present);
- return;
- }
- if (present >= 0) if (screen<0 || screen>3)
- {
- printf("%s: ERROR: screen(%d) is out of range.\n", __FUNCTION__, screen);
- return;
- }
-
- if (MISDN_IE_DEBG) printf(" type=%d plan=%d present=%d screen=%d number='%s'\n", type, plan, present, screen, number);
-
- l = 1;
- if (number) if (number[0])
- l += strlen((char *)number);
- if (present >= 0)
- l += 1;
- p = msg_put(msg, l+2);
- if (nt)
- *ntmode = p+1;
- else
- qi->QI_ELEMENT(connected_nr) = p - (unsigned char *)qi - sizeof(Q931_info_t);
- p[0] = IE_CONNECT_PN;
- p[1] = l;
- if (present >= 0)
- {
- p[2] = 0x00 + (type<<4) + plan;
- p[3] = 0x80 + (present<<5) + screen;
- if (number) if (number[0])
- strncpy((char *)p+4, (char *)number, strlen((char *)number));
- } else
- {
- p[2] = 0x80 + (type<<4) + plan;
- if (number) if (number[0])
- strncpy((char *)p+3, (char *)number, strlen((char *)number));
- }
-}
-
-static void dec_ie_connected_pn(unsigned char *p, Q931_info_t *qi, int *type, int *plan, int *present, int *screen, char *number, int number_len, int nt, struct misdn_bchannel *bc)
-{
- *type = -1;
- *plan = -1;
- *present = -1;
- *screen = -1;
- *number = '\0';
-
- if (!nt)
- {
- p = NULL;
- if (qi->QI_ELEMENT(connected_nr))
- p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(connected_nr) + 1;
- }
- if (!p)
- return;
- if (p[0] < 1)
- {
- printf("%s: ERROR: IE too short (%d).\n", __FUNCTION__, p[0]);
- return;
- }
-
- *type = (p[1]&0x70) >> 4;
- *plan = p[1] & 0xf;
- if (!(p[1] & 0x80))
- {
- if (p[0] < 2)
- {
- printf("%s: ERROR: IE too short (%d).\n", __FUNCTION__, p[0]);
- return;
- }
- *present = (p[2]&0x60) >> 5;
- *screen = p[2] & 0x3;
- strnncpy(number, (char *)p+3, p[0]-2, number_len);
- } else
- {
- strnncpy(number, (char *)p+2, p[0]-1, number_len);
- }
-
- if (MISDN_IE_DEBG) printf(" type=%d plan=%d present=%d screen=%d number='%s'\n", *type, *plan, *present, *screen, number);
-}
-
-
-/* IE_CAUSE */
-static void enc_ie_cause(unsigned char **ntmode, msg_t *msg, int location, int cause, int nt, struct misdn_bchannel *bc)
-{
- unsigned char *p;
- Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
- int l;
-
- if (location<0 || location>7)
- {
- printf("%s: ERROR: location(%d) is out of range.\n", __FUNCTION__, location);
- return;
- }
- if (cause<0 || cause>127)
- {
- printf("%s: ERROR: cause(%d) is out of range.\n", __FUNCTION__, cause);
- return;
- }
-
- if (MISDN_IE_DEBG) printf(" location=%d cause=%d\n", location, cause);
-
- l = 2;
- p = msg_put(msg, l+2);
- if (nt)
- *ntmode = p+1;
- else
- qi->QI_ELEMENT(cause) = p - (unsigned char *)qi - sizeof(Q931_info_t);
- p[0] = IE_CAUSE;
- p[1] = l;
- p[2] = 0x80 + location;
- p[3] = 0x80 + cause;
-}
-
-#if 0
-static void enc_ie_cause_standalone(unsigned char **ntmode, msg_t *msg, int location, int cause, int nt, struct misdn_bchannel *bc)
-{
- unsigned char *p = msg_put(msg, 4);
- Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
- if (ntmode)
- *ntmode = p+1;
- else
- qi->QI_ELEMENT(cause) = p - (unsigned char *)qi - sizeof(Q931_info_t);
- p[0] = IE_CAUSE;
- p[1] = 2;
- p[2] = 0x80 + location;
- p[3] = 0x80 + cause;
-}
-#endif
-
-static void dec_ie_cause(unsigned char *p, Q931_info_t *qi, int *location, int *cause, int nt, struct misdn_bchannel *bc)
-{
- *location = -1;
- *cause = -1;
-
- if (!nt)
- {
- p = NULL;
- if (qi->QI_ELEMENT(cause))
- p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(cause) + 1;
- }
- if (!p)
- return;
- if (p[0] < 2)
- {
- printf("%s: ERROR: IE too short (%d).\n", __FUNCTION__, p[0]);
- return;
- }
-
- *location = p[1] & 0x0f;
- *cause = p[2] & 0x7f;
-
- if (MISDN_IE_DEBG) printf(" location=%d cause=%d\n", *location, *cause);
-}
-
-
-/* IE_CHANNEL_ID */
-static void enc_ie_channel_id(unsigned char **ntmode, msg_t *msg, int exclusive, int channel, int nt, struct misdn_bchannel *bc)
-{
- unsigned char *p;
- Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
- int l;
- struct misdn_stack *stack=get_stack_by_bc(bc);
- int pri = stack->pri;
-
- if (exclusive<0 || exclusive>1)
- {
- printf("%s: ERROR: exclusive(%d) is out of range.\n", __FUNCTION__, exclusive);
- return;
- }
- if ((channel<0 || channel>0xff)
- || (!pri && (channel>2 && channel<0xff))
- || (pri && (channel>31 && channel<0xff))
- || (pri && channel==16))
- {
- printf("%s: ERROR: channel(%d) is out of range.\n", __FUNCTION__, channel);
- return;
- }
-
- /* if (MISDN_IE_DEBG) printf(" exclusive=%d channel=%d\n", exclusive, channel); */
-
-
- if (!pri)
- {
- /* BRI */
- l = 1;
- p = msg_put(msg, l+2);
- if (nt)
- *ntmode = p+1;
- else
- qi->QI_ELEMENT(channel_id) = p - (unsigned char *)qi - sizeof(Q931_info_t);
- p[0] = IE_CHANNEL_ID;
- p[1] = l;
- if (channel == 0xff)
- channel = 3;
- p[2] = 0x80 + (exclusive<<3) + channel;
- /* printf(" exclusive=%d channel=%d\n", exclusive, channel); */
- } else
- {
- /* PRI */
- if (channel == 0) /* no channel */
- return; /* IE not present */
-/* if (MISDN_IE_DEBG) printf("channel = %d\n", channel); */
- if (channel == 0xff) /* any channel */
- {
- l = 1;
- p = msg_put(msg, l+2);
- if (nt)
- *ntmode = p+1;
- else
- qi->QI_ELEMENT(channel_id) = p - (unsigned char *)qi - sizeof(Q931_info_t);
- p[0] = IE_CHANNEL_ID;
- p[1] = l;
- p[2] = 0x80 + 0x20 + 0x03;
-/* if (MISDN_IE_DEBG) printf("%02x\n", p[2]); */
- return; /* end */
- }
- l = 3;
- p = msg_put(msg, l+2);
- if (nt)
- *ntmode = p+1;
- else
- qi->QI_ELEMENT(channel_id) = p - (unsigned char *)qi - sizeof(Q931_info_t);
- p[0] = IE_CHANNEL_ID;
- p[1] = l;
- p[2] = 0x80 + 0x20 + (exclusive<<3) + 0x01;
- p[3] = 0x80 + 3; /* CCITT, Number, B-type */
- p[4] = 0x80 + channel;
-/* if (MISDN_IE_DEBG) printf("%02x %02x %02x\n", p[2], p[3], p[4]); */
- }
-}
-
-static void dec_ie_channel_id(unsigned char *p, Q931_info_t *qi, int *exclusive, int *channel, int nt, struct misdn_bchannel *bc)
-{
- struct misdn_stack *stack=get_stack_by_bc(bc);
- int pri =stack->pri;
-
- *exclusive = -1;
- *channel = -1;
-
- if (!nt)
- {
- p = NULL;
- if (qi->QI_ELEMENT(channel_id))
- p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(channel_id) + 1;
- }
- if (!p)
- return;
- if (p[0] < 1)
- {
- printf("%s: ERROR: IE too short (%d).\n", __FUNCTION__, p[0]);
- return;
- }
-
- if (p[1] & 0x40)
- {
- printf("%s: ERROR: refering to channels of other interfaces is not supported.\n", __FUNCTION__);
- return;
- }
- if (p[1] & 0x04)
- {
- printf("%s: ERROR: using d-channel is not supported.\n", __FUNCTION__);
- return;
- }
-
- *exclusive = (p[1]&0x08) >> 3;
- if (!pri)
- {
- /* BRI */
- if (p[1] & 0x20)
- {
- printf("%s: ERROR: extended channel ID with non PRI interface.\n", __FUNCTION__);
- return;
- }
- *channel = p[1] & 0x03;
- if (*channel == 3)
- *channel = 0xff;
- } else
- {
- /* PRI */
- if (p[0] < 1)
- {
- printf("%s: ERROR: IE too short for PRI (%d).\n", __FUNCTION__, p[0]);
- return;
- }
- if (!(p[1] & 0x20))
- {
- printf("%s: ERROR: basic channel ID with PRI interface.\n", __FUNCTION__);
- return;
- }
- if ((p[1]&0x03) == 0x00)
- {
- /* no channel */
- *channel = 0;
- return;
- }
- if ((p[1]&0x03) == 0x03)
- {
- /* any channel */
- *channel = 0xff;
- return;
- }
- if (p[0] < 3)
- {
- printf("%s: ERROR: IE too short for PRI with channel(%d).\n", __FUNCTION__, p[0]);
- return;
- }
- if (p[2] & 0x10)
- {
- printf("%s: ERROR: channel map not supported.\n", __FUNCTION__);
- return;
- }
- *channel = p[3] & 0x7f;
- if ( (*channel<1) | (*channel==16) | (*channel>31))
- {
- printf("%s: ERROR: PRI interface channel out of range (%d).\n", __FUNCTION__, *channel);
- return;
- }
-/* if (MISDN_IE_DEBG) printf("%02x %02x %02x\n", p[1], p[2], p[3]); */
- }
-
- if (MISDN_IE_DEBG) printf(" exclusive=%d channel=%d\n", *exclusive, *channel);
-}
-
-
-/* IE_DATE */
-static void enc_ie_date(unsigned char **ntmode, msg_t *msg, time_t ti, int nt, struct misdn_bchannel *bc)
-{
- unsigned char *p;
- Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
- int l;
-
- struct tm *tm;
-
- tm = localtime(&ti);
- if (!tm)
- {
- printf("%s: ERROR: gettimeofday() returned NULL.\n", __FUNCTION__);
- return;
- }
-
- if (MISDN_IE_DEBG) printf(" year=%d month=%d day=%d hour=%d minute=%d\n", tm->tm_year%100, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min);
-
- l = 5;
- p = msg_put(msg, l+2);
- if (nt)
- *ntmode = p+1;
- else
- qi->QI_ELEMENT(date) = p - (unsigned char *)qi - sizeof(Q931_info_t);
- p[0] = IE_DATE;
- p[1] = l;
- p[2] = tm->tm_year % 100;
- p[3] = tm->tm_mon + 1;
- p[4] = tm->tm_mday;
- p[5] = tm->tm_hour;
- p[6] = tm->tm_min;
-}
-
-
-/* IE_DISPLAY */
-static void enc_ie_display(unsigned char **ntmode, msg_t *msg, char *display, int nt, struct misdn_bchannel *bc)
-{
- unsigned char *p;
- Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
- int l;
-
- if (!display[0])
- {
- printf("%s: ERROR: display text not given.\n", __FUNCTION__);
- return;
- }
-
- if (strlen((char *)display) > 80)
- {
- printf("%s: WARNING: display text too long (max 80 chars), cutting.\n", __FUNCTION__);
- display[80] = '\0';
- }
-
- /* if (MISDN_IE_DEBG) printf(" display='%s' (len=%d)\n", display, strlen((char *)display)); */
-
- l = strlen((char *)display);
- p = msg_put(msg, l+2);
- if (nt)
- *ntmode = p+1;
- else
- qi->QI_ELEMENT(display) = p - (unsigned char *)qi - sizeof(Q931_info_t);
- p[0] = IE_DISPLAY;
- p[1] = l;
- strncpy((char *)p+2, (char *)display, strlen((char *)display));
-}
-
-#if 0
-static void dec_ie_display(unsigned char *p, Q931_info_t *qi, char *display, int display_len, int nt, struct misdn_bchannel *bc)
-{
- *display = '\0';
-
- if (!nt)
- {
- p = NULL;
- if (qi->QI_ELEMENT(display))
- p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(display) + 1;
- }
- if (!p)
- return;
- if (p[0] < 1)
- {
- printf("%s: ERROR: IE too short (%d).\n", __FUNCTION__, p[0]);
- return;
- }
-
- strnncpy(display, (char *)p+1, p[0], display_len);
-
- if (MISDN_IE_DEBG) printf(" display='%s'\n", display);
-}
-#endif
-
-/* IE_KEYPAD */
-#if 1
-static void enc_ie_keypad(unsigned char **ntmode, msg_t *msg, char *keypad, int nt, struct misdn_bchannel *bc)
-{
- unsigned char *p;
- Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
- int l;
-
- if (!keypad[0])
- {
- printf("%s: ERROR: keypad info not given.\n", __FUNCTION__);
- return;
- }
-
- if (MISDN_IE_DEBG) printf(" keypad='%s'\n", keypad);
-
- l = strlen(keypad);
- p = msg_put(msg, l+2);
- if (nt)
- *ntmode = p+1;
- else
- qi->QI_ELEMENT(keypad) = p - (unsigned char *)qi - sizeof(Q931_info_t);
- p[0] = IE_KEYPAD;
- p[1] = l;
- strncpy((char *)p+2, keypad, strlen(keypad));
-}
-#endif
-
-static void dec_ie_keypad(unsigned char *p, Q931_info_t *qi, char *keypad, int keypad_len, int nt, struct misdn_bchannel *bc)
-{
- *keypad = '\0';
-
- if (!nt)
- {
- p = NULL;
- if (qi->QI_ELEMENT(keypad))
- p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(keypad) + 1;
- }
- if (!p)
- return;
- if (p[0] < 1)
- {
- printf("%s: ERROR: IE too short (%d).\n", __FUNCTION__, p[0]);
- return;
- }
-
- strnncpy(keypad, (char *)p+1, p[0], keypad_len);
-
- if (MISDN_IE_DEBG) printf(" keypad='%s'\n", keypad);
-}
-
-
-/* IE_NOTIFY */
-#if 0
-static void enc_ie_notify(unsigned char **ntmode, msg_t *msg, int notify, int nt, struct misdn_bchannel *bc)
-{
- unsigned char *p;
- Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
- int l;
-
- if (notify<0 || notify>0x7f)
- {
- printf("%s: ERROR: notify(%d) is out of range.\n", __FUNCTION__, notify);
- return;
- }
-
- if (MISDN_IE_DEBG) printf(" notify=%d\n", notify);
-
- l = 1;
- p = msg_put(msg, l+2);
- if (nt)
- *ntmode = p+1;
- else
- qi->QI_ELEMENT(notify) = p - (unsigned char *)qi - sizeof(Q931_info_t);
- p[0] = IE_NOTIFY;
- p[1] = l;
- p[2] = 0x80 + notify;
-}
-#endif
-
-#if 0
-static void dec_ie_notify(unsigned char *p, Q931_info_t *qi, int *notify, int nt, struct misdn_bchannel *bc)
-{
- *notify = -1;
-
- if (!nt)
- {
- p = NULL;
- if (qi->QI_ELEMENT(notify))
- p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(notify) + 1;
- }
- if (!p)
- return;
- if (p[0] < 1)
- {
- printf("%s: ERROR: IE too short (%d).\n", __FUNCTION__, p[0]);
- return;
- }
-
- *notify = p[1] & 0x7f;
-
- if (MISDN_IE_DEBG) printf(" notify=%d\n", *notify);
-}
-#endif
-
-
-/* IE_PROGRESS */
-static void enc_ie_progress(unsigned char **ntmode, msg_t *msg, int coding, int location, int progress, int nt, struct misdn_bchannel *bc)
-{
- unsigned char *p;
- Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
- int l;
-
- if (coding<0 || coding>0x03)
- {
- printf("%s: ERROR: coding(%d) is out of range.\n", __FUNCTION__, coding);
- return;
- }
- if (location<0 || location>0x0f)
- {
- printf("%s: ERROR: location(%d) is out of range.\n", __FUNCTION__, location);
- return;
- }
- if (progress<0 || progress>0x7f)
- {
- printf("%s: ERROR: progress(%d) is out of range.\n", __FUNCTION__, progress);
- return;
- }
-
- if (MISDN_IE_DEBG) printf(" coding=%d location=%d progress=%d\n", coding, location, progress);
-
- l = 2;
- p = msg_put(msg, l+2);
- if (nt)
- *ntmode = p+1;
- else
- qi->QI_ELEMENT(progress) = p - (unsigned char *)qi - sizeof(Q931_info_t);
- p[0] = IE_PROGRESS;
- p[1] = l;
- p[2] = 0x80 + (coding<<5) + location;
- p[3] = 0x80 + progress;
-}
-
-static void dec_ie_progress(unsigned char *p, Q931_info_t *qi, int *coding, int *location, int *progress, int nt, struct misdn_bchannel *bc)
-{
- *coding = -1;
- *location = -1;
- //*progress = -1;
- *progress = 0;
-
- if (!nt)
- {
- p = NULL;
- if (qi->QI_ELEMENT(progress))
- p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(progress) + 1;
- }
- if (!p)
- return;
- if (p[0] < 1)
- {
- printf("%s: ERROR: IE too short (%d).\n", __FUNCTION__, p[0]);
- return;
- }
-
- *coding = (p[1]&0x60) >> 5;
- *location = p[1] & 0x0f;
- *progress = p[2] & 0x7f;
-
- if (MISDN_IE_DEBG) printf(" coding=%d location=%d progress=%d\n", *coding, *location, *progress);
-}
-
-
-/* IE_REDIR_NR (redirecting = during MT_SETUP) */
-static void enc_ie_redir_nr(unsigned char **ntmode, msg_t *msg, int type, int plan, int present, int screen, int reason, char *number, int nt, struct misdn_bchannel *bc)
-{
- unsigned char *p;
- Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
- int l;
-
- if (type<0 || type>7)
- {
- printf("%s: ERROR: type(%d) is out of range.\n", __FUNCTION__, type);
- return;
- }
- if (plan<0 || plan>15)
- {
- printf("%s: ERROR: plan(%d) is out of range.\n", __FUNCTION__, plan);
- return;
- }
- if (present > 3)
- {
- printf("%s: ERROR: present(%d) is out of range.\n", __FUNCTION__, present);
- return;
- }
- if (present >= 0) if (screen<0 || screen>3)
- {
- printf("%s: ERROR: screen(%d) is out of range.\n", __FUNCTION__, screen);
- return;
- }
- if (reason > 0x0f)
- {
- printf("%s: ERROR: reason(%d) is out of range.\n", __FUNCTION__, reason);
- return;
- }
-
- if (MISDN_IE_DEBG) printf(" type=%d plan=%d present=%d screen=%d readon=%d number='%s'\n", type, plan, present, screen, reason, number);
-
- l = 1;
- if (number)
- l += strlen((char *)number);
- if (present >= 0)
- {
- l += 1;
- if (reason >= 0)
- l += 1;
- }
- p = msg_put(msg, l+2);
- if (nt)
- *ntmode = p+1;
- else
- qi->QI_ELEMENT(redirect_nr) = p - (unsigned char *)qi - sizeof(Q931_info_t);
- p[0] = IE_REDIR_NR;
- p[1] = l;
- if (present >= 0)
- {
- if (reason >= 0)
- {
- p[2] = 0x00 + (type<<4) + plan;
- p[3] = 0x00 + (present<<5) + screen;
- p[4] = 0x80 + reason;
- if (number)
- strncpy((char *)p+5, (char *)number, strlen((char *)number));
- } else
- {
- p[2] = 0x00 + (type<<4) + plan;
- p[3] = 0x80 + (present<<5) + screen;
- if (number)
- strncpy((char *)p+4, (char *)number, strlen((char *)number));
- }
- } else
- {
- p[2] = 0x80 + (type<<4) + plan;
- if (number) if (number[0])
- strncpy((char *)p+3, (char *)number, strlen((char *)number));
- }
-}
-
-static void dec_ie_redir_nr(unsigned char *p, Q931_info_t *qi, int *type, int *plan, int *present, int *screen, int *reason, char *number, int number_len, int nt, struct misdn_bchannel *bc)
-{
- *type = -1;
- *plan = -1;
- *present = -1;
- *screen = -1;
- *reason = -1;
- *number = '\0';
-
- if (!nt)
- {
- p = NULL;
- if (qi->QI_ELEMENT(redirect_nr))
- p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(redirect_nr) + 1;
- }
- if (!p)
- return;
- if (p[0] < 1)
- {
- printf("%s: ERROR: IE too short (%d).\n", __FUNCTION__, p[0]);
- return;
- }
-
- *type = (p[1]&0x70) >> 4;
- *plan = p[1] & 0xf;
- if (!(p[1] & 0x80))
- {
- *present = (p[2]&0x60) >> 5;
- *screen = p[2] & 0x3;
- if (!(p[2] & 0x80))
- {
- *reason = p[3] & 0x0f;
- strnncpy(number, (char *)p+4, p[0]-3, number_len);
- } else
- {
- strnncpy(number, (char *)p+3, p[0]-2, number_len);
- }
- } else
- {
- strnncpy(number, (char *)p+2, p[0]-1, number_len);
- }
-
- if (MISDN_IE_DEBG) printf(" type=%d plan=%d present=%d screen=%d reason=%d number='%s'\n", *type, *plan, *present, *screen, *reason, number);
-}
-
-
-/* IE_REDIR_DN (redirection = during MT_NOTIFY) */
-#if 0
-static void enc_ie_redir_dn(unsigned char **ntmode, msg_t *msg, int type, int plan, int present, char *number, int nt, struct misdn_bchannel *bc)
-{
- unsigned char *p;
-/* Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN); */
- int l;
-
- if (type<0 || type>7)
- {
- printf("%s: ERROR: type(%d) is out of range.\n", __FUNCTION__, type);
- return;
- }
- if (plan<0 || plan>15)
- {
- printf("%s: ERROR: plan(%d) is out of range.\n", __FUNCTION__, plan);
- return;
- }
- if (present > 3)
- {
- printf("%s: ERROR: present(%d) is out of range.\n", __FUNCTION__, present);
- return;
- }
-
- if (MISDN_IE_DEBG) printf(" type=%d plan=%d present=%d number='%s'\n", type, plan, present, number);
-
- l = 1;
- if (number)
- l += strlen((char *)number);
- if (present >= 0)
- l += 1;
- p = msg_put(msg, l+2);
- if (nt)
- *ntmode = p+1;
- else
-/* #warning REINSERT redir_dn, when included in te-mode */
- /*qi->QI_ELEMENT(redir_dn) = p - (unsigned char *)qi - sizeof(Q931_info_t)*/;
- p[0] = IE_REDIR_DN;
- p[1] = l;
- if (present >= 0)
- {
- p[2] = 0x00 + (type<<4) + plan;
- p[3] = 0x80 + (present<<5);
- if (number)
- strncpy((char *)p+4, (char *)number, strlen((char *)number));
- } else
- {
- p[2] = 0x80 + (type<<4) + plan;
- if (number)
- strncpy((char *)p+3, (char *)number, strlen((char *)number));
- }
-}
-#endif
-
-#if 0
-static void dec_ie_redir_dn(unsigned char *p, Q931_info_t *qi, int *type, int *plan, int *present, char *number, int number_len, int nt, struct misdn_bchannel *bc)
-{
- *type = -1;
- *plan = -1;
- *present = -1;
- *number = '\0';
-
- if (!nt)
- {
- p = NULL;
-/* #warning REINSERT redir_dn, when included in te-mode */
-/* if (qi->QI_ELEMENT(redir_dn)) */
-/* p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(redir_dn) + 1; */
- }
- if (!p)
- return;
- if (p[0] < 1)
- {
- printf("%s: ERROR: IE too short (%d).\n", __FUNCTION__, p[0]);
- return;
- }
-
- *type = (p[1]&0x70) >> 4;
- *plan = p[1] & 0xf;
- if (!(p[1] & 0x80))
- {
- *present = (p[2]&0x60) >> 5;
- strnncpy(number, (char *)p+3, p[0]-2, number_len);
- } else
- {
- strnncpy(number, (char *)p+2, p[0]-1, number_len);
- }
-
- if (MISDN_IE_DEBG) printf(" type=%d plan=%d present=%d number='%s'\n", *type, *plan, *present, number);
-}
-#endif
-
-
-/* IE_USERUSER */
-#if 1
-static void enc_ie_useruser(unsigned char **ntmode, msg_t *msg, int protocol, char *user, int user_len, int nt, struct misdn_bchannel *bc)
-{
- unsigned char *p;
- Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
- int l;
-
- char debug[768];
- int i;
-
- if (protocol<0 || protocol>127)
- {
- printf("%s: ERROR: protocol(%d) is out of range.\n", __FUNCTION__, protocol);
- return;
- }
- if (!user || user_len<=0)
- {
- return;
- }
-
- i = 0;
- while(i < user_len)
- {
- if (MISDN_IE_DEBG) printf(debug+(i*3), " %02x", user[i]);
- i++;
- }
-
- if (MISDN_IE_DEBG) printf(" protocol=%d user-user%s\n", protocol, debug);
-
- l = user_len+1;
- p = msg_put(msg, l+3);
- if (nt)
- *ntmode = p+1;
- else
- qi->QI_ELEMENT(useruser) = p - (unsigned char *)qi - sizeof(Q931_info_t);
- p[0] = IE_USER_USER;
- p[1] = l;
- p[2] = protocol;
- memcpy(p+3, user, user_len);
-}
-#endif
-
-#if 1
-static void dec_ie_useruser(unsigned char *p, Q931_info_t *qi, int *protocol, char *user, int *user_len, int nt, struct misdn_bchannel *bc)
-{
- char debug[768];
- int i;
-
- *user_len = 0;
- *protocol = -1;
-
- if (!nt)
- {
- p = NULL;
- if (qi->QI_ELEMENT(useruser))
- p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(useruser) + 1;
- }
- if (!p)
- return;
-
- *user_len = p[0]-1;
- if (p[0] < 1)
- return;
- *protocol = p[1];
- memcpy(user, p+2, (*user_len<=128)?*(user_len):128); /* clip to 128 maximum */
-
- i = 0;
- while(i < *user_len)
- {
- if (MISDN_IE_DEBG) printf(debug+(i*3), " %02x", user[i]);
- i++;
- }
- debug[i*3] = '\0';
-
- if (MISDN_IE_DEBG) printf(" protocol=%d user-user%s\n", *protocol, debug);
-}
-#endif
-
-/* IE_DISPLAY */
-static void enc_ie_restart_ind(unsigned char **ntmode, msg_t *msg, unsigned char rind, int nt, struct misdn_bchannel *bc)
-{
- unsigned char *p;
- Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
- /* if (MISDN_IE_DEBG) printf(" display='%s' (len=%d)\n", display, strlen((char *)display)); */
-
- p = msg_put(msg, 3);
- if (nt)
- *ntmode = p+1;
- else
- qi->QI_ELEMENT(restart_ind) = p - (unsigned char *)qi - sizeof(Q931_info_t);
- p[0] = IE_RESTART_IND;
- p[1] = 1;
- p[2] = rind;
-
-}
-
diff --git a/1.4.23-rc4/channels/misdn/isdn_lib.c b/1.4.23-rc4/channels/misdn/isdn_lib.c
deleted file mode 100644
index b21c794e7..000000000
--- a/1.4.23-rc4/channels/misdn/isdn_lib.c
+++ /dev/null
@@ -1,4661 +0,0 @@
-/*
- * Chan_Misdn -- Channel Driver for Asterisk
- *
- * Interface to mISDN
- *
- * Copyright (C) 2004, Christian Richter
- *
- * Christian Richter <crich@beronet.com>
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License
- */
-
-/*! \file
- * \brief Interface to mISDN
- * \author Christian Richter <crich@beronet.com>
- */
-
-
-
-#include <syslog.h>
-#include <sys/time.h>
-#include <mISDNuser/isdn_debug.h>
-
-#include "isdn_lib_intern.h"
-#include "isdn_lib.h"
-
-/*
- * Define ARRAY_LEN() because I cannot
- * #include "asterisk/utils.h"
- */
-#define ARRAY_LEN(a) (sizeof(a) / sizeof(a[0]))
-
-#include "asterisk/causes.h"
-
-void misdn_join_conf(struct misdn_bchannel *bc, int conf_id);
-void misdn_split_conf(struct misdn_bchannel *bc, int conf_id);
-
-int queue_cleanup_bc(struct misdn_bchannel *bc) ;
-
-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);
-
-int misdn_lib_port_is_pri(int port)
-{
- struct misdn_stack *stack=get_misdn_stack();
- for ( ; stack; stack=stack->next) {
- if (stack->port == port) {
- return stack->pri;
- }
- }
-
- return -1;
-}
-
-static void misdn_make_dummy(struct misdn_bchannel *dummybc, int port, int l3id, int nt, int channel)
-{
- memset (dummybc,0,sizeof(struct misdn_bchannel));
- dummybc->port=port;
- dummybc->l3_id=l3id;
- dummybc->nt=nt;
- dummybc->dummy=1;
- dummybc->channel=channel;
-}
-
-int misdn_lib_port_block(int port)
-{
- struct misdn_stack *stack=get_misdn_stack();
- for ( ; stack; stack=stack->next) {
- if (stack->port == port) {
- stack->blocked=1;
- return 0;
- }
- }
- return -1;
-
-}
-
-int misdn_lib_port_unblock(int port)
-{
- struct misdn_stack *stack=get_misdn_stack();
- for ( ; stack; stack=stack->next) {
- if (stack->port == port) {
- stack->blocked=0;
- return 0;
- }
- }
- return -1;
-
-}
-
-int misdn_lib_is_port_blocked(int port)
-{
- struct misdn_stack *stack=get_misdn_stack();
- for ( ; stack; stack=stack->next) {
- if (stack->port == port) {
- return stack->blocked;
- }
- }
- return -1;
-}
-
-int misdn_lib_is_ptp(int port)
-{
- struct misdn_stack *stack=get_misdn_stack();
- for ( ; stack; stack=stack->next) {
- if (stack->port == port) return stack->ptp;
- }
- return -1;
-}
-
-int misdn_lib_get_maxchans(int port)
-{
- struct misdn_stack *stack=get_misdn_stack();
- for ( ; stack; stack=stack->next) {
- if (stack->port == port) {
- if (stack->pri)
- return 30;
- else
- return 2;
- }
- }
- return -1;
-}
-
-
-struct misdn_stack *get_stack_by_bc(struct misdn_bchannel *bc)
-{
- struct misdn_stack *stack = get_misdn_stack();
-
- if (!bc)
- return NULL;
-
- for ( ; stack; stack = stack->next) {
- if (bc->port == stack->port)
- return stack;
- }
-
- return NULL;
-}
-
-
-void get_show_stack_details(int port, char *buf)
-{
- struct misdn_stack *stack=get_misdn_stack();
-
- for ( ; stack; stack=stack->next) {
- if (stack->port == port) break;
- }
-
- if (stack) {
- sprintf(buf, "* Port %d Type %s Prot. %s L2Link %s L1Link:%s Blocked:%d",
- stack->port, stack->nt ? "NT" : "TE", stack->ptp ? "PTP" : "PMP",
- stack->l2link ? "UP" : "DOWN", stack->l1link ? "UP" : "DOWN",
- stack->blocked);
- } else {
- buf[0]=0;
- }
-}
-
-
-static int nt_err_cnt =0 ;
-
-enum global_states {
- MISDN_INITIALIZING,
- MISDN_INITIALIZED
-} ;
-
-static enum global_states global_state=MISDN_INITIALIZING;
-
-
-#include <mISDNuser/net_l2.h>
-#include <mISDNuser/tone.h>
-#include <unistd.h>
-#include <semaphore.h>
-#include <pthread.h>
-#include <signal.h>
-
-#include "isdn_lib.h"
-
-
-struct misdn_lib {
- /*! \brief mISDN device handle returned by mISDN_open() */
- int midev;
- int midev_nt; /* Not used */
-
- pthread_t event_thread;
- pthread_t event_handler_thread;
-
- void *user_data;
-
- msg_queue_t upqueue;
- msg_queue_t activatequeue;
-
- sem_t new_msg;
-
- struct misdn_stack *stack_list;
-} ;
-
-#ifndef ECHOCAN_ON
-#define ECHOCAN_ON 123
-#define ECHOCAN_OFF 124
-#endif
-
-#define MISDN_DEBUG 0
-
-void misdn_tx_jitter(struct misdn_bchannel *bc, int len);
-
-struct misdn_bchannel *find_bc_by_l3id(struct misdn_stack *stack, unsigned long l3id);
-
-struct misdn_bchannel *find_bc_by_confid(unsigned long confid);
-
-struct misdn_bchannel *stack_holder_find_bychan(struct misdn_stack *stack, int chan);
-
-int setup_bc(struct misdn_bchannel *bc);
-
-int manager_isdn_handler(iframe_t *frm ,msg_t *msg);
-
-int misdn_lib_port_restart(int port);
-int misdn_lib_pid_restart(int pid);
-
-extern struct isdn_msg msgs_g[];
-
-#define ISDN_PID_L3_B_USER 0x430000ff
-#define ISDN_PID_L4_B_USER 0x440000ff
-
-/* #define MISDN_IBUF_SIZE 1024 */
-#define MISDN_IBUF_SIZE 512
-
-/* Fine Tuning of Inband Signalling time */
-#define TONE_ALERT_CNT 41 /* 1 Sec */
-#define TONE_ALERT_SILENCE_CNT 200 /* 4 Sec */
-
-#define TONE_BUSY_CNT 20 /* ? */
-#define TONE_BUSY_SILENCE_CNT 48 /* ? */
-
-static int entity;
-
-static struct misdn_lib *glob_mgr;
-
-char tone_425_flip[TONE_425_SIZE];
-char tone_silence_flip[TONE_SILENCE_SIZE];
-
-static void misdn_lib_isdn_event_catcher(void *arg);
-static int handle_event_nt(void *dat, void *arg);
-
-
-void stack_holder_add(struct misdn_stack *stack, struct misdn_bchannel *holder);
-void stack_holder_remove(struct misdn_stack *stack, struct misdn_bchannel *holder);
-struct misdn_bchannel *stack_holder_find(struct misdn_stack *stack, unsigned long l3id);
-
-/* 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);
-void manager_ph_control_block(struct misdn_bchannel *bc, int c1, void *c2, int c2_len);
-void manager_clean_bc(struct misdn_bchannel *bc );
-void manager_bchannel_setup (struct misdn_bchannel *bc);
-void manager_bchannel_cleanup (struct misdn_bchannel *bc);
-
-void ec_chunk( struct misdn_bchannel *bc, unsigned char *rxchunk, unsigned char *txchunk, int chunk_size);
- /* end */
-int bchdev_echocancel_activate(struct misdn_bchannel* dev);
-void bchdev_echocancel_deactivate(struct misdn_bchannel* dev);
-/* end */
-
-
-static char *bearer2str(int cap) {
- static char *bearers[]={
- "Speech",
- "Audio 3.1k",
- "Unres Digital",
- "Res Digital",
- "Unknown Bearer"
- };
-
- switch (cap) {
- case INFO_CAPABILITY_SPEECH:
- return bearers[0];
- break;
- case INFO_CAPABILITY_AUDIO_3_1K:
- return bearers[1];
- break;
- case INFO_CAPABILITY_DIGITAL_UNRESTRICTED:
- return bearers[2];
- break;
- case INFO_CAPABILITY_DIGITAL_RESTRICTED:
- return bearers[3];
- break;
- default:
- return bearers[4];
- break;
- }
-}
-
-
-static char flip_table[256];
-
-static void init_flip_bits(void)
-{
- int i,k;
-
- for (i = 0 ; i < 256 ; i++) {
- unsigned char sample = 0 ;
- for (k = 0; k<8; k++) {
- if ( i & 1 << k ) sample |= 0x80 >> k;
- }
- flip_table[i] = sample;
- }
-}
-
-static char * flip_buf_bits ( char * buf , int len)
-{
- int i;
- char * start = buf;
-
- for (i = 0 ; i < len; i++) {
- buf[i] = flip_table[(unsigned char)buf[i]];
- }
-
- return start;
-}
-
-
-
-
-static msg_t *create_l2msg(int prim, int dinfo, int size) /* NT only */
-{
- int i = 0;
- msg_t *dmsg;
-
- while(i < 10)
- {
- dmsg = prep_l3data_msg(prim, dinfo, size, 256, NULL);
- if (dmsg)
- return(dmsg);
-
- if (!i)
- printf("cannot allocate memory, trying again...\n");
- i++;
- usleep(300000);
- }
- printf("cannot allocate memory, system overloaded.\n");
- exit(-1);
-}
-
-
-
-msg_t *create_l3msg(int prim, int mt, int dinfo, int size, int ntmode)
-{
- int i = 0;
- msg_t *dmsg;
- Q931_info_t *qi;
- iframe_t *frm;
-
- if (!ntmode)
- size = sizeof(Q931_info_t)+2;
-
- while(i < 10) {
- if (ntmode) {
- dmsg = prep_l3data_msg(prim, dinfo, size, 256, NULL);
- if (dmsg) {
- return(dmsg);
- }
- } else {
- dmsg = alloc_msg(size+256+mISDN_HEADER_LEN+DEFAULT_HEADROOM);
- if (dmsg)
- {
- memset(msg_put(dmsg,size+mISDN_HEADER_LEN), 0, size+mISDN_HEADER_LEN);
- frm = (iframe_t *)dmsg->data;
- frm->prim = prim;
- frm->dinfo = dinfo;
- qi = (Q931_info_t *)(dmsg->data + mISDN_HEADER_LEN);
- qi->type = mt;
- return(dmsg);
- }
- }
-
- if (!i) printf("cannot allocate memory, trying again...\n");
- i++;
- usleep(300000);
- }
- printf("cannot allocate memory, system overloaded.\n");
- exit(-1);
-}
-
-
-static int send_msg (int midev, struct misdn_bchannel *bc, msg_t *dmsg)
-{
- iframe_t *frm = (iframe_t *)dmsg->data;
- struct misdn_stack *stack=get_stack_by_bc(bc);
-
- if (!stack) {
- cb_log(0,bc->port,"send_msg: IEK!! no stack\n ");
- return -1;
- }
-
- frm->addr = (stack->upper_id | FLG_MSG_DOWN);
- frm->dinfo = bc->l3_id;
- frm->len = (dmsg->len) - mISDN_HEADER_LEN;
-
- cb_log(4,stack->port,"Sending msg, prim:%x addr:%x dinfo:%x\n",frm->prim,frm->addr,frm->dinfo);
-
- mISDN_write(midev, dmsg->data, dmsg->len, TIMEOUT_1SEC);
- free_msg(dmsg);
-
- return 0;
-}
-
-
-static int mypid=1;
-
-
-int misdn_cap_is_speech(int cap)
-/** Poor mans version **/
-{
- if ( (cap != INFO_CAPABILITY_DIGITAL_UNRESTRICTED) &&
- (cap != INFO_CAPABILITY_DIGITAL_RESTRICTED) ) return 1;
- return 0;
-}
-
-int misdn_inband_avail(struct misdn_bchannel *bc)
-{
-
- if (!bc->early_bconnect) {
- /* We have opted to never receive any available inband recorded messages */
- return 0;
- }
-
- switch (bc->progress_indicator) {
- case INFO_PI_INBAND_AVAILABLE:
- case INFO_PI_CALL_NOT_E2E_ISDN:
- case INFO_PI_CALLED_NOT_ISDN:
- return 1;
- default:
- return 0;
- }
- return 0;
-}
-
-
-static void dump_chan_list(struct misdn_stack *stack)
-{
- 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);
- }
-}
-
-
-void misdn_dump_chanlist()
-{
- struct misdn_stack *stack=get_misdn_stack();
- for ( ; stack; stack=stack->next) {
- dump_chan_list(stack);
- }
-
-}
-
-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 (!stack->channels[channel-1])
- stack->channels[channel-1] = 1;
- else {
- cb_log(4,stack->port,"channel already in use:%d\n", channel );
- return -1;
- }
- } else {
- cb_log(0,stack->port,"couldn't set channel %d in\n", channel );
- return -1;
- }
-
- return 0;
-}
-
-
-
-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)
- 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;
- }
- }
- }
- } 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;
- }
- }
- }
- }
-
- if (!chan) {
- 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);
- bc->out_cause = AST_CAUSE_REQUESTED_CHAN_UNAVAIL;
- return -1;
- }
-
- 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;
- dump_chan_list(stack);
- return 0;
-}
-
-char *bc_state2str(enum bchannel_state state) {
- int i;
-
- struct bchan_state_s {
- char *n;
- enum bchannel_state s;
- } states[] = {
- {"BCHAN_CLEANED", BCHAN_CLEANED },
- {"BCHAN_EMPTY", BCHAN_EMPTY},
- {"BCHAN_SETUP", BCHAN_SETUP},
- {"BCHAN_SETUPED", BCHAN_SETUPED},
- {"BCHAN_ACTIVE", BCHAN_ACTIVE},
- {"BCHAN_ACTIVATED", BCHAN_ACTIVATED},
- {"BCHAN_BRIDGE", BCHAN_BRIDGE},
- {"BCHAN_BRIDGED", BCHAN_BRIDGED},
- {"BCHAN_RELEASE", BCHAN_RELEASE},
- {"BCHAN_RELEASED", BCHAN_RELEASED},
- {"BCHAN_CLEAN", BCHAN_CLEAN},
- {"BCHAN_CLEAN_REQUEST", BCHAN_CLEAN_REQUEST},
- {"BCHAN_ERROR", BCHAN_ERROR}
- };
-
- for (i=0; i< sizeof(states)/sizeof(struct bchan_state_s); i++)
- if ( states[i].s == state)
- return states[i].n;
-
- return "UNKNOWN";
-}
-
-void bc_state_change(struct misdn_bchannel *bc, enum bchannel_state state)
-{
- cb_log(5,bc->port,"BC_STATE_CHANGE: l3id:%x from:%s to:%s\n",
- bc->l3_id,
- bc_state2str(bc->bc_state),
- bc_state2str(state) );
-
- switch (state) {
- case BCHAN_ACTIVATED:
- if (bc->next_bc_state == BCHAN_BRIDGED) {
- misdn_join_conf(bc, bc->conf_id);
- bc->next_bc_state = BCHAN_EMPTY;
- return;
- }
- default:
- bc->bc_state=state;
- break;
- }
-}
-
-static void bc_next_state_change(struct misdn_bchannel *bc, enum bchannel_state state)
-{
- cb_log(5,bc->port,"BC_NEXT_STATE_CHANGE: from:%s to:%s\n",
- bc_state2str(bc->next_bc_state),
- bc_state2str(state) );
-
- bc->next_bc_state=state;
-}
-
-
-static void empty_bc(struct misdn_bchannel *bc)
-{
- bc->dummy=0;
-
- bc->bframe_len=0;
-
- bc->cw= 0;
-
- bc->dec=0;
- bc->channel = 0;
-
- bc->sending_complete = 0;
-
- bc->restart_channel=0;
-
- bc->conf_id = 0;
-
- bc->need_more_infos = 0;
-
- bc->send_dtmf=0;
- bc->nodsp=0;
- bc->nojitter=0;
-
- bc->time_usec=0;
-
- bc->rxgain=0;
- bc->txgain=0;
-
- bc->crypt=0;
- bc->curptx=0; bc->curprx=0;
-
- bc->crypt_key[0] = 0;
-
- bc->generate_tone=0;
- bc->tone_cnt=0;
-
- bc->dnumplan=NUMPLAN_UNKNOWN;
- bc->onumplan=NUMPLAN_UNKNOWN;
- bc->rnumplan=NUMPLAN_UNKNOWN;
- bc->cpnnumplan=NUMPLAN_UNKNOWN;
-
-
- bc->active = 0;
-
- bc->early_bconnect = 1;
-
-#ifdef MISDN_1_2
- *bc->pipeline = 0;
-#else
- bc->ec_enable = 0;
- bc->ec_deftaps = 128;
-#endif
-
- bc->orig=0;
-
- bc->cause = AST_CAUSE_NORMAL_CLEARING;
- bc->out_cause = AST_CAUSE_NORMAL_CLEARING;
- bc->pres = 0; /* allowed */
-
- bc->evq=EVENT_NOTHING;
-
- bc->progress_coding=0;
- bc->progress_location=0;
- bc->progress_indicator=0;
-
-/** Set Default Bearer Caps **/
- bc->capability=INFO_CAPABILITY_SPEECH;
- bc->law=INFO_CODEC_ALAW;
- bc->mode=0;
- bc->rate=0x10;
- bc->user1=0;
- bc->urate=0;
-
- bc->hdlc=0;
-
-
- bc->info_dad[0] = 0;
- bc->display[0] = 0;
- bc->infos_pending[0] = 0;
- bc->cad[0] = 0;
- bc->oad[0] = 0;
- bc->dad[0] = 0;
- bc->rad[0] = 0;
- bc->orig_dad[0] = 0;
- bc->uu[0]=0;
- bc->uulen=0;
-
- bc->fac_in.Function = Fac_None;
- bc->fac_out.Function = Fac_None;
-
- bc->te_choose_channel = 0;
- bc->channel_found= 0;
-
- gettimeofday(&bc->last_used, NULL);
-}
-
-
-static int clean_up_bc(struct misdn_bchannel *bc)
-{
- int ret=0;
- unsigned char buff[32];
- struct misdn_stack * stack;
-
- cb_log(3, bc?bc->port:0, "$$$ CLEANUP CALLED pid:%d\n", bc?bc->pid:-1);
-
- if (!bc ) return -1;
- stack=get_stack_by_bc(bc);
-
- if (!stack) return -1;
-
- switch (bc->bc_state ) {
- case BCHAN_CLEANED:
- cb_log(5, stack->port, "$$$ Already cleaned up bc with stid :%x\n", bc->b_stid);
- return -1;
-
- default:
- break;
- }
-
- cb_log(2, stack->port, "$$$ Cleaning up bc with stid :%x pid:%d\n", bc->b_stid, bc->pid);
-
- manager_ec_disable(bc);
-
- manager_bchannel_deactivate(bc);
-
- mISDN_write_frame(stack->midev, buff, bc->layer_id|FLG_MSG_TARGET|FLG_MSG_DOWN, MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
-
- bc->b_stid = 0;
- bc_state_change(bc, BCHAN_CLEANED);
-
- return ret;
-}
-
-
-
-static void clear_l3(struct misdn_stack *stack)
-{
- int i;
-
- for (i=0; i<=stack->b_num; i++) {
- if (global_state == MISDN_INITIALIZED) {
- cb_event(EVENT_CLEANUP, &stack->bc[i], NULL);
- 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 new_te_id = 0;
-
-#define MAXPROCS 0x100
-
-static int misdn_lib_get_l1_down(struct misdn_stack *stack)
-{
- /* Pull Up L1 */
- iframe_t act;
- act.prim = PH_DEACTIVATE | REQUEST;
- act.addr = stack->lower_id|FLG_MSG_DOWN;
- act.dinfo = 0;
- act.len = 0;
-
- cb_log(1, stack->port, "SENDING PH_DEACTIVATE | REQ\n");
- return mISDN_write(stack->midev, &act, mISDN_HEADER_LEN+act.len, TIMEOUT_1SEC);
-}
-
-
-static int misdn_lib_get_l2_down(struct misdn_stack *stack)
-{
-
- if (stack->ptp && (stack->nt) ) {
- msg_t *dmsg;
- /* L2 */
- dmsg = create_l2msg(DL_RELEASE| REQUEST, 0, 0);
-
- if (stack->nst.manager_l3(&stack->nst, dmsg))
- free_msg(dmsg);
-
- } else {
- iframe_t act;
-
- act.prim = DL_RELEASE| REQUEST;
- act.addr = (stack->upper_id |FLG_MSG_DOWN) ;
-
- act.dinfo = 0;
- act.len = 0;
- return mISDN_write(stack->midev, &act, mISDN_HEADER_LEN+act.len, TIMEOUT_1SEC);
- }
-
- return 0;
-}
-
-
-static int misdn_lib_get_l1_up(struct misdn_stack *stack)
-{
- /* Pull Up L1 */
- iframe_t act;
- act.prim = PH_ACTIVATE | REQUEST;
- act.addr = (stack->upper_id | FLG_MSG_DOWN) ;
-
-
- act.dinfo = 0;
- act.len = 0;
-
- return mISDN_write(stack->midev, &act, mISDN_HEADER_LEN+act.len, TIMEOUT_1SEC);
-
-}
-
-int misdn_lib_get_l2_up(struct misdn_stack *stack)
-{
-
- if (stack->ptp && (stack->nt) ) {
- msg_t *dmsg;
- /* L2 */
- dmsg = create_l2msg(DL_ESTABLISH | REQUEST, 0, 0);
-
- if (stack->nst.manager_l3(&stack->nst, dmsg))
- free_msg(dmsg);
-
- } else {
- iframe_t act;
-
- act.prim = DL_ESTABLISH | REQUEST;
- act.addr = (stack->upper_id |FLG_MSG_DOWN) ;
-
- act.dinfo = 0;
- act.len = 0;
- return mISDN_write(stack->midev, &act, mISDN_HEADER_LEN+act.len, TIMEOUT_1SEC);
- }
-
- return 0;
-}
-
-#if 0
-static int misdn_lib_get_l2_te_ptp_up(struct misdn_stack *stack)
-{
- iframe_t act;
-
- act.prim = DL_ESTABLISH | REQUEST;
- act.addr = (stack->upper_id & ~LAYER_ID_MASK) | 3 | FLG_MSG_DOWN;
-
- act.dinfo = 0;
- act.len = 0;
- return mISDN_write(stack->midev, &act, mISDN_HEADER_LEN+act.len, TIMEOUT_1SEC);
- return 0;
-}
-#endif
-
-static int misdn_lib_get_short_status(struct misdn_stack *stack)
-{
- iframe_t act;
-
-
- act.prim = MGR_SHORTSTATUS | REQUEST;
-
- act.addr = (stack->upper_id | MSG_BROADCAST) ;
-
- act.dinfo = SSTATUS_BROADCAST_BIT | SSTATUS_ALL;
-
- act.len = 0;
- return mISDN_write(stack->midev, &act, mISDN_HEADER_LEN+act.len, TIMEOUT_1SEC);
-}
-
-
-
-static int create_process(int midev, struct misdn_bchannel *bc)
-{
- iframe_t ncr;
- int l3_id;
- 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 (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[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;
- mISDN_write(midev, &ncr, mISDN_HEADER_LEN + ncr.len, TIMEOUT_1SEC);
- }
-
- return l3_id;
-}
-
-
-void misdn_lib_setup_bc(struct misdn_bchannel *bc)
-{
- clean_up_bc(bc);
- setup_bc(bc);
-}
-
-
-int setup_bc(struct misdn_bchannel *bc)
-{
- unsigned char buff[1025];
- int midev;
- int channel;
- int b_stid;
- int i;
- mISDN_pid_t pid;
- int ret;
-
- struct misdn_stack *stack=get_stack_by_bc(bc);
-
- if (!stack) {
- cb_log(0, bc->port, "setup_bc: NO STACK FOUND!!\n");
- return -1;
- }
-
- midev = stack->midev;
- channel = bc->channel - 1 - (bc->channel > 16);
- b_stid = stack->b_stids[channel >= 0 ? channel : 0];
-
- switch (bc->bc_state) {
- case BCHAN_CLEANED:
- break;
- default:
- cb_log(4, stack->port, "$$$ bc already setup stid :%x (state:%s)\n", b_stid, bc_state2str(bc->bc_state) );
- return -1;
- }
-
- cb_log(5, stack->port, "$$$ Setting up bc with stid :%x\n", b_stid);
-
- /*check if the b_stid is already initialized*/
- for (i=0; i <= stack->b_num; i++) {
- if (stack->bc[i].b_stid == b_stid) {
- cb_log(0, bc->port, "setup_bc: b_stid:%x already in use !!!\n", b_stid);
- return -1;
- }
- }
-
- if (b_stid <= 0) {
- cb_log(0, stack->port," -- Stid <=0 at the moment in channel:%d\n",channel);
-
- bc_state_change(bc,BCHAN_ERROR);
- return 1;
- }
-
- bc->b_stid = b_stid;
-
- {
- layer_info_t li;
- memset(&li, 0, sizeof(li));
-
- li.object_id = -1;
- li.extentions = 0;
-
- li.st = bc->b_stid; /* given idx */
-
-
-#define MISDN_DSP
-#ifndef MISDN_DSP
- bc->nodsp=1;
-#endif
- if ( bc->hdlc || bc->nodsp) {
- cb_log(4, stack->port,"setup_bc: without dsp\n");
- {
- int l = sizeof(li.name);
- strncpy(li.name, "B L3", l);
- li.name[l-1] = 0;
- }
- li.pid.layermask = ISDN_LAYER((3));
- li.pid.protocol[3] = ISDN_PID_L3_B_USER;
-
- bc->layer=3;
- } else {
- cb_log(4, stack->port,"setup_bc: with dsp\n");
- {
- int l = sizeof(li.name);
- strncpy(li.name, "B L4", l);
- li.name[l-1] = 0;
- }
- li.pid.layermask = ISDN_LAYER((4));
- li.pid.protocol[4] = ISDN_PID_L4_B_USER;
-
- bc->layer=4;
- }
-
- ret = mISDN_new_layer(midev, &li);
- if (ret ) {
- cb_log(0, stack->port,"New Layer Err: %d %s\n",ret,strerror(errno));
-
- bc_state_change(bc,BCHAN_ERROR);
- return(-EINVAL);
- }
-
- bc->layer_id = li.id;
- }
-
- memset(&pid, 0, sizeof(pid));
-
-
-
- cb_log(4, stack->port," --> Channel is %d\n", bc->channel);
-
- if (bc->nodsp) {
- cb_log(2, stack->port," --> TRANSPARENT Mode (no DSP, no HDLC)\n");
- pid.protocol[1] = ISDN_PID_L1_B_64TRANS;
- pid.protocol[2] = ISDN_PID_L2_B_TRANS;
- pid.protocol[3] = ISDN_PID_L3_B_USER;
- pid.layermask = ISDN_LAYER((1)) | ISDN_LAYER((2)) | ISDN_LAYER((3));
-
- } else if ( bc->hdlc ) {
- cb_log(2, stack->port," --> HDLC Mode\n");
- pid.protocol[1] = ISDN_PID_L1_B_64HDLC ;
- pid.protocol[2] = ISDN_PID_L2_B_TRANS ;
- pid.protocol[3] = ISDN_PID_L3_B_USER;
- pid.layermask = ISDN_LAYER((1)) | ISDN_LAYER((2)) | ISDN_LAYER((3)) ;
- } else {
- cb_log(2, stack->port," --> TRANSPARENT Mode\n");
- pid.protocol[1] = ISDN_PID_L1_B_64TRANS;
- pid.protocol[2] = ISDN_PID_L2_B_TRANS;
- pid.protocol[3] = ISDN_PID_L3_B_DSP;
- pid.protocol[4] = ISDN_PID_L4_B_USER;
- pid.layermask = ISDN_LAYER((1)) | ISDN_LAYER((2)) | ISDN_LAYER((3)) | ISDN_LAYER((4));
-
- }
-
- ret = mISDN_set_stack(midev, bc->b_stid, &pid);
-
- if (ret){
- cb_log(0, stack->port,"$$$ Set Stack Err: %d %s\n",ret,strerror(errno));
-
- mISDN_write_frame(midev, buff, bc->layer_id, MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
-
- bc_state_change(bc,BCHAN_ERROR);
- cb_event(EVENT_BCHAN_ERROR, bc, glob_mgr->user_data);
- return(-EINVAL);
- }
-
- ret = mISDN_get_setstack_ind(midev, bc->layer_id);
-
- if (ret) {
- cb_log(0, stack->port,"$$$ Set StackIND Err: %d %s\n",ret,strerror(errno));
- mISDN_write_frame(midev, buff, bc->layer_id, MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
-
- bc_state_change(bc,BCHAN_ERROR);
- cb_event(EVENT_BCHAN_ERROR, bc, glob_mgr->user_data);
- return(-EINVAL);
- }
-
- ret = mISDN_get_layerid(midev, bc->b_stid, bc->layer) ;
-
- bc->addr = ret>0? ret : 0;
-
- if (!bc->addr) {
- cb_log(0, stack->port,"$$$ Get Layerid Err: %d %s\n",ret,strerror(errno));
- mISDN_write_frame(midev, buff, bc->layer_id, MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
-
- bc_state_change(bc,BCHAN_ERROR);
- cb_event(EVENT_BCHAN_ERROR, bc, glob_mgr->user_data);
- return (-EINVAL);
- }
-
- manager_bchannel_activate(bc);
-
- bc_state_change(bc,BCHAN_ACTIVATED);
-
- return 0;
-}
-
-
-
-/** IFACE **/
-static int init_bc(struct misdn_stack *stack, struct misdn_bchannel *bc, int midev, int port, int bidx, char *msn, int firsttime)
-{
- unsigned char buff[1025] = "";
- iframe_t *frm = (iframe_t *)buff;
- int ret;
-
- if (!bc) return -1;
-
- cb_log(8, port, "Init.BC %d.\n",bidx);
-
- memset(bc, 0,sizeof(struct misdn_bchannel));
-
- bc->send_lock=malloc(sizeof(struct send_lock));
- if (!bc->send_lock) {
- return -1;
- }
- pthread_mutex_init(&bc->send_lock->lock, NULL);
-
- if (msn) {
- int l = sizeof(bc->msn);
- strncpy(bc->msn,msn, l);
- bc->msn[l-1] = 0;
- }
-
-
- empty_bc(bc);
- bc_state_change(bc, BCHAN_CLEANED);
-
- bc->port=stack->port;
- bc->nt=stack->nt?1:0;
- bc->pri=stack->pri;
-
- {
- ibuffer_t* ibuf= init_ibuffer(MISDN_IBUF_SIZE);
-
- if (!ibuf) return -1;
-
- clear_ibuffer( ibuf);
-
- ibuf->rsem=malloc(sizeof(sem_t));
- if (!ibuf->rsem) {
- return -1;
- }
-
- bc->astbuf=ibuf;
-
- if (sem_init(ibuf->rsem,1,0)<0)
- sem_init(ibuf->rsem,0,0);
-
- }
-
- {
- stack_info_t *stinf;
- ret = mISDN_get_stack_info(midev, stack->port, buff, sizeof(buff));
- if (ret < 0) {
- cb_log(0, port, "%s: Cannot get stack info for this port. (ret=%d)\n", __FUNCTION__, ret);
- return -1;
- }
-
- stinf = (stack_info_t *)&frm->data.p;
-
- cb_log(8, port, " --> Child %x\n",stinf->child[bidx]);
- }
-
- return 0;
-}
-
-
-
-static struct misdn_stack *stack_init(int midev, int port, int ptp)
-{
- int ret;
- unsigned char buff[1025];
- iframe_t *frm = (iframe_t *)buff;
- stack_info_t *stinf;
- int i;
- layer_info_t li;
-
- struct misdn_stack *stack = malloc(sizeof(struct misdn_stack));
- if (!stack ) return NULL;
-
-
- cb_log(8, port, "Init. Stack.\n");
-
- memset(stack,0,sizeof(struct misdn_stack));
-
- for (i=0; i<MAX_BCHANS + 1; i++ ) stack->channels[i]=0;
-
- stack->port=port;
- stack->midev=midev;
- stack->ptp=ptp;
-
- stack->holding=NULL;
- stack->pri=0;
-
- msg_queue_init(&stack->downqueue);
- msg_queue_init(&stack->upqueue);
-
- /* query port's requirements */
- ret = mISDN_get_stack_info(midev, port, buff, sizeof(buff));
- if (ret < 0) {
- cb_log(0, port, "%s: Cannot get stack info for this port. (ret=%d)\n", __FUNCTION__, ret);
- return(NULL);
- }
-
- stinf = (stack_info_t *)&frm->data.p;
-
- stack->d_stid = stinf->id;
- stack->b_num = stinf->childcnt;
-
- for (i=0; i<=stinf->childcnt; i++)
- stack->b_stids[i] = stinf->child[i];
-
- switch(stinf->pid.protocol[0] & ~ISDN_PID_FEATURE_MASK) {
- case ISDN_PID_L0_TE_S0:
- stack->nt=0;
- break;
- case ISDN_PID_L0_NT_S0:
- cb_log(8, port, "NT Stack\n");
-
- stack->nt=1;
- break;
- case ISDN_PID_L0_TE_E1:
- cb_log(8, port, "TE S2M Stack\n");
- stack->nt=0;
- stack->pri=1;
- break;
- case ISDN_PID_L0_NT_E1:
- cb_log(8, port, "TE S2M Stack\n");
- stack->nt=1;
- stack->pri=1;
-
- break;
- default:
- cb_log(0, port, "this is a unknown port type 0x%08x\n", stinf->pid.protocol[0]);
-
- }
-
- if (!stack->nt) {
- if (stinf->pid.protocol[2] & ISDN_PID_L2_DF_PTP ) {
- stack->ptp = 1;
- } else {
- stack->ptp = 0;
- }
- }
-
- {
- int ret;
- int nt=stack->nt;
-
- cb_log(8, port, "Init. Stack.\n");
-
- memset(&li, 0, sizeof(li));
- {
- int l = sizeof(li.name);
- strncpy(li.name,nt?"net l2":"user l4", l);
- li.name[l-1] = 0;
- }
- li.object_id = -1;
- li.extentions = 0;
- li.pid.protocol[nt?2:4] = nt?ISDN_PID_L2_LAPD_NET:ISDN_PID_L4_CAPI20;
- li.pid.layermask = ISDN_LAYER((nt?2:4));
- li.st = stack->d_stid;
-
-
- ret = mISDN_new_layer(midev, &li);
- if (ret) {
- cb_log(0, port, "%s: Cannot add layer %d to this port.\n", __FUNCTION__, nt?2:4);
- return(NULL);
- }
-
-
- stack->upper_id = li.id;
- ret = mISDN_register_layer(midev, stack->d_stid, stack->upper_id);
- if (ret)
- {
- cb_log(0,port,"Cannot register layer %d of this port.\n", nt?2:4);
- return(NULL);
- }
-
- stack->lower_id = mISDN_get_layerid(midev, stack->d_stid, nt?1:3);
- if (stack->lower_id < 0) {
- cb_log(0, port, "%s: Cannot get layer(%d) id of this port.\n", __FUNCTION__, nt?1:3);
- return(NULL);
- }
-
- stack->upper_id = mISDN_get_layerid(midev, stack->d_stid, nt?2:4);
- if (stack->upper_id < 0) {
- cb_log(0, port, "%s: Cannot get layer(%d) id of this port.\n", __FUNCTION__, 2);
- return(NULL);
- }
-
- cb_log(8, port, "NT Stacks upper_id %x\n",stack->upper_id);
-
-
- /* create nst (nt-mode only) */
- if (nt) {
-
- memset(&stack->nst, 0, sizeof(net_stack_t));
- memset(&stack->mgr, 0, sizeof(manager_t));
-
- stack->mgr.nst = &stack->nst;
- stack->nst.manager = &stack->mgr;
-
- stack->nst.l3_manager = handle_event_nt;
- stack->nst.device = midev;
- stack->nst.cardnr = port;
- stack->nst.d_stid = stack->d_stid;
-
- stack->nst.feature = FEATURE_NET_HOLD;
- if (stack->ptp)
- stack->nst.feature |= FEATURE_NET_PTP;
- if (stack->pri)
- stack->nst.feature |= FEATURE_NET_CRLEN2 | FEATURE_NET_EXTCID;
-
- stack->nst.l1_id = stack->lower_id;
- stack->nst.l2_id = stack->upper_id;
-
- msg_queue_init(&stack->nst.down_queue);
-
- Isdnl2Init(&stack->nst);
- Isdnl3Init(&stack->nst);
-
- }
-
- if (!stack->nt) {
- /*assume L1 is up, we'll get DEACTIVATES soon, for non
- * up L1s*/
- stack->l1link=0;
- }
- stack->l1link=0;
- stack->l2link=0;
-#if 0
- if (!stack->nt) {
- misdn_lib_get_short_status(stack);
- } else {
- misdn_lib_get_l1_up(stack);
- if (!stack->ptp) misdn_lib_get_l1_up(stack);
- misdn_lib_get_l2_up(stack);
- }
-#endif
-
- misdn_lib_get_short_status(stack);
- misdn_lib_get_l1_up(stack);
- misdn_lib_get_l2_up(stack);
-
- }
-
- cb_log(8,0,"stack_init: port:%d lowerId:%x upperId:%x\n",stack->port,stack->lower_id, stack->upper_id);
-
- return stack;
-}
-
-
-static void stack_destroy(struct misdn_stack *stack)
-{
- char buf[1024];
- if (!stack) return;
-
- if (stack->nt) {
- cleanup_Isdnl2(&stack->nst);
- cleanup_Isdnl3(&stack->nst);
- }
-
- if (stack->lower_id)
- mISDN_write_frame(stack->midev, buf, stack->lower_id, MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
-
- if (stack->upper_id)
- mISDN_write_frame(stack->midev, buf, stack->upper_id, MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
-}
-
-
-static struct misdn_stack * find_stack_by_addr(int addr)
-{
- struct misdn_stack *stack;
-
- for (stack=glob_mgr->stack_list;
- stack;
- stack=stack->next) {
- if ( (stack->upper_id&STACK_ID_MASK) == (addr&STACK_ID_MASK)) return stack;
-
- }
-
- return NULL;
-}
-
-
-static struct misdn_stack * find_stack_by_port(int port)
-{
- struct misdn_stack *stack;
-
- for (stack=glob_mgr->stack_list;
- stack;
- stack=stack->next)
- if (stack->port == port) return stack;
-
- return NULL;
-}
-
-static struct misdn_stack * find_stack_by_mgr(manager_t* mgr_nt)
-{
- struct misdn_stack *stack;
-
- for (stack=glob_mgr->stack_list;
- stack;
- stack=stack->next)
- if ( &stack->mgr == mgr_nt) return stack;
-
- return NULL;
-}
-
-static struct misdn_bchannel *find_bc_by_masked_l3id(struct misdn_stack *stack, unsigned long l3id, unsigned long mask)
-{
- int i;
- for (i=0; i<=stack->b_num; i++) {
- if ( (stack->bc[i].l3_id & mask) == (l3id & mask)) return &stack->bc[i] ;
- }
- return stack_holder_find(stack,l3id);
-}
-
-
-struct misdn_bchannel *find_bc_by_l3id(struct misdn_stack *stack, unsigned long l3id)
-{
- int i;
- for (i=0; i<=stack->b_num; i++) {
- if (stack->bc[i].l3_id == l3id) return &stack->bc[i] ;
- }
- return stack_holder_find(stack,l3id);
-}
-
-static struct misdn_bchannel *find_bc_holded(struct misdn_stack *stack)
-{
- int i;
- for (i=0; i<=stack->b_num; i++) {
- if (stack->bc[i].holded ) return &stack->bc[i] ;
- }
- return NULL;
-}
-
-
-static struct misdn_bchannel *find_bc_by_addr(unsigned long addr)
-{
- struct misdn_stack* stack;
- int i;
-
- for (stack=glob_mgr->stack_list;
- stack;
- stack=stack->next) {
- for (i=0; i<=stack->b_num; i++) {
- if ( (stack->bc[i].addr&STACK_ID_MASK)==(addr&STACK_ID_MASK) || stack->bc[i].layer_id== addr ) {
- return &stack->bc[i];
- }
- }
- }
-
- return NULL;
-}
-
-struct misdn_bchannel *find_bc_by_confid(unsigned long confid)
-{
- struct misdn_stack* stack;
- int i;
-
- for (stack=glob_mgr->stack_list;
- stack;
- stack=stack->next) {
- for (i=0; i<=stack->b_num; i++) {
- if ( stack->bc[i].conf_id==confid ) {
- return &stack->bc[i];
- }
- }
- }
- return NULL;
-}
-
-
-static struct misdn_bchannel *find_bc_by_channel(int port, int channel)
-{
- struct misdn_stack* stack=find_stack_by_port(port);
- int i;
-
- if (!stack) return NULL;
-
- for (i=0; i<=stack->b_num; i++) {
- if ( stack->bc[i].channel== channel ) {
- return &stack->bc[i];
- }
- }
-
- return NULL;
-}
-
-
-
-
-
-static int handle_event ( struct misdn_bchannel *bc, enum event_e event, iframe_t *frm)
-{
- struct misdn_stack *stack=get_stack_by_bc(bc);
-
- if (!stack->nt) {
-
- switch (event) {
-
- case EVENT_CONNECT_ACKNOWLEDGE:
- setup_bc(bc);
-
- if ( *bc->crypt_key ) {
- cb_log(4, stack->port, "ENABLING BLOWFISH channel:%d oad%d:%s dad%d:%s\n", bc->channel, bc->onumplan,bc->oad, bc->dnumplan,bc->dad);
- manager_ph_control_block(bc, BF_ENABLE_KEY, bc->crypt_key, strlen(bc->crypt_key) );
- }
-
- if (misdn_cap_is_speech(bc->capability)) {
- if ( !bc->nodsp) manager_ph_control(bc, DTMF_TONE_START, 0);
- manager_ec_enable(bc);
-
- if ( bc->txgain != 0 ) {
- cb_log(4, stack->port, "--> Changing txgain to %d\n", bc->txgain);
- manager_ph_control(bc, VOL_CHANGE_TX, bc->txgain);
- }
- if ( bc->rxgain != 0 ) {
- cb_log(4, stack->port, "--> Changing rxgain to %d\n", bc->rxgain);
- manager_ph_control(bc, VOL_CHANGE_RX, bc->rxgain);
- }
- }
-
- break;
- case EVENT_CONNECT:
-
- if ( *bc->crypt_key ) {
- cb_log(4, stack->port, "ENABLING BLOWFISH channel:%d oad%d:%s dad%d:%s\n", bc->channel, bc->onumplan,bc->oad, bc->dnumplan,bc->dad);
- manager_ph_control_block(bc, BF_ENABLE_KEY, bc->crypt_key, strlen(bc->crypt_key) );
- }
- case EVENT_ALERTING:
- case EVENT_PROGRESS:
- case EVENT_PROCEEDING:
- case EVENT_SETUP_ACKNOWLEDGE:
- case EVENT_SETUP:
- {
- if (bc->channel == 0xff || bc->channel<=0)
- bc->channel=0;
-
- if (find_free_chan_in_stack(stack, bc, bc->channel, 0)<0){
- if (!stack->pri && !stack->ptp) {
- bc->cw=1;
- break;
- }
-
- if (!bc->channel)
- cb_log(0, stack->port, "Any Channel Requested, but we have no more!!\n");
- else
- cb_log(0, stack->port, "Requested Channel Already in Use releasing this call with cause 34!!!!\n");
-
- /* when the channel is already in use, we can't
- * simply clear it, we need to make sure that
- * it will still be marked as in_use in the
- * available channels list.*/
- bc->channel=0;
-
- misdn_lib_send_event(bc,EVENT_RELEASE_COMPLETE);
- return -1;
- }
- }
-
- setup_bc(bc);
- break;
-
- case EVENT_RELEASE_COMPLETE:
- case EVENT_RELEASE:
- break;
- default:
- break;
- }
- } else { /** NT MODE **/
-
- }
- return 0;
-}
-
-static int handle_cr ( struct misdn_stack *stack, iframe_t *frm)
-{
- struct misdn_bchannel *bc;
-
- if (!stack) return -1;
-
- switch (frm->prim) {
- case CC_NEW_CR|INDICATION:
- cb_log(7, stack->port, " --> lib: NEW_CR Ind with l3id:%x on this port.\n",frm->dinfo);
-
- bc = misdn_lib_get_free_bc(stack->port, 0, 1, 0);
- if (!bc) {
- cb_log(0, stack->port, " --> !! lib: No free channel!\n");
- return -1;
- }
-
- cb_log(7, stack->port, " --> new_process: New L3Id: %x\n",frm->dinfo);
- bc->l3_id=frm->dinfo;
- return 1;
- case CC_NEW_CR|CONFIRM:
- return 1;
- case CC_NEW_CR|REQUEST:
- return 1;
- case CC_RELEASE_CR|REQUEST:
- return 1;
- case CC_RELEASE_CR|CONFIRM:
- break;
- case CC_RELEASE_CR|INDICATION:
- cb_log(4, stack->port, " --> lib: RELEASE_CR Ind with l3id:%x\n",frm->dinfo);
- {
- struct misdn_bchannel *bc=find_bc_by_l3id(stack, frm->dinfo);
- struct misdn_bchannel dummybc;
-
- if (!bc) {
- cb_log(4, stack->port, " --> Didn't find BC so temporarily creating dummy BC (l3id:%x) on this port.\n", frm->dinfo);
- misdn_make_dummy(&dummybc, stack->port, frm->dinfo, stack->nt, 0);
-
- bc=&dummybc;
- }
-
- if (bc) {
- int channel = bc->channel;
- cb_log(4, stack->port, " --> lib: CLEANING UP l3id: %x\n",frm->dinfo);
-
- /*bc->pid = 0;*/
- bc->need_disconnect=0;
- bc->need_release=0;
- bc->need_release_complete=0;
-
- cb_event(EVENT_CLEANUP, bc, glob_mgr->user_data);
-
- empty_bc(bc);
- clean_up_bc(bc);
-
- if (channel>0)
- empty_chan_in_stack(stack,channel);
- bc->in_use=0;
-
- dump_chan_list(stack);
-
- if (bc->stack_holder) {
- cb_log(4,stack->port, "REMOVING Holder\n");
- stack_holder_remove( stack, bc);
- free(bc);
- }
- }
- else {
- if (stack->nt)
- cb_log(4, stack->port, "BC with dinfo: %x not found.. (prim was %x and addr %x)\n",frm->dinfo, frm->prim, frm->addr);
- }
-
- return 1;
- }
- break;
- }
-
- return 0;
-}
-
-
-/* Empties bc if it's reserved (no SETUP out yet) */
-void misdn_lib_release(struct misdn_bchannel *bc)
-{
- struct misdn_stack *stack=get_stack_by_bc(bc);
-
- if (!stack) {
- cb_log(1,0,"misdn_release: No Stack found\n");
- return;
- }
-
- if (bc->channel>0)
- empty_chan_in_stack(stack,bc->channel);
-
- empty_bc(bc);
- clean_up_bc(bc);
- bc->in_use=0;
-}
-
-
-
-
-int misdn_lib_get_port_up (int port)
-{ /* Pull Up L1 */
- struct misdn_stack *stack;
-
- for (stack=glob_mgr->stack_list;
- stack;
- stack=stack->next) {
-
- if (stack->port == port) {
-
- if (!stack->l1link)
- misdn_lib_get_l1_up(stack);
- if (!stack->l2link)
- misdn_lib_get_l2_up(stack);
-
- return 0;
- }
- }
- return 0;
-}
-
-
-int misdn_lib_get_port_down (int port)
-{ /* Pull Down L1 */
- struct misdn_stack *stack;
- for (stack=glob_mgr->stack_list;
- stack;
- stack=stack->next) {
- if (stack->port == port) {
- if (stack->l2link)
- misdn_lib_get_l2_down(stack);
- misdn_lib_get_l1_down(stack);
- return 0;
- }
- }
- return 0;
-}
-
-int misdn_lib_port_up(int port, int check)
-{
- struct misdn_stack *stack;
-
-
- for (stack=glob_mgr->stack_list;
- stack;
- stack=stack->next) {
-
- if (stack->port == port) {
-
- if (stack->blocked) {
- cb_log(0,port, "Port Blocked:%d L2:%d L1:%d\n", stack->blocked, stack->l2link, stack->l1link);
- return -1;
- }
-
- if (stack->ptp ) {
-
- if (stack->l1link && stack->l2link) {
- return 1;
- } else {
- cb_log(1,port, "Port Down L2:%d L1:%d\n",
- stack->l2link, stack->l1link);
- return 0;
- }
- } else {
- if ( !check || stack->l1link )
- return 1;
- else {
- cb_log(1,port, "Port down PMP\n");
- return 0;
- }
- }
- }
- }
-
- return -1;
-}
-
-
-int release_cr(struct misdn_stack *stack, mISDNuser_head_t *hh)
-{
- struct misdn_bchannel *bc=find_bc_by_l3id(stack, hh->dinfo);
- struct misdn_bchannel dummybc;
- iframe_t frm; /* fake te frm to remove callref from global callreflist */
- frm.dinfo = hh->dinfo;
-
- frm.addr=stack->upper_id | FLG_MSG_DOWN;
-
- frm.prim = CC_RELEASE_CR|INDICATION;
- cb_log(4, stack->port, " --> CC_RELEASE_CR: Faking Release_cr for %x l3id:%x\n",frm.addr, frm.dinfo);
- /** removing procid **/
- if (!bc) {
- cb_log(4, stack->port, " --> Didn't find BC so temporarily creating dummy BC (l3id:%x) on this port.\n", hh->dinfo);
- misdn_make_dummy(&dummybc, stack->port, hh->dinfo, stack->nt, 0);
- bc=&dummybc;
- }
-
- if (bc) {
- if ( (bc->l3_id & 0xff00) == 0xff00) {
- cb_log(4, stack->port, " --> Removing Process Id:%x on this port.\n", bc->l3_id&0xff);
- stack->procids[bc->l3_id&0xff] = 0 ;
- }
- }
- else cb_log(0, stack->port, "Couldn't find BC so I couldn't remove the Process!!!! this is a bad port.\n");
-
- if (handle_cr(stack, &frm)<0) {
- }
-
- return 0 ;
-}
-
-int
-handle_event_nt(void *dat, void *arg)
-{
- manager_t *mgr = (manager_t *)dat;
- msg_t *msg = (msg_t *)arg;
- mISDNuser_head_t *hh;
- int reject=0;
-
- struct misdn_stack *stack=find_stack_by_mgr(mgr);
- int port;
-
- if (!msg || !mgr)
- return(-EINVAL);
-
- hh=(mISDNuser_head_t*)msg->data;
- port=stack->port;
-
- cb_log(5, stack->port, " --> lib: prim %x dinfo %x\n",hh->prim, hh->dinfo);
- {
- switch(hh->prim){
- case CC_RETRIEVE|INDICATION:
- {
- struct misdn_bchannel *bc;
- struct misdn_bchannel *hold_bc;
-
- iframe_t frm; /* fake te frm to add callref to global callreflist */
- frm.dinfo = hh->dinfo;
-
- frm.addr=stack->upper_id | FLG_MSG_DOWN;
-
- frm.prim = CC_NEW_CR|INDICATION;
-
- if (handle_cr( stack, &frm)< 0) {
- msg_t *dmsg;
- cb_log(4, stack->port, "Patch from MEIDANIS:Sending RELEASE_COMPLETE %x (No free Chan for you..)\n", hh->dinfo);
- dmsg = create_l3msg(CC_RELEASE_COMPLETE | REQUEST,MT_RELEASE_COMPLETE, hh->dinfo,sizeof(RELEASE_COMPLETE_t), 1);
- stack->nst.manager_l3(&stack->nst, dmsg);
- free_msg(msg);
- return 0;
- }
-
- bc = find_bc_by_l3id(stack, hh->dinfo);
- hold_bc = stack_holder_find(stack, bc->l3_id);
- cb_log(4, stack->port, "bc_l3id:%x holded_bc_l3id:%x\n",bc->l3_id, hold_bc->l3_id);
-
- if (hold_bc) {
- cb_log(4, stack->port, "REMOVING Holder\n");
-
- /*swap the backup to our new channel back*/
- stack_holder_remove(stack, hold_bc);
- memcpy(bc, hold_bc, sizeof(struct misdn_bchannel));
- free(hold_bc);
-
- bc->holded=0;
- bc->b_stid=0;
- }
-
- }
-
- break;
-
- case CC_SETUP|CONFIRM:
- {
- struct misdn_bchannel *bc=find_bc_by_l3id(stack, hh->dinfo);
- int l3id = *((int *)(((u_char *)msg->data)+ mISDNUSER_HEAD_SIZE));
- cb_log(4, stack->port, " --> lib: Event_ind:SETUP CONFIRM [NT] : new L3ID is %x\n",l3id );
-
- if (!bc) { cb_log(4, stack->port, "Bc Not found (after SETUP CONFIRM)\n"); return 0; }
- cb_log (2,bc->port,"I IND :CC_SETUP|CONFIRM: old l3id:%x new l3id:%x\n", bc->l3_id, l3id);
- bc->l3_id=l3id;
- cb_event(EVENT_NEW_L3ID, bc, glob_mgr->user_data);
- }
- free_msg(msg);
- return 0;
-
- case CC_SETUP|INDICATION:
- {
- struct misdn_bchannel* bc=misdn_lib_get_free_bc(stack->port, 0, 1, 0);
- if (!bc)
- ERR_NO_CHANNEL:
- {
- msg_t *dmsg;
- cb_log(4, stack->port, "Patch from MEIDANIS:Sending RELEASE_COMPLETE %x (No free Chan for you..)\n", hh->dinfo);
- dmsg = create_l3msg(CC_RELEASE_COMPLETE | REQUEST,MT_RELEASE_COMPLETE, hh->dinfo,sizeof(RELEASE_COMPLETE_t), 1);
- stack->nst.manager_l3(&stack->nst, dmsg);
- free_msg(msg);
- return 0;
- }
-
- cb_log(4, stack->port, " --> new_process: New L3Id: %x\n",hh->dinfo);
- bc->l3_id=hh->dinfo;
- }
- break;
-
- case CC_CONNECT_ACKNOWLEDGE|INDICATION:
- break;
-
- case CC_ALERTING|INDICATION:
- case CC_PROCEEDING|INDICATION:
- case CC_SETUP_ACKNOWLEDGE|INDICATION:
- if(!stack->ptp) break;
- case CC_CONNECT|INDICATION:
- break;
- case CC_DISCONNECT|INDICATION:
- {
- struct misdn_bchannel *bc=find_bc_by_l3id(stack, hh->dinfo);
- if (!bc) {
- bc=find_bc_by_masked_l3id(stack, hh->dinfo, 0xffff0000);
- if (bc) {
- int myprocid=bc->l3_id&0x0000ffff;
- hh->dinfo=(hh->dinfo&0xffff0000)|myprocid;
- cb_log(3,stack->port,"Reject dinfo: %x cause:%d\n",hh->dinfo,bc->cause);
- reject=1;
- }
- }
- }
- break;
-
- case CC_FACILITY|INDICATION:
- {
- struct misdn_bchannel *bc=find_bc_by_l3id(stack, hh->dinfo);
- if (!bc) {
- bc=find_bc_by_masked_l3id(stack, hh->dinfo, 0xffff0000);
- if (bc) {
- int myprocid=bc->l3_id&0x0000ffff;
- hh->dinfo=(hh->dinfo&0xffff0000)|myprocid;
- cb_log(4,bc->port,"Repaired reject Bug, new dinfo: %x\n",hh->dinfo);
- }
- }
- }
- break;
-
- case CC_RELEASE_COMPLETE|INDICATION:
- break;
-
- case CC_SUSPEND|INDICATION:
- {
- msg_t *dmsg;
- cb_log(4, stack->port, " --> Got Suspend, sending Reject for now\n");
- dmsg = create_l3msg(CC_SUSPEND_REJECT | REQUEST,MT_SUSPEND_REJECT, hh->dinfo,sizeof(RELEASE_COMPLETE_t), 1);
- stack->nst.manager_l3(&stack->nst, dmsg);
- free_msg(msg);
- return 0;
- }
- break;
- case CC_RESUME|INDICATION:
- break;
-
- case CC_RELEASE|CONFIRM:
- {
- struct misdn_bchannel *bc=find_bc_by_l3id(stack, hh->dinfo);
-
- if (bc) {
- cb_log(1, stack->port, "CC_RELEASE|CONFIRM (l3id:%x), sending RELEASE_COMPLETE\n", hh->dinfo);
- misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE);
- }
- }
- break;
-
- case CC_RELEASE|INDICATION:
- break;
-
- case CC_RELEASE_CR|INDICATION:
- release_cr(stack, hh);
- free_msg(msg);
- return 0 ;
- break;
-
- case CC_NEW_CR|INDICATION:
- /* Got New CR for bchan, for now I handle this one in */
- /* connect_ack, Need to be changed */
- {
- struct misdn_bchannel *bc=find_bc_by_l3id(stack, hh->dinfo);
- int l3id = *((int *)(((u_char *)msg->data)+ mISDNUSER_HEAD_SIZE));
- if (!bc) { cb_log(0, stack->port, " --> In NEW_CR: didn't found bc ??\n"); return -1;};
- if (((l3id&0xff00)!=0xff00) && ((bc->l3_id&0xff00)==0xff00)) {
- cb_log(4, stack->port, " --> Removing Process Id:%x on this port.\n", 0xff&bc->l3_id);
- stack->procids[bc->l3_id&0xff] = 0 ;
- }
- cb_log(4, stack->port, "lib: Event_ind:CC_NEW_CR : very new L3ID is %x\n",l3id );
-
- bc->l3_id =l3id;
- cb_event(EVENT_NEW_L3ID, bc, glob_mgr->user_data);
-
- free_msg(msg);
- return 0;
- }
-
- case DL_ESTABLISH | INDICATION:
- case DL_ESTABLISH | CONFIRM:
- {
- cb_log(3, stack->port, "%% GOT L2 Activate Info.\n");
-
- if (stack->ptp && stack->l2link) {
- cb_log(0, stack->port, "%% GOT L2 Activate Info. but we're activated already.. this l2 is faulty, blocking port\n");
- cb_event(EVENT_PORT_ALARM, &stack->bc[0], glob_mgr->user_data);
- }
-
- if (stack->ptp && !stack->restart_sent) {
- /* make sure we restart the interface of the
- * other side */
- stack->restart_sent=1;
- misdn_lib_send_restart(stack->port, -1);
-
- }
-
- /* when we get the L2 UP, the L1 is UP definitely too*/
- stack->l1link = 1;
- stack->l2link = 1;
- stack->l2upcnt=0;
-
- free_msg(msg);
- return 0;
- }
- break;
-
-
- case DL_RELEASE | INDICATION:
- case DL_RELEASE | CONFIRM:
- {
- if (stack->ptp) {
- cb_log(3 , stack->port, "%% GOT L2 DeActivate Info.\n");
-
- if (stack->l2upcnt>3) {
- cb_log(0 , stack->port, "!!! Could not Get the L2 up after 3 Attempts!!!\n");
- } else {
-#if 0
- if (stack->nt) misdn_lib_reinit_nt_stack(stack->port);
-#endif
- if (stack->l1link) {
- misdn_lib_get_l2_up(stack);
- stack->l2upcnt++;
- }
- }
-
- } else
- cb_log(3, stack->port, "%% GOT L2 DeActivate Info.\n");
-
- stack->l2link = 0;
- free_msg(msg);
- return 0;
- }
- break;
- }
- }
-
- {
- /* Parse Events and fire_up to App. */
- struct misdn_bchannel *bc;
- struct misdn_bchannel dummybc;
-
- enum event_e event = isdn_msg_get_event(msgs_g, msg, 1);
-
- bc=find_bc_by_l3id(stack, hh->dinfo);
-
- if (!bc) {
- cb_log(4, stack->port, " --> Didn't find BC so temporarily creating dummy BC (l3id:%x).\n", hh->dinfo);
- misdn_make_dummy(&dummybc, stack->port, hh->dinfo, stack->nt, 0);
- bc=&dummybc;
- }
- if (bc ) {
- isdn_msg_parse_event(msgs_g,msg,bc, 1);
-
- switch (event) {
- case EVENT_SETUP:
- if (bc->channel<=0 || bc->channel==0xff)
- bc->channel=0;
-
- if (find_free_chan_in_stack(stack,bc, bc->channel,0)<0)
- goto ERR_NO_CHANNEL;
- break;
- case EVENT_RELEASE:
- case EVENT_RELEASE_COMPLETE:
- {
- int channel=bc->channel;
- int tmpcause=bc->cause;
- empty_bc(bc);
- bc->cause=tmpcause;
- clean_up_bc(bc);
-
- if (channel>0)
- empty_chan_in_stack(stack,channel);
- bc->in_use=0;
- }
- break;
-
- default:
- break;
- }
-
- if(!isdn_get_info(msgs_g,event,1)) {
- cb_log(4, stack->port, "Unknown Event Ind: prim %x dinfo %x\n",hh->prim, hh->dinfo);
- } else {
- if (reject) {
- switch(bc->cause){
- case AST_CAUSE_USER_BUSY:
- cb_log(1, stack->port, "Siemens Busy reject..\n");
-
- break;
- default:
- break;
- }
- }
- cb_event(event, bc, glob_mgr->user_data);
- }
- } else {
- cb_log(4, stack->port, "No BC found with l3id: prim %x dinfo %x\n",hh->prim, hh->dinfo);
- }
-
- free_msg(msg);
- }
-
-
- return 0;
-}
-
-
-static int handle_timers(msg_t* msg)
-{
- iframe_t *frm= (iframe_t*)msg->data;
- struct misdn_stack *stack;
-
- /* Timer Stuff */
- switch (frm->prim) {
- case MGR_INITTIMER | CONFIRM:
- case MGR_ADDTIMER | CONFIRM:
- case MGR_DELTIMER | CONFIRM:
- case MGR_REMOVETIMER | CONFIRM:
- free_msg(msg);
- return(1);
- }
-
-
-
- if (frm->prim==(MGR_TIMER | INDICATION) ) {
- for (stack = glob_mgr->stack_list;
- stack;
- stack = stack->next) {
- itimer_t *it;
-
- if (!stack->nt) continue;
-
- it = stack->nst.tlist;
- /* find timer */
- for(it=stack->nst.tlist;
- it;
- it=it->next) {
- if (it->id == (int)frm->addr)
- break;
- }
- if (it) {
- int ret;
- ret = mISDN_write_frame(stack->midev, msg->data, frm->addr,
- MGR_TIMER | RESPONSE, 0, 0, NULL, TIMEOUT_1SEC);
- test_and_clear_bit(FLG_TIMER_RUNING, (long unsigned int *)&it->Flags);
- ret = it->function(it->data);
- free_msg(msg);
- return 1;
- }
- }
-
- cb_log(0, 0, "Timer Msg without Timer ??\n");
- free_msg(msg);
- return 1;
- }
-
- return 0;
-}
-
-
-
-void misdn_lib_tone_generator_start(struct misdn_bchannel *bc)
-{
- bc->generate_tone=1;
-}
-
-void misdn_lib_tone_generator_stop(struct misdn_bchannel *bc)
-{
- bc->generate_tone=0;
-}
-
-
-static int do_tone(struct misdn_bchannel *bc, int len)
-{
- bc->tone_cnt=len;
-
- if (bc->generate_tone) {
- cb_event(EVENT_TONE_GENERATE, bc, glob_mgr->user_data);
-
- if ( !bc->nojitter ) {
- misdn_tx_jitter(bc,len);
- }
-
- return 1;
- }
-
- return 0;
-}
-
-
-#ifdef MISDN_SAVE_DATA
-static void misdn_save_data(int id, char *p1, int l1, char *p2, int l2)
-{
- char n1[32],n2[32];
- FILE *rx, *tx;
-
- sprintf(n1,"/tmp/misdn-rx-%d.raw",id);
- sprintf(n2,"/tmp/misdn-tx-%d.raw",id);
-
- rx = fopen(n1,"a+");
- tx = fopen(n2,"a+");
-
- if (!rx || !tx) {
- cb_log(0,0,"Couldn't open files: %s\n",strerror(errno));
- return ;
- }
-
- fwrite(p1,1,l1,rx);
- fwrite(p2,1,l2,tx);
-
- fclose(rx);
- fclose(tx);
-
-}
-#endif
-
-void misdn_tx_jitter(struct misdn_bchannel *bc, int len)
-{
- char buf[4096 + mISDN_HEADER_LEN];
- char *data=&buf[mISDN_HEADER_LEN];
- iframe_t *txfrm= (iframe_t*)buf;
- int jlen, r;
-
- jlen=cb_jb_empty(bc,data,len);
-
- if (jlen) {
-#ifdef MISDN_SAVE_DATA
- misdn_save_data((bc->port*100+bc->channel), data, jlen, bc->bframe, bc->bframe_len);
-#endif
- flip_buf_bits( data, jlen);
-
- if (jlen < len) {
- cb_log(7,bc->port,"Jitterbuffer Underrun.\n");
- }
-
- txfrm->prim = DL_DATA|REQUEST;
-
- txfrm->dinfo = 0;
-
- txfrm->addr = bc->addr|FLG_MSG_DOWN; /* | IF_DOWN; */
-
- txfrm->len =jlen;
- cb_log(9, bc->port, "Transmitting %d samples 2 misdn\n", txfrm->len);
-
- r=mISDN_write( glob_mgr->midev, buf, txfrm->len + mISDN_HEADER_LEN, 8000 );
- } else {
-#define MISDN_GEN_SILENCE
-#ifdef MISDN_GEN_SILENCE
- int cnt=len/TONE_SILENCE_SIZE;
- int rest=len%TONE_SILENCE_SIZE;
- int i;
-
- for (i=0; i<cnt; i++) {
- memcpy(data, tone_silence_flip, TONE_SILENCE_SIZE );
- data +=TONE_SILENCE_SIZE;
- }
-
- if (rest) {
- memcpy(data, tone_silence_flip, rest);
- }
-
- txfrm->prim = DL_DATA|REQUEST;
-
- txfrm->dinfo = 0;
-
- txfrm->addr = bc->addr|FLG_MSG_DOWN; /* | IF_DOWN; */
-
- txfrm->len =len;
- cb_log(9, bc->port, "Transmitting %d samples 2 misdn\n", txfrm->len);
-
- r=mISDN_write( glob_mgr->midev, buf, txfrm->len + mISDN_HEADER_LEN, 8000 );
-#endif
-
- }
-}
-
-static int handle_bchan(msg_t *msg)
-{
- iframe_t *frm= (iframe_t*)msg->data;
- struct misdn_bchannel *bc=find_bc_by_addr(frm->addr);
- struct misdn_stack *stack;
-
- if (!bc) {
- cb_log(1,0,"handle_bchan: BC not found for prim:%x with addr:%x dinfo:%x\n", frm->prim, frm->addr, frm->dinfo);
- return 0 ;
- }
-
- stack = get_stack_by_bc(bc);
-
- if (!stack) {
- cb_log(0, bc->port,"handle_bchan: STACK not found for prim:%x with addr:%x dinfo:%x\n", frm->prim, frm->addr, frm->dinfo);
- return 0;
- }
-
- switch (frm->prim) {
-
- case MGR_SETSTACK| CONFIRM:
- cb_log(3, stack->port, "BCHAN: MGR_SETSTACK|CONFIRM pid:%d\n",bc->pid);
- break;
-
- case MGR_SETSTACK| INDICATION:
- cb_log(3, stack->port, "BCHAN: MGR_SETSTACK|IND pid:%d\n",bc->pid);
- break;
-#if 0
- AGAIN:
- bc->addr = mISDN_get_layerid(stack->midev, bc->b_stid, bc->layer);
- if (!bc->addr) {
-
- if (errno == EAGAIN) {
- usleep(1000);
- goto AGAIN;
- }
-
- cb_log(0,stack->port,"$$$ Get Layer (%d) Id Error: %s\n",bc->layer,strerror(errno));
-
- /* we kill the channel later, when we received some
- data. */
- bc->addr= frm->addr;
- } else if ( bc->addr < 0) {
- cb_log(0, stack->port,"$$$ bc->addr <0 Error:%s\n",strerror(errno));
- bc->addr=0;
- }
-
- cb_log(4, stack->port," --> Got Adr %x\n", bc->addr);
-
- free_msg(msg);
-
-
- switch(bc->bc_state) {
- case BCHAN_SETUP:
- bc_state_change(bc,BCHAN_SETUPED);
- break;
-
- case BCHAN_CLEAN_REQUEST:
- default:
- cb_log(0, stack->port," --> STATE WASN'T SETUP (but %s) in SETSTACK|IND pid:%d\n",bc_state2str(bc->bc_state), bc->pid);
- clean_up_bc(bc);
- }
- return 1;
-#endif
-
- case MGR_DELLAYER| INDICATION:
- cb_log(3, stack->port, "BCHAN: MGR_DELLAYER|IND pid:%d\n",bc->pid);
- break;
-
- case MGR_DELLAYER| CONFIRM:
- cb_log(3, stack->port, "BCHAN: MGR_DELLAYER|CNF pid:%d\n",bc->pid);
-
- bc->pid=0;
- bc->addr=0;
-
- free_msg(msg);
- return 1;
-
- case PH_ACTIVATE | INDICATION:
- case DL_ESTABLISH | INDICATION:
- cb_log(3, stack->port, "BCHAN: ACT Ind pid:%d\n", bc->pid);
-
- free_msg(msg);
- return 1;
-
- case PH_ACTIVATE | CONFIRM:
- case DL_ESTABLISH | CONFIRM:
-
- cb_log(3, stack->port, "BCHAN: bchan ACT Confirm pid:%d\n",bc->pid);
- free_msg(msg);
-
- return 1;
-
- case DL_ESTABLISH | REQUEST:
- {
- char buf[128];
- mISDN_write_frame(stack->midev, buf, bc->addr | FLG_MSG_TARGET | FLG_MSG_DOWN, DL_ESTABLISH | CONFIRM, 0,0, NULL, TIMEOUT_1SEC);
- }
- free_msg(msg);
- return 1;
-
- case DL_RELEASE|REQUEST:
- {
- char buf[128];
- mISDN_write_frame(stack->midev, buf, bc->addr | FLG_MSG_TARGET | FLG_MSG_DOWN, DL_RELEASE| CONFIRM, 0,0, NULL, TIMEOUT_1SEC);
- }
- free_msg(msg);
- return 1;
-
- case PH_DEACTIVATE | INDICATION:
- case DL_RELEASE | INDICATION:
- cb_log (3, stack->port, "BCHAN: DeACT Ind pid:%d\n",bc->pid);
-
- free_msg(msg);
- return 1;
-
- case PH_DEACTIVATE | CONFIRM:
- case DL_RELEASE | CONFIRM:
- cb_log(3, stack->port, "BCHAN: DeACT Conf pid:%d\n",bc->pid);
-
- free_msg(msg);
- return 1;
-
- case PH_CONTROL|INDICATION:
- {
- unsigned int *cont = (unsigned int *) &frm->data.p;
-
- cb_log(4, stack->port, "PH_CONTROL: channel:%d oad%d:%s dad%d:%s \n", bc->channel, bc->onumplan,bc->oad, bc->dnumplan,bc->dad);
-
- if ((*cont & ~DTMF_TONE_MASK) == DTMF_TONE_VAL) {
- int dtmf = *cont & DTMF_TONE_MASK;
- cb_log(4, stack->port, " --> DTMF TONE: %c\n",dtmf);
- bc->dtmf=dtmf;
- cb_event(EVENT_DTMF_TONE, bc, glob_mgr->user_data);
-
- free_msg(msg);
- return 1;
- }
- if (*cont == BF_REJECT) {
- cb_log(4, stack->port, " --> BF REJECT\n");
- free_msg(msg);
- return 1;
- }
- if (*cont == BF_ACCEPT) {
- cb_log(4, stack->port, " --> BF ACCEPT\n");
- free_msg(msg);
- return 1;
- }
- }
- break;
-
- case PH_DATA|REQUEST:
- case DL_DATA|REQUEST:
- cb_log(0, stack->port, "DL_DATA REQUEST \n");
- do_tone(bc, 64);
-
- free_msg(msg);
- return 1;
-
-
- case PH_DATA|INDICATION:
- case DL_DATA|INDICATION:
- {
- bc->bframe = (void*)&frm->data.i;
- bc->bframe_len = frm->len;
-
- /** Anyway flip the bufbits **/
- if ( misdn_cap_is_speech(bc->capability) )
- flip_buf_bits(bc->bframe, bc->bframe_len);
-
-
- if (!bc->bframe_len) {
- cb_log(2, stack->port, "DL_DATA INDICATION bc->addr:%x frm->addr:%x\n", bc->addr, frm->addr);
- free_msg(msg);
- return 1;
- }
-
- if ( (bc->addr&STACK_ID_MASK) != (frm->addr&STACK_ID_MASK) ) {
- cb_log(2, stack->port, "DL_DATA INDICATION bc->addr:%x frm->addr:%x\n", bc->addr, frm->addr);
- free_msg(msg);
- return 1;
- }
-
-#if MISDN_DEBUG
- cb_log(0, stack->port, "DL_DATA INDICATION Len %d\n", frm->len);
-
-#endif
-
- if ( (bc->bc_state == BCHAN_ACTIVATED) && frm->len > 0) {
- int t;
-
-#ifdef MISDN_B_DEBUG
- cb_log(0,bc->port,"do_tone START\n");
-#endif
- t=do_tone(bc,frm->len);
-
-#ifdef MISDN_B_DEBUG
- cb_log(0,bc->port,"do_tone STOP (%d)\n",t);
-#endif
- if ( !t ) {
- int i;
-
- if ( misdn_cap_is_speech(bc->capability)) {
- if ( !bc->nojitter ) {
-#ifdef MISDN_B_DEBUG
- cb_log(0,bc->port,"tx_jitter START\n");
-#endif
- misdn_tx_jitter(bc,frm->len);
-#ifdef MISDN_B_DEBUG
- cb_log(0,bc->port,"tx_jitter STOP\n");
-#endif
- }
- }
-
-#ifdef MISDN_B_DEBUG
- cb_log(0,bc->port,"EVENT_B_DATA START\n");
-#endif
-
- i = cb_event(EVENT_BCHAN_DATA, bc, glob_mgr->user_data);
-#ifdef MISDN_B_DEBUG
- cb_log(0,bc->port,"EVENT_B_DATA STOP\n");
-#endif
-
- if (i<0) {
- cb_log(10,stack->port,"cb_event returned <0\n");
- /*clean_up_bc(bc);*/
- }
- }
- }
- free_msg(msg);
- return 1;
- }
-
-
- case PH_CONTROL | CONFIRM:
- cb_log(4, stack->port, "PH_CONTROL|CNF bc->addr:%x\n", frm->addr);
- free_msg(msg);
- return 1;
-
- case PH_DATA | CONFIRM:
- case DL_DATA|CONFIRM:
-#if MISDN_DEBUG
-
- cb_log(0, stack->port, "Data confirmed\n");
-
-#endif
- free_msg(msg);
- return 1;
- case DL_DATA|RESPONSE:
-#if MISDN_DEBUG
- cb_log(0, stack->port, "Data response\n");
-
-#endif
- break;
- }
-
- return 0;
-}
-
-
-
-static int handle_frm_nt(msg_t *msg)
-{
- iframe_t *frm= (iframe_t*)msg->data;
- struct misdn_stack *stack;
- int err=0;
-
- stack=find_stack_by_addr( frm->addr );
-
-
-
- if (!stack || !stack->nt) {
- return 0;
- }
-
-
- if ((err=stack->nst.l1_l2(&stack->nst,msg))) {
-
- if (nt_err_cnt > 0 ) {
- if (nt_err_cnt < 100) {
- nt_err_cnt++;
- cb_log(0, stack->port, "NT Stack sends us error: %d \n", err);
- } else if (nt_err_cnt < 105){
- cb_log(0, stack->port, "NT Stack sends us error: %d over 100 times, so I'll stop this message\n", err);
- nt_err_cnt = - 1;
- }
- }
- free_msg(msg);
- return 1;
-
- }
-
- return 1;
-}
-
-
-static int handle_frm(msg_t *msg)
-{
- iframe_t *frm = (iframe_t*) msg->data;
-
- struct misdn_stack *stack=find_stack_by_addr(frm->addr);
-
- if (!stack || stack->nt) {
- return 0;
- }
-
- cb_log(4,stack?stack->port:0,"handle_frm: frm->addr:%x frm->prim:%x\n",frm->addr,frm->prim);
-
- {
- struct misdn_bchannel dummybc;
- struct misdn_bchannel *bc;
- int ret=handle_cr(stack, frm);
-
- if (ret<0) {
- cb_log(3,stack?stack->port:0,"handle_frm: handle_cr <0 prim:%x addr:%x\n", frm->prim, frm->addr);
-
-
- }
-
- if(ret) {
- free_msg(msg);
- return 1;
- }
-
- bc=find_bc_by_l3id(stack, frm->dinfo);
-
- if (!bc && (frm->prim==(CC_RESTART|CONFIRM)) ) {
- misdn_make_dummy(&dummybc, stack->port, MISDN_ID_GLOBAL, stack->nt, 0);
- bc=&dummybc;
- }
-
- if (!bc && (frm->prim==(CC_SETUP|INDICATION)) ) {
- misdn_make_dummy(&dummybc, stack->port, MISDN_ID_GLOBAL, stack->nt, 0);
- dummybc.port=stack->port;
- dummybc.l3_id=frm->dinfo;
- bc=&dummybc;
-
- misdn_lib_send_event(bc,EVENT_RELEASE_COMPLETE);
-
- free_msg(msg);
- return 1;
- }
-
-
-handle_frm_bc:
- if (bc ) {
- enum event_e event = isdn_msg_get_event(msgs_g, msg, 0);
- enum event_response_e response=RESPONSE_OK;
- int ret;
-
- isdn_msg_parse_event(msgs_g,msg,bc, 0);
-
- /** Preprocess some Events **/
- ret = handle_event(bc, event, frm);
- if (ret<0) {
- cb_log(0,stack->port,"couldn't handle event\n");
- free_msg(msg);
- return 1;
- }
- /* shoot up event to App: */
- cb_log(5, stack->port, "lib Got Prim: Addr %x prim %x dinfo %x\n",frm->addr, frm->prim, frm->dinfo);
-
- if(!isdn_get_info(msgs_g,event,0))
- cb_log(0, stack->port, "Unknown Event Ind: Addr:%x prim %x dinfo %x\n",frm->addr, frm->prim, frm->dinfo);
- else
- response=cb_event(event, bc, glob_mgr->user_data);
-#if 1
- if (event == EVENT_SETUP) {
- switch (response) {
- case RESPONSE_IGNORE_SETUP_WITHOUT_CLOSE:
-
- cb_log(0, stack->port, "TOTALLY IGNORING SETUP\n");
-
- break;
- case RESPONSE_IGNORE_SETUP:
- /* I think we should send CC_RELEASE_CR, but am not sure*/
- bc->out_cause = AST_CAUSE_NORMAL_CLEARING;
-
- case RESPONSE_RELEASE_SETUP:
- misdn_lib_send_event(bc,EVENT_RELEASE_COMPLETE);
- if (bc->channel>0)
- empty_chan_in_stack(stack, bc->channel);
- empty_bc(bc);
- bc_state_change(bc,BCHAN_CLEANED);
- bc->in_use=0;
-
- cb_log(0, stack->port, "GOT IGNORE SETUP\n");
- break;
- case RESPONSE_OK:
- cb_log(4, stack->port, "GOT SETUP OK\n");
-
-
- break;
- default:
- break;
- }
- }
-
- if (event == EVENT_RELEASE_COMPLETE) {
- /* release bchannel only after we've announced the RELEASE_COMPLETE */
- int channel=bc->channel;
- int tmpcause=bc->cause;
- int tmp_out_cause=bc->out_cause;
- empty_bc(bc);
- bc->cause=tmpcause;
- bc->out_cause=tmp_out_cause;
- clean_up_bc(bc);
-
- if (tmpcause == AST_CAUSE_REQUESTED_CHAN_UNAVAIL) {
- cb_log(0,stack->port,"**** Received CAUSE:%d, so not cleaning up channel %d\n", AST_CAUSE_REQUESTED_CHAN_UNAVAIL, channel);
- cb_log(0,stack->port,"**** This channel is now no longer available,\nplease try to restart it with 'misdn send restart <port> <channel>'\n");
- set_chan_in_stack(stack, channel);
- bc->channel=channel;
- misdn_lib_send_restart(stack->port, channel);
- } else {
- if (channel>0)
- empty_chan_in_stack(stack, channel);
- }
- bc->in_use=0;
- }
-
- if (event == EVENT_RESTART) {
- cb_log(0, stack->port, "**** Received RESTART_ACK channel:%d\n", bc->restart_channel);
- empty_chan_in_stack(stack, bc->restart_channel);
- }
-
- cb_log(5, stack->port, "Freeing Msg on prim:%x \n",frm->prim);
-
-
- free_msg(msg);
- return 1;
-#endif
-
- } else {
- struct misdn_bchannel dummybc;
- cb_log(0, stack->port, " --> Didn't find BC so temporarily creating dummy BC (l3id:%x) on this port.\n", frm->dinfo);
- memset (&dummybc,0,sizeof(dummybc));
- dummybc.port=stack->port;
- dummybc.l3_id=frm->dinfo;
- bc=&dummybc;
- goto handle_frm_bc;
- }
- }
-
- cb_log(4, stack->port, "TE_FRM_HANDLER: Returning 0 on prim:%x \n",frm->prim);
- return 0;
-}
-
-
-static int handle_l1(msg_t *msg)
-{
- iframe_t *frm = (iframe_t*) msg->data;
- struct misdn_stack *stack = find_stack_by_addr(frm->addr);
- int i ;
-
- if (!stack) return 0 ;
-
- switch (frm->prim) {
- case PH_ACTIVATE | CONFIRM:
- case PH_ACTIVATE | INDICATION:
- cb_log (3, stack->port, "L1: PH L1Link Up!\n");
- stack->l1link=1;
-
- if (stack->nt) {
-
- if (stack->nst.l1_l2(&stack->nst, msg))
- free_msg(msg);
-
- if (stack->ptp)
- misdn_lib_get_l2_up(stack);
- } else {
- free_msg(msg);
- }
-
- for (i=0;i<=stack->b_num; i++) {
- if (stack->bc[i].evq != EVENT_NOTHING) {
- cb_log(4, stack->port, "Firing Queued Event %s because L1 got up\n", isdn_get_info(msgs_g, stack->bc[i].evq, 0));
- misdn_lib_send_event(&stack->bc[i],stack->bc[i].evq);
- stack->bc[i].evq=EVENT_NOTHING;
- }
-
- }
- return 1;
-
- case PH_ACTIVATE | REQUEST:
- free_msg(msg);
- cb_log(3,stack->port,"L1: PH_ACTIVATE|REQUEST \n");
- return 1;
-
- case PH_DEACTIVATE | REQUEST:
- free_msg(msg);
- cb_log(3,stack->port,"L1: PH_DEACTIVATE|REQUEST \n");
- return 1;
-
- case PH_DEACTIVATE | CONFIRM:
- case PH_DEACTIVATE | INDICATION:
- cb_log (3, stack->port, "L1: PH L1Link Down! \n");
-
-#if 0
- for (i=0; i<=stack->b_num; i++) {
- if (global_state == MISDN_INITIALIZED) {
- cb_event(EVENT_CLEANUP, &stack->bc[i], glob_mgr->user_data);
- }
- }
-#endif
-
- if (stack->nt) {
- if (stack->nst.l1_l2(&stack->nst, msg))
- free_msg(msg);
- } else {
- free_msg(msg);
- }
-
- stack->l1link=0;
- stack->l2link=0;
- return 1;
- }
-
- return 0;
-}
-
-static int handle_l2(msg_t *msg)
-{
- iframe_t *frm = (iframe_t*) msg->data;
-
- struct misdn_stack *stack = find_stack_by_addr(frm->addr);
-
- if (!stack) {
- return 0 ;
- }
-
- switch(frm->prim) {
-
- case DL_ESTABLISH | REQUEST:
- cb_log(1,stack->port,"DL_ESTABLISH|REQUEST \n");
- return 1;
- case DL_RELEASE | REQUEST:
- cb_log(1,stack->port,"DL_RELEASE|REQUEST \n");
- return 1;
-
- case DL_ESTABLISH | INDICATION:
- case DL_ESTABLISH | CONFIRM:
- {
- cb_log (3, stack->port, "L2: L2Link Up! \n");
- if (stack->ptp && stack->l2link) {
- cb_log (-1, stack->port, "L2: L2Link Up! but it's already UP.. must be faulty, blocking port\n");
- cb_event(EVENT_PORT_ALARM, &stack->bc[0], glob_mgr->user_data);
- }
- stack->l2link=1;
- free_msg(msg);
- return 1;
- }
- break;
-
- case DL_RELEASE | INDICATION:
- case DL_RELEASE | CONFIRM:
- {
- cb_log (3, stack->port, "L2: L2Link Down! \n");
- stack->l2link=0;
-
- free_msg(msg);
- return 1;
- }
- break;
- }
- return 0;
-}
-
-static int handle_mgmt(msg_t *msg)
-{
- iframe_t *frm = (iframe_t*) msg->data;
- struct misdn_stack *stack;
-
- if ( (frm->addr == 0) && (frm->prim == (MGR_DELLAYER|CONFIRM)) ) {
- cb_log(2, 0, "MGMT: DELLAYER|CONFIRM Addr: 0 !\n") ;
- free_msg(msg);
- return 1;
- }
-
- stack = find_stack_by_addr(frm->addr);
-
- if (!stack) {
- if (frm->prim == (MGR_DELLAYER|CONFIRM)) {
- cb_log(2, 0, "MGMT: DELLAYER|CONFIRM Addr: %x !\n",
- frm->addr) ;
- free_msg(msg);
- return 1;
- }
-
- return 0;
- }
-
- switch(frm->prim) {
- case MGR_SHORTSTATUS | INDICATION:
- case MGR_SHORTSTATUS | CONFIRM:
- cb_log(5, 0, "MGMT: Short status dinfo %x\n",frm->dinfo);
-
- switch (frm->dinfo) {
- case SSTATUS_L1_ACTIVATED:
- cb_log(3, 0, "MGMT: SSTATUS: L1_ACTIVATED \n");
- stack->l1link=1;
-
- break;
- case SSTATUS_L1_DEACTIVATED:
- cb_log(3, 0, "MGMT: SSTATUS: L1_DEACTIVATED \n");
- stack->l1link=0;
-#if 0
- clear_l3(stack);
-#endif
- break;
-
- case SSTATUS_L2_ESTABLISHED:
- cb_log(3, stack->port, "MGMT: SSTATUS: L2_ESTABLISH \n");
-
- /*when the L2 goes UP, L1 needs to be UP too*/
- stack->l1link=1;
- stack->l2link=1;
- break;
-
- case SSTATUS_L2_RELEASED:
- cb_log(3, stack->port, "MGMT: SSTATUS: L2_RELEASED \n");
- stack->l2link=0;
- break;
- }
-
- free_msg(msg);
- return 1;
-
- case MGR_SETSTACK | INDICATION:
- cb_log(4, stack->port, "MGMT: SETSTACK|IND dinfo %x\n",frm->dinfo);
- free_msg(msg);
- return 1;
- case MGR_DELLAYER | CONFIRM:
- cb_log(4, stack->port, "MGMT: DELLAYER|CNF dinfo %x\n",frm->dinfo) ;
- free_msg(msg);
- return 1;
-
- }
-
- /*
- if ( (frm->prim & 0x0f0000) == 0x0f0000) {
- cb_log(5, 0, "$$$ MGMT FRAME: prim %x addr %x dinfo %x\n",frm->prim, frm->addr, frm->dinfo) ;
- free_msg(msg);
- return 1;
- } */
-
- return 0;
-}
-
-
-static msg_t *fetch_msg(int midev)
-{
- msg_t *msg=alloc_msg(MAX_MSG_SIZE);
- int r;
-
- if (!msg) {
- cb_log(0, 0, "fetch_msg: alloc msg failed !!");
- return NULL;
- }
-
- AGAIN:
- r=mISDN_read(midev,msg->data,MAX_MSG_SIZE, TIMEOUT_10SEC);
- msg->len=r;
-
- if (r==0) {
- free_msg(msg); /* danger, cause usually freeing in main_loop */
- cb_log(6,0,"Got empty Msg..\n");
- return NULL;
- }
-
- if (r<0) {
- if (errno == EAGAIN) {
- /*we wait for mISDN here*/
- cb_log(4,0,"mISDN_read wants us to wait\n");
- usleep(5000);
- goto AGAIN;
- }
-
- cb_log(0,0,"mISDN_read returned :%d error:%s (%d)\n",r,strerror(errno),errno);
- }
-
-#if 0
- if (!(frm->prim == (DL_DATA|INDICATION) )|| (frm->prim == (PH_DATA|INDICATION)))
- cb_log(0,0,"prim: %x dinfo:%x addr:%x msglen:%d frm->len:%d\n",frm->prim, frm->dinfo, frm->addr, msg->len,frm->len );
-#endif
- return msg;
-}
-
-void misdn_lib_isdn_l1watcher(int port)
-{
- struct misdn_stack *stack;
-
- for (stack = glob_mgr->stack_list; stack && (stack->port != port); stack = stack->next)
- ;
-
- if (stack) {
- cb_log(4, port, "Checking L1 State\n");
- if (!stack->l1link) {
- cb_log(4, port, "L1 State Down, trying to get it up again\n");
- misdn_lib_get_short_status(stack);
- misdn_lib_get_l1_up(stack);
- misdn_lib_get_l2_up(stack);
- }
- }
-}
-
-/* This is a thread */
-static void misdn_lib_isdn_event_catcher(void *arg)
-{
- struct misdn_lib *mgr = arg;
- int zero_frm=0 , fff_frm=0 ;
- int midev= mgr->midev;
- int port=0;
-
- while (1) {
- msg_t *msg = fetch_msg(midev);
- iframe_t *frm;
-
-
- if (!msg) continue;
-
- frm = (iframe_t*) msg->data;
-
- /** When we make a call from NT2Ast we get these frames **/
- if (frm->len == 0 && frm->addr == 0 && frm->dinfo == 0 && frm->prim == 0 ) {
- zero_frm++;
- free_msg(msg);
- continue;
- } else {
- if (zero_frm) {
- cb_log(0, port, "*** Alert: %d zero_frms caught\n", zero_frm);
- zero_frm = 0 ;
- }
- }
-
- /** I get this sometimes after setup_bc **/
- if (frm->len == 0 && frm->dinfo == 0 && frm->prim == 0xffffffff ) {
- fff_frm++;
- free_msg(msg);
- continue;
- } else {
- if (fff_frm) {
- cb_log(0, port, "*** Alert: %d fff_frms caught\n", fff_frm);
- fff_frm = 0 ;
- }
- }
-
- manager_isdn_handler(frm, msg);
- }
-
-}
-
-
-/** App Interface **/
-
-int te_lib_init() {
- char buff[1025] = "";
- iframe_t *frm=(iframe_t*)buff;
- int midev=mISDN_open();
- int ret;
-
- if (midev<=0) return midev;
-
-/* create entity for layer 3 TE-mode */
- mISDN_write_frame(midev, buff, 0, MGR_NEWENTITY | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
- ret = mISDN_read_frame(midev, frm, sizeof(iframe_t), 0, MGR_NEWENTITY | CONFIRM, TIMEOUT_1SEC);
-
- if (ret < mISDN_HEADER_LEN) {
- noentity:
- fprintf(stderr, "cannot request MGR_NEWENTITY from mISDN: %s\n",strerror(errno));
- exit(-1);
- }
-
- entity = frm->dinfo & 0xffff ;
-
- if (!entity)
- goto noentity;
-
- return midev;
-
-}
-
-void te_lib_destroy(int midev)
-{
- char buf[1024];
- mISDN_write_frame(midev, buf, 0, MGR_DELENTITY | REQUEST, entity, 0, NULL, TIMEOUT_1SEC);
-
- cb_log(4, 0, "Entity deleted\n");
- mISDN_close(midev);
- cb_log(4, 0, "midev closed\n");
-}
-
-
-
-void misdn_lib_transfer(struct misdn_bchannel* holded_bc)
-{
- holded_bc->holded=0;
-}
-
-struct misdn_bchannel *manager_find_bc_by_pid(int pid)
-{
- struct misdn_stack *stack;
- int i;
-
- for (stack=glob_mgr->stack_list;
- stack;
- stack=stack->next) {
- for (i=0; i<=stack->b_num; i++)
- if (stack->bc[i].pid == pid) return &stack->bc[i];
- }
-
- return NULL;
-}
-
-struct misdn_bchannel *manager_find_bc_holded(struct misdn_bchannel* bc)
-{
- struct misdn_stack *stack=get_stack_by_bc(bc);
- return find_bc_holded(stack);
-}
-
-
-
-static int test_inuse(struct misdn_bchannel *bc)
-{
- struct timeval now;
- gettimeofday(&now, NULL);
- if (!bc->in_use) {
- if (misdn_lib_port_is_pri(bc->port) && bc->last_used.tv_sec == now.tv_sec ) {
- cb_log(2,bc->port, "channel with stid:%x for one second still in use! (n:%d lu:%d)\n", bc->b_stid, (int) now.tv_sec, (int) bc->last_used.tv_sec);
- return 1;
- }
-
-
- cb_log(3,bc->port, "channel with stid:%x not in use!\n", bc->b_stid);
- return 0;
- }
-
- cb_log(2,bc->port, "channel with stid:%x in use!\n", bc->b_stid);
- return 1;
-}
-
-
-static void prepare_bc(struct misdn_bchannel*bc, int channel)
-{
- bc->channel = channel;
- bc->channel_preselected = channel?1:0;
- bc->in_use = 1;
- bc->need_disconnect=1;
- bc->need_release=1;
- bc->need_release_complete=1;
- bc->cause = AST_CAUSE_NORMAL_CLEARING;
-
- if (++mypid>5000) mypid=1;
- bc->pid=mypid;
-
-#if 0
- bc->addr=0;
- bc->b_stid=0;
- bc->layer_id=0;
-#endif
-}
-
-struct misdn_bchannel* misdn_lib_get_free_bc(int port, int channel, int inout, int dec)
-{
- struct misdn_stack *stack;
- int i;
-
- if (channel < 0 || channel > MAX_BCHANS) {
- cb_log(0,port,"Requested channel out of bounds (%d)\n",channel);
- return NULL;
- }
-
- usleep(1000);
-
- for (stack=glob_mgr->stack_list; stack; stack=stack->next) {
-
- if (stack->port == port) {
- int maxnum;
-
- if (stack->blocked) {
- cb_log(0,port,"Port is blocked\n");
- return NULL;
- }
-
- if (channel > 0) {
- if (channel <= stack->b_num) {
- for (i = 0; i < stack->b_num; i++) {
- if ( stack->bc[i].channel == channel) {
- if (test_inuse(&stack->bc[i])) {
- cb_log(0,port,"Requested channel:%d on port:%d is already in use\n",channel, port);
- return NULL;
-
- } else {
- prepare_bc(&stack->bc[i], channel);
- return &stack->bc[i];
- }
- }
- }
- } else {
- cb_log(0,port,"Requested channel:%d is out of bounds on port:%d\n",channel, port);
- return NULL;
- }
- }
-
- maxnum = inout && !stack->pri && !stack->ptp ? stack->b_num + 1 : stack->b_num;
-
- if (dec) {
- for (i = maxnum-1; i>=0; i--) {
- if (!test_inuse(&stack->bc[i])) {
- /* 3. channel on bri means CW*/
- if (!stack->pri && i==stack->b_num)
- stack->bc[i].cw=1;
-
- prepare_bc(&stack->bc[i], channel);
- stack->bc[i].dec=1;
- return &stack->bc[i];
- }
- }
- } else {
- for (i = 0; i <maxnum; i++) {
- if (!test_inuse(&stack->bc[i])) {
- /* 3. channel on bri means CW*/
- if (!stack->pri && i==stack->b_num)
- stack->bc[i].cw=1;
-
- prepare_bc(&stack->bc[i], channel);
- return &stack->bc[i];
- }
- }
- }
-
- cb_log(1,port,"There is no free channel on port (%d)\n",port);
- return NULL;
- }
- }
-
- cb_log(0,port,"Port is not configured (%d)\n",port);
- return NULL;
-}
-
-
-
-
-/* ******************************************************************* */
-/*!
- * \internal
- * \brief Convert the facility function enum value into a string.
- *
- * \return String version of the enum value
- */
-static const char *fac2str(enum FacFunction facility)
-{
- static const struct {
- enum FacFunction facility;
- char *name;
- } arr[] = {
-/* *INDENT-OFF* */
- { Fac_None, "Fac_None" },
- { Fac_GetSupportedServices, "Fac_GetSupportedServices" },
- { Fac_Listen, "Fac_Listen" },
- { Fac_Suspend, "Fac_Suspend" },
- { Fac_Resume, "Fac_Resume" },
- { Fac_CFActivate, "Fac_CFActivate" },
- { Fac_CFDeactivate, "Fac_CFDeactivate" },
- { Fac_CFInterrogateParameters, "Fac_CFInterrogateParameters" },
- { Fac_CFInterrogateNumbers, "Fac_CFInterrogateNumbers" },
- { Fac_CD, "Fac_CD" },
- { Fac_AOCDCurrency, "Fac_AOCDCurrency" },
- { Fac_AOCDChargingUnit, "Fac_AOCDChargingUnit" },
-/* *INDENT-ON* */
- };
-
- unsigned index;
-
- for (index = 0; index < ARRAY_LEN(arr); ++index) {
- if (arr[index].facility == facility) {
- return arr[index].name;
- }
- } /* end for */
-
- return "unknown";
-} /* end fac2str() */
-
-void misdn_lib_log_ies(struct misdn_bchannel *bc)
-{
- struct misdn_stack *stack;
-
- if (!bc) return;
-
- stack = get_stack_by_bc(bc);
-
- if (!stack) return;
-
- cb_log(2, stack->port, " --> channel:%d mode:%s cause:%d ocause:%d rad:%s cad:%s\n", bc->channel, stack->nt?"NT":"TE", bc->cause, bc->out_cause, bc->rad, bc->cad);
-
- cb_log(2, stack->port,
- " --> info_dad:%s onumplan:%c dnumplan:%c rnumplan:%c cpnnumplan:%c\n",
- bc->info_dad,
- bc->onumplan>=0?'0'+bc->onumplan:' ',
- bc->dnumplan>=0?'0'+bc->dnumplan:' ',
- bc->rnumplan>=0?'0'+bc->rnumplan:' ',
- bc->cpnnumplan>=0?'0'+bc->cpnnumplan:' '
- );
-
- cb_log(3, stack->port, " --> caps:%s pi:%x keypad:%s sending_complete:%d\n", bearer2str(bc->capability),bc->progress_indicator, bc->keypad, bc->sending_complete);
- cb_log(4, stack->port, " --> screen:%d --> pres:%d\n",
- bc->screen, bc->pres);
-
- cb_log(4, stack->port, " --> addr:%x l3id:%x b_stid:%x layer_id:%x\n", bc->addr, bc->l3_id, bc->b_stid, bc->layer_id);
-
- cb_log(4, stack->port, " --> facility:%s out_facility:%s\n",fac2str(bc->fac_in.Function),fac2str(bc->fac_out.Function));
-
- cb_log(5, stack->port, " --> urate:%d rate:%d mode:%d user1:%d\n", bc->urate, bc->rate, bc->mode,bc->user1);
-
- cb_log(5, stack->port, " --> bc:%p h:%d sh:%d\n", bc, bc->holded, bc->stack_holder);
-}
-
-
-#define RETURN(a,b) {retval=a; goto b;}
-
-static void misdn_send_lock(struct misdn_bchannel *bc)
-{
- //cb_log(0,bc->port,"Locking bc->pid:%d\n", bc->pid);
- if (bc->send_lock)
- pthread_mutex_lock(&bc->send_lock->lock);
-}
-
-static void misdn_send_unlock(struct misdn_bchannel *bc)
-{
- //cb_log(0,bc->port,"UnLocking bc->pid:%d\n", bc->pid);
- if (bc->send_lock)
- pthread_mutex_unlock(&bc->send_lock->lock);
-}
-
-int misdn_lib_send_event(struct misdn_bchannel *bc, enum event_e event )
-{
- msg_t *msg;
- int retval=0;
- struct misdn_stack *stack;
-
- if (!bc) RETURN(-1,OUT_POST_UNLOCK);
-
- stack = get_stack_by_bc(bc);
-
- if (!stack) {
- cb_log(0,bc->port,"SENDEVENT: no Stack for event:%s oad:%s dad:%s \n", isdn_get_info(msgs_g, event, 0), bc->oad, bc->dad);
- RETURN(-1,OUT);
- }
-
- misdn_send_lock(bc);
-
-
- cb_log(6,stack->port,"SENDEVENT: stack->nt:%d stack->upperid:%x\n",stack->nt, stack->upper_id);
-
- if ( stack->nt && !stack->l1link) {
- /** Queue Event **/
- bc->evq=event;
- cb_log(1, stack->port, "Queueing Event %s because L1 is down (btw. Activating L1)\n", isdn_get_info(msgs_g, event, 0));
- misdn_lib_get_l1_up(stack);
- RETURN(0,OUT);
- }
-
- cb_log(1, stack->port, "I SEND:%s oad:%s dad:%s pid:%d\n", isdn_get_info(msgs_g, event, 0), bc->oad, bc->dad, bc->pid);
- cb_log(4, stack->port, " --> bc_state:%s\n",bc_state2str(bc->bc_state));
- misdn_lib_log_ies(bc);
-
- switch (event) {
- case EVENT_SETUP:
- if (create_process(glob_mgr->midev, bc)<0) {
- cb_log(0, stack->port, " No free channel at the moment @ send_event\n");
-
- RETURN(-ENOCHAN,OUT);
- }
- break;
-
- case EVENT_PROGRESS:
- case EVENT_ALERTING:
- case EVENT_PROCEEDING:
- case EVENT_SETUP_ACKNOWLEDGE:
- case EVENT_CONNECT:
- if (!stack->nt) break;
-
- case EVENT_RETRIEVE_ACKNOWLEDGE:
-
- if (stack->nt) {
- if (bc->channel <=0 ) { /* else we have the channel already */
- if (find_free_chan_in_stack(stack, bc, 0, 0)<0) {
- cb_log(0, stack->port, " No free channel at the moment\n");
- /*FIXME: add disconnect*/
- RETURN(-ENOCHAN,OUT);
- }
- }
- /* Its that i generate channels */
- }
-
- retval=setup_bc(bc);
- if (retval == -EINVAL) {
- cb_log(0,bc->port,"send_event: setup_bc failed\n");
- }
-
- if (misdn_cap_is_speech(bc->capability)) {
- if ((event==EVENT_CONNECT)||(event==EVENT_RETRIEVE_ACKNOWLEDGE)) {
- if ( *bc->crypt_key ) {
- cb_log(4, stack->port, " --> ENABLING BLOWFISH channel:%d oad%d:%s dad%d:%s \n", bc->channel, bc->onumplan,bc->oad, bc->dnumplan,bc->dad);
-
- manager_ph_control_block(bc, BF_ENABLE_KEY, bc->crypt_key, strlen(bc->crypt_key) );
- }
-
- if (!bc->nodsp) manager_ph_control(bc, DTMF_TONE_START, 0);
- manager_ec_enable(bc);
-
- if (bc->txgain != 0) {
- cb_log(4, stack->port, "--> Changing txgain to %d\n", bc->txgain);
- manager_ph_control(bc, VOL_CHANGE_TX, bc->txgain);
- }
-
- if ( bc->rxgain != 0 ) {
- cb_log(4, stack->port, "--> Changing rxgain to %d\n", bc->rxgain);
- manager_ph_control(bc, VOL_CHANGE_RX, bc->rxgain);
- }
- }
- }
- break;
-
- case EVENT_HOLD_ACKNOWLEDGE:
- {
- struct misdn_bchannel *holded_bc=malloc(sizeof(struct misdn_bchannel));
- if (!holded_bc) {
- cb_log(0,bc->port, "Could not allocate holded_bc!!!\n");
- RETURN(-1,OUT);
- }
-
- /*backup the bc*/
- memcpy(holded_bc,bc,sizeof(struct misdn_bchannel));
- holded_bc->holded=1;
- bc_state_change(holded_bc,BCHAN_CLEANED);
-
- stack_holder_add(stack,holded_bc);
-
- /*kill the bridge and clean the bchannel*/
- if (stack->nt) {
- int channel;
- if (bc->bc_state == BCHAN_BRIDGED) {
- struct misdn_bchannel *bc2;
-
- misdn_split_conf(bc,bc->conf_id);
- bc2 = find_bc_by_confid(bc->conf_id);
- if (!bc2) {
- cb_log(0,bc->port,"We have no second bc in bridge???\n");
- } else {
- misdn_split_conf(bc2,bc->conf_id);
- }
- }
-
- channel = bc->channel;
-
- empty_bc(bc);
- clean_up_bc(bc);
-
- if (channel>0)
- empty_chan_in_stack(stack,channel);
-
- bc->in_use=0;
- }
-
- }
- break;
-
- /* finishing the channel eh ? */
- case EVENT_DISCONNECT:
- if (!bc->need_disconnect) {
- cb_log(0,bc->port," --> we have already send Disconnect\n");
- RETURN(-1,OUT);
- }
-
- bc->need_disconnect=0;
- break;
- case EVENT_RELEASE:
- if (!bc->need_release) {
- cb_log(0,bc->port," --> we have already send Release\n");
- RETURN(-1,OUT);
- }
- bc->need_disconnect=0;
- bc->need_release=0;
- break;
- case EVENT_RELEASE_COMPLETE:
- if (!bc->need_release_complete) {
- cb_log(0,bc->port," --> we have already send Release_complete\n");
- RETURN(-1,OUT);
- }
- bc->need_disconnect=0;
- bc->need_release=0;
- bc->need_release_complete=0;
-
- if (!stack->nt) {
- /*create cleanup in TE*/
- int channel=bc->channel;
-
- int tmpcause=bc->cause;
- int tmp_out_cause=bc->out_cause;
- empty_bc(bc);
- bc->cause=tmpcause;
- bc->out_cause=tmp_out_cause;
- clean_up_bc(bc);
-
- if (channel>0)
- empty_chan_in_stack(stack,channel);
-
- bc->in_use=0;
- }
- break;
-
- case EVENT_CONNECT_ACKNOWLEDGE:
-
- if ( bc->nt || misdn_cap_is_speech(bc->capability)) {
- int retval=setup_bc(bc);
- if (retval == -EINVAL){
- cb_log(0,bc->port,"send_event: setup_bc failed\n");
-
- }
- }
-
- if (misdn_cap_is_speech(bc->capability)) {
- if ( !bc->nodsp) manager_ph_control(bc, DTMF_TONE_START, 0);
- manager_ec_enable(bc);
-
- if ( bc->txgain != 0 ) {
- cb_log(4, stack->port, "--> Changing txgain to %d\n", bc->txgain);
- manager_ph_control(bc, VOL_CHANGE_TX, bc->txgain);
- }
- if ( bc->rxgain != 0 ) {
- cb_log(4, stack->port, "--> Changing rxgain to %d\n", bc->rxgain);
- manager_ph_control(bc, VOL_CHANGE_RX, bc->rxgain);
- }
- }
- break;
-
- default:
- break;
- }
-
- /* Later we should think about sending bchannel data directly to misdn. */
- msg = isdn_msg_build_event(msgs_g, bc, event, stack->nt);
- msg_queue_tail(&stack->downqueue, msg);
- sem_post(&glob_mgr->new_msg);
-
-OUT:
- misdn_send_unlock(bc);
-
-OUT_POST_UNLOCK:
- return retval;
-}
-
-
-static int handle_err(msg_t *msg)
-{
- iframe_t *frm = (iframe_t*) msg->data;
-
-
- if (!frm->addr) {
- static int cnt=0;
- if (!cnt)
- cb_log(0,0,"mISDN Msg without Address pr:%x dinfo:%x\n",frm->prim,frm->dinfo);
- cnt++;
- if (cnt>100) {
- cb_log(0,0,"mISDN Msg without Address pr:%x dinfo:%x (already more than 100 of them)\n",frm->prim,frm->dinfo);
- cnt=0;
- }
-
- free_msg(msg);
- return 1;
-
- }
-
- switch (frm->prim) {
- case MGR_SETSTACK|INDICATION:
- return handle_bchan(msg);
- break;
-
- case MGR_SETSTACK|CONFIRM:
- case MGR_CLEARSTACK|CONFIRM:
- free_msg(msg) ;
- return 1;
- break;
-
- case DL_DATA|CONFIRM:
- cb_log(4,0,"DL_DATA|CONFIRM\n");
- free_msg(msg);
- return 1;
-
- case PH_CONTROL|CONFIRM:
- cb_log(4,0,"PH_CONTROL|CONFIRM\n");
- free_msg(msg);
- return 1;
-
- case DL_DATA|INDICATION:
- {
- int port=(frm->addr&MASTER_ID_MASK) >> 8;
- int channel=(frm->addr&CHILD_ID_MASK) >> 16;
- struct misdn_bchannel *bc;
-
- /*we flush the read buffer here*/
-
- cb_log(9,0,"BCHAN DATA without BC: addr:%x port:%d channel:%d\n",frm->addr, port,channel);
-
- free_msg(msg);
- return 1;
-
-
- bc = find_bc_by_channel(port, channel);
-
- if (!bc) {
- struct misdn_stack *stack = find_stack_by_port(port);
-
- if (!stack) {
- cb_log(0,0," --> stack not found\n");
- free_msg(msg);
- return 1;
- }
-
- cb_log(0,0," --> bc not found by channel\n");
- if (stack->l2link)
- misdn_lib_get_l2_down(stack);
-
- if (stack->l1link)
- misdn_lib_get_l1_down(stack);
-
- free_msg(msg);
- return 1;
- }
-
- cb_log(3,port," --> BC in state:%s\n", bc_state2str(bc->bc_state));
- }
- }
-
- return 0;
-}
-
-#if 0
-static int queue_l2l3(msg_t *msg)
-{
- iframe_t *frm= (iframe_t*)msg->data;
- struct misdn_stack *stack;
- stack=find_stack_by_addr( frm->addr );
-
-
- if (!stack) {
- return 0;
- }
-
- msg_queue_tail(&stack->upqueue, msg);
- sem_post(&glob_mgr->new_msg);
- return 1;
-}
-#endif
-
-int manager_isdn_handler(iframe_t *frm ,msg_t *msg)
-{
-
- if (frm->dinfo==0xffffffff && frm->prim==(PH_DATA|CONFIRM)) {
- cb_log(0,0,"SERIOUS BUG, dinfo == 0xffffffff, prim == PH_DATA | CONFIRM !!!!\n");
- }
-
- if ( ((frm->addr | ISDN_PID_BCHANNEL_BIT )>> 28 ) == 0x5) {
- static int unhandled_bmsg_count=1000;
- if (handle_bchan(msg)) {
- return 0 ;
- }
-
- if (unhandled_bmsg_count==1000) {
- cb_log(0, 0, "received 1k Unhandled Bchannel Messages: prim %x len %d from addr %x, dinfo %x on this port.\n",frm->prim, frm->len, frm->addr, frm->dinfo);
- unhandled_bmsg_count=0;
- }
-
- unhandled_bmsg_count++;
- free_msg(msg);
- return 0;
- }
-
-#ifdef RECV_FRM_SYSLOG_DEBUG
- syslog(LOG_NOTICE,"mISDN recv: P(%02d): ADDR:%x PRIM:%x DINFO:%x\n",stack->port, frm->addr, frm->prim, frm->dinfo);
-#endif
-
- if (handle_timers(msg))
- return 0 ;
-
-
- if (handle_mgmt(msg))
- return 0 ;
-
- if (handle_l2(msg))
- return 0 ;
-
- /* Its important to handle l1 AFTER l2 */
- if (handle_l1(msg))
- return 0 ;
-
- if (handle_frm_nt(msg)) {
- return 0;
- }
-
- if (handle_frm(msg)) {
- return 0;
- }
-
- if (handle_err(msg)) {
- return 0 ;
- }
-
- cb_log(0, 0, "Unhandled Message: prim %x len %d from addr %x, dinfo %x on this port.\n",frm->prim, frm->len, frm->addr, frm->dinfo);
- free_msg(msg);
-
-
- return 0;
-}
-
-
-
-
-int misdn_lib_get_port_info(int port)
-{
- msg_t *msg=alloc_msg(MAX_MSG_SIZE);
- iframe_t *frm;
- struct misdn_stack *stack=find_stack_by_port(port);
- if (!msg) {
- cb_log(0, port, "misdn_lib_get_port_info: alloc_msg failed!\n");
- return -1;
- }
- frm=(iframe_t*)msg->data;
- if (!stack ) {
- cb_log(0, port, "There is no Stack for this port.\n");
- return -1;
- }
- /* activate bchannel */
- frm->prim = CC_STATUS_ENQUIRY | REQUEST;
-
- frm->addr = stack->upper_id| FLG_MSG_DOWN;
-
- frm->dinfo = 0;
- frm->len = 0;
-
- msg_queue_tail(&glob_mgr->activatequeue, msg);
- sem_post(&glob_mgr->new_msg);
-
-
- return 0;
-}
-
-
-int queue_cleanup_bc(struct misdn_bchannel *bc)
-{
- msg_t *msg=alloc_msg(MAX_MSG_SIZE);
- iframe_t *frm;
- if (!msg) {
- cb_log(0, bc->port, "queue_cleanup_bc: alloc_msg failed!\n");
- return -1;
- }
- frm=(iframe_t*)msg->data;
-
- /* activate bchannel */
- frm->prim = MGR_CLEARSTACK| REQUEST;
-
- frm->addr = bc->l3_id;
-
- frm->dinfo = bc->port;
- frm->len = 0;
-
- msg_queue_tail(&glob_mgr->activatequeue, msg);
- sem_post(&glob_mgr->new_msg);
-
- return 0;
-
-}
-
-int misdn_lib_pid_restart(int pid)
-{
- struct misdn_bchannel *bc=manager_find_bc_by_pid(pid);
-
- if (bc) {
- manager_clean_bc(bc);
- }
- return 0;
-}
-
-/*Sends Restart message for every bchannel*/
-int misdn_lib_send_restart(int port, int channel)
-{
- struct misdn_stack *stack=find_stack_by_port(port);
- struct misdn_bchannel dummybc;
- /*default is all channels*/
- cb_log(0, port, "Sending Restarts on this port.\n");
-
- misdn_make_dummy(&dummybc, stack->port, MISDN_ID_GLOBAL, stack->nt, 0);
-
- /*default is all channels*/
- if (channel <0) {
- dummybc.channel=-1;
- cb_log(0, port, "Restarting and all Interfaces\n");
- misdn_lib_send_event(&dummybc, EVENT_RESTART);
-
- return 0;
- }
-
- /*if a channel is specified we restart only this one*/
- if (channel >0) {
- int cnt;
- dummybc.channel=channel;
- cb_log(0, port, "Restarting and cleaning channel %d\n",channel);
- misdn_lib_send_event(&dummybc, EVENT_RESTART);
- /* clean up chan in stack, to be sure we don't think it's
- * in use anymore */
- for (cnt=0; cnt<=stack->b_num; cnt++) {
- if (stack->bc[cnt].channel == channel) {
- empty_bc(&stack->bc[cnt]);
- clean_up_bc(&stack->bc[cnt]);
- stack->bc[cnt].in_use=0;
- }
- }
- }
-
- return 0;
-}
-
-/*reinitializes the L2/L3*/
-int misdn_lib_port_restart(int port)
-{
- struct misdn_stack *stack=find_stack_by_port(port);
-
- cb_log(0, port, "Restarting this port.\n");
- if (stack) {
- cb_log(0, port, "Stack:%p\n",stack);
-
- clear_l3(stack);
- {
- msg_t *msg=alloc_msg(MAX_MSG_SIZE);
- iframe_t *frm;
-
- if (!msg) {
- cb_log(0, port, "port_restart: alloc_msg failed\n");
- return -1;
- }
-
- frm=(iframe_t*)msg->data;
- /* we must activate if we are deactivated */
- /* activate bchannel */
- frm->prim = DL_RELEASE | REQUEST;
- frm->addr = stack->upper_id | FLG_MSG_DOWN;
-
- frm->dinfo = 0;
- frm->len = 0;
- msg_queue_tail(&glob_mgr->activatequeue, msg);
- sem_post(&glob_mgr->new_msg);
- }
-
- if (stack->nt)
- misdn_lib_reinit_nt_stack(stack->port);
-
- }
-
- return 0;
-}
-
-
-
-sem_t handler_started;
-
-/* This is a thread */
-static void manager_event_handler(void *arg)
-{
- sem_post(&handler_started);
- while (1) {
- struct misdn_stack *stack;
- msg_t *msg;
-
- /** wait for events **/
- sem_wait(&glob_mgr->new_msg);
-
- for (msg=msg_dequeue(&glob_mgr->activatequeue);
- msg;
- msg=msg_dequeue(&glob_mgr->activatequeue)
- )
- {
-
- iframe_t *frm = (iframe_t*) msg->data ;
-
- switch ( frm->prim) {
-
- case MGR_CLEARSTACK | REQUEST:
- /*a queued bchannel cleanup*/
- {
- struct misdn_stack *stack=find_stack_by_port(frm->dinfo);
- struct misdn_bchannel *bc;
- if (!stack) {
- cb_log(0,0,"no stack found with port [%d]!! so we cannot cleanup the bc\n",frm->dinfo);
- free_msg(msg);
- break;
- }
-
- bc = find_bc_by_l3id(stack, frm->addr);
- if (bc) {
- cb_log(1,bc->port,"CLEARSTACK queued, cleaning up\n");
- clean_up_bc(bc);
- } else {
- cb_log(0,stack->port,"bc could not be cleaned correctly !! addr [%x]\n",frm->addr);
- }
- }
- free_msg(msg);
- break;
- case MGR_SETSTACK | REQUEST :
- /* Warning: memory leak here if we get this message */
- break;
- default:
- mISDN_write(glob_mgr->midev, frm, mISDN_HEADER_LEN+frm->len, TIMEOUT_1SEC);
- free_msg(msg);
- }
- }
-
- for (stack=glob_mgr->stack_list;
- stack;
- stack=stack->next ) {
-
- while ( (msg=msg_dequeue(&stack->upqueue)) ) {
- /** Handle L2/3 Signalling after bchans **/
- if (!handle_frm_nt(msg)) {
- /* Maybe it's TE */
- if (!handle_frm(msg)) {
- /* wow none! */
- cb_log(0,stack->port,"Wow we've got a strange issue while dequeueing a Frame\n");
- }
- }
- }
-
- /* Here we should check if we really want to
- send all the messages we've queued, lets
- assume we've queued a Disconnect, but
- received it already from the other side!*/
-
- while ( (msg=msg_dequeue(&stack->downqueue)) ) {
- if (stack->nt ) {
- if (stack->nst.manager_l3(&stack->nst, msg))
- cb_log(0, stack->port, "Error@ Sending Message in NT-Stack.\n");
-
- } else {
- iframe_t *frm = (iframe_t *)msg->data;
- struct misdn_bchannel *bc = find_bc_by_l3id(stack, frm->dinfo);
- if (bc)
- send_msg(glob_mgr->midev, bc, msg);
- else {
- if (frm->dinfo == MISDN_ID_GLOBAL) {
- struct misdn_bchannel dummybc;
- misdn_make_dummy(&dummybc, stack->port, MISDN_ID_GLOBAL, stack->nt, 0);
- send_msg(glob_mgr->midev, &dummybc, msg);
- }
- }
- }
- }
- }
- }
-}
-
-
-int misdn_lib_maxports_get(void)
-{
- /* BE AWARE WE HAVE NO cb_log() HERE! */
-
- int i = mISDN_open();
- int max=0;
-
- if (i<0)
- return -1;
-
- max = mISDN_get_stack_count(i);
-
- mISDN_close(i);
-
- return max;
-}
-
-
-void misdn_lib_nt_keepcalls( int kc)
-{
-#ifdef FEATURE_NET_KEEPCALLS
- if (kc) {
- struct misdn_stack *stack=get_misdn_stack();
- for ( ; stack; stack=stack->next) {
- stack->nst.feature |= FEATURE_NET_KEEPCALLS;
- }
- }
-#endif
-}
-
-void misdn_lib_nt_debug_init( int flags, char *file )
-{
- static int init=0;
- char *f;
-
- if (!flags)
- f=NULL;
- else
- f=file;
-
- if (!init) {
- debug_init( flags , f, f, f);
- init=1;
- } else {
- debug_close();
- debug_init( flags , f, f, f);
- }
-}
-
-
-int misdn_lib_init(char *portlist, struct misdn_lib_iface *iface, void *user_data)
-{
- struct misdn_lib *mgr=calloc(1, sizeof(struct misdn_lib));
- char *tok, *tokb;
- char plist[1024];
- int midev;
- int port_count=0;
-
- cb_log = iface->cb_log;
- cb_event = iface->cb_event;
- cb_jb_empty = iface->cb_jb_empty;
-
- glob_mgr = mgr;
-
- msg_init();
-
- misdn_lib_nt_debug_init(0,NULL);
-
- if (!portlist || (*portlist == 0) ) return 1;
-
- init_flip_bits();
-
- {
- strncpy(plist,portlist, 1024);
- plist[1023] = 0;
- }
-
- memcpy(tone_425_flip,tone_425,TONE_425_SIZE);
- flip_buf_bits(tone_425_flip,TONE_425_SIZE);
-
- memcpy(tone_silence_flip,tone_SILENCE,TONE_SILENCE_SIZE);
- flip_buf_bits(tone_silence_flip,TONE_SILENCE_SIZE);
-
- midev=te_lib_init();
- mgr->midev=midev;
-
- port_count=mISDN_get_stack_count(midev);
-
- msg_queue_init(&mgr->activatequeue);
-
- if (sem_init(&mgr->new_msg, 1, 0)<0)
- sem_init(&mgr->new_msg, 0, 0);
-
- for (tok=strtok_r(plist," ,",&tokb );
- tok;
- tok=strtok_r(NULL," ,",&tokb)) {
- int port = atoi(tok);
- struct misdn_stack *stack;
- static int first=1;
- int ptp=0;
-
- if (strstr(tok, "ptp"))
- ptp=1;
-
- if (port > port_count) {
- cb_log(0, port, "Couldn't Initialize this port since we have only %d ports\n", port_count);
- exit(1);
- }
- stack=stack_init(midev, port, ptp);
-
- if (!stack) {
- perror("stack_init");
- exit(1);
- }
-
- {
- int i;
- for(i=0;i<=stack->b_num; i++) {
- int r;
- if ((r=init_bc(stack, &stack->bc[i], stack->midev,port,i, "", 1))<0) {
- cb_log(0, port, "Got Err @ init_bc :%d\n",r);
- exit(1);
- }
- }
- }
-
- if (stack && first) {
- mgr->stack_list=stack;
- first=0;
- continue;
- }
-
- if (stack) {
- struct misdn_stack * help;
- for ( help=mgr->stack_list; help; help=help->next )
- if (help->next == NULL) break;
- help->next=stack;
- }
-
- }
-
- if (sem_init(&handler_started, 1, 0)<0)
- sem_init(&handler_started, 0, 0);
-
- cb_log(8, 0, "Starting Event Handler\n");
- pthread_create( &mgr->event_handler_thread, NULL,(void*)manager_event_handler, mgr);
-
- sem_wait(&handler_started) ;
- cb_log(8, 0, "Starting Event Catcher\n");
- pthread_create( &mgr->event_thread, NULL, (void*)misdn_lib_isdn_event_catcher, mgr);
-
- cb_log(8, 0, "Event Catcher started\n");
-
- global_state= MISDN_INITIALIZED;
-
- return (mgr == NULL);
-}
-
-void misdn_lib_destroy(void)
-{
- struct misdn_stack *help;
- int i;
-
- for ( help=glob_mgr->stack_list; help; help=help->next ) {
- for(i=0;i<=help->b_num; i++) {
- char buf[1024];
- mISDN_write_frame(help->midev, buf, help->bc[i].addr, MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
- help->bc[i].addr = 0;
- }
- cb_log (1, help->port, "Destroying this port.\n");
- stack_destroy(help);
- }
-
- if (global_state == MISDN_INITIALIZED) {
- cb_log(4, 0, "Killing Handler Thread\n");
- if ( pthread_cancel(glob_mgr->event_handler_thread) == 0 ) {
- cb_log(4, 0, "Joining Handler Thread\n");
- pthread_join(glob_mgr->event_handler_thread, NULL);
- }
-
- cb_log(4, 0, "Killing Main Thread\n");
- if ( pthread_cancel(glob_mgr->event_thread) == 0 ) {
- cb_log(4, 0, "Joining Main Thread\n");
- pthread_join(glob_mgr->event_thread, NULL);
- }
- }
-
- cb_log(1, 0, "Closing mISDN device\n");
- te_lib_destroy(glob_mgr->midev);
-}
-
-char *manager_isdn_get_info(enum event_e event)
-{
- return isdn_get_info(msgs_g , event, 0);
-}
-
-void manager_bchannel_activate(struct misdn_bchannel *bc)
-{
- char buf[128];
-
- struct misdn_stack *stack=get_stack_by_bc(bc);
-
- if (!stack) {
- cb_log(0, bc->port, "bchannel_activate: Stack not found !");
- return ;
- }
-
- /* we must activate if we are deactivated */
- clear_ibuffer(bc->astbuf);
-
- cb_log(5, stack->port, "$$$ Bchan Activated addr %x\n", bc->addr);
-
- mISDN_write_frame(stack->midev, buf, bc->addr | FLG_MSG_DOWN, DL_ESTABLISH | REQUEST, 0,0, NULL, TIMEOUT_1SEC);
-
- return ;
-}
-
-
-void manager_bchannel_deactivate(struct misdn_bchannel * bc)
-{
- struct misdn_stack *stack=get_stack_by_bc(bc);
- iframe_t dact;
- char buf[128];
-
- switch (bc->bc_state) {
- case BCHAN_ACTIVATED:
- break;
- case BCHAN_BRIDGED:
- misdn_split_conf(bc,bc->conf_id);
- break;
- default:
- cb_log( 4, bc->port,"bchan_deactivate: called but not activated\n");
- return ;
-
- }
-
- cb_log(5, stack->port, "$$$ Bchan deActivated addr %x\n", bc->addr);
-
- bc->generate_tone=0;
-
- dact.prim = DL_RELEASE | REQUEST;
- dact.addr = bc->addr | FLG_MSG_DOWN;
- dact.dinfo = 0;
- dact.len = 0;
- mISDN_write_frame(stack->midev, buf, bc->addr | FLG_MSG_DOWN, DL_RELEASE|REQUEST,0,0,NULL, TIMEOUT_1SEC);
-
- clear_ibuffer(bc->astbuf);
-
- bc_state_change(bc,BCHAN_RELEASE);
-
- return;
-}
-
-
-int misdn_lib_tx2misdn_frm(struct misdn_bchannel *bc, void *data, int len)
-{
- struct misdn_stack *stack=get_stack_by_bc(bc);
- char buf[4096 + mISDN_HEADER_LEN];
- iframe_t *frm = (iframe_t*)buf;
- int r;
-
- switch (bc->bc_state) {
- case BCHAN_ACTIVATED:
- case BCHAN_BRIDGED:
- break;
- default:
- cb_log(3, bc->port, "BC not yet activated (state:%s)\n",bc_state2str(bc->bc_state));
- return -1;
- }
-
- frm->prim = DL_DATA|REQUEST;
- frm->dinfo = 0;
- frm->addr = bc->addr | FLG_MSG_DOWN ;
-
- frm->len = len;
- memcpy(&buf[mISDN_HEADER_LEN], data,len);
-
- if ( misdn_cap_is_speech(bc->capability) )
- flip_buf_bits( &buf[mISDN_HEADER_LEN], len);
- else
- cb_log(6, stack->port, "Writing %d data bytes\n",len);
-
- cb_log(9, stack->port, "Writing %d bytes 2 mISDN\n",len);
- r=mISDN_write(stack->midev, buf, frm->len + mISDN_HEADER_LEN, TIMEOUT_INFINIT);
- return 0;
-}
-
-
-
-/*
- * send control information to the channel (dsp-module)
- */
-void manager_ph_control(struct misdn_bchannel *bc, int c1, int c2)
-{
- unsigned char buffer[mISDN_HEADER_LEN+2*sizeof(int)];
- iframe_t *ctrl = (iframe_t *)buffer; /* preload data */
- unsigned int *d = (unsigned int*)&ctrl->data.p;
- /*struct misdn_stack *stack=get_stack_by_bc(bc);*/
-
- cb_log(4,bc->port,"ph_control: c1:%x c2:%x\n",c1,c2);
-
- ctrl->prim = PH_CONTROL | REQUEST;
- ctrl->addr = bc->addr | FLG_MSG_DOWN;
- ctrl->dinfo = 0;
- ctrl->len = sizeof(unsigned int)*2;
- *d++ = c1;
- *d++ = c2;
- mISDN_write(glob_mgr->midev, ctrl, mISDN_HEADER_LEN+ctrl->len, TIMEOUT_1SEC);
-}
-
-/*
- * allow live control of channel parameters
- */
-void isdn_lib_update_rxgain (struct misdn_bchannel *bc)
-{
- manager_ph_control(bc, VOL_CHANGE_RX, bc->rxgain);
-}
-
-void isdn_lib_update_txgain (struct misdn_bchannel *bc)
-{
- manager_ph_control(bc, VOL_CHANGE_TX, bc->txgain);
-}
-
-void isdn_lib_update_ec (struct misdn_bchannel *bc)
-{
-#ifdef MISDN_1_2
- if (*bc->pipeline)
-#else
- if (bc->ec_enable)
-#endif
- manager_ec_enable(bc);
- else
- manager_ec_disable(bc);
-}
-
-void isdn_lib_stop_dtmf (struct misdn_bchannel *bc)
-{
- manager_ph_control(bc, DTMF_TONE_STOP, 0);
-}
-
-/*
- * send control information to the channel (dsp-module)
- */
-void manager_ph_control_block(struct misdn_bchannel *bc, int c1, void *c2, int c2_len)
-{
- unsigned char buffer[mISDN_HEADER_LEN+sizeof(int)+c2_len];
- iframe_t *ctrl = (iframe_t *)buffer;
- unsigned int *d = (unsigned int *)&ctrl->data.p;
- /*struct misdn_stack *stack=get_stack_by_bc(bc);*/
-
- ctrl->prim = PH_CONTROL | REQUEST;
- ctrl->addr = bc->addr | FLG_MSG_DOWN;
- ctrl->dinfo = 0;
- ctrl->len = sizeof(unsigned int) + c2_len;
- *d++ = c1;
- memcpy(d, c2, c2_len);
- mISDN_write(glob_mgr->midev, ctrl, mISDN_HEADER_LEN+ctrl->len, TIMEOUT_1SEC);
-}
-
-
-
-
-void manager_clean_bc(struct misdn_bchannel *bc )
-{
- struct misdn_stack *stack=get_stack_by_bc(bc);
-
- if (bc->channel>0)
- empty_chan_in_stack(stack, bc->channel);
- empty_bc(bc);
- bc->in_use=0;
-
- cb_event(EVENT_CLEANUP, bc, NULL);
-}
-
-
-void stack_holder_add(struct misdn_stack *stack, struct misdn_bchannel *holder)
-{
- struct misdn_bchannel *help;
- cb_log(4,stack->port, "*HOLDER: add %x\n",holder->l3_id);
-
- holder->stack_holder=1;
- holder->next=NULL;
-
- if (!stack->holding) {
- stack->holding = holder;
- return;
- }
-
- for (help=stack->holding;
- help;
- help=help->next) {
- if (!help->next) {
- help->next=holder;
- break;
- }
- }
-
-}
-
-void stack_holder_remove(struct misdn_stack *stack, struct misdn_bchannel *holder)
-{
- struct misdn_bchannel *h1;
-
- if (!holder->stack_holder) return;
-
- holder->stack_holder=0;
-
- cb_log(4,stack->port, "*HOLDER: remove %x\n",holder->l3_id);
- if (!stack || ! stack->holding) return;
-
- if (holder == stack->holding) {
- stack->holding = stack->holding->next;
- return;
- }
-
- for (h1=stack->holding;
- h1;
- h1=h1->next) {
- if (h1->next == holder) {
- h1->next=h1->next->next;
- return ;
- }
- }
-}
-
-struct misdn_bchannel *stack_holder_find_bychan(struct misdn_stack *stack, int chan)
-{
- struct misdn_bchannel *help;
-
- cb_log(4,stack?stack->port:0, "*HOLDER: find_bychan %c\n", chan);
-
- if (!stack) return NULL;
-
- for (help=stack->holding;
- help;
- help=help->next) {
- if (help->channel == chan) {
- cb_log(4,stack->port, "*HOLDER: found_bychan bc\n");
- return help;
- }
- }
-
- cb_log(4,stack->port, "*HOLDER: find_bychan nothing\n");
- return NULL;
-
-}
-
-struct misdn_bchannel *stack_holder_find(struct misdn_stack *stack, unsigned long l3id)
-{
- struct misdn_bchannel *help;
-
- cb_log(4,stack?stack->port:0, "*HOLDER: find %lx\n",l3id);
-
- if (!stack) return NULL;
-
- for (help=stack->holding;
- help;
- help=help->next) {
- if (help->l3_id == l3id) {
- cb_log(4,stack->port, "*HOLDER: found bc\n");
- return help;
- }
- }
-
- cb_log(4,stack->port, "*HOLDER: find nothing\n");
- return NULL;
-}
-
-
-
-void misdn_lib_send_tone(struct misdn_bchannel *bc, enum tone_e tone)
-{
- char buf[mISDN_HEADER_LEN + 128] = "";
- iframe_t *frm = (iframe_t*)buf;
-
- switch(tone) {
- case TONE_DIAL:
- manager_ph_control(bc, TONE_PATT_ON, TONE_GERMAN_DIALTONE);
- break;
-
- case TONE_ALERTING:
- manager_ph_control(bc, TONE_PATT_ON, TONE_GERMAN_RINGING);
- break;
-
- case TONE_HANGUP:
- manager_ph_control(bc, TONE_PATT_ON, TONE_GERMAN_HANGUP);
- break;
-
- case TONE_NONE:
- default:
- manager_ph_control(bc, TONE_PATT_OFF, TONE_GERMAN_HANGUP);
- }
-
- frm->prim=DL_DATA|REQUEST;
- frm->addr=bc->addr|FLG_MSG_DOWN;
- frm->dinfo=0;
- frm->len=128;
-
- mISDN_write(glob_mgr->midev, frm, mISDN_HEADER_LEN+frm->len, TIMEOUT_1SEC);
-}
-
-
-void manager_ec_enable(struct misdn_bchannel *bc)
-{
- struct misdn_stack *stack=get_stack_by_bc(bc);
-
- cb_log(4, stack?stack->port:0,"ec_enable\n");
-
- if (!misdn_cap_is_speech(bc->capability)) {
- cb_log(1, stack?stack->port:0, " --> no speech? cannot enable EC\n");
- } else {
-
-#ifdef MISDN_1_2
- if (*bc->pipeline) {
- cb_log(3, stack?stack->port:0,"Sending Control PIPELINE_CFG %s\n",bc->pipeline);
- manager_ph_control_block(bc, PIPELINE_CFG, bc->pipeline, strlen(bc->pipeline) + 1);
- }
-#else
- int ec_arr[2];
-
- if (bc->ec_enable) {
- cb_log(3, stack?stack->port:0,"Sending Control ECHOCAN_ON taps:%d\n",bc->ec_deftaps);
-
- switch (bc->ec_deftaps) {
- case 4:
- case 8:
- case 16:
- case 32:
- case 64:
- case 128:
- case 256:
- case 512:
- case 1024:
- cb_log(4, stack->port, "Taps is %d\n",bc->ec_deftaps);
- break;
- default:
- cb_log(0, stack->port, "Taps should be power of 2\n");
- bc->ec_deftaps=128;
- }
-
- ec_arr[0]=bc->ec_deftaps;
- ec_arr[1]=0;
-
- manager_ph_control_block(bc, ECHOCAN_ON, ec_arr, sizeof(ec_arr));
- }
-#endif
- }
-}
-
-
-
-void manager_ec_disable(struct misdn_bchannel *bc)
-{
- struct misdn_stack *stack=get_stack_by_bc(bc);
-
- cb_log(4, stack?stack->port:0," --> ec_disable\n");
-
- if (!misdn_cap_is_speech(bc->capability)) {
- cb_log(1, stack?stack->port:0, " --> no speech? cannot disable EC\n");
- return;
- }
-
-#ifdef MISDN_1_2
- manager_ph_control_block(bc, PIPELINE_CFG, "", 0);
-#else
- if ( ! bc->ec_enable) {
- cb_log(3, stack?stack->port:0, "Sending Control ECHOCAN_OFF\n");
- manager_ph_control(bc, ECHOCAN_OFF, 0);
- }
-#endif
-}
-
-struct misdn_stack* get_misdn_stack() {
- return glob_mgr->stack_list;
-}
-
-
-
-void misdn_join_conf(struct misdn_bchannel *bc, int conf_id)
-{
- char data[16] = "";
-
- bc_state_change(bc,BCHAN_BRIDGED);
- manager_ph_control(bc, CMX_RECEIVE_OFF, 0);
- manager_ph_control(bc, CMX_CONF_JOIN, conf_id);
-
- cb_log(3,bc->port, "Joining bc:%x in conf:%d\n",bc->addr,conf_id);
-
- misdn_lib_tx2misdn_frm(bc, data, sizeof(data) - 1);
-}
-
-
-void misdn_split_conf(struct misdn_bchannel *bc, int conf_id)
-{
- bc_state_change(bc,BCHAN_ACTIVATED);
- manager_ph_control(bc, CMX_RECEIVE_ON, 0);
- manager_ph_control(bc, CMX_CONF_SPLIT, conf_id);
-
- cb_log(4,bc->port, "Splitting bc:%x in conf:%d\n",bc->addr,conf_id);
-}
-
-void misdn_lib_bridge( struct misdn_bchannel * bc1, struct misdn_bchannel *bc2)
-{
- int conf_id = bc1->pid + 1;
- struct misdn_bchannel *bc_list[] = { bc1, bc2, NULL };
- struct misdn_bchannel **bc;
-
- cb_log(4, bc1->port, "I Send: BRIDGE from:%d to:%d\n",bc1->port,bc2->port);
-
- for (bc=bc_list; *bc; bc++) {
- (*bc)->conf_id=conf_id;
- cb_log(4, (*bc)->port, " --> bc_addr:%x\n",(*bc)->addr);
-
- switch((*bc)->bc_state) {
- case BCHAN_ACTIVATED:
- misdn_join_conf(*bc,conf_id);
- break;
- default:
- bc_next_state_change(*bc,BCHAN_BRIDGED);
- break;
- }
- }
-}
-
-void misdn_lib_split_bridge( struct misdn_bchannel * bc1, struct misdn_bchannel *bc2)
-{
-
- struct misdn_bchannel *bc_list[]={
- bc1,bc2,NULL
- };
- struct misdn_bchannel **bc;
-
- for (bc=bc_list; *bc; bc++) {
- if ( (*bc)->bc_state == BCHAN_BRIDGED){
- misdn_split_conf( *bc, (*bc)->conf_id);
- } else {
- cb_log( 2, (*bc)->port, "BC not bridged (state:%s) so not splitting it\n",bc_state2str((*bc)->bc_state));
- }
- }
-
-}
-
-
-
-void misdn_lib_echo(struct misdn_bchannel *bc, int onoff)
-{
- cb_log(3,bc->port, " --> ECHO %s\n", onoff?"ON":"OFF");
- manager_ph_control(bc, onoff?CMX_ECHO_ON:CMX_ECHO_OFF, 0);
-}
-
-
-
-void misdn_lib_reinit_nt_stack(int port)
-{
- struct misdn_stack *stack=find_stack_by_port(port);
-
- if (stack) {
- stack->l2link=0;
- stack->blocked=0;
-
- cleanup_Isdnl3(&stack->nst);
- cleanup_Isdnl2(&stack->nst);
-
-
- memset(&stack->nst, 0, sizeof(net_stack_t));
- memset(&stack->mgr, 0, sizeof(manager_t));
-
- stack->mgr.nst = &stack->nst;
- stack->nst.manager = &stack->mgr;
-
- stack->nst.l3_manager = handle_event_nt;
- stack->nst.device = glob_mgr->midev;
- stack->nst.cardnr = port;
- stack->nst.d_stid = stack->d_stid;
-
- stack->nst.feature = FEATURE_NET_HOLD;
- if (stack->ptp)
- stack->nst.feature |= FEATURE_NET_PTP;
- if (stack->pri)
- stack->nst.feature |= FEATURE_NET_CRLEN2 | FEATURE_NET_EXTCID;
-
- stack->nst.l1_id = stack->lower_id;
- stack->nst.l2_id = stack->upper_id;
-
- msg_queue_init(&stack->nst.down_queue);
-
- Isdnl2Init(&stack->nst);
- Isdnl3Init(&stack->nst);
-
- if (!stack->ptp)
- misdn_lib_get_l1_up(stack);
- misdn_lib_get_l2_up(stack);
- }
-}
-
-
diff --git a/1.4.23-rc4/channels/misdn/isdn_lib.h b/1.4.23-rc4/channels/misdn/isdn_lib.h
deleted file mode 100644
index 451876888..000000000
--- a/1.4.23-rc4/channels/misdn/isdn_lib.h
+++ /dev/null
@@ -1,674 +0,0 @@
-/*
- * Chan_Misdn -- Channel Driver for Asterisk
- *
- * Interface to mISDN
- *
- * Copyright (C) 2004, Christian Richter
- *
- * Christian Richter <crich@beronet.com>
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License
- */
-
-/*! \file
- * \brief Interface to mISDN
- *
- * \author Christian Richter <crich@beronet.com>
- */
-
-#ifndef TE_LIB
-#define TE_LIB
-
-#include <mISDNuser/suppserv.h>
-
-/** For initialization usage **/
-/* typedef int ie_nothing_t ;*/
-/** end of init usage **/
-
-
-/*
- * uncomment the following to make chan_misdn create
- * record files in /tmp/misdn-{rx|tx}-PortChannel format
- * */
-
-/*#define MISDN_SAVE_DATA*/
-
-#ifdef WITH_BEROEC
-typedef int beroec_t;
-
-
-enum beroec_type {
- BEROEC_FULLBAND=0,
- BEROEC_SUBBAND,
- BEROEC_FASTSUBBAND
-};
-
-void beroec_init(void);
-void beroec_exit(void);
-beroec_t *beroec_new(int tail, enum beroec_type type, int anti_howl,
- int tonedisable, int zerocoeff, int adapt, int nlp);
-
-void beroec_destroy(beroec_t *ec);
-int beroec_cancel_alaw_chunk(beroec_t *ec,
- char *send,
- char *receive,
- int len);
-
-int beroec_version(void);
-#endif
-
-
-
-enum tone_e {
- TONE_NONE=0,
- TONE_DIAL,
- TONE_ALERTING,
- TONE_FAR_ALERTING,
- TONE_BUSY,
- TONE_HANGUP,
- TONE_CUSTOM,
- TONE_FILE
-};
-
-
-
-#define MAX_BCHANS 31
-
-enum bchannel_state {
- BCHAN_CLEANED=0,
- BCHAN_EMPTY,
- BCHAN_SETUP,
- BCHAN_SETUPED,
- BCHAN_ACTIVE,
- BCHAN_ACTIVATED,
- BCHAN_BRIDGE,
- BCHAN_BRIDGED,
- BCHAN_RELEASE,
- BCHAN_RELEASED,
- BCHAN_CLEAN,
- BCHAN_CLEAN_REQUEST,
- BCHAN_ERROR
-};
-
-
-enum misdn_err_e {
- ENOCHAN=1
-};
-
-
-enum mISDN_NUMBER_PLAN {
- NUMPLAN_UNINITIALIZED=-1,
- NUMPLAN_INTERNATIONAL=0x1,
- NUMPLAN_NATIONAL=0x2,
- NUMPLAN_SUBSCRIBER=0x4,
- NUMPLAN_UNKNOWN=0x0
-};
-
-
-enum event_response_e {
- RESPONSE_IGNORE_SETUP_WITHOUT_CLOSE,
- RESPONSE_IGNORE_SETUP,
- RESPONSE_RELEASE_SETUP,
- RESPONSE_ERR,
- RESPONSE_OK
-};
-
-
-enum event_e {
- EVENT_NOTHING,
- EVENT_TONE_GENERATE,
- EVENT_BCHAN_DATA,
- EVENT_BCHAN_ACTIVATED,
- EVENT_BCHAN_ERROR,
- EVENT_CLEANUP,
- EVENT_PROCEEDING,
- EVENT_PROGRESS,
- EVENT_SETUP,
- EVENT_ALERTING,
- EVENT_CONNECT,
- EVENT_SETUP_ACKNOWLEDGE,
- EVENT_CONNECT_ACKNOWLEDGE ,
- EVENT_USER_INFORMATION,
- EVENT_SUSPEND_REJECT,
- EVENT_RESUME_REJECT,
- EVENT_HOLD,
- EVENT_SUSPEND,
- EVENT_RESUME,
- EVENT_HOLD_ACKNOWLEDGE,
- EVENT_SUSPEND_ACKNOWLEDGE,
- EVENT_RESUME_ACKNOWLEDGE,
- EVENT_HOLD_REJECT,
- EVENT_RETRIEVE,
- EVENT_RETRIEVE_ACKNOWLEDGE,
- EVENT_RETRIEVE_REJECT,
- EVENT_DISCONNECT,
- EVENT_RESTART,
- EVENT_RELEASE,
- EVENT_RELEASE_COMPLETE,
- EVENT_FACILITY,
- EVENT_NOTIFY,
- EVENT_STATUS_ENQUIRY,
- EVENT_INFORMATION,
- EVENT_STATUS,
- EVENT_TIMEOUT,
- EVENT_DTMF_TONE,
- EVENT_NEW_L3ID,
- EVENT_NEW_BC,
- EVENT_PORT_ALARM,
- EVENT_NEW_CHANNEL,
- EVENT_UNKNOWN
-};
-
-
-enum ie_name_e {
- IE_DUMMY,
- IE_LAST
-};
-
-enum { /* bearer capability */
- INFO_CAPABILITY_SPEECH=0,
- INFO_CAPABILITY_AUDIO_3_1K=0x10 ,
- INFO_CAPABILITY_AUDIO_7K=0x11 ,
- INFO_CAPABILITY_VIDEO =0x18,
- INFO_CAPABILITY_DIGITAL_UNRESTRICTED =0x8,
- INFO_CAPABILITY_DIGITAL_RESTRICTED =0x09,
- INFO_CAPABILITY_DIGITAL_UNRESTRICTED_TONES
-};
-
-enum { /* progress indicators */
- INFO_PI_CALL_NOT_E2E_ISDN =0x01,
- INFO_PI_CALLED_NOT_ISDN =0x02,
- INFO_PI_CALLER_NOT_ISDN =0x03,
- INFO_PI_CALLER_RETURNED_TO_ISDN =0x04,
- INFO_PI_INBAND_AVAILABLE =0x08,
- INFO_PI_DELAY_AT_INTERF =0x0a,
- INFO_PI_INTERWORKING_WITH_PUBLIC =0x10,
- INFO_PI_INTERWORKING_NO_RELEASE =0x11,
- INFO_PI_INTERWORKING_NO_RELEASE_PRE_ANSWER =0x12,
- INFO_PI_INTERWORKING_NO_RELEASE_POST_ANSWER =0x13
-};
-
-enum { /*CODECS*/
- INFO_CODEC_ULAW=2,
- INFO_CODEC_ALAW=3
-};
-
-
-enum layer_e {
- L3,
- L2,
- L1,
- UNKNOWN
-};
-
-
-
-struct misdn_bchannel {
- /*! \brief B channel send locking structure */
- struct send_lock *send_lock;
-
- /*! \brief TRUE if this is a dummy BC record */
- int dummy;
-
- /*! \brief TRUE if NT side of protocol (TE otherwise) */
- int nt;
-
- /*! \brief TRUE if ISDN-PRI (ISDN-BRI otherwise) */
- int pri;
-
- /*! \brief Logical Layer 1 port associated with this B channel */
- int port;
-
- /** init stuff **/
- /*! \brief B Channel mISDN driver stack ID */
- int b_stid;
-
- /* int b_addr; */
-
- /*! \brief B Channel mISDN driver layer ID from mISDN_new_layer() */
- int layer_id;
-
- /*! \brief B channel layer; set to 3 or 4 */
- int layer;
-
- /* state stuff */
- /*! \brief TRUE if DISCONNECT needs to be sent to clear a call */
- int need_disconnect;
-
- /*! \brief TRUE if RELEASE needs to be sent to clear a call */
- int need_release;
-
- /*! \brief TRUE if RELEASE_COMPLETE needs to be sent to clear a call */
- int need_release_complete;
-
- /*! \brief TRUE if allocate higher B channels first */
- int dec;
-
- /* var stuff */
- /*! \brief Layer 3 process ID */
- int l3_id;
-
- /*! \brief B channel process ID (1-5000) */
- int pid;
-
- /*! \brief Not used. Saved mISDN stack CONNECT_t ces value */
- int ces;
-
- /*! \brief B channel to restart if received a RESTART message */
- int restart_channel;
-
- /*! \brief Assigned B channel number B1, B2... 0 if not assigned */
- int channel;
-
- /*! \brief TRUE if the B channel number is preselected */
- int channel_preselected;
-
- /*! \brief TRUE if B channel record is in use */
- int in_use;
-
- /*! \brief Time when empty_bc() last called on this record */
- struct timeval last_used;
-
- /*! \brief TRUE if call waiting */
- int cw;
-
- /*! \brief B Channel mISDN driver layer ID from mISDN_get_layerid() */
- int addr;
-
- /*! \brief B channel speech sample data buffer */
- char *bframe;
-
- /*! \brief B channel speech sample data buffer size */
- int bframe_len;
- int time_usec; /* Not used */
-
- /*! \brief Not used. Contents are setup but not used. */
- void *astbuf;
-
- void *misdnbuf; /* Not used */
-
- /*! \brief TRUE if the TE side should choose the B channel to use
- * \note This value is user configurable in /etc/asterisk/misdn.conf
- */
- int te_choose_channel;
-
- /*! \brief TRUE if the call progress indicators can indicate an inband audio message for the user to listen to
- * \note This value is user configurable in /etc/asterisk/misdn.conf
- */
- int early_bconnect;
-
- /*! \brief Last decoded DTMF digit from mISDN driver */
- int dtmf;
-
- /*! \brief TRUE if we should produce DTMF tones ourselves
- * \note This value is user configurable in /etc/asterisk/misdn.conf
- */
- int send_dtmf;
-
- /*! \brief TRUE if we send SETUP_ACKNOWLEDGE on incoming calls anyway (instead of PROCEEDING).
- *
- * This requests additional INFORMATION messages, so we can
- * wait for digits without issues.
- * \note This value is user configurable in /etc/asterisk/misdn.conf
- */
- int need_more_infos;
-
- /*! \brief TRUE if all digits necessary to complete the call are available.
- * No more INFORMATION messages are needed.
- */
- int sending_complete;
-
-
- /*! \brief TRUE if we will not use jollys dsp */
- int nodsp;
-
- /*! \brief TRUE if we will not use the jitter buffer system */
- int nojitter;
-
- /*! \brief Type-of-number in ISDN terms for the dialed/called number
- * \note This value is set to "dialplan" in /etc/asterisk/misdn.conf for outgoing calls
- */
- enum mISDN_NUMBER_PLAN dnumplan;
-
- /*! \brief Type-of-number in ISDN terms for the redirecting number which a call diversion or transfer was invoked.
- * \note Collected from the incoming SETUP message but not used.
- */
- enum mISDN_NUMBER_PLAN rnumplan;
-
- /*! \brief Type-of-number in ISDN terms for the originating/calling number (Caller-ID)
- * \note This value is set to "localdialplan" in /etc/asterisk/misdn.conf for outgoing calls
- */
- enum mISDN_NUMBER_PLAN onumplan;
-
- /*! \brief Type-of-number in ISDN terms for the connected party number
- * \note This value is set to "cpndialplan" in /etc/asterisk/misdn.conf for outgoing calls
- */
- enum mISDN_NUMBER_PLAN cpnnumplan;
-
- /*! \brief Progress Indicator IE coding standard field.
- * \note Collected from the incoming messages but not used.
- */
- int progress_coding;
-
- /*! \brief Progress Indicator IE location field.
- * \note Collected from the incoming messages but not used.
- */
- int progress_location;
-
- /*! \brief Progress Indicator IE progress description field.
- * Used to determine if there is an inband audio message present.
- */
- int progress_indicator;
-
- /*! \brief Inbound FACILITY message function type and contents */
- struct FacParm fac_in;
-
- /*! \brief Outbound FACILITY message function type and contents.
- * \note Filled in by misdn facility commands before FACILITY message sent.
- */
- struct FacParm fac_out;
-
- /* storing the current AOCD info here */
- enum FacFunction AOCDtype;
- union {
- struct FacAOCDCurrency currency;
- struct FacAOCDChargingUnit chargingUnit;
- } AOCD;
-
- /*! \brief Event waiting for Layer 1 to come up */
- enum event_e evq;
-
- /*** CRYPTING STUFF ***/
- int crypt; /* Initialized, Not used */
- int curprx; /* Initialized, Not used */
- int curptx; /* Initialized, Not used */
-
- /*! \brief Blowfish encryption key string (secret) */
- char crypt_key[255];
-
- int crypt_state; /* Not used */
- /*** CRYPTING STUFF END***/
-
- /*! \brief Seems to have been intended for something to do with the jitter buffer.
- * \note Used as a boolean. Only initialized to 0 and referenced in a couple places
- */
- int active;
- int upset; /* Not used */
-
- /*! \brief TRUE if tone generator allowed to start */
- int generate_tone;
-
- /*! \brief Number of tone samples to generate */
- int tone_cnt;
-
- /*! \brief Current B Channel state */
- enum bchannel_state bc_state;
-
- /*! \brief This is used as a pending bridge join request for when bc_state becomes BCHAN_ACTIVATED */
- enum bchannel_state next_bc_state;
-
- /*! \brief Bridging conference ID */
- int conf_id;
-
- /*! \brief TRUE if this channel is on hold */
- int holded;
-
- /*! \brief TRUE if this channel is on the misdn_stack->holding list
- * \note If TRUE this implies that the structure is also malloced.
- */
- int stack_holder;
-
- /*! \brief Caller ID presentation restriction code
- * 0=Allowed, 1=Restricted, 2=Unavailable
- * \note It is settable by the misdn_set_opt() application.
- */
- int pres;
-
- /*! \brief Caller ID screening code
- * 0=Unscreened, 1=Passed Screen, 2=Failed Screen, 3=Network Number
- */
- int screen;
-
- /*! \brief SETUP message bearer capability field code value */
- int capability;
-
- /*! \brief Companding ALaw/uLaw encoding (INFO_CODEC_ALAW / INFO_CODEC_ULAW) */
- int law;
-
- /* V110 Stuff */
- /*! \brief Q.931 Bearer Capability IE Information Transfer Rate field. Initialized to 0x10 (64kbit). Altered by incoming SETUP messages. */
- int rate;
-
- /*! \brief Q.931 Bearer Capability IE Transfer Mode field. Initialized to 0 (Circuit). Altered by incoming SETUP messages. */
- int mode;
-
- /*! \brief Q.931 Bearer Capability IE User Information Layer 1 Protocol field code.
- * \note Collected from the incoming SETUP message but not used.
- */
- int user1;
-
- /*! \brief Q.931 Bearer Capability IE Layer 1 User Rate field.
- * \note Collected from the incoming SETUP message and exported to Asterisk variable MISDN_URATE.
- */
- int urate;
-
- /*! \brief TRUE if call made in digital HDLC mode
- * \note This value is user configurable in /etc/asterisk/misdn.conf.
- * It is also settable by the misdn_set_opt() application.
- */
- int hdlc;
- /* V110 */
-
- /*! \brief Display message that can be displayed by the user phone.
- * \note Maximum displayable length is 34 or 82 octets.
- * It is also settable by the misdn_set_opt() application.
- */
- char display[84];
-
- /*! \brief Not used. Contents are setup but not used. */
- char msn[32];
-
- /*! \brief Originating/Calling Phone Number (Address)
- * \note This value can be set to "callerid" in /etc/asterisk/misdn.conf for outgoing calls
- */
- char oad[32];
-
- /*! \brief Redirecting Phone Number (Address) where a call diversion or transfer was invoked */
- char rad[32];
-
- /*! \brief Dialed/Called Phone Number (Address) */
- char dad[32];
-
- /*! \brief Connected Party/Line Phone Number (Address) */
- char cad[32];
-
- /*! \brief Original Dialed/Called Phone Number (Address) before national/international dialing prefix added.
- * \note Not used. Contents are setup but not used.
- */
- char orig_dad[32];
-
- /*! \brief Q.931 Keypad Facility IE contents
- * \note Contents exported and imported to Asterisk variable MISDN_KEYPAD
- */
- char keypad[32];
-
- /*! \brief Current overlap dialing digits to/from INFORMATION messages */
- char info_dad[64];
-
- /*! \brief Collected digits to go into info_dad[] while waiting for a SETUP_ACKNOWLEDGE to come in. */
- char infos_pending[64];
-
-/* unsigned char info_keypad[32]; */
-/* unsigned char clisub[24]; */
-/* unsigned char cldsub[24]; */
-
- /*! \brief User-User information string.
- * \note Contents exported and imported to Asterisk variable MISDN_USERUSER
- * \note We only support ASCII strings (IA5 characters).
- */
- char uu[256];
-
- /*! \brief User-User information string length in uu[] */
- int uulen;
-
- /*! \brief Q.931 Cause for disconnection code (received)
- * \note Need to use the AST_CAUSE_xxx code definitions in causes.h
- */
- int cause;
-
- /*! \brief Q.931 Cause for disconnection code (sent)
- * \note Need to use the AST_CAUSE_xxx code definitions in causes.h
- * \note -1 is used to suppress including the cause code in the RELEASE message.
- */
- int out_cause;
-
- /* struct misdn_bchannel hold_bc; */
-
- /** list stuf **/
-
-#ifdef MISDN_1_2
- /*! \brief The configuration string for the mISDN dsp pipeline in /etc/asterisk/misdn.conf. */
- char pipeline[128];
-#else
- /*! \brief TRUE if the echo cancellor is enabled */
- int ec_enable;
-
- /*! \brief Number of taps in the echo cancellor when enabled.
- * \note This value is user configurable in /etc/asterisk/misdn.conf (echocancel)
- */
- int ec_deftaps;
-#endif
-
- /*! \brief TRUE if the channel was allocated from the available B channels */
- int channel_found;
-
- /*! \brief Who originated the call (ORG_AST, ORG_MISDN)
- * \note Set but not used when the misdn_set_opt() application enables echo cancellation.
- */
- int orig;
-
- /*! \brief Tx gain setting (range -8 to 8)
- * \note This value is user configurable in /etc/asterisk/misdn.conf.
- * It is also settable by the misdn_set_opt() application.
- */
- int txgain;
-
- /*! \brief Rx gain setting (range -8 to 8)
- * \note This value is user configurable in /etc/asterisk/misdn.conf.
- * It is also settable by the misdn_set_opt() application.
- */
- int rxgain;
-
- /*! \brief Next node in the misdn_stack.holding list */
- struct misdn_bchannel *next;
-};
-
-
-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);
-
-struct misdn_lib_iface {
- 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);
-};
-
-/***** USER IFACE **********/
-
-void misdn_lib_nt_keepcalls(int kc);
-
-void misdn_lib_nt_debug_init( int flags, char *file );
-
-int misdn_lib_init(char *portlist, struct misdn_lib_iface* iface, void *user_data);
-int misdn_lib_send_event(struct misdn_bchannel *bc, enum event_e event );
-void misdn_lib_destroy(void);
-
-void misdn_lib_isdn_l1watcher(int port);
-
-void misdn_lib_log_ies(struct misdn_bchannel *bc);
-
-char *manager_isdn_get_info(enum event_e event);
-
-void misdn_lib_transfer(struct misdn_bchannel* holded_bc);
-
-struct misdn_bchannel* misdn_lib_get_free_bc(int port, int channel, int inout, int dec);
-
-void manager_bchannel_activate(struct misdn_bchannel *bc);
-void manager_bchannel_deactivate(struct misdn_bchannel * bc);
-
-int misdn_lib_tx2misdn_frm(struct misdn_bchannel *bc, void *data, int len);
-
-void manager_ph_control(struct misdn_bchannel *bc, int c1, int c2);
-
-void isdn_lib_update_rxgain (struct misdn_bchannel *bc);
-void isdn_lib_update_txgain (struct misdn_bchannel *bc);
-void isdn_lib_update_ec (struct misdn_bchannel *bc);
-void isdn_lib_stop_dtmf (struct misdn_bchannel *bc);
-
-int misdn_lib_port_restart(int port);
-int misdn_lib_pid_restart(int pid);
-int misdn_lib_send_restart(int port, int channel);
-
-int misdn_lib_get_port_info(int port);
-
-int misdn_lib_is_port_blocked(int port);
-int misdn_lib_port_block(int port);
-int misdn_lib_port_unblock(int port);
-
-int misdn_lib_port_is_pri(int port);
-
-int misdn_lib_port_up(int port, int notcheck);
-
-int misdn_lib_get_port_down(int port);
-
-int misdn_lib_get_port_up (int port) ;
-
-int misdn_lib_maxports_get(void) ;
-
-void misdn_lib_release(struct misdn_bchannel *bc);
-
-int misdn_cap_is_speech(int cap);
-int misdn_inband_avail(struct misdn_bchannel *bc);
-
-void manager_ec_enable(struct misdn_bchannel *bc);
-void manager_ec_disable(struct misdn_bchannel *bc);
-
-void misdn_lib_send_tone(struct misdn_bchannel *bc, enum tone_e tone);
-
-void get_show_stack_details(int port, char *buf);
-
-
-void misdn_lib_tone_generator_start(struct misdn_bchannel *bc);
-void misdn_lib_tone_generator_stop(struct misdn_bchannel *bc);
-
-
-void misdn_lib_setup_bc(struct misdn_bchannel *bc);
-
-void misdn_lib_bridge( struct misdn_bchannel * bc1, struct misdn_bchannel *bc2);
-void misdn_lib_split_bridge( struct misdn_bchannel * bc1, struct misdn_bchannel *bc2);
-
-void misdn_lib_echo(struct misdn_bchannel *bc, int onoff);
-
-int misdn_lib_is_ptp(int port);
-int misdn_lib_get_maxchans(int port);
-
-void misdn_lib_reinit_nt_stack(int port);
-
-#define PRI_TRANS_CAP_SPEECH 0x0
-#define PRI_TRANS_CAP_DIGITAL 0x08
-#define PRI_TRANS_CAP_RESTRICTED_DIGITAL 0x09
-#define PRI_TRANS_CAP_3_1K_AUDIO 0x10
-#define PRI_TRANS_CAP_7K_AUDIO 0x11
-
-
-
-char *bc_state2str(enum bchannel_state state);
-void bc_state_change(struct misdn_bchannel *bc, enum bchannel_state state);
-
-void misdn_dump_chanlist(void);
-
-#endif
diff --git a/1.4.23-rc4/channels/misdn/isdn_lib_intern.h b/1.4.23-rc4/channels/misdn/isdn_lib_intern.h
deleted file mode 100644
index 93d879744..000000000
--- a/1.4.23-rc4/channels/misdn/isdn_lib_intern.h
+++ /dev/null
@@ -1,142 +0,0 @@
-#ifndef ISDN_LIB_INTERN
-#define ISDN_LIB_INTERN
-
-
-#include <mISDNuser/mISDNlib.h>
-#include <mISDNuser/isdn_net.h>
-#include <mISDNuser/l3dss1.h>
-#include <mISDNuser/net_l3.h>
-
-#include <pthread.h>
-
-#include "isdn_lib.h"
-
-#if !defined MISDNUSER_VERSION_CODE || (MISDNUSER_VERSION_CODE < MISDNUSER_VERSION(1, 0, 3))
-#error "You need a newer version of mISDNuser ..."
-#endif
-
-
-#define QI_ELEMENT(a) a.off
-
-
-#ifndef mISDNUSER_HEAD_SIZE
-
-#define mISDNUSER_HEAD_SIZE (sizeof(mISDNuser_head_t))
-/*#define mISDNUSER_HEAD_SIZE (sizeof(mISDN_head_t))*/
-#endif
-
-
-ibuffer_t *astbuf; /* Not used */
-ibuffer_t *misdnbuf; /* Not used */
-
-struct send_lock {
- pthread_mutex_t lock;
-};
-
-
-struct isdn_msg {
- unsigned long misdn_msg;
-
- enum layer_e layer;
- enum event_e event;
-
- void (*msg_parser)(struct isdn_msg *msgs, msg_t *msg, struct misdn_bchannel *bc, int nt);
- msg_t *(*msg_builder)(struct isdn_msg *msgs, struct misdn_bchannel *bc, int nt);
- char *info;
-} ;
-
-/* for isdn_msg_parser.c */
-msg_t *create_l3msg(int prim, int mt, int dinfo , int size, int nt);
-
-
-
-struct misdn_stack {
- /** is first element because &nst equals &mISDNlist **/
- net_stack_t nst;
- manager_t mgr;
-
- /*! \brief D Channel mISDN driver stack ID (Parent stack ID) */
- int d_stid;
-
- /*! /brief Number of B channels supported by this port */
- int b_num;
-
- /*! \brief B Channel mISDN driver stack IDs (Child stack IDs) */
- int b_stids[MAX_BCHANS + 1];
-
- /*! \brief TRUE if Point-To-Point(PTP) (Point-To-Multipoint(PTMP) otherwise) */
- int ptp;
-
- /*! \brief Number of consecutive times PTP Layer 2 declared down */
- int l2upcnt;
-
- int l2_id; /* Not used */
-
- /*! \brief Lower layer mISDN ID (addr) (Layer 1/3) */
- int lower_id;
-
- /*! \brief Upper layer mISDN ID (addr) (Layer 2/4) */
- int upper_id;
-
- /*! \brief TRUE if port is blocked */
- int blocked;
-
- /*! \brief TRUE if Layer 2 is UP */
- int l2link;
-
- time_t l2establish; /* Not used */
-
- /*! \brief TRUE if Layer 1 is UP */
- int l1link;
-
- /*! \brief TRUE if restart has been sent to the other side after stack startup */
- int restart_sent;
-
- /*! \brief mISDN device handle returned by mISDN_open() */
- int midev;
-
- /*! \brief TRUE if NT side of protocol (TE otherwise) */
- int nt;
-
- /*! \brief TRUE if ISDN-PRI (ISDN-BRI otherwise) */
- int pri;
-
- /*! \brief CR Process ID allocation table. TRUE if ID allocated */
- int procids[0x100+1];
-
- /*! \brief Queue of Event messages to send to mISDN */
- msg_queue_t downqueue;
- msg_queue_t upqueue; /* No code puts anything on this queue */
- int busy; /* Not used */
-
- /*! \brief Logical Layer 1 port associated with this stack */
- int port;
-
- /*! \brief B Channel record pool array */
- struct misdn_bchannel bc[MAX_BCHANS + 1];
-
- struct misdn_bchannel* bc_list; /* Not used */
-
- /*! \brief Array of B channels in use (a[0] = B1). TRUE if B channel in use */
- int channels[MAX_BCHANS + 1];
-
- /*! \brief List of holded channels */
- struct misdn_bchannel *holding;
-
- /*! \brief Next stack in the list of stacks */
- struct misdn_stack *next;
-};
-
-
-struct misdn_stack* get_stack_by_bc(struct misdn_bchannel *bc);
-
-int isdn_msg_get_index(struct isdn_msg msgs[], msg_t *frm, int nt);
-enum event_e isdn_msg_get_event(struct isdn_msg msgs[], msg_t *frm, int nt);
-int isdn_msg_parse_event(struct isdn_msg msgs[], msg_t *frm, struct misdn_bchannel *bc, int nt);
-char * isdn_get_info(struct isdn_msg msgs[], enum event_e event, int nt);
-msg_t * isdn_msg_build_event(struct isdn_msg msgs[], struct misdn_bchannel *bc, enum event_e event, int nt);
-int isdn_msg_get_index_by_event(struct isdn_msg msgs[], enum event_e event, int nt);
-char * isdn_msg_get_info(struct isdn_msg msgs[], msg_t *msg, int nt);
-
-
-#endif
diff --git a/1.4.23-rc4/channels/misdn/isdn_msg_parser.c b/1.4.23-rc4/channels/misdn/isdn_msg_parser.c
deleted file mode 100644
index a587f8eae..000000000
--- a/1.4.23-rc4/channels/misdn/isdn_msg_parser.c
+++ /dev/null
@@ -1,1348 +0,0 @@
-/*
- * Chan_Misdn -- Channel Driver for Asterisk
- *
- * Interface to mISDN
- *
- * Copyright (C) 2004, Christian Richter
- *
- * Christian Richter <crich@beronet.com>
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License
- */
-
-
-#include "isdn_lib_intern.h"
-
-
-#include "isdn_lib.h"
-
-#include "ie.c"
-
-
-static void set_channel(struct misdn_bchannel *bc, int channel)
-{
-
- cb_log(3,bc->port,"set_channel: bc->channel:%d channel:%d\n", bc->channel, channel);
-
-
- if (channel==0xff) {
- /* any channel */
- channel=-1;
- }
-
- /* ALERT: is that everytime true ? */
- if (channel > 0 && bc->nt ) {
-
- if (bc->channel && ( bc->channel != 0xff) ) {
- cb_log(0,bc->port,"We already have a channel (%d)\n", bc->channel);
- } else {
- bc->channel = channel;
- cb_event(EVENT_NEW_CHANNEL,bc,NULL);
- }
- }
-
- if (channel > 0 && !bc->nt ) {
- bc->channel = channel;
- cb_event(EVENT_NEW_CHANNEL,bc,NULL);
- }
-}
-
-static void parse_proceeding (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
-{
- int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
- CALL_PROCEEDING_t *proceeding=(CALL_PROCEEDING_t*)((unsigned long)msg->data+ HEADER_LEN);
- //struct misdn_stack *stack=get_stack_by_bc(bc);
-
- {
- int exclusive, channel;
- dec_ie_channel_id(proceeding->CHANNEL_ID, (Q931_info_t *)proceeding, &exclusive, &channel, nt,bc);
-
- set_channel(bc,channel);
-
- }
-
- dec_ie_progress(proceeding->PROGRESS, (Q931_info_t *)proceeding, &bc->progress_coding, &bc->progress_location, &bc->progress_indicator, nt, bc);
-
-
-#if DEBUG
- printf("Parsing PROCEEDING Msg\n");
-#endif
-}
-static msg_t *build_proceeding (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
-{
- int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
- CALL_PROCEEDING_t *proceeding;
- msg_t *msg =(msg_t*)create_l3msg(CC_PROCEEDING | REQUEST, MT_CALL_PROCEEDING, bc?bc->l3_id:-1, sizeof(CALL_PROCEEDING_t) ,nt);
-
- proceeding=(CALL_PROCEEDING_t*)((msg->data+HEADER_LEN));
-
- enc_ie_channel_id(&proceeding->CHANNEL_ID, msg, 1,bc->channel, nt,bc);
-
- if (nt)
- enc_ie_progress(&proceeding->PROGRESS, msg, 0, nt?1:5, 8, nt,bc);
-
-
-#if DEBUG
- printf("Building PROCEEDING Msg\n");
-#endif
- return msg;
-}
-
-static void parse_alerting (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
-{
- int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
- ALERTING_t *alerting=(ALERTING_t*)((unsigned long)(msg->data+HEADER_LEN));
- //Q931_info_t *qi=(Q931_info_t*)(msg->data+HEADER_LEN);
-
- dec_ie_progress(alerting->PROGRESS, (Q931_info_t *)alerting, &bc->progress_coding, &bc->progress_location, &bc->progress_indicator, nt, bc);
-
-#if DEBUG
- printf("Parsing ALERTING Msg\n");
-#endif
-
-
-}
-
-static msg_t *build_alerting (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
-{
- int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
- ALERTING_t *alerting;
- msg_t *msg =(msg_t*)create_l3msg(CC_ALERTING | REQUEST, MT_ALERTING, bc?bc->l3_id:-1, sizeof(ALERTING_t) ,nt);
-
- alerting=(ALERTING_t*)((msg->data+HEADER_LEN));
-
- enc_ie_channel_id(&alerting->CHANNEL_ID, msg, 1,bc->channel, nt,bc);
-
- if (nt)
- enc_ie_progress(&alerting->PROGRESS, msg, 0, nt?1:5, 8, nt,bc);
-#if DEBUG
- printf("Building ALERTING Msg\n");
-#endif
- return msg;
-}
-
-
-static void parse_progress (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
-{
- int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
- PROGRESS_t *progress=(PROGRESS_t*)((unsigned long)(msg->data+HEADER_LEN));
- //Q931_info_t *qi=(Q931_info_t*)(msg->data+HEADER_LEN);
-
- dec_ie_progress(progress->PROGRESS, (Q931_info_t *)progress, &bc->progress_coding, &bc->progress_location, &bc->progress_indicator, nt, bc);
-
-#if DEBUG
- printf("Parsing PROGRESS Msg\n");
-#endif
-}
-
-static msg_t *build_progress (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
-{
- int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
- PROGRESS_t *progress;
- msg_t *msg =(msg_t*)create_l3msg(CC_PROGRESS | REQUEST, MT_PROGRESS, bc?bc->l3_id:-1, sizeof(PROGRESS_t) ,nt);
-
- progress=(PROGRESS_t*)((msg->data+HEADER_LEN));
-
-#if DEBUG
- printf("Building PROGRESS Msg\n");
-#endif
- return msg;
-}
-
-static void parse_setup (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
-{
- int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
- SETUP_t *setup= (SETUP_t*)((unsigned long)msg->data+HEADER_LEN);
- Q931_info_t *qi=(Q931_info_t*)((unsigned long)msg->data+HEADER_LEN);
-
-#if DEBUG
- printf("Parsing SETUP Msg\n");
-#endif
- {
- int type,plan,present, screen;
- char id[32];
- dec_ie_calling_pn(setup->CALLING_PN, qi, &type, &plan, &present, &screen, id, sizeof(id)-1, nt,bc);
-
- bc->onumplan=type;
- strcpy(bc->oad, id);
- switch (present) {
- case 0:
- bc->pres=0; /* screened */
- break;
- case 1:
- bc->pres=1; /* not screened */
- break;
- default:
- bc->pres=0;
- }
- switch (screen) {
- case 0:
- break;
- default:
- ;
- }
- }
- {
- int type, plan;
- char number[32];
- dec_ie_called_pn(setup->CALLED_PN, (Q931_info_t *)setup, &type, &plan, number, sizeof(number)-1, nt,bc);
- strcpy(bc->dad, number);
- bc->dnumplan=type;
- }
- {
- char keypad[32];
- dec_ie_keypad(setup->KEYPAD, (Q931_info_t *)setup, keypad, sizeof(keypad)-1, nt,bc);
- strcpy(bc->keypad, keypad);
- }
-
- {
- dec_ie_complete(setup->COMPLETE, (Q931_info_t *)setup, &bc->sending_complete, nt,bc);
-
- }
-
- {
- int type, plan, present, screen, reason;
- char id[32];
- dec_ie_redir_nr(setup->REDIR_NR, (Q931_info_t *)setup, &type, &plan, &present, &screen, &reason, id, sizeof(id)-1, nt,bc);
-
- strcpy(bc->rad, id);
- bc->rnumplan=type;
- }
- {
- int coding, capability, mode, rate, multi, user, async, urate, stopbits, dbits, parity;
- dec_ie_bearer(setup->BEARER, (Q931_info_t *)setup, &coding, &capability, &mode, &rate, &multi, &user, &async, &urate, &stopbits, &dbits, &parity, nt,bc);
- switch (capability) {
- case -1: bc->capability=INFO_CAPABILITY_DIGITAL_UNRESTRICTED;
- break;
- case 0: bc->capability=INFO_CAPABILITY_SPEECH;
- break;
- case 18: bc->capability=INFO_CAPABILITY_VIDEO;
- break;
- case 8: bc->capability=INFO_CAPABILITY_DIGITAL_UNRESTRICTED;
- bc->user1 = user;
- bc->urate = urate;
-
- bc->rate = rate;
- bc->mode = mode;
- break;
- case 9: bc->capability=INFO_CAPABILITY_DIGITAL_RESTRICTED;
- break;
- default:
- break;
- }
-
- switch(user) {
- case 2:
- bc->law=INFO_CODEC_ULAW;
- break;
- case 3:
- bc->law=INFO_CODEC_ALAW;
- break;
- default:
- bc->law=INFO_CODEC_ALAW;
-
- }
-
- bc->capability=capability;
- }
- {
- int exclusive, channel;
- dec_ie_channel_id(setup->CHANNEL_ID, (Q931_info_t *)setup, &exclusive, &channel, nt,bc);
-
- set_channel(bc,channel);
- }
-
- {
- int protocol ;
- dec_ie_useruser(setup->USER_USER, (Q931_info_t *)setup, &protocol, bc->uu, &bc->uulen, nt,bc);
- if (bc->uulen) cb_log(1,bc->port,"USERUESRINFO:%s\n",bc->uu);
- else
- cb_log(1,bc->port,"NO USERUESRINFO\n");
- }
-
- dec_ie_progress(setup->PROGRESS, (Q931_info_t *)setup, &bc->progress_coding, &bc->progress_location, &bc->progress_indicator, nt, bc);
-
-}
-
-#define ANY_CHANNEL 0xff /* IE attribut for 'any channel' */
-static msg_t *build_setup (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
-{
- int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
- SETUP_t *setup;
- msg_t *msg =(msg_t*)create_l3msg(CC_SETUP | REQUEST, MT_SETUP, bc?bc->l3_id:-1, sizeof(SETUP_t) ,nt);
-
- setup=(SETUP_t*)((msg->data+HEADER_LEN));
-
- if (bc->channel == 0 || bc->channel == ANY_CHANNEL || bc->channel==-1)
- enc_ie_channel_id(&setup->CHANNEL_ID, msg, 0, bc->channel, nt,bc);
- else
- enc_ie_channel_id(&setup->CHANNEL_ID, msg, 1, bc->channel, nt,bc);
-
-
- {
- int type=bc->onumplan,plan=1,present=bc->pres,screen=bc->screen;
- enc_ie_calling_pn(&setup->CALLING_PN, msg, type, plan, present,
- screen, bc->oad, nt, bc);
- }
-
- {
- if (bc->dad[0])
- enc_ie_called_pn(&setup->CALLED_PN, msg, bc->dnumplan, 1, bc->dad, nt,bc);
- }
-
- {
- if (bc->rad[0])
- enc_ie_redir_nr(&setup->REDIR_NR, msg, 1, 1, bc->pres, bc->screen, 0, bc->rad, nt,bc);
- }
-
- {
- if (bc->keypad[0])
- enc_ie_keypad(&setup->KEYPAD, msg, bc->keypad, nt,bc);
- }
-
-
- if (*bc->display) {
- enc_ie_display(&setup->DISPLAY, msg, bc->display, nt,bc);
- }
-
- {
- int coding=0, capability, mode=0 /* 2 for packet ! */
- ,user, rate=0x10;
-
- switch (bc->law) {
- case INFO_CODEC_ULAW: user=2;
- break;
- case INFO_CODEC_ALAW: user=3;
- break;
- default:
- user=3;
- }
-
- switch (bc->capability) {
- case INFO_CAPABILITY_SPEECH: capability = 0;
- break;
- case INFO_CAPABILITY_DIGITAL_UNRESTRICTED: capability = 8;
- user=-1;
- mode=bc->mode;
- rate=bc->rate;
- break;
- case INFO_CAPABILITY_DIGITAL_RESTRICTED: capability = 9;
- user=-1;
- break;
- default:
- capability=bc->capability;
- }
-
-
-
- enc_ie_bearer(&setup->BEARER, msg, coding, capability, mode, rate, -1, user, nt,bc);
- }
-
- if (bc->sending_complete) {
- enc_ie_complete(&setup->COMPLETE,msg, bc->sending_complete, nt, bc);
- }
-
- if (bc->uulen) {
- int protocol=4;
- enc_ie_useruser(&setup->USER_USER, msg, protocol, bc->uu, bc->uulen, nt,bc);
- cb_log(1,bc->port,"ENCODING USERUESRINFO:%s\n",bc->uu);
- }
-
-#if DEBUG
- printf("Building SETUP Msg\n");
-#endif
- return msg;
-}
-
-static void parse_connect (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
-{
- int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
- CONNECT_t *connect=(CONNECT_t*)((unsigned long)(msg->data+HEADER_LEN));
-
- int plan,pres,screen;
-
- bc->ces = connect->ces;
- bc->ces = connect->ces;
-
- dec_ie_progress(connect->PROGRESS, (Q931_info_t *)connect, &bc->progress_coding, &bc->progress_location, &bc->progress_indicator, nt, bc);
-
- dec_ie_connected_pn(connect->CONNECT_PN,(Q931_info_t *)connect, &bc->cpnnumplan, &plan, &pres, &screen, bc->cad, 31, nt, bc);
-
- /*
- cb_log(1,bc->port,"CONNETED PN: %s cpn_dialplan:%d\n", connected_pn, type);
- */
-
-#if DEBUG
- printf("Parsing CONNECT Msg\n");
-#endif
-}
-
-static msg_t *build_connect (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
-{
- int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
- CONNECT_t *connect;
- msg_t *msg =(msg_t*)create_l3msg(CC_CONNECT | REQUEST, MT_CONNECT, bc?bc->l3_id:-1, sizeof(CONNECT_t) ,nt);
-
- cb_log(6,bc->port,"BUILD_CONNECT: bc:%p bc->l3id:%d, nt:%d\n",bc,bc->l3_id,nt);
-
- connect=(CONNECT_t*)((msg->data+HEADER_LEN));
-
- if (nt) {
- time_t now;
- time(&now);
- enc_ie_date(&connect->DATE, msg, now, nt,bc);
- }
-
- {
- int type=bc->cpnnumplan, plan=1, present=2, screen=0;
- enc_ie_connected_pn(&connect->CONNECT_PN, msg, type,plan, present, screen, bc->cad, nt , bc);
- }
-
-#if DEBUG
- printf("Building CONNECT Msg\n");
-#endif
- return msg;
-}
-
-static void parse_setup_acknowledge (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
-{
- int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
- SETUP_ACKNOWLEDGE_t *setup_acknowledge=(SETUP_ACKNOWLEDGE_t*)((unsigned long)(msg->data+HEADER_LEN));
-
- {
- int exclusive, channel;
- dec_ie_channel_id(setup_acknowledge->CHANNEL_ID, (Q931_info_t *)setup_acknowledge, &exclusive, &channel, nt,bc);
-
-
- set_channel(bc, channel);
- }
-
- dec_ie_progress(setup_acknowledge->PROGRESS, (Q931_info_t *)setup_acknowledge, &bc->progress_coding, &bc->progress_location, &bc->progress_indicator, nt, bc);
-#if DEBUG
- printf("Parsing SETUP_ACKNOWLEDGE Msg\n");
-#endif
-
-
-}
-
-static msg_t *build_setup_acknowledge (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
-{
- int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
- SETUP_ACKNOWLEDGE_t *setup_acknowledge;
- msg_t *msg =(msg_t*)create_l3msg(CC_SETUP_ACKNOWLEDGE | REQUEST, MT_SETUP_ACKNOWLEDGE, bc?bc->l3_id:-1, sizeof(SETUP_ACKNOWLEDGE_t) ,nt);
-
- setup_acknowledge=(SETUP_ACKNOWLEDGE_t*)((msg->data+HEADER_LEN));
-
- enc_ie_channel_id(&setup_acknowledge->CHANNEL_ID, msg, 1,bc->channel, nt,bc);
-
- if (nt)
- enc_ie_progress(&setup_acknowledge->PROGRESS, msg, 0, nt?1:5, 8, nt,bc);
-
-#if DEBUG
- printf("Building SETUP_ACKNOWLEDGE Msg\n");
-#endif
- return msg;
-}
-
-static void parse_connect_acknowledge (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
-{
-#if DEBUG
- printf("Parsing CONNECT_ACKNOWLEDGE Msg\n");
-#endif
-
-
-}
-
-static msg_t *build_connect_acknowledge (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
-{
- int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
- CONNECT_ACKNOWLEDGE_t *connect_acknowledge;
- msg_t *msg =(msg_t*)create_l3msg(CC_CONNECT | RESPONSE, MT_CONNECT, bc?bc->l3_id:-1, sizeof(CONNECT_ACKNOWLEDGE_t) ,nt);
-
- connect_acknowledge=(CONNECT_ACKNOWLEDGE_t*)((msg->data+HEADER_LEN));
-
- enc_ie_channel_id(&connect_acknowledge->CHANNEL_ID, msg, 1, bc->channel, nt,bc);
-
-#if DEBUG
- printf("Building CONNECT_ACKNOWLEDGE Msg\n");
-#endif
- return msg;
-}
-
-static void parse_user_information (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
-{
-#if DEBUG
- printf("Parsing USER_INFORMATION Msg\n");
-#endif
-
-
-}
-
-static msg_t *build_user_information (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
-{
- int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
- USER_INFORMATION_t *user_information;
- msg_t *msg =(msg_t*)create_l3msg(CC_USER_INFORMATION | REQUEST, MT_USER_INFORMATION, bc?bc->l3_id:-1, sizeof(USER_INFORMATION_t) ,nt);
-
- user_information=(USER_INFORMATION_t*)((msg->data+HEADER_LEN));
-
-#if DEBUG
- printf("Building USER_INFORMATION Msg\n");
-#endif
- return msg;
-}
-
-static void parse_suspend_reject (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
-{
-#if DEBUG
- printf("Parsing SUSPEND_REJECT Msg\n");
-#endif
-
-
-}
-
-static msg_t *build_suspend_reject (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
-{
- int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
- SUSPEND_REJECT_t *suspend_reject;
- msg_t *msg =(msg_t*)create_l3msg(CC_SUSPEND_REJECT | REQUEST, MT_SUSPEND_REJECT, bc?bc->l3_id:-1, sizeof(SUSPEND_REJECT_t) ,nt);
-
- suspend_reject=(SUSPEND_REJECT_t*)((msg->data+HEADER_LEN));
-
-#if DEBUG
- printf("Building SUSPEND_REJECT Msg\n");
-#endif
- return msg;
-}
-
-static void parse_resume_reject (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
-{
-#if DEBUG
- printf("Parsing RESUME_REJECT Msg\n");
-#endif
-
-
-}
-
-static msg_t *build_resume_reject (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
-{
- int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
- RESUME_REJECT_t *resume_reject;
- msg_t *msg =(msg_t*)create_l3msg(CC_RESUME_REJECT | REQUEST, MT_RESUME_REJECT, bc?bc->l3_id:-1, sizeof(RESUME_REJECT_t) ,nt);
-
- resume_reject=(RESUME_REJECT_t*)((msg->data+HEADER_LEN));
-
-#if DEBUG
- printf("Building RESUME_REJECT Msg\n");
-#endif
- return msg;
-}
-
-static void parse_hold (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
-{
-#if DEBUG
- printf("Parsing HOLD Msg\n");
-#endif
-
-
-}
-
-static msg_t *build_hold (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
-{
- int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
- HOLD_t *hold;
- msg_t *msg =(msg_t*)create_l3msg(CC_HOLD | REQUEST, MT_HOLD, bc?bc->l3_id:-1, sizeof(HOLD_t) ,nt);
-
- hold=(HOLD_t*)((msg->data+HEADER_LEN));
-
-#if DEBUG
- printf("Building HOLD Msg\n");
-#endif
- return msg;
-}
-
-static void parse_suspend (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
-{
-#if DEBUG
- printf("Parsing SUSPEND Msg\n");
-#endif
-
-
-}
-
-static msg_t *build_suspend (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
-{
- int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
- SUSPEND_t *suspend;
- msg_t *msg =(msg_t*)create_l3msg(CC_SUSPEND | REQUEST, MT_SUSPEND, bc?bc->l3_id:-1, sizeof(SUSPEND_t) ,nt);
-
- suspend=(SUSPEND_t*)((msg->data+HEADER_LEN));
-
-#if DEBUG
- printf("Building SUSPEND Msg\n");
-#endif
- return msg;
-}
-
-static void parse_resume (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
-{
-#if DEBUG
- printf("Parsing RESUME Msg\n");
-#endif
-
-
-}
-
-static msg_t *build_resume (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
-{
- int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
- RESUME_t *resume;
- msg_t *msg =(msg_t*)create_l3msg(CC_RESUME | REQUEST, MT_RESUME, bc?bc->l3_id:-1, sizeof(RESUME_t) ,nt);
-
- resume=(RESUME_t*)((msg->data+HEADER_LEN));
-
-#if DEBUG
- printf("Building RESUME Msg\n");
-#endif
- return msg;
-}
-
-static void parse_hold_acknowledge (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
-{
-#if DEBUG
- printf("Parsing HOLD_ACKNOWLEDGE Msg\n");
-#endif
-
-
-}
-
-static msg_t *build_hold_acknowledge (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
-{
- int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
- HOLD_ACKNOWLEDGE_t *hold_acknowledge;
- msg_t *msg =(msg_t*)create_l3msg(CC_HOLD_ACKNOWLEDGE | REQUEST, MT_HOLD_ACKNOWLEDGE, bc?bc->l3_id:-1, sizeof(HOLD_ACKNOWLEDGE_t) ,nt);
-
- hold_acknowledge=(HOLD_ACKNOWLEDGE_t*)((msg->data+HEADER_LEN));
-
-#if DEBUG
- printf("Building HOLD_ACKNOWLEDGE Msg\n");
-#endif
- return msg;
-}
-
-static void parse_suspend_acknowledge (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
-{
-#if DEBUG
- printf("Parsing SUSPEND_ACKNOWLEDGE Msg\n");
-#endif
-
-
-}
-
-static msg_t *build_suspend_acknowledge (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
-{
- int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
- SUSPEND_ACKNOWLEDGE_t *suspend_acknowledge;
- msg_t *msg =(msg_t*)create_l3msg(CC_SUSPEND_ACKNOWLEDGE | REQUEST, MT_SUSPEND_ACKNOWLEDGE, bc?bc->l3_id:-1, sizeof(SUSPEND_ACKNOWLEDGE_t) ,nt);
-
- suspend_acknowledge=(SUSPEND_ACKNOWLEDGE_t*)((msg->data+HEADER_LEN));
-
-#if DEBUG
- printf("Building SUSPEND_ACKNOWLEDGE Msg\n");
-#endif
- return msg;
-}
-
-static void parse_resume_acknowledge (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
-{
-#if DEBUG
- printf("Parsing RESUME_ACKNOWLEDGE Msg\n");
-#endif
-
-
-}
-
-static msg_t *build_resume_acknowledge (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
-{
- int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
- RESUME_ACKNOWLEDGE_t *resume_acknowledge;
- msg_t *msg =(msg_t*)create_l3msg(CC_RESUME_ACKNOWLEDGE | REQUEST, MT_RESUME_ACKNOWLEDGE, bc?bc->l3_id:-1, sizeof(RESUME_ACKNOWLEDGE_t) ,nt);
-
- resume_acknowledge=(RESUME_ACKNOWLEDGE_t*)((msg->data+HEADER_LEN));
-
-#if DEBUG
- printf("Building RESUME_ACKNOWLEDGE Msg\n");
-#endif
- return msg;
-}
-
-static void parse_hold_reject (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
-{
-#if DEBUG
- printf("Parsing HOLD_REJECT Msg\n");
-#endif
-
-
-}
-
-static msg_t *build_hold_reject (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
-{
- int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
- HOLD_REJECT_t *hold_reject;
- msg_t *msg =(msg_t*)create_l3msg(CC_HOLD_REJECT | REQUEST, MT_HOLD_REJECT, bc?bc->l3_id:-1, sizeof(HOLD_REJECT_t) ,nt);
-
- hold_reject=(HOLD_REJECT_t*)((msg->data+HEADER_LEN));
-
-#if DEBUG
- printf("Building HOLD_REJECT Msg\n");
-#endif
- return msg;
-}
-
-static void parse_retrieve (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
-{
-#if DEBUG
- printf("Parsing RETRIEVE Msg\n");
-#endif
-
-
-}
-
-static msg_t *build_retrieve (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
-{
- int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
- RETRIEVE_t *retrieve;
- msg_t *msg =(msg_t*)create_l3msg(CC_RETRIEVE | REQUEST, MT_RETRIEVE, bc?bc->l3_id:-1, sizeof(RETRIEVE_t) ,nt);
-
- retrieve=(RETRIEVE_t*)((msg->data+HEADER_LEN));
-
-#if DEBUG
- printf("Building RETRIEVE Msg\n");
-#endif
- return msg;
-}
-
-static void parse_retrieve_acknowledge (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
-{
-#if DEBUG
- printf("Parsing RETRIEVE_ACKNOWLEDGE Msg\n");
-#endif
-
-
-}
-
-static msg_t *build_retrieve_acknowledge (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
-{
- int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
- RETRIEVE_ACKNOWLEDGE_t *retrieve_acknowledge;
- msg_t *msg =(msg_t*)create_l3msg(CC_RETRIEVE_ACKNOWLEDGE | REQUEST, MT_RETRIEVE_ACKNOWLEDGE, bc?bc->l3_id:-1, sizeof(RETRIEVE_ACKNOWLEDGE_t) ,nt);
-
- retrieve_acknowledge=(RETRIEVE_ACKNOWLEDGE_t*)((msg->data+HEADER_LEN));
-
- enc_ie_channel_id(&retrieve_acknowledge->CHANNEL_ID, msg, 1, bc->channel, nt,bc);
-#if DEBUG
- printf("Building RETRIEVE_ACKNOWLEDGE Msg\n");
-#endif
- return msg;
-}
-
-static void parse_retrieve_reject (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
-{
-#if DEBUG
- printf("Parsing RETRIEVE_REJECT Msg\n");
-#endif
-
-
-}
-
-static msg_t *build_retrieve_reject (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
-{
- int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
- RETRIEVE_REJECT_t *retrieve_reject;
- msg_t *msg =(msg_t*)create_l3msg(CC_RETRIEVE_REJECT | REQUEST, MT_RETRIEVE_REJECT, bc?bc->l3_id:-1, sizeof(RETRIEVE_REJECT_t) ,nt);
-
- retrieve_reject=(RETRIEVE_REJECT_t*)((msg->data+HEADER_LEN));
-
-#if DEBUG
- printf("Building RETRIEVE_REJECT Msg\n");
-#endif
- return msg;
-}
-
-static void parse_disconnect (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
-{
- int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
- DISCONNECT_t *disconnect=(DISCONNECT_t*)((unsigned long)(msg->data+HEADER_LEN));
- int location;
- int cause;
- dec_ie_cause(disconnect->CAUSE, (Q931_info_t *)(disconnect), &location, &cause, nt,bc);
- if (cause>0) bc->cause=cause;
-
- dec_ie_progress(disconnect->PROGRESS, (Q931_info_t *)disconnect, &bc->progress_coding, &bc->progress_location, &bc->progress_indicator, nt, bc);
-#if DEBUG
- printf("Parsing DISCONNECT Msg\n");
-#endif
-
-
-}
-
-static msg_t *build_disconnect (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
-{
- int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
- DISCONNECT_t *disconnect;
- msg_t *msg =(msg_t*)create_l3msg(CC_DISCONNECT | REQUEST, MT_DISCONNECT, bc?bc->l3_id:-1, sizeof(DISCONNECT_t) ,nt);
-
- disconnect=(DISCONNECT_t*)((msg->data+HEADER_LEN));
-
- enc_ie_cause(&disconnect->CAUSE, msg, (nt)?1:0, bc->out_cause,nt,bc);
- if (nt) enc_ie_progress(&disconnect->PROGRESS, msg, 0, nt?1:5, 8 ,nt,bc);
-
- if (bc->uulen) {
- int protocol=4;
- enc_ie_useruser(&disconnect->USER_USER, msg, protocol, bc->uu, bc->uulen, nt,bc);
- cb_log(1,bc->port,"ENCODING USERUESRINFO:%s\n",bc->uu);
- }
-
-#if DEBUG
- printf("Building DISCONNECT Msg\n");
-#endif
- return msg;
-}
-
-static void parse_restart (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
-{
- int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
- RESTART_t *restart=(RESTART_t*)((unsigned long)(msg->data+HEADER_LEN));
-
- struct misdn_stack *stack=get_stack_by_bc(bc);
-
-#if DEBUG
- printf("Parsing RESTART Msg\n");
-#endif
-
- {
- int exclusive;
- dec_ie_channel_id(restart->CHANNEL_ID, (Q931_info_t *)restart, &exclusive, &bc->restart_channel, nt,bc);
- cb_log(3, stack->port, "CC_RESTART Request on channel:%d on this port.\n", bc->restart_channel);
- }
-
-}
-
-static msg_t *build_restart (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
-{
- int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
- RESTART_t *restart;
- msg_t *msg =(msg_t*)create_l3msg(CC_RESTART | REQUEST, MT_RESTART, bc?bc->l3_id:-1, sizeof(RESTART_t) ,nt);
-
- restart=(RESTART_t*)((msg->data+HEADER_LEN));
-
-#if DEBUG
- printf("Building RESTART Msg\n");
-#endif
-
- if (bc->channel > 0) {
- enc_ie_channel_id(&restart->CHANNEL_ID, msg, 1,bc->channel, nt,bc);
- enc_ie_restart_ind(&restart->RESTART_IND, msg, 0x80, nt, bc);
- } else {
- enc_ie_restart_ind(&restart->RESTART_IND, msg, 0x87, nt, bc);
- }
-
- cb_log(0,bc->port, "Restarting channel %d\n", bc->channel);
-
- return msg;
-}
-
-static void parse_release (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
-{
- int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
- RELEASE_t *release=(RELEASE_t*)((unsigned long)(msg->data+HEADER_LEN));
- int location;
- int cause;
-
- dec_ie_cause(release->CAUSE, (Q931_info_t *)(release), &location, &cause, nt,bc);
- if (cause>0) bc->cause=cause;
-#if DEBUG
- printf("Parsing RELEASE Msg\n");
-#endif
-
-
-}
-
-static msg_t *build_release (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
-{
- int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
- RELEASE_t *release;
- msg_t *msg =(msg_t*)create_l3msg(CC_RELEASE | REQUEST, MT_RELEASE, bc?bc->l3_id:-1, sizeof(RELEASE_t) ,nt);
-
- release=(RELEASE_t*)((msg->data+HEADER_LEN));
-
- if (bc->out_cause>= 0)
- enc_ie_cause(&release->CAUSE, msg, nt?1:0, bc->out_cause, nt,bc);
-
- if (bc->uulen) {
- int protocol=4;
- enc_ie_useruser(&release->USER_USER, msg, protocol, bc->uu, bc->uulen, nt,bc);
- cb_log(1,bc->port,"ENCODING USERUESRINFO:%s\n",bc->uu);
- }
-
-#if DEBUG
- printf("Building RELEASE Msg\n");
-#endif
- return msg;
-}
-
-static void parse_release_complete (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
-{
- int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
- RELEASE_COMPLETE_t *release_complete=(RELEASE_COMPLETE_t*)((unsigned long)(msg->data+HEADER_LEN));
- int location;
- int cause;
- iframe_t *frm = (iframe_t*) msg->data;
-
- struct misdn_stack *stack=get_stack_by_bc(bc);
- mISDNuser_head_t *hh;
- hh=(mISDNuser_head_t*)msg->data;
-
- /*hh=(mISDN_head_t*)msg->data;
- mISDN_head_t *hh;*/
-
- if (nt) {
- if (hh->prim == (CC_RELEASE_COMPLETE|CONFIRM)) {
- cb_log(0, stack->port, "CC_RELEASE_COMPLETE|CONFIRM [NT] \n");
- return;
- }
- } else {
- if (frm->prim == (CC_RELEASE_COMPLETE|CONFIRM)) {
- cb_log(0, stack->port, "CC_RELEASE_COMPLETE|CONFIRM [TE] \n");
- return;
- }
- }
- dec_ie_cause(release_complete->CAUSE, (Q931_info_t *)(release_complete), &location, &cause, nt,bc);
- if (cause>0) bc->cause=cause;
-
-#if DEBUG
- printf("Parsing RELEASE_COMPLETE Msg\n");
-#endif
-}
-
-static msg_t *build_release_complete (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
-{
- int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
- RELEASE_COMPLETE_t *release_complete;
- msg_t *msg =(msg_t*)create_l3msg(CC_RELEASE_COMPLETE | REQUEST, MT_RELEASE_COMPLETE, bc?bc->l3_id:-1, sizeof(RELEASE_COMPLETE_t) ,nt);
-
- release_complete=(RELEASE_COMPLETE_t*)((msg->data+HEADER_LEN));
-
- enc_ie_cause(&release_complete->CAUSE, msg, nt?1:0, bc->out_cause, nt,bc);
-
- if (bc->uulen) {
- int protocol=4;
- enc_ie_useruser(&release_complete->USER_USER, msg, protocol, bc->uu, bc->uulen, nt,bc);
- cb_log(1,bc->port,"ENCODING USERUESRINFO:%s\n",bc->uu);
- }
-
-#if DEBUG
- printf("Building RELEASE_COMPLETE Msg\n");
-#endif
- return msg;
-}
-
-static void parse_facility (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
-{
- int HEADER_LEN = nt ? mISDNUSER_HEAD_SIZE : mISDN_HEADER_LEN;
- FACILITY_t *facility = (FACILITY_t*)(msg->data+HEADER_LEN);
- Q931_info_t *qi = (Q931_info_t*)(msg->data+HEADER_LEN);
- unsigned char *p = NULL;
- int err;
-
-#if DEBUG
- printf("Parsing FACILITY Msg\n");
-#endif
-
- if (!bc->nt) {
- if (qi->QI_ELEMENT(facility))
- p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(facility) + 1;
- } else {
- p = facility->FACILITY;
- }
- if (!p)
- return;
-
- err = decodeFac(p, &(bc->fac_in));
- if (err) {
- cb_log(1, bc->port, "Decoding FACILITY failed! (%d)\n", err);
- }
-}
-
-static msg_t *build_facility (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
-{
- int len,
- HEADER_LEN = nt ? mISDNUSER_HEAD_SIZE : mISDN_HEADER_LEN;
- unsigned char *ie_fac,
- fac_tmp[256];
- msg_t *msg =(msg_t*)create_l3msg(CC_FACILITY | REQUEST, MT_FACILITY, bc?bc->l3_id:-1, sizeof(FACILITY_t) ,nt);
- FACILITY_t *facility = (FACILITY_t*)(msg->data+HEADER_LEN);
- Q931_info_t *qi;
-
-#if DEBUG
- printf("Building FACILITY Msg\n");
-#endif
-
- len = encodeFac(fac_tmp, &(bc->fac_out));
- if (len <= 0)
- return NULL;
-
- ie_fac = msg_put(msg, len);
- if (bc->nt) {
- facility->FACILITY = ie_fac + 1;
- } else {
- qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
- qi->QI_ELEMENT(facility) = ie_fac - (unsigned char *)qi - sizeof(Q931_info_t);
- }
-
- memcpy(ie_fac, fac_tmp, len);
-
- if (*bc->display) {
- printf("Sending %s as Display\n", bc->display);
- enc_ie_display(&facility->DISPLAY, msg, bc->display, nt,bc);
- }
-
- return msg;
-}
-
-static void parse_notify (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
-{
-#if DEBUG
- printf("Parsing NOTIFY Msg\n");
-#endif
-}
-
-static msg_t *build_notify (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
-{
- int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
- NOTIFY_t *notify;
- msg_t *msg =(msg_t*)create_l3msg(CC_NOTIFY | REQUEST, MT_NOTIFY, bc?bc->l3_id:-1, sizeof(NOTIFY_t) ,nt);
-
- notify=(NOTIFY_t*)((msg->data+HEADER_LEN));
-
-#if DEBUG
- printf("Building NOTIFY Msg\n");
-#endif
- return msg;
-}
-
-static void parse_status_enquiry (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
-{
-#if DEBUG
- printf("Parsing STATUS_ENQUIRY Msg\n");
-#endif
-}
-
-static msg_t *build_status_enquiry (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
-{
- int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
- STATUS_ENQUIRY_t *status_enquiry;
- msg_t *msg =(msg_t*)create_l3msg(CC_STATUS_ENQUIRY | REQUEST, MT_STATUS_ENQUIRY, bc?bc->l3_id:-1, sizeof(STATUS_ENQUIRY_t) ,nt);
-
- status_enquiry=(STATUS_ENQUIRY_t*)((msg->data+HEADER_LEN));
-
-#if DEBUG
- printf("Building STATUS_ENQUIRY Msg\n");
-#endif
- return msg;
-}
-
-static void parse_information (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
-{
- int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
- INFORMATION_t *information=(INFORMATION_t*)((unsigned long)(msg->data+HEADER_LEN));
- {
- int type, plan;
- char number[32];
- char keypad[32];
- dec_ie_called_pn(information->CALLED_PN, (Q931_info_t *)information, &type, &plan, number, sizeof(number)-1, nt, bc);
- dec_ie_keypad(information->KEYPAD, (Q931_info_t *)information, keypad, sizeof(keypad)-1, nt, bc);
- strcpy(bc->info_dad, number);
- strcpy(bc->keypad,keypad);
- }
-#if DEBUG
- printf("Parsing INFORMATION Msg\n");
-#endif
-}
-
-static msg_t *build_information (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
-{
- int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
- INFORMATION_t *information;
- msg_t *msg =(msg_t*)create_l3msg(CC_INFORMATION | REQUEST, MT_INFORMATION, bc?bc->l3_id:-1, sizeof(INFORMATION_t) ,nt);
-
- information=(INFORMATION_t*)((msg->data+HEADER_LEN));
-
- {
- enc_ie_called_pn(&information->CALLED_PN, msg, 0, 1, bc->info_dad, nt,bc);
- }
-
- {
- if (*bc->display) {
- printf("Sending %s as Display\n", bc->display);
- enc_ie_display(&information->DISPLAY, msg, bc->display, nt,bc);
- }
- }
-
-#if DEBUG
- printf("Building INFORMATION Msg\n");
-#endif
- return msg;
-}
-
-static void parse_status (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
-{
- int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
- STATUS_t *status=(STATUS_t*)((unsigned long)(msg->data+HEADER_LEN));
- int location;
- int cause;
-
- dec_ie_cause(status->CAUSE, (Q931_info_t *)(status), &location, &cause, nt,bc);
- if (cause>0) bc->cause=cause;
- ;
-
-#if DEBUG
- printf("Parsing STATUS Msg\n");
-#endif
-}
-
-static msg_t *build_status (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
-{
- int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
- STATUS_t *status;
- msg_t *msg =(msg_t*)create_l3msg(CC_STATUS | REQUEST, MT_STATUS, bc?bc->l3_id:-1, sizeof(STATUS_t) ,nt);
-
- status=(STATUS_t*)((msg->data+HEADER_LEN));
-
-#if DEBUG
- printf("Building STATUS Msg\n");
-#endif
- return msg;
-}
-
-static void parse_timeout (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
-{
-#if DEBUG
- printf("Parsing STATUS Msg\n");
-#endif
-}
-
-static msg_t *build_timeout (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
-{
- int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
- STATUS_t *status;
- msg_t *msg =(msg_t*)create_l3msg(CC_STATUS | REQUEST, MT_STATUS, bc?bc->l3_id:-1, sizeof(STATUS_t) ,nt);
-
- status=(STATUS_t*)((msg->data+HEADER_LEN));
-
-#if DEBUG
- printf("Building STATUS Msg\n");
-#endif
- return msg;
-}
-
-
-/************************************/
-
-
-
-
-/** Msg Array **/
-
-struct isdn_msg msgs_g[] = {
- {CC_PROCEEDING,L3,EVENT_PROCEEDING,
- parse_proceeding,build_proceeding,
- "PROCEEDING"},
- {CC_ALERTING,L3,EVENT_ALERTING,
- parse_alerting,build_alerting,
- "ALERTING"},
- {CC_PROGRESS,L3,EVENT_PROGRESS,
- parse_progress,build_progress,
- "PROGRESS"},
- {CC_SETUP,L3,EVENT_SETUP,
- parse_setup,build_setup,
- "SETUP"},
- {CC_CONNECT,L3,EVENT_CONNECT,
- parse_connect,build_connect,
- "CONNECT"},
- {CC_SETUP_ACKNOWLEDGE,L3,EVENT_SETUP_ACKNOWLEDGE,
- parse_setup_acknowledge,build_setup_acknowledge,
- "SETUP_ACKNOWLEDGE"},
- {CC_CONNECT_ACKNOWLEDGE ,L3,EVENT_CONNECT_ACKNOWLEDGE ,
- parse_connect_acknowledge ,build_connect_acknowledge,
- "CONNECT_ACKNOWLEDGE "},
- {CC_USER_INFORMATION,L3,EVENT_USER_INFORMATION,
- parse_user_information,build_user_information,
- "USER_INFORMATION"},
- {CC_SUSPEND_REJECT,L3,EVENT_SUSPEND_REJECT,
- parse_suspend_reject,build_suspend_reject,
- "SUSPEND_REJECT"},
- {CC_RESUME_REJECT,L3,EVENT_RESUME_REJECT,
- parse_resume_reject,build_resume_reject,
- "RESUME_REJECT"},
- {CC_HOLD,L3,EVENT_HOLD,
- parse_hold,build_hold,
- "HOLD"},
- {CC_SUSPEND,L3,EVENT_SUSPEND,
- parse_suspend,build_suspend,
- "SUSPEND"},
- {CC_RESUME,L3,EVENT_RESUME,
- parse_resume,build_resume,
- "RESUME"},
- {CC_HOLD_ACKNOWLEDGE,L3,EVENT_HOLD_ACKNOWLEDGE,
- parse_hold_acknowledge,build_hold_acknowledge,
- "HOLD_ACKNOWLEDGE"},
- {CC_SUSPEND_ACKNOWLEDGE,L3,EVENT_SUSPEND_ACKNOWLEDGE,
- parse_suspend_acknowledge,build_suspend_acknowledge,
- "SUSPEND_ACKNOWLEDGE"},
- {CC_RESUME_ACKNOWLEDGE,L3,EVENT_RESUME_ACKNOWLEDGE,
- parse_resume_acknowledge,build_resume_acknowledge,
- "RESUME_ACKNOWLEDGE"},
- {CC_HOLD_REJECT,L3,EVENT_HOLD_REJECT,
- parse_hold_reject,build_hold_reject,
- "HOLD_REJECT"},
- {CC_RETRIEVE,L3,EVENT_RETRIEVE,
- parse_retrieve,build_retrieve,
- "RETRIEVE"},
- {CC_RETRIEVE_ACKNOWLEDGE,L3,EVENT_RETRIEVE_ACKNOWLEDGE,
- parse_retrieve_acknowledge,build_retrieve_acknowledge,
- "RETRIEVE_ACKNOWLEDGE"},
- {CC_RETRIEVE_REJECT,L3,EVENT_RETRIEVE_REJECT,
- parse_retrieve_reject,build_retrieve_reject,
- "RETRIEVE_REJECT"},
- {CC_DISCONNECT,L3,EVENT_DISCONNECT,
- parse_disconnect,build_disconnect,
- "DISCONNECT"},
- {CC_RESTART,L3,EVENT_RESTART,
- parse_restart,build_restart,
- "RESTART"},
- {CC_RELEASE,L3,EVENT_RELEASE,
- parse_release,build_release,
- "RELEASE"},
- {CC_RELEASE_COMPLETE,L3,EVENT_RELEASE_COMPLETE,
- parse_release_complete,build_release_complete,
- "RELEASE_COMPLETE"},
- {CC_FACILITY,L3,EVENT_FACILITY,
- parse_facility,build_facility,
- "FACILITY"},
- {CC_NOTIFY,L3,EVENT_NOTIFY,
- parse_notify,build_notify,
- "NOTIFY"},
- {CC_STATUS_ENQUIRY,L3,EVENT_STATUS_ENQUIRY,
- parse_status_enquiry,build_status_enquiry,
- "STATUS_ENQUIRY"},
- {CC_INFORMATION,L3,EVENT_INFORMATION,
- parse_information,build_information,
- "INFORMATION"},
- {CC_STATUS,L3,EVENT_STATUS,
- parse_status,build_status,
- "STATUS"},
- {CC_TIMEOUT,L3,EVENT_TIMEOUT,
- parse_timeout,build_timeout,
- "TIMEOUT"},
- {0,0,0,NULL,NULL,NULL}
-};
-
-#define msgs_max (sizeof(msgs_g)/sizeof(struct isdn_msg))
-
-/** INTERFACE FCTS ***/
-int isdn_msg_get_index(struct isdn_msg msgs[], msg_t *msg, int nt)
-{
- int i;
-
- if (nt){
- mISDNuser_head_t *hh = (mISDNuser_head_t*)msg->data;
-
- for (i=0; i< msgs_max -1; i++) {
- if ( (hh->prim&COMMAND_MASK)==(msgs[i].misdn_msg&COMMAND_MASK)) return i;
- }
-
- } else {
- iframe_t *frm = (iframe_t*)msg->data;
-
- for (i=0; i< msgs_max -1; i++)
- if ( (frm->prim&COMMAND_MASK)==(msgs[i].misdn_msg&COMMAND_MASK)) return i;
- }
-
- return -1;
-}
-
-int isdn_msg_get_index_by_event(struct isdn_msg msgs[], enum event_e event, int nt)
-{
- int i;
- for (i=0; i< msgs_max; i++)
- if ( event == msgs[i].event) return i;
-
- cb_log(10,0, "get_index: event not found!\n");
-
- return -1;
-}
-
-enum event_e isdn_msg_get_event(struct isdn_msg msgs[], msg_t *msg, int nt)
-{
- int i=isdn_msg_get_index(msgs, msg, nt);
- if(i>=0) return msgs[i].event;
- return EVENT_UNKNOWN;
-}
-
-char * isdn_msg_get_info(struct isdn_msg msgs[], msg_t *msg, int nt)
-{
- int i=isdn_msg_get_index(msgs, msg, nt);
- if(i>=0) return msgs[i].info;
- return NULL;
-}
-
-
-char EVENT_CLEAN_INFO[] = "CLEAN_UP";
-char EVENT_DTMF_TONE_INFO[] = "DTMF_TONE";
-char EVENT_NEW_L3ID_INFO[] = "NEW_L3ID";
-char EVENT_NEW_BC_INFO[] = "NEW_BC";
-char EVENT_PORT_ALARM_INFO[] = "ALARM";
-char EVENT_NEW_CHANNEL_INFO[] = "NEW_CHANNEL";
-char EVENT_BCHAN_DATA_INFO[] = "BCHAN_DATA";
-char EVENT_BCHAN_ACTIVATED_INFO[] = "BCHAN_ACTIVATED";
-char EVENT_TONE_GENERATE_INFO[] = "TONE_GENERATE";
-char EVENT_BCHAN_ERROR_INFO[] = "BCHAN_ERROR";
-
-char * isdn_get_info(struct isdn_msg msgs[], enum event_e event, int nt)
-{
- int i=isdn_msg_get_index_by_event(msgs, event, nt);
-
- if(i>=0) return msgs[i].info;
-
- if (event == EVENT_CLEANUP) return EVENT_CLEAN_INFO;
- if (event == EVENT_DTMF_TONE) return EVENT_DTMF_TONE_INFO;
- if (event == EVENT_NEW_L3ID) return EVENT_NEW_L3ID_INFO;
- if (event == EVENT_NEW_BC) return EVENT_NEW_BC_INFO;
- if (event == EVENT_NEW_CHANNEL) return EVENT_NEW_CHANNEL_INFO;
- if (event == EVENT_BCHAN_DATA) return EVENT_BCHAN_DATA_INFO;
- if (event == EVENT_BCHAN_ACTIVATED) return EVENT_BCHAN_ACTIVATED_INFO;
- if (event == EVENT_TONE_GENERATE) return EVENT_TONE_GENERATE_INFO;
- if (event == EVENT_PORT_ALARM) return EVENT_PORT_ALARM_INFO;
- if (event == EVENT_BCHAN_ERROR) return EVENT_BCHAN_ERROR_INFO;
-
- return NULL;
-}
-
-int isdn_msg_parse_event(struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
-{
- int i=isdn_msg_get_index(msgs, msg, nt);
- if(i<0) return -1;
-
- msgs[i].msg_parser(msgs, msg, bc, nt);
- return 0;
-}
-
-msg_t * isdn_msg_build_event(struct isdn_msg msgs[], struct misdn_bchannel *bc, enum event_e event, int nt)
-{
- int i=isdn_msg_get_index_by_event(msgs, event, nt);
- if(i<0) return NULL;
-
- return msgs[i].msg_builder(msgs, bc, nt);
-}
diff --git a/1.4.23-rc4/channels/misdn/portinfo.c b/1.4.23-rc4/channels/misdn/portinfo.c
deleted file mode 100644
index bcb9f0313..000000000
--- a/1.4.23-rc4/channels/misdn/portinfo.c
+++ /dev/null
@@ -1,198 +0,0 @@
-
-
-#include "isdn_lib.h"
-#include "isdn_lib_intern.h"
-
-
-/*
- * global function to show all available isdn ports
- */
-void isdn_port_info(void)
-{
- int err;
- int i, ii, p;
- int useable, nt, pri;
- unsigned char buff[1025];
- iframe_t *frm = (iframe_t *)buff;
- stack_info_t *stinf;
- int device;
-
- /* open mISDN */
- if ((device = mISDN_open()) < 0)
- {
- fprintf(stderr, "mISDN_open() failed: ret=%d errno=%d (%s) Check for mISDN modules and device.\n", device, errno, strerror(errno));
- exit(-1);
- }
-
- /* get number of stacks */
- i = 1;
- ii = mISDN_get_stack_count(device);
- printf("\n");
- if (ii <= 0)
- {
- printf("Found no card. Please be sure to load card drivers.\n");
- }
-
- /* loop the number of cards and get their info */
- while(i <= ii)
- {
- err = mISDN_get_stack_info(device, i, buff, sizeof(buff));
- if (err <= 0)
- {
- fprintf(stderr, "mISDN_get_stack_info() failed: port=%d err=%d\n", i, err);
- break;
- }
- stinf = (stack_info_t *)&frm->data.p;
-
- nt = pri = 0;
- useable = 1;
-
- /* output the port info */
- printf("Port %2d: ", i);
- switch(stinf->pid.protocol[0] & ~ISDN_PID_FEATURE_MASK)
- {
- case ISDN_PID_L0_TE_S0:
- printf("TE-mode BRI S/T interface line (for phone lines)");
-#if 0
- if (stinf->pid.protocol[0] & ISDN_PID_L0_TE_S0_HFC & ISDN_PID_FEATURE_MASK)
- printf(" HFC multiport card");
-#endif
- break;
- case ISDN_PID_L0_NT_S0:
- nt = 1;
- printf("NT-mode BRI S/T interface port (for phones)");
-#if 0
- if (stinf->pid.protocol[0] & ISDN_PID_L0_NT_S0_HFC & ISDN_PID_FEATURE_MASK)
- printf(" HFC multiport card");
-#endif
- break;
- case ISDN_PID_L0_TE_U:
- printf("TE-mode BRI U interface line");
- break;
- case ISDN_PID_L0_NT_U:
- nt = 1;
- printf("NT-mode BRI U interface port");
- break;
- case ISDN_PID_L0_TE_UP2:
- printf("TE-mode BRI Up2 interface line");
- break;
- case ISDN_PID_L0_NT_UP2:
- nt = 1;
- printf("NT-mode BRI Up2 interface port");
- break;
- case ISDN_PID_L0_TE_E1:
- pri = 1;
- printf("TE-mode PRI E1 interface line (for phone lines)");
-#if 0
- if (stinf->pid.protocol[0] & ISDN_PID_L0_TE_E1_HFC & ISDN_PID_FEATURE_MASK)
- printf(" HFC-E1 card");
-#endif
- break;
- case ISDN_PID_L0_NT_E1:
- nt = 1;
- pri = 1;
- printf("NT-mode PRI E1 interface port (for phones)");
-#if 0
- if (stinf->pid.protocol[0] & ISDN_PID_L0_NT_E1_HFC & ISDN_PID_FEATURE_MASK)
- printf(" HFC-E1 card");
-#endif
- break;
- default:
- useable = 0;
- printf("unknown type 0x%08x",stinf->pid.protocol[0]);
- }
- printf("\n");
-
- if (nt)
- {
- if (stinf->pid.protocol[1] == 0)
- {
- useable = 0;
- printf(" -> Missing layer 1 NT-mode protocol.\n");
- }
- p = 2;
- while(p <= MAX_LAYER_NR) {
- if (stinf->pid.protocol[p])
- {
- useable = 0;
- printf(" -> Layer %d protocol 0x%08x is detected, but not allowed for NT lib.\n", p, stinf->pid.protocol[p]);
- }
- p++;
- }
- if (useable)
- {
- if (pri)
- printf(" -> Interface is Point-To-Point (PRI).\n");
- else
- printf(" -> Interface can be Poin-To-Point/Multipoint.\n");
- }
- } else
- {
- if (stinf->pid.protocol[1] == 0)
- {
- useable = 0;
- printf(" -> Missing layer 1 protocol.\n");
- }
- if (stinf->pid.protocol[2] == 0)
- {
- useable = 0;
- printf(" -> Missing layer 2 protocol.\n");
- }
- if (stinf->pid.protocol[2] & ISDN_PID_L2_DF_PTP)
- {
- printf(" -> Interface is Poin-To-Point.\n");
- }
- if (stinf->pid.protocol[3] == 0)
- {
- useable = 0;
- printf(" -> Missing layer 3 protocol.\n");
- } else
- {
- printf(" -> Protocol: ");
- switch(stinf->pid.protocol[3] & ~ISDN_PID_FEATURE_MASK)
- {
- case ISDN_PID_L3_DSS1USER:
- printf("DSS1 (Euro ISDN)");
- break;
-
- default:
- useable = 0;
- printf("unknown protocol 0x%08x",stinf->pid.protocol[3]);
- }
- printf("\n");
- }
- p = 4;
- while(p <= MAX_LAYER_NR) {
- if (stinf->pid.protocol[p])
- {
- useable = 0;
- printf(" -> Layer %d protocol 0x%08x is detected, but not allowed for TE lib.\n", p, stinf->pid.protocol[p]);
- }
- p++;
- }
- printf(" -> childcnt: %d\n",stinf->childcnt);
- }
-
- if (!useable)
- printf(" * Port NOT useable for PBX\n");
-
- printf("--------\n");
-
- i++;
- }
- printf("\n");
-
- /* close mISDN */
- if ((err = mISDN_close(device)))
- {
- fprintf(stderr, "mISDN_close() failed: err=%d '%s'\n", err, strerror(err));
- exit(-1);
- }
-}
-
-
-int main()
-{
- isdn_port_info();
- return 0;
-}
diff --git a/1.4.23-rc4/channels/misdn_config.c b/1.4.23-rc4/channels/misdn_config.c
deleted file mode 100644
index 0924ad983..000000000
--- a/1.4.23-rc4/channels/misdn_config.c
+++ /dev/null
@@ -1,1160 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2005, Christian Richter
- *
- * Christian Richter <crich@beronet.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- *
- */
-
-/*!
- * \file
- *
- * \brief chan_misdn configuration management
- * \author Christian Richter <crich@beronet.com>
- *
- * \ingroup channel_drivers
- */
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-
-#include "chan_misdn_config.h"
-
-#include "asterisk/config.h"
-#include "asterisk/channel.h"
-#include "asterisk/logger.h"
-#include "asterisk/lock.h"
-#include "asterisk/pbx.h"
-#include "asterisk/strings.h"
-#include "asterisk/utils.h"
-
-#define AST_LOAD_CFG ast_config_load
-#define AST_DESTROY_CFG ast_config_destroy
-
-#define NO_DEFAULT "<>"
-#define NONE 0
-
-#define GEN_CFG 1
-#define PORT_CFG 2
-#define NUM_GEN_ELEMENTS (sizeof(gen_spec) / sizeof(struct misdn_cfg_spec))
-#define NUM_PORT_ELEMENTS (sizeof(port_spec) / sizeof(struct misdn_cfg_spec))
-
-enum misdn_cfg_type {
- MISDN_CTYPE_STR,
- MISDN_CTYPE_INT,
- MISDN_CTYPE_BOOL,
- MISDN_CTYPE_BOOLINT,
- MISDN_CTYPE_MSNLIST,
- MISDN_CTYPE_ASTGROUP
-};
-
-struct msn_list {
- char *msn;
- struct msn_list *next;
-};
-
-union misdn_cfg_pt {
- char *str;
- int *num;
- struct msn_list *ml;
- ast_group_t *grp;
- void *any;
-};
-
-struct misdn_cfg_spec {
- char name[BUFFERSIZE];
- enum misdn_cfg_elements elem;
- enum misdn_cfg_type type;
- char def[BUFFERSIZE];
- int boolint_def;
- char desc[BUFFERSIZE];
-};
-
-
-static const char ports_description[] =
- "Define your ports, e.g. 1,2 (depends on mISDN-driver loading order).";
-
-static const struct misdn_cfg_spec port_spec[] = {
- { "name", MISDN_CFG_GROUPNAME, MISDN_CTYPE_STR, "default", NONE,
- "Name of the portgroup." },
- { "allowed_bearers", MISDN_CFG_ALLOWED_BEARERS, MISDN_CTYPE_STR, "all", NONE,
- "Here you can list which bearer capabilities should be allowed:\n"
- "\t all - allow any bearer capability\n"
- "\t speech - allow speech\n"
- "\t 3_1khz - allow 3.1KHz audio\n"
- "\t digital_unrestricted - allow unrestricted digital\n"
- "\t digital_restricted - allow restricted digital\n"
- "\t video - allow video" },
- { "rxgain", MISDN_CFG_RXGAIN, MISDN_CTYPE_INT, "0", NONE,
- "Set this between -8 and 8 to change the RX Gain." },
- { "txgain", MISDN_CFG_TXGAIN, MISDN_CTYPE_INT, "0", NONE,
- "Set this between -8 and 8 to change the TX Gain." },
- { "te_choose_channel", MISDN_CFG_TE_CHOOSE_CHANNEL, MISDN_CTYPE_BOOL, "no", NONE,
- "Some telcos especially in NL seem to need this set to yes,\n"
- "\talso in Switzerland this seems to be important." },
- { "far_alerting", MISDN_CFG_FAR_ALERTING, MISDN_CTYPE_BOOL, "no", NONE,
- "If we should generate ringing for chan_sip and others." },
- { "pmp_l1_check", MISDN_CFG_PMP_L1_CHECK, MISDN_CTYPE_BOOL, "no", NONE,
- "This option defines, if chan_misdn should check the L1 on a PMP\n"
- "\tbefore making a group call on it. The L1 may go down for PMP Ports\n"
- "\tso we might need this.\n"
- "\tBut be aware! a broken or plugged off cable might be used for a group call\n"
- "\tas well, since chan_misdn has no chance to distinguish if the L1 is down\n"
- "\tbecause of a lost Link or because the Provider shut it down..." },
- { "block_on_alarm", MISDN_CFG_ALARM_BLOCK, MISDN_CTYPE_BOOL, "no", NONE ,
- "Block this port if we have an alarm on it." },
- { "hdlc", MISDN_CFG_HDLC, MISDN_CTYPE_BOOL, "no", NONE,
- "Set this to yes, if you want to bridge a mISDN data channel to\n"
- "\tanother channel type or to an application." },
- { "context", MISDN_CFG_CONTEXT, MISDN_CTYPE_STR, "default", NONE,
- "Context to use for incoming calls." },
- { "language", MISDN_CFG_LANGUAGE, MISDN_CTYPE_STR, "en", NONE,
- "Language." },
- { "musicclass", MISDN_CFG_MUSICCLASS, MISDN_CTYPE_STR, "default", NONE,
- "Sets the musiconhold class." },
- { "callerid", MISDN_CFG_CALLERID, MISDN_CTYPE_STR, "", NONE,
- "Sets the caller ID." },
- { "method", MISDN_CFG_METHOD, MISDN_CTYPE_STR, "standard", NONE,
- "Sets the method to use for channel selection:\n"
- "\t standard - always choose the first free channel with the lowest number\n"
- "\t round_robin - use the round robin algorithm to select a channel. use this\n"
- "\t if you want to balance your load." },
- { "dialplan", MISDN_CFG_DIALPLAN, MISDN_CTYPE_INT, "0", NONE,
- "Dialplan means Type Of Number in ISDN Terms (for outgoing calls)\n"
- "\n"
- "\tThere are different types of the dialplan:\n"
- "\n"
- "\tdialplan -> outgoing Number\n"
- "\tlocaldialplan -> callerid\n"
- "\tcpndialplan -> connected party number\n"
- "\n"
- "\tdialplan options:\n"
- "\n"
- "\t0 - unknown\n"
- "\t1 - International\n"
- "\t2 - National\n"
- "\t4 - Subscriber\n"
- "\n"
- "\tThis setting is used for outgoing calls." },
- { "localdialplan", MISDN_CFG_LOCALDIALPLAN, MISDN_CTYPE_INT, "0", NONE,
- "Dialplan means Type Of Number in ISDN Terms (for outgoing calls)\n"
- "\n"
- "\tThere are different types of the dialplan:\n"
- "\n"
- "\tdialplan -> outgoing Number\n"
- "\tlocaldialplan -> callerid\n"
- "\tcpndialplan -> connected party number\n"
- "\n"
- "\tdialplan options:\n"
- "\n"
- "\t0 - unknown\n"
- "\t1 - International\n"
- "\t2 - National\n"
- "\t4 - Subscriber\n"
- "\n"
- "\tThis setting is used for outgoing calls." },
- { "cpndialplan", MISDN_CFG_CPNDIALPLAN, MISDN_CTYPE_INT, "0", NONE,
- "Dialplan means Type Of Number in ISDN Terms (for outgoing calls)\n"
- "\n"
- "\tThere are different types of the dialplan:\n"
- "\n"
- "\tdialplan -> outgoing Number\n"
- "\tlocaldialplan -> callerid\n"
- "\tcpndialplan -> connected party number\n"
- "\n"
- "\tdialplan options:\n"
- "\n"
- "\t0 - unknown\n"
- "\t1 - International\n"
- "\t2 - National\n"
- "\t4 - Subscriber\n"
- "\n"
- "\tThis setting is used for outgoing calls." },
- { "nationalprefix", MISDN_CFG_NATPREFIX, MISDN_CTYPE_STR, "0", NONE,
- "Prefix for national, this is put before the\n"
- "\toad if an according dialplan is set by the other end." },
- { "internationalprefix", MISDN_CFG_INTERNATPREFIX, MISDN_CTYPE_STR, "00", NONE,
- "Prefix for international, this is put before the\n"
- "\toad if an according dialplan is set by the other end." },
- { "presentation", MISDN_CFG_PRES, MISDN_CTYPE_INT, "-1", NONE,
- "These (presentation and screen) are the exact isdn screening and presentation\n"
- "\tindicators.\n"
- "\tIf -1 is given for either value, the presentation indicators are used from\n"
- "\tAsterisk's SetCallerPres application.\n"
- "\n"
- "\tscreen=0, presentation=0 -> callerid presented\n"
- "\tscreen=1, presentation=1 -> callerid restricted (the remote end doesn't see it!)" },
- { "screen", MISDN_CFG_SCREEN, MISDN_CTYPE_INT, "-1", NONE,
- "These (presentation and screen) are the exact isdn screening and presentation\n"
- "\tindicators.\n"
- "\tIf -1 is given for either value, the presentation indicators are used from\n"
- "\tAsterisk's SetCallerPres application.\n"
- "\n"
- "\tscreen=0, presentation=0 -> callerid presented\n"
- "\tscreen=1, presentation=1 -> callerid restricted (the remote end doesn't see it!)" },
- { "always_immediate", MISDN_CFG_ALWAYS_IMMEDIATE, MISDN_CTYPE_BOOL, "no", NONE,
- "Enable this to get into the s dialplan-extension.\n"
- "\tThere you can use DigitTimeout if you can't or don't want to use\n"
- "\tisdn overlap dial.\n"
- "\tNOTE: This will jump into the s extension for every exten!" },
- { "nodialtone", MISDN_CFG_NODIALTONE, MISDN_CTYPE_BOOL, "no", NONE,
- "Enable this to prevent chan_misdn to generate the dialtone\n"
- "\tThis makes only sense together with the always_immediate=yes option\n"
- "\tto generate your own dialtone with Playtones or so."},
- { "immediate", MISDN_CFG_IMMEDIATE, MISDN_CTYPE_BOOL, "no", NONE,
- "Enable this if you want callers which called exactly the base\n"
- "\tnumber (so no extension is set) to jump into the s extension.\n"
- "\tIf the user dials something more, it jumps to the correct extension\n"
- "\tinstead." },
- { "senddtmf", MISDN_CFG_SENDDTMF, MISDN_CTYPE_BOOL, "no", NONE,
- "Enable this if we should produce DTMF Tones ourselves." },
- { "astdtmf", MISDN_CFG_ASTDTMF, MISDN_CTYPE_BOOL, "no", NONE,
- "Enable this if you want to use the Asterisk dtmf detector\n"
- "instead of the mISDN_dsp/hfcmulti one."
- },
- { "hold_allowed", MISDN_CFG_HOLD_ALLOWED, MISDN_CTYPE_BOOL, "no", NONE,
- "Enable this to have support for hold and retrieve." },
- { "early_bconnect", MISDN_CFG_EARLY_BCONNECT, MISDN_CTYPE_BOOL, "yes", NONE,
- "Disable this if you don't mind correct handling of Progress Indicators." },
- { "incoming_early_audio", MISDN_CFG_INCOMING_EARLY_AUDIO, MISDN_CTYPE_BOOL, "no", NONE,
- "Turn this on if you like to send Tone Indications to a Incoming\n"
- "\tisdn channel on a TE Port. Rarely used, only if the Telco allows\n"
- "\tyou to send indications by yourself, normally the Telco sends the\n"
- "\tindications to the remote party." },
- { "echocancel", MISDN_CFG_ECHOCANCEL, MISDN_CTYPE_BOOLINT, "0", 128,
- "This enables echo cancellation with the given number of taps.\n"
- "\tBe aware: Move this setting only to outgoing portgroups!\n"
- "\tA value of zero turns echo cancellation off.\n"
- "\n"
- "\tPossible values are: 0,32,64,128,256,yes(=128),no(=0)" },
-#ifdef MISDN_1_2
- { "pipeline", MISDN_CFG_PIPELINE, MISDN_CTYPE_STR, NO_DEFAULT, NONE,
- "Set the configuration string for the mISDN dsp pipeline.\n"
- "\n"
- "\tExample for enabling the mg2 echo cancellation module with deftaps\n"
- "\tset to 128:\n"
- "\t\tmg2ec(deftaps=128)" },
-#endif
-#ifdef WITH_BEROEC
- { "bnechocancel", MISDN_CFG_BNECHOCANCEL, MISDN_CTYPE_BOOLINT, "yes", 64,
- "echotail in ms (1-200)\n"},
- { "bnec_antihowl", MISDN_CFG_BNEC_ANTIHOWL, MISDN_CTYPE_INT, "0", NONE,
- "Use antihowl\n"},
- { "bnec_nlp", MISDN_CFG_BNEC_NLP, MISDN_CTYPE_BOOL, "yes", NONE,
- "Nonlinear Processing (much faster adaption)"},
- { "bnec_zerocoeff", MISDN_CFG_BNEC_ZEROCOEFF, MISDN_CTYPE_BOOL, "no", NONE,
- "ZeroCoeffeciens\n"},
- { "bnec_tonedisabler", MISDN_CFG_BNEC_TD, MISDN_CTYPE_BOOL, "no", NONE,
- "Disable Tone\n"},
- { "bnec_adaption", MISDN_CFG_BNEC_ADAPT, MISDN_CTYPE_INT, "1", NONE,
- "Adaption mode (0=no,1=full,2=fast)\n"},
-#endif
- { "need_more_infos", MISDN_CFG_NEED_MORE_INFOS, MISDN_CTYPE_BOOL, "0", NONE,
- "Send Setup_Acknowledge on incoming calls anyway (instead of PROCEEDING),\n"
- "\tthis requests additional Infos, so we can waitfordigits without much\n"
- "\tissues. This works only for PTP Ports" },
- { "noautorespond_on_setup", MISDN_CFG_NOAUTORESPOND_ON_SETUP, MISDN_CTYPE_BOOL, "0", NONE,
- "Do not send SETUP_ACKNOWLEDGE or PROCEEDING automatically to the calling Party.\n"
- "Instead we directly jump into the dialplan. This might be useful for fast call\n"
- "rejection, or for some broken switches, that need hangup causes like busy in the.\n"
- "RELEASE_COMPLETE Message, instead of the DISCONNECT Message."},
- { "jitterbuffer", MISDN_CFG_JITTERBUFFER, MISDN_CTYPE_INT, "4000", NONE,
- "The jitterbuffer." },
- { "jitterbuffer_upper_threshold", MISDN_CFG_JITTERBUFFER_UPPER_THRESHOLD, MISDN_CTYPE_INT, "0", NONE,
- "Change this threshold to enable dejitter functionality." },
- { "callgroup", MISDN_CFG_CALLGROUP, MISDN_CTYPE_ASTGROUP, NO_DEFAULT, NONE,
- "Callgroup." },
- { "pickupgroup", MISDN_CFG_PICKUPGROUP, MISDN_CTYPE_ASTGROUP, NO_DEFAULT, NONE,
- "Pickupgroup." },
- { "max_incoming", MISDN_CFG_MAX_IN, MISDN_CTYPE_INT, "-1", NONE,
- "Defines the maximum amount of incoming calls per port for this group.\n"
- "\tCalls which exceed the maximum will be marked with the channel variable\n"
- "\tMAX_OVERFLOW. It will contain the amount of overflowed calls" },
- { "max_outgoing", MISDN_CFG_MAX_OUT, MISDN_CTYPE_INT, "-1", NONE,
- "Defines the maximum amount of outgoing calls per port for this group\n"
- "\texceeding calls will be rejected" },
-
- { "reject_cause", MISDN_CFG_REJECT_CAUSE, MISDN_CTYPE_INT, "21", NONE,
- "Defines the cause with which a 3. call is rejected on PTMP BRI."},
- { "faxdetect", MISDN_CFG_FAXDETECT, MISDN_CTYPE_STR, "no", NONE,
- "Setup fax detection:\n"
- "\t no - no fax detection\n"
- "\t incoming - fax detection for incoming calls\n"
- "\t outgoing - fax detection for outgoing calls\n"
- "\t both - fax detection for incoming and outgoing calls\n"
- "\tAdd +nojump to your value (i.e. faxdetect=both+nojump) if you don't want to jump into the\n"
- "\tfax-extension but still want to detect the fax and prepare the channel for fax transfer." },
- { "faxdetect_timeout", MISDN_CFG_FAXDETECT_TIMEOUT, MISDN_CTYPE_INT, "5", NONE,
- "Number of seconds the fax detection should do its job. After the given period of time,\n"
- "\twe assume that it's not a fax call and save some CPU time by turning off fax detection.\n"
- "\tSet this to 0 if you don't want a timeout (never stop detecting)." },
- { "faxdetect_context", MISDN_CFG_FAXDETECT_CONTEXT, MISDN_CTYPE_STR, NO_DEFAULT, NONE,
- "Context to jump into if we detect a fax. Don't set this if you want to stay in the current context." },
- { "l1watcher_timeout", MISDN_CFG_L1_TIMEOUT, MISDN_CTYPE_BOOLINT, "0", 4,
- "Watches the layer 1. If the layer 1 is down, it tries to\n"
- "\tget it up. The timeout is given in seconds. with 0 as value it\n"
- "\tdoes not watch the l1 at all\n"
- "\n"
- "\tThis option is only read at loading time of chan_misdn, which\n"
- "\tmeans you need to unload and load chan_misdn to change the value,\n"
- "\tan Asterisk restart should do the trick." },
- { "overlapdial", MISDN_CFG_OVERLAP_DIAL, MISDN_CTYPE_BOOLINT, "0", 4,
- "Enables overlap dial for the given amount of seconds.\n"
- "\tPossible values are positive integers or:\n"
- "\t yes (= 4 seconds)\n"
- "\t no (= 0 seconds = disabled)" },
- { "nttimeout", MISDN_CFG_NTTIMEOUT, MISDN_CTYPE_BOOL, "no", NONE ,
- "Set this to yes if you want calls disconnected in overlap mode"
- "when a timeout happens."},
- { "bridging", MISDN_CFG_BRIDGING, MISDN_CTYPE_BOOL, "yes", NONE,
- "Set this to yes/no, default is yes.\n"
- "This can be used to have bridging enabled in general and to\n"
- "disable it for specific ports. It makes sense to disable\n"
- "bridging on NT Port where you plan to use the HOLD/RETRIEVE\n"
- "features with ISDN phones." },
- { "msns", MISDN_CFG_MSNS, MISDN_CTYPE_MSNLIST, "*", NONE,
- "MSN's for TE ports, listen on those numbers on the above ports, and\n"
- "\tindicate the incoming calls to Asterisk.\n"
- "\tHere you can give a comma separated list, or simply an '*' for any msn." },
-};
-
-static const struct misdn_cfg_spec gen_spec[] = {
- { "debug", MISDN_GEN_DEBUG, MISDN_CTYPE_INT, "0", NONE,
- "Sets the debugging flag:\n"
- "\t0 - No Debug\n"
- "\t1 - mISDN Messages and * - Messages, and * - State changes\n"
- "\t2 - Messages + Message specific Informations (e.g. bearer capability)\n"
- "\t3 - very Verbose, the above + lots of Driver specific infos\n"
- "\t4 - even more Verbose than 3" },
-#ifndef MISDN_1_2
- { "misdn_init", MISDN_GEN_MISDN_INIT, MISDN_CTYPE_STR, "/etc/misdn-init.conf", NONE,
- "Set the path to the misdn-init.conf (for nt_ptp mode checking)." },
-#endif
- { "tracefile", MISDN_GEN_TRACEFILE, MISDN_CTYPE_STR, "/var/log/asterisk/misdn.log", NONE,
- "Set the path to the massively growing trace file, if you want that." },
- { "bridging", MISDN_GEN_BRIDGING, MISDN_CTYPE_BOOL, "yes", NONE,
- "Set this to yes if you want mISDN_dsp to bridge the calls in HW." },
- { "stop_tone_after_first_digit", MISDN_GEN_STOP_TONE, MISDN_CTYPE_BOOL, "yes", NONE,
- "Stops dialtone after getting first digit on NT Port." },
- { "append_digits2exten", MISDN_GEN_APPEND_DIGITS2EXTEN, MISDN_CTYPE_BOOL, "yes", NONE,
- "Whether to append overlapdialed Digits to Extension or not." },
- { "dynamic_crypt", MISDN_GEN_DYNAMIC_CRYPT, MISDN_CTYPE_BOOL, "no", NONE,
- "Whether to look out for dynamic crypting attempts." },
- { "crypt_prefix", MISDN_GEN_CRYPT_PREFIX, MISDN_CTYPE_STR, NO_DEFAULT, NONE,
- "What is used for crypting Protocol." },
- { "crypt_keys", MISDN_GEN_CRYPT_KEYS, MISDN_CTYPE_STR, NO_DEFAULT, NONE,
- "Keys for cryption, you reference them in the dialplan\n"
- "\tLater also in dynamic encr." },
- { "ntkeepcalls", MISDN_GEN_NTKEEPCALLS, MISDN_CTYPE_BOOL, "no", NONE,
- "avoid dropping calls if the L2 goes down. some Nortel pbx\n"
- "do put down the L2/L1 for some milliseconds even if there\n"
- "are running calls. with this option you can avoid dropping them" },
- { "ntdebugflags", MISDN_GEN_NTDEBUGFLAGS, MISDN_CTYPE_INT, "0", NONE,
- "No description yet."},
- { "ntdebugfile", MISDN_GEN_NTDEBUGFILE, MISDN_CTYPE_STR, "/var/log/misdn-nt.log", NONE,
- "No description yet." }
-};
-
-
-/* array of port configs, default is at position 0. */
-static union misdn_cfg_pt **port_cfg;
-/* max number of available ports, is set on init */
-static int max_ports;
-/* general config */
-static union misdn_cfg_pt *general_cfg;
-/* storing the ptp flag separated to save memory */
-static int *ptp;
-/* maps enum config elements to array positions */
-static int *map;
-
-static ast_mutex_t config_mutex;
-
-#define CLI_ERROR(name, value, section) ({ \
- ast_log(LOG_WARNING, "misdn.conf: \"%s=%s\" (section: %s) invalid or out of range. " \
- "Please edit your misdn.conf and then do a \"misdn reload\".\n", name, value, section); \
-})
-
-static int _enum_array_map (void)
-{
- int i, j, ok;
-
- for (i = MISDN_CFG_FIRST + 1; i < MISDN_CFG_LAST; ++i) {
- if (i == MISDN_CFG_PTP)
- continue;
- ok = 0;
- for (j = 0; j < NUM_PORT_ELEMENTS; ++j) {
- if (port_spec[j].elem == i) {
- map[i] = j;
- ok = 1;
- break;
- }
- }
- if (!ok) {
- ast_log(LOG_WARNING, "Enum element %d in misdn_cfg_elements (port section) has no corresponding element in the config struct!\n", i);
- return -1;
- }
- }
- for (i = MISDN_GEN_FIRST + 1; i < MISDN_GEN_LAST; ++i) {
- ok = 0;
- for (j = 0; j < NUM_GEN_ELEMENTS; ++j) {
- if (gen_spec[j].elem == i) {
- map[i] = j;
- ok = 1;
- break;
- }
- }
- if (!ok) {
- ast_log(LOG_WARNING, "Enum element %d in misdn_cfg_elements (general section) has no corresponding element in the config struct!\n", i);
- return -1;
- }
- }
- return 0;
-}
-
-static int get_cfg_position (char *name, int type)
-{
- int i;
-
- switch (type) {
- case PORT_CFG:
- for (i = 0; i < NUM_PORT_ELEMENTS; ++i) {
- if (!strcasecmp(name, port_spec[i].name))
- return i;
- }
- break;
- case GEN_CFG:
- for (i = 0; i < NUM_GEN_ELEMENTS; ++i) {
- if (!strcasecmp(name, gen_spec[i].name))
- return i;
- }
- }
-
- return -1;
-}
-
-static inline void misdn_cfg_lock (void)
-{
- ast_mutex_lock(&config_mutex);
-}
-
-static inline void misdn_cfg_unlock (void)
-{
- ast_mutex_unlock(&config_mutex);
-}
-
-static void _free_msn_list (struct msn_list* iter)
-{
- if (iter->next)
- _free_msn_list(iter->next);
- if (iter->msn)
- free(iter->msn);
- free(iter);
-}
-
-static void _free_port_cfg (void)
-{
- int i, j;
- int gn = map[MISDN_CFG_GROUPNAME];
- union misdn_cfg_pt* free_list[max_ports + 2];
-
- memset(free_list, 0, sizeof(free_list));
- free_list[0] = port_cfg[0];
- for (i = 1; i <= max_ports; ++i) {
- if (port_cfg[i][gn].str) {
- /* we always have a groupname in the non-default case, so this is fine */
- for (j = 1; j <= max_ports; ++j) {
- if (free_list[j] && free_list[j][gn].str == port_cfg[i][gn].str)
- break;
- else if (!free_list[j]) {
- free_list[j] = port_cfg[i];
- break;
- }
- }
- }
- }
- for (j = 0; free_list[j]; ++j) {
- for (i = 0; i < NUM_PORT_ELEMENTS; ++i) {
- if (free_list[j][i].any) {
- if (port_spec[i].type == MISDN_CTYPE_MSNLIST)
- _free_msn_list(free_list[j][i].ml);
- else
- free(free_list[j][i].any);
- }
- }
- }
-}
-
-static void _free_general_cfg (void)
-{
- int i;
-
- for (i = 0; i < NUM_GEN_ELEMENTS; i++)
- if (general_cfg[i].any)
- free(general_cfg[i].any);
-}
-
-void misdn_cfg_get (int port, enum misdn_cfg_elements elem, void *buf, int bufsize)
-{
- int place;
-
- if ((elem < MISDN_CFG_LAST) && !misdn_cfg_is_port_valid(port)) {
- memset(buf, 0, bufsize);
- ast_log(LOG_WARNING, "Invalid call to misdn_cfg_get! Port number %d is not valid.\n", port);
- return;
- }
-
- misdn_cfg_lock();
- if (elem == MISDN_CFG_PTP) {
- if (!memcpy(buf, &ptp[port], (bufsize > ptp[port]) ? sizeof(ptp[port]) : bufsize))
- memset(buf, 0, bufsize);
- } else {
- if ((place = map[elem]) < 0) {
- memset (buf, 0, bufsize);
- ast_log(LOG_WARNING, "Invalid call to misdn_cfg_get! Invalid element (%d) requested.\n", elem);
- } else {
- if (elem < MISDN_CFG_LAST) {
- switch (port_spec[place].type) {
- case MISDN_CTYPE_STR:
- if (port_cfg[port][place].str) {
- if (!memccpy(buf, port_cfg[port][place].str, 0, bufsize))
- memset(buf, 0, 1);
- } else if (port_cfg[0][place].str) {
- if (!memccpy(buf, port_cfg[0][place].str, 0, bufsize))
- memset(buf, 0, 1);
- } else
- memset(buf, 0, bufsize);
- break;
- default:
- if (port_cfg[port][place].any)
- memcpy(buf, port_cfg[port][place].any, bufsize);
- else if (port_cfg[0][place].any)
- memcpy(buf, port_cfg[0][place].any, bufsize);
- else
- memset(buf, 0, bufsize);
- }
- } else {
- switch (gen_spec[place].type) {
- case MISDN_CTYPE_STR:
- if (!general_cfg[place].str || !memccpy(buf, general_cfg[place].str, 0, bufsize))
- memset(buf, 0, 1);
- break;
- default:
- if (general_cfg[place].any)
- memcpy(buf, general_cfg[place].any, bufsize);
- else
- memset(buf, 0, bufsize);
- }
- }
- }
- }
- misdn_cfg_unlock();
-}
-
-enum misdn_cfg_elements misdn_cfg_get_elem (char *name)
-{
- int pos;
-
- /* here comes a hack to replace the (not existing) "name" element with the "ports" element */
- if (!strcmp(name, "ports"))
- return MISDN_CFG_GROUPNAME;
- if (!strcmp(name, "name"))
- return MISDN_CFG_FIRST;
-
- pos = get_cfg_position (name, PORT_CFG);
- if (pos >= 0)
- return port_spec[pos].elem;
-
- pos = get_cfg_position (name, GEN_CFG);
- if (pos >= 0)
- return gen_spec[pos].elem;
-
- return MISDN_CFG_FIRST;
-}
-
-void misdn_cfg_get_name (enum misdn_cfg_elements elem, void *buf, int bufsize)
-{
- struct misdn_cfg_spec *spec = NULL;
- int place = map[elem];
-
- /* the ptp hack */
- if (elem == MISDN_CFG_PTP) {
- memset(buf, 0, 1);
- return;
- }
-
- /* here comes a hack to replace the (not existing) "name" element with the "ports" element */
- if (elem == MISDN_CFG_GROUPNAME) {
- if (!snprintf(buf, bufsize, "ports"))
- memset(buf, 0, 1);
- return;
- }
-
- if ((elem > MISDN_CFG_FIRST) && (elem < MISDN_CFG_LAST))
- spec = (struct misdn_cfg_spec *)port_spec;
- else if ((elem > MISDN_GEN_FIRST) && (elem < MISDN_GEN_LAST))
- spec = (struct misdn_cfg_spec *)gen_spec;
-
- if (!spec || !memccpy(buf, spec[place].name, 0, bufsize))
- memset(buf, 0, 1);
-}
-
-void misdn_cfg_get_desc (enum misdn_cfg_elements elem, void *buf, int bufsize, void *buf_default, int bufsize_default)
-{
- int place = map[elem];
- struct misdn_cfg_spec *spec = NULL;
-
- /* here comes a hack to replace the (not existing) "name" element with the "ports" element */
- if (elem == MISDN_CFG_GROUPNAME) {
- if (!memccpy(buf, ports_description, 0, bufsize))
- memset(buf, 0, 1);
- if (buf_default && bufsize_default)
- memset(buf_default, 0, 1);
- return;
- }
-
- if ((elem > MISDN_CFG_FIRST) && (elem < MISDN_CFG_LAST))
- spec = (struct misdn_cfg_spec *)port_spec;
- else if ((elem > MISDN_GEN_FIRST) && (elem < MISDN_GEN_LAST))
- spec = (struct misdn_cfg_spec *)gen_spec;
-
- if (!spec || !spec[place].desc)
- memset(buf, 0, 1);
- else {
- if (!memccpy(buf, spec[place].desc, 0, bufsize))
- memset(buf, 0, 1);
- if (buf_default && bufsize) {
- if (!strcmp(spec[place].def, NO_DEFAULT))
- memset(buf_default, 0, 1);
- else if (!memccpy(buf_default, spec[place].def, 0, bufsize_default))
- memset(buf_default, 0, 1);
- }
- }
-}
-
-int misdn_cfg_is_msn_valid (int port, char* msn)
-{
- int re = 0;
- struct msn_list *iter;
-
- if (!misdn_cfg_is_port_valid(port)) {
- ast_log(LOG_WARNING, "Invalid call to misdn_cfg_is_msn_valid! Port number %d is not valid.\n", port);
- return 0;
- }
-
- misdn_cfg_lock();
- if (port_cfg[port][map[MISDN_CFG_MSNS]].ml)
- iter = port_cfg[port][map[MISDN_CFG_MSNS]].ml;
- else
- iter = port_cfg[0][map[MISDN_CFG_MSNS]].ml;
- for (; iter; iter = iter->next)
- if (*(iter->msn) == '*' || ast_extension_match(iter->msn, msn)) {
- re = 1;
- break;
- }
- misdn_cfg_unlock();
-
- return re;
-}
-
-int misdn_cfg_is_port_valid (int port)
-{
- int gn = map[MISDN_CFG_GROUPNAME];
-
- return (port >= 1 && port <= max_ports && port_cfg[port][gn].str);
-}
-
-int misdn_cfg_is_group_method (char *group, enum misdn_cfg_method meth)
-{
- int i, re = 0;
- char *method ;
-
- misdn_cfg_lock();
-
- method = port_cfg[0][map[MISDN_CFG_METHOD]].str;
-
- for (i = 1; i <= max_ports; i++) {
- if (port_cfg[i] && port_cfg[i][map[MISDN_CFG_GROUPNAME]].str) {
- if (!strcasecmp(port_cfg[i][map[MISDN_CFG_GROUPNAME]].str, group))
- method = (port_cfg[i][map[MISDN_CFG_METHOD]].str ?
- port_cfg[i][map[MISDN_CFG_METHOD]].str : port_cfg[0][map[MISDN_CFG_METHOD]].str);
- }
- }
-
- if (method) {
- switch (meth) {
- case METHOD_STANDARD: re = !strcasecmp(method, "standard");
- break;
- case METHOD_ROUND_ROBIN: re = !strcasecmp(method, "round_robin");
- break;
- case METHOD_STANDARD_DEC: re = !strcasecmp(method, "standard_dec");
- break;
- }
- }
- misdn_cfg_unlock();
-
- return re;
-}
-
-/*!
- * \brief Generate a comma separated list of all active ports
- */
-void misdn_cfg_get_ports_string (char *ports)
-{
- char tmp[16];
- int l, i;
- int gn = map[MISDN_CFG_GROUPNAME];
-
- *ports = 0;
-
- misdn_cfg_lock();
- for (i = 1; i <= max_ports; i++) {
- if (port_cfg[i][gn].str) {
- if (ptp[i])
- sprintf(tmp, "%dptp,", i);
- else
- sprintf(tmp, "%d,", i);
- strcat(ports, tmp);
- }
- }
- misdn_cfg_unlock();
-
- if ((l = strlen(ports))) {
- /* Strip trailing ',' */
- ports[l-1] = 0;
- }
-}
-
-void misdn_cfg_get_config_string (int port, enum misdn_cfg_elements elem, char* buf, int bufsize)
-{
- int place;
- char tempbuf[BUFFERSIZE] = "";
- struct msn_list *iter;
-
- if ((elem < MISDN_CFG_LAST) && !misdn_cfg_is_port_valid(port)) {
- *buf = 0;
- ast_log(LOG_WARNING, "Invalid call to misdn_cfg_get_config_string! Port number %d is not valid.\n", port);
- return;
- }
-
- place = map[elem];
-
- misdn_cfg_lock();
- if (elem == MISDN_CFG_PTP) {
- snprintf(buf, bufsize, " -> ptp: %s", ptp[port] ? "yes" : "no");
- }
- else if (elem > MISDN_CFG_FIRST && elem < MISDN_CFG_LAST) {
- switch (port_spec[place].type) {
- case MISDN_CTYPE_INT:
- case MISDN_CTYPE_BOOLINT:
- if (port_cfg[port][place].num)
- snprintf(buf, bufsize, " -> %s: %d", port_spec[place].name, *port_cfg[port][place].num);
- else if (port_cfg[0][place].num)
- snprintf(buf, bufsize, " -> %s: %d", port_spec[place].name, *port_cfg[0][place].num);
- else
- snprintf(buf, bufsize, " -> %s:", port_spec[place].name);
- break;
- case MISDN_CTYPE_BOOL:
- if (port_cfg[port][place].num)
- snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name, *port_cfg[port][place].num ? "yes" : "no");
- else if (port_cfg[0][place].num)
- snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name, *port_cfg[0][place].num ? "yes" : "no");
- else
- snprintf(buf, bufsize, " -> %s:", port_spec[place].name);
- break;
- case MISDN_CTYPE_ASTGROUP:
- if (port_cfg[port][place].grp)
- snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name,
- ast_print_group(tempbuf, sizeof(tempbuf), *port_cfg[port][place].grp));
- else if (port_cfg[0][place].grp)
- snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name,
- ast_print_group(tempbuf, sizeof(tempbuf), *port_cfg[0][place].grp));
- else
- snprintf(buf, bufsize, " -> %s:", port_spec[place].name);
- break;
- case MISDN_CTYPE_MSNLIST:
- if (port_cfg[port][place].ml)
- iter = port_cfg[port][place].ml;
- else
- iter = port_cfg[0][place].ml;
- if (iter) {
- for (; iter; iter = iter->next) {
- strncat(tempbuf, iter->msn, sizeof(tempbuf) - strlen(tempbuf) - 1);
- }
- tempbuf[strlen(tempbuf)-2] = 0;
- }
- snprintf(buf, bufsize, " -> msns: %s", *tempbuf ? tempbuf : "none");
- break;
- case MISDN_CTYPE_STR:
- if ( port_cfg[port][place].str) {
- snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name, port_cfg[port][place].str);
- } else if (port_cfg[0][place].str) {
- snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name, port_cfg[0][place].str);
- } else {
- snprintf(buf, bufsize, " -> %s:", port_spec[place].name);
- }
- break;
- }
- } else if (elem > MISDN_GEN_FIRST && elem < MISDN_GEN_LAST) {
- switch (gen_spec[place].type) {
- case MISDN_CTYPE_INT:
- case MISDN_CTYPE_BOOLINT:
- if (general_cfg[place].num)
- snprintf(buf, bufsize, " -> %s: %d", gen_spec[place].name, *general_cfg[place].num);
- else
- snprintf(buf, bufsize, " -> %s:", gen_spec[place].name);
- break;
- case MISDN_CTYPE_BOOL:
- if (general_cfg[place].num)
- snprintf(buf, bufsize, " -> %s: %s", gen_spec[place].name, *general_cfg[place].num ? "yes" : "no");
- else
- snprintf(buf, bufsize, " -> %s:", gen_spec[place].name);
- break;
- case MISDN_CTYPE_STR:
- if ( general_cfg[place].str) {
- snprintf(buf, bufsize, " -> %s: %s", gen_spec[place].name, general_cfg[place].str);
- } else {
- snprintf(buf, bufsize, " -> %s:", gen_spec[place].name);
- }
- break;
- default:
- snprintf(buf, bufsize, " -> type of %s not handled yet", gen_spec[place].name);
- break;
- }
- } else {
- *buf = 0;
- ast_log(LOG_WARNING, "Invalid call to misdn_cfg_get_config_string! Invalid config element (%d) requested.\n", elem);
- }
- misdn_cfg_unlock();
-}
-
-int misdn_cfg_get_next_port (int port)
-{
- int p = -1;
- int gn = map[MISDN_CFG_GROUPNAME];
-
- misdn_cfg_lock();
- for (port++; port <= max_ports; port++) {
- if (port_cfg[port][gn].str) {
- p = port;
- break;
- }
- }
- misdn_cfg_unlock();
-
- return p;
-}
-
-int misdn_cfg_get_next_port_spin (int port)
-{
- int p = misdn_cfg_get_next_port(port);
- return (p > 0) ? p : misdn_cfg_get_next_port(0);
-}
-
-static int _parse (union misdn_cfg_pt *dest, char *value, enum misdn_cfg_type type, int boolint_def)
-{
- int re = 0;
- int len, tmp;
- char *valtmp;
-
- switch (type) {
- case MISDN_CTYPE_STR:
- if ((len = strlen(value))) {
- dest->str = (char *)malloc((len + 1) * sizeof(char));
- strncpy(dest->str, value, len);
- dest->str[len] = 0;
- } else {
- dest->str = (char *)malloc( sizeof(char));
- dest->str[0] = 0;
- }
- break;
- case MISDN_CTYPE_INT:
- {
- char *pat;
- if (strchr(value,'x'))
- pat="%x";
- else
- pat="%d";
- if (sscanf(value, pat, &tmp)) {
- dest->num = (int *)malloc(sizeof(int));
- memcpy(dest->num, &tmp, sizeof(int));
- } else
- re = -1;
- }
- break;
- case MISDN_CTYPE_BOOL:
- dest->num = (int *)malloc(sizeof(int));
- *(dest->num) = (ast_true(value) ? 1 : 0);
- break;
- case MISDN_CTYPE_BOOLINT:
- dest->num = (int *)malloc(sizeof(int));
- if (sscanf(value, "%d", &tmp)) {
- memcpy(dest->num, &tmp, sizeof(int));
- } else {
- *(dest->num) = (ast_true(value) ? boolint_def : 0);
- }
- break;
- case MISDN_CTYPE_MSNLIST:
- for (valtmp = strsep(&value, ","); valtmp; valtmp = strsep(&value, ",")) {
- if ((len = strlen(valtmp))) {
- struct msn_list *ml = (struct msn_list *)malloc(sizeof(struct msn_list));
- ml->msn = (char *)calloc(len+1, sizeof(char));
- strncpy(ml->msn, valtmp, len);
- ml->next = dest->ml;
- dest->ml = ml;
- }
- }
- break;
- case MISDN_CTYPE_ASTGROUP:
- dest->grp = (ast_group_t *)malloc(sizeof(ast_group_t));
- *(dest->grp) = ast_get_group(value);
- break;
- }
-
- return re;
-}
-
-static void _build_general_config (struct ast_variable *v)
-{
- int pos;
-
- for (; v; v = v->next) {
- if (((pos = get_cfg_position(v->name, GEN_CFG)) < 0) ||
- (_parse(&general_cfg[pos], v->value, gen_spec[pos].type, gen_spec[pos].boolint_def) < 0))
- CLI_ERROR(v->name, v->value, "general");
- }
-}
-
-static void _build_port_config (struct ast_variable *v, char *cat)
-{
- int pos, i;
- union misdn_cfg_pt cfg_tmp[NUM_PORT_ELEMENTS];
- int cfg_for_ports[max_ports + 1];
-
- if (!v || !cat)
- return;
-
- memset(cfg_tmp, 0, sizeof(cfg_tmp));
- memset(cfg_for_ports, 0, sizeof(cfg_for_ports));
-
- if (!strcasecmp(cat, "default")) {
- cfg_for_ports[0] = 1;
- }
-
- if (((pos = get_cfg_position("name", PORT_CFG)) < 0) ||
- (_parse(&cfg_tmp[pos], cat, port_spec[pos].type, port_spec[pos].boolint_def) < 0)) {
- CLI_ERROR(v->name, v->value, cat);
- return;
- }
-
- for (; v; v = v->next) {
- if (!strcasecmp(v->name, "ports")) {
- char *token;
- char ptpbuf[BUFFERSIZE] = "";
- int start, end;
- for (token = strsep(&v->value, ","); token; token = strsep(&v->value, ","), *ptpbuf = 0) {
- if (!*token)
- continue;
- if (sscanf(token, "%d-%d%s", &start, &end, ptpbuf) >= 2) {
- for (; start <= end; start++) {
- if (start <= max_ports && start > 0) {
- cfg_for_ports[start] = 1;
- ptp[start] = (strstr(ptpbuf, "ptp")) ? 1 : 0;
- } else
- CLI_ERROR(v->name, v->value, cat);
- }
- } else {
- if (sscanf(token, "%d%s", &start, ptpbuf)) {
- if (start <= max_ports && start > 0) {
- cfg_for_ports[start] = 1;
- ptp[start] = (strstr(ptpbuf, "ptp")) ? 1 : 0;
- } else
- CLI_ERROR(v->name, v->value, cat);
- } else
- CLI_ERROR(v->name, v->value, cat);
- }
- }
- } else {
- if (((pos = get_cfg_position(v->name, PORT_CFG)) < 0) ||
- (_parse(&cfg_tmp[pos], v->value, port_spec[pos].type, port_spec[pos].boolint_def) < 0))
- CLI_ERROR(v->name, v->value, cat);
- }
- }
-
- for (i = 0; i < (max_ports + 1); ++i) {
- if (cfg_for_ports[i]) {
- memcpy(port_cfg[i], cfg_tmp, sizeof(cfg_tmp));
- }
- }
-}
-
-void misdn_cfg_update_ptp (void)
-{
-#ifndef MISDN_1_2
- char misdn_init[BUFFERSIZE];
- char line[BUFFERSIZE];
- FILE *fp;
- char *tok, *p, *end;
- int port;
-
- misdn_cfg_get(0, MISDN_GEN_MISDN_INIT, &misdn_init, sizeof(misdn_init));
-
- if (!ast_strlen_zero(misdn_init)) {
- fp = fopen(misdn_init, "r");
- if (fp) {
- while(fgets(line, sizeof(line), fp)) {
- if (!strncmp(line, "nt_ptp", 6)) {
- for (tok = strtok_r(line,",=", &p);
- tok;
- tok = strtok_r(NULL,",=", &p)) {
- port = strtol(tok, &end, 10);
- if (end != tok && misdn_cfg_is_port_valid(port)) {
- misdn_cfg_lock();
- ptp[port] = 1;
- misdn_cfg_unlock();
- }
- }
- }
- }
- fclose(fp);
- } else {
- ast_log(LOG_WARNING,"Couldn't open %s: %s\n", misdn_init, strerror(errno));
- }
- }
-#else
- int i;
- int proto;
- char filename[128];
- FILE *fp;
-
- for (i = 1; i <= max_ports; ++i) {
- snprintf(filename, sizeof(filename), "/sys/class/mISDN-stacks/st-%08x/protocol", i << 8);
- fp = fopen(filename, "r");
- if (!fp) {
- ast_log(LOG_WARNING, "Could not open %s: %s\n", filename, strerror(errno));
- continue;
- }
- if (fscanf(fp, "0x%08x", &proto) != 1)
- ast_log(LOG_WARNING, "Could not parse contents of %s!\n", filename);
- else
- ptp[i] = proto & 1<<5 ? 1 : 0;
- fclose(fp);
- }
-#endif
-}
-
-static void _fill_defaults (void)
-{
- int i;
-
- for (i = 0; i < NUM_PORT_ELEMENTS; ++i) {
- if (!port_cfg[0][i].any && strcasecmp(port_spec[i].def, NO_DEFAULT))
- _parse(&(port_cfg[0][i]), (char *)port_spec[i].def, port_spec[i].type, port_spec[i].boolint_def);
- }
- for (i = 0; i < NUM_GEN_ELEMENTS; ++i) {
- if (!general_cfg[i].any && strcasecmp(gen_spec[i].def, NO_DEFAULT))
- _parse(&(general_cfg[i]), (char *)gen_spec[i].def, gen_spec[i].type, gen_spec[i].boolint_def);
- }
-}
-
-void misdn_cfg_reload (void)
-{
- misdn_cfg_init (0);
-}
-
-void misdn_cfg_destroy (void)
-{
- misdn_cfg_lock();
-
- _free_port_cfg();
- _free_general_cfg();
-
- free(port_cfg);
- free(general_cfg);
- free(ptp);
- free(map);
-
- misdn_cfg_unlock();
- ast_mutex_destroy(&config_mutex);
-}
-
-int misdn_cfg_init (int this_max_ports)
-{
- char config[] = "misdn.conf";
- char *cat, *p;
- int i;
- struct ast_config *cfg;
- struct ast_variable *v;
-
- if (!(cfg = AST_LOAD_CFG(config))) {
- ast_log(LOG_WARNING, "missing file: misdn.conf\n");
- return -1;
- }
-
- ast_mutex_init(&config_mutex);
-
- misdn_cfg_lock();
-
- if (this_max_ports) {
- /* this is the first run */
- max_ports = this_max_ports;
- map = (int *)calloc(MISDN_GEN_LAST + 1, sizeof(int));
- if (_enum_array_map())
- return -1;
- p = (char *)calloc(1, (max_ports + 1) * sizeof(union misdn_cfg_pt *)
- + (max_ports + 1) * NUM_PORT_ELEMENTS * sizeof(union misdn_cfg_pt));
- port_cfg = (union misdn_cfg_pt **)p;
- p += (max_ports + 1) * sizeof(union misdn_cfg_pt *);
- for (i = 0; i <= max_ports; ++i) {
- port_cfg[i] = (union misdn_cfg_pt *)p;
- p += NUM_PORT_ELEMENTS * sizeof(union misdn_cfg_pt);
- }
- general_cfg = (union misdn_cfg_pt *)calloc(1, sizeof(union misdn_cfg_pt *) * NUM_GEN_ELEMENTS);
- ptp = (int *)calloc(max_ports + 1, sizeof(int));
- }
- else {
- /* misdn reload */
- _free_port_cfg();
- _free_general_cfg();
- memset(port_cfg[0], 0, NUM_PORT_ELEMENTS * sizeof(union misdn_cfg_pt) * (max_ports + 1));
- memset(general_cfg, 0, sizeof(union misdn_cfg_pt *) * NUM_GEN_ELEMENTS);
- memset(ptp, 0, sizeof(int) * (max_ports + 1));
- }
-
- cat = ast_category_browse(cfg, NULL);
-
- while(cat) {
- v = ast_variable_browse(cfg, cat);
- if (!strcasecmp(cat, "general")) {
- _build_general_config(v);
- } else {
- _build_port_config(v, cat);
- }
- cat = ast_category_browse(cfg, cat);
- }
-
- _fill_defaults();
-
- misdn_cfg_unlock();
- AST_DESTROY_CFG(cfg);
-
- return 0;
-}
-
-
diff --git a/1.4.23-rc4/channels/ring10.h b/1.4.23-rc4/channels/ring10.h
deleted file mode 100644
index f45f8dbb9..000000000
--- a/1.4.23-rc4/channels/ring10.h
+++ /dev/null
@@ -1,1752 +0,0 @@
-/*! \file
- * \brief Signed 16-bit audio data
- *
- * Source: /home/markster/ring10.raw
- *
- * Copyright (C) 1999-2005, Digium, Inc.
- *
- * Distributed under the terms of the GNU General Public License
- *
- */
-
-static signed short ring10[] = {
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 0x82a0, 0x8dc7, 0x607e, 0xc0c6, 0x2bd3,
-0x8df5, 0x828d, 0x0716, 0xaca6, 0xcefe, 0x41df, 0xd185, 0x8aa3, 0x8b1a, 0x789b,
-0x82a2, 0x804f, 0x7ea8, 0x8113, 0x7f7d, 0x7fff, 0x801e, 0x801d, 0x7f32, 0x82ec,
-0x83e1, 0x7fb0, 0x7f71, 0x80de, 0x7f3d, 0x7fe3, 0x81b4, 0x7c37, 0x8553, 0x7b29,
-0x7ede, 0xde6e, 0x0e64, 0xf9f4, 0x015e, 0x00f6, 0xfe56, 0x0019, 0xf8bb, 0xfd90,
-0x08cc, 0x05ab, 0xfd0b, 0xf9c6, 0xf875, 0xf789, 0xfc74, 0x032e, 0xf97a, 0xf4bb,
-0x0212, 0x006e, 0x03df, 0x17c5, 0x0f50, 0xfb23, 0xfdbd, 0xf7cf, 0xdf5b, 0xe2d3,
-0xf111, 0xef27, 0x11c5, 0x33a4, 0x168d, 0x0145, 0x0494, 0xe85c, 0xdac3, 0xf0c7,
-0xeea8, 0x0023, 0x3036, 0x252a, 0xffb7, 0x01d1, 0xf637, 0xd506, 0xe8eb, 0xf5ff,
-0xe5ca, 0x1ec5, 0x3fa4, 0x0e3c, 0x1570, 0x2b37, 0xea23, 0xca43, 0xf392, 0xdf0e,
-0xde40, 0x2e7c, 0x276f, 0x035c, 0x2ccc, 0x1acf, 0xcf4a, 0xeb5b, 0x0fb1, 0xe01a,
-0x0c69, 0x3a97, 0xfb54, 0x0751, 0x20f1, 0xdce9, 0xd2a2, 0x19b3, 0x096f, 0xf1b6,
-0x38de, 0x1f70, 0xf32b, 0x2569, 0x0650, 0xc3d7, 0xf1ad, 0x1aa5, 0xe87e, 0x0c7f,
-0x406d, 0xffaa, 0x0ba8, 0x2e02, 0xe545, 0xcebb, 0x10fc, 0x0102, 0xded8, 0x2b7c,
-0x2053, 0xec6f, 0x266e, 0x1770, 0xcb63, 0xf18e, 0x2015, 0xe6ef, 0xfe64, 0x3700,
-0xf628, 0xfb00, 0x2e43, 0xee48, 0xcd4a, 0x1867, 0x0ec3, 0xdd77, 0x2291, 0x1c80,
-0xe325, 0x19b7, 0x1719, 0xcb88, 0xeded, 0x258c, 0xe7e8, 0xf0c6, 0x2d21, 0xf3d5,
-0xf494, 0x290d, 0xef7b, 0xca28, 0x12c8, 0x0d8d, 0xd5f3, 0x171d, 0x1994, 0xe0c0,
-0x1348, 0x1929, 0xcf9b, 0xe6fb, 0x20ae, 0xe921, 0xed2b, 0x2c54, 0xf96e, 0xf19f,
-0x21b6, 0xf12e, 0xc8b4, 0x0907, 0x0964, 0xd049, 0x0eb8, 0x1fa6, 0xe6b5, 0x0cec,
-0x16b6, 0xcd0c, 0xda57, 0x17c9, 0xe440, 0xe2a2, 0x2b4d, 0xffa2, 0xec7e, 0x1ee9,
-0xf674, 0xbfcb, 0xf769, 0x0402, 0xcfe8, 0x104b, 0x2734, 0xe7e9, 0x07d9, 0x19f4,
-0xd032, 0xd00b, 0x0e46, 0xe17d, 0xe2d8, 0x3456, 0x0781, 0xed01, 0x238d, 0xfa72,
-0xbb51, 0xf543, 0x050b, 0xccd5, 0x1491, 0x3358, 0xedad, 0x10c4, 0x283b, 0xd051,
-0xc9e9, 0x11f8, 0xe2cb, 0xe534, 0x43aa, 0x1090, 0xf11b, 0x3267, 0x02c3, 0xb72d,
-0xf9ac, 0x0fbd, 0xce45, 0x1d7b, 0x4389, 0xef2e, 0x1593, 0x348e, 0xd0cb, 0xca8c,
-0x1f61, 0xe981, 0xdef7, 0x4774, 0x15ae, 0xefab, 0x3b28, 0x0a9e, 0xb2f6, 0xf9e9,
-0x1976, 0xcc08, 0x15ab, 0x4534, 0xee6c, 0x159b, 0x3753, 0xcf09, 0xc69a, 0x2270,
-0xf15c, 0xdee6, 0x48ce, 0x1af4, 0xf169, 0x3da0, 0x0d68, 0xb573, 0xff9e, 0x20ba,
-0xcbfe, 0x142d, 0x4879, 0xed49, 0x1434, 0x3d96, 0xd714, 0xca99, 0x298b, 0xf708,
-0xd92c, 0x4632, 0x1acc, 0xea6e, 0x3d2c, 0x1412, 0xb534, 0xfbfa, 0x24f9, 0xcd72,
-0x0df9, 0x48f8, 0xeb87, 0x0bca, 0x3dd5, 0xd6cc, 0xc015, 0x2605, 0xfa87, 0xd1a9,
-0x40d0, 0x1c59, 0xe0de, 0x34f9, 0x14c6, 0xaf61, 0xf2a5, 0x23e6, 0xc929, 0x01be,
-0x4423, 0xe53b, 0x0182, 0x3c3a, 0xd758, 0xbb9d, 0x1fa9, 0xf454, 0xc611, 0x36e8,
-0x18f7, 0xdac9, 0x2e8a, 0x126d, 0xac14, 0xead6, 0x2215, 0xc990, 0xf9f5, 0x43cb,
-0xea01, 0xfcbf, 0x38fd, 0xd9f3, 0xb7cd, 0x1bc4, 0xfd41, 0xca56, 0x31e3, 0x1d4b,
-0xdca2, 0x2a9f, 0x1c24, 0xb8aa, 0xeb59, 0x25d5, 0xd2d0, 0xfa10, 0x44fa, 0xefe0,
-0xfced, 0x3ef4, 0xe9a1, 0xbdf0, 0x19ac, 0x0198, 0xca6f, 0x2f04, 0x25b6, 0xe187,
-0x29ba, 0x250a, 0xbe42, 0xe40e, 0x24ef, 0xd75d, 0xf476, 0x44f8, 0xf719, 0xf7a1,
-0x3c94, 0xf20e, 0xbcdf, 0x16a3, 0x07e8, 0xc8d4, 0x2a3e, 0x2b3f, 0xdf4e, 0x235d,
-0x2c92, 0xc2c7, 0xdf39, 0x2873, 0xd790, 0xea2a, 0x47fd, 0xfd0e, 0xf0e3, 0x3bd8,
-0xf4e9, 0xb265, 0x0c2c, 0x0751, 0xc302, 0x29bb, 0x37bd, 0xe138, 0x1e0c, 0x2d09,
-0xbddb, 0xd246, 0x24c4, 0xd87a, 0xe5df, 0x4ff6, 0x08d6, 0xf0d8, 0x3d61, 0xf8bf,
-0xaede, 0x0a36, 0x0df3, 0xc0f5, 0x23ec, 0x3e92, 0xe3d7, 0x1cad, 0x348e, 0xc0d6,
-0xcd4e, 0x265c, 0xd9b6, 0xdf83, 0x510e, 0x0c41, 0xeece, 0x4153, 0xfeeb, 0xa9f6,
-0x04b3, 0x12a4, 0xbf2f, 0x20d1, 0x42f4, 0xe1b1, 0x1b1e, 0x3980, 0xc2b4, 0xcb50,
-0x2b74, 0xded0, 0xd835, 0x4e7a, 0x0b46, 0xe555, 0x4015, 0x0517, 0xaa54, 0x0504,
-0x1932, 0xbc34, 0x1a77, 0x48b1, 0xe0bb, 0x149b, 0x3ba7, 0xc34a, 0xc481, 0x2bc2,
-0xe401, 0xd20e, 0x4f53, 0x1389, 0xe3b7, 0x418b, 0x0a15, 0xa70d, 0x0024, 0x1f9f,
-0xbf65, 0x142d, 0x4a81, 0xe0ca, 0x1152, 0x4325, 0xcb03, 0xc18a, 0x2b95, 0xeb45,
-0xcf92, 0x4c54, 0x18ad, 0xe08b, 0x3f12, 0x1264, 0xa9fc, 0xfd97, 0x246f, 0xbf86,
-0x0ce2, 0x4e7c, 0xe4f3, 0x0c20, 0x44e0, 0xd069, 0xbdcb, 0x2b8e, 0xf32d, 0xcad4,
-0x464f, 0x1e76, 0xdf62, 0x3b07, 0x17ea, 0xaafb, 0xf5a0, 0x2835, 0xc7c2, 0x0842,
-0x4d2b, 0xe634, 0x03ef, 0x42bc, 0xd7f2, 0xbb73, 0x2662, 0xf892, 0xc8b3, 0x3e30,
-0x1f20, 0xdcca, 0x354a, 0x1c6b, 0xaf75, 0xf0f7, 0x2963, 0xc908, 0xfdbf, 0x4c3c,
-0xebe5, 0x00e3, 0x44c4, 0xdf15, 0xb9e9, 0x243b, 0x00e9, 0xcb76, 0x3b53, 0x248e,
-0xdc27, 0x2fcb, 0x22e5, 0xb66c, 0xec96, 0x2b19, 0xd0ef, 0xf97b, 0x48ae, 0xecc0,
-0xf8b4, 0x411d, 0xe769, 0xb9f7, 0x1c41, 0x0022, 0xc369, 0x2ced, 0x23ac, 0xd8eb,
-0x2522, 0x232a, 0xb611, 0xe19f, 0x2738, 0xd013, 0xece5, 0x434c, 0xf00e, 0xefcc,
-0x3b79, 0xeb32, 0xb19c, 0x135e, 0x04ef, 0xc1b9, 0x27a8, 0x2992, 0xd7b3, 0x1ba5,
-0x2481, 0xb8c5, 0xd97d, 0x246f, 0xd113, 0xe45d, 0x4486, 0xf7f7, 0xeb36, 0x395a,
-0xf122, 0xaea5, 0x0c28, 0x05eb, 0xbde4, 0x2585, 0x36a2, 0xde67, 0x1b86, 0x2dac,
-0xbd03, 0xd2b8, 0x2624, 0xd8b8, 0xe802, 0x521b, 0x0855, 0xefbc, 0x4048, 0xfad2,
-0xafe2, 0x0fb1, 0x12b2, 0xc62c, 0x2c2a, 0x43f5, 0xe562, 0x1fcb, 0x3791, 0xc2ac,
-0xd4d1, 0x2dfd, 0xde0a, 0xe53f, 0x5578, 0x0f49, 0xf2b6, 0x4609, 0x0105, 0xabf5,
-0x09a8, 0x157e, 0xc286, 0x23e7, 0x425f, 0xe36a, 0x1d93, 0x3580, 0xbf80, 0xcaf2,
-0x2a04, 0xf16e, 0xd92b, 0x0eaa, 0xf1a7, 0x1ddb, 0x5b52, 0x0665, 0xd2e3, 0x15f8,
-0xf606, 0x9d42, 0xdba7, 0xf312, 0xd349, 0x21ed, 0x576a, 0x34e8, 0x2450, 0x2679,
-0xdc01, 0xb506, 0xcb0f, 0xa454, 0xccf3, 0x2c13, 0x1673, 0xf8ca, 0x4ff1, 0x63ac,
-0xec26, 0xd77c, 0xf1f9, 0xc268, 0xb11a, 0xdfe4, 0x02e7, 0x10f5, 0x3512, 0x19dd,
-0x0edc, 0x3568, 0xf6f7, 0xbe10, 0xda93, 0xf4fe, 0xda03, 0xe293, 0x15dd, 0x15f3,
-0x1ba5, 0x1521, 0x12e8, 0x23ab, 0x0fc3, 0xdb3e, 0xb671, 0xe960, 0xe13c, 0xc695,
-0x1a81, 0x3d23, 0x1c56, 0x190d, 0x4234, 0x1970, 0xd784, 0xd86b, 0xb5e8, 0xc9f3,
-0xeb89, 0xe344, 0x17ae, 0x5713, 0x37fc, 0xffe2, 0x36b3, 0x1dfe, 0xb963, 0xbf9c,
-0xc9a1, 0xcc7b, 0xe409, 0x08a6, 0x2077, 0x3b4d, 0x3cba, 0x0553, 0x220e, 0x226e,
-0xd219, 0xb7ec, 0xcb8b, 0xdf2a, 0xd0c7, 0xf5be, 0x2ff0, 0x42a6, 0x3c24, 0x25ae,
-0x2d6d, 0x0d94, 0xde80, 0xb78b, 0xb12b, 0xdf7a, 0xde33, 0x0046, 0x47b1, 0x5170,
-0x29c0, 0x2945, 0x3ab5, 0xf08f, 0xc806, 0xc229, 0xbbf4, 0xe40d, 0xf365, 0x0bfe,
-0x448d, 0x5cd8, 0x1e52, 0x10ba, 0x3908, 0xefa4, 0xc243, 0xcf89, 0xd02d, 0xde92,
-0xf8e0, 0x191e, 0x2f7b, 0x48e6, 0x1e38, 0x1074, 0x3785, 0xf8be, 0xbd1c, 0xc06b,
-0xdc36, 0xdb97, 0xe3c0, 0x2042, 0x37c5, 0x36ff, 0x1b73, 0x2064, 0x2c9a, 0xefa2,
-0xbf0c, 0xb7f0, 0xe221, 0xe243, 0xd998, 0x2263, 0x4bae, 0x3596, 0x18aa, 0x3763,
-0x27d0, 0xdcc6, 0xcacc, 0xc06f, 0xd83d, 0xecfe, 0xeefa, 0x1ffa, 0x5052, 0x393f,
-0x0af5, 0x3c9e, 0x316b, 0xd2df, 0xc575, 0xd3c8, 0xddd2, 0xdf98, 0xfbd7, 0x2929,
-0x4879, 0x4052, 0x160c, 0x3708, 0x2b31, 0xdac6, 0xc0c3, 0xcfc0, 0xe71d, 0xddec,
-0x0145, 0x3847, 0x457c, 0x356b, 0x214a, 0x3a5f, 0x1474, 0xd892, 0xc579, 0xc6a7,
-0xe77a, 0xe4dc, 0x00ab, 0x3b89, 0x4eba, 0x290a, 0x16ea, 0x3dc6, 0x0956, 0xcc12,
-0xc3bd, 0xc9e9, 0xe4be, 0xe60b, 0x0561, 0x3707, 0x4c82, 0x2444, 0x1406, 0x3a8e,
-0xff5b, 0xc494, 0xbf9f, 0xcb26, 0xdfef, 0xe755, 0x1060, 0x334f, 0x40e5, 0x1f87,
-0x16b9, 0x33e8, 0xfa6e, 0xc670, 0xb774, 0xcc17, 0xe18f, 0xdd0f, 0x102c, 0x3f0d,
-0x4098, 0x1b95, 0x24b2, 0x315a, 0xe9d8, 0xc459, 0xb314, 0xc524, 0xe2a6, 0xe1cf,
-0x100a, 0x44af, 0x455c, 0x1551, 0x264f, 0x2ab1, 0xd681, 0xb90c, 0xb4d6, 0xc68d,
-0xddac, 0xef74, 0x1f57, 0x4357, 0x4192, 0x0e60, 0x1bcb, 0x20fd, 0xd477, 0xb435,
-0xb3e3, 0xcdc3, 0xd9c4, 0xef97, 0x2384, 0x3b60, 0x34c9, 0x119d, 0x1f15, 0x0fb3,
-0xd15d, 0xb30d, 0xa9e3, 0xd431, 0xdc02, 0xe98a, 0x2987, 0x4204, 0x290c, 0x1181,
-0x2d0c, 0x0800, 0xcb55, 0xb8f5, 0xaaa6, 0xd49f, 0xe57c, 0xf063, 0x281c, 0x4c65,
-0x2d19, 0x0cd2, 0x2ddb, 0xfefe, 0xc171, 0xbd4c, 0xb7c2, 0xd4c5, 0xe6f3, 0x0040,
-0x2b86, 0x4b6d, 0x2ed1, 0x0ce3, 0x2d97, 0x01f9, 0xc2ad, 0xb8fc, 0xc53e, 0xe1cf,
-0xea35, 0x0eb0, 0x38b8, 0x4a3b, 0x2a1e, 0x1457, 0x2a1e, 0xfbca, 0xcdf1, 0xbc93,
-0xcc0b, 0xec27, 0xeb05, 0x144b, 0x4443, 0x496d, 0x2233, 0x2180, 0x30b2, 0xf03c,
-0xcced, 0xbf0d, 0xcc55, 0xeec3, 0xf367, 0x186f, 0x45cd, 0x4e7d, 0x215a, 0x2485,
-0x3122, 0xe7a8, 0xc40a, 0xbf85, 0xd4dd, 0xebe8, 0xf32b, 0x2121, 0x49bb, 0x4c61,
-0x1af5, 0x1f88, 0x2c32, 0xe8c5, 0xc512, 0xc0b7, 0xdbf9, 0xe9ea, 0xf2f4, 0x2584,
-0x43e2, 0x3e1b, 0x19cf, 0x28d2, 0x2442, 0xe27b, 0xc589, 0xbe8a, 0xdddc, 0xe567,
-0xed4e, 0x27f2, 0x48cd, 0x3505, 0x0e88, 0x2cd5, 0x207d, 0xda54, 0xc1cf, 0xb8c1,
-0xd925, 0xe569, 0xefd0, 0x2723, 0x4dd1, 0x38b2, 0x0de5, 0x2d90, 0x155b, 0xca06,
-0xbab6, 0xbf37, 0xdd46, 0xe3fd, 0xfb50, 0x2e5d, 0x487b, 0x343e, 0x0abe, 0x25e9,
-0x0f65, 0xcb83, 0xb474, 0xbc50, 0xe2ab, 0xe1df, 0xfd3e, 0x3672, 0x458b, 0x294e,
-0x10fd, 0x2afa, 0x027f, 0xcae8, 0xb95b, 0xbc6f, 0xe536, 0xe3af, 0xfd1c, 0x3b18,
-0x4cb1, 0x23ff, 0x13eb, 0x3353, 0xfb34, 0xc4aa, 0xb71a, 0xb9f2, 0xe1d7, 0xe97f,
-0x058d, 0x3a0f, 0x4fcd, 0x2408, 0x11a3, 0x2fb9, 0xf271, 0xbb7f, 0xb447, 0xc317,
-0xde44, 0xe56a, 0x110a, 0x3ccc, 0x494a, 0x1f80, 0x11af, 0x26a1, 0xeb09, 0xbcd0,
-0xaf90, 0xc8d4, 0xe63f, 0xe47d, 0x1435, 0x3f4f, 0x3fbe, 0x17c7, 0x1a4f, 0x2393,
-0xe191, 0xbfa1, 0xb0e4, 0xc7c9, 0xe2d9, 0xe363, 0x1625, 0x4320, 0x3da9, 0x11c4,
-0x1e02, 0x1d1b, 0xd6be, 0xbe96, 0xb123, 0xc8a4, 0xe6ce, 0xef2e, 0x1c03, 0x4584,
-0x3fd1, 0x1006, 0x20d8, 0x197b, 0xcf64, 0xb99e, 0xb693, 0xd396, 0xe8eb, 0xfb01,
-0x2aca, 0x4b38, 0x3f87, 0x0de0, 0x1f2f, 0x1503, 0xd574, 0xba46, 0xb72d, 0xf07a,
-0xfa16, 0xf608, 0x29c0, 0x3a7e, 0x42a7, 0x43ac, 0x2717, 0xec6f, 0xd732, 0xc1ac,
-0xa146, 0xef37, 0x122b, 0x05c1, 0x5c67, 0x8e8c, 0x3d5e, 0x0043, 0x00d0, 0xb9ef,
-0xa38d, 0xc8dd, 0xc921, 0x15c9, 0x5fe3, 0x531a, 0x477d, 0x5852, 0x1b9f, 0xb930,
-0xd1b6, 0xde60, 0xbcce, 0xe7f7, 0x16b1, 0x2aeb, 0x4605, 0x3592, 0xfe8c, 0x0c1d,
-0x1b24, 0xd084, 0xd667, 0x2736, 0x06f7, 0xdfa7, 0x1976, 0x0df9, 0xc5e8, 0x032b,
-0x324e, 0xea0e, 0x1ab4, 0x46e4, 0xf72e, 0x0369, 0x0ef3, 0xbe35, 0xbd17, 0x10fd,
-0xfb35, 0xeb3f, 0x4e43, 0x2da4, 0xfe31, 0x2f50, 0xf64c, 0xafd6, 0xe267, 0xfd01,
-0xca77, 0x1087, 0x48c1, 0xfcf4, 0x1bb0, 0x31af, 0xd234, 0xc0cb, 0x054e, 0xec6b,
-0xce29, 0x29db, 0x1bb4, 0xf0fd, 0x3608, 0x12eb, 0xbb40, 0xeaa8, 0x190f, 0xce00,
-0xed59, 0x39ef, 0xf1f0, 0xfb2a, 0x3535, 0xe3b3, 0xbf33, 0x1a9b, 0x013b, 0xc2ab,
-0x2976, 0x21e0, 0xd3d8, 0x1ca6, 0x14ae, 0xb242, 0xe538, 0x2958, 0xd98c, 0xf279,
-0x4106, 0xf13e, 0xf68b, 0x3379, 0xe023, 0xb4a8, 0x104b, 0x0685, 0xcca4, 0x2e61,
-0x2d96, 0xe2b8, 0x26ac, 0x2510, 0xc114, 0xd9e5, 0x1f91, 0xdbc9, 0xe515, 0x40bd,
-0x0693, 0xff44, 0x3c5e, 0xf664, 0xb8dc, 0x0b37, 0x1314, 0xc29c, 0x161f, 0x3582,
-0xe32e, 0x17c0, 0x2de6, 0xc7c1, 0xcfeb, 0x23a6, 0xe644, 0xe65f, 0x4256, 0xf765,
-0xe698, 0x4148, 0xfbe1, 0xa6b4, 0x03fa, 0x1c92, 0xcb85, 0x1a54, 0x37af, 0xe830,
-0x1b0b, 0x255d, 0xc13f, 0xd3d9, 0x205e, 0xde69, 0xe2ab, 0x48d5, 0x0931, 0xee2f,
-0x3d79, 0x0658, 0xb36c, 0xf59e, 0x11f4, 0xd042, 0x110b, 0x2e1b, 0xe763, 0x2269,
-0x3bda, 0xcefb, 0xd37b, 0x2d7f, 0xe9d7, 0xd48e, 0x3fd2, 0x0e86, 0xea62, 0x3cd5,
-0x11e0, 0xc1dc, 0x08e0, 0x1f68, 0xd3f1, 0x1fc8, 0x3da6, 0xe12f, 0x1d62, 0x4060,
-0xccb6, 0xd211, 0x316f, 0xf370, 0xe20e, 0x4657, 0x1280, 0xf30a, 0x3df0, 0x07fc,
-0xb956, 0x023e, 0x1978, 0xcbba, 0x137d, 0x3ff7, 0xecbc, 0x1698, 0x3f29, 0xdf9f,
-0xcc1c, 0x1bdc, 0xef17, 0xd3da, 0x346b, 0x1296, 0xeb25, 0x3885, 0x190f, 0xbf13,
-0xfb71, 0x1df2, 0xc509, 0xffa2, 0x3a66, 0xe5fd, 0x04f6, 0x36be, 0xda99, 0xc67e,
-0x1fc2, 0xef95, 0xcfa8, 0x39df, 0x0f1a, 0xd986, 0x2d7b, 0x0e88, 0xb2a2, 0xf40f,
-0x1bd3, 0xc95c, 0x0511, 0x408d, 0xec48, 0x03d2, 0x3281, 0xd7a0, 0xb9a0, 0x13ab,
-0xf02d, 0xc92c, 0x3af6, 0x26c0, 0xe5f8, 0x2de7, 0x18b9, 0xafd8, 0xddbf, 0x15bc,
-0xc4d3, 0xf6dc, 0x4b73, 0xf89f, 0x018a, 0x3c4e, 0xdf11, 0xb20d, 0x12d7, 0xf511,
-0xbf7e, 0x33aa, 0x286f, 0xe309, 0x3107, 0x1f74, 0xb1c3, 0xe10f, 0x1fd3, 0xc7d4,
-0xef6e, 0x4b78, 0xf32f, 0xf8e5, 0x43cb, 0xe7da, 0xaf46, 0x115a, 0xfeb2, 0xbf7a,
-0x2e9a, 0x2ed7, 0xde2f, 0x2807, 0x259c, 0xb09f, 0xd3d4, 0x2606, 0xd544, 0xeb3d,
-0x5107, 0xfecf, 0xf63f, 0x4304, 0xedfe, 0xae0d, 0x0d7f, 0x0957, 0xc47d, 0x2f62,
-0x3b51, 0xdfea, 0x2a01, 0x3390, 0xb825, 0xd3e9, 0x29f1, 0xd82e, 0xe2e3, 0x509a,
-0x061c, 0xf530, 0x48b1, 0xf740, 0xabeb, 0x0d93, 0x0ed4, 0xbed0, 0x274e, 0x3e3b,
-0xddc2, 0x2168, 0x35a1, 0xbbb0, 0xcedb, 0x2b94, 0xdd5b, 0xdd2d, 0x4e6a, 0x068d,
-0xe741, 0x3eef, 0xfe34, 0xad12, 0x0bb7, 0x1a73, 0xbea5, 0x1c31, 0x4269, 0xdc1a,
-0x1611, 0x37d6, 0xc048, 0xcaa3, 0x2f7e, 0xe59c, 0xd94c, 0x4ed8, 0x0af6, 0xe225,
-0x3c84, 0xfd49, 0xa4b2, 0x048d, 0x1ed5, 0xc496, 0x1caa, 0x4641, 0xddd4, 0x1578,
-0x37dc, 0xc13b, 0xcab7, 0x30dc, 0xfec0, 0xd462, 0x1387, 0x07dd, 0x14c1, 0x4b92,
-0x0d74, 0xda49, 0x12de, 0x02fe, 0xb8fe, 0xeaae, 0x0363, 0xdab0, 0x23b0, 0x68fb,
-0x3681, 0x1351, 0x29fc, 0xf22e, 0xb781, 0xd225, 0xc11d, 0xd7d8, 0x354d, 0x26b8,
-0x09af, 0x60fa, 0x5f8c, 0xe302, 0xde80, 0xff6a, 0xbb95, 0xafec, 0x029f, 0x161d,
-0x0fee, 0x3924, 0x2b6c, 0x1ed5, 0x24fe, 0xec7b, 0xc1fe, 0xe22b, 0xfbcd, 0xdc4d,
-0xf3f7, 0x210f, 0x1d01, 0x1305, 0x1342, 0x1f6c, 0x0852, 0xfea5, 0xdd42, 0xc083,
-0xf243, 0xde95, 0xd818, 0x23f7, 0x3eab, 0x0891, 0x1381, 0x52fd, 0xff10, 0xc983,
-0xe091, 0xc3b8, 0xcafc, 0xe7d7, 0xfc8d, 0x2043, 0x559d, 0x2c2e, 0x0418, 0x4485,
-0x0b4c, 0xb4e5, 0xc68e, 0xddbf, 0xd0b6, 0xdc81, 0x1e4b, 0x2d10, 0x365b, 0x2c50,
-0x170a, 0x303e, 0x0a60, 0xcc89, 0xb88a, 0xdbc7, 0xe3e7, 0xcdd2, 0x0b38, 0x3c7e,
-0x392b, 0x254c, 0x3272, 0x2fc9, 0xf0ee, 0xd4d8, 0xb5b4, 0xc03b, 0xdef0, 0xd8e9,
-0x0edc, 0x533e, 0x46e4, 0x0fc4, 0x358a, 0x34b8, 0xd1c3, 0xbf29, 0xbb64, 0xbeea,
-0xdb1c, 0xf31b, 0x17f1, 0x44fa, 0x4bfb, 0x0a36, 0x1fe2, 0x2ce9, 0xcf0d, 0xb605,
-0xc6c6, 0xcc96, 0xcf30, 0xf9cd, 0x25fb, 0x36d1, 0x4086, 0x1499, 0x21d8, 0x287f,
-0xde77, 0xb0fd, 0xba6d, 0xe0f5, 0xd3e4, 0xee77, 0x3561, 0x4077, 0x2baa, 0x1d38,
-0x3753, 0x1587, 0xd2e2, 0xb252, 0xb44b, 0xe5a7, 0xdbb5, 0xe778, 0x3790, 0x55cb,
-0x234e, 0x10ab, 0x42e9, 0x083e, 0xc15a, 0xc2a9, 0xbe30, 0xd7d1, 0xe76a, 0xfa22,
-0x2b37, 0x53cb, 0x29a6, 0x0950, 0x4086, 0x0f68, 0xbba0, 0xb824, 0xcc9c, 0xd743,
-0xd665, 0x06ae, 0x3597, 0x44f1, 0x2854, 0x19d4, 0x3395, 0xfe8f, 0xc1b9, 0xad2d,
-0xc39d, 0xde05, 0xd850, 0x0bf2, 0x4266, 0x457f, 0x1d4b, 0x2284, 0x337f, 0xe442,
-0xbc43, 0xb8ba, 0xc33a, 0xe0e4, 0xe8f8, 0x10b5, 0x4262, 0x4afc, 0x1744, 0x1d2b,
-0x3125, 0xe2b5, 0xbcb6, 0xbdea, 0xccfd, 0xdfe5, 0xefed, 0x1bae, 0x3f5e, 0x451d,
-0x167c, 0x1ea7, 0x2848, 0xdf70, 0xbb35, 0xbbfc, 0xd959, 0xe266, 0xec2b, 0x20e3,
-0x435c, 0x3878, 0x0fee, 0x25e8, 0x1ba1, 0xdaf0, 0xc061, 0xb76f, 0xdd9c, 0xe727,
-0xece4, 0x247e, 0x48ee, 0x303d, 0x099a, 0x320b, 0x19b9, 0xd0b8, 0xc508, 0xbe20,
-0xd52c, 0xe430, 0xf5f1, 0x21d1, 0x4aae, 0x3670, 0x0bc4, 0x349a, 0x16c6, 0xc9e1,
-0xbb8f, 0xc44e, 0xdbed, 0xde26, 0x03b2, 0x34c9, 0x4689, 0x30a8, 0x17ea, 0x33bd,
-0x0b87, 0xcd79, 0xb9b9, 0xc3c1, 0xe227, 0xdffc, 0x07ae, 0x3deb, 0x4732, 0x25e8,
-0x1ef9, 0x370f, 0xfb29, 0xcc78, 0xbf32, 0xc5c0, 0xe807, 0xe571, 0x074b, 0x4121,
-0x4902, 0x1968, 0x206c, 0x3da5, 0xf467, 0xc9c7, 0xc240, 0xc6d8, 0xe2b1, 0xeca9,
-0x0f7d, 0x3a80, 0x4ac1, 0x1bda, 0x1cdc, 0x3836, 0xee35, 0xc32e, 0xc0a2, 0xce3e,
-0xdfd7, 0xe9c8, 0x162c, 0x3eb5, 0x48b0, 0x1a61, 0x1e8f, 0x2cf5, 0xe5c6, 0xbb80,
-0xb378, 0xd228, 0xe3dd, 0xeba5, 0x2266, 0x46f5, 0x3e1f, 0x13fa, 0x26ea, 0x21ec,
-0xd925, 0xbdc7, 0xb66d, 0xd76b, 0xe81e, 0xf025, 0x269d, 0x4d69, 0x3d40, 0x1027,
-0x2c58, 0x1cc9, 0xd265, 0xbfd4, 0xbabe, 0xd919, 0xe822, 0xf931, 0x2bc9, 0x4c69,
-0x3d20, 0x158d, 0x31ca, 0x1821, 0xce8a, 0xb8af, 0xba0f, 0xdfb6, 0xe677, 0xfd3b,
-0x385e, 0x53d9, 0x3764, 0x14a8, 0x30af, 0x0a51, 0xcb95, 0xbad7, 0xbc48, 0xe366,
-0xea7e, 0x06cf, 0x3f08, 0x53c7, 0x2fe0, 0x189d, 0x383f, 0x00fd, 0xc5f3, 0xbf0d,
-0xc38f, 0xe4a3, 0xecee, 0x0ef5, 0x432c, 0x54a7, 0x2a15, 0x190d, 0x3675, 0xf7bc,
-0xc3e0, 0xbc22, 0xc381, 0xe210, 0xec59, 0x15ed, 0x4300, 0x4fd8, 0x269c, 0x1bda,
-0x324a, 0xed57, 0xbb9c, 0xb705, 0xceb8, 0xeb30, 0xed72, 0x1baa, 0x48ad, 0x4bd3,
-0x1fde, 0x1ea9, 0x2826, 0xe505, 0xc2b3, 0xb577, 0xceec, 0xeeb9, 0xef73, 0x1fd5,
-0x4c99, 0x41f7, 0x12c7, 0x24ad, 0x22eb, 0xd504, 0xbfe3, 0xba2a, 0xd063, 0xea6f,
-0xf037, 0x1c9c, 0x4acf, 0x430c, 0x0b68, 0x200d, 0x1c9e, 0xcce4, 0xb9ad, 0xbc29,
-0xd211, 0xe475, 0xfc21, 0x2910, 0x443b, 0x3a83, 0x0ef1, 0x2295, 0x15ac, 0xd00d,
-0xb774, 0xbaff, 0xded3, 0xe41e, 0xf945, 0x331e, 0x49b7, 0x3276, 0x128d, 0x28c7,
-0x08f2, 0xce8e, 0xbb2e, 0xb907, 0xe4c0, 0xe9f8, 0xf98a, 0x3323, 0x4a75, 0x2718,
-0x0ddc, 0x3369, 0x0795, 0xc936, 0xc192, 0xc3cc, 0xe2b9, 0xe583, 0xfce9, 0x312f,
-0x4951, 0x266f, 0x0ffe, 0x3698, 0x0679, 0xca63, 0xc301, 0xc844, 0xde4c, 0xe26e,
-0x076e, 0x3283, 0x4507, 0x259a, 0x11af, 0x30ff, 0xfd1c, 0xc1b2, 0xb384, 0xc924,
-0xe414, 0xde8f, 0x0781, 0x295f, 0x51b4, 0x5b09, 0x17c9, 0xf17b, 0xd9cd, 0xb11a,
-0x8396, 0xbd98, 0x073f, 0x0598, 0x5258, 0x7bf8, 0x3dd3, 0x096d, 0xe7f8, 0xa966,
-0x9271, 0xc3c7, 0xb173, 0xf5d9, 0x6db2, 0x3b89, 0x2231, 0x4aaf, 0x1c3b, 0xc115,
-0xcb06, 0xd460, 0xbb98, 0x03f6, 0xf9d7, 0xecaf, 0x4aa5, 0x27cf, 0xcf8c, 0x0764,
-0x3489, 0xd9cb, 0xf31b, 0x39b5, 0xebc3, 0xeb7f, 0x1192, 0xceee, 0xbd72, 0x16f9,
-0x1b5a, 0xf888, 0x4a44, 0x34a8, 0xedd8, 0x18bb, 0xf8d6, 0xa74c, 0xd19c, 0x139c,
-0xeaf7, 0x0d0b, 0x5317, 0x0e81, 0x0c44, 0x35bd, 0xe010, 0xb51d, 0x075b, 0xfc77,
-0xc9ae, 0x2b95, 0x35a1, 0xf0e8, 0x2c61, 0x2481, 0xc370, 0xe826, 0x20b5, 0xd95a,
-0xf832, 0x43e0, 0xf261, 0xf7ef, 0x414e, 0xf14b, 0xbf9e, 0x1c6c, 0x1380, 0xd3d1,
-0x2650, 0x1f52, 0xd592, 0x1ddb, 0x2414, 0xc347, 0xebd1, 0x3e70, 0xf240, 0xeb89,
-0x3d66, 0xf738, 0xe57b, 0x2fe8, 0xf22d, 0xbd68, 0x1e7b, 0x2466, 0xd858, 0x2613,
-0x3122, 0xdc86, 0x16b9, 0x277b, 0xc324, 0xdb13, 0x2c78, 0xe8ab, 0xed0b, 0x49bb,
-0x0342, 0xf02a, 0x3b6c, 0xf7d9, 0xb9c6, 0x0fd8, 0x1192, 0xc763, 0x12e5, 0x2738,
-0xe26c, 0x1a89, 0x2a72, 0xcd72, 0xdca7, 0x27a9, 0xe962, 0xd98a, 0x271e, 0xf948,
-0xe783, 0x29f0, 0x000e, 0xc137, 0x064c, 0x17e6, 0xcd48, 0x0efb, 0x329b, 0xdc50,
-0xf9d6, 0x28fd, 0xd866, 0xc34b, 0x13df, 0xefa3, 0xdcbf, 0x3578, 0x09a7, 0xe33f,
-0x2c3f, 0x02a6, 0xaa76, 0xf3eb, 0x1870, 0xc21d, 0x029e, 0x3d07, 0xedbb, 0x0a92,
-0x33dc, 0xd94f, 0xc985, 0x15a5, 0xdf1c, 0xd3f5, 0x3f5e, 0x0fca, 0xe50f, 0x3b04,
-0x1a3d, 0xb99b, 0xf6d1, 0x1c75, 0xcc21, 0x0987, 0x3e95, 0xed51, 0x0dcf, 0x3b32,
-0xd980, 0xc6f7, 0x280e, 0xf587, 0xd3c2, 0x4871, 0x233c, 0xe02f, 0x3039, 0x183d,
-0xaecf, 0xf137, 0x2776, 0xcc66, 0x0bf0, 0x5162, 0xeddf, 0x088c, 0x4536, 0xd457,
-0xb205, 0x2315, 0xf51a, 0xc60d, 0x4281, 0x2682, 0xe5d9, 0x3aad, 0x1cab, 0xb02d,
-0xf294, 0x20af, 0xbecb, 0x0084, 0x4c16, 0xeaf2, 0x054e, 0x449f, 0xdf02, 0xbd48,
-0x25bf, 0xfda9, 0xcb15, 0x3a93, 0x1e9b, 0xddd4, 0x3408, 0x1f70, 0xb333, 0xf3df,
-0x32ab, 0xd133, 0x014e, 0x52b2, 0xf138, 0xfe00, 0x4260, 0xe1f2, 0xbbac, 0x28bf,
-0x0404, 0xcc81, 0x4649, 0x2e56, 0xdee8, 0x3677, 0x23ef, 0xabc0, 0xea62, 0x3159,
-0xcf59, 0xfdcf, 0x575a, 0xf403, 0xfe40, 0x4759, 0xe094, 0xb225, 0x1ffa, 0xfefc,
-0xc26f, 0x3a61, 0x2be1, 0xdb44, 0x2efe, 0x2504, 0xadcb, 0xe074, 0x2713, 0xc6d3,
-0xecc2, 0x48d6, 0xea4d, 0xf2ec, 0x43a0, 0xe1fc, 0xaa5f, 0x1825, 0xffd7, 0xba38,
-0x2bdb, 0x24a3, 0xce10, 0x1cd8, 0x1cfc, 0xab2e, 0xdc4d, 0x276d, 0xca22, 0xeb01,
-0x4a08, 0xeb0e, 0xe94c, 0x3cd7, 0xe45f, 0xa6c6, 0x0f8c, 0x066f, 0xc2d2, 0x2a01,
-0x2aea, 0xd9bf, 0x251a, 0x2933, 0xb64d, 0xd9b5, 0x26a1, 0xd2ba, 0xe822, 0x4af1,
-0xfec7, 0xf323, 0x3fdf, 0xf78e, 0xb4c1, 0x0f7f, 0x0e1c, 0xc7ce, 0x25fb, 0x3129,
-0xdeb5, 0x2268, 0x3385, 0xc266, 0xd9b6, 0x2efc, 0xddb0, 0xe00f, 0x45ac, 0x0168,
-0xea8d, 0x3cd9, 0xfeda, 0xb603, 0x13c5, 0x166b, 0xc192, 0x1f5a, 0x3804, 0xda94,
-0x15a3, 0x35b3, 0xc729, 0xd3ae, 0x2e68, 0xe359, 0xde70, 0x4764, 0x0725, 0xe6b1,
-0x3882, 0xfed4, 0xad23, 0x0819, 0x16c2, 0xc15b, 0x1c91, 0x4358, 0xe49c, 0x1162,
-0x35d1, 0xc8f8, 0xc74f, 0x2676, 0xe0e9, 0xd0d7, 0x4b09, 0x1cea, 0xedea, 0x3f3b,
-0x11f4, 0xb09a, 0xfc73, 0x177b, 0xba40, 0x109f, 0x4fcb, 0xf285, 0x1d0f, 0x3dc2,
-0xc588, 0xc98d, 0x329a, 0xfd8a, 0xcc33, 0x1573, 0x1810, 0x1532, 0x434e, 0x102d,
-0xd555, 0x08d4, 0x0011, 0xb77c, 0xec37, 0x098c, 0xd4fc, 0x2033, 0x7926, 0x32be,
-0xfe95, 0x28ab, 0xef9c, 0xa428, 0xcffc, 0xcbdf, 0xd07c, 0x3681, 0x2f87, 0x0680,
-0x626e, 0x5e9c, 0xd624, 0xd9e4, 0x080a, 0xadfe, 0xa2f5, 0x12af, 0x142c, 0xffde,
-0x3703, 0x3570, 0x269e, 0x24fb, 0xe8a1, 0xb7ec, 0xe753, 0xf82a, 0xce4d, 0x001a,
-0x2e98, 0x1f84, 0x0eb8, 0x1beb, 0x2603, 0xfcff, 0xfd98, 0xd8c0, 0xc719, 0xfc52,
-0xddd2, 0xe3ec, 0x2ee0, 0x4393, 0x042b, 0x1929, 0x569a, 0xef83, 0xc35d, 0xd9e5,
-0xc6ce, 0xd1e0, 0xed86, 0x0b2a, 0x23b2, 0x504c, 0x20ad, 0x029d, 0x3b72, 0xf5a5,
-0xad6b, 0xbe54, 0xddfc, 0xd162, 0xddcd, 0x2952, 0x324b, 0x3156, 0x1d3f, 0x12f5,
-0x235b, 0xf27f, 0xc001, 0xb250, 0xdfdd, 0xe3f3, 0xd455, 0x14e4, 0x3c06, 0x3326,
-0x1a60, 0x30e7, 0x24a0, 0xe2c3, 0xcd08, 0xb21c, 0xc75c, 0xdc66, 0xe088, 0x1e09,
-0x54ef, 0x4197, 0x0dca, 0x356f, 0x22ce, 0xcaf2, 0xc0ce, 0xbc3d, 0xcfda, 0xe59b,
-0xfe5c, 0x27b1, 0x4caa, 0x45a1, 0x0add, 0x274f, 0x1c6c, 0xcde6, 0xc343, 0xd011,
-0xdf48, 0xe021, 0x0b0c, 0x335a, 0x3c8e, 0x345d, 0x0d86, 0x278e, 0x1b8f, 0xdc12,
-0xbc28, 0xc6ff, 0xead3, 0xdba0, 0xfdee, 0x39b8, 0x3f03, 0x2143, 0x1858, 0x376b,
-0x021b, 0xcaa8, 0xbb59, 0xc6f6, 0xef67, 0xe041, 0xf9ba, 0x3cd7, 0x4cfd, 0x168d,
-0x1037, 0x3fec, 0xf71d, 0xbed3, 0xc8d6, 0xcbc6, 0xdd8f, 0xea8c, 0x09b1, 0x2e92,
-0x4701, 0x1829, 0x091c, 0x3ad7, 0xfd4b, 0xb999, 0xbe68, 0xdc50, 0xdc39, 0xd663,
-0x1009, 0x330e, 0x37f3, 0x1ad3, 0x1cca, 0x3476, 0xf66a, 0xc5e8, 0xbb6f, 0xd5e8,
-0xe008, 0xd5ea, 0x10b5, 0x3f63, 0x3725, 0x1102, 0x2911, 0x3855, 0xe9cb, 0xc610,
-0xc44b, 0xd547, 0xdd89, 0xe4aa, 0x195d, 0x4084, 0x3d9b, 0x10ab, 0x2a1f, 0x3667,
-0xe38c, 0xc1a0, 0xc4c5, 0xdd94, 0xe21b, 0xe99c, 0x1f49, 0x4312, 0x3b69, 0x0f14,
-0x2b3d, 0x2eaa, 0xdeab, 0xc00a, 0xc634, 0xe225, 0xe0e3, 0xf311, 0x2b9a, 0x44fd,
-0x3881, 0x11ee, 0x2f2a, 0x2428, 0xdc87, 0xc347, 0xc2d0, 0xe6e0, 0xe5b0, 0xf196,
-0x2d4e, 0x4a97, 0x3366, 0x1388, 0x3ae0, 0x1bf8, 0xd058, 0xc212, 0xc09b, 0xdbf3,
-0xe25c, 0xfa1f, 0x3093, 0x4e94, 0x31f0, 0x12fe, 0x3bde, 0x11ad, 0xc841, 0xb8bd,
-0xbe0b, 0xdd25, 0xdd7e, 0x0138, 0x3ac9, 0x4ccb, 0x2ba2, 0x1359, 0x3033, 0xfbc6,
-0xc14d, 0xb543, 0xbd7e, 0xdcf8, 0xde2b, 0x0754, 0x388b, 0x409a, 0x1e0d, 0x134a,
-0x2ba8, 0xeee4, 0xbe5b, 0xafaf, 0xbb90, 0xe059, 0xde74, 0x0736, 0x3d1c, 0x4310,
-0x16f1, 0x1686, 0x2f2a, 0xe9de, 0xbe17, 0xb446, 0xc0ca, 0xdd27, 0xe1a0, 0x0ccd,
-0x3c13, 0x4661, 0x1949, 0x196a, 0x2a50, 0xdf8d, 0xb6a7, 0xb25a, 0xc8aa, 0xdf0e,
-0xe6dc, 0x19c8, 0x411d, 0x423f, 0x15db, 0x1a0d, 0x2316, 0xdf69, 0xba97, 0xb2a9,
-0xd092, 0xe29a, 0xebf2, 0x2556, 0x4a3b, 0x3fb1, 0x16cb, 0x2603, 0x1c1b, 0xd67d,
-0xbcf3, 0xb765, 0xdad1, 0xea4b, 0xf176, 0x27e4, 0x4d31, 0x3b4c, 0x0fab, 0x2ad5,
-0x1a4d, 0xd10b, 0xbc49, 0xba78, 0xda1f, 0xe903, 0xffda, 0x308c, 0x4a2f, 0x38ce,
-0x11cc, 0x299c, 0x105c, 0xcdc3, 0xba31, 0xc03e, 0xe616, 0xe849, 0xfec7, 0x37e1,
-0x4e98, 0x3198, 0x12d8, 0x2aeb, 0x03e5, 0xcb29, 0xbccb, 0xc232, 0xe734, 0xeb9c,
-0x07ed, 0x3d12, 0x4b48, 0x2515, 0x14e8, 0x330c, 0xfd19, 0xc86d, 0xc241, 0xca17,
-0xe64b, 0xe918, 0x09ed, 0x3ba3, 0x4eee, 0x25e2, 0x167a, 0x38a6, 0xffcf, 0xcb0e,
-0xc615, 0xd055, 0xe3d3, 0xeafc, 0x1602, 0x3e86, 0x49c2, 0x257e, 0x2166, 0x3bcd,
-0xfc55, 0xc4ad, 0xbb87, 0xd6e3, 0xe7a1, 0xe64f, 0x1ddd, 0x4682, 0x4516, 0x1dee,
-0x1dc5, 0x2b0d, 0xed86, 0xc590, 0xb97d, 0xd84f, 0xec06, 0xe368, 0x1c7f, 0x4cee,
-0x3f07, 0x13c3, 0x289d, 0x28fb, 0xdcf0, 0xc5b7, 0xbdb7, 0xd4a7, 0xec46, 0xecd0,
-0x1bda, 0x48cc, 0x4019, 0x0cd7, 0x23a7, 0x2698, 0xd5be, 0xbc3e, 0xb90e, 0xcc6c,
-0xddf3, 0xf12b, 0x24f1, 0x4448, 0x3b5c, 0x118e, 0x2441, 0x1c2b, 0xd270, 0xb368,
-0xb6c7, 0xdd46, 0xdf51, 0xefbb, 0x3138, 0x49d2, 0x3667, 0x1864, 0x2b86, 0x1073,
-0xd35e, 0xbbf4, 0xb47a, 0xdfb4, 0xe8bb, 0xf6b2, 0x353a, 0x4fd4, 0x2e9f, 0x12a8,
-0x323d, 0x07c8, 0xcb04, 0xc1fa, 0xbd57, 0xdf17, 0xe6e8, 0xfa82, 0x3052, 0x4c63,
-0x2d83, 0x12bf, 0x3366, 0x0318, 0xc6dd, 0xbd85, 0xbc4f, 0xd9e1, 0xe604, 0x0814,
-0x34df, 0x4a09, 0x2d9d, 0x148f, 0x2e79, 0xfba1, 0xc12c, 0xb277, 0xbf95, 0xdeb7,
-0xe211, 0x10bc, 0x423c, 0x4956, 0x24f7, 0x1571, 0x2434, 0xebbb, 0xc333, 0xb587,
-0xc733, 0xedc0, 0xebba, 0x0854, 0x3f2e, 0x6f7e, 0x4a81, 0x0e5e, 0x03fe, 0xcb43,
-0xa313, 0xa8c3, 0xd5fe, 0x0fe0, 0x3ce3, 0x6922, 0x5cb3, 0x4541, 0x10b8, 0xc5c1,
-0xb7c8, 0xca44, 0xca38, 0xd7f7, 0x38e7, 0x4e53, 0x1cb5, 0x3dfb, 0x3d19, 0x06ab,
-0xeda0, 0xe9ef, 0xd83d, 0xf9bf, 0x0ebe, 0xca2a, 0x0a79, 0x510e, 0xf01d, 0xe7eb,
-0x3be6, 0x1a2e, 0xf989, 0x353e, 0x099c, 0xe538, 0x16d7, 0xd697, 0xa93c, 0x0407,
-0x1bee, 0xf75f, 0x46c6, 0x50e3, 0xf430, 0x1813, 0x169b, 0xaf5d, 0xc57c, 0x0fb5,
-0xe638, 0xf7e9, 0x459c, 0x122e, 0x0654, 0x352e, 0xfc93, 0xc262, 0xf99c, 0x072c,
-0xc8f1, 0x0bf2, 0x32cd, 0xf85b, 0x1790, 0x25c1, 0xde96, 0xd882, 0x18ea, 0xe834,
-0xd77c, 0x3995, 0x1231, 0xeab1, 0x28e3, 0x0cfc, 0xc5ef, 0xf7bd, 0x18f1, 0xd03e,
-0x057e, 0x320a, 0xe5e4, 0x07c7, 0x2d5d, 0xd88a, 0xc884, 0x2072, 0xfd6c, 0xd3d0,
-0x2a59, 0x1066, 0xe564, 0x22a2, 0x047a, 0xb2ee, 0xeaad, 0x1c28, 0xcc6c, 0xf7e5,
-0x3c36, 0xee88, 0xfbfb, 0x3085, 0xddf6, 0xb28a, 0x0aaf, 0xf456, 0xbc45, 0x223a,
-0x21ed, 0xe31c, 0x2214, 0x1882, 0xb51a, 0xdbdc, 0x18ba, 0xc1ce, 0xe1c3, 0x397c,
-0xed39, 0xf426, 0x3690, 0xe68c, 0xb498, 0x0e83, 0x00c5, 0xc494, 0x1ef7, 0x1b31,
-0xdc33, 0x1f84, 0x1b7f, 0xb9c1, 0xdc07, 0x2246, 0xd5fb, 0xeaf7, 0x4a41, 0x042a,
-0xed8c, 0x29a9, 0xf4c4, 0xbbf5, 0xffbd, 0x02b3, 0xd089, 0x2a98, 0x349a, 0xe5f4,
-0x231d, 0x3682, 0xc042, 0xc757, 0x28ee, 0xe56b, 0xda47, 0x3eac, 0x0d7c, 0xfc17,
-0x4512, 0x05d1, 0xbb63, 0x0fc8, 0x0da5, 0xb98f, 0x1ecc, 0x3aea, 0xdbbd, 0x1bd6,
-0x4041, 0xd007, 0xd35e, 0x2aaf, 0xea38, 0xe711, 0x3e4a, 0xfa47, 0xef65, 0x3f02,
-0xf730, 0xae98, 0x0fae, 0x1e19, 0xc953, 0x1ea3, 0x3db2, 0xe20d, 0x1043, 0x2d87,
-0xc8ab, 0xca8a, 0x2270, 0xe769, 0xe021, 0x4751, 0x0a42, 0xed5b, 0x468e, 0x0a0e,
-0xa823, 0xfc1e, 0x19ce, 0xc19e, 0x0fd8, 0x3c33, 0xe854, 0x1d91, 0x3f3f, 0xd03c,
-0xd290, 0x2d60, 0xe292, 0xd443, 0x4229, 0x0590, 0xe446, 0x3c78, 0x0d2e, 0xbba0,
-0x0b10, 0x1fdc, 0xccc6, 0x142f, 0x3174, 0xdc18, 0x1061, 0x371b, 0xd368, 0xd200,
-0x2d59, 0xf1a5, 0xdc23, 0x3edd, 0x0fb6, 0xe812, 0x2f6f, 0x0a77, 0xb941, 0xfe00,
-0x1d36, 0xcc9c, 0x11f2, 0x404a, 0xe70a, 0x0abc, 0x3965, 0xd3be, 0xbed2, 0x1fe7,
-0xee09, 0xd03e, 0x3f07, 0x1799, 0xe33b, 0x342f, 0x1443, 0xb44b, 0xf906, 0x1979,
-0xbeaf, 0x0a9f, 0x45b3, 0xe73c, 0x0a6f, 0x3e78, 0xd655, 0xc03d, 0x2087, 0xeb0b,
-0xcf7a, 0x4395, 0x1915, 0xe1a6, 0x34d0, 0x134e, 0xac96, 0xeeeb, 0x1aa0, 0xc459,
-0x0965, 0x4852, 0xe8bd, 0x0151, 0x3569, 0xd16f, 0xb855, 0x1c6f, 0xed54, 0xcabb,
-0x428e, 0x1dfb, 0xdf3c, 0x323b, 0x15f0, 0xab84, 0xe597, 0x18a2, 0xc34f, 0x0120,
-0x48dd, 0xedf1, 0x07d1, 0x3f6b, 0xd521, 0xb0ac, 0x1903, 0xf0c7, 0xc122, 0x3959,
-0x22ad, 0xe010, 0x2ec7, 0x1837, 0xaaf6, 0xe170, 0x1e2b, 0xc7b9, 0xfdb5, 0x4c53,
-0xebef, 0xfb34, 0x3ee4, 0xdef9, 0xb297, 0x1b34, 0xfd76, 0xc42a, 0x391e, 0x2b29,
-0xde3f, 0x2dc8, 0x2491, 0xb2a5, 0xe544, 0x2b06, 0xcad8, 0xf507, 0x54ba, 0xf673,
-0xfa92, 0x48ca, 0xe9a8, 0xafd3, 0x1ef7, 0x084a, 0xc383, 0x3a6e, 0x3354, 0xdbff,
-0x2c3f, 0x2b2a, 0xb115, 0xe1c4, 0x348d, 0xd2d5, 0xf3b1, 0x5801, 0xf84b, 0xf5dc,
-0x4897, 0xeba9, 0xac5a, 0x1d11, 0x0bb4, 0xbcd7, 0x32ed, 0x3809, 0xdc0a, 0x2aa8,
-0x3035, 0xb63c, 0xddf9, 0x3359, 0xe1e6, 0xdc8c, 0x1666, 0xf007, 0x2428, 0x5dbe,
-0x00c2, 0xd781, 0x22f0, 0xf405, 0xa1af, 0xed74, 0xf64b, 0xd808, 0x304e, 0x5c2f,
-0x2e87, 0x2aaf, 0x32b5, 0xdc5e, 0xbf90, 0xd852, 0xad5b, 0xdde3, 0x38e2, 0x1923,
-0x04d1, 0x62c4, 0x5bb8, 0xe529, 0xeaaf, 0xfd61, 0xc422, 0xc0df, 0xfa6b, 0x0d7b,
-0x16ff, 0x3f3e, 0x1d78, 0x1a46, 0x3b1d, 0xf55f, 0xc829, 0xeeb5, 0x0157, 0xdd55,
-0xf41a, 0x20b5, 0x1533, 0x2329, 0x1f7c, 0x1523, 0x1e43, 0x1419, 0xdc00, 0xbfc2,
-0xfbcf, 0xe187, 0xd1ef, 0x2a18, 0x3c8b, 0x1862, 0x2179, 0x4380, 0x06a1, 0xdc67,
-0xe0e4, 0xb854, 0xda4e, 0xf2b5, 0xe744, 0x1f54, 0x57ea, 0x2932, 0xfa55, 0x3961,
-0x0fd9, 0xbac6, 0xcdda, 0xd258, 0xcf89, 0xe3ab, 0x0707, 0x1a3e, 0x3967, 0x30cc,
-0x0264, 0x2d4f, 0x1e6c, 0xcc01, 0xb70b, 0xd1c4, 0xdac0, 0xca7b, 0xfba8, 0x26c2,
-0x371b, 0x359b, 0x23c6, 0x2fb4, 0x0da1, 0xd9bd, 0xae9d, 0xb89c, 0xdb61, 0xcb90,
-0x0132, 0x482d, 0x42cd, 0x1e49, 0x2e1f, 0x3691, 0xe7fa, 0xc93c, 0xba66, 0xbb0a,
-0xe251, 0xe472, 0x0383, 0x3f08, 0x4cc8, 0x1215, 0x1c80, 0x3b71, 0xe4f3, 0xc431,
-0xcbb0, 0xc403, 0xd2f9, 0xf12b, 0x1313, 0x2f50, 0x4774, 0x1313, 0x18c4, 0x4058,
-0xed5d, 0xb643, 0xc25a, 0xd92a, 0xcdc3, 0xe267, 0x25f0, 0x37bf, 0x38e3, 0x1db0,
-0x2909, 0x2dab, 0xe635, 0xb3fb, 0xb52f, 0xe71a, 0xdad1, 0xdbe5, 0x2dd4, 0x4a45,
-0x2f11, 0x15fc, 0x375b, 0x1edc, 0xd95e, 0xc7dd, 0xb91d, 0xdb9a, 0xe8d2, 0xea7d,
-0x243c, 0x50aa, 0x347a, 0x0b10, 0x3f2c, 0x24ae, 0xc984, 0xc48d, 0xccec, 0xd726,
-0xda77, 0xf845, 0x2782, 0x491b, 0x3bb7, 0x1233, 0x3698, 0x200c, 0xcd29, 0xb25f,
-0xc2ef, 0xdd85, 0xd457, 0xfe96, 0x3830, 0x43f0, 0x2e94, 0x1a60, 0x3369, 0x07e9,
-0xcb4f, 0xb645, 0xba73, 0xdbb8, 0xdb8f, 0xffae, 0x3a33, 0x48d7, 0x2211, 0x15da,
-0x362f, 0xfbd5, 0xc39a, 0xb7fb, 0xc2cf, 0xe1cd, 0xe2d2, 0x0604, 0x36c9, 0x495d,
-0x209d, 0x15d2, 0x37e6, 0xf91a, 0xc431, 0xbe00, 0xccf7, 0xe3be, 0xe90a, 0x14f8,
-0x3bed, 0x4775, 0x22c5, 0x1a55, 0x2eb8, 0xf7ab, 0xcbee, 0xbb0a, 0xd4b7, 0xea3e,
-0xe43a, 0x18fd, 0x455e, 0x429e, 0x1d75, 0x27b4, 0x2e04, 0xeadd, 0xca0c, 0xb834,
-0xcf7e, 0xebe8, 0xec12, 0x1d2b, 0x4ce6, 0x4388, 0x1410, 0x2882, 0x2863, 0xdbfa,
-0xc201, 0xbc64, 0xd1a8, 0xe40d, 0xf23c, 0x21f6, 0x44ac, 0x3ed5, 0x105b, 0x1f33,
-0x1ab9, 0xd393, 0xb879, 0xb8a2, 0xd559, 0xdf87, 0xf31b, 0x2555, 0x3b7c, 0x3066,
-0x0f9b, 0x206c, 0x1043, 0xd352, 0xb6fe, 0xb4ae, 0xdacb, 0xdd79, 0xed28, 0x2944,
-0x40cc, 0x26e3, 0x1073, 0x2c6d, 0x0a8e, 0xd1fe, 0xbe7c, 0xb79c, 0xdbb0, 0xe28f,
-0xf1b8, 0x2782, 0x45d6, 0x288a, 0x146e, 0x3752, 0x08d7, 0xccea, 0xc003, 0xbd89,
-0xda98, 0xe4f4, 0x0193, 0x3341, 0x4c65, 0x29eb, 0x1665, 0x385c, 0x0502, 0xcaf3,
-0xbfdd, 0xc859, 0xe1b4, 0xe85f, 0x0f40, 0x394b, 0x49b1, 0x2907, 0x1adb, 0x324c,
-0xf922, 0xc6e9, 0xb961, 0xcbdd, 0xe7b2, 0xe6bd, 0x11f6, 0x3fef, 0x46fb, 0x1df6,
-0x1d0f, 0x2f40, 0xeef5, 0xc4a6, 0xb575, 0xcb9f, 0xe637, 0xea22, 0x1afc, 0x450f,
-0x486c, 0x1ca2, 0x2081, 0x27c1, 0xe170, 0xbe81, 0xb610, 0xd4bd, 0xe951, 0xed82,
-0x22d8, 0x4920, 0x44fd, 0x1967, 0x24be, 0x230d, 0xdd5b, 0xbd48, 0xb2b2, 0xd74f,
-0xebd6, 0xf51e, 0x2d0e, 0x4f15, 0x406d, 0x18ea, 0x2d32, 0x1b37, 0xd68b, 0xc044,
-0xb935, 0xdd2b, 0xe8ca, 0xf474, 0x309b, 0x54b6, 0x3c42, 0x14ba, 0x347b, 0x1910,
-0xd0a8, 0xbcba, 0xb8c9, 0xdc46, 0xe9fe, 0xfff4, 0x3532, 0x5389, 0x3988, 0x14af,
-0x3504, 0x102d, 0xc848, 0xb929, 0xbe6f, 0xdd0e, 0xe430, 0x059c, 0x3ba7, 0x4f58,
-0x2e33, 0x10f0, 0x2a2f, 0xfdb9, 0xc2f6, 0xafbb, 0xbb99, 0xe4f6, 0xe5f2, 0x07f0,
-0x3ce6, 0x4606, 0x2206, 0x1803, 0x2b80, 0xee52, 0xc24f, 0xb46d, 0xbb4a, 0xe32e,
-0xe633, 0x0953, 0x4238, 0x4b00, 0x1a28, 0x1723, 0x280d, 0xe191, 0xbf29, 0xb512,
-0xbb95, 0xe083, 0xee77, 0x11e1, 0x3d02, 0x4905, 0x18fb, 0x175c, 0x25d3, 0xdaba,
-0xb4bd, 0xb51c, 0xcc2b, 0xe1c5, 0xed1f, 0x1d15, 0x42ae, 0x42e0, 0x12aa, 0x15c7,
-0x1ce6, 0xdd86, 0xbb2e, 0xb339, 0xd4c6, 0xe6a3, 0xee5c, 0x246d, 0x4599, 0x378a,
-0x117f, 0x247f, 0x1587, 0xd40f, 0xc211, 0xba12, 0xda04, 0xe9d2, 0xf097, 0x2593,
-0x4a0d, 0x33f2, 0x0e58, 0x2f92, 0x1796, 0xd23e, 0xc5d1, 0xbd1d, 0xd6a8, 0xea03,
-0xfd4b, 0x2b76, 0x4d07, 0x372b, 0x12c1, 0x3610, 0x1455, 0xc9fa, 0xc082, 0xc65f,
-0xdbf3, 0xe5fa, 0x0864, 0x3695, 0x4d6d, 0x3441, 0x13be, 0x2f2f, 0x090c, 0xce34,
-0xb830, 0xc505, 0xfada, 0xec81, 0xfb68, 0x2eba, 0x319e, 0x3ce2, 0x44fb, 0x1d01,
-0xdd9d, 0xd66a, 0xb232, 0xa016, 0xf64b, 0xfff6, 0x09d5, 0x7376, 0x8570, 0x20f6,
-0xfe82, 0xf200, 0x9a52, 0xa325, 0xc4f5, 0xcbde, 0x2c79, 0x67bb, 0x4c8f, 0x46a8,
-0x523c, 0xf79d, 0xabd0, 0xda12, 0xcc15, 0xb71c, 0xf62d, 0x1e60, 0x327a, 0x4b18,
-0x2770, 0xf598, 0x157f, 0x094e, 0xbe89, 0xebf7, 0x2a77, 0xf098, 0xe9ee, 0x28e2,
-0xf32a, 0xc056, 0x237c, 0x271d, 0xe4a4, 0x3978, 0x35ba, 0xe536, 0x10f5, 0xfdaa,
-0xa68b, 0xd3ea, 0x212f, 0xea07, 0x08a6, 0x5e96, 0x0ae2, 0x07c6, 0x37b6, 0xd70c,
-0xb092, 0xfe7d, 0xf21a, 0xcad9, 0x34d2, 0x36e9, 0xf083, 0x37da, 0x22a5, 0xbc01,
-0xdc00, 0x1395, 0xd553, 0xe5e3, 0x3bac, 0xfd08, 0xfe92, 0x3f5c, 0xee23, 0xbc45,
-0x0d39, 0x0a9c, 0xc61a, 0x146f, 0x2951, 0xdb39, 0x171e, 0x293d, 0xc2e7, 0xdd20,
-0x32b9, 0xe330, 0xd7b9, 0x3cc5, 0xf7d9, 0xdcad, 0x311b, 0xf1df, 0xb0b8, 0x105b,
-0x1a8c, 0xca51, 0x1be5, 0x2f80, 0xd616, 0x11ca, 0x2652, 0xbc4e, 0xcb96, 0x21a7,
-0xe4b4, 0xe253, 0x4487, 0x0196, 0xe674, 0x3516, 0xfb04, 0xb3bc, 0xfeb8, 0x1079,
-0xc24e, 0x088e, 0x3298, 0xe80b, 0x14c1, 0x2ed3, 0xd1a8, 0xcf82, 0x2207, 0xee50,
-0xcf02, 0x2dec, 0x08af, 0xe42a, 0x344d, 0x0fb2, 0xb971, 0xfa3f, 0x1df7, 0xd32e,
-0x11cc, 0x3722, 0xda30, 0x07ac, 0x3d3f, 0xd7ab, 0xc34d, 0x271b, 0xfe76, 0xdbb3,
-0x3d61, 0x18ed, 0xed9b, 0x3389, 0x0c14, 0xba7c, 0xf987, 0x187e, 0xcd50, 0x1066,
-0x476b, 0xf480, 0x1314, 0x42bb, 0xe5fe, 0xc3be, 0x1389, 0xf39f, 0xd575, 0x3648,
-0x1e47, 0xf2fa, 0x3e74, 0x234a, 0xbf4c, 0xf288, 0x221b, 0xc710, 0xfa3c, 0x5035,
-0xfb9e, 0x0502, 0x44eb, 0xeee6, 0xc43e, 0x1d61, 0xfb1c, 0xc9de, 0x3c74, 0x2aae,
-0xe190, 0x3674, 0x2619, 0xaff2, 0xe8b6, 0x2937, 0xc78c, 0xf5df, 0x540b, 0xfb05,
-0x020b, 0x434b, 0xe0e6, 0xacc1, 0x10fc, 0xf91d, 0xbcee, 0x3592, 0x3566, 0xe36e,
-0x337d, 0x30bf, 0xb32f, 0xd426, 0x2162, 0xc820, 0xe042, 0x4c56, 0xfe46, 0xf61f,
-0x4a89, 0xf803, 0xad4d, 0x11a6, 0x0a6c, 0xb6d1, 0x253a, 0x3311, 0xd5a0, 0x2667,
-0x3498, 0xb800, 0xd872, 0x2f83, 0xd41e, 0xe4e1, 0x5463, 0xf738, 0xea30, 0x492c,
-0xf007, 0xaab2, 0x16ec, 0x11da, 0xc262, 0x2e37, 0x3e3b, 0xdd03, 0x22dd, 0x30e8,
-0xb674, 0xd170, 0x2e2c, 0xdcd6, 0xe399, 0x56b9, 0x04f1, 0xea52, 0x4a44, 0xfd31,
-0xa60d, 0x09bf, 0x162d, 0xbcc9, 0x1f55, 0x4352, 0xde68, 0x1cd9, 0x3c0d, 0xbf98,
-0xc8d8, 0x2a1f, 0xdc64, 0xd503, 0x4d6c, 0x0785, 0xe7a8, 0x476e, 0xff01, 0xa5cd,
-0x064f, 0x17bf, 0xbe55, 0x1800, 0x3b7b, 0xd4d9, 0x10f0, 0x3690, 0xbf8d, 0xc71e,
-0x297a, 0xe393, 0xd729, 0x47fe, 0x0285, 0xda51, 0x391b, 0xfeb3, 0xa48e, 0xfbc3,
-0x19a9, 0xc3a0, 0x108e, 0x3eae, 0xdebc, 0x0f12, 0x36a2, 0xc4c0, 0xbf91, 0x1e2f,
-0xe5de, 0xd395, 0x4354, 0x10d5, 0xe319, 0x39c0, 0x0a87, 0xace4, 0xf7d2, 0x18b7,
-0xc582, 0x0b6f, 0x3da5, 0xe290, 0x0dde, 0x3c3e, 0xcfe6, 0xc55b, 0x253d, 0xeca1,
-0xcf94, 0x3b7a, 0x0f41, 0xdf74, 0x366b, 0x1370, 0xb644, 0xfb14, 0x1f1e, 0xc7c9,
-0x07b4, 0x41e9, 0xe70d, 0x071d, 0x3d77, 0xdb66, 0xc478, 0x265f, 0xf916, 0xd180,
-0x3ee6, 0x1beb, 0xdeb9, 0x31d9, 0x191a, 0xb479, 0xf52c, 0x2801, 0xccf7, 0x03d4,
-0x4bd7, 0xedac, 0x016a, 0x3a65, 0xd6fc, 0xbe27, 0x2266, 0x07f4, 0xd0c6, 0x0dcf,
-0x1281, 0x0eb0, 0x45e8, 0x1d9a, 0xd8e3, 0x05c1, 0x084a, 0xb5be, 0xdaec, 0x09a2,
-0xe1b9, 0x11ee, 0x6086, 0x43d5, 0x17db, 0x2892, 0xfb50, 0xb60e, 0xc9f7, 0xc054,
-0xc68d, 0x23e0, 0x2ffe, 0x062b, 0x4e99, 0x701f, 0xf80e, 0xd329, 0xff2c, 0xcb90,
-0xa2d6, 0xed8c, 0x1910, 0x0699, 0x2f80, 0x3089, 0x1d1c, 0x374f, 0x03b2, 0xc14c,
-0xd8b6, 0xfb3d, 0xd617, 0xe1a7, 0x22a2, 0x2021, 0x1a55, 0x1dcb, 0x2025, 0x150c,
-0x0753, 0xe11c, 0xb5ad, 0xeb4f, 0xe450, 0xcc01, 0x1b1d, 0x3faa, 0x18aa, 0x0e6d,
-0x4970, 0x17e5, 0xcba3, 0xd80b, 0xbb23, 0xc5d9, 0xe755, 0xf01c, 0x158e, 0x5028,
-0x3e7d, 0xfcdb, 0x3482, 0x21eb, 0xbae5, 0xbfbe, 0xd2fb, 0xcfc4, 0xd821, 0x0aca,
-0x27bb, 0x3924, 0x3d1e, 0x0e86, 0x271a, 0x205b, 0xd16c, 0xaf53, 0xc9df, 0xe377,
-0xce6f, 0xfa21, 0x34f1, 0x4083, 0x3410, 0x259d, 0x319d, 0x06b6, 0xd9dc, 0xb750,
-0xb2df, 0xde42, 0xd8e4, 0xfe96, 0x4970, 0x54f6, 0x25ba, 0x2520, 0x3c2e, 0xedea,
-0xc061, 0xba0d, 0xba48, 0xde9c, 0xeb84, 0x0af2, 0x401e, 0x56b2, 0x1aa5, 0x0f66,
-0x36cf, 0xe844, 0xb80e, 0xc1dd, 0xc246, 0xcece, 0xe9fe, 0x177a, 0x32d2, 0x4547,
-0x1818, 0x0c52, 0x30b6, 0xec12, 0xaf1a, 0xb2f2, 0xcfa8, 0xd2b1, 0xdf9e, 0x2116,
-0x3ab2, 0x35ab, 0x1b48, 0x247c, 0x25e1, 0xdedd, 0xb1e5, 0xaf2b, 0xdb4a, 0xe17b,
-0xdfc7, 0x27da, 0x4f71, 0x34be, 0x0ed1, 0x2d58, 0x1ef5, 0xd091, 0xc1bb, 0xbe47,
-0xd524, 0xeaee, 0xf469, 0x2112, 0x4cf4, 0x3d3e, 0x0aff, 0x304c, 0x281a, 0xcdc7,
-0xbbed, 0xd088, 0xe04a, 0xdeea, 0xfee9, 0x2f94, 0x47fc, 0x3dff, 0x1a27, 0x31e9,
-0x1deb, 0xd894, 0xbec6, 0xc6e8, 0xe5fc, 0xe340, 0x014d, 0x3cd1, 0x4e2f, 0x32bd,
-0x1d0c, 0x372e, 0x0af1, 0xce88, 0xc502, 0xc97d, 0xe495, 0xeb9c, 0x0798, 0x374a,
-0x4e4d, 0x2a7e, 0x16b3, 0x3ddd, 0x08ed, 0xc949, 0xc5ee, 0xce08, 0xdf28, 0xe8b7,
-0x0fe9, 0x3689, 0x490a, 0x2817, 0x1714, 0x38c1, 0x0109, 0xc527, 0xc1af, 0xd087,
-0xdced, 0xe41e, 0x12dc, 0x3476, 0x3cd2, 0x201b, 0x1cbb, 0x2e40, 0xf269, 0xc5fe,
-0xb844, 0xcaac, 0xdf7f, 0xe02f, 0x0f09, 0x373a, 0x383b, 0x13eb, 0x21ef, 0x2cbc,
-0xe41a, 0xc568, 0xb82e, 0xc319, 0xdca2, 0xe63b, 0x0f93, 0x3ca2, 0x4202, 0x11af,
-0x2392, 0x2ac6, 0xd906, 0xb7d3, 0xb715, 0xce35, 0xdb89, 0xef49, 0x2213, 0x3ff6,
-0x3f4b, 0x14d9, 0x2398, 0x1f27, 0xd7ab, 0xb866, 0xb50a, 0xd74b, 0xe11e, 0xf58b,
-0x2ece, 0x467f, 0x3963, 0x1933, 0x2caa, 0x1426, 0xd5d8, 0xbe81, 0xb620, 0xdf76,
-0xe789, 0xf65e, 0x349f, 0x505c, 0x3366, 0x16ea, 0x3646, 0x0f5a, 0xd18a, 0xc1b2,
-0xb7f7, 0xdd2a, 0xeb2f, 0xfd79, 0x30f5, 0x516e, 0x31d6, 0x12af, 0x388a, 0x0be7,
-0xca82, 0xbdf0, 0xbc89, 0xda3c, 0xe687, 0x06e8, 0x3695, 0x5204, 0x3323, 0x158c,
-0x3447, 0x05f1, 0xca02, 0xb88d, 0xc1cf, 0xe381, 0xea5c, 0x110d, 0x40c6, 0x4e27,
-0x2a69, 0x1e8c, 0x30b5, 0xf349, 0xc5eb, 0xb6f0, 0xc440, 0xe7cd, 0xebf2, 0x1281,
-0x4308, 0x4ce7, 0x1f25, 0x1bf5, 0x2d5c, 0xe897, 0xc291, 0xb85f, 0xc6be, 0xe556,
-0xf257, 0x1cc0, 0x442d, 0x4d14, 0x200a, 0x1f36, 0x26a6, 0xdf96, 0xbef2, 0xb898,
-0xd0e1, 0xe9a1, 0xf513, 0x2536, 0x486a, 0x4666, 0x1bd4, 0x216e, 0x1a61, 0xd966,
-0xbfd6, 0xb46f, 0xd414, 0xeb0f, 0xf5c1, 0x2917, 0x4b03, 0x3b01, 0x120a, 0x279d,
-0x127b, 0xce60, 0xc0b2, 0xbaa1, 0xd93a, 0xea16, 0xf79d, 0x29e1, 0x4e28, 0x3952,
-0x0c9b, 0x2918, 0x0da3, 0xc8e3, 0xbf5d, 0xbd5b, 0xd7be, 0xe6b5, 0xff78, 0x2bfe,
-0x474e, 0x30ea, 0x0afb, 0x2996, 0x09da, 0xc618, 0xb66b, 0xc002, 0xde8f, 0xe009,
-0x0068, 0x34b1, 0x479e, 0x290d, 0x1057, 0x2cf4, 0x0037, 0xc901, 0xba19, 0xc161,
-0xe4c1, 0xe626, 0x06b7, 0x3bce, 0x46e6, 0x1fc6, 0x1c43, 0x37dd, 0xf4a3, 0xc6e9,
-0xc0da, 0xc57a, 0xe45d, 0xe96e, 0x0b68, 0x3e09, 0x4c53, 0x1c9e, 0x1978, 0x350c,
-0xec82, 0xc2fd, 0xc069, 0xc683, 0xdf64, 0xee42, 0x1619, 0x39da, 0x4685, 0x1dc8,
-0x1c78, 0x2de4, 0xe52f, 0xbb56, 0xb88c, 0xd10f, 0xe424, 0xed39, 0x226e, 0x45c9,
-0x4373, 0x1798, 0x1d16, 0x2213, 0xe050, 0xbf9c, 0xb315, 0xd32f, 0xe7c5, 0xec31,
-0x23d2, 0x48dd, 0x38f4, 0x0de0, 0x25fc, 0x1996, 0xcef8, 0xbc82, 0xb55a, 0xd59c,
-0xe89f, 0xefe0, 0x23a4, 0x4993, 0x37a4, 0x0c32, 0x2be5, 0x17d1, 0xcddd, 0xc07a,
-0xb8e9, 0xd329, 0xe54b, 0xfb4e, 0x2cfc, 0x4d3a, 0x3bad, 0x0fee, 0x2b2b, 0x1047,
-0xc712, 0xb4f7, 0xbbf0, 0xdc5f, 0xe2f3, 0xfef6, 0x224e, 0x4c36, 0x6c76, 0x2b5c,
-0xfa57, 0xe594, 0xbdb1, 0x8b0a, 0xa7ca, 0x0160, 0x0786, 0x400c, 0x8424, 0x5796,
-0x1be9, 0xf540, 0xbdf9, 0x9768, 0xc4df, 0xbd3d, 0xdd3d, 0x63d3, 0x4e65, 0x1fea,
-0x4e57, 0x38bb, 0xd91b, 0xcd56, 0xe3ad, 0xbffd, 0xfbd6, 0x0607, 0xdb8e, 0x3ccb,
-0x4192, 0xd6b0, 0xf73b, 0x42bf, 0xeff1, 0xe330, 0x3dbd, 0xfa84, 0xdccf, 0x13df,
-0xde74, 0xb718, 0x0b45, 0x28d2, 0xfb25, 0x3fa0, 0x4276, 0xedb2, 0x1335, 0x0954,
-0xadc9, 0xc6fc, 0x1522, 0xf53c, 0xfe45, 0x4b87, 0x18e7, 0x04a7, 0x3412, 0xee3f,
-0xb321, 0xfd48, 0x04c9, 0xc508, 0x15a8, 0x372c, 0xeb2f, 0x165c, 0x2ca0, 0xce55,
-0xd34d, 0x1c95, 0xe2fd, 0xdd7e, 0x3294, 0xf905, 0xe452, 0x34a4, 0x04d0, 0xbdd7,
-0x0a01, 0x1d14, 0xce45, 0x0c02, 0x2888, 0xd716, 0x03dc, 0x2b4a, 0xd5cd, 0xd68c,
-0x2ef2, 0xfc10, 0xda6f, 0x316f, 0x0773, 0xda8e, 0x2215, 0x0507, 0xb6f3, 0xfe70,
-0x2a5d, 0xd6c8, 0x0b84, 0x4188, 0xe8c4, 0xfdd0, 0x2ec5, 0xd794, 0xc3a2, 0x2279,
-0xf779, 0xd09d, 0x423d, 0x27fc, 0xe6f8, 0x2f40, 0x1b5a, 0xbc8b, 0xf157, 0x1fb4,
-0xcaa0, 0xfa3a, 0x4232, 0xf922, 0x0ecb, 0x3f09, 0xe3ee, 0xc318, 0x1cef, 0xfdc1,
-0xca4c, 0x2a22, 0x20f1, 0xe87d, 0x279c, 0x1afc, 0xbe72, 0xe720, 0x2220, 0xd1d4,
-0xf6a7, 0x4e3e, 0xf5f4, 0xecca, 0x3b54, 0xf567, 0xb06f, 0x0a45, 0x0b98, 0xc973,
-0x28f0, 0x2f21, 0xdfeb, 0x24a0, 0x2810, 0xaef4, 0xd207, 0x2ab3, 0xcd51, 0xdc82,
-0x4ca3, 0xfdde, 0xef82, 0x40ab, 0xf143, 0xac33, 0x082b, 0xfdac, 0xb9b7, 0x28f3,
-0x2b71, 0xd054, 0x2723, 0x3651, 0xb6cf, 0xd176, 0x2ba8, 0xd75d, 0xdb92, 0x450f,
-0xfd8f, 0xec9c, 0x3e23, 0xf598, 0xaf02, 0x111a, 0x135a, 0xbd2d, 0x2334, 0x3d0a,
-0xd3d8, 0x1768, 0x3bb0, 0xbab9, 0xc676, 0x311a, 0xe06f, 0xd889, 0x5018, 0x070b,
-0xe756, 0x4942, 0xfd09, 0x9d71, 0x0bcc, 0x1bed, 0xb4ce, 0x1c66, 0x47ec, 0xdc5f,
-0x1b74, 0x4238, 0xc481, 0xcf1b, 0x32f5, 0xe1ce, 0xda85, 0x4e4d, 0x0437, 0xe474,
-0x4777, 0x07ed, 0xaff9, 0x127d, 0x24cd, 0xc370, 0x199d, 0x3e29, 0xd8bf, 0x14fd,
-0x3d8b, 0xc8ea, 0xd1b6, 0x3766, 0xecd3, 0xda6f, 0x4fa7, 0x0ce7, 0xdddd, 0x4019,
-0x0c05, 0xaedb, 0x0dbc, 0x2b4c, 0xcdd3, 0x1ddc, 0x470d, 0xe283, 0x1764, 0x40d4,
-0xcabb, 0xcd66, 0x3585, 0xf1c2, 0xdda9, 0x4ffb, 0x11e4, 0xe28a, 0x415d, 0x12d2,
-0xb486, 0x055e, 0x1fd4, 0xc66e, 0x12ca, 0x417e, 0xe4e2, 0x1229, 0x3e2a, 0xd10c,
-0xc800, 0x29e0, 0xed4e, 0xd10c, 0x3fcc, 0x11a3, 0xe1f9, 0x3ad7, 0x16ca, 0xb727,
-0x0155, 0x2400, 0xc8c6, 0x0c22, 0x40bf, 0xe1dc, 0x06e9, 0x3e89, 0xd924, 0xc59a,
-0x27a2, 0xf22c, 0xcfad, 0x3f51, 0x14cd, 0xda51, 0x2f15, 0x1235, 0xae68, 0xedef,
-0x1983, 0xc602, 0x06d9, 0x46e6, 0xe9de, 0x01cd, 0x3928, 0xd470, 0xb512, 0x15ff,
-0xec31, 0xc9cd, 0x3f78, 0x243a, 0xe15e, 0x29ed, 0x1245, 0xaba1, 0xe5e9, 0x199e,
-0xc296, 0xfe39, 0x4ac5, 0xeb5f, 0xfa56, 0x3c11, 0xd94f, 0xae50, 0x1511, 0xf001,
-0xbde3, 0x36c2, 0x230d, 0xd7fe, 0x2c17, 0x1e3a, 0xaa06, 0xe31f, 0x226e, 0xc144,
-0xf626, 0x4f4e, 0xeb1e, 0xf4dd, 0x3e8c, 0xdc0a, 0xaf47, 0x1e56, 0xfed8, 0xc48e,
-0x3d56, 0x2b0f, 0xd682, 0x2918, 0x1dec, 0xa955, 0xe5bb, 0x2b6b, 0xc9b8, 0xfa77,
-0x56f8, 0xf481, 0xfb61, 0x4479, 0xdf2e, 0xabca, 0x1c70, 0xffe7, 0xbc88, 0x3a59,
-0x3826, 0xe054, 0x2f4b, 0x2c11, 0xb1dd, 0xe03e, 0x2b29, 0xc998, 0xf18d, 0x59ee,
-0xf7ac, 0xf73d, 0x4d8e, 0xed67, 0xb1d8, 0x21a9, 0x1848, 0xccda, 0x07a8, 0xffcd,
-0xfa23, 0x5aea, 0x3797, 0xd62f, 0x0ab0, 0x245e, 0xb225, 0xc27c, 0x09d2, 0xd863,
-0xfe56, 0x5bb6, 0x4ddb, 0x2aa0, 0x3bda, 0x0b4a, 0xc172, 0xdcc2, 0xc178, 0xb04a,
-0x211f, 0x3a69, 0xf99a, 0x3316, 0x7dfa, 0x1afe, 0xd954, 0x046d, 0xdf49, 0xb051,
-0xdb3e, 0x09de, 0x0f9f, 0x347e, 0x2f84, 0x0af2, 0x3895, 0x1ade, 0xc5b6, 0xd468,
-0xfe63, 0xe6d0, 0xddae, 0x14b5, 0x175e, 0x16c3, 0x1fae, 0x122e, 0x1fcb, 0x16f5,
-0xef7f, 0xbe99, 0xdd8a, 0xf61b, 0xc6ce, 0x019a, 0x43c3, 0x2909, 0x1168, 0x39ad,
-0x2f76, 0xde14, 0xddd2, 0xc963, 0xbd2a, 0xea45, 0xea62, 0x0266, 0x4616, 0x4e1c,
-0x015e, 0x18de, 0x36f6, 0xcf20, 0xb656, 0xd210, 0xd017, 0xd8b3, 0xfb2f, 0x1950,
-0x2b27, 0x3c69, 0x095e, 0x0ec5, 0x2d9c, 0xe85e, 0xb75b, 0xc4ac, 0xe1a3, 0xcfe0,
-0xdf2a, 0x1a10, 0x3183, 0x376b, 0x1d4c, 0x237d, 0x185c, 0xe4f3, 0xbf7b, 0xab18,
-0xcfc2, 0xd346, 0xe11c, 0x2903, 0x45ea, 0x24aa, 0x102b, 0x353d, 0x080f, 0xc677,
-0xbdeb, 0xb32e, 0xd477, 0xe331, 0xef66, 0x2325, 0x4c5c, 0x27b3, 0xfaf5, 0x3106,
-0x1252, 0xc709, 0xca81, 0xcbe5, 0xd04d, 0xdd4e, 0xfd3c, 0x1a5f, 0x3c21, 0x2935,
-0x0252, 0x3750, 0x1e8e, 0xc8e4, 0xb83e, 0xd48f, 0xdc6e, 0xce04, 0x0585, 0x31bc,
-0x360a, 0x2009, 0x14c2, 0x394e, 0x10a3, 0xc93d, 0xafa5, 0xd6b1, 0xef04, 0xcd94,
-0x0467, 0x48be, 0x4051, 0x1437, 0x1fb5, 0x3cd3, 0xf79e, 0xcc8f, 0xc153, 0xcd1f,
-0xeeb7, 0xe37c, 0x03cf, 0x4174, 0x4958, 0x1000, 0x1d3b, 0x4853, 0xf289, 0xbea9,
-0xc9e2, 0xd4e7, 0xde7b, 0xe633, 0x1461, 0x3e75, 0x4911, 0x1b5a, 0x2106, 0x4059,
-0xf467, 0xbf92, 0xc1f8, 0xd995, 0xdcf6, 0xe0ba, 0x1eb5, 0x4600, 0x4167, 0x1d25,
-0x2ef9, 0x3639, 0xe56b, 0xc105, 0xc027, 0xd70a, 0xe1eb, 0xea01, 0x247e, 0x4c66,
-0x3f10, 0x14c8, 0x3245, 0x3094, 0xdd32, 0xc132, 0xc147, 0xd9a1, 0xe18c, 0xeeb8,
-0x2824, 0x4a69, 0x395c, 0x1015, 0x3040, 0x238d, 0xd48a, 0xc21b, 0xc53b, 0xdc6d,
-0xe1ce, 0xf6ef, 0x2ad6, 0x46b7, 0x34da, 0x1114, 0x34eb, 0x1e8c, 0xd361, 0xbe8c,
-0xc1c6, 0xe012, 0xdf71, 0xf81f, 0x3359, 0x4a06, 0x2d71, 0x1454, 0x38da, 0x0f58,
-0xccf4, 0xbea1, 0xbbb5, 0xdb25, 0xe2c4, 0xfd77, 0x3627, 0x5121, 0x2c35, 0x15a0,
-0x3989, 0x0018, 0xc03f, 0xbaf5, 0xc3cd, 0xe02b, 0xe6c9, 0x0e3d, 0x3eb5, 0x4d58,
-0x26cb, 0x1318, 0x2fe0, 0xf891, 0xc27d, 0xb828, 0xc71e, 0xe21d, 0xe699, 0x15c5,
-0x4058, 0x45ef, 0x2262, 0x1985, 0x28bc, 0xeca7, 0xc32c, 0xb7e4, 0xcfc1, 0xea07,
-0xe4ac, 0x173a, 0x461c, 0x3eba, 0x15fa, 0x2087, 0x2703, 0xe29a, 0xc4b3, 0xb600,
-0xc8f7, 0xe687, 0xe9ba, 0x15c4, 0x426b, 0x3e74, 0x0edd, 0x1f75, 0x23b8, 0xd925,
-0xc0ab, 0xba1f, 0xcb2d, 0xe095, 0xeca2, 0x1990, 0x40e5, 0x3c5d, 0x1023, 0x24d2,
-0x1ebd, 0xd280, 0xbab7, 0xba30, 0xd226, 0xe0d0, 0xf39a, 0x22d6, 0x4063, 0x34fc,
-0x0f3b, 0x2825, 0x190f, 0xd310, 0xbcd9, 0xbd2e, 0xd80b, 0xdd5a, 0xf3ce, 0x2b22,
-0x4783, 0x32fb, 0x13a4, 0x3361, 0x1484, 0xcf84, 0xc067, 0xc184, 0xdb6a, 0xe3e8,
-0x0230, 0x3122, 0x4768, 0x320a, 0x16c1, 0x3427, 0x0aed, 0xc9bb, 0xba81, 0xc328,
-0xe12c, 0xe1e3, 0x07e1, 0x3ec1, 0x4f67, 0x2ddc, 0x15f0, 0x2f32, 0xfe24, 0xc964,
-0xbbfd, 0xc754, 0xe848, 0xe9ef, 0x1196, 0x41b3, 0x4b5f, 0x2760, 0x1f91, 0x35ce,
-0xf3d5, 0xc722, 0xbfad, 0xcade, 0xe85a, 0xeaa5, 0x1660, 0x4809, 0x4c60, 0x1f11,
-0x212f, 0x36b0, 0xefd1, 0xc764, 0xbc28, 0xc837, 0xe455, 0xec50, 0x1c88, 0x4b3c,
-0x4de3, 0x2041, 0x28c6, 0x32d7, 0xe1ea, 0xbea7, 0xbd29, 0xd1a9, 0xe60c, 0xf02d,
-0x2433, 0x4c51, 0x4811, 0x1816, 0x23ce, 0x292b, 0xdf35, 0xbcec, 0xb6b3, 0xd50d,
-0xe49a, 0xee6a, 0x2b0c, 0x4b27, 0x39f9, 0x15f5, 0x29d8, 0x1859, 0xd36e, 0xc04c,
-0xb5ab, 0xd4b0, 0xe461, 0xec0c, 0x2803, 0x4fb2, 0x371f, 0x0f49, 0x2de8, 0x1063,
-0xc7dd, 0xbbcc, 0xb195, 0xcdad, 0xe2b5, 0xf6ed, 0x29d0, 0x4ac5, 0x31e4, 0x0aa9,
-0x2acb, 0x0735, 0xbe72, 0xb39c, 0xb620, 0xd1d9, 0xdc5c, 0xfcdd, 0x307a, 0x46be,
-0x2c7c, 0x0a2b, 0x22ab, 0xfca8, 0xc0ac, 0xafc4, 0xb815, 0xde74, 0xe13f, 0x0269,
-0x370e, 0x4107, 0x21c4, 0x13c8, 0x26a3, 0xf061, 0xc3ac, 0xb5ad, 0xbbea, 0xe2b6,
-0xe314, 0x03cd, 0x3a8a, 0x453e, 0x1c0b, 0x167a, 0x2afd, 0xe8ae, 0xc330, 0xbb1d,
-0xbd71, 0xdff6, 0xea8c, 0x0cd6, 0x3cc1, 0x4b59, 0x1e08, 0x1762, 0x288a, 0xe327,
-0xbcf5, 0xbc04, 0xcc41, 0xe3b8, 0xf214, 0x1f63, 0x40b7, 0x4556, 0x1932, 0x14e9,
-0x22d4, 0xe5af, 0xc176, 0xbaf1, 0xd516, 0xeaa3, 0xed1a, 0x10a5, 0x4490, 0x6d0e,
-0x387d, 0x06ad, 0xf979, 0xc011, 0x9e3c, 0xad92, 0xe582, 0x1234, 0x4531, 0x6a71,
-0x4d3b, 0x3443, 0xfe14, 0xbf35, 0xb76f, 0xcbe7, 0xc8b4, 0xe9aa, 0x501f, 0x43d8,
-0x1d18, 0x4560, 0x2e0d, 0xf4de, 0xea75, 0xe7b7, 0xd73f, 0x0fdc, 0x11cd, 0xd145,
-0x29c3, 0x44d4, 0xdad6, 0xf4f0, 0x3e51, 0x092e, 0x07b6, 0x43ce, 0xfd5a, 0xf591,
-0x1f19, 0xc2ea, 0xb2d7, 0x198e, 0x140f, 0xfa53, 0x5e12, 0x4564, 0xf1ae, 0x2e33,
-0x0b49, 0xa4bb, 0xdaed, 0x1485, 0xdc90, 0x0cbf, 0x4f0d, 0x0854, 0x15b5, 0x3b75,
-0xe6b5, 0xbe4e, 0x0981, 0xfc23, 0xc6c6, 0x22a2, 0x2984, 0xf1db, 0x27f9, 0x1ab0,
-0xc60e, 0xe49e, 0x21a8, 0xd681, 0xe953, 0x41f4, 0xf337, 0xeb9d, 0x3560, 0xf514,
-0xbd12, 0x135a, 0x1144, 0xc99f, 0x21e0, 0x2271, 0xd155, 0x1a35, 0x25a3, 0xbec7,
-0xdc7d, 0x31ed, 0xe802, 0xe46d, 0x3ef6, 0xfc72, 0xeb7d, 0x2fc5, 0xecf1, 0xb132,
-0x0d6d, 0x171d, 0xcaf3, 0x20be, 0x36cd, 0xdeff, 0x1430, 0x2c97, 0xc49c, 0xcab8,
-0x247c, 0xe2b5, 0xd3f1, 0x3d93, 0x0c22, 0xee37, 0x3907, 0x01ea, 0xb32c, 0x07e5,
-0x153f, 0xb7d0, 0x0a61, 0x333d, 0xdb8a, 0x1138, 0x3892, 0xcfca, 0xccd1, 0x2831,
-0xeb12, 0xd73f, 0x357e, 0xfe1d, 0xe21b, 0x300a, 0xfded, 0xaf91, 0xffaf, 0x1ba1,
-0xc5b1, 0x0c52, 0x3c73, 0xe33f, 0xfac8, 0x2338, 0xd7bc, 0xc7f4, 0x0f99, 0xe739,
-0xd9e0, 0x3980, 0x0e6d, 0xe382, 0x335e, 0x15f9, 0xae82, 0xe698, 0x1c86, 0xca1d,
-0xf6f1, 0x34d2, 0xf14d, 0x0fec, 0x3c9a, 0xdef1, 0xc8df, 0x20f3, 0xea68, 0xc50a,
-0x33ef, 0x1185, 0xd7d4, 0x2ebc, 0x2178, 0xc1c1, 0xf72b, 0x2354, 0xd2eb, 0x0168,
-0x30db, 0xe0a6, 0x05a6, 0x3bad, 0xdc09, 0xc45f, 0x276d, 0xfd11, 0xcf0a, 0x363e,
-0x204b, 0xe4d0, 0x2851, 0x199c, 0xbc3c, 0xe9df, 0x1c38, 0xcf05, 0x03b3, 0x4c0e,
-0xf6ee, 0x068d, 0x44a0, 0xe3e0, 0xb163, 0x17fa, 0xfdee, 0xc709, 0x37cd, 0x2e63,
-0xea1c, 0x3531, 0x2ca0, 0xbf9e, 0xeeec, 0x2b06, 0xc5f7, 0xf1c8, 0x5385, 0xfc84,
-0x0002, 0x49cb, 0xf52b, 0xbfbf, 0x204d, 0x04c6, 0xc649, 0x35e9, 0x30b9, 0xe658,
-0x31b2, 0x2cb7, 0xb96b, 0xe5a8, 0x2f24, 0xd410, 0xf6ab, 0x5771, 0x04b9, 0xfc36,
-0x3ec2, 0xecd7, 0xb28a, 0x1904, 0x0954, 0xc24d, 0x3764, 0x3ade, 0xddf2, 0x29ce,
-0x3445, 0xb4d5, 0xd352, 0x2d79, 0xd037, 0xe09a, 0x535a, 0x01a5, 0xf095, 0x48ef,
-0xf767, 0xa8aa, 0x11b3, 0x097b, 0xb15c, 0x2a36, 0x3db4, 0xd6cd, 0x24b8, 0x3712,
-0xb430, 0xcdb4, 0x2b60, 0xd3aa, 0xe09b, 0x53eb, 0xfc4a, 0xea6b, 0x4b2a, 0xf90e,
-0xa8c8, 0x1124, 0x129b, 0xbaac, 0x269d, 0x4030, 0xda96, 0x20e1, 0x3a2e, 0xbd1c,
-0xd0d8, 0x3158, 0xdd88, 0xdee5, 0x57dc, 0x0a22, 0xeb70, 0x4be8, 0x027e, 0xa602,
-0x0680, 0x1714, 0xbfed, 0x242e, 0x47b1, 0xe011, 0x1d8e, 0x3eca, 0xc029, 0xc616,
-0x2e06, 0xe28f, 0xd4aa, 0x4f9e, 0x0f06, 0xe649, 0x438d, 0x0564, 0xa6f1, 0x02f6,
-0x1bd3, 0xc020, 0x18b7, 0x4204, 0xd71b, 0x0fc8, 0x3e52, 0xc2b8, 0xbf78, 0x2bd7,
-0xe6d3, 0xce7b, 0x47d7, 0x0a5d, 0xd7d4, 0x39c7, 0x074e, 0xa273, 0xfc77, 0x1fef,
-0xbcf9, 0x0cec, 0x426a, 0xd4f2, 0x044f, 0x3d93, 0xc6ea, 0xbcdf, 0x2bd1, 0xed0b,
-0xce10, 0x43d0, 0x0ca2, 0xd5d2, 0x35c4, 0x0c15, 0xa646, 0xfa2d, 0x2097, 0xc0dd,
-0x0c2b, 0x439b, 0xdc9c, 0x059f, 0x3b30, 0xca4a, 0xbbcb, 0x2337, 0xe7a3, 0xc717,
-0x3dae, 0x1491, 0xdc09, 0x3229, 0x0f3e, 0xac38, 0xf62a, 0x25d7, 0xcda9, 0xe86a,
-0x0ccd, 0xe87d, 0x2a51, 0x46ee, 0xea42, 0xe40d, 0x22b1, 0xd631, 0xa84b, 0xf868,
-0xe4f9, 0xdc35, 0x395d, 0x50be, 0x1fd6, 0x25ac, 0x1e57, 0xc641, 0xc358, 0xd0f2,
-0xac56, 0xf1aa, 0x385d, 0x08e0, 0x0c0c, 0x6c90, 0x3d9a, 0xd534, 0xf575, 0xf32f,
-0xb660, 0xc715, 0x00c3, 0x060a, 0x1cc0, 0x3bee, 0x0fef, 0x2648, 0x390e, 0xe520,
-0xcaa4, 0xfc07, 0xfa8c, 0xcfc3, 0xff3b, 0x2146, 0x0eaa, 0x22f7, 0x21eb, 0x22a5,
-0x2b3f, 0x140f, 0xd035, 0xce0d, 0x018b, 0xcdfd, 0xe402, 0x4024, 0x35a0, 0x11b4,
-0x30f7, 0x48c6, 0xfc36, 0xe429, 0xd9e4, 0xb819, 0xe9ae, 0xecf6, 0xeaac, 0x339b,
-0x5af6, 0x18c2, 0x0a7d, 0x49f9, 0xfaf8, 0xba8d, 0xd5ae, 0xd0dc, 0xd43b, 0xee6d,
-0x117b, 0x23d1, 0x46ee, 0x29ad, 0x0339, 0x3a96, 0x1314, 0xc110, 0xbad0, 0xd9cf,
-0xd706, 0xcd74, 0x0d91, 0x315e, 0x3f9c, 0x359b, 0x2190, 0x2aef, 0x0433, 0xcdb2,
-0xa574, 0xc711, 0xe12e, 0xcf40, 0x197f, 0x5324, 0x3d77, 0x20a5, 0x375c, 0x2d03,
-0xe262, 0xca54, 0xb0b0, 0xc640, 0xed6e, 0xe3a9, 0x14a7, 0x559a, 0x4789, 0x0af5,
-0x2c0d, 0x3078, 0xd574, 0xc8f1, 0xc60c, 0xc4a3, 0xddbb, 0xf434, 0x12bf, 0x3a4f,
-0x46b5, 0x0de9, 0x28f8, 0x3a3e, 0xd862, 0xb36e, 0xc4b9, 0xd290, 0xcc9e, 0xf150,
-0x28e5, 0x36b7, 0x3727, 0x1942, 0x296a, 0x1f3b, 0xd304, 0xaa50, 0xb7e0, 0xe064,
-0xcd60, 0xe774, 0x36d2, 0x4354, 0x256f, 0x16b9, 0x32a9, 0x04e9, 0xc94b, 0xbd89,
-0xb4e8, 0xde63, 0xe6b3, 0xefc2, 0x2c99, 0x4d30, 0x244c, 0x0dd9, 0x4013, 0x0a25,
-0xbf81, 0xc647, 0xc8d3, 0xd098, 0xddd7, 0x0729, 0x2f46, 0x49fe, 0x3186, 0x11dd,
-0x33c9, 0x0a1a, 0xc455, 0xb4fe, 0xcbf9, 0xe01f, 0xd9c3, 0x0d63, 0x3ca9, 0x40e4,
-0x2597, 0x1f85, 0x2fee, 0xf6c7, 0xc763, 0xb733, 0xcbd2, 0xe734, 0xe337, 0x11ef,
-0x4379, 0x4377, 0x1865, 0x216c, 0x32c8, 0xee0c, 0xca47, 0xc04a, 0xd076, 0xe70b,
-0xebed, 0x16a9, 0x3f81, 0x44ae, 0x16f6, 0x2266, 0x31f0, 0xe6d6, 0xc30d, 0xc333,
-0xd87e, 0xe495, 0xf14b, 0x1f91, 0x3ab4, 0x3a37, 0x1822, 0x291b, 0x2bcf, 0xea2c,
-0xc762, 0xbf57, 0xdd08, 0xe181, 0xec7b, 0x28f2, 0x456d, 0x366d, 0x1d72, 0x3891,
-0x2266, 0xe229, 0xcd55, 0xbe26, 0xdad8, 0xe6b2, 0xf1ad, 0x2a59, 0x4ce7, 0x346f,
-0x18da, 0x3eb3, 0x1a5c, 0xd0e6, 0xc45c, 0xbfe1, 0xd4d3, 0xe11f, 0x014a, 0x2f81,
-0x4863, 0x3408, 0x1268, 0x31f4, 0x0ec8, 0xca3c, 0xb9fc, 0xc1dc, 0xdd52, 0xe093,
-0x05ff, 0x33c3, 0x43d7, 0x2da7, 0x1671, 0x2bf0, 0x0034, 0xc97d, 0xb0c3, 0xbe5e,
-0xe43b, 0xdb68, 0x0387, 0x3ae6, 0x3ee7, 0x1b43, 0x174b, 0x2d76, 0xf26e, 0xc68d,
-0xb289, 0xbb76, 0xe0fe, 0xde57, 0x0305, 0x3b0e, 0x44f7, 0x17e8, 0x1ae0, 0x2e9e,
-0xe6b9, 0xc23e, 0xb5b3, 0xbe35, 0xde8a, 0xe55c, 0x0e04, 0x3e2d, 0x4749, 0x1891,
-0x1cce, 0x2c46, 0xe31a, 0xbc10, 0xb2be, 0xc7d4, 0xe1b0, 0xec58, 0x1b5f, 0x42a4,
-0x4577, 0x18af, 0x206d, 0x2610, 0xe0cf, 0xbee7, 0xb63b, 0xd3ec, 0xe4ab, 0xed6c,
-0x253f, 0x4a99, 0x42a8, 0x18da, 0x2a90, 0x2130, 0xd967, 0xc013, 0xb623, 0xd3d0,
-0xe7d4, 0xf7c7, 0x2d1b, 0x4df4, 0x3dfe, 0x18d3, 0x2e94, 0x12e1, 0xceb7, 0xbc8b,
-0xb721, 0xd9e6, 0xe7b6, 0xfe42, 0x37c7, 0x5256, 0x3916, 0x14fa, 0x2b19, 0x0829,
-0xcbbc, 0xbc11, 0xba4e, 0xe0c8, 0xec3c, 0x04ba, 0x39d7, 0x4f48, 0x314f, 0x1b2a,
-0x320f, 0xfbd4, 0xc7ad, 0xbe46, 0xbcb0, 0xdfec, 0xea9d, 0x0a76, 0x3eae, 0x51ce,
-0x28b8, 0x15c7, 0x32b1, 0xf736, 0xc436, 0xbbe2, 0xc2bd, 0xe357, 0xecf4, 0x10c4,
-0x40f6, 0x524e, 0x25cd, 0x19ce, 0x301e, 0xec1e, 0xbc6a, 0xbace, 0xd1d8, 0xe825,
-0xec23, 0x1b1b, 0x4400, 0x482a, 0x1bce, 0x1896, 0x260d, 0xe7f6, 0xc325, 0xb5e4,
-0xd101, 0xeabf, 0xea0d, 0x1d52, 0x47b3, 0x3cf0, 0x1282, 0x235d, 0x2050, 0xd9ae,
-0xc4d9, 0xb970, 0xd086, 0xe87d, 0xea86, 0x1b23, 0x48b1, 0x3c02, 0x0e92, 0x2cb2,
-0x2472, 0xd2cb, 0xbff8, 0xbc43, 0xce22, 0xe2d3, 0xf745, 0x2364, 0x47bb, 0x3e11,
-0x1209, 0x2f53, 0x1fb0, 0xcfac, 0xba0d, 0xbeea, 0xd8e3, 0xde1c, 0xf854, 0x2f24,
-0x49ea, 0x387f, 0x14be, 0x2de7, 0x1304, 0xd01b, 0xb948, 0xbc56, 0xe0d1, 0xe484,
-0xff93, 0x3655, 0x488a, 0x2bf5, 0x16ba, 0x3637, 0x07aa, 0xcf32, 0xc24d, 0xc063,
-0xe449, 0xe713, 0x01e8, 0x3b25, 0x4f83, 0x26c5, 0x1640, 0x3ab8, 0xff8c, 0xc83c,
-0xbf7c, 0xc052, 0xdf32, 0xe807, 0x09ef, 0x390f, 0x4d01, 0x25f5, 0x19b1, 0x3685,
-0xf201, 0xbb2e, 0xb561, 0xc59a, 0xdeac, 0xe81d, 0x110d, 0x2f0d, 0x5faf, 0x5bc4,
-0x12fe, 0xf615, 0xda50, 0xa9ae, 0x886f, 0xcd18, 0x0718, 0x09f1, 0x5bb7, 0x7af7,
-0x3e15, 0x0a73, 0xe799, 0xa715, 0x9c71, 0xc971, 0xb0a1, 0x07a7, 0x6f82, 0x3163,
-0x2a82, 0x5398, 0x14c9, 0xbfc2, 0xd8b3, 0xd540, 0xc5ce, 0x0fda, 0xf099, 0xf1a7,
-0x518e, 0x1c60, 0xcd84, 0x19da, 0x35b8, 0xd346, 0x03a1, 0x377b, 0xdf14, 0xefc5,
-0x0c59, 0xc206, 0xc448, 0x2196, 0x11ee, 0xfe70, 0x4f48, 0x1fa8, 0xeb2d, 0x1d5b,
-0xeaf2, 0x9f51, 0xdaef, 0x10e0, 0xe2b8, 0x140e, 0x4a7c, 0x0548, 0x11c6, 0x2b5c,
-0xd063, 0xb9e9, 0x0c49, 0xee9f, 0xcd6b, 0x32da, 0x2204, 0xe702, 0x2c36, 0x195d,
-0xbc4d, 0xef56, 0x1ea6, 0xd1a8, 0xfb24, 0x33f8, 0xe2fa, 0xffb5, 0x3ccd, 0xe4cb,
-0xca25, 0x2563, 0x0355, 0xd2da, 0x2bb0, 0x137a, 0xd6ec, 0x2218, 0x1b95, 0xc3b7,
-0xf854, 0x3722, 0xe6e8, 0xf671, 0x3596, 0xec18, 0xf030, 0x2d9c, 0xe6e7, 0xc2e9,
-0x26d5, 0x1a49, 0xd733, 0x2bbd, 0x26a1, 0xdab2, 0x1ba0, 0x23f0, 0xc355, 0xe703,
-0x2bce, 0xdc49, 0xf190, 0x496d, 0xfc6e, 0xf386, 0x3dfc, 0xf7e9, 0xbcff, 0x1444,
-0x0996, 0xc579, 0x1fc6, 0x2a9c, 0xe722, 0x261f, 0x2af6, 0xc74c, 0xe3b8, 0x2a8b,
-0xe105, 0xe8c4, 0x3bef, 0xfd9f, 0xefc2, 0x313f, 0xf888, 0xbeed, 0x0f0d, 0x10ba,
-0xcf13, 0x2814, 0x3a0d, 0xdf51, 0x0dca, 0x2f8f, 0xccfa, 0xc831, 0x1d1f, 0xe940,
-0xe8cf, 0x4a93, 0x0d52, 0xef83, 0x3c76, 0xfaba, 0xa5dd, 0x0126, 0x112f, 0xbdc7,
-0x1a61, 0x422a, 0xe9fb, 0x1b1a, 0x3694, 0xc9c9, 0xce2b, 0x1ef2, 0xd732, 0xdc7b,
-0x46da, 0xff7f, 0xe9fc, 0x46e1, 0x05ac, 0xaeb6, 0x0663, 0x159d, 0xc012, 0x1316,
-0x34ba, 0xdd94, 0x12fd, 0x31f6, 0xc596, 0xcbff, 0x2ae2, 0xe4d5, 0xd6c1, 0x4927,
-0x0b3d, 0xdd77, 0x3926, 0x07d1, 0xa2d2, 0xfb2e, 0x211d, 0xc317, 0x1769, 0x4b14,
-0xe280, 0x1326, 0x411c, 0xc1e2, 0xbac5, 0x2cf6, 0xe603, 0xcb4b, 0x4ed8, 0x191b,
-0xe401, 0x458d, 0x1545, 0xac87, 0x005f, 0x1e4a, 0xba9b, 0x0cc0, 0x467e, 0xe1cf,
-0x11da, 0x478e, 0xd350, 0xc70d, 0x31c1, 0xf201, 0xce1e, 0x434c, 0x12d6, 0xdd0b,
-0x3986, 0x1337, 0xaf6d, 0x006c, 0x2ca7, 0xc8ff, 0x0c23, 0x4bde, 0xe11d, 0x0318,
-0x41ef, 0xd0e5, 0xbd29, 0x3042, 0xf8a0, 0xd014, 0x4ad2, 0x1b53, 0xda3d, 0x3aa3,
-0x14be, 0xa4bb, 0xf7a1, 0x2b27, 0xc43a, 0x0948, 0x507e, 0xe296, 0x0297, 0x45db,
-0xd510, 0xb990, 0x273a, 0xf430, 0xc750, 0x3f4c, 0x1a85, 0xdb6a, 0x3993, 0x1ab4,
-0xadf3, 0xf5f6, 0x280d, 0xc5fc, 0xfe8a, 0x4668, 0xe58d, 0x011c, 0x457a, 0xdfc7,
-0xbebe, 0x255e, 0xfae1, 0xcb02, 0x3a3a, 0x1b49, 0xd635, 0x2c90, 0x1a6d, 0xb0f1,
-0xf0b7, 0x2851, 0xcb11, 0xfd3b, 0x4815, 0xe902, 0xf73a, 0x3af3, 0xde3a, 0xb633,
-0x1a27, 0xfae7, 0xc8e7, 0x3373, 0x1efa, 0xdab3, 0x2af8, 0x1f54, 0xb3a4, 0xe5bd,
-0x2010, 0xc657, 0xef33, 0x4332, 0xf32a, 0xf8bc, 0x3a43, 0xe716, 0xb380, 0x1025,
-0xf94b, 0xbff8, 0x2cbe, 0x2722, 0xd958, 0x2238, 0x24de, 0xb4e0, 0xd8e0, 0x219f,
-0xcbf4, 0xec3e, 0x4cc4, 0xf5db, 0xee65, 0x3cb1, 0xe88f, 0xad6b, 0x15fb, 0x0312,
-0xbe65, 0x3207, 0x3441, 0xd731, 0x1ee6, 0x2923, 0xb321, 0xd7af, 0x26e1, 0xce3a,
-0xeb73, 0x52d6, 0xfb3a, 0xed11, 0x3fa2, 0xeb93, 0xa537, 0x0fde, 0x078b, 0xbcc7,
-0x2dd2, 0x39bf, 0xde73, 0x2216, 0x2ba5, 0xb204, 0xd113, 0x2873, 0xd059, 0xe433,
-0x5331, 0x00f5, 0xede6, 0x41c9, 0xf3f8, 0xaa8c, 0x0f24, 0x06be, 0xb5e6, 0x29e9,
-0x39f4, 0xda5d, 0x25b6, 0x2b84, 0xb07f, 0xd942, 0x36fe, 0xe8ec, 0xcdd1, 0x1733,
-0x0849, 0x1aa1, 0x4558, 0xfb48, 0xd3ef, 0x11bd, 0xef48, 0xb142, 0xf697, 0xfdea,
-0xd64a, 0x32a6, 0x6fed, 0x25f8, 0x0b17, 0x2a5c, 0xdff3, 0xaef4, 0xd4ec, 0xbcba,
-0xe25d, 0x44cb, 0x234b, 0x1321, 0x73ba, 0x4da9, 0xced4, 0xe817, 0x007f, 0xa908,
-0xb5df, 0x1df6, 0x1875, 0x0e2c, 0x3ec1, 0x2fcd, 0x272d, 0x2290, 0xe25c, 0xc07e,
-0xf134, 0xfb4d, 0xd6f2, 0x0ad3, 0x3447, 0x223c, 0x13f1, 0x2272, 0x269f, 0x025a,
-0x0161, 0xd722, 0xd224, 0x0308, 0xde38, 0xef78, 0x3c18, 0x42ed, 0x0555, 0x290a,
-0x5400, 0xe6be, 0xca2d, 0xdae9, 0xc68f, 0xd7d0, 0xf47c, 0x10ed, 0x3184, 0x5941,
-0x1cf6, 0x0891, 0x3a35, 0xeb6f, 0xae39, 0xc817, 0xe6f7, 0xd6ef, 0xebb0, 0x3372,
-0x35f1, 0x34dd, 0x1e90, 0x16f7, 0x21a1, 0xf074, 0xc287, 0xb8c4, 0xe82d, 0xe6eb,
-0xdb90, 0x1e19, 0x40af, 0x3208, 0x1a9a, 0x320f, 0x1b9a, 0xdeff, 0xcf46, 0xb4a3,
-0xcbd7, 0xdf68, 0xe59a, 0x22fe, 0x55b5, 0x3892, 0x0be2, 0x396b, 0x1a98, 0xc635,
-0xc146, 0xc092, 0xd361, 0xe7eb, 0x0383, 0x2879, 0x4c6a, 0x3c0d, 0x05ca, 0x2976,
-0x14a9, 0xc798, 0xc116, 0xd2d8, 0xdd50, 0xdcd3, 0x0b09, 0x2bce, 0x3653, 0x2ab8,
-0x0a52, 0x2aa9, 0x14b7, 0xd401, 0xb890, 0xcc60, 0xea88, 0xd5e4, 0xfe7d, 0x383b,
-0x3ade, 0x1b88, 0x1ad7, 0x3ed1, 0x075f, 0xcd9c, 0xbbc4, 0xcbe8, 0xeb85, 0xd822,
-0xfbc3, 0x3e44, 0x459b, 0x10ea, 0x17ee, 0x43df, 0xf7f9, 0xc0a0, 0xc419, 0xcf1f,
-0xdea4, 0xe05f, 0x0678, 0x330f, 0x42d4, 0x111c, 0x0fba, 0x3f57, 0xf9a8, 0xb669,
-0xbe1b, 0xe146, 0xdd9a, 0xd4be, 0x11a3, 0x389d, 0x37d6, 0x13b2, 0x1c70, 0x3370,
-0xf10c, 0xc063, 0xb6e6, 0xd48a, 0xdc66, 0xd809, 0x1789, 0x3f92, 0x3566, 0x0e0f,
-0x231e, 0x2ea3, 0xde28, 0xbb31, 0xba09, 0xcf05, 0xd866, 0xdfc8, 0x18f1, 0x3ecd,
-0x369b, 0x0a8f, 0x2386, 0x2af2, 0xda2a, 0xb79e, 0xb7d0, 0xd687, 0xde35, 0xe721,
-0x22ba, 0x4574, 0x3572, 0x0dd3, 0x2e06, 0x263b, 0xd7ab, 0xbfc7, 0xc2f6, 0xdf1b,
-0xe1c3, 0xf1d5, 0x2cb4, 0x4e1c, 0x37cd, 0x115d, 0x35cd, 0x1fe6, 0xd779, 0xc301,
-0xc58e, 0xe72d, 0xe5ce, 0xf960, 0x335a, 0x4fb4, 0x357b, 0x1898, 0x426e, 0x1cc2,
-0xd473, 0xc727, 0xc831, 0xe1fb, 0xe68f, 0x072e, 0x3da1, 0x58d4, 0x39ac, 0x1d25,
-0x4338, 0x1401, 0xcf2b, 0xbee6, 0xca41, 0xe875, 0xe64f, 0x1316, 0x4982, 0x5236,
-0x2f67, 0x2085, 0x38b8, 0xfd01, 0xc7c8, 0xba93, 0xc979, 0xebc7, 0xea26, 0x168d,
-0x477d, 0x4817, 0x212b, 0x1fdd, 0x335a, 0xef3e, 0xc484, 0xb895, 0xc9b8, 0xec42,
-0xe805, 0x136b, 0x4a61, 0x4971, 0x17b6, 0x1f6a, 0x2f97, 0xe4b1, 0xc086, 0xb999,
-0xcac9, 0xe5fd, 0xee0c, 0x1807, 0x412f, 0x460f, 0x166d, 0x1f4c, 0x29b3, 0xdc64,
-0xb965, 0xb861, 0xd211, 0xe147, 0xeb99, 0x2193, 0x450f, 0x3ce4, 0x113e, 0x1f63,
-0x1c84, 0xd769, 0xb874, 0xb487, 0xd682, 0xe1c9, 0xed74, 0x24b0, 0x43a4, 0x33ba,
-0x0e1c, 0x2413, 0x10f7, 0xcdd3, 0xb977, 0xb8d7, 0xdbc4, 0xe37c, 0xf175, 0x272e,
-0x457d, 0x2d0a, 0x07d0, 0x297e, 0x0f41, 0xca51, 0xb9f7, 0xbc9a, 0xdaa7, 0xddfe,
-0xf766, 0x2c64, 0x4532, 0x2d7b, 0x0dd9, 0x2cf4, 0x0c17, 0xc90f, 0xb4bc, 0xc07f,
-0xe270, 0xdce1, 0xfc63, 0x371a, 0x4749, 0x2579, 0x1187, 0x2dc1, 0xff1f, 0xc7eb,
-0xb7f0, 0xc150, 0xe209, 0xe0bb, 0x0562, 0x39a6, 0x419b, 0x18df, 0x11d0, 0x32b0,
-0xf640, 0xc162, 0xbaa8, 0xc92a, 0xe355, 0xdf42, 0x07ce, 0x3de6, 0x485f, 0x1a8d,
-0x15e0, 0x345d, 0xf2a7, 0xc2b4, 0xbc48, 0xcb43, 0xe331, 0xe771, 0x171d, 0x41c7,
-0x46e8, 0x1e6a, 0x1d99, 0x3169, 0xea47, 0xbb34, 0xb612, 0xcfe5, 0xe372, 0xe4f4,
-0x1dce, 0x4978, 0x4538, 0x1abb, 0x1ff9, 0x2726, 0xe2ee, 0xbf5a, 0xb642, 0xd6a7,
-0xeb65, 0xe981, 0x26c2, 0x5246, 0x3d0f, 0x142e, 0x2f6c, 0x28fc, 0xda88, 0xc3aa,
-0xbdbe, 0xd749, 0xeb54, 0xf1e0, 0x25cd, 0x526c, 0x41ba, 0x10bf, 0x2fe6, 0x2449,
-0xd374, 0xbfc4, 0xbbe2, 0xd283, 0xe25c, 0xf99f, 0x2cef, 0x4ac7, 0x3ddf, 0x17d9,
-0x3082, 0x1925, 0xce89, 0xb6a1, 0xbc50, 0xe283, 0xe474, 0xfd8d, 0x3bcc, 0x4e96,
-0x33c3, 0x167a, 0x2e47, 0x0a43, 0xcef1, 0xbc29, 0xba3d, 0xe1a3, 0xe5f7, 0xfe7c,
-0x39db, 0x4bea, 0x270e, 0x128b, 0x30de, 0xfb59, 0xc505, 0xbdab, 0xbd60, 0xe0c5,
-0xe64a, 0x0171, 0x35c3, 0x47fc, 0x21b5, 0x11b5, 0x30fa, 0xf4fc, 0xc06e, 0xbaa3,
-0xbc7a, 0xd83f, 0xe4e1, 0x0b66, 0x373d, 0x497a, 0x2421, 0x109c, 0x26f1, 0xecb6,
-0xbadf, 0xb11f, 0xc45d, 0xdf59, 0xe4b2, 0x1641, 0x3f59, 0x42bc, 0x1c1c, 0x129c,
-0x1bee, 0xe133, 0xbe64, 0xb1ad, 0xcc9f, 0xec32, 0xe986, 0x19ae, 0x44e5, 0x3a19,
-0x0e88, 0x1ade, 0x1f2c, 0xdec4, 0xc3cc, 0xb2ef, 0xdaab, 0xfd08, 0xe6a7, 0x1123,
-0x3704, 0x3898, 0x3ad4, 0x346f, 0xfe92, 0xd1d3, 0xcc04, 0x9cbd, 0xc135, 0x02eb,
-0xf63b, 0x365b, 0x8b58, 0x58ad, 0x0415, 0x0488, 0xcf1c, 0x8e64, 0xb611, 0xc2c4,
-0xeda1, 0x4ea8, 0x63da, 0x49bb, 0x50ec, 0x3618, 0xc859, 0xb818, 0xe010, 0xbc83,
-0xd14a, 0x1ad8, 0x32a9, 0x4030, 0x4434, 0x0f51, 0xf80f, 0x1895, 0xeaf8, 0xc48d,
-0x175a, 0x2702, 0xe895, 0x0fd2, 0x2756, 0xcf30, 0xdfad, 0x3a11, 0xfb80, 0xfa5f,
-0x565f, 0x121d, 0xf290, 0x2352, 0xddf3, 0xa5f4, 0xfe06, 0x187b, 0xde96, 0x3a13,
-0x5105, 0xf698, 0x255a, 0x212e, 0xb7a3, 0xc5a7, 0x10d7, 0xdeff, 0xe90b, 0x551a,
-0x1708, 0xfd81, 0x42e8, 0xf9ae, 0xb328, 0xf8c8, 0x0cd4, 0xc910, 0x1398, 0x3cf8,
-0xe89b, 0x1c9d, 0x36c1, 0xcb0b, 0xcca6, 0x2759, 0xf1e2, 0xd264, 0x3d80, 0x146d,
-0xe372, 0x36c2, 0x0ab3, 0xb2ef, 0x0a0e, 0x2e96, 0xc7be, 0x0dcf, 0x4ba5, 0xdcd8,
-0xff1f, 0x391f, 0xcf51, 0xc4c3, 0x314b, 0xfef3, 0xd680, 0x41c6, 0x156e, 0xdd3b,
-0x2eeb, 0x0886, 0xa9c9, 0xf3a6, 0x247e, 0xc927, 0x069f, 0x4a37, 0xe895, 0x0061,
-0x378e, 0xd6a1, 0xb348, 0x1688, 0xf810, 0xc498, 0x323f, 0x1fc5, 0xe066, 0x29b3,
-0x139d, 0xadbb, 0xe71a, 0x2c44, 0xcae3, 0xe8e1, 0x3f89, 0xe822, 0xf034, 0x367a,
-0xdf30, 0xb32c, 0x1aba, 0x0281, 0xcc1b, 0x36c4, 0x14ca, 0xc6d5, 0x2590, 0x1c08,
-0xa351, 0xd7ce, 0x2a74, 0xd59f, 0xf3fa, 0x477e, 0xf4e0, 0xf8ff, 0x3121, 0xdc01,
-0xb775, 0x150c, 0xfcd8, 0xcc0d, 0x38c8, 0x2ece, 0xe423, 0x2849, 0x29b5, 0xc302,
-0xda74, 0x1f47, 0xdd2f, 0xf247, 0x3ab2, 0xf2d7, 0x006a, 0x4787, 0xf2b8, 0xbc9f,
-0x1f1c, 0x0ac7, 0xbde9, 0x23df, 0x2b4d, 0xd869, 0x1cf2, 0x2e59, 0xc8ac, 0xe6ca,
-0x2cef, 0xd907, 0xf197, 0x4b23, 0xf20c, 0xef15, 0x4469, 0xf156, 0xb2a9, 0x1bfd,
-0x127b, 0xca28, 0x306d, 0x3438, 0xdf08, 0x20cf, 0x27a1, 0xb9c7, 0xd8d7, 0x2741,
-0xd309, 0xe588, 0x5056, 0x03d5, 0xef96, 0x4207, 0xfd8d, 0xae5f, 0x03b5, 0x0589,
-0xbd38, 0x23af, 0x3a76, 0xe095, 0x2023, 0x3839, 0xc165, 0xd4ca, 0x2de1, 0xd781,
-0xe09b, 0x50bd, 0x0340, 0xea0c, 0x4022, 0xf840, 0xad2c, 0x1331, 0x12e3, 0xc260,
-0x2f2a, 0x3b6c, 0xd12c, 0x18a4, 0x3197, 0xb77c, 0xd13d, 0x2bd2, 0xd972, 0xe616,
-0x52eb, 0x041e, 0xeb26, 0x3bdc, 0xf119, 0xa2b2, 0x06d5, 0x1049, 0xbd97, 0x289f,
-0x44ee, 0xdf14, 0x1d7f, 0x34ac, 0xb7bb, 0xc690, 0x278a, 0xda25, 0xdff9, 0x579a,
-0x080c, 0xe6ec, 0x4374, 0xfcbd, 0xa5be, 0x078c, 0x146b, 0xbb5b, 0x2164, 0x4262,
-0xdc47, 0x1e50, 0x39f8, 0xbce7, 0xcbb4, 0x2afe, 0xdc45, 0xdb5e, 0x5409, 0x0b3a,
-0xe53c, 0x4358, 0x02ae, 0xa896, 0x0857, 0x1af8, 0xc23a, 0x2352, 0x496b, 0xdfb5,
-0x197e, 0x3ce3, 0xbe54, 0xc506, 0x3012, 0xe677, 0xd704, 0x5217, 0x11ee, 0xe2e7,
-0x3fe4, 0x06fa, 0xa5a3, 0xfdcd, 0x181f, 0xbb44, 0x1747, 0x4a1f, 0xdca9, 0x10d6,
-0x4291, 0xc4a6, 0xbd25, 0x2a87, 0xe605, 0xcbf6, 0x4b38, 0x15fb, 0xe0ad, 0x3f35,
-0x0d36, 0xa652, 0x0068, 0x234a, 0xbde1, 0x11e2, 0x4aeb, 0xdbe0, 0x0a9d, 0x4344,
-0xcb41, 0xbfb5, 0x3005, 0xef5d, 0xcc1b, 0x497b, 0x1516, 0xd825, 0x3b8a, 0x1677,
-0xabc7, 0xfeb9, 0x2dcb, 0xc484, 0x08d9, 0x4f69, 0xe275, 0x041d, 0x4846, 0xd81a,
-0xc055, 0x3307, 0xfcca, 0xce29, 0x4a68, 0x20cb, 0xd8f3, 0x379a, 0x1b24, 0xaf02,
-0xfaf5, 0x36a2, 0xdc0c, 0xf2c4, 0x1be5, 0xefab, 0x3121, 0x54a4, 0xf198, 0xe7b1,
-0x2ba4, 0xe144, 0xad6e, 0x0105, 0xf0a8, 0xe331, 0x4379, 0x5911, 0x2529, 0x2cc9,
-0x279d, 0xcce3, 0xc4aa, 0xd6d0, 0xaebe, 0xee7a, 0x3b83, 0x0e08, 0x0c23, 0x6c6b,
-0x4249, 0xd2d0, 0xee99, 0xf0dc, 0xb1d9, 0xc315, 0x0097, 0x05b2, 0x198e, 0x3a21,
-0x0a87, 0x19af, 0x3001, 0xda73, 0xbf3b, 0xf320, 0xf1e8, 0xce48, 0xfde9, 0x1c97,
-0x092a, 0x1c03, 0x1996, 0x174f, 0x1e06, 0x0784, 0xc7d4, 0xc266, 0xf6c0, 0xcc3e,
-0xdd41, 0x35c9, 0x3070, 0x0e9b, 0x2df6, 0x46cc, 0xf777, 0xdb3b, 0xd86d, 0xb2ad,
-0xdad5, 0xea97, 0xeb13, 0x2dfd, 0x5bf5, 0x1d45, 0x0c80, 0x4c6b, 0xf9d2, 0xb332,
-0xd3b1, 0xcca7, 0xc90a, 0xeeb9, 0x1637, 0x2142, 0x4501, 0x2b65, 0x034c, 0x35ee,
-0x0df0, 0xbcaf, 0xb962, 0xda48, 0xd509, 0xd169, 0x125a, 0x2f7e, 0x3ce9, 0x31e9,
-0x1f9f, 0x25c3, 0xf9ce, 0xc7fa, 0xa4bc, 0xc4e4, 0xde14, 0xd114, 0x1820, 0x4ec1,
-0x3955, 0x1716, 0x2ffb, 0x23e1, 0xd401, 0xc118, 0xaea8, 0xc267, 0xe761, 0xe650,
-0x166b, 0x5317, 0x4508, 0x02ef, 0x256f, 0x2a58, 0xc9bf, 0xbfb1, 0xc690, 0xc4c0,
-0xdb5a, 0xfc3e, 0x1d56, 0x406f, 0x4672, 0x07f9, 0x258b, 0x3563, 0xd0af, 0xad4b,
-0xc62c, 0xd7ec, 0xd118, 0xfacb, 0x32c8, 0x3cf8, 0x3893, 0x1827, 0x2a88, 0x2056,
-0xd2e0, 0xa9a8, 0xbc95, 0xe82d, 0xd209, 0xed42, 0x4049, 0x4bca, 0x27a4, 0x17b5,
-0x33c7, 0x048c, 0xc896, 0xbbc4, 0xb5e8, 0xde55, 0xe670, 0xf26e, 0x319d, 0x5284,
-0x20bb, 0x0a37, 0x3f54, 0x0425, 0xb7b6, 0xbeac, 0xc4a7, 0xd10a, 0xdf90, 0x067a,
-0x32d8, 0x4def, 0x29e9, 0x0de0, 0x33b8, 0x00f9, 0xbb53, 0xb44c, 0xca99, 0xdcb3,
-0xdf0d, 0x140a, 0x4211, 0x47c0, 0x2741, 0x1ffe, 0x3026, 0xf2ee, 0xc44d, 0xb8c2,
-0xcbde, 0xe86b, 0xed77, 0x1b4d, 0x47ee, 0x4766, 0x1ae9, 0x2386, 0x33e9, 0xea57,
-0xc4ae, 0xc182, 0xd3ec, 0xeae1, 0xf2fa, 0x1c99, 0x46ce, 0x4849, 0x16e5, 0x2357,
-0x2d0d, 0xe171, 0xc2b4, 0xc619, 0xdb43, 0xe861, 0xf96a, 0x2580, 0x41a1, 0x3fcc,
-0x14f6, 0x245e, 0x2692, 0xe3d9, 0xc4b2, 0xc084, 0xdcfb, 0xe481, 0xf277, 0x26e8,
-0x4453, 0x3677, 0x1401, 0x2eb5, 0x1c61, 0xda3a, 0xc536, 0xbbc2, 0xd95f, 0xe409,
-0xf088, 0x24e3, 0x4a50, 0x36ef, 0x1343, 0x3794, 0x1bd7, 0xd0b1, 0xbf04, 0xc0c0,
-0xd999, 0xe102, 0xfe57, 0x307b, 0x4c60, 0x3446, 0x110b, 0x34af, 0x1719, 0xd246,
-0xbe92, 0xc661, 0xdf01, 0xde95, 0x04b9, 0x34ae, 0x44b2, 0x2c3e, 0x140f, 0x311d,
-0x09e5, 0xcd57, 0xb673, 0xc4ea, 0xe8e6, 0xdfae, 0x02f2, 0x3c51, 0x460d, 0x2037,
-0x160e, 0x33a4, 0xffd5, 0xd044, 0xbb77, 0xbff6, 0xe547, 0xe2d3, 0x02a5, 0x3927,
-0x483e, 0x1e84, 0x18a8, 0x35a4, 0xf428, 0xc4b4, 0xb810, 0xbe31, 0xdf3f, 0xe3b9,
-0x070a, 0x3a6e, 0x4a01, 0x1d3d, 0x19b7, 0x312f, 0xe9ed, 0xb9d2, 0xb185, 0xc27d,
-0xdf74, 0xeaac, 0x163c, 0x40b2, 0x480f, 0x196b, 0x1a68, 0x2946, 0xe387, 0xbd44,
-0xb687, 0xcdd3, 0xe1c0, 0xe73f, 0x19c6, 0x454e, 0x4471, 0x1517, 0x1f37, 0x2415,
-0xde12, 0xbc28, 0xb193, 0xce92, 0xe199, 0xeb2a, 0x208d, 0x45c9, 0x3dfd, 0x140f,
-0x2554, 0x1b8d, 0xd3e4, 0xb631, 0xaeee, 0xd2a0, 0xe032, 0xeefc, 0x2bad, 0x4d46,
-0x3a27, 0x0f3b, 0x24c9, 0x111e, 0xcdbf, 0xb6b5, 0xb194, 0xd7c9, 0xe60a, 0xf93b,
-0x2f30, 0x4968, 0x3246, 0x1306, 0x2d46, 0x06e7, 0xc785, 0xba49, 0xb9ab, 0xde3a,
-0xe629, 0xff26, 0x3a02, 0x5456, 0x30f0, 0x10ea, 0x3149, 0x0578, 0xc92c, 0xbe07,
-0xc00c, 0xe26f, 0xec57, 0x0aaf, 0x3ec0, 0x560f, 0x2fbd, 0x16da, 0x3543, 0xfe12,
-0xc441, 0xbe1e, 0xce80, 0xec2a, 0xeeda, 0x1761, 0x467e, 0x531c, 0x2945, 0x16f3,
-0x30b3, 0xfa85, 0xc82a, 0xb95b, 0xd0b9, 0xf0bf, 0xecf0, 0x1a23, 0x4acc, 0x48e2,
-0x1c65, 0x1e4d, 0x2902, 0xe8e0, 0xc9c2, 0xbc2f, 0xd2c0, 0xf22e, 0xed1c, 0x1844,
-0x4b01, 0x4776, 0x146e, 0x2125, 0x2832, 0xde1c, 0xc52b, 0xbd52, 0xcf76, 0xec76,
-0xf496, 0x1c9f, 0x4726, 0x432c, 0x116f, 0x25e7, 0x2766, 0xd731, 0xbc99, 0xc162,
-0xd7c6, 0xe12d, 0xf3c2, 0x27ac, 0x489f, 0x3fb7, 0x11f9, 0x23e3, 0x1dd1, 0xd9f9,
-0xbc81, 0xbc41, 0xe051, 0xe6f9, 0xf6af, 0x2df2, 0x4613, 0x2fe6, 0x12b9, 0x303c,
-0x120f, 0xd130, 0xc1da, 0xbc62, 0xdb80, 0xe279, 0xf4be, 0x2c52, 0x4660, 0x275e,
-0x0d1c, 0x3149, 0x075f, 0xc931, 0xbf24, 0xbaf3, 0xd888, 0xe2cc, 0xfb8b, 0x2cb6,
-0x4a52, 0x29ea, 0x0caa, 0x3097, 0xff78, 0xbdf9, 0xb45b, 0xc1cb, 0xdd4e, 0xe310,
-0x068a, 0x24f2, 0x54ac, 0x60d2, 0x1650, 0xf4c6, 0xe059, 0xb014, 0x83b1, 0xbc91,
-0x02f9, 0x0157, 0x4fca, 0x7cb3, 0x41bb, 0x0df7, 0xea9f, 0xace6, 0x957f, 0xc6c1,
-0xb25c, 0xf25c, 0x6d4a, 0x3c23, 0x2274, 0x5314, 0x2754, 0xc59a, 0xd13d, 0xdf25,
-0xc110, 0x097d, 0xfee9, 0xe7e9, 0x4a58, 0x3073, 0xd0cf, 0x0834, 0x3f47, 0xde37,
-0xefad, 0x3de0, 0xef24, 0xe80f, 0x1519, 0xd4ff, 0xbae7, 0x160b, 0x1ed5, 0xf6f3,
-0x4a32, 0x391f, 0xed02, 0x1a95, 0x0194, 0xa798, 0xcdb4, 0x1870, 0xed7d, 0x0805,
-0x5609, 0x1649, 0x0c10, 0x37fb, 0xe698, 0xb602, 0x0ab1, 0x02bc, 0xc982, 0x29a0,
-0x3592, 0xeb4c, 0x26a0, 0x2b39, 0xc51e, 0xe028, 0x25df, 0xdd3d, 0xeb89, 0x3c7d,
-0xf25b, 0xf2a8, 0x40cd, 0xf67a, 0xbd91, 0x18e1, 0x1367, 0xcbf7, 0x1e2b, 0x2469,
-0xd608, 0x16f8, 0x2a0b, 0xc927, 0xe2cc, 0x37b1, 0xf346, 0xe694, 0x382d, 0xf93e,
-0xe10a, 0x2a89, 0xf6d1, 0xba9a, 0x1681, 0x2591, 0xd24e, 0x187c, 0x2fad, 0xd8f6,
-0x0b46, 0x2ae5, 0xc8c2, 0xd38a, 0x2a7a, 0xe7b1, 0xdcb3, 0x3e95, 0x03d8, 0xe5e1,
-0x3718, 0x0451, 0xb6fc, 0x05d7, 0x1636, 0xc589, 0x0c0d, 0x2d31, 0xe2a5, 0x145e,
-0x2ff3, 0xd16c, 0xd748, 0x2961, 0xeee4, 0xd89a, 0x2f77, 0x0413, 0xe432, 0x2a18,
-0x07e4, 0xbf90, 0xffac, 0x1a5c, 0xce43, 0x0eae, 0x3e2a, 0xe525, 0xfcdf, 0x3412,
-0xe19f, 0xc0d0, 0x160c, 0xf679, 0xdaf7, 0x3d0f, 0x184f, 0xe643, 0x3314, 0x0d97,
-0xa9d1, 0xf210, 0x1e09, 0xc374, 0x0591, 0x4995, 0xef24, 0x05bf, 0x3aa6, 0xdaf6,
-0xc1a1, 0x198b, 0xe5e1, 0xce1f, 0x40dc, 0x134c, 0xddc5, 0x3b68, 0x1d73, 0xb2c0,
-0xf385, 0x2228, 0xc6a9, 0xff0d, 0x4056, 0xea16, 0x071a, 0x3ca3, 0xd74b, 0xbcb1,
-0x210f, 0xf2c1, 0xcb2c, 0x414d, 0x1f07, 0xd958, 0x2f24, 0x195a, 0xa747, 0xe84d,
-0x2605, 0xc501, 0xff0e, 0x4e0a, 0xea48, 0x02a4, 0x46c5, 0xd723, 0xafda, 0x23af,
-0xf6a4, 0xbc7c, 0x3c45, 0x26f8, 0xdc74, 0x367d, 0x2543, 0xb0bd, 0xed3e, 0x27e5,
-0xc333, 0xf8e2, 0x4d51, 0xeb5f, 0xfefc, 0x4865, 0xe34b, 0xb937, 0x2748, 0x0266,
-0xc562, 0x3a6b, 0x25b1, 0xd774, 0x2daa, 0x2313, 0xb311, 0xef4a, 0x32e8, 0xcf60,
-0xf8b2, 0x51fb, 0xee07, 0xf368, 0x44ab, 0xe548, 0xb2da, 0x24f2, 0x07b3, 0xc446,
-0x3bc4, 0x2db3, 0xd779, 0x2ee4, 0x281e, 0xace1, 0xe4c5, 0x335a, 0xceab, 0xf17b,
-0x55c7, 0xf4d4, 0xf24d, 0x4603, 0xeb3d, 0xaf65, 0x1bbf, 0x08f3, 0xbf31, 0x300f,
-0x30d1, 0xd9cf, 0x29ba, 0x2ead, 0xb5b6, 0xdd53, 0x2dff, 0xcf0d, 0xe2d2, 0x4b14,
-0xf7cf, 0xf104, 0x48fe, 0xf5f9, 0xb102, 0x175c, 0x0bd9, 0xbcb2, 0x27b4, 0x336a,
-0xd7be, 0x2088, 0x3408, 0xbf37, 0xdc20, 0x3264, 0xdb9f, 0xe60e, 0x5013, 0xffb1,
-0xe856, 0x4281, 0xff01, 0xb10f, 0x1094, 0x176a, 0xc863, 0x243b, 0x390b, 0xdf6d,
-0x1d95, 0x3900, 0xc65f, 0xd25c, 0x2c3a, 0xe187, 0xdbeb, 0x465f, 0x0986, 0xeb79,
-0x4044, 0x0711, 0xb0da, 0x0496, 0x1513, 0xc287, 0x187b, 0x3c78, 0xe032, 0x1521,
-0x3c5f, 0xccc3, 0xcce1, 0x2b96, 0xe4ca, 0xd2ba, 0x430a, 0x0aa2, 0xdffc, 0x3ad9,
-0x0be5, 0xaea0, 0x03b6, 0x1ba6, 0xbbed, 0x0db5, 0x4113, 0xdc05, 0x05bb, 0x3a65,
-0xcc55, 0xc14b, 0x25ec, 0xe783, 0xd1d2, 0x4965, 0x1616, 0xdbb4, 0x3263, 0x0a8b,
-0xa569, 0xf7cf, 0x1f57, 0xc4d2, 0x1559, 0x517f, 0xea47, 0x0848, 0x3a1f, 0xc9f1,
-0xbb1e, 0x266f, 0xea60, 0xcd1c, 0x4d59, 0x23a6, 0xe328, 0x3b46, 0x19d2, 0xabe2,
-0xf47d, 0x1e1a, 0xbcd3, 0x09ed, 0x4fb3, 0xe964, 0x0dbc, 0x485b, 0xd3bb, 0xbbbe,
-0x2722, 0xffc5, 0xce39, 0x0d09, 0xfe2c, 0x112d, 0x596c, 0x16f5, 0xd170, 0x12a7,
-0x07ab, 0xa521, 0xd945, 0x0290, 0xcf7b, 0x0c60, 0x5af6, 0x3c64, 0x1c78, 0x2c17,
-0xf082, 0xb62e, 0xcf0c, 0xac7d, 0xba75, 0x27ac, 0x23af, 0xf129, 0x473d, 0x6f3b,
-0xefd4, 0xd0fc, 0xfcb5, 0xc5fa, 0xa532, 0xe2aa, 0x08ff, 0x0704, 0x304a, 0x21e6,
-0x0f85, 0x38c1, 0x010f, 0xbcdf, 0xd894, 0xf8ab, 0xd8c7, 0xe36a, 0x1b7a, 0x178e,
-0x1a72, 0x1741, 0x157f, 0x1dd4, 0x0dfe, 0xe47e, 0xbdd3, 0xf139, 0xe9ae, 0xc861,
-0x198e, 0x432e, 0x1c93, 0x1246, 0x4ca3, 0x23d4, 0xd5a3, 0xdda1, 0xc097, 0xcd1a,
-0xeddd, 0xed1a, 0x1738, 0x5658, 0x41b1, 0xfba0, 0x3319, 0x2a1d, 0xc048, 0xc0cf,
-0xd583, 0xd4c9, 0xdb7a, 0x070a, 0x2588, 0x3798, 0x3aa9, 0x0add, 0x25af, 0x2337,
-0xd4c2, 0xb504, 0xca8a, 0xe4dd, 0xd039, 0xf1df, 0x2bb9, 0x3c1d, 0x3426, 0x22ac,
-0x331f, 0x0f10, 0xdc7d, 0xbbe1, 0xb47c, 0xdb63, 0xd984, 0xfcbd, 0x450f, 0x5431,
-0x271a, 0x210b, 0x3c62, 0xf43d, 0xc565, 0xc201, 0xc114, 0xe4f6, 0xee9b, 0x085b,
-0x3cf5, 0x5653, 0x1e82, 0x0d52, 0x38a8, 0xf608, 0xc456, 0xce8b, 0xcfd1, 0xda08,
-0xf0f6, 0x16f4, 0x3014, 0x4610, 0x1a46, 0x0c35, 0x36d1, 0xfb60, 0xbc9c, 0xbcea,
-0xdb0c, 0xda74, 0xdb6c, 0x17ce, 0x3715, 0x33b3, 0x13c8, 0x1e7d, 0x290c, 0xe55b,
-0xb756, 0xb135, 0xdad6, 0xde70, 0xd336, 0x1782, 0x43a0, 0x29e5, 0x03f8, 0x2c8f,
-0x2768, 0xd396, 0xc0e1, 0xbc23, 0xccce, 0xdf32, 0xe829, 0x16bf, 0x4610, 0x3567,
-0x012e, 0x312c, 0x3059, 0xcf4c, 0xbc48, 0xcf7d, 0xdb0c, 0xd4f7, 0xefe3, 0x2327,
-0x3f5e, 0x34bf, 0x11d9, 0x3885, 0x2a09, 0xd700, 0xbd59, 0xc753, 0xde26, 0xd765,
-0xf612, 0x31cc, 0x45d3, 0x2d56, 0x17c3, 0x3e94, 0x16b7, 0xce82, 0xc389, 0xc8ab,
-0xdd9d, 0xdd82, 0xfe36, 0x3550, 0x4d5b, 0x2a45, 0x1384, 0x3ff2, 0x0ef3, 0xc81d,
-0xbe61, 0xcce9, 0xe4aa, 0xe0ab, 0x0699, 0x385e, 0x486b, 0x2294, 0x15f0, 0x3d85,
-0x01db, 0xc686, 0xc116, 0xcff5, 0xe34d, 0xe14b, 0x10c9, 0x3f07, 0x466b, 0x1f0d,
-0x1d05, 0x3ab5, 0xf8ef, 0xc8ce, 0xc05e, 0xd357, 0xe7d4, 0xe29f, 0x13df, 0x471a,
-0x4a47, 0x1c4c, 0x297f, 0x3e3f, 0xed74, 0xc6f8, 0xbfdc, 0xccde, 0xe3d5, 0xeaa0,
-0x19ee, 0x4b1b, 0x4d49, 0x1865, 0x2976, 0x37a0, 0xe1a2, 0xb9e8, 0xba35, 0xd299,
-0xde2b, 0xecfc, 0x27c6, 0x4ae2, 0x4564, 0x19a4, 0x28b5, 0x2426, 0xd885, 0xbc0a,
-0xb90e, 0xd777, 0xe284, 0xf34a, 0x2d9a, 0x4813, 0x38b9, 0x14ee, 0x2c67, 0x1894,
-0xd324, 0xbc7e, 0xb3bc, 0xda55, 0xe3e2, 0xef0a, 0x2fd7, 0x4da0, 0x2e6a, 0x0ee2,
-0x326e, 0x0fc1, 0xcb23, 0xbee7, 0xb82c, 0xdaac, 0xe70d, 0xf676, 0x2c96, 0x4efe,
-0x3180, 0x0f59, 0x3430, 0x0900, 0xc464, 0xbdf3, 0xbfd4, 0xdc18, 0xe54f, 0x02ac,
-0x346a, 0x4ca2, 0x2bdb, 0x0ba0, 0x2ca5, 0x00e4, 0xc0c2, 0xb4ae, 0xbea2, 0xdd3b,
-0xe1b5, 0x05e5, 0x36cd, 0x455d, 0x228c, 0x0f39, 0x2721, 0xf06a, 0xbe3c, 0xb625,
-0xc315, 0xe0db, 0xe130, 0x0824, 0x3af9, 0x4450, 0x1a04, 0x1254, 0x2a20, 0xeab7,
-0xbec0, 0xb857, 0xc3f1, 0xdf5a, 0xe831, 0x122e, 0x3daa, 0x44fa, 0x18f6, 0x1739,
-0x28bb, 0xe41d, 0xbbf3, 0xb89c, 0xcff6, 0xe5c1, 0xea00, 0x1c60, 0x45d5, 0x43ef,
-0x1c06, 0x2434, 0x292a, 0xe39e, 0xc2cb, 0xbd71, 0xd5c4, 0xe95c, 0xf5d3, 0x2a36,
-0x4b75, 0x403d, 0x1c75, 0x32bf, 0x27ef, 0xdda2, 0xcb76, 0xc7c5, 0xdb1a, 0xe84b,
-0xf612, 0x2b74, 0x5112, 0x4137, 0x18a7, 0x3889, 0x2791, 0xd8ed, 0xc90a, 0xc6c8,
-0xd83c, 0xe5cf, 0x01d1, 0x32e1, 0x4e08, 0x3e77, 0x1bcc, 0x39cc, 0x1bcb, 0xcf7c,
-0xbfad, 0xc693, 0xe1af, 0xe44a, 0x0379, 0x3b80, 0x5122, 0x34da, 0x12cd, 0x2ff7,
-0x0b3f, 0xcb7c, 0xb95e, 0xc0f4, 0xe555, 0xe1ce, 0x01a1, 0x3cc9, 0x475e, 0x2196,
-0x156a, 0x33d5, 0xf97d, 0xc4c1, 0xb9ed, 0xbd90, 0xe1db, 0xe24b, 0x021d, 0x3cfa,
-0x4dca, 0x1ea3, 0x12f7, 0x33e9, 0xf159, 0xbf15, 0xb984, 0xbdf4, 0xd9dc, 0xe483,
-0x0d28, 0x3bb5, 0x4aee, 0x1fcf, 0x1792, 0x2e75, 0xe773, 0xb55d, 0xaeed, 0xc525,
-0xdc07, 0xe07a, 0x162d, 0x403a, 0x41df, 0x18e6, 0x1816, 0x22ca, 0xe0d7, 0xba3f,
-0xab7d, 0xc6d9, 0xe296, 0xe464, 0x1a6b, 0x45ec, 0x3cb4, 0x1203, 0x21d7, 0x1e19,
-0xd553, 0xc042, 0xb44a, 0xca17, 0xe29f, 0xe893, 0x1a35, 0x457e, 0x3ca4, 0x0eee,
-0x274f, 0x1dc0, 0xd010, 0xbe2a, 0xb43a, 0xca4c, 0xe2e4, 0xf448, 0x246d, 0x4965,
-0x3fdb, 0x10f7, 0x25b8, 0x162e, 0xcca7, 0xb882, 0xb947, 0xd7a5, 0xe438, 0xfea1,
-0x33b7, 0x4cfe, 0x3b14, 0x1175, 0x24b7, 0x0bf7, 0xcecd, 0xbc06, 0xbdfc, 0xe81e,
-0xee24, 0x01b0, 0x3af8, 0x476e, 0x28b0, 0x20d9, 0x3412, 0xf8f1, 0xc8c9, 0xbcf1,
-0xbe75, 0xed66, 0xf061, 0x0477, 0x2e04, 0x4a13, 0x58d9, 0x3473, 0x0a86, 0xde23,
-0xc927, 0xa391, 0xa85a, 0xfd01, 0x01c0, 0x26a1, 0x8016, 0x6b60, 0x1f2e, 0x05f0,
-0xdab1, 0x948b, 0xb8c2, 0xc47d, 0xcb07, 0x3e6c, 0x61b3, 0x38d1, 0x421e, 0x423b,
-0xe147, 0xbac6, 0xe0e9, 0xbe22, 0xd9dd, 0x0b3a, 0x03de, 0x31f4, 0x40dc, 0xf8e0,
-0xf398, 0x2cdd, 0xec3a, 0xc582, 0x25ea, 0x1c58, 0xd8cd, 0x0700, 0x13d5, 0xbffb,
-0xdfbf, 0x2eeb, 0xf5a6, 0x0a90, 0x5506, 0x0dfc, 0xf5d4, 0x194f, 0xd0b1, 0xa469,
-0xf944, 0x0659, 0xe225, 0x3e8d, 0x4455, 0xf804, 0x285d, 0x16e8, 0xac54, 0xcbe6,
-0x0dc1, 0xcfa2, 0xef3a, 0x51ba, 0x0cea, 0x02d9, 0x4169, 0xec8e, 0xb42c, 0x04b3,
-0xfdcb, 0xc5c1, 0x233b, 0x2fa0, 0xe530, 0x27ec, 0x2937, 0xc096, 0xdeaa, 0x2435,
-0xe010, 0xe6f7, 0x3e0a, 0xfd91, 0xeb2e, 0x333b, 0xf30c, 0xb2be, 0x1250, 0x1fd9,
-0xc7fa, 0x1877, 0x3b5d, 0xdbdb, 0x0644, 0x23bb, 0xbdc0, 0xcc54, 0x2f0c, 0xf1f3,
-0xe57b, 0x48e5, 0x082c, 0xe598, 0x360e, 0xf80f, 0xa876, 0x0659, 0x1b42, 0xc57b,
-0x1fb9, 0x48cb, 0xe657, 0x1591, 0x3682, 0xcb26, 0xccd4, 0x2692, 0xe8fa, 0xda38,
-0x445f, 0x1220, 0xf0e0, 0x3d8f, 0x09d0, 0xb6bc, 0x00e1, 0x260a, 0xd188, 0x0576,
-0x3935, 0xef31, 0x1179, 0x33e9, 0xd401, 0xcde0, 0x2d56, 0xfa21, 0xdbb0, 0x4a3c,
-0x1c17, 0xdc92, 0x334e, 0x1ceb, 0xb17d, 0xebbf, 0x27e0, 0xd919, 0x0f7e, 0x4a4b,
-0xf20c, 0x107b, 0x3a20, 0xcab0, 0xba0a, 0x24cb, 0xf1fa, 0xcaf2, 0x3f6a, 0x2005,
-0xe495, 0x30ba, 0x16ef, 0xb7a7, 0xec01, 0x1401, 0xc9b7, 0x05b6, 0x393b, 0xe12d,
-0x07bf, 0x44cb, 0xdee8, 0xbd85, 0x23f1, 0xfc20, 0xc5f2, 0x2bd6, 0x194b, 0xdfc0,
-0x26e3, 0x160b, 0xba3e, 0xf25d, 0x2457, 0xcdc4, 0x004b, 0x4634, 0xe4dc, 0xf4a7,
-0x3d04, 0xdcc3, 0xb397, 0x1fb0, 0x0021, 0xcbc7, 0x37a0, 0x223d, 0xdd2e, 0x2e4a,
-0x1e22, 0xae9d, 0xea89, 0x28db, 0xc94f, 0xf4c9, 0x4a0c, 0xf565, 0xfefa, 0x4525,
-0xee89, 0xbfb1, 0x1b8b, 0xfa5c, 0xc436, 0x2f51, 0x24ca, 0xdfcd, 0x2cf4, 0x2a31,
-0xbd55, 0xe94e, 0x2b96, 0xd147, 0xee2f, 0x4235, 0xf2bf, 0xf601, 0x3b75, 0xe821,
-0xb876, 0x1f6c, 0x056a, 0xc597, 0x378b, 0x2e60, 0xd377, 0x1e9d, 0x283c, 0xb892,
-0xdee1, 0x2781, 0xd1f0, 0xf4ba, 0x554c, 0x0123, 0xf9be, 0x420b, 0xea52, 0xaa76,
-0x121d, 0x04f0, 0xbdca, 0x333f, 0x4315, 0xe753, 0x27d8, 0x325a, 0xb873, 0xd272,
-0x2388, 0xcf65, 0xe913, 0x57fe, 0x07f4, 0xf542, 0x4773, 0xf6c7, 0xab18, 0x11a2,
-0x0c42, 0xb926, 0x2816, 0x3c96, 0xde7c, 0x28fb, 0x3ab1, 0xb843, 0xd1f6, 0x2e08,
-0xd30e, 0xdd67, 0x552d, 0x04b1, 0xe6f1, 0x4408, 0xfac7, 0xa436, 0x0956, 0x1138,
-0xb9e0, 0x267a, 0x42e3, 0xd676, 0x199d, 0x3443, 0xb086, 0xc200, 0x28e5, 0xda7a,
-0xd827, 0x53d9, 0x0bab, 0xe3c1, 0x40a6, 0xfc98, 0xa29e, 0x018f, 0x1105, 0xb6e7,
-0x1b43, 0x498c, 0xdd00, 0x1541, 0x4138, 0xc0de, 0xbf2e, 0x283d, 0xe09c, 0xce50,
-0x4aa8, 0x1053, 0xdfdb, 0x3f0a, 0x0676, 0xa0c4, 0xfe21, 0x1b86, 0xb753, 0x10a7,
-0x4958, 0xd934, 0x0821, 0x3f0a, 0xc34f, 0xba57, 0x2b9e, 0xe817, 0xc7b8, 0x46a9,
-0x0faa, 0xd39d, 0x38e6, 0x0b67, 0x9f2e, 0xfa87, 0x2298, 0xbafd, 0x0a31, 0x466b,
-0xd41d, 0xfd51, 0x3a2b, 0xc101, 0xb40d, 0x2b20, 0xef1f, 0xc9c0, 0x46b9, 0x10a8,
-0xce9c, 0x3371, 0x097d, 0x9c55, 0xf5c4, 0x3090, 0xd2df, 0xecd4, 0x147e, 0xe806,
-0x2e2d, 0x4ebd, 0xe525, 0xe179, 0x26a7, 0xd61d, 0xaa44, 0x0053, 0xe8dc, 0xe136,
-0x46b6, 0x57fc, 0x24b5, 0x2da9, 0x235d, 0xcd31, 0xca81, 0xd1c7, 0xaf26, 0xfdb0,
-0x3bad, 0x09ac, 0x1da0, 0x74cf, 0x3a9c, 0xd9e6, 0xf662, 0xf1b3, 0xb74e, 0xc78b,
-0x079d, 0x1303, 0x25f7, 0x3f88, 0x14f4, 0x2459, 0x2c9b, 0xdd69, 0xc8da, 0xfb0c,
-0xfc56, 0xd94a, 0x0b6d, 0x29c0, 0x150a, 0x22e5, 0x1d92, 0x18ef, 0x1cfc, 0x0c23,
-0xcdc3, 0xcd7b, 0x0116, 0xd225, 0xea05, 0x3ecf, 0x321c, 0x114b, 0x3429, 0x4818,
-0xf80f, 0xe0f6, 0xd86d, 0xb88f, 0xe34c, 0xec85, 0xf335, 0x37f0, 0x5dfb, 0x1c42,
-0x11db, 0x4f23, 0xfc26, 0xba44, 0xd5aa, 0xd324, 0xd1fd, 0xf17c, 0x1856, 0x276a,
-0x4692, 0x286a, 0x0ba3, 0x3d7b, 0x1150, 0xc1ac, 0xbdf0, 0xe136, 0xd542, 0xcf26,
-0x1384, 0x2faf, 0x3870, 0x2e2c, 0x2318, 0x28d4, 0xfdee, 0xcb16, 0xa730, 0xc88d,
-0xdb00, 0xceb6, 0x1995, 0x4d9d, 0x384a, 0x1a5c, 0x3253, 0x2473, 0xd8f1, 0xc53c,
-0xafa7, 0xc440, 0xe9ed, 0xe807, 0x176e, 0x51f8, 0x4372, 0x074b, 0x2912, 0x2b6d,
-0xcf1e, 0xc37a, 0xc518, 0xc3a3, 0xdc9c, 0xfa3e, 0x1a98, 0x40fa, 0x4783, 0x0983,
-0x2539, 0x3545, 0xd15a, 0xad3e, 0xc7ca, 0xd8f8, 0xd06d, 0xf96a, 0x3340, 0x3d0f,
-0x375f, 0x19a1, 0x2cbe, 0x2480, 0xd619, 0xaa0f, 0xbfde, 0xe9c8, 0xd157, 0xf05e,
-0x42af, 0x4a8c, 0x2ada, 0x1e55, 0x372a, 0x09e1, 0xcd35, 0xbbbe, 0xb8fb, 0xe193,
-0xe480, 0xf329, 0x3476, 0x51aa, 0x233d, 0x1102, 0x44ce, 0x08c4, 0xbbca, 0xc158,
-0xc692, 0xd1e1, 0xdde2, 0x0656, 0x33cd, 0x4f74, 0x2ddc, 0x0f4d, 0x394e, 0x09e6,
-0xbe5c, 0xb5ad, 0xcc4d, 0xdc27, 0xdab2, 0x1043, 0x3ea4, 0x479b, 0x2b41, 0x1d61,
-0x308b, 0xf8bb, 0xc464, 0xb735, 0xcd64, 0xe75e, 0xe437, 0x161f, 0x4870, 0x48ad,
-0x1c9b, 0x1ea2, 0x33d1, 0xf0d7, 0xc828, 0xc0cf, 0xd2aa, 0xe99c, 0xeb83, 0x1a23,
-0x47fe, 0x4a7b, 0x1905, 0x1e38, 0x324a, 0xe958, 0xc1e9, 0xc325, 0xd7e4, 0xe635,
-0xf2dc, 0x2267, 0x3faa, 0x415f, 0x1a59, 0x202f, 0x2852, 0xe889, 0xc4bd, 0xbe6c,
-0xdab6, 0xe56a, 0xef10, 0x26eb, 0x4556, 0x3a6e, 0x180a, 0x2a09, 0x1fb9, 0xde8b,
-0xc5cf, 0xb9e8, 0xd7a7, 0xe7b9, 0xedd9, 0x2300, 0x49df, 0x37d1, 0x12a8, 0x2f9a,
-0x18aa, 0xce1b, 0xbdb0, 0xbc6b, 0xd29e, 0xdeee, 0xf71a, 0x2781, 0x45f4, 0x339d,
-0x0ccf, 0x2b8f, 0x12d6, 0xc8e8, 0xb6b6, 0xbda1, 0xd3af, 0xd912, 0xfe42, 0x2d6d,
-0x3ef8, 0x304b, 0x1689, 0x29cf, 0x067c, 0xcba1, 0xb57d, 0xbede, 0xdf90, 0xdc36,
-0xfffb, 0x3465, 0x3c40, 0x2128, 0x1a44, 0x31e1, 0xfd23, 0xcc9c, 0xbac3, 0xbc48,
-0xdd17, 0xde23, 0xfd31, 0x3137, 0x4362, 0x1eee, 0x18fc, 0x32b8, 0xf20e, 0xc5cc,
-0xbb44, 0xbdcc, 0xd9bd, 0xe2e3, 0x076b, 0x353c, 0x4892, 0x1e7b, 0x18f6, 0x30cf,
-0xea76, 0xbae7, 0xb387, 0xc4fa, 0xdcc0, 0xe7b8, 0x15fe, 0x3d5b, 0x45ed, 0x199f,
-0x192d, 0x2670, 0xe39c, 0xbd23, 0xb49a, 0xce79, 0xe000, 0xe7b3, 0x1c0b, 0x42fb,
-0x4231, 0x1500, 0x214f, 0x24b7, 0xddd0, 0xbdaf, 0xb443, 0xd1d6, 0xe488, 0xf035,
-0x248c, 0x481a, 0x412e, 0x17e3, 0x2a09, 0x1e55, 0xd730, 0xbb6d, 0xb458, 0xd6fe,
-0xe4f4, 0xf65d, 0x30dd, 0x50e1, 0x3ee0, 0x15ff, 0x2a77, 0x133f, 0xd208, 0xbb41,
-0xb5d0, 0xdc9b, 0xea0f, 0xfe2e, 0x33e8, 0x4ec6, 0x3729, 0x17b0, 0x327e, 0x0ae7,
-0xcbb1, 0xbd40, 0xbbb0, 0xe021, 0xe92f, 0x0274, 0x3a54, 0x53fa, 0x3201, 0x1417,
-0x340a, 0x073d, 0xcaf8, 0xbd21, 0xbddc, 0xdfe9, 0xebda, 0x0cee, 0x3df0, 0x5410,
-0x3025, 0x16c7, 0x32e0, 0xfb90, 0xc1f6, 0xbac8, 0xcb01, 0xe852, 0xeb00, 0x14bb,
-0x4362, 0x4e09, 0x267e, 0x175e, 0x2ea6, 0xf673, 0xc679, 0xb7ca, 0xce42, 0xef38,
-0xea88, 0x19da, 0x4c19, 0x4976, 0x1f9b, 0x2155, 0x2984, 0xe747, 0xc939, 0xbc60,
-0xced0, 0xf05b, 0xef4a, 0x1a1b, 0x4d06, 0x49db, 0x1707, 0x21a4, 0x261f, 0xdb58,
-0xc42f, 0xbd07, 0xcd03, 0xeb57, 0xf6f1, 0x1fe4, 0x4885, 0x45cb, 0x1391, 0x2121,
-0x232c, 0xd7ec, 0xbd29, 0xbf59, 0xd799, 0xe575, 0xf6b7, 0x28c6, 0x4774, 0x3e39,
-0x1137, 0x1ef7, 0x1744, 0xd610, 0xbc35, 0xb9e4, 0xdd70, 0xe860, 0xf41e, 0x2929,
-0x4423, 0x2e1c, 0x110a, 0x2d77, 0x0e41, 0xced2, 0xc1cd, 0xbb1d, 0xd9b8, 0xe41e,
-0xf4ed, 0x2b8f, 0x4959, 0x2b92, 0x0f36, 0x32ac, 0x0962, 0xc983, 0xc063, 0xbadd,
-0xd65d, 0xe557, 0xfe42, 0x2c4a, 0x49b0, 0x2cc4, 0x11af, 0x335e, 0x0099, 0xbfb6,
-0xb950, 0xc282, 0xda13, 0xe2c3, 0x0c6b, 0x2301, 0x3d0d, 0x5b32, 0x2bf1, 0xf816,
-0xd811, 0xc694, 0x94e5, 0xa76b, 0x02b3, 0xf90f, 0x23f0, 0x863b, 0x6a8b, 0x1164,
-0xf826, 0xd412, 0x8d7c, 0xade7, 0xbb44, 0xce06, 0x446e, 0x60cd, 0x37d3, 0x464b,
-0x4603, 0xdb1a, 0xadc9, 0xd748, 0xbb79, 0xd2d1, 0x0130, 0x0928, 0x3b0a, 0x4390,
-0x0002, 0xef18, 0x25c7, 0xf662, 0xbcac, 0x1201, 0x1f14, 0xda32, 0xff28, 0x1fbe,
-0xd1ed, 0xd6db, 0x389e, 0x0dbf, 0xf3fb, 0x488e, 0x1c7e, 0xe70e, 0x1374, 0xed9e,
-0xa6a3, 0xedff, 0x24fa, 0xe3d7, 0x2454, 0x55ff, 0xfbf6, 0x19ad, 0x27e2, 0xbe48,
-0xc206, 0x1296, 0xe45b, 0xdd35, 0x4db6, 0x1c33, 0xef46, 0x4348, 0x0b24, 0xb5eb,
-0xf732, 0x126a, 0xcd2b, 0x063c, 0x37c5, 0xec01, 0x18d9, 0x3cc8, 0xd616, 0xd2bc,
-0x273a, 0xf84b, 0xd381, 0x30e7, 0x1385, 0xdff9, 0x30f4, 0x18b0, 0xc10e, 0x0696,
-0x364d, 0xd762, 0xfbf8, 0x3d8c, 0xe397, 0xf63d, 0x3932, 0xe0e0, 0xc7fb, 0x31c6,
-0x0e47, 0xd472, 0x33f1, 0x19cb, 0xd9b6, 0x297e, 0x174d, 0xb770, 0xf385, 0x2b80,
-0xd844, 0x020b, 0x44ae, 0xecdc, 0xffc6, 0x3c84, 0xe59b, 0xc239, 0x1b9c, 0x03d8,
-0xcdfc, 0x284d, 0x2050, 0xe856, 0x29ba, 0x1da6, 0xc79c, 0xf13e, 0x2a8b, 0xdb89,
-0xe7cf, 0x315a, 0xf321, 0xf5f9, 0x332c, 0xf230, 0xc508, 0x1566, 0x093d, 0xce9a,
-0x23e7, 0x1dac, 0xd1bc, 0x1aa1, 0x2c3b, 0xbf9a, 0xd5cb, 0x286f, 0xe374, 0xeccb,
-0x3bb8, 0xfa4b, 0xf5e8, 0x2f2d, 0xe9fe, 0xbb23, 0x0ce2, 0xff3a, 0xc469, 0x2484,
-0x2c01, 0xe186, 0x1b3d, 0x26db, 0xc966, 0xd43c, 0x0cf6, 0xd3cc, 0xeaf1, 0x349d,
-0xf49e, 0xfa1b, 0x3da3, 0xf2ae, 0xb5a2, 0x09f1, 0x0303, 0xbee6, 0x1c15, 0x2f77,
-0xe137, 0x187e, 0x2a96, 0xc3d0, 0xd414, 0x1e88, 0xd685, 0xe774, 0x4a59, 0xfa19,
-0xe6e2, 0x3f71, 0xf365, 0xa657, 0x0aac, 0x0b27, 0xbbf9, 0x22a4, 0x3896, 0xdde2,
-0x1ea6, 0x2ddb, 0xb6a3, 0xcf13, 0x234d, 0xd209, 0xdfcd, 0x4de4, 0x0530, 0xf235,
-0x458e, 0xfe1c, 0xaf9c, 0x04ff, 0x0ba8, 0xc04a, 0x1dfe, 0x3a8f, 0xe44e, 0x1ebd,
-0x3786, 0xc838, 0xd340, 0x2d49, 0xe462, 0xdc75, 0x4606, 0x05e5, 0xe8d6, 0x3e07,
-0x0367, 0xb349, 0x0d09, 0x1be3, 0xc56a, 0x2148, 0x4004, 0xd8d7, 0x1595, 0x3a7d,
-0xc56d, 0xd126, 0x3261, 0xe7bb, 0xe124, 0x5308, 0x0eb8, 0xeb26, 0x437a, 0x042c,
-0xaf26, 0x0eb2, 0x218d, 0xc6ad, 0x22c2, 0x4ab9, 0xe2d2, 0x1874, 0x40cd, 0xca8d,
-0xc838, 0x2e68, 0xedb9, 0xd7fa, 0x4c7a, 0x1526, 0xe7cb, 0x4150, 0x0c9e, 0xae99,
-0x0430, 0x20bb, 0xc1b5, 0x1187, 0x47d4, 0xe4da, 0x1440, 0x42ec, 0xcdff, 0xc6df,
-0x2c13, 0xec08, 0xd2d5, 0x46ed, 0x0ef1, 0xdd36, 0x3d9e, 0x0f6f, 0xadf9, 0x0331,
-0x2434, 0xc516, 0x0f43, 0x4485, 0xde32, 0x0700, 0x3d61, 0xce91, 0xbeff, 0x2926,
-0xf4fa, 0xd134, 0x41a9, 0x1664, 0xdc49, 0x34e2, 0x1333, 0xace3, 0xf361, 0x1f70,
-0xc693, 0x0699, 0x47e9, 0xe934, 0x0537, 0x4024, 0xd7ae, 0xba09, 0x1da8, 0xf1cd,
-0xcbb4, 0x3981, 0x188e, 0xddeb, 0x326b, 0x1892, 0xb095, 0xf130, 0x20bc, 0xc29d,
-0xf9a7, 0x3f9b, 0xe3d4, 0xfb7a, 0x3e64, 0xdf3d, 0xbe59, 0x2395, 0xf6d6, 0xc4b9,
-0x3386, 0x1936, 0xd767, 0x2b7a, 0x1dd1, 0xb547, 0xeefe, 0x2814, 0xcaa5, 0xf817,
-0x487c, 0xeb89, 0xf26b, 0x397c, 0xdf7f, 0xb39b, 0x1c04, 0xfe68, 0xc54d, 0x349f,
-0x2a68, 0xdbdd, 0x22d6, 0x1ddd, 0xb0a0, 0xe0fa, 0x21cc, 0xc993, 0xf898, 0x52ec,
-0xf689, 0xf70a, 0x426a, 0xe741, 0xaf61, 0x151d, 0xf921, 0xc0cc, 0x3886, 0x3002,
-0xdf54, 0x2dc5, 0x25fe, 0xb022, 0xe019, 0x2b01, 0xdc46, 0xdf34, 0x113b, 0xf3ef,
-0x2b9e, 0x5380, 0xf6a9, 0xdedb, 0x2143, 0xe2d9, 0xa1ed, 0xf09b, 0xf0dc, 0xdb67,
-0x3407, 0x5e55, 0x32ca, 0x27e1, 0x25c5, 0xd709, 0xc36a, 0xcfc9, 0xa7f8, 0xea51,
-0x3bd7, 0x0e16, 0x0801, 0x6978, 0x4f5b, 0xdcee, 0xefc1, 0xfe47, 0xbe36, 0xbc03,
-0xf6fb, 0x0a54, 0x1b49, 0x3bd0, 0x15ec, 0x2382, 0x3cb2, 0xeb19, 0xc5aa, 0xedb7,
-0xf957, 0xd7a6, 0xf768, 0x22e7, 0x17a3, 0x2061, 0x1ba7, 0x1fd9, 0x23d8, 0x0c01,
-0xd667, 0xc4b5, 0xfb1e, 0xd994, 0xd7e9, 0x3398, 0x3e92, 0x166b, 0x27af, 0x4ec2,
-0x0515, 0xd7d3, 0xde1a, 0xb994, 0xdcbe, 0xf079, 0xeced, 0x2d31, 0x5f61, 0x253a,
-0x040a, 0x4aa6, 0x0dcf, 0xb7f1, 0xcf3e, 0xd1b1, 0xcf61, 0xe63f, 0x105c, 0x26cc,
-0x431a, 0x31ef, 0x089d, 0x3279, 0x1505, 0xc9c8, 0xbc77, 0xd253, 0xdbe3, 0xd185,
-0x028c, 0x2ef7, 0x3d5b, 0x2ff3, 0x2436, 0x2ecc, 0xffae, 0xd27d, 0xae72, 0xb7bb,
-0xda8b, 0xd2ea, 0x0b5f, 0x4d03, 0x43e6, 0x19f3, 0x2a63, 0x2e3d, 0xdc83, 0xc2d3,
-0xb8a6, 0xbf1e, 0xe681, 0xe9fe, 0x0c02, 0x47ed, 0x4b9b, 0x0b96, 0x1c09, 0x3193,
-0xdad3, 0xc2e7, 0xcba3, 0xc7a2, 0xd979, 0xf765, 0x1768, 0x34eb, 0x4272, 0x0e6d,
-0x1cba, 0x35bf, 0xe2f7, 0xb4ec, 0xc2dc, 0xdbc9, 0xd4b0, 0xeaf5, 0x2a04, 0x3d45,
-0x3135, 0x163c, 0x29bf, 0x1de9, 0xd862, 0xb512, 0xbc25, 0xe60f, 0xdb2d, 0xe4e1,
-0x2e4c, 0x46ed, 0x2280, 0x0c95, 0x3390, 0x0dba, 0xc912, 0xc227, 0xbe99, 0xd9c1,
-0xe290, 0xed33, 0x2239, 0x44f4, 0x1ed4, 0x0166, 0x3720, 0x122c, 0xc1e5, 0xbe0b,
-0xcc00, 0xd5f1, 0xd17f, 0xf3b3, 0x23a2, 0x3db4, 0x2624, 0x0cc4, 0x33e1, 0x1023,
-0xc9ae, 0xb631, 0xc8cd, 0xdd8a, 0xceea, 0xfaf7, 0x3621, 0x3ded, 0x1ca5, 0x1b0d,
-0x3ba6, 0x0216, 0xce92, 0xc394, 0xc90e, 0xdd1a, 0xd9c7, 0x0438, 0x3a3b, 0x43f5,
-0x193b, 0x1b93, 0x427f, 0xfe8c, 0xc66d, 0xc591, 0xd58c, 0xe393, 0xe1bc, 0x0fe2,
-0x3df6, 0x448e, 0x1c8a, 0x21c0, 0x3e71, 0xf9bd, 0xc96f, 0xc456, 0xd5d9, 0xe4b5,
-0xe922, 0x1ce5, 0x418b, 0x417b, 0x1d09, 0x2518, 0x341d, 0xf03a, 0xcbea, 0xc1e1,
-0xd6e8, 0xe7f3, 0xe55f, 0x1d2e, 0x4954, 0x3f9e, 0x1b23, 0x31e7, 0x3163, 0xe580,
-0xcb7b, 0xbe90, 0xd27b, 0xe98e, 0xede5, 0x22f3, 0x51cc, 0x440f, 0x174a, 0x3744,
-0x308b, 0xdab4, 0xc2e8, 0xc03f, 0xd50d, 0xe3f9, 0xf766, 0x2e0e, 0x4fbc, 0x4269,
-0x17f2, 0x2ec2, 0x1f55, 0xd524, 0xbca2, 0xbb93, 0xda21, 0xe34e, 0xfad1, 0x31b6,
-0x47da, 0x36e7, 0x19ff, 0x2ef6, 0x0ef3, 0xd0a0, 0xb94c, 0xb54a, 0xdd97, 0xe171,
-0xf86b, 0x35bc, 0x47ba, 0x2983, 0x1694, 0x3324, 0x023b, 0xc961, 0xbc03, 0xb2d4,
-0xd7d9, 0xe2e7, 0xf9f7, 0x3391, 0x4b1a, 0x23f3, 0x1255, 0x2f9f, 0xf2dd, 0xbf1b,
-0xb8c8, 0xb595, 0xd67b, 0xe49e, 0x04eb, 0x3553, 0x491e, 0x20bc, 0x101c, 0x2d09,
-0xefb9, 0xbc9b, 0xb456, 0xbc74, 0xdcb8, 0xe7e3, 0x1085, 0x3e2d, 0x4862, 0x20a4,
-0x178e, 0x24e7, 0xe5be, 0xbfc5, 0xb5ac, 0xc6ce, 0xe4c1, 0xe9df, 0x156b, 0x41e6,
-0x4347, 0x169b, 0x1dcf, 0x2537, 0xdbdb, 0xbd60, 0xb4ac, 0xc74f, 0xe58f, 0xf1d1,
-0x1bdb, 0x438d, 0x41e3, 0x1215, 0x1c5f, 0x197b, 0xd34e, 0xbb05, 0xb7f2, 0xd3b2,
-0xe362, 0xf0f9, 0x2581, 0x46a8, 0x3c22, 0x115f, 0x2009, 0x122f, 0xd304, 0xbd34,
-0xb54b, 0xd890, 0xe911, 0xf7d8, 0x2be6, 0x4644, 0x3124, 0x11c4, 0x2d7b, 0x0ee0,
-0xcfc2, 0xc445, 0xbf59, 0xdf01, 0xe6a3, 0xf6fe, 0x2fa7, 0x4f24, 0x32c6, 0x10fe,
-0x360f, 0x14d0, 0xd1fe, 0xc5f6, 0xc3cd, 0xdf16, 0xe84d, 0x00f9, 0x3302, 0x4f34,
-0x330f, 0x190f, 0x3c38, 0x0f70, 0xcd2f, 0xc1c9, 0xccf8, 0xe5e1, 0xe528, 0x0d0a,
-0x3fdc, 0x4c89, 0x2965, 0x1572, 0x3558, 0x0773, 0xcf30, 0xbe56, 0xcfa1, 0xeeb4,
-0xe390, 0x0d40, 0x446b, 0x47d6, 0x22c9, 0x1f4d, 0x33f7, 0xf611, 0xcd9c, 0xbd57,
-0xc66d, 0xec7d, 0xe7bf, 0x0df9, 0x474d, 0x4b43, 0x1b2f, 0x1f2d, 0x35f1, 0xea3c,
-0xc455, 0xbc6b, 0xc16f, 0xe41e, 0xef9d, 0x16e5, 0x457b, 0x4d9b, 0x1df1, 0x2052,
-0x310e, 0xe35e, 0xbd3b, 0xbe4a, 0xd17b, 0xe63a, 0xf0dd, 0x2445, 0x4bde, 0x4c1f,
-0x20d2, 0x25a1, 0x2da1, 0xe9a8, 0xc288, 0xb909, 0xd9c6, 0xee3e, 0xf6a6, 0x2ef9,
-0x50a3, 0x43ee, 0x1dd3, 0x2eed, 0x2309, 0xe027, 0xcabc, 0xbd16, 0xdbde, 0xee25,
-0xf339, 0x2c27, 0x5390, 0x40a0, 0x1b96, 0x375c, 0x1d2b, 0xd734, 0xc78b, 0xb807,
-0xd541, 0xecee, 0xfe54, 0x2fa0, 0x5361, 0x3f28, 0x1522, 0x3393, 0x1266, 0xc88d,
-0xbc85, 0xb8d2, 0xd4a8, 0xe5ab, 0x0438, 0x3396, 0x4c0c, 0x33cd, 0x0a79, 0x2169,
-0xfe45, 0xc2f1, 0xb2f9, 0xb954, 0xe0e9, 0xe165, 0x029e, 0x2aa5, 0x318e, 0x465f,
-0x33d0, 0x0444, 0xd0f3, 0xc734, 0xa46c, 0x9309, 0xec1b, 0xfbdf, 0x010e, 0x6440,
-0x7e13, 0x1ed8, 0xeedd, 0xe7dd, 0x9c36, 0x94bd, 0xaeea, 0xb4e6, 0x08d9, 0x4ccc,
-0x44d3, 0x3995, 0x43b3, 0xfbc8, 0xa9f8, 0xbc47, 0xb7e9, 0xb05c, 0xd4b9, 0x0205,
-0x2fad, 0x38f1, 0x145d, 0xf759, 0x0aec, 0xf6cf, 0xb93a, 0xdb0a, 0x14b9, 0xe52f,
-0xdb64, 0x2275, 0xfc04, 0xc169, 0x1482, 0x2708, 0xda58, 0x13ad, 0x34f3, 0xe68c,
-0xf5c6, 0x0b27, 0xbfca, 0xc11f, 0x1a39, 0xf895, 0xf15a, 0x535e, 0x1fbe, 0xfd1c,
-0x2fab, 0xeb46, 0xb207, 0xf114, 0xfe7d, 0xd0f4, 0x2a5f, 0x4be3, 0xf98f, 0x2db3,
-0x365b, 0xcbe5, 0xd12f, 0x160e, 0xe93e, 0xe29c, 0x4478, 0x1d6f, 0x0413, 0x49f1,
-0x0cdb, 0xc582, 0x08ff, 0x1ce3, 0xd295, 0x10d4, 0x44fb, 0xeff9, 0x15bb, 0x4310,
-0xddfd, 0xd8c9, 0x34f7, 0xfaaf, 0xd716, 0x4457, 0x1cff, 0xe28a, 0x3514, 0x1237,
-0xb5a9, 0x01cc, 0x3075, 0xd90a, 0x1130, 0x4b8f, 0xf1cd, 0x0fee, 0x37f4, 0xcf77,
-0xc32c, 0x262d, 0xfb1f, 0xde11, 0x4cfa, 0x220f, 0xe7b6, 0x379f, 0x1630, 0xb473,
-0xeb2b, 0x1f40, 0xcdde, 0xfb49, 0x44ba, 0xf7a8, 0x0b44, 0x3ad4, 0xdf56, 0xbc11,
-0x192e, 0xfdae, 0xc1e6, 0x2be2, 0x260a, 0xe13b, 0x285b, 0x1e09, 0xb912, 0xe471,
-0x2223, 0xd36d, 0xfe2f, 0x46c5, 0xe36b, 0xf7a8, 0x4755, 0xdf55, 0xa7b3, 0x1a23,
-0x0b84, 0xc893, 0x2faf, 0x2991, 0xe2bb, 0x2481, 0x13cb, 0xb383, 0xe0a3, 0x1702,
-0xc7e4, 0xf45d, 0x4b67, 0xf6a6, 0xf97a, 0x3e6f, 0xecd9, 0xadf3, 0xfeb4, 0xfd06,
-0xc788, 0x1f7a, 0x200a, 0xe5ba, 0x31ba, 0x2511, 0xb3da, 0xe100, 0x2776, 0xc990,
-0xe1ba, 0x44f0, 0xef0a, 0xe6e3, 0x3c2c, 0xf024, 0xb397, 0x1376, 0x054e, 0xc2a5,
-0x2c7f, 0x2067, 0xc5d1, 0x227f, 0x2507, 0xa6ee, 0xd8b4, 0x2da2, 0xd0d2, 0xe5d2,
-0x4ae3, 0xf3c8, 0xec01, 0x3d1d, 0xe4c8, 0xa76d, 0x0cd7, 0x02fe, 0xc051, 0x2a3f,
-0x2ff4, 0xd96d, 0x206e, 0x2cdb, 0xbcc2, 0xcfce, 0x1d9e, 0xd936, 0xe286, 0x3c62,
-0xf899, 0xf161, 0x4188, 0xfacc, 0xb89c, 0x13b2, 0x0f18, 0xbfc2, 0x1908, 0x2b9b,
-0xdd40, 0x1c58, 0x31c8, 0xcc18, 0xe1de, 0x3029, 0xe1a2, 0xeab8, 0x4814, 0xf8bb,
-0xec3b, 0x41cd, 0xfd3d, 0xbb42, 0x1ab1, 0x1bc5, 0xd03f, 0x2b94, 0x39e6, 0xe56b,
-0x20f6, 0x302f, 0xc7e3, 0xe07e, 0x304b, 0xe35d, 0xef37, 0x556b, 0x0a77, 0xf3f3,
-0x471e, 0x0715, 0xb6bf, 0x0a15, 0x15a7, 0xc8f0, 0x27ce, 0x49e1, 0xef3f, 0x24d8,
-0x3fc8, 0xcf85, 0xd3a9, 0x2981, 0xe391, 0xe1e2, 0x5568, 0x1a44, 0xf6f8, 0x47a5,
-0x0bb1, 0xb4f6, 0x0758, 0x180f, 0xc264, 0x1c7f, 0x4997, 0xe7b6, 0x1790, 0x3eec,
-0xcc71, 0xc989, 0x25c5, 0xe0ff, 0xd5eb, 0x4cb5, 0x1585, 0xe9fb, 0x3f4e, 0x079f,
-0xa4e8, 0xf8b6, 0x18b7, 0xbe0e, 0x140f, 0x4dcd, 0xe6f8, 0x106e, 0x3e48, 0xc659,
-0xb8d1, 0x1fc6, 0xe2f7, 0xcafc, 0x4b21, 0x1aac, 0xddf9, 0x38ef, 0x0d86, 0xa172,
-0xefb8, 0x1ae3, 0xb8b9, 0x022b, 0x4952, 0xe3b7, 0x0763, 0x3fb6, 0xcaa1, 0xb546,
-0x2034, 0xe7b3, 0xc26e, 0x4341, 0x1b44, 0xd872, 0x37f9, 0x158c, 0xa302, 0xed16,
-0x212e, 0xbda6, 0x0112, 0x4eb5, 0xe481, 0x0180, 0x448c, 0xd2be, 0xb34a, 0x2659,
-0xf969, 0xc3e7, 0x4253, 0x2498, 0xd3ac, 0x2f84, 0x1c93, 0xa86a, 0xeae4, 0x2be9,
-0xc824, 0xfb1e, 0x5254, 0xeb1f, 0xf85a, 0x40c6, 0xd602, 0xacc6, 0x20d2, 0xfcc1,
-0xbfa1, 0x3d9b, 0x2b83, 0xd669, 0x2fcc, 0x202d, 0xa65f, 0xe170, 0x2e20, 0xdd4c,
-0xe4e8, 0x1128, 0xe9c6, 0x2b2e, 0x54f5, 0xec68, 0xd881, 0x25b3, 0xe44f, 0x9e7f,
-0xf130, 0xeb8e, 0xd492, 0x3413, 0x5451, 0x26e6, 0x289d, 0x2623, 0xcf51, 0xbd9d,
-0xcfb5, 0xa20d, 0xdfe7, 0x36b7, 0x0cc4, 0x056d, 0x65fe, 0x4dbe, 0xdc03, 0xeb0b,
-0xf3c5, 0xb95e, 0xbfab, 0xf463, 0x0575, 0x1cd4, 0x3d59, 0x1332, 0x1c9e, 0x36b2,
-0xe6ff, 0xc1d2, 0xebab, 0xf875, 0xd9ed, 0xf751, 0x1ec8, 0x177a, 0x1fdf, 0x14b0,
-0x158a, 0x1d8b, 0x09a1, 0xd3cc, 0xc301, 0xfa03, 0xda41, 0xd913, 0x31d2, 0x3bcd,
-0x1398, 0x2276, 0x47f0, 0x04ad, 0xdb13, 0xde05, 0xbc40, 0xe0b4, 0xf233, 0xedf8,
-0x2b4d, 0x5c62, 0x258d, 0x04db, 0x4756, 0x0b9d, 0xbaa9, 0xd2dc, 0xd3e6, 0xd2e5,
-0xeb10, 0x1044, 0x260b, 0x4492, 0x307c, 0x0989, 0x37e3, 0x1952, 0xc9b1, 0xbe5d,
-0xd980, 0xdd51, 0xcfb1, 0x0665, 0x3440, 0x3f66, 0x32e5, 0x2caa, 0x3828, 0x04a2,
-0xd6f3, 0xb98c, 0xc152, 0xdc75, 0xd7fc, 0x131d, 0x50a8, 0x4584, 0x218f, 0x39e9,
-0x3a8c, 0xe3c0, 0xca56, 0xc147, 0xc3c0, 0xe3a0, 0xec33, 0x13df, 0x4aaa, 0x4c83,
-0x117c, 0x2896, 0x399a, 0xdc86, 0xc6f6, 0xcd47, 0xc6ce, 0xd9cc, 0xf86e, 0x19ad,
-0x3a91, 0x491f, 0x123e, 0x24d9, 0x3cde, 0xe11b, 0xb37c, 0xc2df, 0xd7a4, 0xd130,
-0xef29, 0x2c49, 0x3d20, 0x37d9, 0x16ea, 0x291c, 0x26ac, 0xda1f, 0xaaed, 0xb607,
-0xe686, 0xd568, 0xe17d, 0x337f, 0x4b43, 0x2881, 0x1389, 0x38c7, 0x12c8, 0xcd26,
-0xbcc3, 0xb56e, 0xdd1b, 0xe483, 0xea42, 0x2a90, 0x51ed, 0x261e, 0x0805, 0x4126,
-0x1494, 0xbddc, 0xbaf3, 0xc450, 0xd324, 0xd5cd, 0xf712, 0x2ef6, 0x4d20, 0x2af3,
-0x0e0c, 0x3762, 0x0ac6, 0xbe79, 0xae49, 0xc076, 0xd8d1, 0xd3ec, 0x0029, 0x3a43,
-0x4756, 0x22ca, 0x1958, 0x35d2, 0xf721, 0xbeb2, 0xb3fe, 0xbef0, 0xda1f, 0xdc92,
-0x07d3, 0x4050, 0x4bd0, 0x19d3, 0x154a, 0x3522, 0xefeb, 0xbbc4, 0xb715, 0xc994,
-0xdf48, 0xe0b3, 0x1046, 0x40b6, 0x462c, 0x16f6, 0x1aab, 0x3230, 0xe981, 0xbd2a,
-0xbab3, 0xd2a2, 0xe5c9, 0xe97f, 0x1c0b, 0x466f, 0x4272, 0x167d, 0x2642, 0x3042,
-0xe930, 0xc684, 0xbe13, 0xdccc, 0xed63, 0xea9d, 0x2413, 0x5441, 0x43f9, 0x180c,
-0x36e2, 0x2e3f, 0xdd7b, 0xc957, 0xc358, 0xdaa2, 0xeec1, 0xf6ba, 0x27c0, 0x5560,
-0x448c, 0x1635, 0x38ef, 0x285a, 0xd524, 0xc336, 0xc6ef, 0xdd82, 0xe86a, 0x024a,
-0x3514, 0x5243, 0x4024, 0x1679, 0x30ad, 0x19cb, 0xd2e3, 0xbea4, 0xc57f, 0xe4e0,
-0xe5d6, 0xfff4, 0x3873, 0x4af7, 0x2f8e, 0x188b, 0x3243, 0x0881, 0xcd5e, 0xbb93,
-0xbf31, 0xe52f, 0xe3f9, 0xfc94, 0x39c7, 0x4714, 0x1d41, 0x169d, 0x38c9, 0xfecd,
-0xcb1a, 0xc0fc, 0xbdbe, 0xdc75, 0xe1b5, 0xfaa7, 0x3213, 0x48a1, 0x1b68, 0x15dc,
-0x3a99, 0xf55f, 0xc01b, 0xbf71, 0xc2a6, 0xd4e4, 0xdf4d, 0x066a, 0x3170, 0x40f1,
-0x1a26, 0x18e0, 0x342c, 0xedf9, 0xba41, 0xb3b4, 0xc38e, 0xd795, 0xe02b, 0x10cf,
-0x387d, 0x3bf9, 0x151b, 0x1afe, 0x254b, 0xde99, 0xbc43, 0xb3bd, 0xc921, 0xde4a,
-0xe189, 0x1332, 0x3ec6, 0x3af6, 0x0d82, 0x1fcf, 0x23ba, 0xd6bf, 0xb847, 0xb180,
-0xcc73, 0xe0cc, 0xeb2b, 0x1cb5, 0x417e, 0x395b, 0x0e37, 0x260e, 0x1c37, 0xceea,
-0xb693, 0xb466, 0xd44d, 0xde55, 0xeccf, 0x28e9, 0x4c64, 0x3a26, 0x1085, 0x2a16,
-0x12d5, 0xcc04, 0xb7f6, 0xb4e4, 0xda25, 0xe424, 0xf801, 0x3387, 0x4c82, 0x2ff0,
-0x133d, 0x33da, 0x0a6a, 0xc653, 0xba9f, 0xb9a4, 0xdb0d, 0xe2d3, 0xfd70, 0x3932,
-0x535b, 0x2ec6, 0x131d, 0x36f2, 0x041c, 0xc4de, 0xbc13, 0xbb88, 0xdb49, 0xe632,
-0x0792, 0x3bf9, 0x5215, 0x2df5, 0x197b, 0x38ba, 0xfc1c, 0xc000, 0xb9c1, 0xc559,
-0xe3b9, 0xea55, 0x13bb, 0x45e0, 0x506f, 0x2598, 0x1a8a, 0x31d4, 0xf25d, 0xc2c1,
-0xb752, 0xc926, 0xeaa3, 0xebad, 0x18ac, 0x4b3a, 0x4b14, 0x1dc9, 0x246e, 0x2f24,
-0xe2ff, 0xc4be, 0xbca8, 0xccb7, 0xee7a, 0xf1d7, 0x1fad, 0x5446, 0x4e8c, 0x1a55,
-0x2bfd, 0x2de3, 0xdbcc, 0xc7c4, 0xc19e, 0xcdf0, 0xeebf, 0x0347, 0x2b46, 0x50aa,
-0x4efc, 0x1ae7, 0x2bc2, 0x29fc, 0xd661, 0xbcdd, 0xc496, 0xddc3, 0xe917, 0xff6c,
-0x336f, 0x4f83, 0x433f, 0x1820, 0x2877, 0x176c, 0xd63d, 0xbf37, 0xbd41, 0xe3e4,
-0xec70, 0xfccc, 0x35e8, 0x4cad, 0x2f68, 0x12a7, 0x2fac, 0x08d7, 0xcd76, 0xc4f5,
-0xbf59, 0xdfbb, 0xe9f3, 0xfd34, 0x3194, 0x4aa3, 0x2767, 0x0f36, 0x33c2, 0x0048,
-0xc54f, 0xc2fd, 0xbd10, 0xd605, 0xe41c, 0xff51, 0x2a83, 0x4801, 0x28e6, 0x0aff,
-0x2f62, 0xfdb7, 0xbd39, 0xb775, 0xc18e, 0xd7dc, 0xe021, 0x0a7d, 0x33af, 0x423a,
-0x2081, 0x0d26, 0x28f2, 0xf6aa, 0xc604, 0xb20f, 0xca22, 0xf929, 0xe0c9, 0xfe41,
-0x2c91, 0x285c, 0x3479, 0x40e1, 0x11dd, 0xd23c, 0xd207, 0xa861, 0xa807, 0xfe96,
-0xf904, 0x0d6b, 0x7934, 0x78f8, 0x0f08, 0xfce1, 0xe859, 0x8e1b, 0xa714, 0xc4a3,
-0xd05d, 0x3229, 0x6379, 0x4af3, 0x48ea, 0x4a2d, 0xe67d, 0xa875, 0xd782, 0xc120,
-0xb7cb, 0xfb9f, 0x1f2e, 0x34e8, 0x4bf0, 0x20cd, 0xf0b2, 0x1643, 0x0563, 0xbcd0,
-0xf27f, 0x2741, 0xe7cd, 0xef58, 0x2d5f, 0xebc6, 0xc657, 0x2de0, 0x1cb6, 0xe47e,
-0x4360, 0x2d6e, 0xe23e, 0x16ee, 0xf98d, 0xa445, 0xddbb, 0x207f, 0xe2c0, 0x123e,
-0x5bce, 0x016d, 0x1099, 0x3582, 0xc93d, 0xb242, 0x0573, 0xeaa3, 0xcd42, 0x3ec8,
-0x2edf, 0xedf6, 0x39f9, 0x19b8, 0xb85b, 0xe3bc, 0x1369, 0xd1a8, 0xf1db, 0x3e71,
-0xf679, 0x05fa, 0x4211, 0xe5a8, 0xbfbb, 0x17fb, 0x0686, 0xc767, 0x1e4b, 0x24e5,
-0xdea8, 0x2460, 0x26bf, 0xbfbf, 0xebef, 0x3662, 0xdb5b, 0xe735, 0x478f, 0xf36f,
-0xe6aa, 0x3a12, 0xedab, 0xb885, 0x2168, 0x1a11, 0xd137, 0x2b7c, 0x29a9, 0xd6be,
-0x2004, 0x24d0, 0xb744, 0xddad, 0x2f52, 0xe201, 0xeeef, 0x4b3b, 0xfc02, 0xef7b,
-0x3d92, 0xf6b9, 0xb6be, 0x0b17, 0x0d77, 0xc534, 0x191c, 0x30b3, 0xe945, 0x23b0,
-0x2f3b, 0xc9bb, 0xd7dc, 0x269c, 0xe46c, 0xd902, 0x3766, 0x0212, 0xeb25, 0x39af,
-0x03e0, 0xb8e7, 0x077c, 0x169d, 0xcc6f, 0x1b10, 0x2e0e, 0xd19a, 0x0fd8, 0x38f6,
-0xca91, 0xc8f9, 0x29d6, 0xf078, 0xdd5c, 0x3b96, 0x09ef, 0xf001, 0x3507, 0xfbb1,
-0xb660, 0x03d5, 0x0e0a, 0xc387, 0x17f0, 0x3e5b, 0xe93c, 0x15a4, 0x38a5, 0xd46a,
-0xc5fe, 0x1360, 0xe4bc, 0xda9b, 0x39bc, 0x0c8d, 0xef2a, 0x3f9f, 0x0fdb, 0xb193,
-0xf8d2, 0x1694, 0xb855, 0xffea, 0x4558, 0xed39, 0x083b, 0x3cd1, 0xda45, 0xc36d,
-0x1e6e, 0xe476, 0xc765, 0x430f, 0x19a5, 0xde45, 0x3c55, 0x16d3, 0xa619, 0xf171,
-0x1f0a, 0xbe1b, 0x04f9, 0x4d9d, 0xeec4, 0x0d1f, 0x3e78, 0xccbe, 0xb49f, 0x1d9b,
-0xeb29, 0xc2b6, 0x448d, 0x28e1, 0xe2a4, 0x3aab, 0x21b9, 0xad2c, 0xe5d9, 0x1d14,
-0xbe21, 0xf5ec, 0x4db1, 0xef99, 0x030b, 0x4e45, 0xe3cc, 0xb105, 0x20c5, 0xfc50,
-0xb9ac, 0x35e2, 0x2898, 0xd9cf, 0x3397, 0x236d, 0xace6, 0xea90, 0x2c38, 0xc65d,
-0xf7eb, 0x5313, 0xe39f, 0xf211, 0x477a, 0xdbe9, 0xad7a, 0x1ffa, 0x0017, 0xc201,
-0x3906, 0x27ff, 0xd56a, 0x2d70, 0x20b7, 0xa843, 0xe22b, 0x2d3a, 0xc8d1, 0xeff9,
-0x5809, 0xf171, 0xf1ca, 0x4aa1, 0xe752, 0xa7f6, 0x1531, 0x03a8, 0xbd38, 0x3515,
-0x35e4, 0xd873, 0x2cec, 0x2fa3, 0xaedb, 0xd92e, 0x2cc6, 0xccea, 0xe531, 0x5116,
-0xf947, 0xf6dd, 0x4ce8, 0xef45, 0xaeac, 0x190f, 0x0bfc, 0xbc68, 0x2afb, 0x3612,
-0xd723, 0x2687, 0x3899, 0xbdfb, 0xda26, 0x3069, 0xdbaf, 0xe6bf, 0x5016, 0x0057,
-0xf1d5, 0x480e, 0xf64b, 0xad29, 0x13a0, 0x16f4, 0xc33e, 0x2614, 0x4041, 0xe193,
-0x201a, 0x3648, 0xc1be, 0xd35e, 0x2aee, 0xe031, 0xe3b6, 0x52de, 0x0b18, 0xedc3,
-0x4b67, 0x084a, 0xaf95, 0x0ccc, 0x1af7, 0xc089, 0x19da, 0x4369, 0xe6d2, 0x1d97,
-0x422d, 0xcfe2, 0xd1f7, 0x2e93, 0xe6d4, 0xd904, 0x4acc, 0x0d46, 0xe47d, 0x425b,
-0x0eb4, 0xb1bb, 0x06af, 0x2009, 0xc469, 0x12a4, 0x3fee, 0xdd98, 0x0e0f, 0x3d40,
-0xcdb1, 0xc9b2, 0x2f38, 0xedc8, 0xcf7d, 0x42ef, 0x1026, 0xd9af, 0x3710, 0x1033,
-0xad12, 0xfd62, 0x2285, 0xc358, 0x0c72, 0x48be, 0xe51c, 0x0a9a, 0x2ff8, 0xbdc8,
-0xc28d, 0x2cc9, 0xfec9, 0xc7ca, 0x13e5, 0x17e1, 0x02ca, 0x35c6, 0x0fac, 0xcd93,
-0xf8c0, 0xfbac, 0xbba6, 0xe67f, 0x0735, 0xd6a6, 0x1bde, 0x7350, 0x2eb9, 0xfad9,
-0x2334, 0xeee4, 0xa104, 0xc9e5, 0xcf89, 0xd376, 0x2f8b, 0x2f58, 0x13f9, 0x6199,
-0x5172, 0xd760, 0xdae6, 0x0109, 0xaaab, 0x9f01, 0x11f6, 0x1c74, 0xff8b, 0x303b,
-0x3d89, 0x2a49, 0x1900, 0xe5d6, 0xbb94, 0xe00a, 0xeeb6, 0xce23, 0x0253, 0x3291,
-0x20e8, 0x0d77, 0x2650, 0x2ac1, 0xf46d, 0xf971, 0xdbe5, 0xc599, 0xf13a, 0xdd86,
-0xebfb, 0x30a4, 0x422d, 0x0726, 0x20e1, 0x53cf, 0xe990, 0xbf8d, 0xd717, 0xc738,
-0xcc12, 0xed69, 0x1207, 0x2679, 0x4b59, 0x2072, 0x0f6e, 0x3b3c, 0xef93, 0xaf82,
-0xc07e, 0xdcf5, 0xccea, 0xe17b, 0x31b5, 0x3ad1, 0x3673, 0x24ae, 0x1fad, 0x2260,
-0xf0dd, 0xc29e, 0xb494, 0xe43c, 0xe377, 0xdb2b, 0x2318, 0x45fc, 0x34e0, 0x20c4,
-0x3ea5, 0x232d, 0xdb31, 0xcc1d, 0xb320, 0xc65a, 0xdf18, 0xea47, 0x25f0, 0x5cd4,
-0x4386, 0x10e7, 0x3d78, 0x214b, 0xc538, 0xbca9, 0xbe8b, 0xcd16, 0xe049, 0x05f5,
-0x2fe8, 0x5197, 0x45f2, 0x0fc2, 0x2f2f, 0x1971, 0xc5a7, 0xb7fc, 0xca80, 0xd975,
-0xd7df, 0x0c99, 0x3a4e, 0x3fc6, 0x30e6, 0x13a0, 0x2b87, 0x0f79, 0xcd82, 0xaf27,
-0xc107, 0xe381, 0xd5f3, 0x035c, 0x44e6, 0x44fc, 0x1db9, 0x1e95, 0x3a4e, 0xf713,
-0xc17f, 0xb545, 0xc44b, 0xea43, 0xe0b2, 0x034f, 0x458e, 0x4e96, 0x1557, 0x1819,
-0x3caa, 0xeb53, 0xb81f, 0xc29d, 0xcb34, 0xd827, 0xea2e, 0x153f, 0x3683, 0x4599,
-0x17a8, 0x1025, 0x3238, 0xefae, 0xb3df, 0xb7d0, 0xd811, 0xd6f7, 0xd85a, 0x1792,
-0x3a94, 0x35ea, 0x1657, 0x21c8, 0x243d, 0xdfb1, 0xbb30, 0xb0e9, 0xceed, 0xddbf,
-0xdff2, 0x1be1, 0x44e0, 0x3265, 0x0879, 0x260d, 0x1f6a, 0xcd4c, 0xba1b, 0xbafd,
-0xcb3d, 0xd899, 0xeb07, 0x19d6, 0x3c13, 0x3544, 0x08ed, 0x2407, 0x1daa, 0xcd68,
-0xb792, 0xbf01, 0xd1c2, 0xd611, 0xf34b, 0x259b, 0x3b2f, 0x2f39, 0x1053, 0x2d78,
-0x1a05, 0xd265, 0xba97, 0xc02a, 0xdab7, 0xd903, 0xf86d, 0x2ff9, 0x403d, 0x28d3,
-0x14a1, 0x34af, 0x0a0e, 0xcda4, 0xc3ac, 0xc13a, 0xdd8d, 0xe2ea, 0xfd27, 0x2eb2,
-0x45ac, 0x26be, 0x14ec, 0x3dd9, 0x06bc, 0xc81d, 0xc6e2, 0xc719, 0xd8c3, 0xe5c7,
-0x0b66, 0x32c9, 0x4b92, 0x2cb4, 0x19ce, 0x3c10, 0x0272, 0xc5eb, 0xbb96, 0xccd7,
-0xe07a, 0xdfbb, 0x160a, 0x4341, 0x4749, 0x2676, 0x21c7, 0x2fd3, 0xf0d0, 0xc6ee,
-0xb624, 0xcad8, 0xe85f, 0xe7c5, 0x1d81, 0x4b84, 0x45af, 0x1eba, 0x2c0d, 0x30c1,
-0xe4ba, 0xca8d, 0xbdbe, 0xcc89, 0xed50, 0xf3dd, 0x2203, 0x5159, 0x4cd1, 0x1b22,
-0x2e08, 0x3255, 0xe28f, 0xc7e6, 0xc2e3, 0xd510, 0xe8de, 0xfa14, 0x2846, 0x4a33,
-0x4c04, 0x1fed, 0x2f64, 0x2cdb, 0xe195, 0xc51d, 0xc13f, 0xdb62, 0xe696, 0xfa3e,
-0x31bd, 0x4d3c, 0x4355, 0x2150, 0x33b3, 0x204a, 0xe0d7, 0xc877, 0xbdd9, 0xdeff,
-0xeb46, 0x0024, 0x3a0c, 0x5485, 0x3c57, 0x1fe4, 0x3a57, 0x110e, 0xd1f0, 0xc4f8,
-0xbfae, 0xe303, 0xf0e8, 0x0757, 0x3795, 0x525c, 0x364d, 0x163e, 0x3411, 0x078d,
-0xc95e, 0xbed3, 0xc146, 0xdd79, 0xe8cb, 0x0fb0, 0x3b8b, 0x4b40, 0x2f52, 0x1708,
-0x2c9b, 0xf6f7, 0xc33e, 0xb8f8, 0xc0a0, 0xe27b, 0xe6d8, 0x0c22, 0x3d9b, 0x4878,
-0x24a6, 0x186c, 0x2467, 0xe600, 0xc014, 0xb323, 0xbc0b, 0xe0eb, 0xe8da, 0x0f11,
-0x3cef, 0x40c5, 0x12df, 0x1430, 0x227a, 0xdb2e, 0xb8c4, 0xb5de, 0xc528, 0xdd7a,
-0xe824, 0x13d4, 0x3e15, 0x4384, 0x124e, 0x1469, 0x1e10, 0xd6df, 0xb7fb, 0xb8e3,
-0xcdaf, 0xdd42, 0xecbb, 0x1e7d, 0x3c6f, 0x378a, 0x1149, 0x1e8a, 0x1b08, 0xd447,
-0xb3c7, 0xb0b3, 0xd341, 0xe16d, 0xebda, 0x22db, 0x4450, 0x345d, 0x0fcd, 0x27aa,
-0x137c, 0xcfd2, 0xc241, 0xbb1b, 0xd538, 0xe771, 0xf62c, 0x297f, 0x4c37, 0x3271,
-0x103e, 0x360c, 0x143c, 0xc8cb, 0xc2e2, 0xc46f, 0xd919, 0xe83f, 0x0316, 0x2e44,
-0x49f7, 0x320d, 0x1102, 0x34eb, 0x0f20, 0xc998, 0xc1e5, 0xc68b, 0xd8b7, 0xe3aa,
-0x0e51, 0x3839, 0x473d, 0x306d, 0x1936, 0x313b, 0x023a, 0xca3b, 0xb9cb, 0xc4e8,
-0xe9a8, 0xe8e8, 0x0e4f, 0x4390, 0x4a72, 0x23d2, 0x1d52, 0x31ca, 0xf0b0, 0xc813,
-0xbd25, 0xc202, 0xe6ea, 0xee18, 0x12c8, 0x4476, 0x4b2e, 0x198b, 0x19a1, 0x2fcc,
-0xe518, 0xbf8d, 0xbe9e, 0xcb6d, 0xe622, 0xee0e, 0x167e, 0x3fbf, 0x46fb, 0x1a7d,
-0x1f4e, 0x2d08, 0xe17f, 0xbedd, 0xbaa3, 0xcc16, 0xe196, 0xeedc, 0x21cc, 0x44ed,
-0x4348, 0x1a18, 0x2363, 0x242e, 0xdc65, 0xbd61, 0xb300, 0xcfa0, 0xe712, 0xe5c7,
-0x169f, 0x5f17, 0x7299, 0x2bb1, 0x0b65, 0xe2fd, 0x9b1c, 0xa3b5, 0xaeb5, 0xe147,
-0x3787, 0x593a, 0x5290, 0x4a3c, 0x2e69, 0xcbb4, 0xa91f, 0xc5a3, 0xbd85, 0xd07b,
-0x1055, 0x3d01, 0x2411, 0x222c, 0x2b1a, 0x0b05, 0xffdc, 0xe3f2, 0xcf8c, 0xf390,
-0x15ad, 0xd9f5, 0xc944, 0x2d37, 0x09de, 0xc93f, 0x0d00, 0x229d, 0x0eb5, 0x31fb,
-0x193d, 0xdefd, 0x0b6e, 0xe2b8, 0x80c1, 0xd2cb, 0x1719, 0xe9c2, 0x3008, 0x6a8a,
-0xfee8, 0x01bc, 0x299a, 0xb39d, 0xa48f, 0x0798, 0xe5e9, 0xddfa, 0x41e1, 0x17dc,
-0xf43b, 0x3829, 0x05c3, 0xbd89, 0xf1bc, 0x0dab, 0xcd37, 0xfad8, 0x2e14, 0xf080,
-0x107b, 0x24ea, 0xd852, 0xd4a0, 0x17fd, 0xfd24, 0xd818, 0x2b57, 0x168d, 0xdb81,
-0x1759, 0x0cdb, 0xc867, 0xf2e6, 0x257d, 0xe349, 0xfff1, 0x39a1, 0xe33d, 0xee45,
-0x2b9d, 0xe388, 0xc702, 0x21a8, 0x103e, 0xda0f, 0x2f4b, 0x1b70, 0xd6c1, 0x1b55,
-0x104d, 0xb577, 0xe811, 0x28c6, 0xe0aa, 0xfee3, 0x4403, 0xf56f, 0xf711, 0x2c32,
-0xe60a, 0xbd96, 0x0d61, 0x048f, 0xce3d, 0x272f, 0x325d, 0xf1c7, 0x2094, 0x1ff0,
-0xc860, 0xe30a, 0x2515, 0xdac5, 0xe92d, 0x441f, 0x0548, 0xfb76, 0x3d79, 0xfd5c,
-0xbecb, 0x1149, 0x13f9, 0xd214, 0x2a6f, 0x3388, 0xe6f8, 0x2190, 0x2948, 0xc4a5,
-0xdd42, 0x2f43, 0xe6af, 0xf03f, 0x54db, 0x13d9, 0xfca6, 0x3215, 0xf506, 0xc57a,
-0x12c0, 0x0f9f, 0xd3cc, 0x322e, 0x4301, 0xf273, 0x23ab, 0x356e, 0xd3b2, 0xd051,
-0x21b7, 0xf281, 0xecda, 0x4489, 0x12f0, 0x0242, 0x4407, 0x06d1, 0xbafe, 0x0b6c,
-0x1d26, 0xc6ee, 0x19bc, 0x44e9, 0xe86d, 0x13b7, 0x39ca, 0xd446, 0xd119, 0x2941,
-0xee93, 0xe7c5, 0x4bc2, 0x0643, 0xe908, 0x4535, 0x0444, 0xaaed, 0x0a10, 0x21a1,
-0xc807, 0x1964, 0x41d6, 0xe77b, 0x16b3, 0x34e4, 0xc869, 0xc8dc, 0x2196, 0xe4ba,
-0xdb97, 0x4973, 0x106a, 0xe7d9, 0x3cc5, 0x0a39, 0xa769, 0xf083, 0x1925, 0xc4c2,
-0x075d, 0x3c4a, 0xe3ca, 0x0d28, 0x38d3, 0xc8d1, 0xbd34, 0x29a4, 0xea91, 0xbfc6,
-0x3ad0, 0x0fbe, 0xd348, 0x3125, 0x0f03, 0xa6a3, 0xf4e3, 0x222b, 0xbe73, 0x00e2,
-0x3cfa, 0xd671, 0xff6d, 0x3893, 0xc753, 0xb6c9, 0x236e, 0xec95, 0xc571, 0x3925,
-0x1324, 0xdbd6, 0x2c09, 0x07a8, 0xaa2d, 0xf242, 0x1fa6, 0xc716, 0x042c, 0x441c,
-0xe490, 0xffd3, 0x3dc4, 0xdc2a, 0xb9f6, 0x1f30, 0xfbb0, 0xca2e, 0x371c, 0x2003,
-0xddf1, 0x31fa, 0x2307, 0xb4d8, 0xf004, 0x2cbc, 0xc878, 0xf7c6, 0x4caf, 0xed6b,
-0xfe78, 0x48e2, 0xe5f3, 0xb861, 0x209c, 0xffdd, 0xc990, 0x3a8f, 0x2235, 0xd8df,
-0x3307, 0x26fb, 0xb85c, 0xf04e, 0x2cb8, 0xd049, 0xfa7c, 0x49ae, 0xedac, 0xfa25,
-0x3f7d, 0xe587, 0xbae6, 0x1de2, 0x03f4, 0xc964, 0x35b0, 0x2bf3, 0xdcc1, 0x287a,
-0x2509, 0xb53e, 0xdd34, 0x21f5, 0xd014, 0xf4e6, 0x5327, 0xfbed, 0xf63d, 0x422a,
-0xebde, 0xadff, 0x109b, 0x03c0, 0xc66e, 0x34a1, 0x371f, 0xe1e5, 0x266b, 0x298a,
-0xb6ec, 0xdb6e, 0x2815, 0xd421, 0xf019, 0x5352, 0xff26, 0xf3f2, 0x43a2, 0xf389,
-0xb155, 0x11bc, 0x093e, 0xc3cf, 0x2cd7, 0x37d3, 0xe04d, 0x22e3, 0x2ecd, 0xb8a8,
-0xd4f6, 0x2b5c, 0xd879, 0xe9c1, 0x5345, 0x0074, 0xeb1b, 0x3d0d, 0xf0a8, 0xa78e,
-0x0f83, 0x1369, 0xc523, 0x2e80, 0x3d4c, 0xdb13, 0x1e41, 0x2ecc, 0xb34d, 0xd013,
-0x2f65, 0xd81e, 0xe458, 0x57d2, 0x0406, 0xebe0, 0x457a, 0xf7e1, 0xa66e, 0x0b6f,
-0x0e7a, 0xb8d1, 0x251b, 0x3fe1, 0xdd7d, 0x20b9, 0x3687, 0xbb17, 0xd0b9, 0x2e06,
-0xd6de, 0xd8c9, 0x50ce, 0x0665, 0xe605, 0x3fce, 0xfc63, 0xac6f, 0x0f4a, 0x249e,
-0xcfcc, 0xfc68, 0x0488, 0xeb03, 0x4794, 0x43ec, 0xda83, 0xf3bd, 0x2644, 0xc019,
-0xac19, 0xfdb7, 0xdae0, 0xebc8, 0x4a7e, 0x4842, 0x204b, 0x2f4a, 0x0bd7, 0xb466,
-0xc7b6, 0xc25a, 0x9ff5, 0xfeaa, 0x3147, 0xf5d6, 0x1606, 0x7098, 0x2536, 0xcb1f,
-0xef7c, 0xd8bb, 0xa610, 0xc6a6, 0xf94d, 0x01cf, 0x2326, 0x2e92, 0xfa36, 0x1b23,
-0x1fee, 0xc9e0, 0xbf64, 0xf0f7, 0xebf9, 0xcd60, 0xfed7, 0x1727, 0x0a34, 0x1723,
-0x0a36, 0x0e7b, 0x18aa, 0xfc64, 0xb854, 0xc985, 0xfdd8, 0xc68b, 0xea58, 0x3e80,
-0x2a34, 0x0ba2, 0x2d28, 0x367f, 0xec1b, 0xe1de, 0xce20, 0xb654, 0xf084, 0xed7d,
-0xf556, 0x44c2, 0x5de8, 0x118c, 0x103a, 0x43c2, 0xea97, 0xbbb3, 0xd781, 0xd5a7,
-0xe105, 0xfd04, 0x1bc6, 0x2dbd, 0x4a4e, 0x2262, 0x090c, 0x37f3, 0x0697, 0xc337,
-0xc445, 0xe70d, 0xe217, 0xdb53, 0x1953, 0x38c9, 0x40c1, 0x2ede, 0x22c3, 0x260c,
-0xfc8c, 0xcfd4, 0xb0e1, 0xd39e, 0xe34c, 0xdae1, 0x253f, 0x508f, 0x342f, 0x1aa5,
-0x3628, 0x1e6e, 0xd753, 0xc9cd, 0xb7c4, 0xd23c, 0xef41, 0xeb30, 0x1cc2, 0x523c,
-0x3c38, 0x02b5, 0x29f9, 0x28a2, 0xd759, 0xd1f8, 0xd1bf, 0xd245, 0xe508, 0xfe91,
-0x19fc, 0x3b30, 0x3d9b, 0x0a4c, 0x2fd0, 0x37f4, 0xdc8c, 0xbe49, 0xd7b4, 0xe591,
-0xd3af, 0xfd0f, 0x3070, 0x36f1, 0x325e, 0x18a4, 0x3386, 0x27ca, 0xdc73, 0xb513,
-0xcdc8, 0xf809, 0xd5d9, 0xf013, 0x4334, 0x4964, 0x2395, 0x1b7b, 0x3c5a, 0x0fe4,
-0xd7a3, 0xc6c6, 0xc6b6, 0xf0cf, 0xeb7d, 0xf80b, 0x3914, 0x525a, 0x2445, 0x1417,
-0x4928, 0x0ff5, 0xc35d, 0xc78a, 0xd244, 0xdff9, 0xe35e, 0x07df, 0x35ae, 0x4ba7,
-0x2974, 0x1106, 0x3cf3, 0x0fec, 0xc4b4, 0xb9c7, 0xd562, 0xe489, 0xd970, 0x0e52,
-0x3f61, 0x43d6, 0x27aa, 0x2131, 0x364b, 0xfd16, 0xc955, 0xb961, 0xcde0, 0xe8ce,
-0xe024, 0x0e4f, 0x4544, 0x4582, 0x18cd, 0x22be, 0x3a77, 0xf22e, 0xc4f3, 0xbabf,
-0xcce0, 0xe32e, 0xe352, 0x12f7, 0x43a1, 0x4666, 0x1401, 0x1c0c, 0x30e6, 0xe619,
-0xbb56, 0xbb95, 0xd491, 0xe00b, 0xe61a, 0x17a4, 0x3b47, 0x3b00, 0x10e7, 0x1c7e,
-0x2707, 0xe361, 0xb750, 0xb2d2, 0xd7be, 0xdb41, 0xe145, 0x2096, 0x40ed, 0x319a,
-0x118b, 0x2924, 0x1a2e, 0xd6af, 0xba5f, 0xad6c, 0xd2c9, 0xe064, 0xe67c, 0x25df,
-0x4ea4, 0x3357, 0x0fc7, 0x312c, 0x1020, 0xc418, 0xb5ff, 0xb68a, 0xd4f7, 0xe2ef,
-0xfb14, 0x2e11, 0x4c3e, 0x3280, 0x08fc, 0x2966, 0x0e36, 0xc69d, 0xb3ba, 0xbf26,
-0xde72, 0xe461, 0x0918, 0x3887, 0x4967, 0x313c, 0x1236, 0x2763, 0x0526, 0xcb44,
-0xb35a, 0xc8b5, 0xed8f, 0xdf83, 0x05bf, 0x41b2, 0x4548, 0x20ab, 0x1a30, 0x2bd9,
-0xf884, 0xce0f, 0xb377, 0xc10c, 0xede8, 0xe5b7, 0x0520, 0x42f2, 0x4b64, 0x19c0,
-0x1a50, 0x2fd7, 0xee52, 0xc8d4, 0xbcea, 0xc661, 0xe5d5, 0xe9b8, 0x0e4b, 0x42da,
-0x4c23, 0x187a, 0x1ba9, 0x2fdd, 0xe89e, 0xbcad, 0xb84a, 0xd201, 0xe619, 0xeba8,
-0x1a61, 0x40ef, 0x41b7, 0x151a, 0x1cbf, 0x2b05, 0xea44, 0xc1f8, 0xbc6c, 0xdb3c,
-0xe422, 0xe69f, 0x208e, 0x4881, 0x3cc7, 0x1503, 0x2aa9, 0x27ed, 0xe431, 0xc5cc,
-0xbdfa, 0xdd9a, 0xe8e9, 0xf074, 0x2496, 0x4a59, 0x3e74, 0x1374, 0x2e8f, 0x252c,
-0xd82c, 0xba66, 0xbeda, 0xe1cc, 0xe3a5, 0xf456, 0x3043, 0x4df4, 0x382a, 0x0d8b,
-0x25d9, 0x1516, 0xd249, 0xb805, 0xbbdd, 0xe317, 0xe31f, 0xf717, 0x307f, 0x4438,
-0x2ce7, 0x1089, 0x29b8, 0x060d, 0xc757, 0xb6c7, 0xb848, 0xdd4c, 0xde36, 0xf60e,
-0x341a, 0x45f6, 0x1fc8, 0x0b03, 0x2ed5, 0xff75, 0xc14a, 0xb3bb, 0xb4dc, 0xd6d2,
-0xdc36, 0xfbb0, 0x356c, 0x49c3, 0x2300, 0x0fe9, 0x2f18, 0xf499, 0xb802, 0xb1b2,
-0xc06f, 0xdc85, 0xde22, 0x0805, 0x3cc1, 0x488e, 0x1f2e, 0x11d7, 0x2c64, 0xf3b1,
-0xbd78, 0xadbb, 0xc5eb, 0xe451, 0xde57, 0x0e82, 0x4140, 0x4137, 0x1916, 0x1b84,
-0x28d4, 0xe639, 0xc1a0, 0xb2e7, 0xc697, 0xe4be, 0xdf87, 0x10dc, 0x49b4, 0x457d,
-0x1479, 0x2405, 0x2b0f, 0xdcbe, 0xbefc, 0xb3a9, 0xc6dd, 0xe60b, 0xed45, 0x1b13,
-0x497b, 0x4531, 0x1324, 0x24b0, 0x243c, 0xd210, 0xb83d, 0xb984, 0xd0bc, 0xe2a6,
-0xf3b7, 0x2766, 0x4a82, 0x4204, 0x133f, 0x22b4, 0x1b4e, 0xd4a3, 0xba37, 0xbaaf,
-0xdf26, 0xea12, 0xf84b, 0x3177, 0x4e17, 0x39af, 0x193b, 0x308a, 0x13c1, 0xd6b0,
-0xc5d3, 0xbffc, 0xe599, 0xeec6, 0xff4d, 0x38ac, 0x5167, 0x346a, 0x1b9d, 0x376a,
-0x0ce4, 0xd4a8, 0xc78f, 0xc195, 0xe4f4, 0xf0f5, 0x07bb, 0x3cdc, 0x5981, 0x3510,
-0x1b26, 0x3a31, 0x03fb, 0xca72, 0xc53e, 0xcd25, 0xecab, 0xf768, 0x193e, 0x437d,
-0x53af, 0x2c6f, 0x15b8, 0x31bf, 0xff10, 0xcc99, 0xc147, 0xd348, 0xee05, 0xee95,
-0x1782, 0x2f2b, 0x4b20, 0x5a80, 0x2b14, 0xfd25, 0xdd6a, 0xccb5, 0x9c77, 0xbb91,
-0x0abb, 0xfa6d, 0x308d, 0x8b3b, 0x6386, 0x0f1b, 0x0366, 0xd9a6, 0x969a, 0xbb36,
-0xbe42, 0xd650, 0x4a43, 0x5e11, 0x39f6, 0x4e5f, 0x3f3f, 0xd1f7, 0xbac7, 0xda01,
-0xb75e, 0xdb85, 0x0689, 0x0f50, 0x402d, 0x3a48, 0xf492, 0xf3ba, 0x232e, 0xe3c2,
-0xc221, 0x1c7e, 0x103b, 0xda32, 0x0d99, 0x12a9, 0xc374, 0xe4a9, 0x2fee, 0xef59,
-0xf571, 0x4551, 0x09ce, 0xee4d, 0x190c, 0xdd87, 0xa5eb, 0xf5c9, 0x0d02, 0xd8dd,
-0x32e0, 0x4556, 0xf27b, 0x272d, 0x1a0f, 0xac2d, 0xc929, 0x0d48, 0xd065, 0xe73f,
-0x4fb6, 0x0a4b, 0xfcc1, 0x4512, 0xed54, 0xb2b9, 0x0350, 0xfc0b, 0xbed7, 0x1926,
-0x2f0c, 0xe1a6, 0x2871, 0x338a, 0xc365, 0xd8fc, 0x2261, 0xe12a, 0xda5e, 0x3836,
-0x02a6, 0xeb2d, 0x3c29, 0xfc95, 0xb47f, 0x126c, 0x2240, 0xc4df, 0x1301, 0x42d9,
-0xddbd, 0x05c8, 0x2ff4, 0xc609, 0xc9ef, 0x2ebd, 0xf193, 0xda07, 0x46da, 0x0cd3,
-0xe052, 0x39eb, 0x0085, 0xa3df, 0xfdbd, 0x1d67, 0xc36d, 0x1321, 0x461a, 0xe3db,
-0x121d, 0x3bc5, 0xce7e, 0xc611, 0x1e92, 0xe869, 0xd146, 0x3d6e, 0x12f6, 0xe781,
-0x3a2e, 0x100e, 0xb4c0, 0xf87f, 0x2451, 0xce12, 0xfd54, 0x3b61, 0xe9af, 0x0485,
-0x363a, 0xd7a5, 0xc531, 0x26b6, 0xfb26, 0xd3af, 0x4024, 0x13d3, 0xcf38, 0x31ca,
-0x1fe6, 0xacba, 0xe830, 0x28d0, 0xd67b, 0x03f4, 0x4390, 0xeff5, 0x0d9b, 0x3cdc,
-0xd2ef, 0xbce5, 0x1df5, 0xf194, 0xcc0a, 0x3c7b, 0x22be, 0xe9d0, 0x37e4, 0x1f21,
-0xbf6a, 0xed14, 0x13f9, 0xccad, 0xfeed, 0x36f2, 0xe931, 0x0bd9, 0x4870, 0xe9a7,
-0xc649, 0x2406, 0x009e, 0xc7de, 0x28c6, 0x1d14, 0xe19d, 0x2d2e, 0x24eb, 0xc1ae,
-0xf293, 0x2948, 0xd034, 0xfc36, 0x4c80, 0xed33, 0xf76a, 0x4574, 0xe546, 0xb51f,
-0x205e, 0x01e4, 0xc8f6, 0x3c9b, 0x2dfd, 0xe000, 0x3231, 0x23e4, 0xac3f, 0xe1e2,
-0x2470, 0xc806, 0xf279, 0x51f9, 0xfc93, 0xfd3d, 0x471f, 0xf14b, 0xb564, 0x0d8d,
-0xf7a1, 0xbaf7, 0x2ae2, 0x3330, 0xe3cf, 0x2876, 0x2f9d, 0xbe99, 0xd8ed, 0x2066,
-0xcc5b, 0xe037, 0x444b, 0xfc55, 0xf1ae, 0x3dee, 0xedb1, 0xa9f3, 0x0f58, 0x052a,
-0xb88b, 0x286b, 0x32e9, 0xd191, 0x1a2d, 0x2b19, 0xb1ba, 0xd055, 0x2574, 0xcd9d,
-0xe17a, 0x4f5d, 0xf991, 0xe9c8, 0x4424, 0xee22, 0xa03f, 0x0b3e, 0x0833, 0xb2f6,
-0x25d7, 0x3fb5, 0xd971, 0x1eca, 0x3552, 0xb55f, 0xc5ed, 0x2341, 0xd2b5, 0xd7c1,
-0x523e, 0x069d, 0xe63d, 0x453d, 0xfaec, 0xa137, 0x0414, 0x12c4, 0xb981, 0x1bb8,
-0x4054, 0xdb21, 0x1feb, 0x3f6a, 0xbc6b, 0xcb19, 0x2eaa, 0xdddc, 0xd782, 0x53f0,
-0x0db9, 0xe5f5, 0x4ae5, 0x09f1, 0xaaaa, 0x08ea, 0x1b96, 0xc280, 0x22c4, 0x4ce0,
-0xe24f, 0x1cfe, 0x4491, 0xc23a, 0xc424, 0x2faf, 0xe9a8, 0xd606, 0x50b8, 0x16c3,
-0xe5a3, 0x41e4, 0x0b1a, 0xa940, 0xfef6, 0x1bdf, 0xbfb1, 0x1607, 0x4e4e, 0xe252,
-0x116e, 0x44af, 0xc71f, 0xbeed, 0x2c56, 0xed57, 0xd13f, 0x46da, 0x1220, 0xdf44,
-0x3fcf, 0x0e72, 0xa687, 0xfe99, 0x22c2, 0xc0f4, 0x10f5, 0x4ab0, 0xdcc9, 0x0862,
-0x42d3, 0xcce8, 0xbf2b, 0x2c4a, 0xf130, 0xcf23, 0x47a0, 0x1557, 0xd894, 0x3b17,
-0x15eb, 0xac91, 0xfc3e, 0x2839, 0xc889, 0x0a6b, 0x4a0a, 0xe524, 0x0571, 0x40a3,
-0xd642, 0xc2d3, 0x2b1c, 0xfa19, 0xd4f9, 0x465b, 0x1ef6, 0xe106, 0x371e, 0x15ec,
-0xb185, 0xfc2f, 0x2898, 0xcc97, 0x0b55, 0x4c1f, 0xebc4, 0x08bc, 0x3f08, 0xd705,
-0xc599, 0x2bb5, 0x081d, 0xcd96, 0x0d3b, 0x0ffa, 0x0823, 0x3f09, 0x1a45, 0xdad9,
-0x0662, 0x07b7, 0xbb6a, 0xde9a, 0x0740, 0xda46, 0x0e1e, 0x6549, 0x38b1, 0x04bd,
-0x2510, 0xf943, 0xad98, 0xc9a0, 0xca5c, 0xcaba, 0x22c9, 0x2b10, 0x01f0, 0x511a,
-0x637c, 0xe409, 0xcfea, 0xff1b, 0xbae4, 0x9b34, 0xfafc, 0x154f, 0xfdb5, 0x2da1,
-0x2e82, 0x1b20, 0x2472, 0xf46c, 0xbc6b, 0xd8c3, 0xf895, 0xcd65, 0xe4ee, 0x20c1,
-0x1821, 0x08d6, 0x178c, 0x2a03, 0x07e8, 0xfe05, 0xe136, 0xbccf, 0xeb99, 0xdae7,
-0xd3aa, 0x1d70, 0x3e94, 0x094b, 0x0900, 0x5434, 0x0901, 0xc4b1, 0xdc6e, 0xc832,
-0xca7f, 0xe370, 0xfc55, 0x19fb, 0x5037, 0x3174, 0xfe1c, 0x3bdc, 0x1079, 0xb5a5,
-0xbd97, 0xde91, 0xd7dc, 0xd8e9, 0x1ed3, 0x2fd7, 0x3373, 0x2e1c, 0x130d, 0x2861,
-0x0ada, 0xcec0, 0xaf81, 0xd3f1, 0xe991, 0xcbf7, 0x0636, 0x408c, 0x3d14, 0x22da,
-0x2e7f, 0x334f, 0xf091, 0xd23f, 0xb6f6, 0xbe39, 0xe0ea, 0xdac6, 0x0ab7, 0x52de,
-0x5241, 0x1a28, 0x36a7, 0x3ee4, 0xdc10, 0xbfb1, 0xc06c, 0xc69f, 0xdf82, 0xf62e,
-0x1f54, 0x4e25, 0x578d, 0x17a6, 0x26c4, 0x37fc, 0xe05d, 0xc099, 0xcd8c, 0xd886,
-0xd8c3, 0xfcba, 0x2d83, 0x3fa6, 0x48bb, 0x1e77, 0x2a31, 0x31eb, 0xe98e, 0xbcf5,
-0xc196, 0xe4e4, 0xdb34, 0xf4b5, 0x398d, 0x47e8, 0x3526, 0x2168, 0x3d9a, 0x20eb,
-0xddcb, 0xbe09, 0xb85c, 0xe775, 0xe3f6, 0xedd1, 0x3731, 0x576a, 0x2d99, 0x1229,
-0x4011, 0x0fb4, 0xc58a, 0xc2e0, 0xc163, 0xd8b3, 0xe485, 0xfbc4, 0x28a2, 0x4aba,
-0x2b57, 0x06a4, 0x385f, 0x150e, 0xc2cd, 0xb65c, 0xcd33, 0xde60, 0xd4fe, 0x0096,
-0x3507, 0x45bc, 0x2781, 0x142c, 0x33ba, 0x049c, 0xc775, 0xb39c, 0xc6ec, 0xe39b,
-0xd75b, 0x0203, 0x3c34, 0x4589, 0x1c2f, 0x171d, 0x336b, 0xeff6, 0xbf31, 0xb8c6,
-0xc21c, 0xde19, 0xe412, 0x0b3a, 0x399a, 0x4631, 0x1799, 0x116c, 0x3085, 0xeefe,
-0xbcec, 0xb922, 0xcdc6, 0xe051, 0xe2d7, 0x10d0, 0x38e1, 0x3dfb, 0x1356, 0x1516,
-0x2876, 0xe6f8, 0xbb6a, 0xb636, 0xd128, 0xdda0, 0xdf16, 0x11df, 0x387e, 0x338c,
-0x0c5c, 0x211c, 0x2422, 0xdca8, 0xbf10, 0xb435, 0xcd32, 0xde18, 0xe25f, 0x144e,
-0x3fe0, 0x3472, 0x0753, 0x2b41, 0x27e8, 0xd555, 0xc117, 0xbddb, 0xcb8c, 0xdaa8,
-0xee16, 0x185e, 0x406a, 0x394d, 0x0e4c, 0x3224, 0x2283, 0xcee6, 0xb78f, 0xbe46,
-0xd600, 0xd73a, 0xf882, 0x2db5, 0x4253, 0x3500, 0x1558, 0x2eee, 0x13ba, 0xd1b3,
-0xb80a, 0xbd32, 0xe28d, 0xdf23, 0xfd44, 0x3980, 0x4ace, 0x2d3f, 0x18f4, 0x34ae,
-0x039f, 0xcc97, 0xbb5e, 0xbe2a, 0xe6fa, 0xe555, 0x023b, 0x3de8, 0x4db4, 0x2192,
-0x1578, 0x3a68, 0xfe29, 0xc84a, 0xbd0b, 0xc1ef, 0xe3a9, 0xe936, 0x0a3b, 0x3ab4,
-0x505a, 0x260d, 0x1903, 0x39c0, 0xf9ac, 0xc53b, 0xbc41, 0xcc45, 0xe5fc, 0xe843,
-0x15b8, 0x436d, 0x4dae, 0x24c5, 0x212b, 0x33f2, 0xf1b2, 0xc3a3, 0xb509, 0xcd57,
-0xe8db, 0xeb7c, 0x1d1e, 0x4aef, 0x4a01, 0x1af5, 0x24c7, 0x2df1, 0xe4a5, 0xc1ae,
-0xb8ad, 0xd2c8, 0xe887, 0xee7b, 0x21d0, 0x4d5f, 0x4806, 0x171f, 0x2854, 0x27e5,
-0xdd26, 0xc075, 0xb9c1, 0xd6dc, 0xe94e, 0xf760, 0x2a99, 0x4d0c, 0x4405, 0x1751,
-0x2a63, 0x1e7d, 0xd670, 0xba60, 0xb674, 0xde00, 0xe8fc, 0xf57e, 0x3121, 0x51b2,
-0x3a66, 0x11d4, 0x29d9, 0x107f, 0xd01f, 0xbbd1, 0xb864, 0xe08f, 0xea2a, 0xfafd,
-0x34de, 0x5038, 0x3061, 0x1294, 0x3316, 0x07d3, 0xc6ab, 0xbd82, 0xc0f2, 0xe421,
-0xebe4, 0x0398, 0x39c6, 0x54a2, 0x2e8b, 0x0e55, 0x3308, 0x0648, 0xc5ad, 0xbd8e,
-0xc53c, 0xdfb2, 0xe8b4, 0x0f4a, 0x3d14, 0x4caa, 0x2bf1, 0x15bf, 0x2e89, 0xf945,
-0xc136, 0xb890, 0xcaeb, 0xe950, 0xe7bf, 0x115d, 0x451b, 0x4aa1, 0x20cd, 0x1684,
-0x2a91, 0xf0a3, 0xc5b7, 0xb815, 0xc9bf, 0xee16, 0xea12, 0x117d, 0x470b, 0x42c7,
-0x113f, 0x1b7c, 0x2b91, 0xe191, 0xc212, 0xbd24, 0xc84b, 0xe419, 0xe8c1, 0x104f,
-0x440c, 0x4662, 0x1122, 0x20a6, 0x2d8e, 0xda8b, 0xbcf3, 0xc089, 0xcbf5, 0xde1c,
-0xf3c0, 0x2135, 0x414e, 0x3fd9, 0x15e1, 0x26f5, 0x292e, 0xdc7e, 0xb937, 0xb924,
-0xd769, 0xe06d, 0xee92, 0x2aa0, 0x48ae, 0x379d, 0x15e3, 0x2afa, 0x167d, 0xd370,
-0xbfeb, 0xb8aa, 0xd8da, 0xe695, 0xf331, 0x2abe, 0x4918, 0x2e1c, 0x0f19, 0x32cf,
-0x0f46, 0xc822, 0xbf6b, 0xbca2, 0xdadc, 0xe628, 0xf835, 0x2cf1, 0x4b03, 0x2c10,
-0x0df9, 0x358e, 0x0a2c, 0xc678, 0xc06b, 0xc05f, 0xd849, 0xe170, 0x02e1, 0x3324,
-0x4bd0, 0x2fc8, 0x13c8, 0x3314, 0x0029, 0xbf2e, 0xb455, 0xc1d3, 0xe027, 0xe480,
-0x0a7f, 0x2c7a, 0x5506, 0x634d, 0x2129, 0xfadf, 0xe1b5, 0xb620, 0x8bd2, 0xbfae,
-0x0a2a, 0x0d5d, 0x5240, 0x8109, 0x4e83, 0x15cf, 0xf367, 0xba2c, 0x9d5f, 0xcd2e,
-0xbdc8, 0xf85d, 0x6f35, 0x4484, 0x29e8, 0x54f0, 0x2a04, 0xcc06, 0xd6d5, 0xe253,
-0xc387, 0x09da, 0xff4a, 0xebc6, 0x4eb3, 0x2edb, 0xcfcc, 0x0b9a, 0x3d1b, 0xdc1f,
-0xf4a1, 0x3fae, 0xeb9b, 0xe915, 0x13be, 0xcb86, 0xb940, 0x1643, 0x18ee, 0xf7d9,
-0x4acf, 0x30df, 0xe6dc, 0x16fe, 0xf4d5, 0x9c55, 0xcc79, 0x10aa, 0xe384, 0x0496,
-0x4c2c, 0x0504, 0xff4c, 0x2d7e, 0xd93d, 0xacb4, 0x00e4, 0xf5af, 0xc18e, 0x2289,
-0x2a64, 0xe0a9, 0x2089, 0x21b8, 0xbaf3, 0xdd89, 0x1ea4, 0xd2e4, 0xe648, 0x37ea,
-0xec35, 0xe993, 0x35d6, 0xed2e, 0xbadd, 0x15b4, 0x0a9d, 0xc841, 0x1a7c, 0x191c,
-0xcaef, 0x0f4e, 0x1fff, 0xbfae, 0xe155, 0x3460, 0xeb55, 0xe0b6, 0x3048, 0xf2f2,
-0xddca, 0x235a, 0xee7f, 0xb7cc, 0x15dd, 0x2097, 0xce52, 0x180f, 0x2dcf, 0xd499,
-0x0857, 0x29b8, 0xc4c2, 0xd000, 0x28ff, 0xe652, 0xde94, 0x43c5, 0x05e6, 0xe425,
-0x356a, 0xfee7, 0xb2c1, 0x0914, 0x1584, 0xbe7b, 0x0e5a, 0x368a, 0xe276, 0x1274,
-0x3391, 0xd008, 0xd357, 0x26c2, 0xec06, 0xdd61, 0x39e2, 0x0868, 0xe6f9, 0x3207,
-0x091c, 0xbc0e, 0x0582, 0x1f6d, 0xd133, 0x1cab, 0x4d57, 0xeb81, 0x02e3, 0x3712,
-0xde41, 0xc71f, 0x212b, 0xfb67, 0xe7a1, 0x504a, 0x23ac, 0xedd8, 0x3eb6, 0x157e,
-0xad36, 0xfc30, 0x2995, 0xcb86, 0x10c5, 0x529b, 0xf7a7, 0x15fe, 0x4546, 0xdc21,
-0xcaba, 0x26eb, 0xe984, 0xd493, 0x4c8e, 0x16e6, 0xe56c, 0x463b, 0x1cf9, 0xb4a9,
-0xfd71, 0x24ab, 0xc8a4, 0x09c8, 0x41c1, 0xe4ff, 0x0a9c, 0x3d28, 0xd226, 0xc16f,
-0x2d0a, 0xf732, 0xcb2f, 0x42b2, 0x1d8f, 0xd5f3, 0x2c26, 0x1649, 0xa7c7, 0xed21,
-0x286f, 0xc688, 0x04e2, 0x51dd, 0xe73b, 0x0013, 0x46f0, 0xd1e8, 0xab29, 0x260f,
-0xf7aa, 0xbdee, 0x402d, 0x25c0, 0xda8b, 0x3989, 0x21df, 0xa95c, 0xf0ed, 0x290b,
-0xbd3d, 0xfb44, 0x4eba, 0xe63a, 0xfecd, 0x4a1d, 0xe177, 0xbc6f, 0x2af3, 0xfdf2,
-0xc4cf, 0x3b3d, 0x1ebb, 0xd4a0, 0x319d, 0x221e, 0xaf94, 0xf1b0, 0x3313, 0xcaf9,
-0xf7f2, 0x4fd1, 0xeb5b, 0xf54e, 0x3faa, 0xd925, 0xb016, 0x2624, 0x012e, 0xc2f3,
-0x3e16, 0x255d, 0xce61, 0x2b67, 0x1e8d, 0xa020, 0xe075, 0x2e2f, 0xc930, 0xf3f3,
-0x4f96, 0xe6da, 0xef8a, 0x43fb, 0xdd85, 0xab7b, 0x2022, 0xfe5f, 0xba39, 0x346d,
-0x27b4, 0xd20a, 0x2bfd, 0x2882, 0xae6f, 0xe3d3, 0x2b38, 0xc9c6, 0xef8e, 0x49d8,
-0xeade, 0xf2c2, 0x46de, 0xe8ca, 0xb2fe, 0x208e, 0x0855, 0xc5c4, 0x338e, 0x29eb,
-0xd645, 0x257e, 0x260c, 0xb7e2, 0xebef, 0x3365, 0xd6d8, 0xf811, 0x518d, 0xf457,
-0xf134, 0x4558, 0xf41a, 0xb66e, 0x1a28, 0x0bd1, 0xcaa3, 0x31f9, 0x3045, 0xe17a,
-0x2ad4, 0x2f2d, 0xbd2b, 0xe13e, 0x2cfe, 0xd3bd, 0xea52, 0x4fb4, 0x020e, 0xf40a,
-0x4278, 0xf8f7, 0xb45e, 0x127c, 0x0af1, 0xc2d1, 0x2b03, 0x36f1, 0xdd10, 0x20d2,
-0x35ec, 0xc074, 0xd7bd, 0x2eef, 0xd9db, 0xe543, 0x52c9, 0x05cf, 0xec53, 0x41bb,
-0xfa65, 0xaf2a, 0x15c6, 0x1274, 0xbe0e, 0x2c97, 0x448e, 0xdd59, 0x1c74, 0x3817,
-0xbb2b, 0xcf5b, 0x2f9a, 0xdc0c, 0xe4f0, 0x586d, 0x096c, 0xe913, 0x42c2, 0xf921,
-0xa4d2, 0x0f94, 0x157d, 0xbee7, 0x2a97, 0x46c2, 0xe0bf, 0x1d38, 0x3786, 0xb9af,
-0xcb2a, 0x2dd9, 0xd952, 0xdcbe, 0x5596, 0x0bab, 0xea4b, 0x4531, 0xffe2, 0xa78b,
-0x0c61, 0x136f, 0xb532, 0x2148, 0x44ae, 0xd96e, 0x195c, 0x392c, 0xb898, 0xc8e9,
-0x3388, 0xef92, 0xcd85, 0x0ef6, 0xf796, 0x13e1, 0x506a, 0x028d, 0xcd42, 0x14f5,
-0xf58e, 0x9d81, 0xe29f, 0xfb3c, 0xcd66, 0x1bbf, 0x6302, 0x30d7, 0x14e4, 0x29bc,
-0xdf14, 0xae5e, 0xce80, 0xabdc, 0xca7e, 0x3503, 0x1ee4, 0xf688, 0x5aac, 0x62a7,
-0xd87d, 0xd4d5, 0xfc76, 0xb6dd, 0xa5b5, 0xf6e7, 0x0b99, 0x0665, 0x381b, 0x1f19,
-0x1206, 0x2ed5, 0xebdd, 0xb56d, 0xde2e, 0xf87e, 0xce4d, 0xed47, 0x2439, 0x121c,
-0x1266, 0x1483, 0x16c8, 0x10fd, 0x0650, 0xd754, 0xbaff, 0xf7e2, 0xda39, 0xcd45,
-0x2986, 0x40dc, 0x0e53, 0x182a, 0x50a1, 0x01de, 0xcb6e, 0xdc62, 0xb781, 0xcfc4,
-0xee54, 0xf542, 0x2240, 0x5981, 0x2c5e, 0xf8e5, 0x3e3b, 0x0d29, 0xaf98, 0xc3b7,
-0xd787, 0xd3b1, 0xe2e2, 0x19c0, 0x28df, 0x3943, 0x2fe3, 0x081e, 0x2922, 0x0f78,
-0xc962, 0xb6cc, 0xd979, 0xe6a6, 0xd121, 0x07cf, 0x3500, 0x3ad0, 0x2c2a, 0x2624,
-0x2c95, 0xfb6f, 0xd7be, 0xb61f, 0xc05e, 0xe300, 0xd931, 0x0c0c, 0x4eae, 0x4878,
-0x15a7, 0x2a43, 0x31b1, 0xdd24, 0xc4ea, 0xbda7, 0xc680, 0xe6be, 0xf0c6, 0x13f8,
-0x45f0, 0x4cdc, 0x09ee, 0x185b, 0x3039, 0xdd40, 0xc562, 0xd19d, 0xd51e, 0xdcc7,
-0xfbf1, 0x1f9a, 0x3311, 0x4108, 0x10a0, 0x1d6d, 0x368a, 0xebc0, 0xbacd, 0xc61c,
-0xe6be, 0xd8c6, 0xecc7, 0x2b4f, 0x3ad6, 0x3234, 0x16aa, 0x312b, 0x2c20, 0xe5cf,
-0xbf0c, 0xc2d3, 0xef02, 0xde96, 0xe42b, 0x3264, 0x4f6e, 0x2b87, 0x1502, 0x434e,
-0x2169, 0xd824, 0xcd4a, 0xcbe5, 0xe67d, 0xe8bc, 0xf5fe, 0x2bd2, 0x4fbf, 0x2b2a,
-0x05aa, 0x4482, 0x2857, 0xcb20, 0xc28b, 0xdaa2, 0xe5a8, 0xd616, 0xfaa0, 0x2fc3,
-0x4640, 0x2ce5, 0x0f5a, 0x3ab7, 0x1944, 0xcda3, 0xbbcb, 0xcda1, 0xe22a, 0xd491,
-0x0143, 0x3873, 0x3fbe, 0x22bb, 0x1736, 0x3ae6, 0x0407, 0xc3a8, 0xb9c4, 0xc437,
-0xdc67, 0xd7ba, 0x00f1, 0x3801, 0x41a0, 0x1951, 0x11c6, 0x35de, 0xf7fb, 0xbeac,
-0xb811, 0xc658, 0xdc21, 0xd8e4, 0x060e, 0x39e5, 0x4146, 0x14d2, 0x16dd, 0x36f4,
-0xed6d, 0xba86, 0xb9b4, 0xcb20, 0xdd7e, 0xdfe1, 0x0f15, 0x3b82, 0x3e9b, 0x1158,
-0x1b8a, 0x323f, 0xe8e2, 0xbdfb, 0xb835, 0xd09f, 0xddf2, 0xdd36, 0x148a, 0x40d3,
-0x3e5f, 0x13a7, 0x2794, 0x2f4a, 0xde17, 0xbd25, 0xb6e3, 0xcb99, 0xdc56, 0xe6b9,
-0x1ce9, 0x4836, 0x40a4, 0x1189, 0x2c70, 0x2966, 0xd436, 0xb74c, 0xb722, 0xd074,
-0xdc0f, 0xf37b, 0x2f67, 0x4c6c, 0x3aa1, 0x13df, 0x2e82, 0x1863, 0xcd4e, 0xbc3f,
-0xbce0, 0xd9c4, 0xe1be, 0xfb8d, 0x359d, 0x4c01, 0x3625, 0x17b8, 0x32ce, 0x1032,
-0xcc89, 0xbc30, 0xbdba, 0xe2ec, 0xe81c, 0x005e, 0x3db9, 0x512c, 0x2c97, 0x17fc,
-0x380c, 0x06f5, 0xcdb1, 0xc0d4, 0xbe6b, 0xe241, 0xead9, 0x05a4, 0x3a27, 0x518a,
-0x2c10, 0x187d, 0x3809, 0xfd0c, 0xc4ac, 0xbff0, 0xc939, 0xe3de, 0xe907, 0x0ded,
-0x3e36, 0x4e75, 0x2456, 0x1759, 0x31b3, 0xf547, 0xc449, 0xba76, 0xcb7c, 0xe629,
-0xeb17, 0x17cc, 0x43ae, 0x4970, 0x1dfb, 0x1c5c, 0x2c1b, 0xe97c, 0xc40d, 0xbedd,
-0xd492, 0xe90c, 0xea14, 0x18aa, 0x44ec, 0x43bf, 0x15aa, 0x2421, 0x2f68, 0xe453,
-0xc2c4, 0xbef4, 0xd4c2, 0xe5c8, 0xf22d, 0x2430, 0x475e, 0x4461, 0x187f, 0x2916,
-0x2d8a, 0xe382, 0xc1ee, 0xc2fa, 0xe144, 0xe6ea, 0xf400, 0x30a7, 0x50eb, 0x4265,
-0x1b39, 0x2f67, 0x2260, 0xde78, 0xc61b, 0xc3e2, 0xe4c5, 0xea6e, 0xf9b7, 0x32e4,
-0x4b24, 0x330a, 0x1529, 0x377b, 0x1ad4, 0xd298, 0xc471, 0xc39e, 0xdfcf, 0xe493,
-0xf83e, 0x339f, 0x5169, 0x3178, 0x0fe4, 0x3634, 0x10e7, 0xcad8, 0xc188, 0xc0cb,
-0xd97a, 0xe36b, 0x01cf, 0x3255, 0x49ca, 0x2dc9, 0x1019, 0x33a3, 0x059a, 0xbd42,
-0xb33f, 0xbe30, 0xd9b3, 0xdc31, 0x0338, 0x37ee, 0x44ae, 0x224f, 0x0cf2, 0x27ab,
-0xf5dc, 0xbd67, 0xaf02, 0xbe02, 0xde1c, 0xd738, 0x02b2, 0x3eba, 0x4074, 0x174f,
-0x1829, 0x2c82, 0xe72a, 0xbf61, 0xb6b3, 0xbe85, 0xe2b1, 0xe25f, 0x05c1, 0x4181,
-0x4a2b, 0x1512, 0x1a96, 0x326a, 0xe3c7, 0xbc8c, 0xb7af, 0xbd6f, 0xd849, 0xe90a,
-0x150e, 0x3ed0, 0x469e, 0x176f, 0x1b23, 0x2908, 0xdb26, 0xb2f3, 0xb1f8, 0xca6a,
-0xdb06, 0xe6a5, 0x1fb9, 0x4383, 0x3e5d, 0x1596, 0x1e94, 0x1cb0, 0xd8cf, 0xba95,
-0xaec4, 0xcef4, 0xe43f, 0xeaf7, 0x2443, 0x4766, 0x336a, 0x0e32, 0x27a3, 0x1356,
-0xcd5d, 0xc150, 0xb6ba, 0xd1d8, 0xe528, 0xee84, 0x2426, 0x4adf, 0x3667, 0x10cd,
-0x310e, 0x1388, 0xcbbb, 0xc47e, 0xbd1f, 0xd491, 0xe98e, 0x0244, 0x3289, 0x53b3,
-0x3eb9, 0x1566, 0x3290, 0x11e3, 0xcc07, 0xc004, 0xc4fd, 0xe223, 0xed0a, 0x10ae,
-0x3ff0, 0x5037, 0x36e6, 0x164f, 0x29a1, 0x0284, 0xcdb8, 0xbdcd, 0xc637, 0xed96,
-0xeeb1, 0x0cd0, 0x4050, 0x49bb, 0x239a, 0x1780, 0x2eab, 0xf6b6, 0xce3d, 0xbc38,
-0xc8a0, 0x00e6, 0xefad, 0x0021, 0x33f9, 0x3ae3, 0x3cd3, 0x3fb1, 0x1838, 0xd924,
-0xd541, 0xaecf, 0xa5de, 0xf7be, 0xfc4c, 0x140b, 0x790a, 0x7937, 0x1616, 0xfecc,
-0xe9f4, 0x93de, 0xa330, 0xc0f0, 0xcf7e, 0x2cbc, 0x6286, 0x4ccf, 0x462d, 0x450f,
-0xe74f, 0xa99c, 0xd6b1, 0xc669, 0xba55, 0xfefe, 0x25a9, 0x3149, 0x43ec, 0x1f26,
-0xede2, 0x0adf, 0xff6f, 0xbdad, 0xf121, 0x2c23, 0xf18d, 0xf0cc, 0x2718, 0xe6c1,
-0xbbba, 0x1d92, 0x14c7, 0xde85, 0x3e57, 0x31f4, 0xe295, 0x0f8d, 0xf992, 0xa267,
-0xd117, 0x1bec, 0xe179, 0x07c9, 0x5af9, 0x03a7, 0x02e9, 0x3014, 0xd04d, 0xa794,
-0xfb7e, 0xf282, 0xc715, 0x36b9, 0x3764, 0xea25, 0x307a, 0x1cb0, 0xb2ec, 0xd406,
-0x117c, 0xd2a9, 0xea54, 0x43e9, 0xfc21, 0xfaa3, 0x3fc1, 0xeafd, 0xb060, 0x0b4c,
-0x0ff9, 0xc461, 0x1954, 0x3040, 0xd984, 0x1601, 0x2825, 0xbc3f, 0xdbce, 0x3875,
-0xe248, 0xdd2e, 0x4e02, 0xfd2c, 0xd91c, 0x3749, 0xf658, 0xaa69, 0x13e1, 0x2498,
-0xcc14, 0x21ba, 0x3a26, 0xdb15, 0x1623, 0x2c3d, 0xba40, 0xcd2e, 0x2cf5, 0xe4ae,
-0xe186, 0x52e0, 0x0d31, 0xe5cf, 0x3778, 0xffc1, 0xac3d, 0xfddf, 0x1bac, 0xc8ec,
-0x14d4, 0x4029, 0xe79d, 0x15d6, 0x3792, 0xcc34, 0xca86, 0x3225, 0xf50a, 0xcf32,
-0x3e28, 0x12b9, 0xe181, 0x364b, 0x1002, 0xb4c9, 0x031c, 0x26d6, 0xd0a9, 0x1e6a,
-0x443a, 0xd350, 0x08d3, 0x41ed, 0xc7a2, 0xb99c, 0x2fe3, 0xff21, 0xdc75, 0x4839,
-0x19bb, 0xe84c, 0x32f7, 0x01b7, 0xaddf, 0xfef1, 0x1e1c, 0xcae8, 0x16e4, 0x4bda,
-0xecbb, 0x0caf, 0x3f24, 0xe0dc, 0xc4bc, 0x18da, 0xf67e, 0xdd77, 0x3908, 0x10f4,
-0xed5b, 0x4369, 0x1b8d, 0xb980, 0x0190, 0x297a, 0xc6e3, 0x009e, 0x4462, 0xea33,
-0x0155, 0x3cba, 0xe27f, 0xcbef, 0x2bda, 0xf9a0, 0xd4bc, 0x439f, 0x150b, 0xd559,
-0x344d, 0x1a5b, 0xaf57, 0xf935, 0x2de0, 0xcf9a, 0x0979, 0x49a9, 0xea95, 0x051a,
-0x3cdb, 0xd6df, 0xbc25, 0x2174, 0xf28b, 0xc89b, 0x4222, 0x2645, 0xdfc1, 0x315e,
-0x201e, 0xb2fc, 0xe3d4, 0x181b, 0xc442, 0xfd80, 0x4a43, 0xed31, 0xff1f, 0x4381,
-0xdf06, 0xb4dc, 0x1fd7, 0xf6dc, 0xbffe, 0x3a30, 0x24f3, 0xd6d6, 0x297b, 0x1c5d,
-0xaf37, 0xedb8, 0x286b, 0xc61d, 0xfe95, 0x515b, 0xe559, 0xf3c9, 0x4090, 0xd830,
-0xae85, 0x1db8, 0xf7ec, 0xc607, 0x3f9f, 0x264d, 0xd94a, 0x2a8a, 0x1485, 0xa002,
-0xdeaf, 0x235b, 0xc381, 0xfa49, 0x5796, 0xefa6, 0xf6b9, 0x4056, 0xd904, 0xa813,
-0x17bf, 0xf931, 0xbf26, 0x3e31, 0x2c1d, 0xd50a, 0x2d55, 0x22b9, 0xa846, 0xdf9f,
-0x28c5, 0xc598, 0xef6b, 0x51e5, 0xf17d, 0xfa6e, 0x46ce, 0xddcb, 0xac63, 0x1bcf,
-0xff42, 0xc08e, 0x3b8a, 0x30ab, 0xd540, 0x2b2a, 0x2b14, 0xb01e, 0xe003, 0x2eb4,
-0xd207, 0xf705, 0x5a04, 0xf5f1, 0xf4f2, 0x49c1, 0xe735, 0xac7d, 0x1ff2, 0x0bc1,
-0xc150, 0x3a15, 0x3cd0, 0xdc44, 0x29ee, 0x3079, 0xb504, 0xdcbb, 0x2cd7, 0xcfca,
-0xeed8, 0x5c84, 0xfe19, 0xf346, 0x4ec0, 0xf24e, 0xa9a2, 0x1b01, 0x120e, 0xbf61,
-0x31bd, 0x3ed0, 0xdca8, 0x27d7, 0x3553, 0xb79f, 0xddc0, 0x376a, 0xd743, 0xea45,
-0x592a, 0xf9f4, 0xe94c, 0x4a1d, 0xf552, 0xa9a1, 0x19d2, 0x14c6, 0xbc9b, 0x2b11,
-0x3913, 0xd2dc, 0x1f02, 0x340a, 0xb6b6, 0xd426, 0x33f8, 0xd9a8, 0xdc7f, 0x5123,
-0xfd3a, 0xde46, 0x40ce, 0xfa10, 0xa997, 0x14a8, 0x1bb4, 0xc08d, 0x2376, 0x3d24,
-0xd503, 0x166b, 0x35f1, 0xbc86, 0xd0fa, 0x36e8, 0xf1a1, 0xd628, 0x16ed, 0xf145,
-0x0d1a, 0x55e9, 0x09b3, 0xd0ea, 0x189e, 0xfae5, 0xa1d9, 0xe581, 0xfd1f, 0xd241,
-0x1ffa, 0x5b9f, 0x2d05, 0x1f94, 0x316b, 0xe330, 0xba22, 0xd9ab, 0xb354, 0xcfaa,
-0x3059, 0x1e34, 0xfcfc, 0x565e, 0x623a, 0xe738, 0xe027, 0xfe57, 0xc099, 0xb327,
-0xf470, 0x0c3c, 0x0e38, 0x38fd, 0x1a11, 0x0892, 0x3339, 0xf5c3, 0xbab1, 0xe297,
-0xf843, 0xce95, 0xe620, 0x1c2a, 0x09ee, 0x1283, 0x1b02, 0x1187, 0x188b, 0x0e86,
-0xd87e, 0xb652, 0xeca9, 0xdb2d, 0xc7dd, 0x1fe5, 0x379e, 0x0fd2, 0x1c45, 0x4c2e,
-0x1316, 0xd85d, 0xdfc8, 0xb6df, 0xc87f, 0xeb35, 0xe54a, 0x1628, 0x57e4, 0x3419,
-0xff6c, 0x4156, 0x1c74, 0xb5b4, 0xca06, 0xd49b, 0xc6db, 0xdff3, 0x0f42, 0x1c9b,
-0x38c2, 0x3cc3, 0x059b, 0x2a27, 0x2699, 0xce85, 0xb4f9, 0xd393, 0xdea9, 0xcdb3,
-0x03e7, 0x3281, 0x3d54, 0x3c61, 0x2583, 0x2ce2, 0x0c86, 0xdb4d, 0xb3bf, 0xbb9c,
-0xe353, 0xd3fa, 0x034f, 0x4cdb, 0x4ab4, 0x21fa, 0x2b59, 0x391f, 0xeb27, 0xc6cb,
-0xb8e4, 0xba9a, 0xe811, 0xec0e, 0x0c31, 0x4bdb, 0x5772, 0x163d, 0x1a19, 0x3f4d,
-0xe9e8, 0xc3a2, 0xce2a, 0xc788, 0xd9f4, 0xf83e, 0x1bc6, 0x3ce8, 0x5548, 0x1db0,
-0x1a55, 0x4521, 0xf1e2, 0xb3ab, 0xc2fd, 0xdbe1, 0xd800, 0xed52, 0x2c30, 0x402d,
-0x430b, 0x23ff, 0x260b, 0x2f76, 0xea68, 0xb3d7, 0xb28e, 0xe14a, 0xdd06, 0xe066,
-0x33b3, 0x51ec, 0x33b4, 0x1667, 0x3052, 0x1b77, 0xd41e, 0xc1bd, 0xb6c4, 0xd7a4,
-0xeae0, 0xe9c9, 0x2119, 0x50ee, 0x3348, 0x0504, 0x35a7, 0x2224, 0xc555, 0xbad4,
-0xc362, 0xd0c4, 0xdade, 0xf6c3, 0x247a, 0x463c, 0x3726, 0x098e, 0x2ae9, 0x1a2f,
-0xc9d7, 0xb0fe, 0xc012, 0xdaac, 0xd5e1, 0xf9b0, 0x351f, 0x47da, 0x2cc6, 0x10fb,
-0x2d9f, 0x068e, 0xc5e3, 0xb7fe, 0xc297, 0xe2b0, 0xe422, 0x01db, 0x36ef, 0x48cb,
-0x23b7, 0x10de, 0x3507, 0x0307, 0xc7bf, 0xbff3, 0xc77c, 0xe128, 0xe56e, 0x0857,
-0x3924, 0x4aaf, 0x2249, 0x103e, 0x31eb, 0xfa7b, 0xc42a, 0xbff2, 0xca69, 0xdf50,
-0xe715, 0x1070, 0x37d6, 0x4303, 0x1eac, 0x16ba, 0x3184, 0xf739, 0xc4f5, 0xba46,
-0xcd7e, 0xe4d0, 0xe592, 0x10ee, 0x3d09, 0x4044, 0x17ce, 0x2016, 0x2f3f, 0xe9e5,
-0xc633, 0xbad5, 0xc6f9, 0xdeac, 0xe624, 0x121c, 0x413b, 0x4301, 0x1783, 0x29fd,
-0x2ba5, 0xdaa4, 0xbe2e, 0xbb8e, 0xcbc8, 0xdde4, 0xf1e9, 0x21db, 0x439b, 0x4190,
-0x172e, 0x27a0, 0x21f8, 0xd636, 0xbad8, 0xb8bf, 0xd096, 0xdf64, 0xf8a8, 0x2b93,
-0x443b, 0x3b96, 0x185e, 0x26da, 0x10a6, 0xd167, 0xbdb5, 0xb977, 0xdb3a, 0xe708,
-0xfa86, 0x2f52, 0x4806, 0x3265, 0x17a3, 0x31bc, 0x0e05, 0xd510, 0xc461, 0xbd66,
-0xe192, 0xed77, 0x0119, 0x32ba, 0x50ed, 0x31ea, 0x16d3, 0x36ec, 0x0732, 0xcfc7,
-0xc460, 0xc184, 0xdf83, 0xea58, 0x0626, 0x3550, 0x5246, 0x2def, 0x16cd, 0x3427,
-0xfd3a, 0xc953, 0xbd3c, 0xc544, 0xe4ec, 0xf153, 0x166b, 0x3e10, 0x4e6d, 0x26d4,
-0x1968, 0x2f16, 0xf428, 0xcae0, 0xbedd, 0xccf8, 0xe956, 0xefa2, 0x1950, 0x4297,
-0x4a75, 0x1de5, 0x1955, 0x29ba, 0xeb91, 0xc61c, 0xbb12, 0xce33, 0xe7ce, 0xefe6,
-0x18c6, 0x3e32, 0x43c5, 0x1922, 0x1cc3, 0x20fd, 0xde2b, 0xbf55, 0xb70b, 0xd16f,
-0xe788, 0xef8e, 0x20c4, 0x4654, 0x3d93, 0x11d7, 0x1d2e, 0x15c5, 0xd810, 0xc122,
-0xb7df, 0xd5bd, 0xe934, 0xf5a0, 0x24cd, 0x4321, 0x356b, 0x10be, 0x2522, 0x0e25,
-0xcdbf, 0xc120, 0xbd1c, 0xd9ef, 0xe950, 0xf8ec, 0x2940, 0x4a04, 0x31e9, 0x09bb,
-0x2935, 0x0de2, 0xcd32, 0xc3e0, 0xc0ad, 0xd96f, 0xebee, 0x0617, 0x2f65, 0x4a9d,
-0x32b8, 0x104d, 0x2b20, 0x042c, 0xc6fe, 0xc0fc, 0xccb1, 0xe4c6, 0xe7e5, 0x0a2f,
-0x3646, 0x44a9, 0x27ed, 0x0f84, 0x2482, 0xf9ba, 0xc9c9, 0xbc46, 0xc6f1, 0xe7c9,
-0xe7b4, 0x0935, 0x38ab, 0x3dfb, 0x17f4, 0x1202, 0x2366, 0xe8cf, 0xc894, 0xc02b,
-0xc4e7, 0xe682, 0xe9b4, 0x07dc, 0x39bc, 0x4323, 0x1255, 0x11a3, 0x2383, 0xde38,
-0xc201, 0xc28c, 0xc797, 0xe30e, 0xf319, 0x11aa, 0x3329, 0x3e07, 0x11d9, 0x1242,
-0x2173, 0xdd6c, 0xbc12, 0xbfc4, 0xd3cc, 0xe301, 0xf14f, 0x1ed7, 0x3c0b, 0x3bbe,
-0x150a, 0x16d9, 0x1504, 0xded6, 0xc844, 0xc0c3, 0xdedd, 0xf0d7, 0xf666, 0x25d8,
-0x4424, 0x33d0, 0x130e, 0x2876, 0x1370, 0xd7a6, 0xcf17, 0xc604, 0xdfb9, 0xf3d2,
-0xfde9, 0x29bc, 0x4a3a, 0x328f, 0x0b59, 0x293f, 0x0f84, 0xd398, 0xd04b, 0xc938,
-0xdc96, 0xf077, 0x05ff, 0x2a1d, 0x46e9, 0x33e3, 0x0e06, 0x27af, 0x084b, 0xcbee,
-0xc5ed, 0xce50, 0xe4ec, 0xee95, 0x0fc4, 0x3481, 0x4291, 0x2ab8, 0x0ee7, 0x217a,
-0xfbca, 0xd072, 0xc584, 0xcdc2, 0xeeae, 0xf284, 0x0beb, 0x2a91, 0x499c, 0x4ab9,
-0x1751, 0xfb4e, 0xdff4, 0xc548, 0xaa11, 0xcb25, 0x079b, 0x0c5f, 0x3e98, 0x6247,
-0x3e07, 0x0f43, 0xf0e4, 0xca5f, 0xb34f, 0xd401, 0xc893, 0xf3d1, 0x4c26, 0x308b,
-0x22b3, 0x41c0, 0x2279, 0xdc8b, 0xdff8, 0xe310, 0xcceb, 0x027f, 0xf615, 0xee06,
-0x3db0, 0x2392, 0xe01d, 0x1366, 0x3415, 0xe34c, 0xf6fc, 0x29c3, 0xe8c4, 0xee7a,
-0x0fa2, 0xddee, 0xd84b, 0x1d1b, 0x1722, 0xff58, 0x3ac2, 0x1f74, 0xf03f, 0x1870,
-0xfcd6, 0xbff1, 0xe68f, 0x1180, 0xed1f, 0x0a12, 0x3895, 0x07ec, 0x0a31, 0x24b3,
-0xe648, 0xc9fc, 0x0734, 0xf757, 0xd412, 0x1f4f, 0x1e8b, 0xee37, 0x1f0e, 0x1be3,
-0xd43a, 0xefa3, 0x194b, 0xddce, 0xf237, 0x287d, 0xeedf, 0xf88e, 0x2f7f, 0xf704,
-0xd874, 0x1c88, 0x0972, 0xd8d5, 0x1702, 0x0f28, 0xe05e, 0x15f4, 0x1a7c, 0xd9ff,
-0xf6eb, 0x29b0, 0xf002, 0xf068, 0x23d5, 0xf4b8, 0xf046, 0x1d23, 0xf157, 0xd110,
-0x1519, 0x14cc, 0xdede, 0x142d, 0x1a12, 0xe515, 0x0b1c, 0x1636, 0xd4d5, 0xe629,
-0x1cf8, 0xe7c6, 0xea58, 0x2b1f, 0xfc3e, 0xeeea, 0x236a, 0xfb53, 0xcfca, 0x089d,
-0x0488, 0xd160, 0x0a55, 0x141d, 0xe5cd, 0x107d, 0x186d, 0xd8c8, 0xeaf7, 0x1870,
-0xe826, 0xe955, 0x18d7, 0xf4b0, 0xf2f4, 0x198f, 0xf637, 0xd898, 0x0a60, 0x099d,
-0xe121, 0x112c, 0x19f0, 0xe9f0, 0x0257, 0x16f3, 0xea68, 0xe825, 0x11db, 0xf73d,
-0xf784, 0x22c2, 0x01a7, 0xfa94, 0x2329, 0xff98, 0xd3ac, 0x066b, 0x0f20, 0xe092,
-0x0cc3, 0x1ddc, 0xf6f5, 0x1320, 0x1de5, 0xe877, 0xf111, 0x167b, 0xeabe, 0xf59b,
-0x2682, 0xf99e, 0xf763, 0x2689, 0x0359, 0xdfbd, 0x0e98, 0x0da2, 0xe78d, 0x0e20,
-0x0ddb, 0xeff0, 0x11e2, 0x1312, 0xe459, 0xf4b0, 0x1704, 0xee92, 0xf4ab, 0x1ec2,
-0xfc20, 0xf450, 0x169f, 0xfcad, 0xdbac, 0x0468, 0x089e, 0xe794, 0x0e53, 0x118e,
-0xefe9, 0x0e4a, 0x169a, 0xe1da, 0xebc0, 0x15eb, 0xefcb, 0xf2ee, 0x1beb, 0xfce8,
-0xfa9c, 0x1c17, 0xffdb, 0xe6b1, 0x0fc5, 0x065c, 0xe6be, 0x10a6, 0x0c31, 0xefee,
-0x1306, 0x13f9, 0xe94c, 0xfe45, 0x19f0, 0xf32a, 0xfe85, 0x1905, 0xf62a, 0xfd6b,
-0x1747, 0xf729, 0xeaea, 0x11d1, 0x0593, 0xf301, 0x1786, 0x0b5f, 0xf124, 0x0940,
-0x0668, 0xe6ec, 0xfe96, 0x1506, 0xf474, 0x04f3, 0x1923, 0xf708, 0xfe00, 0x1197,
-0xf0a5, 0xe784, 0x0dcb, 0xff73, 0xf084, 0x1476, 0x091e, 0xf640, 0x0af0, 0x0286,
-0xe773, 0xfd6b, 0x0efa, 0xf175, 0xf89a, 0x07af, 0xf9a6, 0x0516, 0x128d, 0x00ff,
-0xfb4e, 0x0ed0, 0xfc70, 0xe60e, 0xf53d, 0xf46c, 0xf494, 0x0bff, 0x1551, 0x06e1,
-0x0c9f, 0x0f55, 0xefab, 0xed70, 0xf731, 0xf0fe, 0xfd13, 0x0d56, 0x068f, 0x0174,
-0x0fee, 0xffe4, 0xea15, 0xfb9a, 0xffd4, 0xf166, 0xfe33, 0x0e6f, 0xfeb8, 0x0068,
-0x0cad, 0xf543, 0xef47, 0x0118, 0xf5be, 0xeb4f, 0x04dc, 0x09b3, 0xf586, 0x0081,
-0x05bb, 0xf123, 0xf60d, 0x03d9, 0xf8d9, 0xfe28, 0x0dac, 0xfb79, 0xf27c, 0xfe7f,
-0xf2c5, 0xeeb0, 0x04d2, 0x030d, 0xfb07, 0x0e9e, 0x0d11, 0xf686, 0xfc94, 0xffbf,
-0xed59, 0xf589, 0x05ab, 0xfa48, 0xffa7, 0x10c1, 0x014b, 0xfa25, 0x09af, 0xfdfc,
-0xf0ef, 0x03b9, 0x0400, 0xf635, 0x063f, 0x0b0b, 0xf9ca, 0x03dd, 0x0d8d, 0xfce6,
-0x00df, 0x0f4b, 0x024e, 0xff59, 0x0dc5, 0x0159, 0xf654, 0x067a, 0x0580, 0xfe5c,
-0x0e74, 0x0f97, 0x0220, 0x099e, 0x09f1, 0xf6cc, 0xfa19, 0x04a0, 0xfb69, 0x0199,
-0x10a2, 0x0726, 0x02f2, 0x0c0d, 0x00c5, 0xf7e4, 0x056d, 0x020c, 0xf921, 0x0880,
-0x0a05, 0xfc9b, 0x05b1, 0x0ba8, 0xfd73, 0x0126, 0x0afa, 0xfedb, 0xfe8e, 0x0754,
-0xff08, 0x010e, 0x0a12, 0xff2a, 0xfc7a, 0x0965, 0x0306, 0xfbf9, 0x0735, 0x05c2,
-0xfdbe, 0x020b, 0x01d4, 0xfd23, 0x035d, 0x0690, 0x0006, 0x0536, 0x0b42, 0x02fd,
-0x0048, 0x04d9, 0xffac, 0xfb96, 0x0522, 0x06ea, 0x01a3, 0x0640, 0x0721, 0x02e7,
-0x04ad, 0x0494, 0xfe70, 0x009e, 0x0380, 0xfafb, 0xfecf, 0x0890, 0x0224, 0xffd6,
-0x0613, 0x005f, 0xfada, 0x0129, 0xfdf3, 0xf949, 0x014d, 0x006d, 0xfa91, 0x0029,
-0x002c, 0xf7d8, 0xff02, 0x0615, 0xfbc4, 0xfc2b, 0x035b, 0xfb89, 0xf601, 0xfa4f,
-0xfabf, 0xfbd9, 0x00a3, 0xfe0a, 0xfbd4, 0x0009, 0xfe8b, 0xf866, 0xf96c, 0xfcbd,
-0xf750, 0xf6d5, 0xfee5, 0xfea6, 0xfc47, 0x00a5, 0x013f, 0xfaa4, 0xf910, 0xf98a,
-0xf6f0, 0xfa55, 0xfc01, 0xfac1, 0xff53, 0x001d, 0xfac1, 0xfb9d, 0xfef2, 0xf9c9,
-0xf9ce, 0xff10, 0xfabf, 0xfab8, 0xfe59, 0xfa05, 0xfa90, 0x00a1, 0xff54, 0xfdbe,
-0x0243, 0xff6b, 0xfac6, 0xfde2, 0xfc78, 0xf927, 0xfc12, 0xfe2f, 0xfc8a, 0xfe15,
-0x00a9, 0xff55, 0x0011, 0x0049, 0xfbfb, 0xfa18, 0xfd23, 0xfbc7, 0xf7ac, 0xfd25,
-0x019e, 0x0030, 0x02a9, 0x0344, 0x0053, 0x0036, 0x003f, 0xfc42, 0xfd77, 0x047f,
-0x022f, 0xffd5, 0x0747, 0x065b, 0xffcd, 0x058c, 0x0801, 0x00b8, 0x029f, 0x057c,
-0x0228, 0x02a9, 0x03ae, 0x0336, 0x052e, 0x06d3, 0x0355, 0x0367, 0x097b, 0x0767,
-0x040b, 0x0708, 0x062b, 0x00f3, 0x010e, 0x0624, 0x0661, 0x0641, 0x0870, 0x08cf,
-0x095c, 0x0672, 0x0114, 0x0064, 0x0450, 0x0372, 0x00f0, 0x074e, 0x0927, 0x0375,
-0x04d0, 0x06fa, 0x0278, 0x00e0, 0x023e, 0x0105, 0x0392, 0x0478, 0x01dc, 0x0633,
-0x06ad, 0x0137, 0x035b, 0x071e, 0x039a, 0x00b9, 0x0238, 0x0257, 0x03b3, 0x032c,
-0x00b5, 0x062b, 0x0920, 0x0425, 0x05d7, 0x09b0, 0x0457, 0x011e, 0x02cb, 0x0112,
-0x01e7, 0x03e0, 0x04a0, 0x09f0, 0x0993, 0x025d, 0x03ab, 0x06f0, 0x01ce, 0xffa9,
-0x0343, 0x03bf, 0x02bc, 0x0192, 0x0175, 0x03f8, 0x025f, 0xfe13, 0xffaf, 0x037b,
-0x017f, 0xff0d, 0x010c, 0x01cc, 0xff47, 0xfda7, 0xff79, 0xffc8, 0xfd08, 0xfdcd,
-0x01e5, 0x03c0, 0x00fa, 0xfdf8, 0xfdb9, 0xff87, 0xff9b, 0xfbe2, 0xfeae, 0x0380,
-0x0014, 0xfe6f, 0x0115, 0x0048, 0xfe1d, 0xff3b, 0xff7b, 0xff0a, 0x0012, 0xfed0,
-0xfed6, 0xffe0, 0xfcbf, 0xfbdb, 0x005d, 0xffb1, 0xf9ae, 0xfb2b, 0x0004, 0xff44,
-0xfc6c, 0xfb62, 0xfdf8, 0xff0d, 0xfbbb, 0xfae7, 0xfd8a, 0xfd70, 0xfaee, 0xfbe3,
-0xfdf3, 0xfc89, 0xfa9a, 0xfb6e, 0xfd82, 0xfcb8, 0xfaa3, 0xfc2a, 0xfeb9, 0xfc5c,
-0xf8a1, 0xfb85, 0x000c, 0xfee7, 0xfbc5, 0xfc1f, 0xfee8, 0xfdac, 0xfae0, 0xfc8b,
-0xfef5, 0xfebd, 0xfdf5, 0xfec1, 0x0023, 0xff0f, 0xfc4a, 0xfdd7, 0x00f5, 0xfea6,
-0xfd0c, 0x002f, 0x0087, 0xfc77, 0xfc93, 0x0024, 0x013b, 0x00dc, 0xfdb0, 0xfcbd,
-0x0060, 0xfed8, 0xfc65, 0xfff5, 0x0160, 0xfef8, 0x0045, 0x0243, 0x0065, 0xfff6,
-0x0124, 0x00f9, 0x00f5, 0x00ae, 0xff8e, 0x00df, 0x02e1, 0xffa3, 0xfea2, 0x0390,
-0x035d, 0xff35, 0xff1f, 0x009b, 0x0048, 0xffed, 0x0005, 0xfff7, 0x0019, 0xff23,
-0xfe36, 0xff91, 0x0112, 0x0088, 0xfff6, 0x00fa, 0x00a3, 0xfe18, 0xfe82, 0x01b6,
-0x00ae, 0xfead, 0x018f, 0x02ef, 0x0126, 0x002b, 0xffb6, 0x01e3, 0x0382, 0x00b0,
-0x00bd, 0x0402, 0x024e, 0x0002, 0x02e3, 0x0327, 0x00b6, 0x01cf, 0x02ca, 0x0250,
-0x0280, 0x01bd, 0x021d, 0x04f6, 0x0340, 0xfee9, 0x0095, 0x0305, 0x00bc, 0x012c,
-0x04fc, 0x0469, 0x0257, 0x027e, 0x0242, 0x01ad, 0x014b, 0x00c3, 0x0147, 0x037a,
-0x036a, 0x00b5, 0x0068, 0x0121, 0xff9a, 0xfec8, 0x0143, 0x0151, 0xfd18, 0xfced,
-0xffbd, 0x0066, 0x007d, 0xff3b, 0xfdd4, 0xfe9a, 0xff0d, 0xfdc1, 0xfe33, 0xffd7,
-0xfd45, 0xfbe9, 0xffc6, 0xff2d, 0xfb3e, 0xfd69, 0x0057, 0xff59, 0xffc4, 0x00ad,
-0x0017, 0xffc4, 0xfde4, 0xfc22, 0xfe08, 0x004b, 0xffd4, 0x0028, 0x0265, 0x00fa,
-0xfdc5, 0xfe0b, 0xff0e, 0xfe78, 0xfdca, 0xfe74, 0xff9b, 0x005c, 0x0106, 0x00eb,
-0x015c, 0x01a8, 0xff52, 0xfee2, 0x00ee, 0xffbe, 0xfec8, 0x010d, 0x01ab, 0x00d9,
-0x0106, 0x010d, 0x00e8, 0x0118, 0x00e8, 0x012b, 0x02b4, 0x0211, 0xff7a, 0xff8e,
-0x0115, 0x0100, 0x00de, 0x02dd, 0x0379, 0x00f9, 0xffd1, 0x0018, 0xfff6, 0xfffa,
-0x000c, 0xfff1, 0x0004, 0x0012, 0xffc4, 0x009c, 0x010c, 0xfffb, 0xffe4, 0x001a,
-0xfff2, 0xfffc, 0x0012, 0xffe2, 0x0015, 0x015a, 0x0257, 0x01c9, 0x004d, 0xfff9,
-0xffdd, 0x0059, 0x019b, 0x004f, 0x0095, 0x030f, 0x0191, 0xff96, 0x015d, 0x0296,
-0x01ee, 0x0205, 0x01f5, 0x0220, 0x0303, 0x0276, 0x01b6, 0x02a2, 0x02f4, 0x01f9,
-0x0209, 0x01e3, 0x0073, 0x00ad, 0x0219, 0x0205, 0x00f2, 0x000a, 0xffc0, 0x00c9,
-0x0105, 0xffac, 0x007c, 0x0198, 0x0051, 0xffcf, 0x001b, 0xfff4, 0x0001, 0x0002,
-0xfffe, 0xfffb, 0x0005, 0xfffd, 0xfff3, 0x0025, 0xff14, 0xfe3b, 0xffa5, 0xfffc,
-0xfee0, 0xff17, 0xffe8, 0x0010, 0xffec, 0x0017, 0xffe5, 0xff21, 0xfef3, 0xfef8,
-0xff4b, 0x002c, 0xffc0, 0xfee9, 0xffc3, 0x001f, 0xff65, 0xffbc, 0x001d, 0xfff2,
-000000, 0x0003, 0xfffc, 0xfffc, 0x000a, 0xffec, 0x0015, 0x0095, 0x002c, 0xffc9,
-0x006a, 0x0078, 0xfff2, 0xfffb, 0x0006, 0xfffa, 0x0002, 0xfffd, 0x0004, 0xfff4,
-0x0010, 0xfff2, 0xfff7, 0x003a, 0xfeb1, 0xfe3a, 0xfff4, 0x0020, 0xffde, 0x0015,
-0xfff6, 000000, 0x0002, 0xfffc, 0x0001, 0xfffe, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
-000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000 };
diff --git a/1.4.23-rc4/channels/ring_tone.h b/1.4.23-rc4/channels/ring_tone.h
deleted file mode 100644
index 559c42a7b..000000000
--- a/1.4.23-rc4/channels/ring_tone.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/* ringtone.h: Generated from frequencies 440 and 480
- by gentone. 200 samples */
-static short ringtone[200] = {
- 0, 11581, 21659, 28927, 32445, 31764, 26981, 18727,
- 8084, -3559, -14693, -23875, -29927, -32083, -30088, -24228,
- -15290, -4453, 6864, 17195, 25212, 29902, 30693, 27526,
- 20856, 11585, 944, -9673, -18899, -25560, -28837, -28357,
- -24244, -17089, -7868, 2192, 11780, 19667, 24872, 26779,
- 25212, 20450, 13179, 4396, -4731, -13019, -19421, -23164,
- -23839, -21446, -16384, -9384, -1408, 6484, 13281, 18145,
- 20517, 20182, 17286, 12301, 5951, -887, -7314, -12519,
- -15886, -17068, -16017, -12983, -8458, -3109, 2327, 7142,
- 10750, 12757, 13007, 11585, 8793, 5095, 1044, -2800,
- -5951, -8053, -8921, -8560, -7141, -4967, -2421, 104,
- 2260, 3791, 4567, 4589, 3977, 2941, 1733, 600,
- -257, -722, -772, -481, 0, 481, 772, 722,
- 257, -600, -1733, -2941, -3977, -4589, -4567, -3791,
- -2260, -104, 2421, 4967, 7141, 8560, 8921, 8053,
- 5951, 2800, -1044, -5095, -8793, -11585, -13007, -12757,
- -10750, -7142, -2327, 3109, 8458, 12983, 16017, 17068,
- 15886, 12519, 7314, 887, -5951, -12301, -17286, -20182,
- -20517, -18145, -13281, -6484, 1408, 9384, 16384, 21446,
- 23839, 23164, 19421, 13019, 4731, -4396, -13179, -20450,
- -25212, -26779, -24872, -19667, -11780, -2192, 7868, 17089,
- 24244, 28357, 28837, 25560, 18899, 9673, -944, -11585,
- -20856, -27526, -30693, -29902, -25212, -17195, -6864, 4453,
- 15290, 24228, 30088, 32083, 29927, 23875, 14693, 3559,
- -8084, -18727, -26981, -31764, -32445, -28927, -21659, -11581,
-
-};