diff --git a/.gitignore b/.gitignore
index ffc7fb18a3..fafe175062 100644
--- a/.gitignore
+++ b/.gitignore
@@ -171,6 +171,8 @@ BuildLog.htm
Win32/
win32/
!/libs/win32/
+!/libs/speex/win32/
+!/src/mod/endpoints/mod_gsmopen/gsmlib/gsmlib-1.10-patched-13ubuntu/win32/
*.suo
*.sdf
x64/
@@ -182,3 +184,6 @@ ipch/
/w32/Setup/obj
*dSYM*
/libs/xmlrpc-c/lib/expat/xmltok/nametab.h
+
+/UpgradeLog.*
+/_UpgradeReport_Files/
diff --git a/Freeswitch.2008.express.sln b/Freeswitch.2008.express.sln
index 6db9d58611..2c2adaced0 100644
--- a/Freeswitch.2008.express.sln
+++ b/Freeswitch.2008.express.sln
@@ -434,7 +434,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "16khz", "libs\win32\Sound_F
{87A1FE3D-F410-4C8E-9591-8C625985BC70} = {87A1FE3D-F410-4C8E-9591-8C625985BC70}
EndProjectSection
EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download 32khzsound", "libs\win32\Dowload 32khz Sounds.2008.vcproj", "{6E49F6C2-ADDA-4BFB-81FE-AB9AF51B455F}"
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download 32khzsound", "libs\win32\Download 32khz Sounds.2008.vcproj", "{6E49F6C2-ADDA-4BFB-81FE-AB9AF51B455F}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "32khz", "libs\win32\Sound_Files\32khz.2008.vcproj", "{464AAB78-5489-4916-BE51-BF8D61822311}"
ProjectSection(ProjectDependencies) = postProject
@@ -579,7 +579,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "make_at_dictionary", "libs\
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "make_modem_filter", "libs\spandsp\src\msvc\make_modem_filter.2008.vcproj", "{329A6FA0-0FCC-4435-A950-E670AEFA9838}"
EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download 32khz music", "libs\win32\Dowload 32khz music.2008.vcproj", "{1F0A8A77-E661-418F-BB92-82172AE43803}"
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download 32khz music", "libs\win32\Download 32khz music.2008.vcproj", "{1F0A8A77-E661-418F-BB92-82172AE43803}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download 8khz music", "libs\win32\Download 8khz music.2008.vcproj", "{4F5C9D55-98EF-4256-8311-32D7BD360406}"
EndProject
diff --git a/Freeswitch.2008.sln b/Freeswitch.2008.sln
index c3e0c0fbb8..1b121b30d9 100644
--- a/Freeswitch.2008.sln
+++ b/Freeswitch.2008.sln
@@ -1,2961 +1,2964 @@
-
-Microsoft Visual Studio Solution File, Format Version 10.00
-# Visual Studio 2008
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Codecs", "Codecs", "{F881ADA2-2F1A-4046-9FEB-191D9422D781}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Endpoints", "Endpoints", "{9460B5F1-0A95-41C4-BEB7-9C2C96459A7C}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Applications", "Applications", "{E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Dialplans", "Dialplans", "{C5F182F9-754A-4EC5-B50F-76ED02BE13F4}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Event Handlers", "Event Handlers", "{9ADF1E48-2F5C-4ED7-A893-596259FABFE0}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Formats", "Formats", "{A5A27244-AD24-46E5-B01B-840CD296C91D}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docs", "Docs", "{CBD81696-EFB4-4D2F-8451-1B8DAA86155A}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Directories", "Directories", "{B8F5B47B-8568-46EB-B320-64C17D2A98BC}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Languages", "Languages", "{0C808854-54D1-4230-BFF5-77B5FD905000}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ASR-TTS", "ASR-TTS", "{4CF6A6AC-07DE-4B9E-ABE1-7F98B64E0BB0}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Loggers", "Loggers", "{A7AB4405-FDB7-4853-9FBB-1516B1C3D80A}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "XML Interfaces", "XML Interfaces", "{F69A4A6B-9360-4EBB-A280-22AA3C455AC5}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_Libraries", "_Libraries", "{EB910B0D-F27D-4B62-B67B-DE834C99AC5B}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_Downloads", "_Downloads", "{C120A020-773F-4EA3-923F-B67AF28B750D}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "say", "say", "{6CD61A1D-797C-470A-BE08-8C31B68BB336}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_Config", "_Config", "{57D119DC-484F-420F-B9E9-8589FD9A8DF8}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Default", "Default", "{3B08FEFD-4D3D-4C16-BA94-EE83509E32A0}"
- ProjectSection(SolutionItems) = preProject
- conf\vanilla\freeswitch.xml = conf\vanilla\freeswitch.xml
- conf\vanilla\vars.xml = conf\vanilla\vars.xml
- EndProjectSection
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_Build System", "_Build System", "{DB1024A8-41BF-4AD7-9AE6-13202230D1F3}"
- ProjectSection(SolutionItems) = preProject
- acsite.m4 = acsite.m4
- bootstrap.sh = bootstrap.sh
- build\buildlib.sh = build\buildlib.sh
- configure.in = configure.in
- Makefile.am = Makefile.am
- build\modmake.rules.in = build\modmake.rules.in
- build\modules.conf.in = build\modules.conf.in
- libs\win32\util.vbs = libs\win32\util.vbs
- EndProjectSection
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "m4", "m4", "{CDE9B06A-3C27-4987-8FAE-DF1006BC705D}"
- ProjectSection(SolutionItems) = preProject
- build\config\ac_cflags_gcc_option.m4 = build\config\ac_cflags_gcc_option.m4
- build\config\ac_cflags_sun_option.m4 = build\config\ac_cflags_sun_option.m4
- build\config\ac_gcc_archflag.m4 = build\config\ac_gcc_archflag.m4
- build\config\ac_gcc_x86_cpuid.m4 = build\config\ac_gcc_x86_cpuid.m4
- build\config\ac_prog_gzip.m4 = build\config\ac_prog_gzip.m4
- build\config\ac_prog_wget.m4 = build\config\ac_prog_wget.m4
- build\config\ax_cc_maxopt.m4 = build\config\ax_cc_maxopt.m4
- build\config\ax_cflags_warn_all_ansi.m4 = build\config\ax_cflags_warn_all_ansi.m4
- build\config\ax_check_compiler_flags.m4 = build\config\ax_check_compiler_flags.m4
- build\config\ax_compiler_vendor.m4 = build\config\ax_compiler_vendor.m4
- EndProjectSection
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "autoload_configs", "autoload_configs", "{3C90CCF0-2CDD-4A7A-ACFF-208C1E271692}"
- ProjectSection(SolutionItems) = preProject
- conf\vanilla\autoload_configs\alsa.conf.xml = conf\vanilla\autoload_configs\alsa.conf.xml
- conf\vanilla\autoload_configs\conference.conf.xml = conf\vanilla\autoload_configs\conference.conf.xml
- conf\vanilla\autoload_configs\console.conf.xml = conf\vanilla\autoload_configs\console.conf.xml
- conf\vanilla\autoload_configs\dialplan_directory.conf.xml = conf\vanilla\autoload_configs\dialplan_directory.conf.xml
- conf\vanilla\autoload_configs\dingaling.conf.xml = conf\vanilla\autoload_configs\dingaling.conf.xml
- conf\vanilla\autoload_configs\enum.conf.xml = conf\vanilla\autoload_configs\enum.conf.xml
- conf\vanilla\autoload_configs\event_multicast.conf.xml = conf\vanilla\autoload_configs\event_multicast.conf.xml
- conf\vanilla\autoload_configs\event_socket.conf.xml = conf\vanilla\autoload_configs\event_socket.conf.xml
- conf\vanilla\autoload_configs\ivr.conf.xml = conf\vanilla\autoload_configs\ivr.conf.xml
- conf\vanilla\autoload_configs\java.conf.xml = conf\vanilla\autoload_configs\java.conf.xml
- conf\vanilla\autoload_configs\limit.conf.xml = conf\vanilla\autoload_configs\limit.conf.xml
- conf\vanilla\autoload_configs\local_stream.conf.xml = conf\vanilla\autoload_configs\local_stream.conf.xml
- conf\vanilla\autoload_configs\logfile.conf.xml = conf\vanilla\autoload_configs\logfile.conf.xml
- conf\vanilla\autoload_configs\modules.conf.xml = conf\vanilla\autoload_configs\modules.conf.xml
- conf\vanilla\autoload_configs\openmrcp.conf.xml = conf\vanilla\autoload_configs\openmrcp.conf.xml
- conf\vanilla\autoload_configs\portaudio.conf.xml = conf\vanilla\autoload_configs\portaudio.conf.xml
- conf\vanilla\autoload_configs\rss.conf.xml = conf\vanilla\autoload_configs\rss.conf.xml
- conf\vanilla\autoload_configs\sofia.conf.xml = conf\vanilla\autoload_configs\sofia.conf.xml
- conf\vanilla\autoload_configs\spidermonkey.conf.xml = conf\vanilla\autoload_configs\spidermonkey.conf.xml
- conf\vanilla\autoload_configs\switch.conf.xml = conf\vanilla\autoload_configs\switch.conf.xml
- conf\vanilla\autoload_configs\syslog.conf.xml = conf\vanilla\autoload_configs\syslog.conf.xml
- conf\vanilla\autoload_configs\voicemail.conf.xml = conf\vanilla\autoload_configs\voicemail.conf.xml
- conf\vanilla\autoload_configs\wanpipe.conf.xml = conf\vanilla\autoload_configs\wanpipe.conf.xml
- conf\vanilla\autoload_configs\woomera.conf.xml = conf\vanilla\autoload_configs\woomera.conf.xml
- conf\vanilla\autoload_configs\xml_cdr.conf.xml = conf\vanilla\autoload_configs\xml_cdr.conf.xml
- conf\vanilla\autoload_configs\xml_curl.conf.xml = conf\vanilla\autoload_configs\xml_curl.conf.xml
- conf\vanilla\autoload_configs\xml_rpc.conf.xml = conf\vanilla\autoload_configs\xml_rpc.conf.xml
- conf\vanilla\autoload_configs\zeroconf.conf.xml = conf\vanilla\autoload_configs\zeroconf.conf.xml
- EndProjectSection
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dialplan", "dialplan", "{C7E2382E-2C22-4D18-BF93-80C6A1FFA7AC}"
- ProjectSection(SolutionItems) = preProject
- conf\vanilla\dialplan\default.xml = conf\vanilla\dialplan\default.xml
- conf\vanilla\dialplan\public.xml = conf\vanilla\dialplan\public.xml
- EndProjectSection
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "directory", "directory", "{FC71C66E-E268-4EAD-B1F5-F008DC382E83}"
- ProjectSection(SolutionItems) = preProject
- conf\vanilla\directory\default.xml = conf\vanilla\directory\default.xml
- EndProjectSection
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "sip_profiles", "sip_profiles", "{8E2E8798-8B6F-4A55-8E4F-4E6FDE40ED26}"
- ProjectSection(SolutionItems) = preProject
- conf\vanilla\sip_profiles\external.xml = conf\vanilla\sip_profiles\external.xml
- conf\vanilla\sip_profiles\internal.xml = conf\vanilla\sip_profiles\internal.xml
- conf\vanilla\sip_profiles\nat.xml = conf\vanilla\sip_profiles\nat.xml
- EndProjectSection
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "lang", "lang", "{09455AA9-C243-4F16-A1A1-A016881A2765}"
- ProjectSection(SolutionItems) = preProject
- conf\vanilla\directory\default.xml = conf\vanilla\directory\default.xml
- EndProjectSection
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "en", "en", "{57199684-EC63-4A60-9DC6-11815AF6B413}"
- ProjectSection(SolutionItems) = preProject
- conf\vanilla\lang\en\en.xml = conf\vanilla\lang\en\en.xml
- EndProjectSection
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "de", "de", "{2DED4BA2-D6B0-4064-BB2A-76DE3AA49E7C}"
- ProjectSection(SolutionItems) = preProject
- conf\vanilla\lang\de\de.xml = conf\vanilla\lang\de\de.xml
- EndProjectSection
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "fr", "fr", "{D4A12E4C-DBDA-4614-BA26-3425AE9F60F5}"
- ProjectSection(SolutionItems) = preProject
- conf\vanilla\lang\fr\fr.xml = conf\vanilla\lang\fr\fr.xml
- EndProjectSection
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "demo", "demo", "{D3E5C8ED-3A6A-4FEA-92A2-48A0BA865358}"
- ProjectSection(SolutionItems) = preProject
- conf\vanilla\lang\de\demo\demo.xml = conf\vanilla\lang\de\demo\demo.xml
- EndProjectSection
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "vm", "vm", "{CC3E7F48-2590-49CB-AD8B-BE3650F55462}"
- ProjectSection(SolutionItems) = preProject
- conf\vanilla\lang\de\vm\tts.xml = conf\vanilla\lang\de\vm\tts.xml
- EndProjectSection
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "demo", "demo", "{765EF1B9-5027-4820-BC37-A44466A51631}"
- ProjectSection(SolutionItems) = preProject
- conf\vanilla\lang\en\demo\demo.xml = conf\vanilla\lang\en\demo\demo.xml
- EndProjectSection
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "vm", "vm", "{713E4747-1126-40B1-BD84-58F9A7745423}"
- ProjectSection(SolutionItems) = preProject
- conf\vanilla\lang\en\vm\sounds.xml = conf\vanilla\lang\en\vm\sounds.xml
- conf\vanilla\lang\en\vm\tts.xml = conf\vanilla\lang\en\vm\tts.xml
- EndProjectSection
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "demo", "demo", "{F1B71990-EB04-4EB5-B28A-BC3EB6F7E843}"
- ProjectSection(SolutionItems) = preProject
- conf\vanilla\lang\fr\demo\demo.xml = conf\vanilla\lang\fr\demo\demo.xml
- EndProjectSection
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "vm", "vm", "{3DAF028C-AB5B-4183-A01B-DCC43F5A87F0}"
- ProjectSection(SolutionItems) = preProject
- conf\vanilla\lang\fr\vm\sounds.xml = conf\vanilla\lang\fr\vm\sounds.xml
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FreeSwitchConsole", "w32\Console\FreeSwitchConsole.2008.vcproj", "{1AF3A893-F7BE-43DD-B697-8AB2397C0D67}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FreeSwitchCoreLib", "w32\Library\FreeSwitchCore.2008.vcproj", "{202D7A4E-760D-4D0E-AFA1-D7459CED30FF}"
- ProjectSection(ProjectDependencies) = postProject
- {D331904D-A00A-4694-A5A3-FCFF64AB5DBE} = {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}
- {8D04B550-D240-4A44-8A18-35DA3F7038D9} = {8D04B550-D240-4A44-8A18-35DA3F7038D9}
- {89385C74-5860-4174-9CAF-A39E7C48909C} = {89385C74-5860-4174-9CAF-A39E7C48909C}
- {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5} = {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}
- {F057DA7F-79E5-4B00-845C-EF446EF055E3} = {F057DA7F-79E5-4B00-845C-EF446EF055E3}
- {03207781-0D1C-4DB3-A71D-45C608F28DBD} = {03207781-0D1C-4DB3-A71D-45C608F28DBD}
- {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
- {87EE9DA4-DE1E-4448-8324-183C98DCA588} = {87EE9DA4-DE1E-4448-8324-183C98DCA588}
- {EEF031CB-FED8-451E-A471-91EC8D4F6750} = {EEF031CB-FED8-451E-A471-91EC8D4F6750}
- {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3} = {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_g729", "src\mod\codecs\mod_g729\mod_g729.2008.vcproj", "{1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_sndfile", "src\mod\formats\mod_sndfile\mod_sndfile.2008.vcproj", "{AFAC0568-7548-42D5-9F6A-8D3400A1E4F6}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
- {3D0370CA-BED2-4657-A475-32375CBCB6E4} = {3D0370CA-BED2-4657-A475-32375CBCB6E4}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_PortAudio", "src\mod\endpoints\mod_portaudio\mod_PortAudio.2008.vcproj", "{5FD31A25-5D83-4794-8BEE-904DAD84CE71}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- {0A18A071-125E-442F-AFF7-A3F68ABECF99} = {0A18A071-125E-442F-AFF7-A3F68ABECF99}
- {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_speex", "src\mod\codecs\mod_speex\mod_speex.2008.vcproj", "{5580D60E-0F77-4716-9CD4-B8E5986FA375}"
- ProjectSection(ProjectDependencies) = postProject
- {E972C52F-9E85-4D65-B19C-031E511E9DB4} = {E972C52F-9E85-4D65-B19C-031E511E9DB4}
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- {03207781-0D1C-4DB3-A71D-45C608F28DBD} = {03207781-0D1C-4DB3-A71D-45C608F28DBD}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "docs", "docs\docs.2008.vcproj", "{1A1FF289-4FD6-4285-A422-D31DD67A4723}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_dialplan_xml", "src\mod\dialplans\mod_dialplan_xml\mod_dialplan_xml.2008.vcproj", "{07113B25-D3AF-4E04-BA77-4CD1171F022C}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_ldap", "src\mod\directories\mod_ldap\mod_ldap.2008.vcproj", "{EC3E5C7F-EE09-47E2-80FE-546363D14A98}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_dialplan_directory", "src\mod\dialplans\mod_dialplan_directory\mod_dialplan_directory.2008.vcproj", "{A27CCA23-1541-4337-81A4-F0A6413078A0}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_event_multicast", "src\mod\event_handlers\mod_event_multicast\mod_event_multicast.2008.vcproj", "{784113EF-44D9-4949-835D-7065D3C7AD08}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libteletone", "libs\libteletone\libteletone.2008.vcproj", "{89385C74-5860-4174-9CAF-A39E7C48909C}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_spidermonkey", "src\mod\languages\mod_spidermonkey\mod_spidermonkey.2008.vcproj", "{1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
- {87EE9DA4-DE1E-4448-8324-183C98DCA588} = {87EE9DA4-DE1E-4448-8324-183C98DCA588}
- {204FA0DE-305D-4414-AE2E-F195A23F390D} = {204FA0DE-305D-4414-AE2E-F195A23F390D}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_cepstral", "src\mod\asr_tts\mod_cepstral\mod_cepstral.2008.vcproj", "{692F6330-4D87-4C82-81DF-40DB5892636E}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_ilbc", "src\mod\codecs\mod_ilbc\mod_ilbc.2008.vcproj", "{D3EC0AFF-76FC-4210-A825-9A17410660A3}"
- ProjectSection(ProjectDependencies) = postProject
- {9A5DDF08-C88C-4A35-B7F6-D605228446BD} = {9A5DDF08-C88C-4A35-B7F6-D605228446BD}
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_dingaling", "src\mod\endpoints\mod_dingaling\mod_dingaling.2008.vcproj", "{FFAA4C52-3A53-4F99-90C1-D59D1F0427F3}"
- ProjectSection(ProjectDependencies) = postProject
- {1906D736-08BD-4EE1-924F-B536249B9A54} = {1906D736-08BD-4EE1-924F-B536249B9A54}
- {D331904D-A00A-4694-A5A3-FCFF64AB5DBE} = {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- {B4B62169-5AD4-4559-8707-3D933AC5DB39} = {B4B62169-5AD4-4559-8707-3D933AC5DB39}
- {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
- {E727E8F6-935D-46FE-8B0E-37834748A0E3} = {E727E8F6-935D-46FE-8B0E-37834748A0E3}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_commands", "src\mod\applications\mod_commands\mod_commands.2008.vcproj", "{30A5B29C-983E-4580-9FD0-D647CCDCC7EB}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_console", "src\mod\loggers\mod_console\mod_console.2008.vcproj", "{1C453396-D912-4213-89FD-9B489162B7B5}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_xml_rpc", "src\mod\xml_int\mod_xml_rpc\mod_xml_rpc.2008.vcproj", "{CBEC7225-0C21-4DA8-978E-1F158F8AD950}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- {2390F054-A7F1-4CB9-ACB0-F46EC6E77B5B} = {2390F054-A7F1-4CB9-ACB0-F46EC6E77B5B}
- {A4D67895-E709-40C7-82B6-DE1D12DDDE04} = {A4D67895-E709-40C7-82B6-DE1D12DDDE04}
- {510BDAA8-C04D-47DB-8482-E6AF380D3E07} = {510BDAA8-C04D-47DB-8482-E6AF380D3E07}
- {E5A9BCDA-B82D-4B08-B23E-9A782E367888} = {E5A9BCDA-B82D-4B08-B23E-9A782E367888}
- {3CF7C0E0-07C2-473A-A1E4-2274AEEC1268} = {3CF7C0E0-07C2-473A-A1E4-2274AEEC1268}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_rss", "src\mod\applications\mod_rss\mod_rss.2008.vcproj", "{B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_conference", "src\mod\applications\mod_conference\mod_conference.2008.vcproj", "{C24FB505-05D7-4319-8485-7540B44C8603}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_dptools", "src\mod\applications\mod_dptools\mod_dptools.2008.vcproj", "{B5881A85-FE70-4F64-8607-2CAAE52669C6}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_event_socket", "src\mod\event_handlers\mod_event_socket\mod_event_socket.2008.vcproj", "{05515420-16DE-4E63-BE73-85BE85BA5142}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libdingaling", "libs\libdingaling\libdingaling.2008.vcproj", "{1906D736-08BD-4EE1-924F-B536249B9A54}"
- ProjectSection(ProjectDependencies) = postProject
- {F057DA7F-79E5-4B00-845C-EF446EF055E3} = {F057DA7F-79E5-4B00-845C-EF446EF055E3}
- {E727E8F6-935D-46FE-8B0E-37834748A0E3} = {E727E8F6-935D-46FE-8B0E-37834748A0E3}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libsrtp", "libs\srtp\libsrtp.2008.vcproj", "{EEF031CB-FED8-451E-A471-91EC8D4F6750}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libsqlite", "libs\win32\sqlite\sqlite.2008.vcproj", "{6EDFEFD5-3596-4FA9-8EBA-B331547B35A3}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpcre", "libs\win32\pcre\libpcre.2008.vcproj", "{8D04B550-D240-4A44-8A18-35DA3F7038D9}"
- ProjectSection(ProjectDependencies) = postProject
- {1CED5987-A529-46DC-B30F-870D85FF9C94} = {1CED5987-A529-46DC-B30F-870D85FF9C94}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpcre Generate pcre_chartables.c", "libs\win32\pcre\pcre_chartables.c.2008.vcproj", "{1CED5987-A529-46DC-B30F-870D85FF9C94}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libapr", "libs\win32\apr\libapr.2008.vcproj", "{F6C55D93-B927-4483-BB69-15AEF3DD2DFF}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libaprutil", "libs\win32\apr-util\libaprutil.2008.vcproj", "{F057DA7F-79E5-4B00-845C-EF446EF055E3}"
- ProjectSection(ProjectDependencies) = postProject
- {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
- {155844C3-EC5F-407F-97A4-A2DDADED9B2F} = {155844C3-EC5F-407F-97A4-A2DDADED9B2F}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "iksemel", "libs\win32\iksemel\iksemel.2008.vcproj", "{E727E8F6-935D-46FE-8B0E-37834748A0E3}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libsndfile", "libs\win32\libsndfile\libsndfile.2008.vcproj", "{3D0370CA-BED2-4657-A475-32375CBCB6E4}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "curllib", "libs\win32\curl\curllib.2008.vcproj", "{87EE9DA4-DE1E-4448-8324-183C98DCA588}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xml", "libs\win32\apr-util\xml.2008.vcproj", "{155844C3-EC5F-407F-97A4-A2DDADED9B2F}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "js", "libs\win32\js\js.2008.vcproj", "{204FA0DE-305D-4414-AE2E-F195A23F390D}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_sofia", "src\mod\endpoints\mod_sofia\mod_sofia.2008.vcproj", "{0DF3ABD0-DDC0-4265-B778-07C66780979B}"
- ProjectSection(ProjectDependencies) = postProject
- {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4} = {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}
- {D331904D-A00A-4694-A5A3-FCFF64AB5DBE} = {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- {B4B62169-5AD4-4559-8707-3D933AC5DB39} = {B4B62169-5AD4-4559-8707-3D933AC5DB39}
- {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
- {70A49BC2-7500-41D0-B75D-EDCC5BE987A0} = {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libsofia_sip_ua_static", "libs\win32\sofia\libsofia_sip_ua_static.2008.vcproj", "{70A49BC2-7500-41D0-B75D-EDCC5BE987A0}"
- ProjectSection(ProjectDependencies) = postProject
- {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4} = {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}
- {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A} = {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}
- {D331904D-A00A-4694-A5A3-FCFF64AB5DBE} = {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}
- {B4B62169-5AD4-4559-8707-3D933AC5DB39} = {B4B62169-5AD4-4559-8707-3D933AC5DB39}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download PTHREAD", "libs\win32\Download PTHREAD.2008.vcproj", "{8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pthread", "libs\win32\pthread\pthread.2008.vcproj", "{DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}"
- ProjectSection(ProjectDependencies) = postProject
- {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A} = {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_g723_1", "src\mod\codecs\mod_g723_1\mod_g723_1.2008.vcproj", "{FEA1EEF7-876F-48DE-88BF-C0E3E606D758}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_native_file", "src\mod\formats\mod_native_file\mod_native_file.2008.vcproj", "{9254C4B0-6F60-42B6-BB3A-36D63FC001C7}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_spidermonkey_core_db", "src\mod\languages\mod_spidermonkey\mod_spidermonkey_core_db.2008.vcproj", "{ACFFF684-4D19-4D48-AF12-88EA1D778BDF}"
- ProjectSection(ProjectDependencies) = postProject
- {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F} = {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
- {204FA0DE-305D-4414-AE2E-F195A23F390D} = {204FA0DE-305D-4414-AE2E-F195A23F390D}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_spidermonkey_teletone", "src\mod\languages\mod_spidermonkey\mod_spidermonkey_teletone.2008.vcproj", "{8F992C49-6C51-412F-B2A3-34EAB708EB65}"
- ProjectSection(ProjectDependencies) = postProject
- {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F} = {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- {89385C74-5860-4174-9CAF-A39E7C48909C} = {89385C74-5860-4174-9CAF-A39E7C48909C}
- {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
- {204FA0DE-305D-4414-AE2E-F195A23F390D} = {204FA0DE-305D-4414-AE2E-F195A23F390D}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_enum", "src\mod\applications\mod_enum\mod_enum.2008.vcproj", "{71A967D5-0E99-4CEF-A587-98836EE6F2EF}"
- ProjectSection(ProjectDependencies) = postProject
- {23B4D303-79FC-49E0-89E2-2280E7E28940} = {23B4D303-79FC-49E0-89E2-2280E7E28940}
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_spidermonkey_odbc", "src\mod\languages\mod_spidermonkey\mod_spidermonkey_odbc.2008.vcproj", "{0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}"
- ProjectSection(ProjectDependencies) = postProject
- {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F} = {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
- {204FA0DE-305D-4414-AE2E-F195A23F390D} = {204FA0DE-305D-4414-AE2E-F195A23F390D}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_xml_curl", "src\mod\xml_int\mod_xml_curl\mod_xml_curl.2008.vcproj", "{AB91A099-7690-4ECF-8994-E458F4EA1ED4}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- {87EE9DA4-DE1E-4448-8324-183C98DCA588} = {87EE9DA4-DE1E-4448-8324-183C98DCA588}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_say_en", "src\mod\say\mod_say_en\mod_say_en.2008.vcproj", "{988CACF7-3FCB-4992-BE69-77872AE67DC8}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "portaudio", "libs\portaudio\build\msvc\portaudio.2008.vcproj", "{0A18A071-125E-442F-AFF7-A3F68ABECF99}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_xml_cdr", "src\mod\xml_int\mod_xml_cdr\mod_xml_cdr.2008.vcproj", "{08DAD348-9E0A-4A2E-97F1-F1E7E24A7836}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
- {87EE9DA4-DE1E-4448-8324-183C98DCA588} = {87EE9DA4-DE1E-4448-8324-183C98DCA588}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_amr", "src\mod\codecs\mod_amr\mod_amr.2008.vcproj", "{8DEB383C-4091-4F42-A56F-C9E46D552D79}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_h26x", "src\mod\codecs\mod_h26x\mod_h26x.2008.vcproj", "{2C3C2423-234B-4772-8899-D3B137E5CA35}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_esf", "src\mod\applications\mod_esf\mod_esf.2008.vcproj", "{3850D93A-5F24-4922-BC1C-74D08C37C256}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_local_stream", "src\mod\formats\mod_local_stream\mod_local_stream.2008.vcproj", "{2CA40887-1622-46A1-A7F9-17FD7E7E545B}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_spidermonkey_socket", "src\mod\languages\mod_spidermonkey\mod_spidermonkey_socket.2008.vcproj", "{028C7278-05D7-4E18-82FE-BE231B844F41}"
- ProjectSection(ProjectDependencies) = postProject
- {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F} = {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- {204FA0DE-305D-4414-AE2E-F195A23F390D} = {204FA0DE-305D-4414-AE2E-F195A23F390D}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_voicemail", "src\mod\applications\mod_voicemail\mod_voicemail.2008.vcproj", "{D7F1E3F2-A3F4-474C-8555-15122571AF52}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_say_de", "src\mod\say\mod_say_de\mod_say_de.2008.vcproj", "{5BC072DB-3826-48EA-AF34-FE32AA01E83B}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_say_es", "src\mod\say\mod_say_es\mod_say_es.2008.vcproj", "{FA429E98-8B03-45E6-A096-A4BC5E821DE4}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_say_fr", "src\mod\say\mod_say_fr\mod_say_fr.2008.vcproj", "{06E3A538-AB32-44F2-B477-755FF9CB5D37}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_say_it", "src\mod\say\mod_say_it\mod_say_it.2008.vcproj", "{6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_say_nl", "src\mod\say\mod_say_nl\mod_say_nl.2008.vcproj", "{A4B122CF-5196-476B-8C0E-D8BD59AC3C14}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_fifo", "src\mod\applications\mod_fifo\mod_fifo.2008.vcproj", "{75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_db", "src\mod\applications\mod_db\mod_db.2008.vcproj", "{F6A33240-8F29-48BD-98F0-826995911799}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_expr", "src\mod\applications\mod_expr\mod_expr.2008.vcproj", "{65A6273D-FCAB-4C55-B09E-65100141A5D4}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_dialplan_asterisk", "src\mod\dialplans\mod_dialplan_asterisk\mod_dialplan_asterisk.2008.vcproj", "{E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_logfile", "src\mod\loggers\mod_logfile\mod_logfile.2008.vcproj", "{D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_cdr_csv", "src\mod\event_handlers\mod_cdr_csv\mod_cdr_csv.2008.vcproj", "{44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_tone_stream", "src\mod\formats\mod_tone_stream\mod_tone_stream.2008.vcproj", "{6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- {89385C74-5860-4174-9CAF-A39E7C48909C} = {89385C74-5860-4174-9CAF-A39E7C48909C}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_fsv", "src\mod\applications\mod_fsv\mod_fsv.2008.vcproj", "{E3246D17-E29B-4AB5-962A-C69B0C5837BB}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_spidermonkey_curl", "src\mod\languages\mod_spidermonkey\mod_spidermonkey_curl.2008.vcproj", "{36E854E3-CE12-4348-A125-CCF3F9D74813}"
- ProjectSection(ProjectDependencies) = postProject
- {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F} = {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- {87EE9DA4-DE1E-4448-8324-183C98DCA588} = {87EE9DA4-DE1E-4448-8324-183C98DCA588}
- {204FA0DE-305D-4414-AE2E-F195A23F390D} = {204FA0DE-305D-4414-AE2E-F195A23F390D}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_lua", "src\mod\languages\mod_lua\mod_lua.2008.vcproj", "{7B077E7F-1BE7-4291-AB86-55E527B25CAC}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- {D0B36172-CD76-454A-9B89-990025266C2A} = {D0B36172-CD76-454A-9B89-990025266C2A}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download sphinxbase", "libs\win32\Download sphinxbase.2008.vcproj", "{4F92B672-DADB-4047-8D6A-4BB3796733FD}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download sphinxmodel", "libs\win32\Download sphinxmodel.2008.vcproj", "{2DEE4895-1134-439C-B688-52203E57D878}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download pocketsphinx", "libs\win32\Download pocketsphinx.2008.vcproj", "{AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sphinxbase", "libs\win32\sphinxbase\sphinxbase.2008.vcproj", "{2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}"
- ProjectSection(ProjectDependencies) = postProject
- {4F92B672-DADB-4047-8D6A-4BB3796733FD} = {4F92B672-DADB-4047-8D6A-4BB3796733FD}
- {2DEE4895-1134-439C-B688-52203E57D878} = {2DEE4895-1134-439C-B688-52203E57D878}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pocketsphinx", "libs\win32\pocketsphinx\pocketsphinx.2008.vcproj", "{94001A0E-A837-445C-8004-F918F10D0226}"
- ProjectSection(ProjectDependencies) = postProject
- {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D} = {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}
- {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E} = {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_pocketsphinx", "src\mod\asr_tts\mod_pocketsphinx\mod_pocketsphinx.2008.vcproj", "{2286DA73-9FC5-45BC-A508-85994C3317AB}"
- ProjectSection(ProjectDependencies) = postProject
- {94001A0E-A837-445C-8004-F918F10D0226} = {94001A0E-A837-445C-8004-F918F10D0226}
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- {4F92B672-DADB-4047-8D6A-4BB3796733FD} = {4F92B672-DADB-4047-8D6A-4BB3796733FD}
- {2DEE4895-1134-439C-B688-52203E57D878} = {2DEE4895-1134-439C-B688-52203E57D878}
- {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D} = {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}
- {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E} = {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download 8khzsound", "libs\win32\Download 8khz Sounds.2008.vcproj", "{3CE1DC99-8246-4DB1-A709-74F19F08EC67}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sound Files", "Sound Files", "{4F227C26-768F-46A3-8684-1D08A46FB374}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download 16khzsound", "libs\win32\Download 16khz Sounds.2008.vcproj", "{87A1FE3D-F410-4C8E-9591-8C625985BC70}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "8khz", "libs\win32\Sound_Files\8khz.2008.vcproj", "{7A8D8174-B355-4114-AFC1-04777CB9DE0A}"
- ProjectSection(ProjectDependencies) = postProject
- {3CE1DC99-8246-4DB1-A709-74F19F08EC67} = {3CE1DC99-8246-4DB1-A709-74F19F08EC67}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "16khz", "libs\win32\Sound_Files\16khz.2008.vcproj", "{7EB71250-F002-4ED8-92CA-CA218114537A}"
- ProjectSection(ProjectDependencies) = postProject
- {87A1FE3D-F410-4C8E-9591-8C625985BC70} = {87A1FE3D-F410-4C8E-9591-8C625985BC70}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download 32khzsound", "libs\win32\Dowload 32khz Sounds.2008.vcproj", "{6E49F6C2-ADDA-4BFB-81FE-AB9AF51B455F}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "32khz", "libs\win32\Sound_Files\32khz.2008.vcproj", "{464AAB78-5489-4916-BE51-BF8D61822311}"
- ProjectSection(ProjectDependencies) = postProject
- {6E49F6C2-ADDA-4BFB-81FE-AB9AF51B455F} = {6E49F6C2-ADDA-4BFB-81FE-AB9AF51B455F}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "flite", "libs\win32\flite\flite.2008.vcproj", "{0AD1177E-1FD8-4643-9391-431467A11084}"
- ProjectSection(ProjectDependencies) = postProject
- {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B} = {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_flite", "src\mod\asr_tts\mod_flite\mod_flite.2008.vcproj", "{66444AEE-554C-11DD-A9F0-8C5D56D89593}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B} = {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}
- {0AD1177E-1FD8-4643-9391-431467A11084} = {0AD1177E-1FD8-4643-9391-431467A11084}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download FLITE", "libs\win32\Download FLITE.2008.vcproj", "{D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download LAME", "libs\win32\Download LAME.2008.vcproj", "{D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download LIBSHOUT", "libs\win32\Download LIBSHOUT.2008.vcproj", "{D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download OGG", "libs\win32\Download OGG.2008.vcproj", "{D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmp3lame", "libs\win32\libmp3lame\libmp3lame_vc7.vcproj", "{E316772F-5D8F-4F2A-8F71-094C3E859D34}"
- ProjectSection(ProjectDependencies) = postProject
- {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B} = {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libshout", "libs\win32\libshout\libshout.vcproj", "{D3D8B329-20BE-475E-9E83-653CEA0E0EF5}"
- ProjectSection(ProjectDependencies) = postProject
- {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B} = {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}
- {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4} = {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_shout", "src\mod\formats\mod_shout\mod_shout.vcproj", "{38FE0559-9910-43A8-9E45-3E5004C27692}"
- ProjectSection(ProjectDependencies) = postProject
- {D3D8B329-20BE-475E-9E83-653CEA0E0EF5} = {D3D8B329-20BE-475E-9E83-653CEA0E0EF5}
- {E316772F-5D8F-4F2A-8F71-094C3E859D34} = {E316772F-5D8F-4F2A-8F71-094C3E859D34}
- {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4} = {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- {419C8F80-D858-4B48-A25C-AF4007608137} = {419C8F80-D858-4B48-A25C-AF4007608137}
- {87EE9DA4-DE1E-4448-8324-183C98DCA588} = {87EE9DA4-DE1E-4448-8324-183C98DCA588}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libogg", "libs\win32\libogg\libogg.2008.vcproj", "{0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4}"
- ProjectSection(ProjectDependencies) = postProject
- {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B} = {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_snom", "src\mod\applications\mod_snom\mod_snom.2008.vcproj", "{2A3D00C6-588D-4E86-81AC-9EF5EDE86E03}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_say_zh", "src\mod\say\mod_say_zh\mod_say_zh.2008.vcproj", "{B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_managed", "src\mod\languages\mod_managed\mod_managed.vcproj", "{7B42BDA1-72C0-4378-A9B6-5C530F8CD61E}"
- ProjectSection(ProjectDependencies) = postProject
- {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0} = {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FreeSWITCH.Managed", "src\mod\languages\mod_managed\managed\FreeSWITCH.Managed.csproj", "{834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download mpg123", "libs\win32\Download mpg123.2008.vcproj", "{E796E337-DE78-4303-8614-9A590862EE95}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmpg123", "libs\win32\mpg123\libmpg123.2008.vcproj", "{419C8F80-D858-4B48-A25C-AF4007608137}"
- ProjectSection(ProjectDependencies) = postProject
- {E796E337-DE78-4303-8614-9A590862EE95} = {E796E337-DE78-4303-8614-9A590862EE95}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_loopback", "src\mod\endpoints\mod_loopback\mod_loopback.2008.vcproj", "{B3F424EC-3D8F-417C-B244-3919D5E1A577}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_vmd", "src\mod\applications\mod_vmd\mod_vmd.2008.vcproj", "{14E4A972-9CFB-436D-B0A5-4943F3F80D47}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libg722_1", "libs\win32\libg722_1\libg722_1.vcproj", "{1BC8A8EC-E03B-44DF-BCD9-088650F4D29C}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_siren", "src\mod\codecs\mod_siren\mod_siren.2008.vcproj", "{0B6C905B-142E-4999-B39D-92FF7951E921}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C} = {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "esl", "libs\esl\src\esl.2008.vcproj", "{CF405366-9558-4AE8-90EF-5E21B51CCB4E}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fs_cli", "libs\esl\fs_cli.2008.vcproj", "{D2FB8043-D208-4AEE-8F18-3B5857C871B9}"
- ProjectSection(ProjectDependencies) = postProject
- {CF405366-9558-4AE8-90EF-5E21B51CCB4E} = {CF405366-9558-4AE8-90EF-5E21B51CCB4E}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_easyroute", "src\mod\applications\mod_easyroute\mod_easyroute.2008.vcproj", "{329FD5B0-EF28-4606-86D0-F6EA21CF8E36}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_lcr", "src\mod\applications\mod_lcr\mod_lcr.2008.vcproj", "{1A3793D1-05D1-4B57-9B0F-5AF3E79DC439}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libtiff", "libs\spandsp\src\libtiff.2008.vcproj", "{401A40CD-5DB4-4E34-AC68-FA99E9FAC014}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libspandsp", "libs\spandsp\src\libspandsp.2008.vcproj", "{1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}"
- ProjectSection(ProjectDependencies) = postProject
- {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A} = {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}
- {329A6FA0-0FCC-4435-A950-E670AEFA9838} = {329A6FA0-0FCC-4435-A950-E670AEFA9838}
- {DEE932AB-5911-4700-9EEB-8C7090A0A330} = {DEE932AB-5911-4700-9EEB-8C7090A0A330}
- {401A40CD-5DB4-4E34-AC68-FA99E9FAC014} = {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libspeex", "libs\speex\win32\VS2008\libspeex\libspeex.vcproj", "{E972C52F-9E85-4D65-B19C-031E511E9DB4}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libspeexdsp", "libs\speex\win32\VS2008\libspeexdsp\libspeexdsp.vcproj", "{03207781-0D1C-4DB3-A71D-45C608F28DBD}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libilbc", "libs\ilbc\libilbc.2008.vcproj", "{9A5DDF08-C88C-4A35-B7F6-D605228446BD}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lua51", "src\mod\languages\mod_lua\lua\lua.2008.vcproj", "{D0B36172-CD76-454A-9B89-990025266C2A}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_opal", "src\mod\endpoints\mod_opal\mod_opal_2008.vcproj", "{05C9FB27-480E-4D53-B3B7-6338E2526666}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_h323", "src\mod\endpoints\mod_h323\mod_h323_2008.vcproj", "{05C9FB27-480E-4D53-B3B7-7338E2514666}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_iSAC", "src\mod\codecs\mod_isac\mod_iSAC.2008.vcproj", "{7F1610F1-DD5A-4CF7-8610-30AB12C60ADD}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_skinny", "src\mod\endpoints\mod_skinny\mod_skinny_2008.vcproj", "{CC1DD008-9406-448D-A0AD-33C3186CFADB}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_rtmp", "src\mod\endpoints\mod_rtmp\mod_rtmp_2008.vcproj", "{48414740-C693-4968-9846-EE058020C64F}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "make_at_dictionary", "libs\spandsp\src\msvc\make_at_dictionary.2008.vcproj", "{DEE932AB-5911-4700-9EEB-8C7090A0A330}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "make_modem_filter", "libs\spandsp\src\msvc\make_modem_filter.2008.vcproj", "{329A6FA0-0FCC-4435-A950-E670AEFA9838}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_skel", "src\mod\applications\mod_skel\mod_skel.2008.vcproj", "{11C9BC3D-45E9-46E3-BE84-B8CEE4685E39}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_skypopen", "src\mod\endpoints\mod_skypopen\mod_skypopen.2008.vcproj", "{C6E78A4C-DB1E-47F4-9B63-4DC27D86343F}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download 32khz music", "libs\win32\Dowload 32khz music.2008.vcproj", "{1F0A8A77-E661-418F-BB92-82172AE43803}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download 8khz music", "libs\win32\Download 8khz music.2008.vcproj", "{4F5C9D55-98EF-4256-8311-32D7BD360406}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download 16khz music", "libs\win32\Download 16khz music.2008.vcproj", "{E10571C4-E7F4-4608-B5F2-B22E7EB95400}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "8khz music", "libs\win32\Sound_Files\8khzmusic.2008.vcproj", "{D1ABE208-6442-4FB4-9AAD-1677E41BC870}"
- ProjectSection(ProjectDependencies) = postProject
- {4F5C9D55-98EF-4256-8311-32D7BD360406} = {4F5C9D55-98EF-4256-8311-32D7BD360406}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "16khz music", "libs\win32\Sound_Files\16khzmusic.2008.vcproj", "{BA599D0A-4310-4505-91DA-6A6447B3E289}"
- ProjectSection(ProjectDependencies) = postProject
- {E10571C4-E7F4-4608-B5F2-B22E7EB95400} = {E10571C4-E7F4-4608-B5F2-B22E7EB95400}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "32khz music", "libs\win32\Sound_Files\32khzmusic.2008.vcproj", "{EED13FC7-4F81-4E6F-93DB-CDB7DF5CF959}"
- ProjectSection(ProjectDependencies) = postProject
- {1F0A8A77-E661-418F-BB92-82172AE43803} = {1F0A8A77-E661-418F-BB92-82172AE43803}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_nibblebill", "src\mod\applications\mod_nibblebill\mod_nibblebill.2008.vcproj", "{3C977801-FE88-48F2-83D3-FA2EBFF6688E}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_say_ru", "src\mod\say\mod_say_ru\mod_say_ru.2008.vcproj", "{0382E8FD-CFDC-41C0-8B03-792C7C84FC31}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_valet_parking", "src\mod\applications\mod_valet_parking\mod_valet_parking.2008.vcproj", "{432DB165-1EB2-4781-A9C0-71E62610B20A}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libbroadvoice", "libs\broadvoice\src\libbroadvoice.2008.vcproj", "{CF70F278-3364-4395-A2E1-23501C9B8AD2}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_bv", "src\mod\codecs\mod_bv\mod_bv.2008.vcproj", "{D5C87B19-150D-4EF3-A671-96589BD2D14A}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- {CF70F278-3364-4395-A2E1-23501C9B8AD2} = {CF70F278-3364-4395-A2E1-23501C9B8AD2}
- EndProjectSection
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "unimrcp", "unimrcp", "{62F27B1A-C919-4A70-8478-51F178F3B18F}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "aprtoolkit", "libs\unimrcp\libs\apr-toolkit\aprtoolkit.2008.vcproj", "{13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}"
- ProjectSection(ProjectDependencies) = postProject
- {F057DA7F-79E5-4B00-845C-EF446EF055E3} = {F057DA7F-79E5-4B00-845C-EF446EF055E3}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mpf", "libs\unimrcp\libs\mpf\mpf.2008.vcproj", "{B5A00BFA-6083-4FAE-A097-71642D6473B5}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mrcp", "libs\unimrcp\libs\mrcp\mrcp.2008.vcproj", "{1C320193-46A6-4B34-9C56-8AB584FC1B56}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mrcpclient", "libs\unimrcp\libs\mrcp-client\mrcpclient.2008.vcproj", "{72782932-37CC-46AE-8C7F-9A7B1A6EE108}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mrcpsignaling", "libs\unimrcp\libs\mrcp-signaling\mrcpsignaling.2008.vcproj", "{12A49562-BAB9-43A3-A21D-15B60BBB4C31}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mrcpv2transport", "libs\unimrcp\libs\mrcpv2-transport\mrcpv2transport.2008.vcproj", "{A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unirtsp", "libs\unimrcp\libs\uni-rtsp\unirtsp.2008.vcproj", "{504B3154-7A4F-459D-9877-B951021C3F1F}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mrcpsofiasip", "libs\unimrcp\modules\mrcp-sofiasip\mrcpsofiasip.2008.vcproj", "{746F3632-5BB2-4570-9453-31D6D58A7D8E}"
- ProjectSection(ProjectDependencies) = postProject
- {70A49BC2-7500-41D0-B75D-EDCC5BE987A0} = {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mrcpunirtsp", "libs\unimrcp\modules\mrcp-unirtsp\mrcpunirtsp.2008.vcproj", "{DEB01ACB-D65F-4A62-AED9-58C1054499E9}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_unimrcp", "src\mod\asr_tts\mod_unimrcp\mod_unimrcp.2008.vcproj", "{D07C378A-F5F7-438F-ADF3-4AC4FB1883CD}"
- ProjectSection(ProjectDependencies) = postProject
- {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA} = {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}
- {72782932-37CC-46AE-8C7F-9A7B1A6EE108} = {72782932-37CC-46AE-8C7F-9A7B1A6EE108}
- {746F3632-5BB2-4570-9453-31D6D58A7D8E} = {746F3632-5BB2-4570-9453-31D6D58A7D8E}
- {D331904D-A00A-4694-A5A3-FCFF64AB5DBE} = {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- {504B3154-7A4F-459D-9877-B951021C3F1F} = {504B3154-7A4F-459D-9877-B951021C3F1F}
- {12A49562-BAB9-43A3-A21D-15B60BBB4C31} = {12A49562-BAB9-43A3-A21D-15B60BBB4C31}
- {B4B62169-5AD4-4559-8707-3D933AC5DB39} = {B4B62169-5AD4-4559-8707-3D933AC5DB39}
- {F057DA7F-79E5-4B00-845C-EF446EF055E3} = {F057DA7F-79E5-4B00-845C-EF446EF055E3}
- {1C320193-46A6-4B34-9C56-8AB584FC1B56} = {1C320193-46A6-4B34-9C56-8AB584FC1B56}
- {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
- {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2} = {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}
- {70A49BC2-7500-41D0-B75D-EDCC5BE987A0} = {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}
- {DEB01ACB-D65F-4A62-AED9-58C1054499E9} = {DEB01ACB-D65F-4A62-AED9-58C1054499E9}
- {B5A00BFA-6083-4FAE-A097-71642D6473B5} = {B5A00BFA-6083-4FAE-A097-71642D6473B5}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download CELT", "libs\win32\Download CELT.vcproj", "{FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcelt", "libs\win32\celt\libcelt.vcproj", "{ABB71A76-42B0-47A4-973A-42E3D920C6FD}"
- ProjectSection(ProjectDependencies) = postProject
- {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19} = {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_celt", "src\mod\codecs\mod_celt\mod_celt.vcproj", "{4D418176-3B33-47E6-A63E-01BA34ADD21C}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- {ABB71A76-42B0-47A4-973A-42E3D920C6FD} = {ABB71A76-42B0-47A4-973A-42E3D920C6FD}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FSComm", "fscomm\FSComm.2008.vcproj", "{7D3122C7-C9D0-3748-81F8-F0DDCB40BF5E}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_curl", "src\mod\applications\mod_curl\mod_curl.2008.vcproj", "{EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- {87EE9DA4-DE1E-4448-8324-183C98DCA588} = {87EE9DA4-DE1E-4448-8324-183C98DCA588}
- {9778F1C0-09BC-4698-8EBC-BD982247209A} = {9778F1C0-09BC-4698-8EBC-BD982247209A}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download JSON", "libs\win32\Download JSON.2008.vcproj", "{B808178B-82F0-4CF4-A2B1-921939FA24D0}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libjson", "libs\win32\json\libjson.2008.vcproj", "{9778F1C0-09BC-4698-8EBC-BD982247209A}"
- ProjectSection(ProjectDependencies) = postProject
- {B808178B-82F0-4CF4-A2B1-921939FA24D0} = {B808178B-82F0-4CF4-A2B1-921939FA24D0}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_silk", "src\mod\codecs\mod_silk\mod_silk.2008.vcproj", "{AFA983D6-4569-4F88-BA94-555ED00FD9A8}"
- ProjectSection(ProjectDependencies) = postProject
- {56B91D01-9150-4BBF-AFA1-5B68AB991B76} = {56B91D01-9150-4BBF-AFA1-5B68AB991B76}
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Silk_FIX", "libs\silk\src\Silk_FIX.2008.vcproj", "{56B91D01-9150-4BBF-AFA1-5B68AB991B76}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_avmd", "src\mod\applications\mod_avmd\mod_avmd.2008.vcproj", "{990BAA76-89D3-4E38-8479-C7B28784EFC8}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_spandsp", "src\mod\applications\mod_spandsp\mod_spandsp.2008.vcproj", "{1E21AFE0-6FDB-41D2-942D-863607C24B91}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5} = {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_hash", "src\mod\applications\mod_hash\mod_hash.2008.vcproj", "{2E250296-0C08-4342-9C8A-BCBDD0E7DF65}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- {CF405366-9558-4AE8-90EF-5E21B51CCB4E} = {CF405366-9558-4AE8-90EF-5E21B51CCB4E}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download OPENSSL", "libs\win32\Download OPENSSL.2008.vcproj", "{D578E676-7EC8-4548-BD8B-845C635F14AD}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "openssl", "openssl", "{B376D494-D7DD-4B2A-99E2-52916D5A8CD8}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libeay32", "libs\win32\openssl\libeay32.2008.vcproj", "{D331904D-A00A-4694-A5A3-FCFF64AB5DBE}"
- ProjectSection(ProjectDependencies) = postProject
- {D578E676-7EC8-4548-BD8B-845C635F14AD} = {D578E676-7EC8-4548-BD8B-845C635F14AD}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ssleay32", "libs\win32\openssl\ssleay32.2008.vcproj", "{B4B62169-5AD4-4559-8707-3D933AC5DB39}"
- ProjectSection(ProjectDependencies) = postProject
- {D331904D-A00A-4694-A5A3-FCFF64AB5DBE} = {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openssl", "libs\win32\openssl\openssl.2008.vcproj", "{25BD39B1-C8BF-4676-A738-9CABD9C6BC79}"
- ProjectSection(ProjectDependencies) = postProject
- {D331904D-A00A-4694-A5A3-FCFF64AB5DBE} = {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}
- {B4B62169-5AD4-4559-8707-3D933AC5DB39} = {B4B62169-5AD4-4559-8707-3D933AC5DB39}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_directory", "src\mod\applications\mod_directory\mod_directory.2008.vcproj", "{42E721FD-43D6-4B04-A34B-42567199FFB8}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ldns", "libs\win32\ldns\ldns-lib\ldns-lib.2008.vcproj", "{23B4D303-79FC-49E0-89E2-2280E7E28940}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_httapi", "src\mod\applications\mod_httapi\mod_httapi.2008.vcproj", "{0807C5CB-F6FF-451D-89F0-1F7B2E1D9169}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_abstraction", "src\mod\applications\mod_abstraction\mod_abstraction.2008.vcproj", "{BDA173DB-F8EF-4270-9553-B453AF92E43A}"
- ProjectSection(ProjectDependencies) = postProject
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_gsmopen", "src\mod\endpoints\mod_gsmopen\mod_gsmopen.2008.vcproj", "{74B120FF-6935-4DFE-A142-CDB6BEA99C90}"
- ProjectSection(ProjectDependencies) = postProject
- {26C82FCE-E0CF-4D10-A00C-D8E582FFEB53} = {26C82FCE-E0CF-4D10-A00C-D8E582FFEB53}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gsmlib", "src\mod\endpoints\mod_gsmopen\gsmlib\gsmlib-1.10-patched-13ubuntu\win32\gsmlib.vcproj", "{26C82FCE-E0CF-4D10-A00C-D8E582FFEB53}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libjpeg", "libs\win32\libjpeg\libjpeg.2008.vcproj", "{FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}"
- ProjectSection(ProjectDependencies) = postProject
- {21A7DA70-555E-49FA-942B-D84A38B61243} = {21A7DA70-555E-49FA-942B-D84A38B61243}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download libjpeg", "libs\win32\Download libjpeg.2008.vcproj", "{21A7DA70-555E-49FA-942B-D84A38B61243}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "xmlrpc-c", "xmlrpc-c", "{3783935D-7C0A-4166-A376-C3D8E64F3A9C}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "abyss", "libs\win32\xmlrpc-c\abyss.2008.vcproj", "{A4D67895-E709-40C7-82B6-DE1D12DDDE04}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gennmtab", "libs\win32\xmlrpc-c\gennmtab.2008.vcproj", "{2390F054-A7F1-4CB9-ACB0-F46EC6E77B5B}"
- ProjectSection(ProjectDependencies) = postProject
- {E5A9BCDA-B82D-4B08-B23E-9A782E367888} = {E5A9BCDA-B82D-4B08-B23E-9A782E367888}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xmlparse", "libs\win32\xmlrpc-c\xmlparse.2008.vcproj", "{E5A9BCDA-B82D-4B08-B23E-9A782E367888}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xmlrpc", "libs\win32\xmlrpc-c\xmlrpc.2008.vcproj", "{510BDAA8-C04D-47DB-8482-E6AF380D3E07}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xmltok", "libs\win32\xmlrpc-c\xmltok.2008.vcproj", "{3CF7C0E0-07C2-473A-A1E4-2274AEEC1268}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- All|Win32 = All|Win32
- All|x64 = All|x64
- Debug|Win32 = Debug|Win32
- Debug|x64 = Debug|x64
- Release|Win32 = Release|Win32
- Release|x64 = Release|x64
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {1AF3A893-F7BE-43DD-B697-8AB2397C0D67}.All|Win32.ActiveCfg = Release|x64
- {1AF3A893-F7BE-43DD-B697-8AB2397C0D67}.All|x64.ActiveCfg = Release|x64
- {1AF3A893-F7BE-43DD-B697-8AB2397C0D67}.All|x64.Build.0 = Release|x64
- {1AF3A893-F7BE-43DD-B697-8AB2397C0D67}.Debug|Win32.ActiveCfg = Debug|Win32
- {1AF3A893-F7BE-43DD-B697-8AB2397C0D67}.Debug|Win32.Build.0 = Debug|Win32
- {1AF3A893-F7BE-43DD-B697-8AB2397C0D67}.Debug|x64.ActiveCfg = Debug|x64
- {1AF3A893-F7BE-43DD-B697-8AB2397C0D67}.Debug|x64.Build.0 = Debug|x64
- {1AF3A893-F7BE-43DD-B697-8AB2397C0D67}.Release|Win32.ActiveCfg = Release|Win32
- {1AF3A893-F7BE-43DD-B697-8AB2397C0D67}.Release|Win32.Build.0 = Release|Win32
- {1AF3A893-F7BE-43DD-B697-8AB2397C0D67}.Release|x64.ActiveCfg = Release|x64
- {1AF3A893-F7BE-43DD-B697-8AB2397C0D67}.Release|x64.Build.0 = Release|x64
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}.All|Win32.ActiveCfg = Release|x64
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}.All|x64.ActiveCfg = Release|x64
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}.All|x64.Build.0 = Release|x64
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}.Debug|Win32.ActiveCfg = Debug|Win32
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}.Debug|Win32.Build.0 = Debug|Win32
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}.Debug|x64.ActiveCfg = Debug|x64
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}.Debug|x64.Build.0 = Debug|x64
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}.Release|Win32.ActiveCfg = Release|Win32
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}.Release|Win32.Build.0 = Release|Win32
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}.Release|x64.ActiveCfg = Release|x64
- {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}.Release|x64.Build.0 = Release|x64
- {1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0}.All|Win32.ActiveCfg = Release Passthrough|x64
- {1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0}.All|x64.ActiveCfg = Release Passthrough|x64
- {1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0}.All|x64.Build.0 = Release Passthrough|x64
- {1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0}.Debug|Win32.ActiveCfg = Debug Passthrough|Win32
- {1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0}.Debug|Win32.Build.0 = Debug Passthrough|Win32
- {1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0}.Debug|x64.ActiveCfg = Debug Passthrough|x64
- {1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0}.Debug|x64.Build.0 = Debug Passthrough|x64
- {1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0}.Release|Win32.ActiveCfg = Release Passthrough|Win32
- {1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0}.Release|Win32.Build.0 = Release Passthrough|Win32
- {1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0}.Release|x64.ActiveCfg = Release Passthrough|x64
- {1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0}.Release|x64.Build.0 = Release Passthrough|x64
- {AFAC0568-7548-42D5-9F6A-8D3400A1E4F6}.All|Win32.ActiveCfg = Release|x64
- {AFAC0568-7548-42D5-9F6A-8D3400A1E4F6}.All|x64.ActiveCfg = Release|x64
- {AFAC0568-7548-42D5-9F6A-8D3400A1E4F6}.All|x64.Build.0 = Release|x64
- {AFAC0568-7548-42D5-9F6A-8D3400A1E4F6}.Debug|Win32.ActiveCfg = Debug|Win32
- {AFAC0568-7548-42D5-9F6A-8D3400A1E4F6}.Debug|Win32.Build.0 = Debug|Win32
- {AFAC0568-7548-42D5-9F6A-8D3400A1E4F6}.Debug|x64.ActiveCfg = Debug|x64
- {AFAC0568-7548-42D5-9F6A-8D3400A1E4F6}.Debug|x64.Build.0 = Debug|x64
- {AFAC0568-7548-42D5-9F6A-8D3400A1E4F6}.Release|Win32.ActiveCfg = Release|Win32
- {AFAC0568-7548-42D5-9F6A-8D3400A1E4F6}.Release|Win32.Build.0 = Release|Win32
- {AFAC0568-7548-42D5-9F6A-8D3400A1E4F6}.Release|x64.ActiveCfg = Release|x64
- {AFAC0568-7548-42D5-9F6A-8D3400A1E4F6}.Release|x64.Build.0 = Release|x64
- {5FD31A25-5D83-4794-8BEE-904DAD84CE71}.All|Win32.ActiveCfg = Release|x64
- {5FD31A25-5D83-4794-8BEE-904DAD84CE71}.All|x64.ActiveCfg = Release|x64
- {5FD31A25-5D83-4794-8BEE-904DAD84CE71}.All|x64.Build.0 = Release|x64
- {5FD31A25-5D83-4794-8BEE-904DAD84CE71}.Debug|Win32.ActiveCfg = Debug|Win32
- {5FD31A25-5D83-4794-8BEE-904DAD84CE71}.Debug|Win32.Build.0 = Debug|Win32
- {5FD31A25-5D83-4794-8BEE-904DAD84CE71}.Debug|x64.ActiveCfg = Debug|x64
- {5FD31A25-5D83-4794-8BEE-904DAD84CE71}.Debug|x64.Build.0 = Debug|x64
- {5FD31A25-5D83-4794-8BEE-904DAD84CE71}.Release|Win32.ActiveCfg = Release|Win32
- {5FD31A25-5D83-4794-8BEE-904DAD84CE71}.Release|Win32.Build.0 = Release|Win32
- {5FD31A25-5D83-4794-8BEE-904DAD84CE71}.Release|x64.ActiveCfg = Release|x64
- {5FD31A25-5D83-4794-8BEE-904DAD84CE71}.Release|x64.Build.0 = Release|x64
- {5580D60E-0F77-4716-9CD4-B8E5986FA375}.All|Win32.ActiveCfg = Release|x64
- {5580D60E-0F77-4716-9CD4-B8E5986FA375}.All|x64.ActiveCfg = Release|x64
- {5580D60E-0F77-4716-9CD4-B8E5986FA375}.All|x64.Build.0 = Release|x64
- {5580D60E-0F77-4716-9CD4-B8E5986FA375}.Debug|Win32.ActiveCfg = Debug|Win32
- {5580D60E-0F77-4716-9CD4-B8E5986FA375}.Debug|Win32.Build.0 = Debug|Win32
- {5580D60E-0F77-4716-9CD4-B8E5986FA375}.Debug|x64.ActiveCfg = Debug|x64
- {5580D60E-0F77-4716-9CD4-B8E5986FA375}.Debug|x64.Build.0 = Debug|x64
- {5580D60E-0F77-4716-9CD4-B8E5986FA375}.Release|Win32.ActiveCfg = Release|Win32
- {5580D60E-0F77-4716-9CD4-B8E5986FA375}.Release|Win32.Build.0 = Release|Win32
- {5580D60E-0F77-4716-9CD4-B8E5986FA375}.Release|x64.ActiveCfg = Release|x64
- {5580D60E-0F77-4716-9CD4-B8E5986FA375}.Release|x64.Build.0 = Release|x64
- {1A1FF289-4FD6-4285-A422-D31DD67A4723}.All|Win32.ActiveCfg = Release|Win32
- {1A1FF289-4FD6-4285-A422-D31DD67A4723}.All|x64.ActiveCfg = Release|Win32
- {1A1FF289-4FD6-4285-A422-D31DD67A4723}.Debug|Win32.ActiveCfg = Debug|Win32
- {1A1FF289-4FD6-4285-A422-D31DD67A4723}.Debug|x64.ActiveCfg = Debug|Win32
- {1A1FF289-4FD6-4285-A422-D31DD67A4723}.Release|Win32.ActiveCfg = Release|Win32
- {1A1FF289-4FD6-4285-A422-D31DD67A4723}.Release|x64.ActiveCfg = Release|Win32
- {07113B25-D3AF-4E04-BA77-4CD1171F022C}.All|Win32.ActiveCfg = Release|x64
- {07113B25-D3AF-4E04-BA77-4CD1171F022C}.All|x64.ActiveCfg = Release|x64
- {07113B25-D3AF-4E04-BA77-4CD1171F022C}.All|x64.Build.0 = Release|x64
- {07113B25-D3AF-4E04-BA77-4CD1171F022C}.Debug|Win32.ActiveCfg = Debug|Win32
- {07113B25-D3AF-4E04-BA77-4CD1171F022C}.Debug|Win32.Build.0 = Debug|Win32
- {07113B25-D3AF-4E04-BA77-4CD1171F022C}.Debug|x64.ActiveCfg = Debug|x64
- {07113B25-D3AF-4E04-BA77-4CD1171F022C}.Debug|x64.Build.0 = Debug|x64
- {07113B25-D3AF-4E04-BA77-4CD1171F022C}.Release|Win32.ActiveCfg = Release|Win32
- {07113B25-D3AF-4E04-BA77-4CD1171F022C}.Release|Win32.Build.0 = Release|Win32
- {07113B25-D3AF-4E04-BA77-4CD1171F022C}.Release|x64.ActiveCfg = Release|x64
- {07113B25-D3AF-4E04-BA77-4CD1171F022C}.Release|x64.Build.0 = Release|x64
- {EC3E5C7F-EE09-47E2-80FE-546363D14A98}.All|Win32.ActiveCfg = Release MS-LDAP|x64
- {EC3E5C7F-EE09-47E2-80FE-546363D14A98}.All|x64.ActiveCfg = Release MS-LDAP|x64
- {EC3E5C7F-EE09-47E2-80FE-546363D14A98}.All|x64.Build.0 = Release MS-LDAP|x64
- {EC3E5C7F-EE09-47E2-80FE-546363D14A98}.Debug|Win32.ActiveCfg = Debug MS-LDAP|Win32
- {EC3E5C7F-EE09-47E2-80FE-546363D14A98}.Debug|Win32.Build.0 = Debug MS-LDAP|Win32
- {EC3E5C7F-EE09-47E2-80FE-546363D14A98}.Debug|x64.ActiveCfg = Debug MS-LDAP|x64
- {EC3E5C7F-EE09-47E2-80FE-546363D14A98}.Debug|x64.Build.0 = Debug MS-LDAP|x64
- {EC3E5C7F-EE09-47E2-80FE-546363D14A98}.Release|Win32.ActiveCfg = Release MS-LDAP|Win32
- {EC3E5C7F-EE09-47E2-80FE-546363D14A98}.Release|Win32.Build.0 = Release MS-LDAP|Win32
- {EC3E5C7F-EE09-47E2-80FE-546363D14A98}.Release|x64.ActiveCfg = Release MS-LDAP|x64
- {EC3E5C7F-EE09-47E2-80FE-546363D14A98}.Release|x64.Build.0 = Release MS-LDAP|x64
- {A27CCA23-1541-4337-81A4-F0A6413078A0}.All|Win32.ActiveCfg = Release|x64
- {A27CCA23-1541-4337-81A4-F0A6413078A0}.All|x64.ActiveCfg = Release|x64
- {A27CCA23-1541-4337-81A4-F0A6413078A0}.All|x64.Build.0 = Release|x64
- {A27CCA23-1541-4337-81A4-F0A6413078A0}.Debug|Win32.ActiveCfg = Debug|Win32
- {A27CCA23-1541-4337-81A4-F0A6413078A0}.Debug|Win32.Build.0 = Debug|Win32
- {A27CCA23-1541-4337-81A4-F0A6413078A0}.Debug|x64.ActiveCfg = Debug|x64
- {A27CCA23-1541-4337-81A4-F0A6413078A0}.Debug|x64.Build.0 = Debug|x64
- {A27CCA23-1541-4337-81A4-F0A6413078A0}.Release|Win32.ActiveCfg = Release|Win32
- {A27CCA23-1541-4337-81A4-F0A6413078A0}.Release|Win32.Build.0 = Release|Win32
- {A27CCA23-1541-4337-81A4-F0A6413078A0}.Release|x64.ActiveCfg = Release|x64
- {A27CCA23-1541-4337-81A4-F0A6413078A0}.Release|x64.Build.0 = Release|x64
- {784113EF-44D9-4949-835D-7065D3C7AD08}.All|Win32.ActiveCfg = Release|x64
- {784113EF-44D9-4949-835D-7065D3C7AD08}.All|x64.ActiveCfg = Release|x64
- {784113EF-44D9-4949-835D-7065D3C7AD08}.All|x64.Build.0 = Release|x64
- {784113EF-44D9-4949-835D-7065D3C7AD08}.Debug|Win32.ActiveCfg = Debug|Win32
- {784113EF-44D9-4949-835D-7065D3C7AD08}.Debug|Win32.Build.0 = Debug|Win32
- {784113EF-44D9-4949-835D-7065D3C7AD08}.Debug|x64.ActiveCfg = Debug|x64
- {784113EF-44D9-4949-835D-7065D3C7AD08}.Debug|x64.Build.0 = Debug|x64
- {784113EF-44D9-4949-835D-7065D3C7AD08}.Release|Win32.ActiveCfg = Release|Win32
- {784113EF-44D9-4949-835D-7065D3C7AD08}.Release|Win32.Build.0 = Release|Win32
- {784113EF-44D9-4949-835D-7065D3C7AD08}.Release|x64.ActiveCfg = Release|x64
- {784113EF-44D9-4949-835D-7065D3C7AD08}.Release|x64.Build.0 = Release|x64
- {89385C74-5860-4174-9CAF-A39E7C48909C}.All|Win32.ActiveCfg = Release|x64
- {89385C74-5860-4174-9CAF-A39E7C48909C}.All|x64.ActiveCfg = Release|x64
- {89385C74-5860-4174-9CAF-A39E7C48909C}.All|x64.Build.0 = Release|x64
- {89385C74-5860-4174-9CAF-A39E7C48909C}.Debug|Win32.ActiveCfg = Debug|Win32
- {89385C74-5860-4174-9CAF-A39E7C48909C}.Debug|Win32.Build.0 = Debug|Win32
- {89385C74-5860-4174-9CAF-A39E7C48909C}.Debug|x64.ActiveCfg = Debug|x64
- {89385C74-5860-4174-9CAF-A39E7C48909C}.Debug|x64.Build.0 = Debug|x64
- {89385C74-5860-4174-9CAF-A39E7C48909C}.Release|Win32.ActiveCfg = Release|Win32
- {89385C74-5860-4174-9CAF-A39E7C48909C}.Release|Win32.Build.0 = Release|Win32
- {89385C74-5860-4174-9CAF-A39E7C48909C}.Release|x64.ActiveCfg = Release|x64
- {89385C74-5860-4174-9CAF-A39E7C48909C}.Release|x64.Build.0 = Release|x64
- {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}.All|Win32.ActiveCfg = Release|x64
- {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}.All|x64.ActiveCfg = Release|x64
- {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}.All|x64.Build.0 = Release|x64
- {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}.Debug|Win32.ActiveCfg = Debug|Win32
- {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}.Debug|Win32.Build.0 = Debug|Win32
- {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}.Debug|x64.ActiveCfg = Debug|x64
- {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}.Release|Win32.ActiveCfg = Release|Win32
- {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}.Release|Win32.Build.0 = Release|Win32
- {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}.Release|x64.ActiveCfg = Release|x64
- {692F6330-4D87-4C82-81DF-40DB5892636E}.All|Win32.ActiveCfg = Release|x64
- {692F6330-4D87-4C82-81DF-40DB5892636E}.All|x64.ActiveCfg = Release|x64
- {692F6330-4D87-4C82-81DF-40DB5892636E}.All|x64.Build.0 = Release|x64
- {692F6330-4D87-4C82-81DF-40DB5892636E}.Debug|Win32.ActiveCfg = Debug|Win32
- {692F6330-4D87-4C82-81DF-40DB5892636E}.Debug|x64.ActiveCfg = Debug|x64
- {692F6330-4D87-4C82-81DF-40DB5892636E}.Release|Win32.ActiveCfg = Release|Win32
- {692F6330-4D87-4C82-81DF-40DB5892636E}.Release|x64.ActiveCfg = Release|x64
- {D3EC0AFF-76FC-4210-A825-9A17410660A3}.All|Win32.ActiveCfg = Release|x64
- {D3EC0AFF-76FC-4210-A825-9A17410660A3}.All|x64.ActiveCfg = Release|x64
- {D3EC0AFF-76FC-4210-A825-9A17410660A3}.All|x64.Build.0 = Release|x64
- {D3EC0AFF-76FC-4210-A825-9A17410660A3}.Debug|Win32.ActiveCfg = Debug|Win32
- {D3EC0AFF-76FC-4210-A825-9A17410660A3}.Debug|Win32.Build.0 = Debug|Win32
- {D3EC0AFF-76FC-4210-A825-9A17410660A3}.Debug|x64.ActiveCfg = Debug|x64
- {D3EC0AFF-76FC-4210-A825-9A17410660A3}.Debug|x64.Build.0 = Debug|x64
- {D3EC0AFF-76FC-4210-A825-9A17410660A3}.Release|Win32.ActiveCfg = Release|Win32
- {D3EC0AFF-76FC-4210-A825-9A17410660A3}.Release|Win32.Build.0 = Release|Win32
- {D3EC0AFF-76FC-4210-A825-9A17410660A3}.Release|x64.ActiveCfg = Release|x64
- {D3EC0AFF-76FC-4210-A825-9A17410660A3}.Release|x64.Build.0 = Release|x64
- {FFAA4C52-3A53-4F99-90C1-D59D1F0427F3}.All|Win32.ActiveCfg = Release|x64
- {FFAA4C52-3A53-4F99-90C1-D59D1F0427F3}.All|x64.ActiveCfg = Release|x64
- {FFAA4C52-3A53-4F99-90C1-D59D1F0427F3}.All|x64.Build.0 = Release|x64
- {FFAA4C52-3A53-4F99-90C1-D59D1F0427F3}.Debug|Win32.ActiveCfg = Debug|Win32
- {FFAA4C52-3A53-4F99-90C1-D59D1F0427F3}.Debug|Win32.Build.0 = Debug|Win32
- {FFAA4C52-3A53-4F99-90C1-D59D1F0427F3}.Debug|x64.ActiveCfg = Debug|x64
- {FFAA4C52-3A53-4F99-90C1-D59D1F0427F3}.Debug|x64.Build.0 = Debug|x64
- {FFAA4C52-3A53-4F99-90C1-D59D1F0427F3}.Release|Win32.ActiveCfg = Release|Win32
- {FFAA4C52-3A53-4F99-90C1-D59D1F0427F3}.Release|Win32.Build.0 = Release|Win32
- {FFAA4C52-3A53-4F99-90C1-D59D1F0427F3}.Release|x64.ActiveCfg = Release|x64
- {FFAA4C52-3A53-4F99-90C1-D59D1F0427F3}.Release|x64.Build.0 = Release|x64
- {30A5B29C-983E-4580-9FD0-D647CCDCC7EB}.All|Win32.ActiveCfg = Release|x64
- {30A5B29C-983E-4580-9FD0-D647CCDCC7EB}.All|x64.ActiveCfg = Release|x64
- {30A5B29C-983E-4580-9FD0-D647CCDCC7EB}.All|x64.Build.0 = Release|x64
- {30A5B29C-983E-4580-9FD0-D647CCDCC7EB}.Debug|Win32.ActiveCfg = Debug|Win32
- {30A5B29C-983E-4580-9FD0-D647CCDCC7EB}.Debug|Win32.Build.0 = Debug|Win32
- {30A5B29C-983E-4580-9FD0-D647CCDCC7EB}.Debug|x64.ActiveCfg = Debug|x64
- {30A5B29C-983E-4580-9FD0-D647CCDCC7EB}.Debug|x64.Build.0 = Debug|x64
- {30A5B29C-983E-4580-9FD0-D647CCDCC7EB}.Release|Win32.ActiveCfg = Release|Win32
- {30A5B29C-983E-4580-9FD0-D647CCDCC7EB}.Release|Win32.Build.0 = Release|Win32
- {30A5B29C-983E-4580-9FD0-D647CCDCC7EB}.Release|x64.ActiveCfg = Release|x64
- {30A5B29C-983E-4580-9FD0-D647CCDCC7EB}.Release|x64.Build.0 = Release|x64
- {1C453396-D912-4213-89FD-9B489162B7B5}.All|Win32.ActiveCfg = Release|x64
- {1C453396-D912-4213-89FD-9B489162B7B5}.All|x64.ActiveCfg = Release|x64
- {1C453396-D912-4213-89FD-9B489162B7B5}.All|x64.Build.0 = Release|x64
- {1C453396-D912-4213-89FD-9B489162B7B5}.Debug|Win32.ActiveCfg = Debug|Win32
- {1C453396-D912-4213-89FD-9B489162B7B5}.Debug|Win32.Build.0 = Debug|Win32
- {1C453396-D912-4213-89FD-9B489162B7B5}.Debug|x64.ActiveCfg = Debug|x64
- {1C453396-D912-4213-89FD-9B489162B7B5}.Debug|x64.Build.0 = Debug|x64
- {1C453396-D912-4213-89FD-9B489162B7B5}.Release|Win32.ActiveCfg = Release|Win32
- {1C453396-D912-4213-89FD-9B489162B7B5}.Release|Win32.Build.0 = Release|Win32
- {1C453396-D912-4213-89FD-9B489162B7B5}.Release|x64.ActiveCfg = Release|x64
- {1C453396-D912-4213-89FD-9B489162B7B5}.Release|x64.Build.0 = Release|x64
- {CBEC7225-0C21-4DA8-978E-1F158F8AD950}.All|Win32.ActiveCfg = Release|x64
- {CBEC7225-0C21-4DA8-978E-1F158F8AD950}.All|x64.ActiveCfg = Release|x64
- {CBEC7225-0C21-4DA8-978E-1F158F8AD950}.All|x64.Build.0 = Release|x64
- {CBEC7225-0C21-4DA8-978E-1F158F8AD950}.Debug|Win32.ActiveCfg = Debug|Win32
- {CBEC7225-0C21-4DA8-978E-1F158F8AD950}.Debug|Win32.Build.0 = Debug|Win32
- {CBEC7225-0C21-4DA8-978E-1F158F8AD950}.Debug|x64.ActiveCfg = Debug|x64
- {CBEC7225-0C21-4DA8-978E-1F158F8AD950}.Debug|x64.Build.0 = Debug|x64
- {CBEC7225-0C21-4DA8-978E-1F158F8AD950}.Release|Win32.ActiveCfg = Release|Win32
- {CBEC7225-0C21-4DA8-978E-1F158F8AD950}.Release|Win32.Build.0 = Release|Win32
- {CBEC7225-0C21-4DA8-978E-1F158F8AD950}.Release|x64.ActiveCfg = Release|x64
- {CBEC7225-0C21-4DA8-978E-1F158F8AD950}.Release|x64.Build.0 = Release|x64
- {B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4}.All|Win32.ActiveCfg = Release|x64
- {B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4}.All|x64.ActiveCfg = Release|x64
- {B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4}.All|x64.Build.0 = Release|x64
- {B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4}.Debug|Win32.ActiveCfg = Debug|Win32
- {B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4}.Debug|Win32.Build.0 = Debug|Win32
- {B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4}.Debug|x64.ActiveCfg = Debug|x64
- {B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4}.Debug|x64.Build.0 = Debug|x64
- {B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4}.Release|Win32.ActiveCfg = Release|Win32
- {B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4}.Release|Win32.Build.0 = Release|Win32
- {B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4}.Release|x64.ActiveCfg = Release|x64
- {B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4}.Release|x64.Build.0 = Release|x64
- {C24FB505-05D7-4319-8485-7540B44C8603}.All|Win32.ActiveCfg = Release|x64
- {C24FB505-05D7-4319-8485-7540B44C8603}.All|x64.ActiveCfg = Release|x64
- {C24FB505-05D7-4319-8485-7540B44C8603}.All|x64.Build.0 = Release|x64
- {C24FB505-05D7-4319-8485-7540B44C8603}.Debug|Win32.ActiveCfg = Debug|Win32
- {C24FB505-05D7-4319-8485-7540B44C8603}.Debug|Win32.Build.0 = Debug|Win32
- {C24FB505-05D7-4319-8485-7540B44C8603}.Debug|x64.ActiveCfg = Debug|x64
- {C24FB505-05D7-4319-8485-7540B44C8603}.Debug|x64.Build.0 = Debug|x64
- {C24FB505-05D7-4319-8485-7540B44C8603}.Release|Win32.ActiveCfg = Release|Win32
- {C24FB505-05D7-4319-8485-7540B44C8603}.Release|Win32.Build.0 = Release|Win32
- {C24FB505-05D7-4319-8485-7540B44C8603}.Release|x64.ActiveCfg = Release|x64
- {C24FB505-05D7-4319-8485-7540B44C8603}.Release|x64.Build.0 = Release|x64
- {B5881A85-FE70-4F64-8607-2CAAE52669C6}.All|Win32.ActiveCfg = Release|x64
- {B5881A85-FE70-4F64-8607-2CAAE52669C6}.All|x64.ActiveCfg = Release|x64
- {B5881A85-FE70-4F64-8607-2CAAE52669C6}.All|x64.Build.0 = Release|x64
- {B5881A85-FE70-4F64-8607-2CAAE52669C6}.Debug|Win32.ActiveCfg = Debug|Win32
- {B5881A85-FE70-4F64-8607-2CAAE52669C6}.Debug|Win32.Build.0 = Debug|Win32
- {B5881A85-FE70-4F64-8607-2CAAE52669C6}.Debug|x64.ActiveCfg = Debug|x64
- {B5881A85-FE70-4F64-8607-2CAAE52669C6}.Debug|x64.Build.0 = Debug|x64
- {B5881A85-FE70-4F64-8607-2CAAE52669C6}.Release|Win32.ActiveCfg = Release|Win32
- {B5881A85-FE70-4F64-8607-2CAAE52669C6}.Release|Win32.Build.0 = Release|Win32
- {B5881A85-FE70-4F64-8607-2CAAE52669C6}.Release|x64.ActiveCfg = Release|x64
- {B5881A85-FE70-4F64-8607-2CAAE52669C6}.Release|x64.Build.0 = Release|x64
- {05515420-16DE-4E63-BE73-85BE85BA5142}.All|Win32.ActiveCfg = Release|x64
- {05515420-16DE-4E63-BE73-85BE85BA5142}.All|x64.ActiveCfg = Release|x64
- {05515420-16DE-4E63-BE73-85BE85BA5142}.All|x64.Build.0 = Release|x64
- {05515420-16DE-4E63-BE73-85BE85BA5142}.Debug|Win32.ActiveCfg = Debug|Win32
- {05515420-16DE-4E63-BE73-85BE85BA5142}.Debug|Win32.Build.0 = Debug|Win32
- {05515420-16DE-4E63-BE73-85BE85BA5142}.Debug|x64.ActiveCfg = Debug|x64
- {05515420-16DE-4E63-BE73-85BE85BA5142}.Debug|x64.Build.0 = Debug|x64
- {05515420-16DE-4E63-BE73-85BE85BA5142}.Release|Win32.ActiveCfg = Release|Win32
- {05515420-16DE-4E63-BE73-85BE85BA5142}.Release|Win32.Build.0 = Release|Win32
- {05515420-16DE-4E63-BE73-85BE85BA5142}.Release|x64.ActiveCfg = Release|x64
- {05515420-16DE-4E63-BE73-85BE85BA5142}.Release|x64.Build.0 = Release|x64
- {1906D736-08BD-4EE1-924F-B536249B9A54}.All|Win32.ActiveCfg = Release DLL|x64
- {1906D736-08BD-4EE1-924F-B536249B9A54}.All|x64.ActiveCfg = Release DLL|x64
- {1906D736-08BD-4EE1-924F-B536249B9A54}.All|x64.Build.0 = Release DLL|x64
- {1906D736-08BD-4EE1-924F-B536249B9A54}.Debug|Win32.ActiveCfg = Debug|Win32
- {1906D736-08BD-4EE1-924F-B536249B9A54}.Debug|Win32.Build.0 = Debug|Win32
- {1906D736-08BD-4EE1-924F-B536249B9A54}.Debug|x64.ActiveCfg = Debug|x64
- {1906D736-08BD-4EE1-924F-B536249B9A54}.Debug|x64.Build.0 = Debug|x64
- {1906D736-08BD-4EE1-924F-B536249B9A54}.Release|Win32.ActiveCfg = Release|Win32
- {1906D736-08BD-4EE1-924F-B536249B9A54}.Release|Win32.Build.0 = Release|Win32
- {1906D736-08BD-4EE1-924F-B536249B9A54}.Release|x64.ActiveCfg = Release|x64
- {1906D736-08BD-4EE1-924F-B536249B9A54}.Release|x64.Build.0 = Release|x64
- {EEF031CB-FED8-451E-A471-91EC8D4F6750}.All|Win32.ActiveCfg = Release Dll|x64
- {EEF031CB-FED8-451E-A471-91EC8D4F6750}.All|x64.ActiveCfg = Release Dll|x64
- {EEF031CB-FED8-451E-A471-91EC8D4F6750}.All|x64.Build.0 = Release Dll|x64
- {EEF031CB-FED8-451E-A471-91EC8D4F6750}.Debug|Win32.ActiveCfg = Debug|Win32
- {EEF031CB-FED8-451E-A471-91EC8D4F6750}.Debug|Win32.Build.0 = Debug|Win32
- {EEF031CB-FED8-451E-A471-91EC8D4F6750}.Debug|x64.ActiveCfg = Debug|x64
- {EEF031CB-FED8-451E-A471-91EC8D4F6750}.Debug|x64.Build.0 = Debug|x64
- {EEF031CB-FED8-451E-A471-91EC8D4F6750}.Release|Win32.ActiveCfg = Release|Win32
- {EEF031CB-FED8-451E-A471-91EC8D4F6750}.Release|Win32.Build.0 = Release|Win32
- {EEF031CB-FED8-451E-A471-91EC8D4F6750}.Release|x64.ActiveCfg = Release|x64
- {EEF031CB-FED8-451E-A471-91EC8D4F6750}.Release|x64.Build.0 = Release|x64
- {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3}.All|Win32.ActiveCfg = Release DLL|x64
- {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3}.All|x64.ActiveCfg = Release DLL|x64
- {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3}.All|x64.Build.0 = Release DLL|x64
- {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3}.Debug|Win32.ActiveCfg = Debug|Win32
- {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3}.Debug|Win32.Build.0 = Debug|Win32
- {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3}.Debug|x64.ActiveCfg = Debug|x64
- {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3}.Debug|x64.Build.0 = Debug|x64
- {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3}.Release|Win32.ActiveCfg = Release|Win32
- {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3}.Release|Win32.Build.0 = Release|Win32
- {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3}.Release|x64.ActiveCfg = Release|x64
- {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3}.Release|x64.Build.0 = Release|x64
- {8D04B550-D240-4A44-8A18-35DA3F7038D9}.All|Win32.ActiveCfg = Release DLL|x64
- {8D04B550-D240-4A44-8A18-35DA3F7038D9}.All|x64.ActiveCfg = Release DLL|x64
- {8D04B550-D240-4A44-8A18-35DA3F7038D9}.All|x64.Build.0 = Release DLL|x64
- {8D04B550-D240-4A44-8A18-35DA3F7038D9}.Debug|Win32.ActiveCfg = Debug|Win32
- {8D04B550-D240-4A44-8A18-35DA3F7038D9}.Debug|Win32.Build.0 = Debug|Win32
- {8D04B550-D240-4A44-8A18-35DA3F7038D9}.Debug|x64.ActiveCfg = Debug|x64
- {8D04B550-D240-4A44-8A18-35DA3F7038D9}.Debug|x64.Build.0 = Debug|x64
- {8D04B550-D240-4A44-8A18-35DA3F7038D9}.Release|Win32.ActiveCfg = Release|Win32
- {8D04B550-D240-4A44-8A18-35DA3F7038D9}.Release|Win32.Build.0 = Release|Win32
- {8D04B550-D240-4A44-8A18-35DA3F7038D9}.Release|x64.ActiveCfg = Release|x64
- {8D04B550-D240-4A44-8A18-35DA3F7038D9}.Release|x64.Build.0 = Release|x64
- {1CED5987-A529-46DC-B30F-870D85FF9C94}.All|Win32.ActiveCfg = Release|x64
- {1CED5987-A529-46DC-B30F-870D85FF9C94}.All|x64.ActiveCfg = Release|x64
- {1CED5987-A529-46DC-B30F-870D85FF9C94}.All|x64.Build.0 = Release|x64
- {1CED5987-A529-46DC-B30F-870D85FF9C94}.Debug|Win32.ActiveCfg = Debug|Win32
- {1CED5987-A529-46DC-B30F-870D85FF9C94}.Debug|Win32.Build.0 = Debug|Win32
- {1CED5987-A529-46DC-B30F-870D85FF9C94}.Debug|x64.ActiveCfg = Debug|x64
- {1CED5987-A529-46DC-B30F-870D85FF9C94}.Debug|x64.Build.0 = Debug|x64
- {1CED5987-A529-46DC-B30F-870D85FF9C94}.Release|Win32.ActiveCfg = Release|Win32
- {1CED5987-A529-46DC-B30F-870D85FF9C94}.Release|Win32.Build.0 = Release|Win32
- {1CED5987-A529-46DC-B30F-870D85FF9C94}.Release|x64.ActiveCfg = Release|x64
- {1CED5987-A529-46DC-B30F-870D85FF9C94}.Release|x64.Build.0 = Release|x64
- {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}.All|Win32.ActiveCfg = Release|x64
- {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}.All|x64.ActiveCfg = Release|x64
- {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}.All|x64.Build.0 = Release|x64
- {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}.Debug|Win32.ActiveCfg = Debug|Win32
- {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}.Debug|Win32.Build.0 = Debug|Win32
- {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}.Debug|x64.ActiveCfg = Debug|x64
- {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}.Debug|x64.Build.0 = Debug|x64
- {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}.Release|Win32.ActiveCfg = Release|Win32
- {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}.Release|Win32.Build.0 = Release|Win32
- {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}.Release|x64.ActiveCfg = Release|x64
- {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}.Release|x64.Build.0 = Release|x64
- {F057DA7F-79E5-4B00-845C-EF446EF055E3}.All|Win32.ActiveCfg = Release|x64
- {F057DA7F-79E5-4B00-845C-EF446EF055E3}.All|x64.ActiveCfg = Release|x64
- {F057DA7F-79E5-4B00-845C-EF446EF055E3}.All|x64.Build.0 = Release|x64
- {F057DA7F-79E5-4B00-845C-EF446EF055E3}.Debug|Win32.ActiveCfg = Debug|Win32
- {F057DA7F-79E5-4B00-845C-EF446EF055E3}.Debug|Win32.Build.0 = Debug|Win32
- {F057DA7F-79E5-4B00-845C-EF446EF055E3}.Debug|x64.ActiveCfg = Debug|x64
- {F057DA7F-79E5-4B00-845C-EF446EF055E3}.Debug|x64.Build.0 = Debug|x64
- {F057DA7F-79E5-4B00-845C-EF446EF055E3}.Release|Win32.ActiveCfg = Release|Win32
- {F057DA7F-79E5-4B00-845C-EF446EF055E3}.Release|Win32.Build.0 = Release|Win32
- {F057DA7F-79E5-4B00-845C-EF446EF055E3}.Release|x64.ActiveCfg = Release|x64
- {F057DA7F-79E5-4B00-845C-EF446EF055E3}.Release|x64.Build.0 = Release|x64
- {E727E8F6-935D-46FE-8B0E-37834748A0E3}.All|Win32.ActiveCfg = Release|x64
- {E727E8F6-935D-46FE-8B0E-37834748A0E3}.All|x64.ActiveCfg = Release|x64
- {E727E8F6-935D-46FE-8B0E-37834748A0E3}.All|x64.Build.0 = Release|x64
- {E727E8F6-935D-46FE-8B0E-37834748A0E3}.Debug|Win32.ActiveCfg = Debug|Win32
- {E727E8F6-935D-46FE-8B0E-37834748A0E3}.Debug|Win32.Build.0 = Debug|Win32
- {E727E8F6-935D-46FE-8B0E-37834748A0E3}.Debug|x64.ActiveCfg = Debug|x64
- {E727E8F6-935D-46FE-8B0E-37834748A0E3}.Debug|x64.Build.0 = Debug|x64
- {E727E8F6-935D-46FE-8B0E-37834748A0E3}.Release|Win32.ActiveCfg = Release|Win32
- {E727E8F6-935D-46FE-8B0E-37834748A0E3}.Release|Win32.Build.0 = Release|Win32
- {E727E8F6-935D-46FE-8B0E-37834748A0E3}.Release|x64.ActiveCfg = Release|x64
- {E727E8F6-935D-46FE-8B0E-37834748A0E3}.Release|x64.Build.0 = Release|x64
- {3D0370CA-BED2-4657-A475-32375CBCB6E4}.All|Win32.ActiveCfg = Release|x64
- {3D0370CA-BED2-4657-A475-32375CBCB6E4}.All|x64.ActiveCfg = Release|x64
- {3D0370CA-BED2-4657-A475-32375CBCB6E4}.All|x64.Build.0 = Release|x64
- {3D0370CA-BED2-4657-A475-32375CBCB6E4}.Debug|Win32.ActiveCfg = Debug|Win32
- {3D0370CA-BED2-4657-A475-32375CBCB6E4}.Debug|Win32.Build.0 = Debug|Win32
- {3D0370CA-BED2-4657-A475-32375CBCB6E4}.Debug|x64.ActiveCfg = Debug|x64
- {3D0370CA-BED2-4657-A475-32375CBCB6E4}.Debug|x64.Build.0 = Debug|x64
- {3D0370CA-BED2-4657-A475-32375CBCB6E4}.Release|Win32.ActiveCfg = Release|Win32
- {3D0370CA-BED2-4657-A475-32375CBCB6E4}.Release|Win32.Build.0 = Release|Win32
- {3D0370CA-BED2-4657-A475-32375CBCB6E4}.Release|x64.ActiveCfg = Release|x64
- {3D0370CA-BED2-4657-A475-32375CBCB6E4}.Release|x64.Build.0 = Release|x64
- {87EE9DA4-DE1E-4448-8324-183C98DCA588}.All|Win32.ActiveCfg = Debug|x64
- {87EE9DA4-DE1E-4448-8324-183C98DCA588}.All|x64.ActiveCfg = Debug|x64
- {87EE9DA4-DE1E-4448-8324-183C98DCA588}.All|x64.Build.0 = Debug|x64
- {87EE9DA4-DE1E-4448-8324-183C98DCA588}.Debug|Win32.ActiveCfg = Debug|Win32
- {87EE9DA4-DE1E-4448-8324-183C98DCA588}.Debug|Win32.Build.0 = Debug|Win32
- {87EE9DA4-DE1E-4448-8324-183C98DCA588}.Debug|x64.ActiveCfg = Debug|x64
- {87EE9DA4-DE1E-4448-8324-183C98DCA588}.Debug|x64.Build.0 = Debug|x64
- {87EE9DA4-DE1E-4448-8324-183C98DCA588}.Release|Win32.ActiveCfg = Release|Win32
- {87EE9DA4-DE1E-4448-8324-183C98DCA588}.Release|Win32.Build.0 = Release|Win32
- {87EE9DA4-DE1E-4448-8324-183C98DCA588}.Release|x64.ActiveCfg = Release|x64
- {87EE9DA4-DE1E-4448-8324-183C98DCA588}.Release|x64.Build.0 = Release|x64
- {155844C3-EC5F-407F-97A4-A2DDADED9B2F}.All|Win32.ActiveCfg = Debug|x64
- {155844C3-EC5F-407F-97A4-A2DDADED9B2F}.All|x64.ActiveCfg = Debug|x64
- {155844C3-EC5F-407F-97A4-A2DDADED9B2F}.All|x64.Build.0 = Debug|x64
- {155844C3-EC5F-407F-97A4-A2DDADED9B2F}.Debug|Win32.ActiveCfg = Debug|Win32
- {155844C3-EC5F-407F-97A4-A2DDADED9B2F}.Debug|Win32.Build.0 = Debug|Win32
- {155844C3-EC5F-407F-97A4-A2DDADED9B2F}.Debug|x64.ActiveCfg = Debug|x64
- {155844C3-EC5F-407F-97A4-A2DDADED9B2F}.Debug|x64.Build.0 = Debug|x64
- {155844C3-EC5F-407F-97A4-A2DDADED9B2F}.Release|Win32.ActiveCfg = Release|Win32
- {155844C3-EC5F-407F-97A4-A2DDADED9B2F}.Release|Win32.Build.0 = Release|Win32
- {155844C3-EC5F-407F-97A4-A2DDADED9B2F}.Release|x64.ActiveCfg = Release|x64
- {155844C3-EC5F-407F-97A4-A2DDADED9B2F}.Release|x64.Build.0 = Release|x64
- {204FA0DE-305D-4414-AE2E-F195A23F390D}.All|Win32.ActiveCfg = Debug|x64
- {204FA0DE-305D-4414-AE2E-F195A23F390D}.All|x64.ActiveCfg = Debug|x64
- {204FA0DE-305D-4414-AE2E-F195A23F390D}.All|x64.Build.0 = Debug|x64
- {204FA0DE-305D-4414-AE2E-F195A23F390D}.Debug|Win32.ActiveCfg = Debug|Win32
- {204FA0DE-305D-4414-AE2E-F195A23F390D}.Debug|Win32.Build.0 = Debug|Win32
- {204FA0DE-305D-4414-AE2E-F195A23F390D}.Debug|x64.ActiveCfg = Debug|x64
- {204FA0DE-305D-4414-AE2E-F195A23F390D}.Debug|x64.Build.0 = Debug|x64
- {204FA0DE-305D-4414-AE2E-F195A23F390D}.Release|Win32.ActiveCfg = Release|Win32
- {204FA0DE-305D-4414-AE2E-F195A23F390D}.Release|Win32.Build.0 = Release|Win32
- {204FA0DE-305D-4414-AE2E-F195A23F390D}.Release|x64.ActiveCfg = Release|x64
- {204FA0DE-305D-4414-AE2E-F195A23F390D}.Release|x64.Build.0 = Release|x64
- {0DF3ABD0-DDC0-4265-B778-07C66780979B}.All|Win32.ActiveCfg = Release|x64
- {0DF3ABD0-DDC0-4265-B778-07C66780979B}.All|x64.ActiveCfg = Release|x64
- {0DF3ABD0-DDC0-4265-B778-07C66780979B}.All|x64.Build.0 = Release|x64
- {0DF3ABD0-DDC0-4265-B778-07C66780979B}.Debug|Win32.ActiveCfg = Debug|Win32
- {0DF3ABD0-DDC0-4265-B778-07C66780979B}.Debug|Win32.Build.0 = Debug|Win32
- {0DF3ABD0-DDC0-4265-B778-07C66780979B}.Debug|x64.ActiveCfg = Debug|x64
- {0DF3ABD0-DDC0-4265-B778-07C66780979B}.Debug|x64.Build.0 = Debug|x64
- {0DF3ABD0-DDC0-4265-B778-07C66780979B}.Release|Win32.ActiveCfg = Release|Win32
- {0DF3ABD0-DDC0-4265-B778-07C66780979B}.Release|Win32.Build.0 = Release|Win32
- {0DF3ABD0-DDC0-4265-B778-07C66780979B}.Release|x64.ActiveCfg = Release|x64
- {0DF3ABD0-DDC0-4265-B778-07C66780979B}.Release|x64.Build.0 = Release|x64
- {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}.All|Win32.ActiveCfg = Release|x64
- {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}.All|x64.ActiveCfg = Release|x64
- {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}.All|x64.Build.0 = Release|x64
- {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}.Debug|Win32.ActiveCfg = Debug|Win32
- {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}.Debug|Win32.Build.0 = Debug|Win32
- {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}.Debug|x64.ActiveCfg = Debug|x64
- {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}.Debug|x64.Build.0 = Debug|x64
- {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}.Release|Win32.ActiveCfg = Release|Win32
- {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}.Release|Win32.Build.0 = Release|Win32
- {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}.Release|x64.ActiveCfg = Release|x64
- {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}.Release|x64.Build.0 = Release|x64
- {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}.All|Win32.ActiveCfg = Release|Win32
- {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}.All|Win32.Build.0 = Release|Win32
- {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}.All|x64.ActiveCfg = Release|Win32
- {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}.All|x64.Build.0 = Release|Win32
- {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}.Debug|Win32.ActiveCfg = Debug|Win32
- {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}.Debug|Win32.Build.0 = Debug|Win32
- {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}.Debug|x64.ActiveCfg = Debug|Win32
- {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}.Debug|x64.Build.0 = Debug|Win32
- {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}.Release|Win32.ActiveCfg = Release|Win32
- {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}.Release|Win32.Build.0 = Release|Win32
- {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}.Release|x64.ActiveCfg = Release|Win32
- {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}.Release|x64.Build.0 = Release|Win32
- {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}.All|Win32.ActiveCfg = Release DLL|x64
- {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}.All|x64.ActiveCfg = Release DLL|x64
- {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}.All|x64.Build.0 = Release DLL|x64
- {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}.Debug|Win32.ActiveCfg = Debug DLL|Win32
- {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}.Debug|Win32.Build.0 = Debug DLL|Win32
- {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}.Debug|x64.ActiveCfg = Debug DLL|x64
- {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}.Debug|x64.Build.0 = Debug DLL|x64
- {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}.Release|Win32.ActiveCfg = Release DLL|Win32
- {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}.Release|Win32.Build.0 = Release DLL|Win32
- {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}.Release|x64.ActiveCfg = Release DLL|x64
- {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}.Release|x64.Build.0 = Release DLL|x64
- {FEA1EEF7-876F-48DE-88BF-C0E3E606D758}.All|Win32.ActiveCfg = Release Passthrough|x64
- {FEA1EEF7-876F-48DE-88BF-C0E3E606D758}.All|x64.ActiveCfg = Release Passthrough|x64
- {FEA1EEF7-876F-48DE-88BF-C0E3E606D758}.All|x64.Build.0 = Release Passthrough|x64
- {FEA1EEF7-876F-48DE-88BF-C0E3E606D758}.Debug|Win32.ActiveCfg = Debug Passthrough|Win32
- {FEA1EEF7-876F-48DE-88BF-C0E3E606D758}.Debug|Win32.Build.0 = Debug Passthrough|Win32
- {FEA1EEF7-876F-48DE-88BF-C0E3E606D758}.Debug|x64.ActiveCfg = Debug Passthrough|x64
- {FEA1EEF7-876F-48DE-88BF-C0E3E606D758}.Debug|x64.Build.0 = Debug Passthrough|x64
- {FEA1EEF7-876F-48DE-88BF-C0E3E606D758}.Release|Win32.ActiveCfg = Release Passthrough|Win32
- {FEA1EEF7-876F-48DE-88BF-C0E3E606D758}.Release|Win32.Build.0 = Release Passthrough|Win32
- {FEA1EEF7-876F-48DE-88BF-C0E3E606D758}.Release|x64.ActiveCfg = Release Passthrough|x64
- {FEA1EEF7-876F-48DE-88BF-C0E3E606D758}.Release|x64.Build.0 = Release Passthrough|x64
- {9254C4B0-6F60-42B6-BB3A-36D63FC001C7}.All|Win32.ActiveCfg = Release|x64
- {9254C4B0-6F60-42B6-BB3A-36D63FC001C7}.All|x64.ActiveCfg = Release|x64
- {9254C4B0-6F60-42B6-BB3A-36D63FC001C7}.All|x64.Build.0 = Release|x64
- {9254C4B0-6F60-42B6-BB3A-36D63FC001C7}.Debug|Win32.ActiveCfg = Debug|Win32
- {9254C4B0-6F60-42B6-BB3A-36D63FC001C7}.Debug|Win32.Build.0 = Debug|Win32
- {9254C4B0-6F60-42B6-BB3A-36D63FC001C7}.Debug|x64.ActiveCfg = Debug|x64
- {9254C4B0-6F60-42B6-BB3A-36D63FC001C7}.Debug|x64.Build.0 = Debug|x64
- {9254C4B0-6F60-42B6-BB3A-36D63FC001C7}.Release|Win32.ActiveCfg = Release|Win32
- {9254C4B0-6F60-42B6-BB3A-36D63FC001C7}.Release|Win32.Build.0 = Release|Win32
- {9254C4B0-6F60-42B6-BB3A-36D63FC001C7}.Release|x64.ActiveCfg = Release|x64
- {9254C4B0-6F60-42B6-BB3A-36D63FC001C7}.Release|x64.Build.0 = Release|x64
- {ACFFF684-4D19-4D48-AF12-88EA1D778BDF}.All|Win32.ActiveCfg = Release|x64
- {ACFFF684-4D19-4D48-AF12-88EA1D778BDF}.All|x64.ActiveCfg = Release|x64
- {ACFFF684-4D19-4D48-AF12-88EA1D778BDF}.All|x64.Build.0 = Release|x64
- {ACFFF684-4D19-4D48-AF12-88EA1D778BDF}.Debug|Win32.ActiveCfg = Debug|Win32
- {ACFFF684-4D19-4D48-AF12-88EA1D778BDF}.Debug|Win32.Build.0 = Debug|Win32
- {ACFFF684-4D19-4D48-AF12-88EA1D778BDF}.Debug|x64.ActiveCfg = Debug|x64
- {ACFFF684-4D19-4D48-AF12-88EA1D778BDF}.Release|Win32.ActiveCfg = Release|Win32
- {ACFFF684-4D19-4D48-AF12-88EA1D778BDF}.Release|Win32.Build.0 = Release|Win32
- {ACFFF684-4D19-4D48-AF12-88EA1D778BDF}.Release|x64.ActiveCfg = Release|x64
- {8F992C49-6C51-412F-B2A3-34EAB708EB65}.All|Win32.ActiveCfg = Release|x64
- {8F992C49-6C51-412F-B2A3-34EAB708EB65}.All|x64.ActiveCfg = Release|x64
- {8F992C49-6C51-412F-B2A3-34EAB708EB65}.All|x64.Build.0 = Release|x64
- {8F992C49-6C51-412F-B2A3-34EAB708EB65}.Debug|Win32.ActiveCfg = Debug|Win32
- {8F992C49-6C51-412F-B2A3-34EAB708EB65}.Debug|Win32.Build.0 = Debug|Win32
- {8F992C49-6C51-412F-B2A3-34EAB708EB65}.Debug|x64.ActiveCfg = Debug|x64
- {8F992C49-6C51-412F-B2A3-34EAB708EB65}.Release|Win32.ActiveCfg = Release|Win32
- {8F992C49-6C51-412F-B2A3-34EAB708EB65}.Release|Win32.Build.0 = Release|Win32
- {8F992C49-6C51-412F-B2A3-34EAB708EB65}.Release|x64.ActiveCfg = Release|x64
- {71A967D5-0E99-4CEF-A587-98836EE6F2EF}.All|Win32.ActiveCfg = Release|x64
- {71A967D5-0E99-4CEF-A587-98836EE6F2EF}.All|x64.ActiveCfg = Release|x64
- {71A967D5-0E99-4CEF-A587-98836EE6F2EF}.All|x64.Build.0 = Release|x64
- {71A967D5-0E99-4CEF-A587-98836EE6F2EF}.Debug|Win32.ActiveCfg = Debug|Win32
- {71A967D5-0E99-4CEF-A587-98836EE6F2EF}.Debug|Win32.Build.0 = Debug|Win32
- {71A967D5-0E99-4CEF-A587-98836EE6F2EF}.Debug|x64.ActiveCfg = Debug|x64
- {71A967D5-0E99-4CEF-A587-98836EE6F2EF}.Debug|x64.Build.0 = Debug|x64
- {71A967D5-0E99-4CEF-A587-98836EE6F2EF}.Release|Win32.ActiveCfg = Release|Win32
- {71A967D5-0E99-4CEF-A587-98836EE6F2EF}.Release|Win32.Build.0 = Release|Win32
- {71A967D5-0E99-4CEF-A587-98836EE6F2EF}.Release|x64.ActiveCfg = Release|x64
- {71A967D5-0E99-4CEF-A587-98836EE6F2EF}.Release|x64.Build.0 = Release|x64
- {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}.All|Win32.ActiveCfg = Release|x64
- {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}.All|x64.ActiveCfg = Release|x64
- {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}.All|x64.Build.0 = Release|x64
- {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}.Debug|Win32.ActiveCfg = Debug|Win32
- {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}.Debug|Win32.Build.0 = Debug|Win32
- {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}.Debug|x64.ActiveCfg = Debug|x64
- {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}.Release|Win32.ActiveCfg = Release|Win32
- {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}.Release|Win32.Build.0 = Release|Win32
- {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}.Release|x64.ActiveCfg = Release|x64
- {AB91A099-7690-4ECF-8994-E458F4EA1ED4}.All|Win32.ActiveCfg = Release|x64
- {AB91A099-7690-4ECF-8994-E458F4EA1ED4}.All|x64.ActiveCfg = Release|x64
- {AB91A099-7690-4ECF-8994-E458F4EA1ED4}.All|x64.Build.0 = Release|x64
- {AB91A099-7690-4ECF-8994-E458F4EA1ED4}.Debug|Win32.ActiveCfg = Debug|Win32
- {AB91A099-7690-4ECF-8994-E458F4EA1ED4}.Debug|Win32.Build.0 = Debug|Win32
- {AB91A099-7690-4ECF-8994-E458F4EA1ED4}.Debug|x64.ActiveCfg = Debug|x64
- {AB91A099-7690-4ECF-8994-E458F4EA1ED4}.Debug|x64.Build.0 = Debug|x64
- {AB91A099-7690-4ECF-8994-E458F4EA1ED4}.Release|Win32.ActiveCfg = Release|Win32
- {AB91A099-7690-4ECF-8994-E458F4EA1ED4}.Release|Win32.Build.0 = Release|Win32
- {AB91A099-7690-4ECF-8994-E458F4EA1ED4}.Release|x64.ActiveCfg = Release|x64
- {AB91A099-7690-4ECF-8994-E458F4EA1ED4}.Release|x64.Build.0 = Release|x64
- {988CACF7-3FCB-4992-BE69-77872AE67DC8}.All|Win32.ActiveCfg = Release|x64
- {988CACF7-3FCB-4992-BE69-77872AE67DC8}.All|x64.ActiveCfg = Release|x64
- {988CACF7-3FCB-4992-BE69-77872AE67DC8}.All|x64.Build.0 = Release|x64
- {988CACF7-3FCB-4992-BE69-77872AE67DC8}.Debug|Win32.ActiveCfg = Debug|Win32
- {988CACF7-3FCB-4992-BE69-77872AE67DC8}.Debug|Win32.Build.0 = Debug|Win32
- {988CACF7-3FCB-4992-BE69-77872AE67DC8}.Debug|x64.ActiveCfg = Debug|x64
- {988CACF7-3FCB-4992-BE69-77872AE67DC8}.Debug|x64.Build.0 = Debug|x64
- {988CACF7-3FCB-4992-BE69-77872AE67DC8}.Release|Win32.ActiveCfg = Release|Win32
- {988CACF7-3FCB-4992-BE69-77872AE67DC8}.Release|Win32.Build.0 = Release|Win32
- {988CACF7-3FCB-4992-BE69-77872AE67DC8}.Release|x64.ActiveCfg = Release|x64
- {988CACF7-3FCB-4992-BE69-77872AE67DC8}.Release|x64.Build.0 = Release|x64
- {0A18A071-125E-442F-AFF7-A3F68ABECF99}.All|Win32.ActiveCfg = Release DirectSound|x64
- {0A18A071-125E-442F-AFF7-A3F68ABECF99}.All|x64.ActiveCfg = Release DirectSound|x64
- {0A18A071-125E-442F-AFF7-A3F68ABECF99}.All|x64.Build.0 = Release DirectSound|x64
- {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Debug|Win32.ActiveCfg = Debug|Win32
- {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Debug|Win32.Build.0 = Debug|Win32
- {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Debug|x64.ActiveCfg = Debug|x64
- {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Debug|x64.Build.0 = Debug|x64
- {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Release|Win32.ActiveCfg = Release|Win32
- {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Release|Win32.Build.0 = Release|Win32
- {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Release|x64.ActiveCfg = Release|x64
- {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Release|x64.Build.0 = Release|x64
- {08DAD348-9E0A-4A2E-97F1-F1E7E24A7836}.All|Win32.ActiveCfg = Release|x64
- {08DAD348-9E0A-4A2E-97F1-F1E7E24A7836}.All|x64.ActiveCfg = Release|x64
- {08DAD348-9E0A-4A2E-97F1-F1E7E24A7836}.All|x64.Build.0 = Release|x64
- {08DAD348-9E0A-4A2E-97F1-F1E7E24A7836}.Debug|Win32.ActiveCfg = Debug|Win32
- {08DAD348-9E0A-4A2E-97F1-F1E7E24A7836}.Debug|Win32.Build.0 = Debug|Win32
- {08DAD348-9E0A-4A2E-97F1-F1E7E24A7836}.Debug|x64.ActiveCfg = Debug|x64
- {08DAD348-9E0A-4A2E-97F1-F1E7E24A7836}.Debug|x64.Build.0 = Debug|x64
- {08DAD348-9E0A-4A2E-97F1-F1E7E24A7836}.Release|Win32.ActiveCfg = Release|Win32
- {08DAD348-9E0A-4A2E-97F1-F1E7E24A7836}.Release|Win32.Build.0 = Release|Win32
- {08DAD348-9E0A-4A2E-97F1-F1E7E24A7836}.Release|x64.ActiveCfg = Release|x64
- {08DAD348-9E0A-4A2E-97F1-F1E7E24A7836}.Release|x64.Build.0 = Release|x64
- {8DEB383C-4091-4F42-A56F-C9E46D552D79}.All|Win32.ActiveCfg = Release Passthrough|x64
- {8DEB383C-4091-4F42-A56F-C9E46D552D79}.All|x64.ActiveCfg = Release Passthrough|x64
- {8DEB383C-4091-4F42-A56F-C9E46D552D79}.All|x64.Build.0 = Release Passthrough|x64
- {8DEB383C-4091-4F42-A56F-C9E46D552D79}.Debug|Win32.ActiveCfg = Debug Passthrough|Win32
- {8DEB383C-4091-4F42-A56F-C9E46D552D79}.Debug|Win32.Build.0 = Debug Passthrough|Win32
- {8DEB383C-4091-4F42-A56F-C9E46D552D79}.Debug|x64.ActiveCfg = Debug Passthrough|x64
- {8DEB383C-4091-4F42-A56F-C9E46D552D79}.Debug|x64.Build.0 = Debug Passthrough|x64
- {8DEB383C-4091-4F42-A56F-C9E46D552D79}.Release|Win32.ActiveCfg = Release Passthrough|Win32
- {8DEB383C-4091-4F42-A56F-C9E46D552D79}.Release|Win32.Build.0 = Release Passthrough|Win32
- {8DEB383C-4091-4F42-A56F-C9E46D552D79}.Release|x64.ActiveCfg = Release Passthrough|x64
- {8DEB383C-4091-4F42-A56F-C9E46D552D79}.Release|x64.Build.0 = Release Passthrough|x64
- {2C3C2423-234B-4772-8899-D3B137E5CA35}.All|Win32.ActiveCfg = Release|x64
- {2C3C2423-234B-4772-8899-D3B137E5CA35}.All|x64.ActiveCfg = Release|x64
- {2C3C2423-234B-4772-8899-D3B137E5CA35}.All|x64.Build.0 = Release|x64
- {2C3C2423-234B-4772-8899-D3B137E5CA35}.Debug|Win32.ActiveCfg = Debug|Win32
- {2C3C2423-234B-4772-8899-D3B137E5CA35}.Debug|Win32.Build.0 = Debug|Win32
- {2C3C2423-234B-4772-8899-D3B137E5CA35}.Debug|x64.ActiveCfg = Debug|x64
- {2C3C2423-234B-4772-8899-D3B137E5CA35}.Debug|x64.Build.0 = Debug|x64
- {2C3C2423-234B-4772-8899-D3B137E5CA35}.Release|Win32.ActiveCfg = Release|Win32
- {2C3C2423-234B-4772-8899-D3B137E5CA35}.Release|Win32.Build.0 = Release|Win32
- {2C3C2423-234B-4772-8899-D3B137E5CA35}.Release|x64.ActiveCfg = Release|x64
- {2C3C2423-234B-4772-8899-D3B137E5CA35}.Release|x64.Build.0 = Release|x64
- {3850D93A-5F24-4922-BC1C-74D08C37C256}.All|Win32.ActiveCfg = Release|x64
- {3850D93A-5F24-4922-BC1C-74D08C37C256}.All|x64.ActiveCfg = Release|x64
- {3850D93A-5F24-4922-BC1C-74D08C37C256}.All|x64.Build.0 = Release|x64
- {3850D93A-5F24-4922-BC1C-74D08C37C256}.Debug|Win32.ActiveCfg = Debug|Win32
- {3850D93A-5F24-4922-BC1C-74D08C37C256}.Debug|Win32.Build.0 = Debug|Win32
- {3850D93A-5F24-4922-BC1C-74D08C37C256}.Debug|x64.ActiveCfg = Debug|x64
- {3850D93A-5F24-4922-BC1C-74D08C37C256}.Debug|x64.Build.0 = Debug|x64
- {3850D93A-5F24-4922-BC1C-74D08C37C256}.Release|Win32.ActiveCfg = Release|Win32
- {3850D93A-5F24-4922-BC1C-74D08C37C256}.Release|Win32.Build.0 = Release|Win32
- {3850D93A-5F24-4922-BC1C-74D08C37C256}.Release|x64.ActiveCfg = Release|x64
- {3850D93A-5F24-4922-BC1C-74D08C37C256}.Release|x64.Build.0 = Release|x64
- {2CA40887-1622-46A1-A7F9-17FD7E7E545B}.All|Win32.ActiveCfg = Release|x64
- {2CA40887-1622-46A1-A7F9-17FD7E7E545B}.All|x64.ActiveCfg = Release|x64
- {2CA40887-1622-46A1-A7F9-17FD7E7E545B}.All|x64.Build.0 = Release|x64
- {2CA40887-1622-46A1-A7F9-17FD7E7E545B}.Debug|Win32.ActiveCfg = Debug|Win32
- {2CA40887-1622-46A1-A7F9-17FD7E7E545B}.Debug|Win32.Build.0 = Debug|Win32
- {2CA40887-1622-46A1-A7F9-17FD7E7E545B}.Debug|x64.ActiveCfg = Debug|x64
- {2CA40887-1622-46A1-A7F9-17FD7E7E545B}.Debug|x64.Build.0 = Debug|x64
- {2CA40887-1622-46A1-A7F9-17FD7E7E545B}.Release|Win32.ActiveCfg = Release|Win32
- {2CA40887-1622-46A1-A7F9-17FD7E7E545B}.Release|Win32.Build.0 = Release|Win32
- {2CA40887-1622-46A1-A7F9-17FD7E7E545B}.Release|x64.ActiveCfg = Release|x64
- {2CA40887-1622-46A1-A7F9-17FD7E7E545B}.Release|x64.Build.0 = Release|x64
- {028C7278-05D7-4E18-82FE-BE231B844F41}.All|Win32.ActiveCfg = Release|x64
- {028C7278-05D7-4E18-82FE-BE231B844F41}.All|x64.ActiveCfg = Release|x64
- {028C7278-05D7-4E18-82FE-BE231B844F41}.All|x64.Build.0 = Release|x64
- {028C7278-05D7-4E18-82FE-BE231B844F41}.Debug|Win32.ActiveCfg = Debug|Win32
- {028C7278-05D7-4E18-82FE-BE231B844F41}.Debug|Win32.Build.0 = Debug|Win32
- {028C7278-05D7-4E18-82FE-BE231B844F41}.Debug|x64.ActiveCfg = Debug|x64
- {028C7278-05D7-4E18-82FE-BE231B844F41}.Release|Win32.ActiveCfg = Release|Win32
- {028C7278-05D7-4E18-82FE-BE231B844F41}.Release|Win32.Build.0 = Release|Win32
- {028C7278-05D7-4E18-82FE-BE231B844F41}.Release|x64.ActiveCfg = Release|x64
- {D7F1E3F2-A3F4-474C-8555-15122571AF52}.All|Win32.ActiveCfg = Release|x64
- {D7F1E3F2-A3F4-474C-8555-15122571AF52}.All|x64.ActiveCfg = Release|x64
- {D7F1E3F2-A3F4-474C-8555-15122571AF52}.All|x64.Build.0 = Release|x64
- {D7F1E3F2-A3F4-474C-8555-15122571AF52}.Debug|Win32.ActiveCfg = Debug|Win32
- {D7F1E3F2-A3F4-474C-8555-15122571AF52}.Debug|Win32.Build.0 = Debug|Win32
- {D7F1E3F2-A3F4-474C-8555-15122571AF52}.Debug|x64.ActiveCfg = Debug|x64
- {D7F1E3F2-A3F4-474C-8555-15122571AF52}.Debug|x64.Build.0 = Debug|x64
- {D7F1E3F2-A3F4-474C-8555-15122571AF52}.Release|Win32.ActiveCfg = Release|Win32
- {D7F1E3F2-A3F4-474C-8555-15122571AF52}.Release|Win32.Build.0 = Release|Win32
- {D7F1E3F2-A3F4-474C-8555-15122571AF52}.Release|x64.ActiveCfg = Release|x64
- {D7F1E3F2-A3F4-474C-8555-15122571AF52}.Release|x64.Build.0 = Release|x64
- {5BC072DB-3826-48EA-AF34-FE32AA01E83B}.All|Win32.ActiveCfg = Release|x64
- {5BC072DB-3826-48EA-AF34-FE32AA01E83B}.All|x64.ActiveCfg = Release|x64
- {5BC072DB-3826-48EA-AF34-FE32AA01E83B}.All|x64.Build.0 = Release|x64
- {5BC072DB-3826-48EA-AF34-FE32AA01E83B}.Debug|Win32.ActiveCfg = Debug|Win32
- {5BC072DB-3826-48EA-AF34-FE32AA01E83B}.Debug|Win32.Build.0 = Debug|Win32
- {5BC072DB-3826-48EA-AF34-FE32AA01E83B}.Debug|x64.ActiveCfg = Debug|x64
- {5BC072DB-3826-48EA-AF34-FE32AA01E83B}.Debug|x64.Build.0 = Debug|x64
- {5BC072DB-3826-48EA-AF34-FE32AA01E83B}.Release|Win32.ActiveCfg = Release|Win32
- {5BC072DB-3826-48EA-AF34-FE32AA01E83B}.Release|Win32.Build.0 = Release|Win32
- {5BC072DB-3826-48EA-AF34-FE32AA01E83B}.Release|x64.ActiveCfg = Release|x64
- {5BC072DB-3826-48EA-AF34-FE32AA01E83B}.Release|x64.Build.0 = Release|x64
- {FA429E98-8B03-45E6-A096-A4BC5E821DE4}.All|Win32.ActiveCfg = Release|x64
- {FA429E98-8B03-45E6-A096-A4BC5E821DE4}.All|x64.ActiveCfg = Release|x64
- {FA429E98-8B03-45E6-A096-A4BC5E821DE4}.All|x64.Build.0 = Release|x64
- {FA429E98-8B03-45E6-A096-A4BC5E821DE4}.Debug|Win32.ActiveCfg = Debug|Win32
- {FA429E98-8B03-45E6-A096-A4BC5E821DE4}.Debug|Win32.Build.0 = Debug|Win32
- {FA429E98-8B03-45E6-A096-A4BC5E821DE4}.Debug|x64.ActiveCfg = Debug|x64
- {FA429E98-8B03-45E6-A096-A4BC5E821DE4}.Debug|x64.Build.0 = Debug|x64
- {FA429E98-8B03-45E6-A096-A4BC5E821DE4}.Release|Win32.ActiveCfg = Release|Win32
- {FA429E98-8B03-45E6-A096-A4BC5E821DE4}.Release|Win32.Build.0 = Release|Win32
- {FA429E98-8B03-45E6-A096-A4BC5E821DE4}.Release|x64.ActiveCfg = Release|x64
- {FA429E98-8B03-45E6-A096-A4BC5E821DE4}.Release|x64.Build.0 = Release|x64
- {06E3A538-AB32-44F2-B477-755FF9CB5D37}.All|Win32.ActiveCfg = Release|x64
- {06E3A538-AB32-44F2-B477-755FF9CB5D37}.All|x64.ActiveCfg = Release|x64
- {06E3A538-AB32-44F2-B477-755FF9CB5D37}.All|x64.Build.0 = Release|x64
- {06E3A538-AB32-44F2-B477-755FF9CB5D37}.Debug|Win32.ActiveCfg = Debug|Win32
- {06E3A538-AB32-44F2-B477-755FF9CB5D37}.Debug|Win32.Build.0 = Debug|Win32
- {06E3A538-AB32-44F2-B477-755FF9CB5D37}.Debug|x64.ActiveCfg = Debug|x64
- {06E3A538-AB32-44F2-B477-755FF9CB5D37}.Debug|x64.Build.0 = Debug|x64
- {06E3A538-AB32-44F2-B477-755FF9CB5D37}.Release|Win32.ActiveCfg = Release|Win32
- {06E3A538-AB32-44F2-B477-755FF9CB5D37}.Release|Win32.Build.0 = Release|Win32
- {06E3A538-AB32-44F2-B477-755FF9CB5D37}.Release|x64.ActiveCfg = Release|x64
- {06E3A538-AB32-44F2-B477-755FF9CB5D37}.Release|x64.Build.0 = Release|x64
- {6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05}.All|Win32.ActiveCfg = Release|x64
- {6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05}.All|x64.ActiveCfg = Release|x64
- {6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05}.All|x64.Build.0 = Release|x64
- {6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05}.Debug|Win32.ActiveCfg = Debug|Win32
- {6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05}.Debug|Win32.Build.0 = Debug|Win32
- {6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05}.Debug|x64.ActiveCfg = Debug|x64
- {6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05}.Debug|x64.Build.0 = Debug|x64
- {6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05}.Release|Win32.ActiveCfg = Release|Win32
- {6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05}.Release|Win32.Build.0 = Release|Win32
- {6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05}.Release|x64.ActiveCfg = Release|x64
- {6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05}.Release|x64.Build.0 = Release|x64
- {A4B122CF-5196-476B-8C0E-D8BD59AC3C14}.All|Win32.ActiveCfg = Release|x64
- {A4B122CF-5196-476B-8C0E-D8BD59AC3C14}.All|x64.ActiveCfg = Release|x64
- {A4B122CF-5196-476B-8C0E-D8BD59AC3C14}.All|x64.Build.0 = Release|x64
- {A4B122CF-5196-476B-8C0E-D8BD59AC3C14}.Debug|Win32.ActiveCfg = Debug|Win32
- {A4B122CF-5196-476B-8C0E-D8BD59AC3C14}.Debug|Win32.Build.0 = Debug|Win32
- {A4B122CF-5196-476B-8C0E-D8BD59AC3C14}.Debug|x64.ActiveCfg = Debug|x64
- {A4B122CF-5196-476B-8C0E-D8BD59AC3C14}.Debug|x64.Build.0 = Debug|x64
- {A4B122CF-5196-476B-8C0E-D8BD59AC3C14}.Release|Win32.ActiveCfg = Release|Win32
- {A4B122CF-5196-476B-8C0E-D8BD59AC3C14}.Release|Win32.Build.0 = Release|Win32
- {A4B122CF-5196-476B-8C0E-D8BD59AC3C14}.Release|x64.ActiveCfg = Release|x64
- {A4B122CF-5196-476B-8C0E-D8BD59AC3C14}.Release|x64.Build.0 = Release|x64
- {75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD}.All|Win32.ActiveCfg = Release|x64
- {75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD}.All|x64.ActiveCfg = Release|x64
- {75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD}.All|x64.Build.0 = Release|x64
- {75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD}.Debug|Win32.ActiveCfg = Debug|Win32
- {75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD}.Debug|Win32.Build.0 = Debug|Win32
- {75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD}.Debug|x64.ActiveCfg = Debug|x64
- {75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD}.Debug|x64.Build.0 = Debug|x64
- {75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD}.Release|Win32.ActiveCfg = Release|Win32
- {75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD}.Release|Win32.Build.0 = Release|Win32
- {75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD}.Release|x64.ActiveCfg = Release|x64
- {75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD}.Release|x64.Build.0 = Release|x64
- {F6A33240-8F29-48BD-98F0-826995911799}.All|Win32.ActiveCfg = Release|x64
- {F6A33240-8F29-48BD-98F0-826995911799}.All|x64.ActiveCfg = Release|x64
- {F6A33240-8F29-48BD-98F0-826995911799}.All|x64.Build.0 = Release|x64
- {F6A33240-8F29-48BD-98F0-826995911799}.Debug|Win32.ActiveCfg = Debug|Win32
- {F6A33240-8F29-48BD-98F0-826995911799}.Debug|Win32.Build.0 = Debug|Win32
- {F6A33240-8F29-48BD-98F0-826995911799}.Debug|x64.ActiveCfg = Debug|x64
- {F6A33240-8F29-48BD-98F0-826995911799}.Debug|x64.Build.0 = Debug|x64
- {F6A33240-8F29-48BD-98F0-826995911799}.Release|Win32.ActiveCfg = Release|Win32
- {F6A33240-8F29-48BD-98F0-826995911799}.Release|Win32.Build.0 = Release|Win32
- {F6A33240-8F29-48BD-98F0-826995911799}.Release|x64.ActiveCfg = Release|x64
- {F6A33240-8F29-48BD-98F0-826995911799}.Release|x64.Build.0 = Release|x64
- {65A6273D-FCAB-4C55-B09E-65100141A5D4}.All|Win32.ActiveCfg = Release|x64
- {65A6273D-FCAB-4C55-B09E-65100141A5D4}.All|x64.ActiveCfg = Release|x64
- {65A6273D-FCAB-4C55-B09E-65100141A5D4}.All|x64.Build.0 = Release|x64
- {65A6273D-FCAB-4C55-B09E-65100141A5D4}.Debug|Win32.ActiveCfg = Debug|Win32
- {65A6273D-FCAB-4C55-B09E-65100141A5D4}.Debug|Win32.Build.0 = Debug|Win32
- {65A6273D-FCAB-4C55-B09E-65100141A5D4}.Debug|x64.ActiveCfg = Debug|x64
- {65A6273D-FCAB-4C55-B09E-65100141A5D4}.Debug|x64.Build.0 = Debug|x64
- {65A6273D-FCAB-4C55-B09E-65100141A5D4}.Release|Win32.ActiveCfg = Release|Win32
- {65A6273D-FCAB-4C55-B09E-65100141A5D4}.Release|Win32.Build.0 = Release|Win32
- {65A6273D-FCAB-4C55-B09E-65100141A5D4}.Release|x64.ActiveCfg = Release|x64
- {65A6273D-FCAB-4C55-B09E-65100141A5D4}.Release|x64.Build.0 = Release|x64
- {E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24}.All|Win32.ActiveCfg = Release|x64
- {E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24}.All|x64.ActiveCfg = Release|x64
- {E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24}.All|x64.Build.0 = Release|x64
- {E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24}.Debug|Win32.ActiveCfg = Debug|Win32
- {E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24}.Debug|Win32.Build.0 = Debug|Win32
- {E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24}.Debug|x64.ActiveCfg = Debug|x64
- {E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24}.Debug|x64.Build.0 = Debug|x64
- {E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24}.Release|Win32.ActiveCfg = Release|Win32
- {E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24}.Release|Win32.Build.0 = Release|Win32
- {E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24}.Release|x64.ActiveCfg = Release|x64
- {E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24}.Release|x64.Build.0 = Release|x64
- {D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909}.All|Win32.ActiveCfg = Release|x64
- {D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909}.All|x64.ActiveCfg = Release|x64
- {D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909}.All|x64.Build.0 = Release|x64
- {D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909}.Debug|Win32.ActiveCfg = Debug|Win32
- {D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909}.Debug|Win32.Build.0 = Debug|Win32
- {D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909}.Debug|x64.ActiveCfg = Debug|x64
- {D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909}.Debug|x64.Build.0 = Debug|x64
- {D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909}.Release|Win32.ActiveCfg = Release|Win32
- {D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909}.Release|Win32.Build.0 = Release|Win32
- {D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909}.Release|x64.ActiveCfg = Release|x64
- {D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909}.Release|x64.Build.0 = Release|x64
- {44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E}.All|Win32.ActiveCfg = Release|x64
- {44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E}.All|x64.ActiveCfg = Release|x64
- {44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E}.All|x64.Build.0 = Release|x64
- {44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E}.Debug|Win32.ActiveCfg = Debug|Win32
- {44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E}.Debug|Win32.Build.0 = Debug|Win32
- {44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E}.Debug|x64.ActiveCfg = Debug|x64
- {44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E}.Debug|x64.Build.0 = Debug|x64
- {44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E}.Release|Win32.ActiveCfg = Release|Win32
- {44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E}.Release|Win32.Build.0 = Release|Win32
- {44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E}.Release|x64.ActiveCfg = Release|x64
- {44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E}.Release|x64.Build.0 = Release|x64
- {6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52}.All|Win32.ActiveCfg = Release|x64
- {6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52}.All|x64.ActiveCfg = Release|x64
- {6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52}.All|x64.Build.0 = Release|x64
- {6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52}.Debug|Win32.ActiveCfg = Debug|Win32
- {6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52}.Debug|Win32.Build.0 = Debug|Win32
- {6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52}.Debug|x64.ActiveCfg = Debug|x64
- {6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52}.Debug|x64.Build.0 = Debug|x64
- {6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52}.Release|Win32.ActiveCfg = Release|Win32
- {6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52}.Release|Win32.Build.0 = Release|Win32
- {6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52}.Release|x64.ActiveCfg = Release|x64
- {6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52}.Release|x64.Build.0 = Release|x64
- {E3246D17-E29B-4AB5-962A-C69B0C5837BB}.All|Win32.ActiveCfg = Release|x64
- {E3246D17-E29B-4AB5-962A-C69B0C5837BB}.All|x64.ActiveCfg = Release|x64
- {E3246D17-E29B-4AB5-962A-C69B0C5837BB}.All|x64.Build.0 = Release|x64
- {E3246D17-E29B-4AB5-962A-C69B0C5837BB}.Debug|Win32.ActiveCfg = Debug|Win32
- {E3246D17-E29B-4AB5-962A-C69B0C5837BB}.Debug|Win32.Build.0 = Debug|Win32
- {E3246D17-E29B-4AB5-962A-C69B0C5837BB}.Debug|x64.ActiveCfg = Debug|x64
- {E3246D17-E29B-4AB5-962A-C69B0C5837BB}.Debug|x64.Build.0 = Debug|x64
- {E3246D17-E29B-4AB5-962A-C69B0C5837BB}.Release|Win32.ActiveCfg = Release|Win32
- {E3246D17-E29B-4AB5-962A-C69B0C5837BB}.Release|Win32.Build.0 = Release|Win32
- {E3246D17-E29B-4AB5-962A-C69B0C5837BB}.Release|x64.ActiveCfg = Release|x64
- {E3246D17-E29B-4AB5-962A-C69B0C5837BB}.Release|x64.Build.0 = Release|x64
- {36E854E3-CE12-4348-A125-CCF3F9D74813}.All|Win32.ActiveCfg = Release|x64
- {36E854E3-CE12-4348-A125-CCF3F9D74813}.All|x64.ActiveCfg = Release|x64
- {36E854E3-CE12-4348-A125-CCF3F9D74813}.All|x64.Build.0 = Release|x64
- {36E854E3-CE12-4348-A125-CCF3F9D74813}.Debug|Win32.ActiveCfg = Debug|Win32
- {36E854E3-CE12-4348-A125-CCF3F9D74813}.Debug|Win32.Build.0 = Debug|Win32
- {36E854E3-CE12-4348-A125-CCF3F9D74813}.Debug|x64.ActiveCfg = Debug|x64
- {36E854E3-CE12-4348-A125-CCF3F9D74813}.Release|Win32.ActiveCfg = Release|Win32
- {36E854E3-CE12-4348-A125-CCF3F9D74813}.Release|Win32.Build.0 = Release|Win32
- {36E854E3-CE12-4348-A125-CCF3F9D74813}.Release|x64.ActiveCfg = Release|x64
- {7B077E7F-1BE7-4291-AB86-55E527B25CAC}.All|Win32.ActiveCfg = Release|x64
- {7B077E7F-1BE7-4291-AB86-55E527B25CAC}.All|x64.ActiveCfg = Release|x64
- {7B077E7F-1BE7-4291-AB86-55E527B25CAC}.All|x64.Build.0 = Release|x64
- {7B077E7F-1BE7-4291-AB86-55E527B25CAC}.Debug|Win32.ActiveCfg = Debug|Win32
- {7B077E7F-1BE7-4291-AB86-55E527B25CAC}.Debug|Win32.Build.0 = Debug|Win32
- {7B077E7F-1BE7-4291-AB86-55E527B25CAC}.Debug|x64.ActiveCfg = Debug|x64
- {7B077E7F-1BE7-4291-AB86-55E527B25CAC}.Debug|x64.Build.0 = Debug|x64
- {7B077E7F-1BE7-4291-AB86-55E527B25CAC}.Release|Win32.ActiveCfg = Release|Win32
- {7B077E7F-1BE7-4291-AB86-55E527B25CAC}.Release|Win32.Build.0 = Release|Win32
- {7B077E7F-1BE7-4291-AB86-55E527B25CAC}.Release|x64.ActiveCfg = Release|x64
- {7B077E7F-1BE7-4291-AB86-55E527B25CAC}.Release|x64.Build.0 = Release|x64
- {4F92B672-DADB-4047-8D6A-4BB3796733FD}.All|Win32.ActiveCfg = Release|Win32
- {4F92B672-DADB-4047-8D6A-4BB3796733FD}.All|Win32.Build.0 = Release|Win32
- {4F92B672-DADB-4047-8D6A-4BB3796733FD}.All|x64.ActiveCfg = Release|Win32
- {4F92B672-DADB-4047-8D6A-4BB3796733FD}.All|x64.Build.0 = Release|Win32
- {4F92B672-DADB-4047-8D6A-4BB3796733FD}.Debug|Win32.ActiveCfg = Debug|Win32
- {4F92B672-DADB-4047-8D6A-4BB3796733FD}.Debug|Win32.Build.0 = Debug|Win32
- {4F92B672-DADB-4047-8D6A-4BB3796733FD}.Debug|x64.ActiveCfg = Debug|Win32
- {4F92B672-DADB-4047-8D6A-4BB3796733FD}.Debug|x64.Build.0 = Debug|Win32
- {4F92B672-DADB-4047-8D6A-4BB3796733FD}.Release|Win32.ActiveCfg = Release|Win32
- {4F92B672-DADB-4047-8D6A-4BB3796733FD}.Release|Win32.Build.0 = Release|Win32
- {4F92B672-DADB-4047-8D6A-4BB3796733FD}.Release|x64.ActiveCfg = Release|Win32
- {4F92B672-DADB-4047-8D6A-4BB3796733FD}.Release|x64.Build.0 = Release|Win32
- {2DEE4895-1134-439C-B688-52203E57D878}.All|Win32.ActiveCfg = Release|Win32
- {2DEE4895-1134-439C-B688-52203E57D878}.All|Win32.Build.0 = Release|Win32
- {2DEE4895-1134-439C-B688-52203E57D878}.All|x64.ActiveCfg = Release|Win32
- {2DEE4895-1134-439C-B688-52203E57D878}.All|x64.Build.0 = Release|Win32
- {2DEE4895-1134-439C-B688-52203E57D878}.Debug|Win32.ActiveCfg = Debug|Win32
- {2DEE4895-1134-439C-B688-52203E57D878}.Debug|Win32.Build.0 = Debug|Win32
- {2DEE4895-1134-439C-B688-52203E57D878}.Debug|x64.ActiveCfg = Debug|Win32
- {2DEE4895-1134-439C-B688-52203E57D878}.Debug|x64.Build.0 = Debug|Win32
- {2DEE4895-1134-439C-B688-52203E57D878}.Release|Win32.ActiveCfg = Release|Win32
- {2DEE4895-1134-439C-B688-52203E57D878}.Release|Win32.Build.0 = Release|Win32
- {2DEE4895-1134-439C-B688-52203E57D878}.Release|x64.ActiveCfg = Release|Win32
- {2DEE4895-1134-439C-B688-52203E57D878}.Release|x64.Build.0 = Release|Win32
- {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}.All|Win32.ActiveCfg = Release|Win32
- {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}.All|Win32.Build.0 = Release|Win32
- {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}.All|x64.ActiveCfg = Release|Win32
- {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}.All|x64.Build.0 = Release|Win32
- {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}.Debug|Win32.ActiveCfg = Debug|Win32
- {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}.Debug|Win32.Build.0 = Debug|Win32
- {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}.Debug|x64.ActiveCfg = Debug|Win32
- {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}.Debug|x64.Build.0 = Debug|Win32
- {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}.Release|Win32.ActiveCfg = Release|Win32
- {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}.Release|Win32.Build.0 = Release|Win32
- {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}.Release|x64.ActiveCfg = Release|Win32
- {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}.Release|x64.Build.0 = Release|Win32
- {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}.All|Win32.ActiveCfg = Debug|x64
- {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}.All|x64.ActiveCfg = Debug|x64
- {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}.All|x64.Build.0 = Debug|x64
- {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}.Debug|Win32.ActiveCfg = Debug|Win32
- {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}.Debug|Win32.Build.0 = Debug|Win32
- {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}.Debug|x64.ActiveCfg = Debug|x64
- {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}.Debug|x64.Build.0 = Debug|x64
- {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}.Release|Win32.ActiveCfg = Release|Win32
- {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}.Release|Win32.Build.0 = Release|Win32
- {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}.Release|x64.ActiveCfg = Release|x64
- {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}.Release|x64.Build.0 = Release|x64
- {94001A0E-A837-445C-8004-F918F10D0226}.All|Win32.ActiveCfg = Debug|x64
- {94001A0E-A837-445C-8004-F918F10D0226}.All|x64.ActiveCfg = Debug|x64
- {94001A0E-A837-445C-8004-F918F10D0226}.All|x64.Build.0 = Debug|x64
- {94001A0E-A837-445C-8004-F918F10D0226}.Debug|Win32.ActiveCfg = Debug|Win32
- {94001A0E-A837-445C-8004-F918F10D0226}.Debug|Win32.Build.0 = Debug|Win32
- {94001A0E-A837-445C-8004-F918F10D0226}.Debug|x64.ActiveCfg = Debug|x64
- {94001A0E-A837-445C-8004-F918F10D0226}.Debug|x64.Build.0 = Debug|x64
- {94001A0E-A837-445C-8004-F918F10D0226}.Release|Win32.ActiveCfg = Release|Win32
- {94001A0E-A837-445C-8004-F918F10D0226}.Release|Win32.Build.0 = Release|Win32
- {94001A0E-A837-445C-8004-F918F10D0226}.Release|x64.ActiveCfg = Release|x64
- {94001A0E-A837-445C-8004-F918F10D0226}.Release|x64.Build.0 = Release|x64
- {2286DA73-9FC5-45BC-A508-85994C3317AB}.All|Win32.ActiveCfg = Release|x64
- {2286DA73-9FC5-45BC-A508-85994C3317AB}.All|x64.ActiveCfg = Release|x64
- {2286DA73-9FC5-45BC-A508-85994C3317AB}.All|x64.Build.0 = Release|x64
- {2286DA73-9FC5-45BC-A508-85994C3317AB}.Debug|Win32.ActiveCfg = Debug|Win32
- {2286DA73-9FC5-45BC-A508-85994C3317AB}.Debug|Win32.Build.0 = Debug|Win32
- {2286DA73-9FC5-45BC-A508-85994C3317AB}.Debug|x64.ActiveCfg = Debug|x64
- {2286DA73-9FC5-45BC-A508-85994C3317AB}.Debug|x64.Build.0 = Debug|x64
- {2286DA73-9FC5-45BC-A508-85994C3317AB}.Release|Win32.ActiveCfg = Release|Win32
- {2286DA73-9FC5-45BC-A508-85994C3317AB}.Release|Win32.Build.0 = Release|Win32
- {2286DA73-9FC5-45BC-A508-85994C3317AB}.Release|x64.ActiveCfg = Release|x64
- {2286DA73-9FC5-45BC-A508-85994C3317AB}.Release|x64.Build.0 = Release|x64
- {3CE1DC99-8246-4DB1-A709-74F19F08EC67}.All|Win32.ActiveCfg = Release|Win32
- {3CE1DC99-8246-4DB1-A709-74F19F08EC67}.All|Win32.Build.0 = Release|Win32
- {3CE1DC99-8246-4DB1-A709-74F19F08EC67}.All|x64.ActiveCfg = Release|Win32
- {3CE1DC99-8246-4DB1-A709-74F19F08EC67}.All|x64.Build.0 = Release|Win32
- {3CE1DC99-8246-4DB1-A709-74F19F08EC67}.Debug|Win32.ActiveCfg = Debug|Win32
- {3CE1DC99-8246-4DB1-A709-74F19F08EC67}.Debug|Win32.Build.0 = Debug|Win32
- {3CE1DC99-8246-4DB1-A709-74F19F08EC67}.Debug|x64.ActiveCfg = Debug|Win32
- {3CE1DC99-8246-4DB1-A709-74F19F08EC67}.Debug|x64.Build.0 = Debug|Win32
- {3CE1DC99-8246-4DB1-A709-74F19F08EC67}.Release|Win32.ActiveCfg = Release|Win32
- {3CE1DC99-8246-4DB1-A709-74F19F08EC67}.Release|Win32.Build.0 = Release|Win32
- {3CE1DC99-8246-4DB1-A709-74F19F08EC67}.Release|x64.ActiveCfg = Release|Win32
- {3CE1DC99-8246-4DB1-A709-74F19F08EC67}.Release|x64.Build.0 = Release|Win32
- {87A1FE3D-F410-4C8E-9591-8C625985BC70}.All|Win32.ActiveCfg = Release|Win32
- {87A1FE3D-F410-4C8E-9591-8C625985BC70}.All|x64.ActiveCfg = Release|Win32
- {87A1FE3D-F410-4C8E-9591-8C625985BC70}.Debug|Win32.ActiveCfg = Debug|Win32
- {87A1FE3D-F410-4C8E-9591-8C625985BC70}.Debug|x64.ActiveCfg = Debug|Win32
- {87A1FE3D-F410-4C8E-9591-8C625985BC70}.Release|Win32.ActiveCfg = Release|Win32
- {87A1FE3D-F410-4C8E-9591-8C625985BC70}.Release|x64.ActiveCfg = Release|Win32
- {7A8D8174-B355-4114-AFC1-04777CB9DE0A}.All|Win32.ActiveCfg = Release|Win32
- {7A8D8174-B355-4114-AFC1-04777CB9DE0A}.All|Win32.Build.0 = Release|Win32
- {7A8D8174-B355-4114-AFC1-04777CB9DE0A}.All|x64.ActiveCfg = Release|Win32
- {7A8D8174-B355-4114-AFC1-04777CB9DE0A}.All|x64.Build.0 = Release|Win32
- {7A8D8174-B355-4114-AFC1-04777CB9DE0A}.Debug|Win32.ActiveCfg = Debug|Win32
- {7A8D8174-B355-4114-AFC1-04777CB9DE0A}.Debug|Win32.Build.0 = Debug|Win32
- {7A8D8174-B355-4114-AFC1-04777CB9DE0A}.Debug|x64.ActiveCfg = Debug|x64
- {7A8D8174-B355-4114-AFC1-04777CB9DE0A}.Debug|x64.Build.0 = Debug|x64
- {7A8D8174-B355-4114-AFC1-04777CB9DE0A}.Release|Win32.ActiveCfg = Release|Win32
- {7A8D8174-B355-4114-AFC1-04777CB9DE0A}.Release|Win32.Build.0 = Release|Win32
- {7A8D8174-B355-4114-AFC1-04777CB9DE0A}.Release|x64.ActiveCfg = Release|x64
- {7A8D8174-B355-4114-AFC1-04777CB9DE0A}.Release|x64.Build.0 = Release|x64
- {7EB71250-F002-4ED8-92CA-CA218114537A}.All|Win32.ActiveCfg = Release|Win32
- {7EB71250-F002-4ED8-92CA-CA218114537A}.All|x64.ActiveCfg = Release|Win32
- {7EB71250-F002-4ED8-92CA-CA218114537A}.Debug|Win32.ActiveCfg = Debug|Win32
- {7EB71250-F002-4ED8-92CA-CA218114537A}.Debug|x64.ActiveCfg = Debug|x64
- {7EB71250-F002-4ED8-92CA-CA218114537A}.Release|Win32.ActiveCfg = Release|Win32
- {7EB71250-F002-4ED8-92CA-CA218114537A}.Release|x64.ActiveCfg = Release|x64
- {6E49F6C2-ADDA-4BFB-81FE-AB9AF51B455F}.All|Win32.ActiveCfg = Release|Win32
- {6E49F6C2-ADDA-4BFB-81FE-AB9AF51B455F}.All|x64.ActiveCfg = Release|Win32
- {6E49F6C2-ADDA-4BFB-81FE-AB9AF51B455F}.Debug|Win32.ActiveCfg = Debug|Win32
- {6E49F6C2-ADDA-4BFB-81FE-AB9AF51B455F}.Debug|x64.ActiveCfg = Debug|Win32
- {6E49F6C2-ADDA-4BFB-81FE-AB9AF51B455F}.Release|Win32.ActiveCfg = Release|Win32
- {6E49F6C2-ADDA-4BFB-81FE-AB9AF51B455F}.Release|x64.ActiveCfg = Release|Win32
- {464AAB78-5489-4916-BE51-BF8D61822311}.All|Win32.ActiveCfg = Release|Win32
- {464AAB78-5489-4916-BE51-BF8D61822311}.All|x64.ActiveCfg = Release|Win32
- {464AAB78-5489-4916-BE51-BF8D61822311}.Debug|Win32.ActiveCfg = Debug|Win32
- {464AAB78-5489-4916-BE51-BF8D61822311}.Debug|x64.ActiveCfg = Debug|x64
- {464AAB78-5489-4916-BE51-BF8D61822311}.Release|Win32.ActiveCfg = Release|Win32
- {464AAB78-5489-4916-BE51-BF8D61822311}.Release|x64.ActiveCfg = Release|x64
- {0AD1177E-1FD8-4643-9391-431467A11084}.All|Win32.ActiveCfg = Release|x64
- {0AD1177E-1FD8-4643-9391-431467A11084}.All|x64.ActiveCfg = Release|x64
- {0AD1177E-1FD8-4643-9391-431467A11084}.All|x64.Build.0 = Release|x64
- {0AD1177E-1FD8-4643-9391-431467A11084}.Debug|Win32.ActiveCfg = Debug|Win32
- {0AD1177E-1FD8-4643-9391-431467A11084}.Debug|Win32.Build.0 = Debug|Win32
- {0AD1177E-1FD8-4643-9391-431467A11084}.Debug|x64.ActiveCfg = Debug|x64
- {0AD1177E-1FD8-4643-9391-431467A11084}.Debug|x64.Build.0 = Debug|x64
- {0AD1177E-1FD8-4643-9391-431467A11084}.Release|Win32.ActiveCfg = Release|Win32
- {0AD1177E-1FD8-4643-9391-431467A11084}.Release|Win32.Build.0 = Release|Win32
- {0AD1177E-1FD8-4643-9391-431467A11084}.Release|x64.ActiveCfg = Release|x64
- {0AD1177E-1FD8-4643-9391-431467A11084}.Release|x64.Build.0 = Release|x64
- {66444AEE-554C-11DD-A9F0-8C5D56D89593}.All|Win32.ActiveCfg = Release Static|x64
- {66444AEE-554C-11DD-A9F0-8C5D56D89593}.All|x64.ActiveCfg = Release Static|x64
- {66444AEE-554C-11DD-A9F0-8C5D56D89593}.All|x64.Build.0 = Release Static|x64
- {66444AEE-554C-11DD-A9F0-8C5D56D89593}.Debug|Win32.ActiveCfg = Debug|Win32
- {66444AEE-554C-11DD-A9F0-8C5D56D89593}.Debug|x64.ActiveCfg = Debug|x64
- {66444AEE-554C-11DD-A9F0-8C5D56D89593}.Release|Win32.ActiveCfg = Release|Win32
- {66444AEE-554C-11DD-A9F0-8C5D56D89593}.Release|x64.ActiveCfg = Release|x64
- {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}.All|Win32.ActiveCfg = Release|Win32
- {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}.All|Win32.Build.0 = Release|Win32
- {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}.All|x64.ActiveCfg = Release|Win32
- {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}.All|x64.Build.0 = Release|Win32
- {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}.Debug|Win32.ActiveCfg = Debug|Win32
- {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}.Debug|Win32.Build.0 = Debug|Win32
- {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}.Debug|x64.ActiveCfg = Debug|Win32
- {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}.Debug|x64.Build.0 = Debug|Win32
- {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}.Release|Win32.ActiveCfg = Release|Win32
- {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}.Release|Win32.Build.0 = Release|Win32
- {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}.Release|x64.ActiveCfg = Release|Win32
- {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}.Release|x64.Build.0 = Release|Win32
- {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.All|Win32.ActiveCfg = Release|Win32
- {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.All|Win32.Build.0 = Release|Win32
- {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.All|x64.ActiveCfg = Release|Win32
- {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.All|x64.Build.0 = Release|Win32
- {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.Debug|Win32.ActiveCfg = Debug|Win32
- {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.Debug|Win32.Build.0 = Debug|Win32
- {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.Debug|x64.ActiveCfg = Debug|Win32
- {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.Debug|x64.Build.0 = Debug|Win32
- {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.Release|Win32.ActiveCfg = Release|Win32
- {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.Release|Win32.Build.0 = Release|Win32
- {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.Release|x64.ActiveCfg = Release|Win32
- {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.Release|x64.Build.0 = Release|Win32
- {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}.All|Win32.ActiveCfg = Release|Win32
- {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}.All|Win32.Build.0 = Release|Win32
- {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}.All|x64.ActiveCfg = Release|Win32
- {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}.All|x64.Build.0 = Release|Win32
- {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}.Debug|Win32.ActiveCfg = Debug|Win32
- {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}.Debug|Win32.Build.0 = Debug|Win32
- {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}.Debug|x64.ActiveCfg = Debug|Win32
- {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}.Debug|x64.Build.0 = Debug|Win32
- {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}.Release|Win32.ActiveCfg = Release|Win32
- {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}.Release|Win32.Build.0 = Release|Win32
- {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}.Release|x64.ActiveCfg = Release|Win32
- {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}.Release|x64.Build.0 = Release|Win32
- {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}.All|Win32.ActiveCfg = Release|Win32
- {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}.All|Win32.Build.0 = Release|Win32
- {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}.All|x64.ActiveCfg = Release|Win32
- {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}.All|x64.Build.0 = Release|Win32
- {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}.Debug|Win32.ActiveCfg = Debug|Win32
- {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}.Debug|Win32.Build.0 = Debug|Win32
- {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}.Debug|x64.ActiveCfg = Debug|Win32
- {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}.Debug|x64.Build.0 = Debug|Win32
- {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}.Release|Win32.ActiveCfg = Release|Win32
- {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}.Release|Win32.Build.0 = Release|Win32
- {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}.Release|x64.ActiveCfg = Release|Win32
- {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}.Release|x64.Build.0 = Release|Win32
- {E316772F-5D8F-4F2A-8F71-094C3E859D34}.All|Win32.ActiveCfg = Debug|x64
- {E316772F-5D8F-4F2A-8F71-094C3E859D34}.All|x64.ActiveCfg = Debug|x64
- {E316772F-5D8F-4F2A-8F71-094C3E859D34}.All|x64.Build.0 = Debug|x64
- {E316772F-5D8F-4F2A-8F71-094C3E859D34}.Debug|Win32.ActiveCfg = Debug|Win32
- {E316772F-5D8F-4F2A-8F71-094C3E859D34}.Debug|Win32.Build.0 = Debug|Win32
- {E316772F-5D8F-4F2A-8F71-094C3E859D34}.Debug|x64.ActiveCfg = Debug|x64
- {E316772F-5D8F-4F2A-8F71-094C3E859D34}.Debug|x64.Build.0 = Debug|x64
- {E316772F-5D8F-4F2A-8F71-094C3E859D34}.Release|Win32.ActiveCfg = Release|Win32
- {E316772F-5D8F-4F2A-8F71-094C3E859D34}.Release|Win32.Build.0 = Release|Win32
- {E316772F-5D8F-4F2A-8F71-094C3E859D34}.Release|x64.ActiveCfg = Release|x64
- {E316772F-5D8F-4F2A-8F71-094C3E859D34}.Release|x64.Build.0 = Release|x64
- {D3D8B329-20BE-475E-9E83-653CEA0E0EF5}.All|Win32.ActiveCfg = Debug|x64
- {D3D8B329-20BE-475E-9E83-653CEA0E0EF5}.All|x64.ActiveCfg = Debug|x64
- {D3D8B329-20BE-475E-9E83-653CEA0E0EF5}.All|x64.Build.0 = Debug|x64
- {D3D8B329-20BE-475E-9E83-653CEA0E0EF5}.Debug|Win32.ActiveCfg = Debug|Win32
- {D3D8B329-20BE-475E-9E83-653CEA0E0EF5}.Debug|Win32.Build.0 = Debug|Win32
- {D3D8B329-20BE-475E-9E83-653CEA0E0EF5}.Debug|x64.ActiveCfg = Debug|x64
- {D3D8B329-20BE-475E-9E83-653CEA0E0EF5}.Debug|x64.Build.0 = Debug|x64
- {D3D8B329-20BE-475E-9E83-653CEA0E0EF5}.Release|Win32.ActiveCfg = Release|Win32
- {D3D8B329-20BE-475E-9E83-653CEA0E0EF5}.Release|Win32.Build.0 = Release|Win32
- {D3D8B329-20BE-475E-9E83-653CEA0E0EF5}.Release|x64.ActiveCfg = Release|x64
- {D3D8B329-20BE-475E-9E83-653CEA0E0EF5}.Release|x64.Build.0 = Release|x64
- {38FE0559-9910-43A8-9E45-3E5004C27692}.All|Win32.ActiveCfg = Release|x64
- {38FE0559-9910-43A8-9E45-3E5004C27692}.All|x64.ActiveCfg = Release|x64
- {38FE0559-9910-43A8-9E45-3E5004C27692}.All|x64.Build.0 = Release|x64
- {38FE0559-9910-43A8-9E45-3E5004C27692}.Debug|Win32.ActiveCfg = Debug|Win32
- {38FE0559-9910-43A8-9E45-3E5004C27692}.Debug|Win32.Build.0 = Debug|Win32
- {38FE0559-9910-43A8-9E45-3E5004C27692}.Debug|x64.ActiveCfg = Debug|x64
- {38FE0559-9910-43A8-9E45-3E5004C27692}.Debug|x64.Build.0 = Debug|x64
- {38FE0559-9910-43A8-9E45-3E5004C27692}.Release|Win32.ActiveCfg = Release|Win32
- {38FE0559-9910-43A8-9E45-3E5004C27692}.Release|Win32.Build.0 = Release|Win32
- {38FE0559-9910-43A8-9E45-3E5004C27692}.Release|x64.ActiveCfg = Release|x64
- {38FE0559-9910-43A8-9E45-3E5004C27692}.Release|x64.Build.0 = Release|x64
- {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4}.All|Win32.ActiveCfg = Debug|x64
- {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4}.All|x64.ActiveCfg = Debug|x64
- {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4}.All|x64.Build.0 = Debug|x64
- {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4}.Debug|Win32.ActiveCfg = Debug|Win32
- {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4}.Debug|Win32.Build.0 = Debug|Win32
- {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4}.Debug|x64.ActiveCfg = Debug|x64
- {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4}.Debug|x64.Build.0 = Debug|x64
- {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4}.Release|Win32.ActiveCfg = Release|Win32
- {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4}.Release|Win32.Build.0 = Release|Win32
- {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4}.Release|x64.ActiveCfg = Release|x64
- {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4}.Release|x64.Build.0 = Release|x64
- {2A3D00C6-588D-4E86-81AC-9EF5EDE86E03}.All|Win32.ActiveCfg = Release|x64
- {2A3D00C6-588D-4E86-81AC-9EF5EDE86E03}.All|x64.ActiveCfg = Release|x64
- {2A3D00C6-588D-4E86-81AC-9EF5EDE86E03}.All|x64.Build.0 = Release|x64
- {2A3D00C6-588D-4E86-81AC-9EF5EDE86E03}.Debug|Win32.ActiveCfg = Debug|Win32
- {2A3D00C6-588D-4E86-81AC-9EF5EDE86E03}.Debug|Win32.Build.0 = Debug|Win32
- {2A3D00C6-588D-4E86-81AC-9EF5EDE86E03}.Debug|x64.ActiveCfg = Debug|x64
- {2A3D00C6-588D-4E86-81AC-9EF5EDE86E03}.Debug|x64.Build.0 = Debug|x64
- {2A3D00C6-588D-4E86-81AC-9EF5EDE86E03}.Release|Win32.ActiveCfg = Release|Win32
- {2A3D00C6-588D-4E86-81AC-9EF5EDE86E03}.Release|Win32.Build.0 = Release|Win32
- {2A3D00C6-588D-4E86-81AC-9EF5EDE86E03}.Release|x64.ActiveCfg = Release|x64
- {2A3D00C6-588D-4E86-81AC-9EF5EDE86E03}.Release|x64.Build.0 = Release|x64
- {B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E}.All|Win32.ActiveCfg = Release|x64
- {B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E}.All|x64.ActiveCfg = Release|x64
- {B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E}.All|x64.Build.0 = Release|x64
- {B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E}.Debug|Win32.ActiveCfg = Debug|Win32
- {B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E}.Debug|Win32.Build.0 = Debug|Win32
- {B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E}.Debug|x64.ActiveCfg = Debug|x64
- {B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E}.Debug|x64.Build.0 = Debug|x64
- {B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E}.Release|Win32.ActiveCfg = Release|Win32
- {B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E}.Release|Win32.Build.0 = Release|Win32
- {B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E}.Release|x64.ActiveCfg = Release|x64
- {B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E}.Release|x64.Build.0 = Release|x64
- {7B42BDA1-72C0-4378-A9B6-5C530F8CD61E}.All|Win32.ActiveCfg = Release_Mono|x64
- {7B42BDA1-72C0-4378-A9B6-5C530F8CD61E}.All|x64.ActiveCfg = Release_Mono|x64
- {7B42BDA1-72C0-4378-A9B6-5C530F8CD61E}.All|x64.Build.0 = Release_Mono|x64
- {7B42BDA1-72C0-4378-A9B6-5C530F8CD61E}.Debug|Win32.ActiveCfg = Debug_CLR|Win32
- {7B42BDA1-72C0-4378-A9B6-5C530F8CD61E}.Debug|Win32.Build.0 = Debug_CLR|Win32
- {7B42BDA1-72C0-4378-A9B6-5C530F8CD61E}.Debug|x64.ActiveCfg = Debug_CLR|x64
- {7B42BDA1-72C0-4378-A9B6-5C530F8CD61E}.Debug|x64.Build.0 = Debug_CLR|x64
- {7B42BDA1-72C0-4378-A9B6-5C530F8CD61E}.Release|Win32.ActiveCfg = Release_CLR|Win32
- {7B42BDA1-72C0-4378-A9B6-5C530F8CD61E}.Release|Win32.Build.0 = Release_CLR|Win32
- {7B42BDA1-72C0-4378-A9B6-5C530F8CD61E}.Release|x64.ActiveCfg = Release_CLR|x64
- {7B42BDA1-72C0-4378-A9B6-5C530F8CD61E}.Release|x64.Build.0 = Release_CLR|x64
- {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.All|Win32.ActiveCfg = Release|Any CPU
- {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.All|x64.ActiveCfg = Release|Any CPU
- {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.Debug|Win32.ActiveCfg = Debug|Any CPU
- {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.Debug|Win32.Build.0 = Debug|Any CPU
- {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.Debug|x64.ActiveCfg = Debug|x64
- {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.Debug|x64.Build.0 = Debug|x64
- {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.Release|Win32.ActiveCfg = Release|Any CPU
- {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.Release|Win32.Build.0 = Release|Any CPU
- {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.Release|x64.ActiveCfg = Release|x64
- {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.Release|x64.Build.0 = Release|x64
- {E796E337-DE78-4303-8614-9A590862EE95}.All|Win32.ActiveCfg = Release|Win32
- {E796E337-DE78-4303-8614-9A590862EE95}.All|Win32.Build.0 = Release|Win32
- {E796E337-DE78-4303-8614-9A590862EE95}.All|x64.ActiveCfg = Release|Win32
- {E796E337-DE78-4303-8614-9A590862EE95}.All|x64.Build.0 = Release|Win32
- {E796E337-DE78-4303-8614-9A590862EE95}.Debug|Win32.ActiveCfg = Debug|Win32
- {E796E337-DE78-4303-8614-9A590862EE95}.Debug|Win32.Build.0 = Debug|Win32
- {E796E337-DE78-4303-8614-9A590862EE95}.Debug|x64.ActiveCfg = Debug|Win32
- {E796E337-DE78-4303-8614-9A590862EE95}.Debug|x64.Build.0 = Debug|Win32
- {E796E337-DE78-4303-8614-9A590862EE95}.Release|Win32.ActiveCfg = Release|Win32
- {E796E337-DE78-4303-8614-9A590862EE95}.Release|Win32.Build.0 = Release|Win32
- {E796E337-DE78-4303-8614-9A590862EE95}.Release|x64.ActiveCfg = Release|Win32
- {E796E337-DE78-4303-8614-9A590862EE95}.Release|x64.Build.0 = Release|Win32
- {419C8F80-D858-4B48-A25C-AF4007608137}.All|Win32.ActiveCfg = Release|x64
- {419C8F80-D858-4B48-A25C-AF4007608137}.All|x64.ActiveCfg = Release|x64
- {419C8F80-D858-4B48-A25C-AF4007608137}.All|x64.Build.0 = Release|x64
- {419C8F80-D858-4B48-A25C-AF4007608137}.Debug|Win32.ActiveCfg = Debug|Win32
- {419C8F80-D858-4B48-A25C-AF4007608137}.Debug|Win32.Build.0 = Debug|Win32
- {419C8F80-D858-4B48-A25C-AF4007608137}.Debug|x64.ActiveCfg = Debug|x64
- {419C8F80-D858-4B48-A25C-AF4007608137}.Debug|x64.Build.0 = Debug|x64
- {419C8F80-D858-4B48-A25C-AF4007608137}.Release|Win32.ActiveCfg = Release|Win32
- {419C8F80-D858-4B48-A25C-AF4007608137}.Release|Win32.Build.0 = Release|Win32
- {419C8F80-D858-4B48-A25C-AF4007608137}.Release|x64.ActiveCfg = Release|x64
- {419C8F80-D858-4B48-A25C-AF4007608137}.Release|x64.Build.0 = Release|x64
- {B3F424EC-3D8F-417C-B244-3919D5E1A577}.All|Win32.ActiveCfg = Release|x64
- {B3F424EC-3D8F-417C-B244-3919D5E1A577}.All|x64.ActiveCfg = Release|x64
- {B3F424EC-3D8F-417C-B244-3919D5E1A577}.All|x64.Build.0 = Release|x64
- {B3F424EC-3D8F-417C-B244-3919D5E1A577}.Debug|Win32.ActiveCfg = Debug|Win32
- {B3F424EC-3D8F-417C-B244-3919D5E1A577}.Debug|Win32.Build.0 = Debug|Win32
- {B3F424EC-3D8F-417C-B244-3919D5E1A577}.Debug|x64.ActiveCfg = Debug|x64
- {B3F424EC-3D8F-417C-B244-3919D5E1A577}.Debug|x64.Build.0 = Debug|x64
- {B3F424EC-3D8F-417C-B244-3919D5E1A577}.Release|Win32.ActiveCfg = Release|Win32
- {B3F424EC-3D8F-417C-B244-3919D5E1A577}.Release|Win32.Build.0 = Release|Win32
- {B3F424EC-3D8F-417C-B244-3919D5E1A577}.Release|x64.ActiveCfg = Release|x64
- {B3F424EC-3D8F-417C-B244-3919D5E1A577}.Release|x64.Build.0 = Release|x64
- {14E4A972-9CFB-436D-B0A5-4943F3F80D47}.All|Win32.ActiveCfg = Release|x64
- {14E4A972-9CFB-436D-B0A5-4943F3F80D47}.All|x64.ActiveCfg = Release|x64
- {14E4A972-9CFB-436D-B0A5-4943F3F80D47}.All|x64.Build.0 = Release|x64
- {14E4A972-9CFB-436D-B0A5-4943F3F80D47}.Debug|Win32.ActiveCfg = Debug|Win32
- {14E4A972-9CFB-436D-B0A5-4943F3F80D47}.Debug|Win32.Build.0 = Debug|Win32
- {14E4A972-9CFB-436D-B0A5-4943F3F80D47}.Debug|x64.ActiveCfg = Debug|x64
- {14E4A972-9CFB-436D-B0A5-4943F3F80D47}.Debug|x64.Build.0 = Debug|x64
- {14E4A972-9CFB-436D-B0A5-4943F3F80D47}.Release|Win32.ActiveCfg = Release|Win32
- {14E4A972-9CFB-436D-B0A5-4943F3F80D47}.Release|Win32.Build.0 = Release|Win32
- {14E4A972-9CFB-436D-B0A5-4943F3F80D47}.Release|x64.ActiveCfg = Release|x64
- {14E4A972-9CFB-436D-B0A5-4943F3F80D47}.Release|x64.Build.0 = Release|x64
- {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C}.All|Win32.ActiveCfg = Release|x64
- {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C}.All|x64.ActiveCfg = Release|x64
- {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C}.All|x64.Build.0 = Release|x64
- {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C}.Debug|Win32.ActiveCfg = Debug|Win32
- {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C}.Debug|Win32.Build.0 = Debug|Win32
- {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C}.Debug|x64.ActiveCfg = Debug|x64
- {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C}.Debug|x64.Build.0 = Debug|x64
- {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C}.Release|Win32.ActiveCfg = Release|Win32
- {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C}.Release|Win32.Build.0 = Release|Win32
- {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C}.Release|x64.ActiveCfg = Release|x64
- {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C}.Release|x64.Build.0 = Release|x64
- {0B6C905B-142E-4999-B39D-92FF7951E921}.All|Win32.ActiveCfg = Release|x64
- {0B6C905B-142E-4999-B39D-92FF7951E921}.All|x64.ActiveCfg = Release|x64
- {0B6C905B-142E-4999-B39D-92FF7951E921}.All|x64.Build.0 = Release|x64
- {0B6C905B-142E-4999-B39D-92FF7951E921}.Debug|Win32.ActiveCfg = Debug|Win32
- {0B6C905B-142E-4999-B39D-92FF7951E921}.Debug|Win32.Build.0 = Debug|Win32
- {0B6C905B-142E-4999-B39D-92FF7951E921}.Debug|x64.ActiveCfg = Debug|x64
- {0B6C905B-142E-4999-B39D-92FF7951E921}.Debug|x64.Build.0 = Debug|x64
- {0B6C905B-142E-4999-B39D-92FF7951E921}.Release|Win32.ActiveCfg = Release|Win32
- {0B6C905B-142E-4999-B39D-92FF7951E921}.Release|Win32.Build.0 = Release|Win32
- {0B6C905B-142E-4999-B39D-92FF7951E921}.Release|x64.ActiveCfg = Release|x64
- {0B6C905B-142E-4999-B39D-92FF7951E921}.Release|x64.Build.0 = Release|x64
- {CF405366-9558-4AE8-90EF-5E21B51CCB4E}.All|Win32.ActiveCfg = Release|x64
- {CF405366-9558-4AE8-90EF-5E21B51CCB4E}.All|x64.ActiveCfg = Release|x64
- {CF405366-9558-4AE8-90EF-5E21B51CCB4E}.All|x64.Build.0 = Release|x64
- {CF405366-9558-4AE8-90EF-5E21B51CCB4E}.Debug|Win32.ActiveCfg = Debug|Win32
- {CF405366-9558-4AE8-90EF-5E21B51CCB4E}.Debug|Win32.Build.0 = Debug|Win32
- {CF405366-9558-4AE8-90EF-5E21B51CCB4E}.Debug|x64.ActiveCfg = Debug|x64
- {CF405366-9558-4AE8-90EF-5E21B51CCB4E}.Debug|x64.Build.0 = Debug|x64
- {CF405366-9558-4AE8-90EF-5E21B51CCB4E}.Release|Win32.ActiveCfg = Release|Win32
- {CF405366-9558-4AE8-90EF-5E21B51CCB4E}.Release|Win32.Build.0 = Release|Win32
- {CF405366-9558-4AE8-90EF-5E21B51CCB4E}.Release|x64.ActiveCfg = Release|x64
- {CF405366-9558-4AE8-90EF-5E21B51CCB4E}.Release|x64.Build.0 = Release|x64
- {D2FB8043-D208-4AEE-8F18-3B5857C871B9}.All|Win32.ActiveCfg = Release|x64
- {D2FB8043-D208-4AEE-8F18-3B5857C871B9}.All|x64.ActiveCfg = Release|x64
- {D2FB8043-D208-4AEE-8F18-3B5857C871B9}.All|x64.Build.0 = Release|x64
- {D2FB8043-D208-4AEE-8F18-3B5857C871B9}.Debug|Win32.ActiveCfg = Debug|Win32
- {D2FB8043-D208-4AEE-8F18-3B5857C871B9}.Debug|Win32.Build.0 = Debug|Win32
- {D2FB8043-D208-4AEE-8F18-3B5857C871B9}.Debug|x64.ActiveCfg = Debug|x64
- {D2FB8043-D208-4AEE-8F18-3B5857C871B9}.Debug|x64.Build.0 = Debug|x64
- {D2FB8043-D208-4AEE-8F18-3B5857C871B9}.Release|Win32.ActiveCfg = Release|Win32
- {D2FB8043-D208-4AEE-8F18-3B5857C871B9}.Release|Win32.Build.0 = Release|Win32
- {D2FB8043-D208-4AEE-8F18-3B5857C871B9}.Release|x64.ActiveCfg = Release|x64
- {D2FB8043-D208-4AEE-8F18-3B5857C871B9}.Release|x64.Build.0 = Release|x64
- {329FD5B0-EF28-4606-86D0-F6EA21CF8E36}.All|Win32.ActiveCfg = Release|x64
- {329FD5B0-EF28-4606-86D0-F6EA21CF8E36}.All|x64.ActiveCfg = Release|x64
- {329FD5B0-EF28-4606-86D0-F6EA21CF8E36}.All|x64.Build.0 = Release|x64
- {329FD5B0-EF28-4606-86D0-F6EA21CF8E36}.Debug|Win32.ActiveCfg = Debug|Win32
- {329FD5B0-EF28-4606-86D0-F6EA21CF8E36}.Debug|Win32.Build.0 = Debug|Win32
- {329FD5B0-EF28-4606-86D0-F6EA21CF8E36}.Debug|x64.ActiveCfg = Debug|x64
- {329FD5B0-EF28-4606-86D0-F6EA21CF8E36}.Debug|x64.Build.0 = Debug|x64
- {329FD5B0-EF28-4606-86D0-F6EA21CF8E36}.Release|Win32.ActiveCfg = Release|Win32
- {329FD5B0-EF28-4606-86D0-F6EA21CF8E36}.Release|Win32.Build.0 = Release|Win32
- {329FD5B0-EF28-4606-86D0-F6EA21CF8E36}.Release|x64.ActiveCfg = Release|x64
- {329FD5B0-EF28-4606-86D0-F6EA21CF8E36}.Release|x64.Build.0 = Release|x64
- {1A3793D1-05D1-4B57-9B0F-5AF3E79DC439}.All|Win32.ActiveCfg = Release|x64
- {1A3793D1-05D1-4B57-9B0F-5AF3E79DC439}.All|x64.ActiveCfg = Release|x64
- {1A3793D1-05D1-4B57-9B0F-5AF3E79DC439}.All|x64.Build.0 = Release|x64
- {1A3793D1-05D1-4B57-9B0F-5AF3E79DC439}.Debug|Win32.ActiveCfg = Debug|Win32
- {1A3793D1-05D1-4B57-9B0F-5AF3E79DC439}.Debug|Win32.Build.0 = Debug|Win32
- {1A3793D1-05D1-4B57-9B0F-5AF3E79DC439}.Debug|x64.ActiveCfg = Debug|x64
- {1A3793D1-05D1-4B57-9B0F-5AF3E79DC439}.Debug|x64.Build.0 = Debug|x64
- {1A3793D1-05D1-4B57-9B0F-5AF3E79DC439}.Release|Win32.ActiveCfg = Release|Win32
- {1A3793D1-05D1-4B57-9B0F-5AF3E79DC439}.Release|Win32.Build.0 = Release|Win32
- {1A3793D1-05D1-4B57-9B0F-5AF3E79DC439}.Release|x64.ActiveCfg = Release|x64
- {1A3793D1-05D1-4B57-9B0F-5AF3E79DC439}.Release|x64.Build.0 = Release|x64
- {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.All|Win32.ActiveCfg = Release|x64
- {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.All|x64.ActiveCfg = Release|x64
- {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.All|x64.Build.0 = Release|x64
- {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.Debug|Win32.ActiveCfg = Debug|Win32
- {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.Debug|Win32.Build.0 = Debug|Win32
- {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.Debug|x64.ActiveCfg = Debug|x64
- {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.Debug|x64.Build.0 = Debug|x64
- {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.Release|Win32.ActiveCfg = Release|Win32
- {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.Release|Win32.Build.0 = Release|Win32
- {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.Release|x64.ActiveCfg = Release|x64
- {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.Release|x64.Build.0 = Release|x64
- {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.All|Win32.ActiveCfg = Release|x64
- {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.All|x64.ActiveCfg = Release|x64
- {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.All|x64.Build.0 = Release|x64
- {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.Debug|Win32.ActiveCfg = Debug|Win32
- {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.Debug|Win32.Build.0 = Debug|Win32
- {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.Debug|x64.ActiveCfg = Debug|x64
- {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.Debug|x64.Build.0 = Debug|x64
- {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.Release|Win32.ActiveCfg = Release|Win32
- {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.Release|Win32.Build.0 = Release|Win32
- {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.Release|x64.ActiveCfg = Release|x64
- {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.Release|x64.Build.0 = Release|x64
- {E972C52F-9E85-4D65-B19C-031E511E9DB4}.All|Win32.ActiveCfg = Release_WM5_PPC_ARM|x64
- {E972C52F-9E85-4D65-B19C-031E511E9DB4}.All|x64.ActiveCfg = Release_WM5_PPC_ARM|x64
- {E972C52F-9E85-4D65-B19C-031E511E9DB4}.All|x64.Build.0 = Release_WM5_PPC_ARM|x64
- {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug|Win32.ActiveCfg = Debug|Win32
- {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug|Win32.Build.0 = Debug|Win32
- {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug|x64.ActiveCfg = Debug|x64
- {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug|x64.Build.0 = Debug|x64
- {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release|Win32.ActiveCfg = Release|Win32
- {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release|Win32.Build.0 = Release|Win32
- {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release|x64.ActiveCfg = Release|x64
- {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release|x64.Build.0 = Release|x64
- {03207781-0D1C-4DB3-A71D-45C608F28DBD}.All|Win32.ActiveCfg = Release_Static_SSE|x64
- {03207781-0D1C-4DB3-A71D-45C608F28DBD}.All|x64.ActiveCfg = Release_Static_SSE|x64
- {03207781-0D1C-4DB3-A71D-45C608F28DBD}.All|x64.Build.0 = Release_Static_SSE|x64
- {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Debug|Win32.ActiveCfg = Debug|Win32
- {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Debug|Win32.Build.0 = Debug|Win32
- {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Debug|x64.ActiveCfg = Debug|x64
- {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Debug|x64.Build.0 = Debug|x64
- {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release|Win32.ActiveCfg = Release|Win32
- {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release|Win32.Build.0 = Release|Win32
- {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release|x64.ActiveCfg = Release|x64
- {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release|x64.Build.0 = Release|x64
- {9A5DDF08-C88C-4A35-B7F6-D605228446BD}.All|Win32.ActiveCfg = Release|x64
- {9A5DDF08-C88C-4A35-B7F6-D605228446BD}.All|x64.ActiveCfg = Release|x64
- {9A5DDF08-C88C-4A35-B7F6-D605228446BD}.All|x64.Build.0 = Release|x64
- {9A5DDF08-C88C-4A35-B7F6-D605228446BD}.Debug|Win32.ActiveCfg = Debug|Win32
- {9A5DDF08-C88C-4A35-B7F6-D605228446BD}.Debug|Win32.Build.0 = Debug|Win32
- {9A5DDF08-C88C-4A35-B7F6-D605228446BD}.Debug|x64.ActiveCfg = Debug|x64
- {9A5DDF08-C88C-4A35-B7F6-D605228446BD}.Debug|x64.Build.0 = Debug|x64
- {9A5DDF08-C88C-4A35-B7F6-D605228446BD}.Release|Win32.ActiveCfg = Release|Win32
- {9A5DDF08-C88C-4A35-B7F6-D605228446BD}.Release|Win32.Build.0 = Release|Win32
- {9A5DDF08-C88C-4A35-B7F6-D605228446BD}.Release|x64.ActiveCfg = Release|x64
- {9A5DDF08-C88C-4A35-B7F6-D605228446BD}.Release|x64.Build.0 = Release|x64
- {D0B36172-CD76-454A-9B89-990025266C2A}.All|Win32.ActiveCfg = Release|x64
- {D0B36172-CD76-454A-9B89-990025266C2A}.All|x64.ActiveCfg = Release|x64
- {D0B36172-CD76-454A-9B89-990025266C2A}.All|x64.Build.0 = Release|x64
- {D0B36172-CD76-454A-9B89-990025266C2A}.Debug|Win32.ActiveCfg = Debug|Win32
- {D0B36172-CD76-454A-9B89-990025266C2A}.Debug|Win32.Build.0 = Debug|Win32
- {D0B36172-CD76-454A-9B89-990025266C2A}.Debug|x64.ActiveCfg = Debug|x64
- {D0B36172-CD76-454A-9B89-990025266C2A}.Debug|x64.Build.0 = Debug|x64
- {D0B36172-CD76-454A-9B89-990025266C2A}.Release|Win32.ActiveCfg = Release|Win32
- {D0B36172-CD76-454A-9B89-990025266C2A}.Release|Win32.Build.0 = Release|Win32
- {D0B36172-CD76-454A-9B89-990025266C2A}.Release|x64.ActiveCfg = Release|x64
- {D0B36172-CD76-454A-9B89-990025266C2A}.Release|x64.Build.0 = Release|x64
- {05C9FB27-480E-4D53-B3B7-6338E2526666}.All|Win32.ActiveCfg = Release|Win32
- {05C9FB27-480E-4D53-B3B7-6338E2526666}.All|Win32.Build.0 = Release|Win32
- {05C9FB27-480E-4D53-B3B7-6338E2526666}.All|x64.ActiveCfg = Release|Win32
- {05C9FB27-480E-4D53-B3B7-6338E2526666}.Debug|Win32.ActiveCfg = Debug|Win32
- {05C9FB27-480E-4D53-B3B7-6338E2526666}.Debug|x64.ActiveCfg = Debug|Win32
- {05C9FB27-480E-4D53-B3B7-6338E2526666}.Release|Win32.ActiveCfg = Release|Win32
- {05C9FB27-480E-4D53-B3B7-6338E2526666}.Release|x64.ActiveCfg = Release|Win32
- {05C9FB27-480E-4D53-B3B7-7338E2514666}.All|Win32.ActiveCfg = Release|Win32
- {05C9FB27-480E-4D53-B3B7-7338E2514666}.All|Win32.Build.0 = Release|Win32
- {05C9FB27-480E-4D53-B3B7-7338E2514666}.All|x64.ActiveCfg = Release|Win32
- {05C9FB27-480E-4D53-B3B7-7338E2514666}.Debug|Win32.ActiveCfg = Debug|Win32
- {05C9FB27-480E-4D53-B3B7-7338E2514666}.Debug|x64.ActiveCfg = Debug|x64
- {05C9FB27-480E-4D53-B3B7-7338E2514666}.Release|Win32.ActiveCfg = Release|Win32
- {05C9FB27-480E-4D53-B3B7-7338E2514666}.Release|x64.ActiveCfg = Release|Win32
- {7F1610F1-DD5A-4CF7-8610-30AB12C60ADD}.All|Win32.ActiveCfg = All|Win32
- {7F1610F1-DD5A-4CF7-8610-30AB12C60ADD}.All|Win32.Build.0 = All|Win32
- {7F1610F1-DD5A-4CF7-8610-30AB12C60ADD}.All|x64.ActiveCfg = All|Win32
- {7F1610F1-DD5A-4CF7-8610-30AB12C60ADD}.Debug|Win32.ActiveCfg = Debug|Win32
- {7F1610F1-DD5A-4CF7-8610-30AB12C60ADD}.Debug|x64.ActiveCfg = Debug|x64
- {7F1610F1-DD5A-4CF7-8610-30AB12C60ADD}.Release|Win32.ActiveCfg = Release|Win32
- {7F1610F1-DD5A-4CF7-8610-30AB12C60ADD}.Release|x64.ActiveCfg = Release|x64
- {CC1DD008-9406-448D-A0AD-33C3186CFADB}.All|Win32.ActiveCfg = Release|Win32
- {CC1DD008-9406-448D-A0AD-33C3186CFADB}.All|x64.ActiveCfg = Release|Win32
- {CC1DD008-9406-448D-A0AD-33C3186CFADB}.Debug|Win32.ActiveCfg = Debug|Win32
- {CC1DD008-9406-448D-A0AD-33C3186CFADB}.Debug|x64.ActiveCfg = Debug|x64
- {CC1DD008-9406-448D-A0AD-33C3186CFADB}.Release|Win32.ActiveCfg = Release|Win32
- {CC1DD008-9406-448D-A0AD-33C3186CFADB}.Release|x64.ActiveCfg = Release|x64
- {48414740-C693-4968-9846-EE058020C64F}.All|Win32.ActiveCfg = Release|Win32
- {48414740-C693-4968-9846-EE058020C64F}.All|x64.ActiveCfg = Release|Win32
- {48414740-C693-4968-9846-EE058020C64F}.Debug|Win32.ActiveCfg = Debug|Win32
- {48414740-C693-4968-9846-EE058020C64F}.Debug|x64.ActiveCfg = Debug|x64
- {48414740-C693-4968-9846-EE058020C64F}.Release|Win32.ActiveCfg = Release|Win32
- {48414740-C693-4968-9846-EE058020C64F}.Release|x64.ActiveCfg = Release|x64
- {DEE932AB-5911-4700-9EEB-8C7090A0A330}.All|Win32.ActiveCfg = All|Win32
- {DEE932AB-5911-4700-9EEB-8C7090A0A330}.All|Win32.Build.0 = All|Win32
- {DEE932AB-5911-4700-9EEB-8C7090A0A330}.All|x64.ActiveCfg = All|Win32
- {DEE932AB-5911-4700-9EEB-8C7090A0A330}.Debug|Win32.ActiveCfg = All|Win32
- {DEE932AB-5911-4700-9EEB-8C7090A0A330}.Debug|Win32.Build.0 = All|Win32
- {DEE932AB-5911-4700-9EEB-8C7090A0A330}.Debug|x64.ActiveCfg = All|Win32
- {DEE932AB-5911-4700-9EEB-8C7090A0A330}.Debug|x64.Build.0 = All|Win32
- {DEE932AB-5911-4700-9EEB-8C7090A0A330}.Release|Win32.ActiveCfg = All|Win32
- {DEE932AB-5911-4700-9EEB-8C7090A0A330}.Release|Win32.Build.0 = All|Win32
- {DEE932AB-5911-4700-9EEB-8C7090A0A330}.Release|x64.ActiveCfg = All|Win32
- {DEE932AB-5911-4700-9EEB-8C7090A0A330}.Release|x64.Build.0 = All|Win32
- {329A6FA0-0FCC-4435-A950-E670AEFA9838}.All|Win32.ActiveCfg = All|Win32
- {329A6FA0-0FCC-4435-A950-E670AEFA9838}.All|Win32.Build.0 = All|Win32
- {329A6FA0-0FCC-4435-A950-E670AEFA9838}.All|x64.ActiveCfg = All|Win32
- {329A6FA0-0FCC-4435-A950-E670AEFA9838}.Debug|Win32.ActiveCfg = All|Win32
- {329A6FA0-0FCC-4435-A950-E670AEFA9838}.Debug|Win32.Build.0 = All|Win32
- {329A6FA0-0FCC-4435-A950-E670AEFA9838}.Debug|x64.ActiveCfg = All|Win32
- {329A6FA0-0FCC-4435-A950-E670AEFA9838}.Debug|x64.Build.0 = All|Win32
- {329A6FA0-0FCC-4435-A950-E670AEFA9838}.Release|Win32.ActiveCfg = All|Win32
- {329A6FA0-0FCC-4435-A950-E670AEFA9838}.Release|Win32.Build.0 = All|Win32
- {329A6FA0-0FCC-4435-A950-E670AEFA9838}.Release|x64.ActiveCfg = All|Win32
- {329A6FA0-0FCC-4435-A950-E670AEFA9838}.Release|x64.Build.0 = All|Win32
- {11C9BC3D-45E9-46E3-BE84-B8CEE4685E39}.All|Win32.ActiveCfg = Release|x64
- {11C9BC3D-45E9-46E3-BE84-B8CEE4685E39}.All|x64.ActiveCfg = Release|x64
- {11C9BC3D-45E9-46E3-BE84-B8CEE4685E39}.All|x64.Build.0 = Release|x64
- {11C9BC3D-45E9-46E3-BE84-B8CEE4685E39}.Debug|Win32.ActiveCfg = Debug|Win32
- {11C9BC3D-45E9-46E3-BE84-B8CEE4685E39}.Debug|x64.ActiveCfg = Debug|x64
- {11C9BC3D-45E9-46E3-BE84-B8CEE4685E39}.Release|Win32.ActiveCfg = Release|Win32
- {11C9BC3D-45E9-46E3-BE84-B8CEE4685E39}.Release|x64.ActiveCfg = Release|x64
- {C6E78A4C-DB1E-47F4-9B63-4DC27D86343F}.All|Win32.ActiveCfg = Release|Win32
- {C6E78A4C-DB1E-47F4-9B63-4DC27D86343F}.All|Win32.Build.0 = Release|Win32
- {C6E78A4C-DB1E-47F4-9B63-4DC27D86343F}.All|x64.ActiveCfg = Release|Win32
- {C6E78A4C-DB1E-47F4-9B63-4DC27D86343F}.Debug|Win32.ActiveCfg = Debug|Win32
- {C6E78A4C-DB1E-47F4-9B63-4DC27D86343F}.Debug|x64.ActiveCfg = Debug|Win32
- {C6E78A4C-DB1E-47F4-9B63-4DC27D86343F}.Release|Win32.ActiveCfg = Release|Win32
- {C6E78A4C-DB1E-47F4-9B63-4DC27D86343F}.Release|x64.ActiveCfg = Release|Win32
- {1F0A8A77-E661-418F-BB92-82172AE43803}.All|Win32.ActiveCfg = Release|Win32
- {1F0A8A77-E661-418F-BB92-82172AE43803}.All|x64.ActiveCfg = Release|Win32
- {1F0A8A77-E661-418F-BB92-82172AE43803}.Debug|Win32.ActiveCfg = Debug|Win32
- {1F0A8A77-E661-418F-BB92-82172AE43803}.Debug|x64.ActiveCfg = Debug|Win32
- {1F0A8A77-E661-418F-BB92-82172AE43803}.Release|Win32.ActiveCfg = Release|Win32
- {1F0A8A77-E661-418F-BB92-82172AE43803}.Release|x64.ActiveCfg = Release|Win32
- {4F5C9D55-98EF-4256-8311-32D7BD360406}.All|Win32.ActiveCfg = Release|Win32
- {4F5C9D55-98EF-4256-8311-32D7BD360406}.All|Win32.Build.0 = Release|Win32
- {4F5C9D55-98EF-4256-8311-32D7BD360406}.All|x64.ActiveCfg = Release|Win32
- {4F5C9D55-98EF-4256-8311-32D7BD360406}.All|x64.Build.0 = Release|Win32
- {4F5C9D55-98EF-4256-8311-32D7BD360406}.Debug|Win32.ActiveCfg = Debug|Win32
- {4F5C9D55-98EF-4256-8311-32D7BD360406}.Debug|Win32.Build.0 = Debug|Win32
- {4F5C9D55-98EF-4256-8311-32D7BD360406}.Debug|x64.ActiveCfg = Debug|Win32
- {4F5C9D55-98EF-4256-8311-32D7BD360406}.Debug|x64.Build.0 = Debug|Win32
- {4F5C9D55-98EF-4256-8311-32D7BD360406}.Release|Win32.ActiveCfg = Release|Win32
- {4F5C9D55-98EF-4256-8311-32D7BD360406}.Release|Win32.Build.0 = Release|Win32
- {4F5C9D55-98EF-4256-8311-32D7BD360406}.Release|x64.ActiveCfg = Release|Win32
- {4F5C9D55-98EF-4256-8311-32D7BD360406}.Release|x64.Build.0 = Release|Win32
- {E10571C4-E7F4-4608-B5F2-B22E7EB95400}.All|Win32.ActiveCfg = Release|Win32
- {E10571C4-E7F4-4608-B5F2-B22E7EB95400}.All|x64.ActiveCfg = Release|Win32
- {E10571C4-E7F4-4608-B5F2-B22E7EB95400}.Debug|Win32.ActiveCfg = Debug|Win32
- {E10571C4-E7F4-4608-B5F2-B22E7EB95400}.Debug|x64.ActiveCfg = Debug|Win32
- {E10571C4-E7F4-4608-B5F2-B22E7EB95400}.Release|Win32.ActiveCfg = Release|Win32
- {E10571C4-E7F4-4608-B5F2-B22E7EB95400}.Release|x64.ActiveCfg = Release|Win32
- {D1ABE208-6442-4FB4-9AAD-1677E41BC870}.All|Win32.ActiveCfg = Release|Win32
- {D1ABE208-6442-4FB4-9AAD-1677E41BC870}.All|Win32.Build.0 = Release|Win32
- {D1ABE208-6442-4FB4-9AAD-1677E41BC870}.All|x64.ActiveCfg = Release|Win32
- {D1ABE208-6442-4FB4-9AAD-1677E41BC870}.All|x64.Build.0 = Release|Win32
- {D1ABE208-6442-4FB4-9AAD-1677E41BC870}.Debug|Win32.ActiveCfg = Debug|Win32
- {D1ABE208-6442-4FB4-9AAD-1677E41BC870}.Debug|Win32.Build.0 = Debug|Win32
- {D1ABE208-6442-4FB4-9AAD-1677E41BC870}.Debug|x64.ActiveCfg = Debug|x64
- {D1ABE208-6442-4FB4-9AAD-1677E41BC870}.Debug|x64.Build.0 = Debug|x64
- {D1ABE208-6442-4FB4-9AAD-1677E41BC870}.Release|Win32.ActiveCfg = Release|Win32
- {D1ABE208-6442-4FB4-9AAD-1677E41BC870}.Release|Win32.Build.0 = Release|Win32
- {D1ABE208-6442-4FB4-9AAD-1677E41BC870}.Release|x64.ActiveCfg = Release|x64
- {D1ABE208-6442-4FB4-9AAD-1677E41BC870}.Release|x64.Build.0 = Release|x64
- {BA599D0A-4310-4505-91DA-6A6447B3E289}.All|Win32.ActiveCfg = Release|Win32
- {BA599D0A-4310-4505-91DA-6A6447B3E289}.All|x64.ActiveCfg = Release|Win32
- {BA599D0A-4310-4505-91DA-6A6447B3E289}.Debug|Win32.ActiveCfg = Debug|Win32
- {BA599D0A-4310-4505-91DA-6A6447B3E289}.Debug|x64.ActiveCfg = Debug|x64
- {BA599D0A-4310-4505-91DA-6A6447B3E289}.Release|Win32.ActiveCfg = Release|Win32
- {BA599D0A-4310-4505-91DA-6A6447B3E289}.Release|x64.ActiveCfg = Release|x64
- {EED13FC7-4F81-4E6F-93DB-CDB7DF5CF959}.All|Win32.ActiveCfg = Release|Win32
- {EED13FC7-4F81-4E6F-93DB-CDB7DF5CF959}.All|x64.ActiveCfg = Release|Win32
- {EED13FC7-4F81-4E6F-93DB-CDB7DF5CF959}.Debug|Win32.ActiveCfg = Debug|Win32
- {EED13FC7-4F81-4E6F-93DB-CDB7DF5CF959}.Debug|x64.ActiveCfg = Debug|x64
- {EED13FC7-4F81-4E6F-93DB-CDB7DF5CF959}.Release|Win32.ActiveCfg = Release|Win32
- {EED13FC7-4F81-4E6F-93DB-CDB7DF5CF959}.Release|x64.ActiveCfg = Release|x64
- {3C977801-FE88-48F2-83D3-FA2EBFF6688E}.All|Win32.ActiveCfg = Release|x64
- {3C977801-FE88-48F2-83D3-FA2EBFF6688E}.All|x64.ActiveCfg = Release|x64
- {3C977801-FE88-48F2-83D3-FA2EBFF6688E}.All|x64.Build.0 = Release|x64
- {3C977801-FE88-48F2-83D3-FA2EBFF6688E}.Debug|Win32.ActiveCfg = Debug|Win32
- {3C977801-FE88-48F2-83D3-FA2EBFF6688E}.Debug|Win32.Build.0 = Debug|Win32
- {3C977801-FE88-48F2-83D3-FA2EBFF6688E}.Debug|x64.ActiveCfg = Debug|x64
- {3C977801-FE88-48F2-83D3-FA2EBFF6688E}.Debug|x64.Build.0 = Debug|x64
- {3C977801-FE88-48F2-83D3-FA2EBFF6688E}.Release|Win32.ActiveCfg = Release|Win32
- {3C977801-FE88-48F2-83D3-FA2EBFF6688E}.Release|Win32.Build.0 = Release|Win32
- {3C977801-FE88-48F2-83D3-FA2EBFF6688E}.Release|x64.ActiveCfg = Release|x64
- {3C977801-FE88-48F2-83D3-FA2EBFF6688E}.Release|x64.Build.0 = Release|x64
- {0382E8FD-CFDC-41C0-8B03-792C7C84FC31}.All|Win32.ActiveCfg = Release|x64
- {0382E8FD-CFDC-41C0-8B03-792C7C84FC31}.All|Win32.Build.0 = Release|x64
- {0382E8FD-CFDC-41C0-8B03-792C7C84FC31}.All|x64.ActiveCfg = Release|x64
- {0382E8FD-CFDC-41C0-8B03-792C7C84FC31}.All|x64.Build.0 = Release|x64
- {0382E8FD-CFDC-41C0-8B03-792C7C84FC31}.Debug|Win32.ActiveCfg = Debug|Win32
- {0382E8FD-CFDC-41C0-8B03-792C7C84FC31}.Debug|Win32.Build.0 = Debug|Win32
- {0382E8FD-CFDC-41C0-8B03-792C7C84FC31}.Debug|x64.ActiveCfg = Debug|x64
- {0382E8FD-CFDC-41C0-8B03-792C7C84FC31}.Debug|x64.Build.0 = Debug|x64
- {0382E8FD-CFDC-41C0-8B03-792C7C84FC31}.Release|Win32.ActiveCfg = Release|Win32
- {0382E8FD-CFDC-41C0-8B03-792C7C84FC31}.Release|Win32.Build.0 = Release|Win32
- {0382E8FD-CFDC-41C0-8B03-792C7C84FC31}.Release|x64.ActiveCfg = Release|x64
- {0382E8FD-CFDC-41C0-8B03-792C7C84FC31}.Release|x64.Build.0 = Release|x64
- {432DB165-1EB2-4781-A9C0-71E62610B20A}.All|Win32.ActiveCfg = Release|x64
- {432DB165-1EB2-4781-A9C0-71E62610B20A}.All|x64.ActiveCfg = Release|x64
- {432DB165-1EB2-4781-A9C0-71E62610B20A}.Debug|Win32.ActiveCfg = Debug|Win32
- {432DB165-1EB2-4781-A9C0-71E62610B20A}.Debug|Win32.Build.0 = Debug|Win32
- {432DB165-1EB2-4781-A9C0-71E62610B20A}.Debug|x64.ActiveCfg = Debug|x64
- {432DB165-1EB2-4781-A9C0-71E62610B20A}.Debug|x64.Build.0 = Debug|x64
- {432DB165-1EB2-4781-A9C0-71E62610B20A}.Release|Win32.ActiveCfg = Release|Win32
- {432DB165-1EB2-4781-A9C0-71E62610B20A}.Release|Win32.Build.0 = Release|Win32
- {432DB165-1EB2-4781-A9C0-71E62610B20A}.Release|x64.ActiveCfg = Release|x64
- {432DB165-1EB2-4781-A9C0-71E62610B20A}.Release|x64.Build.0 = Release|x64
- {CF70F278-3364-4395-A2E1-23501C9B8AD2}.All|Win32.ActiveCfg = Release|Win32
- {CF70F278-3364-4395-A2E1-23501C9B8AD2}.All|Win32.Build.0 = Release|Win32
- {CF70F278-3364-4395-A2E1-23501C9B8AD2}.All|x64.ActiveCfg = Release|Win32
- {CF70F278-3364-4395-A2E1-23501C9B8AD2}.Debug|Win32.ActiveCfg = Debug|Win32
- {CF70F278-3364-4395-A2E1-23501C9B8AD2}.Debug|Win32.Build.0 = Debug|Win32
- {CF70F278-3364-4395-A2E1-23501C9B8AD2}.Debug|x64.ActiveCfg = Debug|x64
- {CF70F278-3364-4395-A2E1-23501C9B8AD2}.Debug|x64.Build.0 = Debug|x64
- {CF70F278-3364-4395-A2E1-23501C9B8AD2}.Release|Win32.ActiveCfg = Release|Win32
- {CF70F278-3364-4395-A2E1-23501C9B8AD2}.Release|Win32.Build.0 = Release|Win32
- {CF70F278-3364-4395-A2E1-23501C9B8AD2}.Release|x64.ActiveCfg = Release|x64
- {CF70F278-3364-4395-A2E1-23501C9B8AD2}.Release|x64.Build.0 = Release|x64
- {D5C87B19-150D-4EF3-A671-96589BD2D14A}.All|Win32.ActiveCfg = Release|x64
- {D5C87B19-150D-4EF3-A671-96589BD2D14A}.All|x64.ActiveCfg = Release|x64
- {D5C87B19-150D-4EF3-A671-96589BD2D14A}.All|x64.Build.0 = Release|x64
- {D5C87B19-150D-4EF3-A671-96589BD2D14A}.Debug|Win32.ActiveCfg = Debug|Win32
- {D5C87B19-150D-4EF3-A671-96589BD2D14A}.Debug|Win32.Build.0 = Debug|Win32
- {D5C87B19-150D-4EF3-A671-96589BD2D14A}.Debug|x64.ActiveCfg = Debug|x64
- {D5C87B19-150D-4EF3-A671-96589BD2D14A}.Debug|x64.Build.0 = Debug|x64
- {D5C87B19-150D-4EF3-A671-96589BD2D14A}.Release|Win32.ActiveCfg = Release|Win32
- {D5C87B19-150D-4EF3-A671-96589BD2D14A}.Release|Win32.Build.0 = Release|Win32
- {D5C87B19-150D-4EF3-A671-96589BD2D14A}.Release|x64.ActiveCfg = Release|x64
- {D5C87B19-150D-4EF3-A671-96589BD2D14A}.Release|x64.Build.0 = Release|x64
- {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}.All|Win32.ActiveCfg = Release|Win32
- {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}.All|Win32.Build.0 = Release|Win32
- {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}.All|x64.ActiveCfg = Release|Win32
- {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}.Debug|Win32.ActiveCfg = Debug|Win32
- {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}.Debug|Win32.Build.0 = Debug|Win32
- {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}.Debug|x64.ActiveCfg = Debug|x64
- {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}.Debug|x64.Build.0 = Debug|x64
- {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}.Release|Win32.ActiveCfg = Release|Win32
- {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}.Release|Win32.Build.0 = Release|Win32
- {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}.Release|x64.ActiveCfg = Release|x64
- {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}.Release|x64.Build.0 = Release|x64
- {B5A00BFA-6083-4FAE-A097-71642D6473B5}.All|Win32.ActiveCfg = Release|Win32
- {B5A00BFA-6083-4FAE-A097-71642D6473B5}.All|Win32.Build.0 = Release|Win32
- {B5A00BFA-6083-4FAE-A097-71642D6473B5}.All|x64.ActiveCfg = Release|Win32
- {B5A00BFA-6083-4FAE-A097-71642D6473B5}.Debug|Win32.ActiveCfg = Debug|Win32
- {B5A00BFA-6083-4FAE-A097-71642D6473B5}.Debug|Win32.Build.0 = Debug|Win32
- {B5A00BFA-6083-4FAE-A097-71642D6473B5}.Debug|x64.ActiveCfg = Debug|x64
- {B5A00BFA-6083-4FAE-A097-71642D6473B5}.Debug|x64.Build.0 = Debug|x64
- {B5A00BFA-6083-4FAE-A097-71642D6473B5}.Release|Win32.ActiveCfg = Release|Win32
- {B5A00BFA-6083-4FAE-A097-71642D6473B5}.Release|Win32.Build.0 = Release|Win32
- {B5A00BFA-6083-4FAE-A097-71642D6473B5}.Release|x64.ActiveCfg = Release|x64
- {B5A00BFA-6083-4FAE-A097-71642D6473B5}.Release|x64.Build.0 = Release|x64
- {1C320193-46A6-4B34-9C56-8AB584FC1B56}.All|Win32.ActiveCfg = Release|Win32
- {1C320193-46A6-4B34-9C56-8AB584FC1B56}.All|Win32.Build.0 = Release|Win32
- {1C320193-46A6-4B34-9C56-8AB584FC1B56}.All|x64.ActiveCfg = Release|Win32
- {1C320193-46A6-4B34-9C56-8AB584FC1B56}.Debug|Win32.ActiveCfg = Debug|Win32
- {1C320193-46A6-4B34-9C56-8AB584FC1B56}.Debug|Win32.Build.0 = Debug|Win32
- {1C320193-46A6-4B34-9C56-8AB584FC1B56}.Debug|x64.ActiveCfg = Debug|x64
- {1C320193-46A6-4B34-9C56-8AB584FC1B56}.Debug|x64.Build.0 = Debug|x64
- {1C320193-46A6-4B34-9C56-8AB584FC1B56}.Release|Win32.ActiveCfg = Release|Win32
- {1C320193-46A6-4B34-9C56-8AB584FC1B56}.Release|Win32.Build.0 = Release|Win32
- {1C320193-46A6-4B34-9C56-8AB584FC1B56}.Release|x64.ActiveCfg = Release|x64
- {1C320193-46A6-4B34-9C56-8AB584FC1B56}.Release|x64.Build.0 = Release|x64
- {72782932-37CC-46AE-8C7F-9A7B1A6EE108}.All|Win32.ActiveCfg = Release|Win32
- {72782932-37CC-46AE-8C7F-9A7B1A6EE108}.All|Win32.Build.0 = Release|Win32
- {72782932-37CC-46AE-8C7F-9A7B1A6EE108}.All|x64.ActiveCfg = Release|Win32
- {72782932-37CC-46AE-8C7F-9A7B1A6EE108}.Debug|Win32.ActiveCfg = Debug|Win32
- {72782932-37CC-46AE-8C7F-9A7B1A6EE108}.Debug|Win32.Build.0 = Debug|Win32
- {72782932-37CC-46AE-8C7F-9A7B1A6EE108}.Debug|x64.ActiveCfg = Debug|x64
- {72782932-37CC-46AE-8C7F-9A7B1A6EE108}.Debug|x64.Build.0 = Debug|x64
- {72782932-37CC-46AE-8C7F-9A7B1A6EE108}.Release|Win32.ActiveCfg = Release|Win32
- {72782932-37CC-46AE-8C7F-9A7B1A6EE108}.Release|Win32.Build.0 = Release|Win32
- {72782932-37CC-46AE-8C7F-9A7B1A6EE108}.Release|x64.ActiveCfg = Release|x64
- {72782932-37CC-46AE-8C7F-9A7B1A6EE108}.Release|x64.Build.0 = Release|x64
- {12A49562-BAB9-43A3-A21D-15B60BBB4C31}.All|Win32.ActiveCfg = Release|Win32
- {12A49562-BAB9-43A3-A21D-15B60BBB4C31}.All|Win32.Build.0 = Release|Win32
- {12A49562-BAB9-43A3-A21D-15B60BBB4C31}.All|x64.ActiveCfg = Release|Win32
- {12A49562-BAB9-43A3-A21D-15B60BBB4C31}.Debug|Win32.ActiveCfg = Debug|Win32
- {12A49562-BAB9-43A3-A21D-15B60BBB4C31}.Debug|Win32.Build.0 = Debug|Win32
- {12A49562-BAB9-43A3-A21D-15B60BBB4C31}.Debug|x64.ActiveCfg = Debug|x64
- {12A49562-BAB9-43A3-A21D-15B60BBB4C31}.Debug|x64.Build.0 = Debug|x64
- {12A49562-BAB9-43A3-A21D-15B60BBB4C31}.Release|Win32.ActiveCfg = Release|Win32
- {12A49562-BAB9-43A3-A21D-15B60BBB4C31}.Release|Win32.Build.0 = Release|Win32
- {12A49562-BAB9-43A3-A21D-15B60BBB4C31}.Release|x64.ActiveCfg = Release|x64
- {12A49562-BAB9-43A3-A21D-15B60BBB4C31}.Release|x64.Build.0 = Release|x64
- {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}.All|Win32.ActiveCfg = Release|Win32
- {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}.All|Win32.Build.0 = Release|Win32
- {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}.All|x64.ActiveCfg = Release|Win32
- {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}.Debug|Win32.ActiveCfg = Debug|Win32
- {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}.Debug|Win32.Build.0 = Debug|Win32
- {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}.Debug|x64.ActiveCfg = Debug|x64
- {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}.Debug|x64.Build.0 = Debug|x64
- {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}.Release|Win32.ActiveCfg = Release|Win32
- {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}.Release|Win32.Build.0 = Release|Win32
- {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}.Release|x64.ActiveCfg = Release|x64
- {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}.Release|x64.Build.0 = Release|x64
- {504B3154-7A4F-459D-9877-B951021C3F1F}.All|Win32.ActiveCfg = Release|Win32
- {504B3154-7A4F-459D-9877-B951021C3F1F}.All|Win32.Build.0 = Release|Win32
- {504B3154-7A4F-459D-9877-B951021C3F1F}.All|x64.ActiveCfg = Release|Win32
- {504B3154-7A4F-459D-9877-B951021C3F1F}.Debug|Win32.ActiveCfg = Debug|Win32
- {504B3154-7A4F-459D-9877-B951021C3F1F}.Debug|Win32.Build.0 = Debug|Win32
- {504B3154-7A4F-459D-9877-B951021C3F1F}.Debug|x64.ActiveCfg = Debug|x64
- {504B3154-7A4F-459D-9877-B951021C3F1F}.Debug|x64.Build.0 = Debug|x64
- {504B3154-7A4F-459D-9877-B951021C3F1F}.Release|Win32.ActiveCfg = Release|Win32
- {504B3154-7A4F-459D-9877-B951021C3F1F}.Release|Win32.Build.0 = Release|Win32
- {504B3154-7A4F-459D-9877-B951021C3F1F}.Release|x64.ActiveCfg = Release|x64
- {504B3154-7A4F-459D-9877-B951021C3F1F}.Release|x64.Build.0 = Release|x64
- {746F3632-5BB2-4570-9453-31D6D58A7D8E}.All|Win32.ActiveCfg = Release|Win32
- {746F3632-5BB2-4570-9453-31D6D58A7D8E}.All|Win32.Build.0 = Release|Win32
- {746F3632-5BB2-4570-9453-31D6D58A7D8E}.All|x64.ActiveCfg = Release|Win32
- {746F3632-5BB2-4570-9453-31D6D58A7D8E}.Debug|Win32.ActiveCfg = Debug|Win32
- {746F3632-5BB2-4570-9453-31D6D58A7D8E}.Debug|Win32.Build.0 = Debug|Win32
- {746F3632-5BB2-4570-9453-31D6D58A7D8E}.Debug|x64.ActiveCfg = Debug|x64
- {746F3632-5BB2-4570-9453-31D6D58A7D8E}.Debug|x64.Build.0 = Debug|x64
- {746F3632-5BB2-4570-9453-31D6D58A7D8E}.Release|Win32.ActiveCfg = Release|Win32
- {746F3632-5BB2-4570-9453-31D6D58A7D8E}.Release|Win32.Build.0 = Release|Win32
- {746F3632-5BB2-4570-9453-31D6D58A7D8E}.Release|x64.ActiveCfg = Release|x64
- {746F3632-5BB2-4570-9453-31D6D58A7D8E}.Release|x64.Build.0 = Release|x64
- {DEB01ACB-D65F-4A62-AED9-58C1054499E9}.All|Win32.ActiveCfg = Release|Win32
- {DEB01ACB-D65F-4A62-AED9-58C1054499E9}.All|Win32.Build.0 = Release|Win32
- {DEB01ACB-D65F-4A62-AED9-58C1054499E9}.All|x64.ActiveCfg = Release|Win32
- {DEB01ACB-D65F-4A62-AED9-58C1054499E9}.Debug|Win32.ActiveCfg = Debug|Win32
- {DEB01ACB-D65F-4A62-AED9-58C1054499E9}.Debug|Win32.Build.0 = Debug|Win32
- {DEB01ACB-D65F-4A62-AED9-58C1054499E9}.Debug|x64.ActiveCfg = Debug|x64
- {DEB01ACB-D65F-4A62-AED9-58C1054499E9}.Debug|x64.Build.0 = Debug|x64
- {DEB01ACB-D65F-4A62-AED9-58C1054499E9}.Release|Win32.ActiveCfg = Release|Win32
- {DEB01ACB-D65F-4A62-AED9-58C1054499E9}.Release|Win32.Build.0 = Release|Win32
- {DEB01ACB-D65F-4A62-AED9-58C1054499E9}.Release|x64.ActiveCfg = Release|x64
- {DEB01ACB-D65F-4A62-AED9-58C1054499E9}.Release|x64.Build.0 = Release|x64
- {D07C378A-F5F7-438F-ADF3-4AC4FB1883CD}.All|Win32.ActiveCfg = Release|x64
- {D07C378A-F5F7-438F-ADF3-4AC4FB1883CD}.All|x64.ActiveCfg = Release|x64
- {D07C378A-F5F7-438F-ADF3-4AC4FB1883CD}.All|x64.Build.0 = Release|x64
- {D07C378A-F5F7-438F-ADF3-4AC4FB1883CD}.Debug|Win32.ActiveCfg = Debug|Win32
- {D07C378A-F5F7-438F-ADF3-4AC4FB1883CD}.Debug|Win32.Build.0 = Debug|Win32
- {D07C378A-F5F7-438F-ADF3-4AC4FB1883CD}.Debug|x64.ActiveCfg = Debug|x64
- {D07C378A-F5F7-438F-ADF3-4AC4FB1883CD}.Debug|x64.Build.0 = Debug|x64
- {D07C378A-F5F7-438F-ADF3-4AC4FB1883CD}.Release|Win32.ActiveCfg = Release|Win32
- {D07C378A-F5F7-438F-ADF3-4AC4FB1883CD}.Release|Win32.Build.0 = Release|Win32
- {D07C378A-F5F7-438F-ADF3-4AC4FB1883CD}.Release|x64.ActiveCfg = Release|x64
- {D07C378A-F5F7-438F-ADF3-4AC4FB1883CD}.Release|x64.Build.0 = Release|x64
- {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19}.All|Win32.ActiveCfg = Release|Win32
- {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19}.All|Win32.Build.0 = Release|Win32
- {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19}.All|x64.ActiveCfg = Release|Win32
- {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19}.Debug|Win32.ActiveCfg = Debug|Win32
- {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19}.Debug|Win32.Build.0 = Debug|Win32
- {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19}.Debug|x64.ActiveCfg = Debug|Win32
- {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19}.Debug|x64.Build.0 = Debug|Win32
- {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19}.Release|Win32.ActiveCfg = Release|Win32
- {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19}.Release|Win32.Build.0 = Release|Win32
- {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19}.Release|x64.ActiveCfg = Release|Win32
- {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19}.Release|x64.Build.0 = Release|Win32
- {ABB71A76-42B0-47A4-973A-42E3D920C6FD}.All|Win32.ActiveCfg = Release|x64
- {ABB71A76-42B0-47A4-973A-42E3D920C6FD}.All|x64.ActiveCfg = Release|x64
- {ABB71A76-42B0-47A4-973A-42E3D920C6FD}.All|x64.Build.0 = Release|x64
- {ABB71A76-42B0-47A4-973A-42E3D920C6FD}.Debug|Win32.ActiveCfg = Debug|Win32
- {ABB71A76-42B0-47A4-973A-42E3D920C6FD}.Debug|Win32.Build.0 = Debug|Win32
- {ABB71A76-42B0-47A4-973A-42E3D920C6FD}.Debug|x64.ActiveCfg = Debug|x64
- {ABB71A76-42B0-47A4-973A-42E3D920C6FD}.Debug|x64.Build.0 = Debug|x64
- {ABB71A76-42B0-47A4-973A-42E3D920C6FD}.Release|Win32.ActiveCfg = Release|Win32
- {ABB71A76-42B0-47A4-973A-42E3D920C6FD}.Release|Win32.Build.0 = Release|Win32
- {ABB71A76-42B0-47A4-973A-42E3D920C6FD}.Release|x64.ActiveCfg = Release|x64
- {ABB71A76-42B0-47A4-973A-42E3D920C6FD}.Release|x64.Build.0 = Release|x64
- {4D418176-3B33-47E6-A63E-01BA34ADD21C}.All|Win32.ActiveCfg = Release Passthrough|x64
- {4D418176-3B33-47E6-A63E-01BA34ADD21C}.All|x64.ActiveCfg = Release Passthrough|x64
- {4D418176-3B33-47E6-A63E-01BA34ADD21C}.All|x64.Build.0 = Release Passthrough|x64
- {4D418176-3B33-47E6-A63E-01BA34ADD21C}.Debug|Win32.ActiveCfg = Debug|Win32
- {4D418176-3B33-47E6-A63E-01BA34ADD21C}.Debug|Win32.Build.0 = Debug|Win32
- {4D418176-3B33-47E6-A63E-01BA34ADD21C}.Debug|x64.ActiveCfg = Debug|x64
- {4D418176-3B33-47E6-A63E-01BA34ADD21C}.Debug|x64.Build.0 = Debug|x64
- {4D418176-3B33-47E6-A63E-01BA34ADD21C}.Release|Win32.ActiveCfg = Release|Win32
- {4D418176-3B33-47E6-A63E-01BA34ADD21C}.Release|Win32.Build.0 = Release|Win32
- {4D418176-3B33-47E6-A63E-01BA34ADD21C}.Release|x64.ActiveCfg = Release|x64
- {4D418176-3B33-47E6-A63E-01BA34ADD21C}.Release|x64.Build.0 = Release|x64
- {7D3122C7-C9D0-3748-81F8-F0DDCB40BF5E}.All|Win32.ActiveCfg = Release|Win32
- {7D3122C7-C9D0-3748-81F8-F0DDCB40BF5E}.All|Win32.Build.0 = Release|Win32
- {7D3122C7-C9D0-3748-81F8-F0DDCB40BF5E}.All|x64.ActiveCfg = Release|Win32
- {7D3122C7-C9D0-3748-81F8-F0DDCB40BF5E}.Debug|Win32.ActiveCfg = Debug|Win32
- {7D3122C7-C9D0-3748-81F8-F0DDCB40BF5E}.Debug|x64.ActiveCfg = Debug|Win32
- {7D3122C7-C9D0-3748-81F8-F0DDCB40BF5E}.Release|Win32.ActiveCfg = Release|Win32
- {7D3122C7-C9D0-3748-81F8-F0DDCB40BF5E}.Release|x64.ActiveCfg = Release|Win32
- {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.All|Win32.ActiveCfg = Release|x64
- {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.All|x64.ActiveCfg = Release|x64
- {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.All|x64.Build.0 = Release|x64
- {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.Debug|Win32.ActiveCfg = Debug|Win32
- {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.Debug|Win32.Build.0 = Debug|Win32
- {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.Debug|x64.ActiveCfg = Debug|x64
- {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.Debug|x64.Build.0 = Debug|x64
- {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.Release|Win32.ActiveCfg = Release|Win32
- {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.Release|Win32.Build.0 = Release|Win32
- {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.Release|x64.ActiveCfg = Release|x64
- {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.Release|x64.Build.0 = Release|x64
- {B808178B-82F0-4CF4-A2B1-921939FA24D0}.All|Win32.ActiveCfg = Release|Win32
- {B808178B-82F0-4CF4-A2B1-921939FA24D0}.All|Win32.Build.0 = Release|Win32
- {B808178B-82F0-4CF4-A2B1-921939FA24D0}.All|x64.ActiveCfg = Release|Win32
- {B808178B-82F0-4CF4-A2B1-921939FA24D0}.Debug|Win32.ActiveCfg = Debug|Win32
- {B808178B-82F0-4CF4-A2B1-921939FA24D0}.Debug|Win32.Build.0 = Debug|Win32
- {B808178B-82F0-4CF4-A2B1-921939FA24D0}.Debug|x64.ActiveCfg = Debug|Win32
- {B808178B-82F0-4CF4-A2B1-921939FA24D0}.Debug|x64.Build.0 = Debug|Win32
- {B808178B-82F0-4CF4-A2B1-921939FA24D0}.Release|Win32.ActiveCfg = Release|Win32
- {B808178B-82F0-4CF4-A2B1-921939FA24D0}.Release|Win32.Build.0 = Release|Win32
- {B808178B-82F0-4CF4-A2B1-921939FA24D0}.Release|x64.ActiveCfg = Release|Win32
- {B808178B-82F0-4CF4-A2B1-921939FA24D0}.Release|x64.Build.0 = Release|Win32
- {9778F1C0-09BC-4698-8EBC-BD982247209A}.All|Win32.ActiveCfg = Release|x64
- {9778F1C0-09BC-4698-8EBC-BD982247209A}.All|x64.ActiveCfg = Release|x64
- {9778F1C0-09BC-4698-8EBC-BD982247209A}.All|x64.Build.0 = Release|x64
- {9778F1C0-09BC-4698-8EBC-BD982247209A}.Debug|Win32.ActiveCfg = Debug|Win32
- {9778F1C0-09BC-4698-8EBC-BD982247209A}.Debug|Win32.Build.0 = Debug|Win32
- {9778F1C0-09BC-4698-8EBC-BD982247209A}.Debug|x64.ActiveCfg = Debug|x64
- {9778F1C0-09BC-4698-8EBC-BD982247209A}.Debug|x64.Build.0 = Debug|x64
- {9778F1C0-09BC-4698-8EBC-BD982247209A}.Release|Win32.ActiveCfg = Release|Win32
- {9778F1C0-09BC-4698-8EBC-BD982247209A}.Release|Win32.Build.0 = Release|Win32
- {9778F1C0-09BC-4698-8EBC-BD982247209A}.Release|x64.ActiveCfg = Release|x64
- {9778F1C0-09BC-4698-8EBC-BD982247209A}.Release|x64.Build.0 = Release|x64
- {AFA983D6-4569-4F88-BA94-555ED00FD9A8}.All|Win32.ActiveCfg = Release|x64
- {AFA983D6-4569-4F88-BA94-555ED00FD9A8}.All|x64.ActiveCfg = Release|x64
- {AFA983D6-4569-4F88-BA94-555ED00FD9A8}.All|x64.Build.0 = Release|x64
- {AFA983D6-4569-4F88-BA94-555ED00FD9A8}.Debug|Win32.ActiveCfg = Debug|Win32
- {AFA983D6-4569-4F88-BA94-555ED00FD9A8}.Debug|Win32.Build.0 = Debug|Win32
- {AFA983D6-4569-4F88-BA94-555ED00FD9A8}.Debug|x64.ActiveCfg = Debug|x64
- {AFA983D6-4569-4F88-BA94-555ED00FD9A8}.Debug|x64.Build.0 = Debug|x64
- {AFA983D6-4569-4F88-BA94-555ED00FD9A8}.Release|Win32.ActiveCfg = Release|Win32
- {AFA983D6-4569-4F88-BA94-555ED00FD9A8}.Release|Win32.Build.0 = Release|Win32
- {AFA983D6-4569-4F88-BA94-555ED00FD9A8}.Release|x64.ActiveCfg = Release|x64
- {AFA983D6-4569-4F88-BA94-555ED00FD9A8}.Release|x64.Build.0 = Release|x64
- {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.All|Win32.ActiveCfg = Release|Win32
- {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.All|Win32.Build.0 = Release|Win32
- {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.All|x64.ActiveCfg = Release|Win32
- {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.Debug|Win32.ActiveCfg = Debug|Win32
- {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.Debug|Win32.Build.0 = Debug|Win32
- {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.Debug|x64.ActiveCfg = Debug|x64
- {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.Debug|x64.Build.0 = Debug|x64
- {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.Release|Win32.ActiveCfg = Release|Win32
- {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.Release|Win32.Build.0 = Release|Win32
- {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.Release|x64.ActiveCfg = Release|x64
- {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.Release|x64.Build.0 = Release|x64
- {990BAA76-89D3-4E38-8479-C7B28784EFC8}.All|Win32.ActiveCfg = Release|Win32
- {990BAA76-89D3-4E38-8479-C7B28784EFC8}.All|Win32.Build.0 = Release|Win32
- {990BAA76-89D3-4E38-8479-C7B28784EFC8}.All|x64.ActiveCfg = Release|Win32
- {990BAA76-89D3-4E38-8479-C7B28784EFC8}.Debug|Win32.ActiveCfg = Debug|Win32
- {990BAA76-89D3-4E38-8479-C7B28784EFC8}.Debug|Win32.Build.0 = Debug|Win32
- {990BAA76-89D3-4E38-8479-C7B28784EFC8}.Debug|x64.ActiveCfg = Debug|x64
- {990BAA76-89D3-4E38-8479-C7B28784EFC8}.Debug|x64.Build.0 = Debug|x64
- {990BAA76-89D3-4E38-8479-C7B28784EFC8}.Release|Win32.ActiveCfg = Release|Win32
- {990BAA76-89D3-4E38-8479-C7B28784EFC8}.Release|Win32.Build.0 = Release|Win32
- {990BAA76-89D3-4E38-8479-C7B28784EFC8}.Release|x64.ActiveCfg = Release|x64
- {990BAA76-89D3-4E38-8479-C7B28784EFC8}.Release|x64.Build.0 = Release|x64
- {1E21AFE0-6FDB-41D2-942D-863607C24B91}.All|Win32.ActiveCfg = Release|x64
- {1E21AFE0-6FDB-41D2-942D-863607C24B91}.All|x64.ActiveCfg = Release|x64
- {1E21AFE0-6FDB-41D2-942D-863607C24B91}.All|x64.Build.0 = Release|x64
- {1E21AFE0-6FDB-41D2-942D-863607C24B91}.Debug|Win32.ActiveCfg = Debug|Win32
- {1E21AFE0-6FDB-41D2-942D-863607C24B91}.Debug|Win32.Build.0 = Debug|Win32
- {1E21AFE0-6FDB-41D2-942D-863607C24B91}.Debug|x64.ActiveCfg = Debug|x64
- {1E21AFE0-6FDB-41D2-942D-863607C24B91}.Debug|x64.Build.0 = Debug|x64
- {1E21AFE0-6FDB-41D2-942D-863607C24B91}.Release|Win32.ActiveCfg = Release|Win32
- {1E21AFE0-6FDB-41D2-942D-863607C24B91}.Release|Win32.Build.0 = Release|Win32
- {1E21AFE0-6FDB-41D2-942D-863607C24B91}.Release|x64.ActiveCfg = Release|x64
- {1E21AFE0-6FDB-41D2-942D-863607C24B91}.Release|x64.Build.0 = Release|x64
- {2E250296-0C08-4342-9C8A-BCBDD0E7DF65}.All|Win32.ActiveCfg = Release|x64
- {2E250296-0C08-4342-9C8A-BCBDD0E7DF65}.All|x64.ActiveCfg = Release|x64
- {2E250296-0C08-4342-9C8A-BCBDD0E7DF65}.All|x64.Build.0 = Release|x64
- {2E250296-0C08-4342-9C8A-BCBDD0E7DF65}.Debug|Win32.ActiveCfg = Debug|Win32
- {2E250296-0C08-4342-9C8A-BCBDD0E7DF65}.Debug|Win32.Build.0 = Debug|Win32
- {2E250296-0C08-4342-9C8A-BCBDD0E7DF65}.Debug|x64.ActiveCfg = Debug|x64
- {2E250296-0C08-4342-9C8A-BCBDD0E7DF65}.Debug|x64.Build.0 = Debug|x64
- {2E250296-0C08-4342-9C8A-BCBDD0E7DF65}.Release|Win32.ActiveCfg = Release|Win32
- {2E250296-0C08-4342-9C8A-BCBDD0E7DF65}.Release|Win32.Build.0 = Release|Win32
- {2E250296-0C08-4342-9C8A-BCBDD0E7DF65}.Release|x64.ActiveCfg = Release|x64
- {2E250296-0C08-4342-9C8A-BCBDD0E7DF65}.Release|x64.Build.0 = Release|x64
- {D578E676-7EC8-4548-BD8B-845C635F14AD}.All|Win32.ActiveCfg = Release|Win32
- {D578E676-7EC8-4548-BD8B-845C635F14AD}.All|Win32.Build.0 = Release|Win32
- {D578E676-7EC8-4548-BD8B-845C635F14AD}.All|x64.ActiveCfg = Release|Win32
- {D578E676-7EC8-4548-BD8B-845C635F14AD}.Debug|Win32.ActiveCfg = Debug|Win32
- {D578E676-7EC8-4548-BD8B-845C635F14AD}.Debug|Win32.Build.0 = Debug|Win32
- {D578E676-7EC8-4548-BD8B-845C635F14AD}.Debug|x64.ActiveCfg = Debug|Win32
- {D578E676-7EC8-4548-BD8B-845C635F14AD}.Debug|x64.Build.0 = Debug|Win32
- {D578E676-7EC8-4548-BD8B-845C635F14AD}.Release|Win32.ActiveCfg = Release|Win32
- {D578E676-7EC8-4548-BD8B-845C635F14AD}.Release|Win32.Build.0 = Release|Win32
- {D578E676-7EC8-4548-BD8B-845C635F14AD}.Release|x64.ActiveCfg = Release|Win32
- {D578E676-7EC8-4548-BD8B-845C635F14AD}.Release|x64.Build.0 = Release|Win32
- {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.All|Win32.ActiveCfg = Release|Win32
- {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.All|Win32.Build.0 = Release|Win32
- {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.All|x64.ActiveCfg = Release|Win32
- {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Debug|Win32.ActiveCfg = Debug|Win32
- {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Debug|Win32.Build.0 = Debug|Win32
- {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Debug|x64.ActiveCfg = Debug|x64
- {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Debug|x64.Build.0 = Debug|x64
- {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Release|Win32.ActiveCfg = Release|Win32
- {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Release|Win32.Build.0 = Release|Win32
- {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Release|x64.ActiveCfg = Release|x64
- {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Release|x64.Build.0 = Release|x64
- {B4B62169-5AD4-4559-8707-3D933AC5DB39}.All|Win32.ActiveCfg = Release|Win32
- {B4B62169-5AD4-4559-8707-3D933AC5DB39}.All|Win32.Build.0 = Release|Win32
- {B4B62169-5AD4-4559-8707-3D933AC5DB39}.All|x64.ActiveCfg = Release|Win32
- {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Debug|Win32.ActiveCfg = Debug|Win32
- {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Debug|Win32.Build.0 = Debug|Win32
- {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Debug|x64.ActiveCfg = Debug|x64
- {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Debug|x64.Build.0 = Debug|x64
- {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Release|Win32.ActiveCfg = Release|Win32
- {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Release|Win32.Build.0 = Release|Win32
- {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Release|x64.ActiveCfg = Release|x64
- {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Release|x64.Build.0 = Release|x64
- {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.All|Win32.ActiveCfg = Release|Win32
- {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.All|Win32.Build.0 = Release|Win32
- {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.All|x64.ActiveCfg = Release|Win32
- {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.Debug|Win32.ActiveCfg = Debug|Win32
- {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.Debug|Win32.Build.0 = Debug|Win32
- {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.Debug|x64.ActiveCfg = Debug|x64
- {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.Debug|x64.Build.0 = Debug|x64
- {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.Release|Win32.ActiveCfg = Release|Win32
- {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.Release|Win32.Build.0 = Release|Win32
- {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.Release|x64.ActiveCfg = Release|x64
- {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.Release|x64.Build.0 = Release|x64
- {42E721FD-43D6-4B04-A34B-42567199FFB8}.All|Win32.ActiveCfg = Release|x64
- {42E721FD-43D6-4B04-A34B-42567199FFB8}.All|x64.ActiveCfg = Release|x64
- {42E721FD-43D6-4B04-A34B-42567199FFB8}.All|x64.Build.0 = Release|x64
- {42E721FD-43D6-4B04-A34B-42567199FFB8}.Debug|Win32.ActiveCfg = Debug|Win32
- {42E721FD-43D6-4B04-A34B-42567199FFB8}.Debug|x64.ActiveCfg = Debug|x64
- {42E721FD-43D6-4B04-A34B-42567199FFB8}.Release|Win32.ActiveCfg = Release|Win32
- {42E721FD-43D6-4B04-A34B-42567199FFB8}.Release|x64.ActiveCfg = Release|x64
- {23B4D303-79FC-49E0-89E2-2280E7E28940}.All|Win32.ActiveCfg = Release|x64
- {23B4D303-79FC-49E0-89E2-2280E7E28940}.All|x64.ActiveCfg = Release|x64
- {23B4D303-79FC-49E0-89E2-2280E7E28940}.All|x64.Build.0 = Release|x64
- {23B4D303-79FC-49E0-89E2-2280E7E28940}.Debug|Win32.ActiveCfg = Debug|Win32
- {23B4D303-79FC-49E0-89E2-2280E7E28940}.Debug|Win32.Build.0 = Debug|Win32
- {23B4D303-79FC-49E0-89E2-2280E7E28940}.Debug|x64.ActiveCfg = Debug|x64
- {23B4D303-79FC-49E0-89E2-2280E7E28940}.Debug|x64.Build.0 = Debug|x64
- {23B4D303-79FC-49E0-89E2-2280E7E28940}.Release|Win32.ActiveCfg = Release|Win32
- {23B4D303-79FC-49E0-89E2-2280E7E28940}.Release|Win32.Build.0 = Release|Win32
- {23B4D303-79FC-49E0-89E2-2280E7E28940}.Release|x64.ActiveCfg = Release|x64
- {23B4D303-79FC-49E0-89E2-2280E7E28940}.Release|x64.Build.0 = Release|x64
- {0807C5CB-F6FF-451D-89F0-1F7B2E1D9169}.All|Win32.ActiveCfg = Release|x64
- {0807C5CB-F6FF-451D-89F0-1F7B2E1D9169}.All|x64.ActiveCfg = Release|x64
- {0807C5CB-F6FF-451D-89F0-1F7B2E1D9169}.All|x64.Build.0 = Release|x64
- {0807C5CB-F6FF-451D-89F0-1F7B2E1D9169}.Debug|Win32.ActiveCfg = Debug|Win32
- {0807C5CB-F6FF-451D-89F0-1F7B2E1D9169}.Debug|Win32.Build.0 = Debug|Win32
- {0807C5CB-F6FF-451D-89F0-1F7B2E1D9169}.Debug|x64.ActiveCfg = Debug|x64
- {0807C5CB-F6FF-451D-89F0-1F7B2E1D9169}.Debug|x64.Build.0 = Debug|x64
- {0807C5CB-F6FF-451D-89F0-1F7B2E1D9169}.Release|Win32.ActiveCfg = Release|Win32
- {0807C5CB-F6FF-451D-89F0-1F7B2E1D9169}.Release|Win32.Build.0 = Release|Win32
- {0807C5CB-F6FF-451D-89F0-1F7B2E1D9169}.Release|x64.ActiveCfg = Release|x64
- {0807C5CB-F6FF-451D-89F0-1F7B2E1D9169}.Release|x64.Build.0 = Release|x64
- {BDA173DB-F8EF-4270-9553-B453AF92E43A}.All|Win32.ActiveCfg = Release|x64
- {BDA173DB-F8EF-4270-9553-B453AF92E43A}.All|x64.ActiveCfg = Release|x64
- {BDA173DB-F8EF-4270-9553-B453AF92E43A}.All|x64.Build.0 = Release|x64
- {BDA173DB-F8EF-4270-9553-B453AF92E43A}.Debug|Win32.ActiveCfg = Debug|Win32
- {BDA173DB-F8EF-4270-9553-B453AF92E43A}.Debug|Win32.Build.0 = Debug|Win32
- {BDA173DB-F8EF-4270-9553-B453AF92E43A}.Debug|x64.ActiveCfg = Debug|x64
- {BDA173DB-F8EF-4270-9553-B453AF92E43A}.Debug|x64.Build.0 = Debug|x64
- {BDA173DB-F8EF-4270-9553-B453AF92E43A}.Release|Win32.ActiveCfg = Release|Win32
- {BDA173DB-F8EF-4270-9553-B453AF92E43A}.Release|Win32.Build.0 = Release|Win32
- {BDA173DB-F8EF-4270-9553-B453AF92E43A}.Release|x64.ActiveCfg = Release|x64
- {BDA173DB-F8EF-4270-9553-B453AF92E43A}.Release|x64.Build.0 = Release|x64
- {74B120FF-6935-4DFE-A142-CDB6BEA99C90}.All|Win32.ActiveCfg = Release|Win32
- {74B120FF-6935-4DFE-A142-CDB6BEA99C90}.All|Win32.Build.0 = Release|Win32
- {74B120FF-6935-4DFE-A142-CDB6BEA99C90}.All|x64.ActiveCfg = Release|Win32
- {74B120FF-6935-4DFE-A142-CDB6BEA99C90}.Debug|Win32.ActiveCfg = Debug|Win32
- {74B120FF-6935-4DFE-A142-CDB6BEA99C90}.Debug|x64.ActiveCfg = Debug|x64
- {74B120FF-6935-4DFE-A142-CDB6BEA99C90}.Release|Win32.ActiveCfg = Release|Win32
- {74B120FF-6935-4DFE-A142-CDB6BEA99C90}.Release|x64.ActiveCfg = Release|x64
- {26C82FCE-E0CF-4D10-A00C-D8E582FFEB53}.All|Win32.ActiveCfg = Debug|Win32
- {26C82FCE-E0CF-4D10-A00C-D8E582FFEB53}.All|Win32.Build.0 = Debug|Win32
- {26C82FCE-E0CF-4D10-A00C-D8E582FFEB53}.All|x64.ActiveCfg = Debug|Win32
- {26C82FCE-E0CF-4D10-A00C-D8E582FFEB53}.Debug|Win32.ActiveCfg = Debug|Win32
- {26C82FCE-E0CF-4D10-A00C-D8E582FFEB53}.Debug|x64.ActiveCfg = Debug|x64
- {26C82FCE-E0CF-4D10-A00C-D8E582FFEB53}.Release|Win32.ActiveCfg = Release|Win32
- {26C82FCE-E0CF-4D10-A00C-D8E582FFEB53}.Release|x64.ActiveCfg = Release|x64
- {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}.All|Win32.ActiveCfg = Debug|x64
- {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}.All|x64.ActiveCfg = Debug|x64
- {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}.All|x64.Build.0 = Debug|x64
- {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}.Debug|Win32.ActiveCfg = Debug|Win32
- {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}.Debug|Win32.Build.0 = Debug|Win32
- {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}.Debug|x64.ActiveCfg = Debug|x64
- {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}.Debug|x64.Build.0 = Debug|x64
- {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}.Release|Win32.ActiveCfg = Release|Win32
- {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}.Release|Win32.Build.0 = Release|Win32
- {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}.Release|x64.ActiveCfg = Release|x64
- {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}.Release|x64.Build.0 = Release|x64
- {21A7DA70-555E-49FA-942B-D84A38B61243}.All|Win32.ActiveCfg = Release|Win32
- {21A7DA70-555E-49FA-942B-D84A38B61243}.All|Win32.Build.0 = Release|Win32
- {21A7DA70-555E-49FA-942B-D84A38B61243}.All|x64.ActiveCfg = Release|Win32
- {21A7DA70-555E-49FA-942B-D84A38B61243}.Debug|Win32.ActiveCfg = Debug|Win32
- {21A7DA70-555E-49FA-942B-D84A38B61243}.Debug|Win32.Build.0 = Debug|Win32
- {21A7DA70-555E-49FA-942B-D84A38B61243}.Debug|x64.ActiveCfg = Debug|Win32
- {21A7DA70-555E-49FA-942B-D84A38B61243}.Debug|x64.Build.0 = Debug|Win32
- {21A7DA70-555E-49FA-942B-D84A38B61243}.Release|Win32.ActiveCfg = Release|Win32
- {21A7DA70-555E-49FA-942B-D84A38B61243}.Release|Win32.Build.0 = Release|Win32
- {21A7DA70-555E-49FA-942B-D84A38B61243}.Release|x64.ActiveCfg = Release|Win32
- {21A7DA70-555E-49FA-942B-D84A38B61243}.Release|x64.Build.0 = Release|Win32
- {A4D67895-E709-40C7-82B6-DE1D12DDDE04}.All|Win32.ActiveCfg = Release|x64
- {A4D67895-E709-40C7-82B6-DE1D12DDDE04}.All|x64.ActiveCfg = Release|x64
- {A4D67895-E709-40C7-82B6-DE1D12DDDE04}.All|x64.Build.0 = Release|x64
- {A4D67895-E709-40C7-82B6-DE1D12DDDE04}.Debug|Win32.ActiveCfg = Debug|Win32
- {A4D67895-E709-40C7-82B6-DE1D12DDDE04}.Debug|Win32.Build.0 = Debug|Win32
- {A4D67895-E709-40C7-82B6-DE1D12DDDE04}.Debug|x64.ActiveCfg = Debug|x64
- {A4D67895-E709-40C7-82B6-DE1D12DDDE04}.Debug|x64.Build.0 = Debug|x64
- {A4D67895-E709-40C7-82B6-DE1D12DDDE04}.Release|Win32.ActiveCfg = Release|Win32
- {A4D67895-E709-40C7-82B6-DE1D12DDDE04}.Release|Win32.Build.0 = Release|Win32
- {A4D67895-E709-40C7-82B6-DE1D12DDDE04}.Release|x64.ActiveCfg = Release|x64
- {A4D67895-E709-40C7-82B6-DE1D12DDDE04}.Release|x64.Build.0 = Release|x64
- {2390F054-A7F1-4CB9-ACB0-F46EC6E77B5B}.All|Win32.ActiveCfg = Release|x64
- {2390F054-A7F1-4CB9-ACB0-F46EC6E77B5B}.All|x64.ActiveCfg = Release|x64
- {2390F054-A7F1-4CB9-ACB0-F46EC6E77B5B}.All|x64.Build.0 = Release|x64
- {2390F054-A7F1-4CB9-ACB0-F46EC6E77B5B}.Debug|Win32.ActiveCfg = Debug|Win32
- {2390F054-A7F1-4CB9-ACB0-F46EC6E77B5B}.Debug|Win32.Build.0 = Debug|Win32
- {2390F054-A7F1-4CB9-ACB0-F46EC6E77B5B}.Debug|x64.ActiveCfg = Debug|x64
- {2390F054-A7F1-4CB9-ACB0-F46EC6E77B5B}.Debug|x64.Build.0 = Debug|x64
- {2390F054-A7F1-4CB9-ACB0-F46EC6E77B5B}.Release|Win32.ActiveCfg = Release|Win32
- {2390F054-A7F1-4CB9-ACB0-F46EC6E77B5B}.Release|Win32.Build.0 = Release|Win32
- {2390F054-A7F1-4CB9-ACB0-F46EC6E77B5B}.Release|x64.ActiveCfg = Release|x64
- {2390F054-A7F1-4CB9-ACB0-F46EC6E77B5B}.Release|x64.Build.0 = Release|x64
- {E5A9BCDA-B82D-4B08-B23E-9A782E367888}.All|Win32.ActiveCfg = Debug|x64
- {E5A9BCDA-B82D-4B08-B23E-9A782E367888}.All|x64.ActiveCfg = Debug|x64
- {E5A9BCDA-B82D-4B08-B23E-9A782E367888}.All|x64.Build.0 = Debug|x64
- {E5A9BCDA-B82D-4B08-B23E-9A782E367888}.Debug|Win32.ActiveCfg = Debug|Win32
- {E5A9BCDA-B82D-4B08-B23E-9A782E367888}.Debug|Win32.Build.0 = Debug|Win32
- {E5A9BCDA-B82D-4B08-B23E-9A782E367888}.Debug|x64.ActiveCfg = Debug|x64
- {E5A9BCDA-B82D-4B08-B23E-9A782E367888}.Debug|x64.Build.0 = Debug|x64
- {E5A9BCDA-B82D-4B08-B23E-9A782E367888}.Release|Win32.ActiveCfg = Release|Win32
- {E5A9BCDA-B82D-4B08-B23E-9A782E367888}.Release|Win32.Build.0 = Release|Win32
- {E5A9BCDA-B82D-4B08-B23E-9A782E367888}.Release|x64.ActiveCfg = Release|x64
- {E5A9BCDA-B82D-4B08-B23E-9A782E367888}.Release|x64.Build.0 = Release|x64
- {510BDAA8-C04D-47DB-8482-E6AF380D3E07}.All|Win32.ActiveCfg = Release|x64
- {510BDAA8-C04D-47DB-8482-E6AF380D3E07}.All|x64.ActiveCfg = Release|x64
- {510BDAA8-C04D-47DB-8482-E6AF380D3E07}.All|x64.Build.0 = Release|x64
- {510BDAA8-C04D-47DB-8482-E6AF380D3E07}.Debug|Win32.ActiveCfg = Debug|Win32
- {510BDAA8-C04D-47DB-8482-E6AF380D3E07}.Debug|Win32.Build.0 = Debug|Win32
- {510BDAA8-C04D-47DB-8482-E6AF380D3E07}.Debug|x64.ActiveCfg = Debug|x64
- {510BDAA8-C04D-47DB-8482-E6AF380D3E07}.Debug|x64.Build.0 = Debug|x64
- {510BDAA8-C04D-47DB-8482-E6AF380D3E07}.Release|Win32.ActiveCfg = Release|Win32
- {510BDAA8-C04D-47DB-8482-E6AF380D3E07}.Release|Win32.Build.0 = Release|Win32
- {510BDAA8-C04D-47DB-8482-E6AF380D3E07}.Release|x64.ActiveCfg = Release|x64
- {510BDAA8-C04D-47DB-8482-E6AF380D3E07}.Release|x64.Build.0 = Release|x64
- {3CF7C0E0-07C2-473A-A1E4-2274AEEC1268}.All|Win32.ActiveCfg = Release|x64
- {3CF7C0E0-07C2-473A-A1E4-2274AEEC1268}.All|x64.ActiveCfg = Release|x64
- {3CF7C0E0-07C2-473A-A1E4-2274AEEC1268}.All|x64.Build.0 = Release|x64
- {3CF7C0E0-07C2-473A-A1E4-2274AEEC1268}.Debug|Win32.ActiveCfg = Debug|Win32
- {3CF7C0E0-07C2-473A-A1E4-2274AEEC1268}.Debug|Win32.Build.0 = Debug|Win32
- {3CF7C0E0-07C2-473A-A1E4-2274AEEC1268}.Debug|x64.ActiveCfg = Debug|x64
- {3CF7C0E0-07C2-473A-A1E4-2274AEEC1268}.Debug|x64.Build.0 = Debug|x64
- {3CF7C0E0-07C2-473A-A1E4-2274AEEC1268}.Release|Win32.ActiveCfg = Release|Win32
- {3CF7C0E0-07C2-473A-A1E4-2274AEEC1268}.Release|Win32.Build.0 = Release|Win32
- {3CF7C0E0-07C2-473A-A1E4-2274AEEC1268}.Release|x64.ActiveCfg = Release|x64
- {3CF7C0E0-07C2-473A-A1E4-2274AEEC1268}.Release|x64.Build.0 = Release|x64
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
- GlobalSection(NestedProjects) = preSolution
- {1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0} = {F881ADA2-2F1A-4046-9FEB-191D9422D781}
- {5580D60E-0F77-4716-9CD4-B8E5986FA375} = {F881ADA2-2F1A-4046-9FEB-191D9422D781}
- {D3EC0AFF-76FC-4210-A825-9A17410660A3} = {F881ADA2-2F1A-4046-9FEB-191D9422D781}
- {FEA1EEF7-876F-48DE-88BF-C0E3E606D758} = {F881ADA2-2F1A-4046-9FEB-191D9422D781}
- {8DEB383C-4091-4F42-A56F-C9E46D552D79} = {F881ADA2-2F1A-4046-9FEB-191D9422D781}
- {2C3C2423-234B-4772-8899-D3B137E5CA35} = {F881ADA2-2F1A-4046-9FEB-191D9422D781}
- {0B6C905B-142E-4999-B39D-92FF7951E921} = {F881ADA2-2F1A-4046-9FEB-191D9422D781}
- {7F1610F1-DD5A-4CF7-8610-30AB12C60ADD} = {F881ADA2-2F1A-4046-9FEB-191D9422D781}
- {D5C87B19-150D-4EF3-A671-96589BD2D14A} = {F881ADA2-2F1A-4046-9FEB-191D9422D781}
- {4D418176-3B33-47E6-A63E-01BA34ADD21C} = {F881ADA2-2F1A-4046-9FEB-191D9422D781}
- {AFA983D6-4569-4F88-BA94-555ED00FD9A8} = {F881ADA2-2F1A-4046-9FEB-191D9422D781}
- {5FD31A25-5D83-4794-8BEE-904DAD84CE71} = {9460B5F1-0A95-41C4-BEB7-9C2C96459A7C}
- {FFAA4C52-3A53-4F99-90C1-D59D1F0427F3} = {9460B5F1-0A95-41C4-BEB7-9C2C96459A7C}
- {0DF3ABD0-DDC0-4265-B778-07C66780979B} = {9460B5F1-0A95-41C4-BEB7-9C2C96459A7C}
- {B3F424EC-3D8F-417C-B244-3919D5E1A577} = {9460B5F1-0A95-41C4-BEB7-9C2C96459A7C}
- {05C9FB27-480E-4D53-B3B7-6338E2526666} = {9460B5F1-0A95-41C4-BEB7-9C2C96459A7C}
- {05C9FB27-480E-4D53-B3B7-7338E2514666} = {9460B5F1-0A95-41C4-BEB7-9C2C96459A7C}
- {CC1DD008-9406-448D-A0AD-33C3186CFADB} = {9460B5F1-0A95-41C4-BEB7-9C2C96459A7C}
- {48414740-C693-4968-9846-EE058020C64F} = {9460B5F1-0A95-41C4-BEB7-9C2C96459A7C}
- {C6E78A4C-DB1E-47F4-9B63-4DC27D86343F} = {9460B5F1-0A95-41C4-BEB7-9C2C96459A7C}
- {74B120FF-6935-4DFE-A142-CDB6BEA99C90} = {9460B5F1-0A95-41C4-BEB7-9C2C96459A7C}
- {30A5B29C-983E-4580-9FD0-D647CCDCC7EB} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
- {B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
- {C24FB505-05D7-4319-8485-7540B44C8603} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
- {B5881A85-FE70-4F64-8607-2CAAE52669C6} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
- {71A967D5-0E99-4CEF-A587-98836EE6F2EF} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
- {3850D93A-5F24-4922-BC1C-74D08C37C256} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
- {D7F1E3F2-A3F4-474C-8555-15122571AF52} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
- {75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
- {F6A33240-8F29-48BD-98F0-826995911799} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
- {65A6273D-FCAB-4C55-B09E-65100141A5D4} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
- {E3246D17-E29B-4AB5-962A-C69B0C5837BB} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
- {2A3D00C6-588D-4E86-81AC-9EF5EDE86E03} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
- {14E4A972-9CFB-436D-B0A5-4943F3F80D47} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
- {329FD5B0-EF28-4606-86D0-F6EA21CF8E36} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
- {1A3793D1-05D1-4B57-9B0F-5AF3E79DC439} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
- {11C9BC3D-45E9-46E3-BE84-B8CEE4685E39} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
- {3C977801-FE88-48F2-83D3-FA2EBFF6688E} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
- {432DB165-1EB2-4781-A9C0-71E62610B20A} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
- {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
- {990BAA76-89D3-4E38-8479-C7B28784EFC8} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
- {1E21AFE0-6FDB-41D2-942D-863607C24B91} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
- {2E250296-0C08-4342-9C8A-BCBDD0E7DF65} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
- {42E721FD-43D6-4B04-A34B-42567199FFB8} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
- {0807C5CB-F6FF-451D-89F0-1F7B2E1D9169} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
- {BDA173DB-F8EF-4270-9553-B453AF92E43A} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
- {07113B25-D3AF-4E04-BA77-4CD1171F022C} = {C5F182F9-754A-4EC5-B50F-76ED02BE13F4}
- {A27CCA23-1541-4337-81A4-F0A6413078A0} = {C5F182F9-754A-4EC5-B50F-76ED02BE13F4}
- {E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24} = {C5F182F9-754A-4EC5-B50F-76ED02BE13F4}
- {784113EF-44D9-4949-835D-7065D3C7AD08} = {9ADF1E48-2F5C-4ED7-A893-596259FABFE0}
- {05515420-16DE-4E63-BE73-85BE85BA5142} = {9ADF1E48-2F5C-4ED7-A893-596259FABFE0}
- {44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E} = {9ADF1E48-2F5C-4ED7-A893-596259FABFE0}
- {AFAC0568-7548-42D5-9F6A-8D3400A1E4F6} = {A5A27244-AD24-46E5-B01B-840CD296C91D}
- {9254C4B0-6F60-42B6-BB3A-36D63FC001C7} = {A5A27244-AD24-46E5-B01B-840CD296C91D}
- {2CA40887-1622-46A1-A7F9-17FD7E7E545B} = {A5A27244-AD24-46E5-B01B-840CD296C91D}
- {6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52} = {A5A27244-AD24-46E5-B01B-840CD296C91D}
- {38FE0559-9910-43A8-9E45-3E5004C27692} = {A5A27244-AD24-46E5-B01B-840CD296C91D}
- {1A1FF289-4FD6-4285-A422-D31DD67A4723} = {CBD81696-EFB4-4D2F-8451-1B8DAA86155A}
- {EC3E5C7F-EE09-47E2-80FE-546363D14A98} = {B8F5B47B-8568-46EB-B320-64C17D2A98BC}
- {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F} = {0C808854-54D1-4230-BFF5-77B5FD905000}
- {ACFFF684-4D19-4D48-AF12-88EA1D778BDF} = {0C808854-54D1-4230-BFF5-77B5FD905000}
- {8F992C49-6C51-412F-B2A3-34EAB708EB65} = {0C808854-54D1-4230-BFF5-77B5FD905000}
- {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF} = {0C808854-54D1-4230-BFF5-77B5FD905000}
- {028C7278-05D7-4E18-82FE-BE231B844F41} = {0C808854-54D1-4230-BFF5-77B5FD905000}
- {36E854E3-CE12-4348-A125-CCF3F9D74813} = {0C808854-54D1-4230-BFF5-77B5FD905000}
- {7B077E7F-1BE7-4291-AB86-55E527B25CAC} = {0C808854-54D1-4230-BFF5-77B5FD905000}
- {7B42BDA1-72C0-4378-A9B6-5C530F8CD61E} = {0C808854-54D1-4230-BFF5-77B5FD905000}
- {692F6330-4D87-4C82-81DF-40DB5892636E} = {4CF6A6AC-07DE-4B9E-ABE1-7F98B64E0BB0}
- {2286DA73-9FC5-45BC-A508-85994C3317AB} = {4CF6A6AC-07DE-4B9E-ABE1-7F98B64E0BB0}
- {66444AEE-554C-11DD-A9F0-8C5D56D89593} = {4CF6A6AC-07DE-4B9E-ABE1-7F98B64E0BB0}
- {D07C378A-F5F7-438F-ADF3-4AC4FB1883CD} = {4CF6A6AC-07DE-4B9E-ABE1-7F98B64E0BB0}
- {1C453396-D912-4213-89FD-9B489162B7B5} = {A7AB4405-FDB7-4853-9FBB-1516B1C3D80A}
- {D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909} = {A7AB4405-FDB7-4853-9FBB-1516B1C3D80A}
- {CBEC7225-0C21-4DA8-978E-1F158F8AD950} = {F69A4A6B-9360-4EBB-A280-22AA3C455AC5}
- {AB91A099-7690-4ECF-8994-E458F4EA1ED4} = {F69A4A6B-9360-4EBB-A280-22AA3C455AC5}
- {08DAD348-9E0A-4A2E-97F1-F1E7E24A7836} = {F69A4A6B-9360-4EBB-A280-22AA3C455AC5}
- {89385C74-5860-4174-9CAF-A39E7C48909C} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
- {1906D736-08BD-4EE1-924F-B536249B9A54} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
- {EEF031CB-FED8-451E-A471-91EC8D4F6750} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
- {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
- {8D04B550-D240-4A44-8A18-35DA3F7038D9} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
- {1CED5987-A529-46DC-B30F-870D85FF9C94} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
- {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
- {F057DA7F-79E5-4B00-845C-EF446EF055E3} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
- {E727E8F6-935D-46FE-8B0E-37834748A0E3} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
- {3D0370CA-BED2-4657-A475-32375CBCB6E4} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
- {87EE9DA4-DE1E-4448-8324-183C98DCA588} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
- {155844C3-EC5F-407F-97A4-A2DDADED9B2F} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
- {204FA0DE-305D-4414-AE2E-F195A23F390D} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
- {70A49BC2-7500-41D0-B75D-EDCC5BE987A0} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
- {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
- {0A18A071-125E-442F-AFF7-A3F68ABECF99} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
- {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
- {94001A0E-A837-445C-8004-F918F10D0226} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
- {0AD1177E-1FD8-4643-9391-431467A11084} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
- {E316772F-5D8F-4F2A-8F71-094C3E859D34} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
- {D3D8B329-20BE-475E-9E83-653CEA0E0EF5} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
- {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
- {419C8F80-D858-4B48-A25C-AF4007608137} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
- {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
- {CF405366-9558-4AE8-90EF-5E21B51CCB4E} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
- {401A40CD-5DB4-4E34-AC68-FA99E9FAC014} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
- {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
- {E972C52F-9E85-4D65-B19C-031E511E9DB4} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
- {03207781-0D1C-4DB3-A71D-45C608F28DBD} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
- {9A5DDF08-C88C-4A35-B7F6-D605228446BD} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
- {D0B36172-CD76-454A-9B89-990025266C2A} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
- {DEE932AB-5911-4700-9EEB-8C7090A0A330} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
- {329A6FA0-0FCC-4435-A950-E670AEFA9838} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
- {CF70F278-3364-4395-A2E1-23501C9B8AD2} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
- {62F27B1A-C919-4A70-8478-51F178F3B18F} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
- {ABB71A76-42B0-47A4-973A-42E3D920C6FD} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
- {9778F1C0-09BC-4698-8EBC-BD982247209A} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
- {56B91D01-9150-4BBF-AFA1-5B68AB991B76} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
- {B376D494-D7DD-4B2A-99E2-52916D5A8CD8} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
- {23B4D303-79FC-49E0-89E2-2280E7E28940} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
- {26C82FCE-E0CF-4D10-A00C-D8E582FFEB53} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
- {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
- {3783935D-7C0A-4166-A376-C3D8E64F3A9C} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
- {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A} = {C120A020-773F-4EA3-923F-B67AF28B750D}
- {4F92B672-DADB-4047-8D6A-4BB3796733FD} = {C120A020-773F-4EA3-923F-B67AF28B750D}
- {2DEE4895-1134-439C-B688-52203E57D878} = {C120A020-773F-4EA3-923F-B67AF28B750D}
- {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E} = {C120A020-773F-4EA3-923F-B67AF28B750D}
- {3CE1DC99-8246-4DB1-A709-74F19F08EC67} = {C120A020-773F-4EA3-923F-B67AF28B750D}
- {87A1FE3D-F410-4C8E-9591-8C625985BC70} = {C120A020-773F-4EA3-923F-B67AF28B750D}
- {6E49F6C2-ADDA-4BFB-81FE-AB9AF51B455F} = {C120A020-773F-4EA3-923F-B67AF28B750D}
- {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B} = {C120A020-773F-4EA3-923F-B67AF28B750D}
- {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B} = {C120A020-773F-4EA3-923F-B67AF28B750D}
- {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B} = {C120A020-773F-4EA3-923F-B67AF28B750D}
- {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B} = {C120A020-773F-4EA3-923F-B67AF28B750D}
- {E796E337-DE78-4303-8614-9A590862EE95} = {C120A020-773F-4EA3-923F-B67AF28B750D}
- {1F0A8A77-E661-418F-BB92-82172AE43803} = {C120A020-773F-4EA3-923F-B67AF28B750D}
- {4F5C9D55-98EF-4256-8311-32D7BD360406} = {C120A020-773F-4EA3-923F-B67AF28B750D}
- {E10571C4-E7F4-4608-B5F2-B22E7EB95400} = {C120A020-773F-4EA3-923F-B67AF28B750D}
- {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19} = {C120A020-773F-4EA3-923F-B67AF28B750D}
- {B808178B-82F0-4CF4-A2B1-921939FA24D0} = {C120A020-773F-4EA3-923F-B67AF28B750D}
- {D578E676-7EC8-4548-BD8B-845C635F14AD} = {C120A020-773F-4EA3-923F-B67AF28B750D}
- {21A7DA70-555E-49FA-942B-D84A38B61243} = {C120A020-773F-4EA3-923F-B67AF28B750D}
- {988CACF7-3FCB-4992-BE69-77872AE67DC8} = {6CD61A1D-797C-470A-BE08-8C31B68BB336}
- {5BC072DB-3826-48EA-AF34-FE32AA01E83B} = {6CD61A1D-797C-470A-BE08-8C31B68BB336}
- {FA429E98-8B03-45E6-A096-A4BC5E821DE4} = {6CD61A1D-797C-470A-BE08-8C31B68BB336}
- {06E3A538-AB32-44F2-B477-755FF9CB5D37} = {6CD61A1D-797C-470A-BE08-8C31B68BB336}
- {6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05} = {6CD61A1D-797C-470A-BE08-8C31B68BB336}
- {A4B122CF-5196-476B-8C0E-D8BD59AC3C14} = {6CD61A1D-797C-470A-BE08-8C31B68BB336}
- {B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E} = {6CD61A1D-797C-470A-BE08-8C31B68BB336}
- {0382E8FD-CFDC-41C0-8B03-792C7C84FC31} = {6CD61A1D-797C-470A-BE08-8C31B68BB336}
- {3B08FEFD-4D3D-4C16-BA94-EE83509E32A0} = {57D119DC-484F-420F-B9E9-8589FD9A8DF8}
- {3C90CCF0-2CDD-4A7A-ACFF-208C1E271692} = {3B08FEFD-4D3D-4C16-BA94-EE83509E32A0}
- {C7E2382E-2C22-4D18-BF93-80C6A1FFA7AC} = {3B08FEFD-4D3D-4C16-BA94-EE83509E32A0}
- {FC71C66E-E268-4EAD-B1F5-F008DC382E83} = {3B08FEFD-4D3D-4C16-BA94-EE83509E32A0}
- {8E2E8798-8B6F-4A55-8E4F-4E6FDE40ED26} = {3B08FEFD-4D3D-4C16-BA94-EE83509E32A0}
- {09455AA9-C243-4F16-A1A1-A016881A2765} = {3B08FEFD-4D3D-4C16-BA94-EE83509E32A0}
- {CDE9B06A-3C27-4987-8FAE-DF1006BC705D} = {DB1024A8-41BF-4AD7-9AE6-13202230D1F3}
- {57199684-EC63-4A60-9DC6-11815AF6B413} = {09455AA9-C243-4F16-A1A1-A016881A2765}
- {2DED4BA2-D6B0-4064-BB2A-76DE3AA49E7C} = {09455AA9-C243-4F16-A1A1-A016881A2765}
- {D4A12E4C-DBDA-4614-BA26-3425AE9F60F5} = {09455AA9-C243-4F16-A1A1-A016881A2765}
- {765EF1B9-5027-4820-BC37-A44466A51631} = {57199684-EC63-4A60-9DC6-11815AF6B413}
- {713E4747-1126-40B1-BD84-58F9A7745423} = {57199684-EC63-4A60-9DC6-11815AF6B413}
- {D3E5C8ED-3A6A-4FEA-92A2-48A0BA865358} = {2DED4BA2-D6B0-4064-BB2A-76DE3AA49E7C}
- {CC3E7F48-2590-49CB-AD8B-BE3650F55462} = {2DED4BA2-D6B0-4064-BB2A-76DE3AA49E7C}
- {F1B71990-EB04-4EB5-B28A-BC3EB6F7E843} = {D4A12E4C-DBDA-4614-BA26-3425AE9F60F5}
- {3DAF028C-AB5B-4183-A01B-DCC43F5A87F0} = {D4A12E4C-DBDA-4614-BA26-3425AE9F60F5}
- {7A8D8174-B355-4114-AFC1-04777CB9DE0A} = {4F227C26-768F-46A3-8684-1D08A46FB374}
- {7EB71250-F002-4ED8-92CA-CA218114537A} = {4F227C26-768F-46A3-8684-1D08A46FB374}
- {464AAB78-5489-4916-BE51-BF8D61822311} = {4F227C26-768F-46A3-8684-1D08A46FB374}
- {D1ABE208-6442-4FB4-9AAD-1677E41BC870} = {4F227C26-768F-46A3-8684-1D08A46FB374}
- {BA599D0A-4310-4505-91DA-6A6447B3E289} = {4F227C26-768F-46A3-8684-1D08A46FB374}
- {EED13FC7-4F81-4E6F-93DB-CDB7DF5CF959} = {4F227C26-768F-46A3-8684-1D08A46FB374}
- {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2} = {62F27B1A-C919-4A70-8478-51F178F3B18F}
- {B5A00BFA-6083-4FAE-A097-71642D6473B5} = {62F27B1A-C919-4A70-8478-51F178F3B18F}
- {1C320193-46A6-4B34-9C56-8AB584FC1B56} = {62F27B1A-C919-4A70-8478-51F178F3B18F}
- {72782932-37CC-46AE-8C7F-9A7B1A6EE108} = {62F27B1A-C919-4A70-8478-51F178F3B18F}
- {12A49562-BAB9-43A3-A21D-15B60BBB4C31} = {62F27B1A-C919-4A70-8478-51F178F3B18F}
- {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA} = {62F27B1A-C919-4A70-8478-51F178F3B18F}
- {504B3154-7A4F-459D-9877-B951021C3F1F} = {62F27B1A-C919-4A70-8478-51F178F3B18F}
- {746F3632-5BB2-4570-9453-31D6D58A7D8E} = {62F27B1A-C919-4A70-8478-51F178F3B18F}
- {DEB01ACB-D65F-4A62-AED9-58C1054499E9} = {62F27B1A-C919-4A70-8478-51F178F3B18F}
- {D331904D-A00A-4694-A5A3-FCFF64AB5DBE} = {B376D494-D7DD-4B2A-99E2-52916D5A8CD8}
- {B4B62169-5AD4-4559-8707-3D933AC5DB39} = {B376D494-D7DD-4B2A-99E2-52916D5A8CD8}
- {25BD39B1-C8BF-4676-A738-9CABD9C6BC79} = {B376D494-D7DD-4B2A-99E2-52916D5A8CD8}
- {A4D67895-E709-40C7-82B6-DE1D12DDDE04} = {3783935D-7C0A-4166-A376-C3D8E64F3A9C}
- {2390F054-A7F1-4CB9-ACB0-F46EC6E77B5B} = {3783935D-7C0A-4166-A376-C3D8E64F3A9C}
- {E5A9BCDA-B82D-4B08-B23E-9A782E367888} = {3783935D-7C0A-4166-A376-C3D8E64F3A9C}
- {510BDAA8-C04D-47DB-8482-E6AF380D3E07} = {3783935D-7C0A-4166-A376-C3D8E64F3A9C}
- {3CF7C0E0-07C2-473A-A1E4-2274AEEC1268} = {3783935D-7C0A-4166-A376-C3D8E64F3A9C}
- EndGlobalSection
-EndGlobal
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Codecs", "Codecs", "{F881ADA2-2F1A-4046-9FEB-191D9422D781}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Endpoints", "Endpoints", "{9460B5F1-0A95-41C4-BEB7-9C2C96459A7C}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Applications", "Applications", "{E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Dialplans", "Dialplans", "{C5F182F9-754A-4EC5-B50F-76ED02BE13F4}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Event Handlers", "Event Handlers", "{9ADF1E48-2F5C-4ED7-A893-596259FABFE0}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Formats", "Formats", "{A5A27244-AD24-46E5-B01B-840CD296C91D}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docs", "Docs", "{CBD81696-EFB4-4D2F-8451-1B8DAA86155A}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Directories", "Directories", "{B8F5B47B-8568-46EB-B320-64C17D2A98BC}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Languages", "Languages", "{0C808854-54D1-4230-BFF5-77B5FD905000}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ASR-TTS", "ASR-TTS", "{4CF6A6AC-07DE-4B9E-ABE1-7F98B64E0BB0}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Loggers", "Loggers", "{A7AB4405-FDB7-4853-9FBB-1516B1C3D80A}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "XML Interfaces", "XML Interfaces", "{F69A4A6B-9360-4EBB-A280-22AA3C455AC5}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_Libraries", "_Libraries", "{EB910B0D-F27D-4B62-B67B-DE834C99AC5B}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_Downloads", "_Downloads", "{C120A020-773F-4EA3-923F-B67AF28B750D}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "say", "say", "{6CD61A1D-797C-470A-BE08-8C31B68BB336}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_Config", "_Config", "{57D119DC-484F-420F-B9E9-8589FD9A8DF8}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Default", "Default", "{3B08FEFD-4D3D-4C16-BA94-EE83509E32A0}"
+ ProjectSection(SolutionItems) = preProject
+ conf\vanilla\freeswitch.xml = conf\vanilla\freeswitch.xml
+ conf\vanilla\vars.xml = conf\vanilla\vars.xml
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_Build System", "_Build System", "{DB1024A8-41BF-4AD7-9AE6-13202230D1F3}"
+ ProjectSection(SolutionItems) = preProject
+ acsite.m4 = acsite.m4
+ bootstrap.sh = bootstrap.sh
+ build\buildlib.sh = build\buildlib.sh
+ configure.in = configure.in
+ Makefile.am = Makefile.am
+ build\modmake.rules.in = build\modmake.rules.in
+ build\modules.conf.in = build\modules.conf.in
+ libs\win32\util.vbs = libs\win32\util.vbs
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "m4", "m4", "{CDE9B06A-3C27-4987-8FAE-DF1006BC705D}"
+ ProjectSection(SolutionItems) = preProject
+ build\config\ac_cflags_gcc_option.m4 = build\config\ac_cflags_gcc_option.m4
+ build\config\ac_cflags_sun_option.m4 = build\config\ac_cflags_sun_option.m4
+ build\config\ac_gcc_archflag.m4 = build\config\ac_gcc_archflag.m4
+ build\config\ac_gcc_x86_cpuid.m4 = build\config\ac_gcc_x86_cpuid.m4
+ build\config\ac_prog_gzip.m4 = build\config\ac_prog_gzip.m4
+ build\config\ac_prog_wget.m4 = build\config\ac_prog_wget.m4
+ build\config\ax_cc_maxopt.m4 = build\config\ax_cc_maxopt.m4
+ build\config\ax_cflags_warn_all_ansi.m4 = build\config\ax_cflags_warn_all_ansi.m4
+ build\config\ax_check_compiler_flags.m4 = build\config\ax_check_compiler_flags.m4
+ build\config\ax_compiler_vendor.m4 = build\config\ax_compiler_vendor.m4
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "autoload_configs", "autoload_configs", "{3C90CCF0-2CDD-4A7A-ACFF-208C1E271692}"
+ ProjectSection(SolutionItems) = preProject
+ conf\vanilla\autoload_configs\alsa.conf.xml = conf\vanilla\autoload_configs\alsa.conf.xml
+ conf\vanilla\autoload_configs\conference.conf.xml = conf\vanilla\autoload_configs\conference.conf.xml
+ conf\vanilla\autoload_configs\console.conf.xml = conf\vanilla\autoload_configs\console.conf.xml
+ conf\vanilla\autoload_configs\dialplan_directory.conf.xml = conf\vanilla\autoload_configs\dialplan_directory.conf.xml
+ conf\vanilla\autoload_configs\dingaling.conf.xml = conf\vanilla\autoload_configs\dingaling.conf.xml
+ conf\vanilla\autoload_configs\enum.conf.xml = conf\vanilla\autoload_configs\enum.conf.xml
+ conf\vanilla\autoload_configs\event_multicast.conf.xml = conf\vanilla\autoload_configs\event_multicast.conf.xml
+ conf\vanilla\autoload_configs\event_socket.conf.xml = conf\vanilla\autoload_configs\event_socket.conf.xml
+ conf\vanilla\autoload_configs\ivr.conf.xml = conf\vanilla\autoload_configs\ivr.conf.xml
+ conf\vanilla\autoload_configs\java.conf.xml = conf\vanilla\autoload_configs\java.conf.xml
+ conf\vanilla\autoload_configs\limit.conf.xml = conf\vanilla\autoload_configs\limit.conf.xml
+ conf\vanilla\autoload_configs\local_stream.conf.xml = conf\vanilla\autoload_configs\local_stream.conf.xml
+ conf\vanilla\autoload_configs\logfile.conf.xml = conf\vanilla\autoload_configs\logfile.conf.xml
+ conf\vanilla\autoload_configs\modules.conf.xml = conf\vanilla\autoload_configs\modules.conf.xml
+ conf\vanilla\autoload_configs\openmrcp.conf.xml = conf\vanilla\autoload_configs\openmrcp.conf.xml
+ conf\vanilla\autoload_configs\portaudio.conf.xml = conf\vanilla\autoload_configs\portaudio.conf.xml
+ conf\vanilla\autoload_configs\rss.conf.xml = conf\vanilla\autoload_configs\rss.conf.xml
+ conf\vanilla\autoload_configs\sofia.conf.xml = conf\vanilla\autoload_configs\sofia.conf.xml
+ conf\vanilla\autoload_configs\spidermonkey.conf.xml = conf\vanilla\autoload_configs\spidermonkey.conf.xml
+ conf\vanilla\autoload_configs\switch.conf.xml = conf\vanilla\autoload_configs\switch.conf.xml
+ conf\vanilla\autoload_configs\syslog.conf.xml = conf\vanilla\autoload_configs\syslog.conf.xml
+ conf\vanilla\autoload_configs\voicemail.conf.xml = conf\vanilla\autoload_configs\voicemail.conf.xml
+ conf\vanilla\autoload_configs\wanpipe.conf.xml = conf\vanilla\autoload_configs\wanpipe.conf.xml
+ conf\vanilla\autoload_configs\woomera.conf.xml = conf\vanilla\autoload_configs\woomera.conf.xml
+ conf\vanilla\autoload_configs\xml_cdr.conf.xml = conf\vanilla\autoload_configs\xml_cdr.conf.xml
+ conf\vanilla\autoload_configs\xml_curl.conf.xml = conf\vanilla\autoload_configs\xml_curl.conf.xml
+ conf\vanilla\autoload_configs\xml_rpc.conf.xml = conf\vanilla\autoload_configs\xml_rpc.conf.xml
+ conf\vanilla\autoload_configs\zeroconf.conf.xml = conf\vanilla\autoload_configs\zeroconf.conf.xml
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dialplan", "dialplan", "{C7E2382E-2C22-4D18-BF93-80C6A1FFA7AC}"
+ ProjectSection(SolutionItems) = preProject
+ conf\vanilla\dialplan\default.xml = conf\vanilla\dialplan\default.xml
+ conf\vanilla\dialplan\public.xml = conf\vanilla\dialplan\public.xml
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "directory", "directory", "{FC71C66E-E268-4EAD-B1F5-F008DC382E83}"
+ ProjectSection(SolutionItems) = preProject
+ conf\vanilla\directory\default.xml = conf\vanilla\directory\default.xml
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "sip_profiles", "sip_profiles", "{8E2E8798-8B6F-4A55-8E4F-4E6FDE40ED26}"
+ ProjectSection(SolutionItems) = preProject
+ conf\vanilla\sip_profiles\external.xml = conf\vanilla\sip_profiles\external.xml
+ conf\vanilla\sip_profiles\internal.xml = conf\vanilla\sip_profiles\internal.xml
+ conf\vanilla\sip_profiles\nat.xml = conf\vanilla\sip_profiles\nat.xml
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "lang", "lang", "{09455AA9-C243-4F16-A1A1-A016881A2765}"
+ ProjectSection(SolutionItems) = preProject
+ conf\vanilla\directory\default.xml = conf\vanilla\directory\default.xml
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "en", "en", "{57199684-EC63-4A60-9DC6-11815AF6B413}"
+ ProjectSection(SolutionItems) = preProject
+ conf\vanilla\lang\en\en.xml = conf\vanilla\lang\en\en.xml
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "de", "de", "{2DED4BA2-D6B0-4064-BB2A-76DE3AA49E7C}"
+ ProjectSection(SolutionItems) = preProject
+ conf\vanilla\lang\de\de.xml = conf\vanilla\lang\de\de.xml
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "fr", "fr", "{D4A12E4C-DBDA-4614-BA26-3425AE9F60F5}"
+ ProjectSection(SolutionItems) = preProject
+ conf\vanilla\lang\fr\fr.xml = conf\vanilla\lang\fr\fr.xml
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "demo", "demo", "{D3E5C8ED-3A6A-4FEA-92A2-48A0BA865358}"
+ ProjectSection(SolutionItems) = preProject
+ conf\vanilla\lang\de\demo\demo.xml = conf\vanilla\lang\de\demo\demo.xml
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "vm", "vm", "{CC3E7F48-2590-49CB-AD8B-BE3650F55462}"
+ ProjectSection(SolutionItems) = preProject
+ conf\vanilla\lang\de\vm\tts.xml = conf\vanilla\lang\de\vm\tts.xml
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "demo", "demo", "{765EF1B9-5027-4820-BC37-A44466A51631}"
+ ProjectSection(SolutionItems) = preProject
+ conf\vanilla\lang\en\demo\demo.xml = conf\vanilla\lang\en\demo\demo.xml
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "vm", "vm", "{713E4747-1126-40B1-BD84-58F9A7745423}"
+ ProjectSection(SolutionItems) = preProject
+ conf\vanilla\lang\en\vm\sounds.xml = conf\vanilla\lang\en\vm\sounds.xml
+ conf\vanilla\lang\en\vm\tts.xml = conf\vanilla\lang\en\vm\tts.xml
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "demo", "demo", "{F1B71990-EB04-4EB5-B28A-BC3EB6F7E843}"
+ ProjectSection(SolutionItems) = preProject
+ conf\vanilla\lang\fr\demo\demo.xml = conf\vanilla\lang\fr\demo\demo.xml
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "vm", "vm", "{3DAF028C-AB5B-4183-A01B-DCC43F5A87F0}"
+ ProjectSection(SolutionItems) = preProject
+ conf\vanilla\lang\fr\vm\sounds.xml = conf\vanilla\lang\fr\vm\sounds.xml
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FreeSwitchConsole", "w32\Console\FreeSwitchConsole.2008.vcproj", "{1AF3A893-F7BE-43DD-B697-8AB2397C0D67}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FreeSwitchCoreLib", "w32\Library\FreeSwitchCore.2008.vcproj", "{202D7A4E-760D-4D0E-AFA1-D7459CED30FF}"
+ ProjectSection(ProjectDependencies) = postProject
+ {D331904D-A00A-4694-A5A3-FCFF64AB5DBE} = {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}
+ {8D04B550-D240-4A44-8A18-35DA3F7038D9} = {8D04B550-D240-4A44-8A18-35DA3F7038D9}
+ {89385C74-5860-4174-9CAF-A39E7C48909C} = {89385C74-5860-4174-9CAF-A39E7C48909C}
+ {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5} = {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}
+ {F057DA7F-79E5-4B00-845C-EF446EF055E3} = {F057DA7F-79E5-4B00-845C-EF446EF055E3}
+ {03207781-0D1C-4DB3-A71D-45C608F28DBD} = {03207781-0D1C-4DB3-A71D-45C608F28DBD}
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
+ {87EE9DA4-DE1E-4448-8324-183C98DCA588} = {87EE9DA4-DE1E-4448-8324-183C98DCA588}
+ {EEF031CB-FED8-451E-A471-91EC8D4F6750} = {EEF031CB-FED8-451E-A471-91EC8D4F6750}
+ {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3} = {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_g729", "src\mod\codecs\mod_g729\mod_g729.2008.vcproj", "{1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_sndfile", "src\mod\formats\mod_sndfile\mod_sndfile.2008.vcproj", "{AFAC0568-7548-42D5-9F6A-8D3400A1E4F6}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
+ {3D0370CA-BED2-4657-A475-32375CBCB6E4} = {3D0370CA-BED2-4657-A475-32375CBCB6E4}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_PortAudio", "src\mod\endpoints\mod_portaudio\mod_PortAudio.2008.vcproj", "{5FD31A25-5D83-4794-8BEE-904DAD84CE71}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ {0A18A071-125E-442F-AFF7-A3F68ABECF99} = {0A18A071-125E-442F-AFF7-A3F68ABECF99}
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_speex", "src\mod\codecs\mod_speex\mod_speex.2008.vcproj", "{5580D60E-0F77-4716-9CD4-B8E5986FA375}"
+ ProjectSection(ProjectDependencies) = postProject
+ {E972C52F-9E85-4D65-B19C-031E511E9DB4} = {E972C52F-9E85-4D65-B19C-031E511E9DB4}
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ {03207781-0D1C-4DB3-A71D-45C608F28DBD} = {03207781-0D1C-4DB3-A71D-45C608F28DBD}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "docs", "docs\docs.2008.vcproj", "{1A1FF289-4FD6-4285-A422-D31DD67A4723}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_dialplan_xml", "src\mod\dialplans\mod_dialplan_xml\mod_dialplan_xml.2008.vcproj", "{07113B25-D3AF-4E04-BA77-4CD1171F022C}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_ldap", "src\mod\directories\mod_ldap\mod_ldap.2008.vcproj", "{EC3E5C7F-EE09-47E2-80FE-546363D14A98}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_dialplan_directory", "src\mod\dialplans\mod_dialplan_directory\mod_dialplan_directory.2008.vcproj", "{A27CCA23-1541-4337-81A4-F0A6413078A0}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_event_multicast", "src\mod\event_handlers\mod_event_multicast\mod_event_multicast.2008.vcproj", "{784113EF-44D9-4949-835D-7065D3C7AD08}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libteletone", "libs\libteletone\libteletone.2008.vcproj", "{89385C74-5860-4174-9CAF-A39E7C48909C}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_spidermonkey", "src\mod\languages\mod_spidermonkey\mod_spidermonkey.2008.vcproj", "{1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
+ {87EE9DA4-DE1E-4448-8324-183C98DCA588} = {87EE9DA4-DE1E-4448-8324-183C98DCA588}
+ {204FA0DE-305D-4414-AE2E-F195A23F390D} = {204FA0DE-305D-4414-AE2E-F195A23F390D}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_cepstral", "src\mod\asr_tts\mod_cepstral\mod_cepstral.2008.vcproj", "{692F6330-4D87-4C82-81DF-40DB5892636E}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_ilbc", "src\mod\codecs\mod_ilbc\mod_ilbc.2008.vcproj", "{D3EC0AFF-76FC-4210-A825-9A17410660A3}"
+ ProjectSection(ProjectDependencies) = postProject
+ {9A5DDF08-C88C-4A35-B7F6-D605228446BD} = {9A5DDF08-C88C-4A35-B7F6-D605228446BD}
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_dingaling", "src\mod\endpoints\mod_dingaling\mod_dingaling.2008.vcproj", "{FFAA4C52-3A53-4F99-90C1-D59D1F0427F3}"
+ ProjectSection(ProjectDependencies) = postProject
+ {1906D736-08BD-4EE1-924F-B536249B9A54} = {1906D736-08BD-4EE1-924F-B536249B9A54}
+ {D331904D-A00A-4694-A5A3-FCFF64AB5DBE} = {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ {B4B62169-5AD4-4559-8707-3D933AC5DB39} = {B4B62169-5AD4-4559-8707-3D933AC5DB39}
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
+ {E727E8F6-935D-46FE-8B0E-37834748A0E3} = {E727E8F6-935D-46FE-8B0E-37834748A0E3}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_commands", "src\mod\applications\mod_commands\mod_commands.2008.vcproj", "{30A5B29C-983E-4580-9FD0-D647CCDCC7EB}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_console", "src\mod\loggers\mod_console\mod_console.2008.vcproj", "{1C453396-D912-4213-89FD-9B489162B7B5}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_xml_rpc", "src\mod\xml_int\mod_xml_rpc\mod_xml_rpc.2008.vcproj", "{CBEC7225-0C21-4DA8-978E-1F158F8AD950}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ {2390F054-A7F1-4CB9-ACB0-F46EC6E77B5B} = {2390F054-A7F1-4CB9-ACB0-F46EC6E77B5B}
+ {A4D67895-E709-40C7-82B6-DE1D12DDDE04} = {A4D67895-E709-40C7-82B6-DE1D12DDDE04}
+ {510BDAA8-C04D-47DB-8482-E6AF380D3E07} = {510BDAA8-C04D-47DB-8482-E6AF380D3E07}
+ {E5A9BCDA-B82D-4B08-B23E-9A782E367888} = {E5A9BCDA-B82D-4B08-B23E-9A782E367888}
+ {3CF7C0E0-07C2-473A-A1E4-2274AEEC1268} = {3CF7C0E0-07C2-473A-A1E4-2274AEEC1268}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_rss", "src\mod\applications\mod_rss\mod_rss.2008.vcproj", "{B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_conference", "src\mod\applications\mod_conference\mod_conference.2008.vcproj", "{C24FB505-05D7-4319-8485-7540B44C8603}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_dptools", "src\mod\applications\mod_dptools\mod_dptools.2008.vcproj", "{B5881A85-FE70-4F64-8607-2CAAE52669C6}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_event_socket", "src\mod\event_handlers\mod_event_socket\mod_event_socket.2008.vcproj", "{05515420-16DE-4E63-BE73-85BE85BA5142}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libdingaling", "libs\libdingaling\libdingaling.2008.vcproj", "{1906D736-08BD-4EE1-924F-B536249B9A54}"
+ ProjectSection(ProjectDependencies) = postProject
+ {F057DA7F-79E5-4B00-845C-EF446EF055E3} = {F057DA7F-79E5-4B00-845C-EF446EF055E3}
+ {E727E8F6-935D-46FE-8B0E-37834748A0E3} = {E727E8F6-935D-46FE-8B0E-37834748A0E3}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libsrtp", "libs\srtp\libsrtp.2008.vcproj", "{EEF031CB-FED8-451E-A471-91EC8D4F6750}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libsqlite", "libs\win32\sqlite\sqlite.2008.vcproj", "{6EDFEFD5-3596-4FA9-8EBA-B331547B35A3}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpcre", "libs\win32\pcre\libpcre.2008.vcproj", "{8D04B550-D240-4A44-8A18-35DA3F7038D9}"
+ ProjectSection(ProjectDependencies) = postProject
+ {1CED5987-A529-46DC-B30F-870D85FF9C94} = {1CED5987-A529-46DC-B30F-870D85FF9C94}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpcre Generate pcre_chartables.c", "libs\win32\pcre\pcre_chartables.c.2008.vcproj", "{1CED5987-A529-46DC-B30F-870D85FF9C94}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libapr", "libs\win32\apr\libapr.2008.vcproj", "{F6C55D93-B927-4483-BB69-15AEF3DD2DFF}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libaprutil", "libs\win32\apr-util\libaprutil.2008.vcproj", "{F057DA7F-79E5-4B00-845C-EF446EF055E3}"
+ ProjectSection(ProjectDependencies) = postProject
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
+ {155844C3-EC5F-407F-97A4-A2DDADED9B2F} = {155844C3-EC5F-407F-97A4-A2DDADED9B2F}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "iksemel", "libs\win32\iksemel\iksemel.2008.vcproj", "{E727E8F6-935D-46FE-8B0E-37834748A0E3}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libsndfile", "libs\win32\libsndfile\libsndfile.2008.vcproj", "{3D0370CA-BED2-4657-A475-32375CBCB6E4}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "curllib", "libs\win32\curl\curllib.2008.vcproj", "{87EE9DA4-DE1E-4448-8324-183C98DCA588}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xml", "libs\win32\apr-util\xml.2008.vcproj", "{155844C3-EC5F-407F-97A4-A2DDADED9B2F}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "js", "libs\win32\js\js.2008.vcproj", "{204FA0DE-305D-4414-AE2E-F195A23F390D}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_sofia", "src\mod\endpoints\mod_sofia\mod_sofia.2008.vcproj", "{0DF3ABD0-DDC0-4265-B778-07C66780979B}"
+ ProjectSection(ProjectDependencies) = postProject
+ {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4} = {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}
+ {D331904D-A00A-4694-A5A3-FCFF64AB5DBE} = {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ {B4B62169-5AD4-4559-8707-3D933AC5DB39} = {B4B62169-5AD4-4559-8707-3D933AC5DB39}
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
+ {70A49BC2-7500-41D0-B75D-EDCC5BE987A0} = {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libsofia_sip_ua_static", "libs\win32\sofia\libsofia_sip_ua_static.2008.vcproj", "{70A49BC2-7500-41D0-B75D-EDCC5BE987A0}"
+ ProjectSection(ProjectDependencies) = postProject
+ {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4} = {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}
+ {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A} = {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}
+ {D331904D-A00A-4694-A5A3-FCFF64AB5DBE} = {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}
+ {B4B62169-5AD4-4559-8707-3D933AC5DB39} = {B4B62169-5AD4-4559-8707-3D933AC5DB39}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download PTHREAD", "libs\win32\Download PTHREAD.2008.vcproj", "{8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pthread", "libs\win32\pthread\pthread.2008.vcproj", "{DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}"
+ ProjectSection(ProjectDependencies) = postProject
+ {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A} = {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_g723_1", "src\mod\codecs\mod_g723_1\mod_g723_1.2008.vcproj", "{FEA1EEF7-876F-48DE-88BF-C0E3E606D758}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_native_file", "src\mod\formats\mod_native_file\mod_native_file.2008.vcproj", "{9254C4B0-6F60-42B6-BB3A-36D63FC001C7}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_spidermonkey_core_db", "src\mod\languages\mod_spidermonkey\mod_spidermonkey_core_db.2008.vcproj", "{ACFFF684-4D19-4D48-AF12-88EA1D778BDF}"
+ ProjectSection(ProjectDependencies) = postProject
+ {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F} = {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
+ {204FA0DE-305D-4414-AE2E-F195A23F390D} = {204FA0DE-305D-4414-AE2E-F195A23F390D}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_spidermonkey_teletone", "src\mod\languages\mod_spidermonkey\mod_spidermonkey_teletone.2008.vcproj", "{8F992C49-6C51-412F-B2A3-34EAB708EB65}"
+ ProjectSection(ProjectDependencies) = postProject
+ {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F} = {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ {89385C74-5860-4174-9CAF-A39E7C48909C} = {89385C74-5860-4174-9CAF-A39E7C48909C}
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
+ {204FA0DE-305D-4414-AE2E-F195A23F390D} = {204FA0DE-305D-4414-AE2E-F195A23F390D}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_enum", "src\mod\applications\mod_enum\mod_enum.2008.vcproj", "{71A967D5-0E99-4CEF-A587-98836EE6F2EF}"
+ ProjectSection(ProjectDependencies) = postProject
+ {23B4D303-79FC-49E0-89E2-2280E7E28940} = {23B4D303-79FC-49E0-89E2-2280E7E28940}
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_spidermonkey_odbc", "src\mod\languages\mod_spidermonkey\mod_spidermonkey_odbc.2008.vcproj", "{0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}"
+ ProjectSection(ProjectDependencies) = postProject
+ {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F} = {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
+ {204FA0DE-305D-4414-AE2E-F195A23F390D} = {204FA0DE-305D-4414-AE2E-F195A23F390D}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_xml_curl", "src\mod\xml_int\mod_xml_curl\mod_xml_curl.2008.vcproj", "{AB91A099-7690-4ECF-8994-E458F4EA1ED4}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ {87EE9DA4-DE1E-4448-8324-183C98DCA588} = {87EE9DA4-DE1E-4448-8324-183C98DCA588}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_say_en", "src\mod\say\mod_say_en\mod_say_en.2008.vcproj", "{988CACF7-3FCB-4992-BE69-77872AE67DC8}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "portaudio", "libs\portaudio\build\msvc\portaudio.2008.vcproj", "{0A18A071-125E-442F-AFF7-A3F68ABECF99}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_xml_cdr", "src\mod\xml_int\mod_xml_cdr\mod_xml_cdr.2008.vcproj", "{08DAD348-9E0A-4A2E-97F1-F1E7E24A7836}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
+ {87EE9DA4-DE1E-4448-8324-183C98DCA588} = {87EE9DA4-DE1E-4448-8324-183C98DCA588}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_amr", "src\mod\codecs\mod_amr\mod_amr.2008.vcproj", "{8DEB383C-4091-4F42-A56F-C9E46D552D79}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_h26x", "src\mod\codecs\mod_h26x\mod_h26x.2008.vcproj", "{2C3C2423-234B-4772-8899-D3B137E5CA35}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_esf", "src\mod\applications\mod_esf\mod_esf.2008.vcproj", "{3850D93A-5F24-4922-BC1C-74D08C37C256}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_local_stream", "src\mod\formats\mod_local_stream\mod_local_stream.2008.vcproj", "{2CA40887-1622-46A1-A7F9-17FD7E7E545B}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_spidermonkey_socket", "src\mod\languages\mod_spidermonkey\mod_spidermonkey_socket.2008.vcproj", "{028C7278-05D7-4E18-82FE-BE231B844F41}"
+ ProjectSection(ProjectDependencies) = postProject
+ {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F} = {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ {204FA0DE-305D-4414-AE2E-F195A23F390D} = {204FA0DE-305D-4414-AE2E-F195A23F390D}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_voicemail", "src\mod\applications\mod_voicemail\mod_voicemail.2008.vcproj", "{D7F1E3F2-A3F4-474C-8555-15122571AF52}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_say_de", "src\mod\say\mod_say_de\mod_say_de.2008.vcproj", "{5BC072DB-3826-48EA-AF34-FE32AA01E83B}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_say_es", "src\mod\say\mod_say_es\mod_say_es.2008.vcproj", "{FA429E98-8B03-45E6-A096-A4BC5E821DE4}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_say_fr", "src\mod\say\mod_say_fr\mod_say_fr.2008.vcproj", "{06E3A538-AB32-44F2-B477-755FF9CB5D37}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_say_it", "src\mod\say\mod_say_it\mod_say_it.2008.vcproj", "{6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_say_nl", "src\mod\say\mod_say_nl\mod_say_nl.2008.vcproj", "{A4B122CF-5196-476B-8C0E-D8BD59AC3C14}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_fifo", "src\mod\applications\mod_fifo\mod_fifo.2008.vcproj", "{75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_db", "src\mod\applications\mod_db\mod_db.2008.vcproj", "{F6A33240-8F29-48BD-98F0-826995911799}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_expr", "src\mod\applications\mod_expr\mod_expr.2008.vcproj", "{65A6273D-FCAB-4C55-B09E-65100141A5D4}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_dialplan_asterisk", "src\mod\dialplans\mod_dialplan_asterisk\mod_dialplan_asterisk.2008.vcproj", "{E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_logfile", "src\mod\loggers\mod_logfile\mod_logfile.2008.vcproj", "{D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_cdr_csv", "src\mod\event_handlers\mod_cdr_csv\mod_cdr_csv.2008.vcproj", "{44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_tone_stream", "src\mod\formats\mod_tone_stream\mod_tone_stream.2008.vcproj", "{6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ {89385C74-5860-4174-9CAF-A39E7C48909C} = {89385C74-5860-4174-9CAF-A39E7C48909C}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_fsv", "src\mod\applications\mod_fsv\mod_fsv.2008.vcproj", "{E3246D17-E29B-4AB5-962A-C69B0C5837BB}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_spidermonkey_curl", "src\mod\languages\mod_spidermonkey\mod_spidermonkey_curl.2008.vcproj", "{36E854E3-CE12-4348-A125-CCF3F9D74813}"
+ ProjectSection(ProjectDependencies) = postProject
+ {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F} = {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ {87EE9DA4-DE1E-4448-8324-183C98DCA588} = {87EE9DA4-DE1E-4448-8324-183C98DCA588}
+ {204FA0DE-305D-4414-AE2E-F195A23F390D} = {204FA0DE-305D-4414-AE2E-F195A23F390D}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_lua", "src\mod\languages\mod_lua\mod_lua.2008.vcproj", "{7B077E7F-1BE7-4291-AB86-55E527B25CAC}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ {D0B36172-CD76-454A-9B89-990025266C2A} = {D0B36172-CD76-454A-9B89-990025266C2A}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download sphinxbase", "libs\win32\Download sphinxbase.2008.vcproj", "{4F92B672-DADB-4047-8D6A-4BB3796733FD}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download sphinxmodel", "libs\win32\Download sphinxmodel.2008.vcproj", "{2DEE4895-1134-439C-B688-52203E57D878}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download pocketsphinx", "libs\win32\Download pocketsphinx.2008.vcproj", "{AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sphinxbase", "libs\win32\sphinxbase\sphinxbase.2008.vcproj", "{2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}"
+ ProjectSection(ProjectDependencies) = postProject
+ {4F92B672-DADB-4047-8D6A-4BB3796733FD} = {4F92B672-DADB-4047-8D6A-4BB3796733FD}
+ {2DEE4895-1134-439C-B688-52203E57D878} = {2DEE4895-1134-439C-B688-52203E57D878}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pocketsphinx", "libs\win32\pocketsphinx\pocketsphinx.2008.vcproj", "{94001A0E-A837-445C-8004-F918F10D0226}"
+ ProjectSection(ProjectDependencies) = postProject
+ {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D} = {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}
+ {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E} = {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_pocketsphinx", "src\mod\asr_tts\mod_pocketsphinx\mod_pocketsphinx.2008.vcproj", "{2286DA73-9FC5-45BC-A508-85994C3317AB}"
+ ProjectSection(ProjectDependencies) = postProject
+ {94001A0E-A837-445C-8004-F918F10D0226} = {94001A0E-A837-445C-8004-F918F10D0226}
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ {4F92B672-DADB-4047-8D6A-4BB3796733FD} = {4F92B672-DADB-4047-8D6A-4BB3796733FD}
+ {2DEE4895-1134-439C-B688-52203E57D878} = {2DEE4895-1134-439C-B688-52203E57D878}
+ {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D} = {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}
+ {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E} = {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download 8khzsound", "libs\win32\Download 8khz Sounds.2008.vcproj", "{3CE1DC99-8246-4DB1-A709-74F19F08EC67}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sound Files", "Sound Files", "{4F227C26-768F-46A3-8684-1D08A46FB374}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download 16khzsound", "libs\win32\Download 16khz Sounds.2008.vcproj", "{87A1FE3D-F410-4C8E-9591-8C625985BC70}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "8khz", "libs\win32\Sound_Files\8khz.2008.vcproj", "{7A8D8174-B355-4114-AFC1-04777CB9DE0A}"
+ ProjectSection(ProjectDependencies) = postProject
+ {3CE1DC99-8246-4DB1-A709-74F19F08EC67} = {3CE1DC99-8246-4DB1-A709-74F19F08EC67}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "16khz", "libs\win32\Sound_Files\16khz.2008.vcproj", "{7EB71250-F002-4ED8-92CA-CA218114537A}"
+ ProjectSection(ProjectDependencies) = postProject
+ {87A1FE3D-F410-4C8E-9591-8C625985BC70} = {87A1FE3D-F410-4C8E-9591-8C625985BC70}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download 32khzsound", "libs\win32\Download 32khz Sounds.2008.vcproj", "{6E49F6C2-ADDA-4BFB-81FE-AB9AF51B455F}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "32khz", "libs\win32\Sound_Files\32khz.2008.vcproj", "{464AAB78-5489-4916-BE51-BF8D61822311}"
+ ProjectSection(ProjectDependencies) = postProject
+ {6E49F6C2-ADDA-4BFB-81FE-AB9AF51B455F} = {6E49F6C2-ADDA-4BFB-81FE-AB9AF51B455F}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "flite", "libs\win32\flite\flite.2008.vcproj", "{0AD1177E-1FD8-4643-9391-431467A11084}"
+ ProjectSection(ProjectDependencies) = postProject
+ {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B} = {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_flite", "src\mod\asr_tts\mod_flite\mod_flite.2008.vcproj", "{66444AEE-554C-11DD-A9F0-8C5D56D89593}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B} = {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}
+ {0AD1177E-1FD8-4643-9391-431467A11084} = {0AD1177E-1FD8-4643-9391-431467A11084}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download FLITE", "libs\win32\Download FLITE.2008.vcproj", "{D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download LAME", "libs\win32\Download LAME.2008.vcproj", "{D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download LIBSHOUT", "libs\win32\Download LIBSHOUT.2008.vcproj", "{D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download OGG", "libs\win32\Download OGG.2008.vcproj", "{D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmp3lame", "libs\win32\libmp3lame\libmp3lame_vc7.vcproj", "{E316772F-5D8F-4F2A-8F71-094C3E859D34}"
+ ProjectSection(ProjectDependencies) = postProject
+ {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B} = {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libshout", "libs\win32\libshout\libshout.vcproj", "{D3D8B329-20BE-475E-9E83-653CEA0E0EF5}"
+ ProjectSection(ProjectDependencies) = postProject
+ {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B} = {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}
+ {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4} = {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_shout", "src\mod\formats\mod_shout\mod_shout.vcproj", "{38FE0559-9910-43A8-9E45-3E5004C27692}"
+ ProjectSection(ProjectDependencies) = postProject
+ {D3D8B329-20BE-475E-9E83-653CEA0E0EF5} = {D3D8B329-20BE-475E-9E83-653CEA0E0EF5}
+ {E316772F-5D8F-4F2A-8F71-094C3E859D34} = {E316772F-5D8F-4F2A-8F71-094C3E859D34}
+ {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4} = {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ {419C8F80-D858-4B48-A25C-AF4007608137} = {419C8F80-D858-4B48-A25C-AF4007608137}
+ {87EE9DA4-DE1E-4448-8324-183C98DCA588} = {87EE9DA4-DE1E-4448-8324-183C98DCA588}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libogg", "libs\win32\libogg\libogg.2008.vcproj", "{0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4}"
+ ProjectSection(ProjectDependencies) = postProject
+ {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B} = {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_snom", "src\mod\applications\mod_snom\mod_snom.2008.vcproj", "{2A3D00C6-588D-4E86-81AC-9EF5EDE86E03}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_say_zh", "src\mod\say\mod_say_zh\mod_say_zh.2008.vcproj", "{B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_managed", "src\mod\languages\mod_managed\mod_managed.vcproj", "{7B42BDA1-72C0-4378-A9B6-5C530F8CD61E}"
+ ProjectSection(ProjectDependencies) = postProject
+ {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0} = {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FreeSWITCH.Managed", "src\mod\languages\mod_managed\managed\FreeSWITCH.Managed.csproj", "{834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download mpg123", "libs\win32\Download mpg123.2008.vcproj", "{E796E337-DE78-4303-8614-9A590862EE95}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmpg123", "libs\win32\mpg123\libmpg123.2008.vcproj", "{419C8F80-D858-4B48-A25C-AF4007608137}"
+ ProjectSection(ProjectDependencies) = postProject
+ {E796E337-DE78-4303-8614-9A590862EE95} = {E796E337-DE78-4303-8614-9A590862EE95}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_loopback", "src\mod\endpoints\mod_loopback\mod_loopback.2008.vcproj", "{B3F424EC-3D8F-417C-B244-3919D5E1A577}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_vmd", "src\mod\applications\mod_vmd\mod_vmd.2008.vcproj", "{14E4A972-9CFB-436D-B0A5-4943F3F80D47}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libg722_1", "libs\win32\libg722_1\libg722_1.vcproj", "{1BC8A8EC-E03B-44DF-BCD9-088650F4D29C}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_siren", "src\mod\codecs\mod_siren\mod_siren.2008.vcproj", "{0B6C905B-142E-4999-B39D-92FF7951E921}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C} = {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "esl", "libs\esl\src\esl.2008.vcproj", "{CF405366-9558-4AE8-90EF-5E21B51CCB4E}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fs_cli", "libs\esl\fs_cli.2008.vcproj", "{D2FB8043-D208-4AEE-8F18-3B5857C871B9}"
+ ProjectSection(ProjectDependencies) = postProject
+ {CF405366-9558-4AE8-90EF-5E21B51CCB4E} = {CF405366-9558-4AE8-90EF-5E21B51CCB4E}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_easyroute", "src\mod\applications\mod_easyroute\mod_easyroute.2008.vcproj", "{329FD5B0-EF28-4606-86D0-F6EA21CF8E36}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_lcr", "src\mod\applications\mod_lcr\mod_lcr.2008.vcproj", "{1A3793D1-05D1-4B57-9B0F-5AF3E79DC439}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libtiff", "libs\spandsp\src\libtiff.2008.vcproj", "{401A40CD-5DB4-4E34-AC68-FA99E9FAC014}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libspandsp", "libs\spandsp\src\libspandsp.2008.vcproj", "{1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}"
+ ProjectSection(ProjectDependencies) = postProject
+ {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A} = {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}
+ {329A6FA0-0FCC-4435-A950-E670AEFA9838} = {329A6FA0-0FCC-4435-A950-E670AEFA9838}
+ {DEE932AB-5911-4700-9EEB-8C7090A0A330} = {DEE932AB-5911-4700-9EEB-8C7090A0A330}
+ {401A40CD-5DB4-4E34-AC68-FA99E9FAC014} = {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libspeex", "libs\speex\win32\VS2008\libspeex\libspeex.vcproj", "{E972C52F-9E85-4D65-B19C-031E511E9DB4}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libspeexdsp", "libs\speex\win32\VS2008\libspeexdsp\libspeexdsp.vcproj", "{03207781-0D1C-4DB3-A71D-45C608F28DBD}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libilbc", "libs\ilbc\libilbc.2008.vcproj", "{9A5DDF08-C88C-4A35-B7F6-D605228446BD}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lua51", "src\mod\languages\mod_lua\lua\lua.2008.vcproj", "{D0B36172-CD76-454A-9B89-990025266C2A}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_opal", "src\mod\endpoints\mod_opal\mod_opal_2008.vcproj", "{05C9FB27-480E-4D53-B3B7-6338E2526666}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_h323", "src\mod\endpoints\mod_h323\mod_h323_2008.vcproj", "{05C9FB27-480E-4D53-B3B7-7338E2514666}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_iSAC", "src\mod\codecs\mod_isac\mod_iSAC.2008.vcproj", "{7F1610F1-DD5A-4CF7-8610-30AB12C60ADD}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_skinny", "src\mod\endpoints\mod_skinny\mod_skinny_2008.vcproj", "{CC1DD008-9406-448D-A0AD-33C3186CFADB}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_rtmp", "src\mod\endpoints\mod_rtmp\mod_rtmp_2008.vcproj", "{48414740-C693-4968-9846-EE058020C64F}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "make_at_dictionary", "libs\spandsp\src\msvc\make_at_dictionary.2008.vcproj", "{DEE932AB-5911-4700-9EEB-8C7090A0A330}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "make_modem_filter", "libs\spandsp\src\msvc\make_modem_filter.2008.vcproj", "{329A6FA0-0FCC-4435-A950-E670AEFA9838}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_skel", "src\mod\applications\mod_skel\mod_skel.2008.vcproj", "{11C9BC3D-45E9-46E3-BE84-B8CEE4685E39}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_skypopen", "src\mod\endpoints\mod_skypopen\mod_skypopen.2008.vcproj", "{C6E78A4C-DB1E-47F4-9B63-4DC27D86343F}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download 32khz music", "libs\win32\Download 32khz music.2008.vcproj", "{1F0A8A77-E661-418F-BB92-82172AE43803}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download 8khz music", "libs\win32\Download 8khz music.2008.vcproj", "{4F5C9D55-98EF-4256-8311-32D7BD360406}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download 16khz music", "libs\win32\Download 16khz music.2008.vcproj", "{E10571C4-E7F4-4608-B5F2-B22E7EB95400}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "8khz music", "libs\win32\Sound_Files\8khzmusic.2008.vcproj", "{D1ABE208-6442-4FB4-9AAD-1677E41BC870}"
+ ProjectSection(ProjectDependencies) = postProject
+ {4F5C9D55-98EF-4256-8311-32D7BD360406} = {4F5C9D55-98EF-4256-8311-32D7BD360406}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "16khz music", "libs\win32\Sound_Files\16khzmusic.2008.vcproj", "{BA599D0A-4310-4505-91DA-6A6447B3E289}"
+ ProjectSection(ProjectDependencies) = postProject
+ {E10571C4-E7F4-4608-B5F2-B22E7EB95400} = {E10571C4-E7F4-4608-B5F2-B22E7EB95400}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "32khz music", "libs\win32\Sound_Files\32khzmusic.2008.vcproj", "{EED13FC7-4F81-4E6F-93DB-CDB7DF5CF959}"
+ ProjectSection(ProjectDependencies) = postProject
+ {1F0A8A77-E661-418F-BB92-82172AE43803} = {1F0A8A77-E661-418F-BB92-82172AE43803}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_nibblebill", "src\mod\applications\mod_nibblebill\mod_nibblebill.2008.vcproj", "{3C977801-FE88-48F2-83D3-FA2EBFF6688E}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_say_ru", "src\mod\say\mod_say_ru\mod_say_ru.2008.vcproj", "{0382E8FD-CFDC-41C0-8B03-792C7C84FC31}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_valet_parking", "src\mod\applications\mod_valet_parking\mod_valet_parking.2008.vcproj", "{432DB165-1EB2-4781-A9C0-71E62610B20A}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libbroadvoice", "libs\broadvoice\src\libbroadvoice.2008.vcproj", "{CF70F278-3364-4395-A2E1-23501C9B8AD2}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_bv", "src\mod\codecs\mod_bv\mod_bv.2008.vcproj", "{D5C87B19-150D-4EF3-A671-96589BD2D14A}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ {CF70F278-3364-4395-A2E1-23501C9B8AD2} = {CF70F278-3364-4395-A2E1-23501C9B8AD2}
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "unimrcp", "unimrcp", "{62F27B1A-C919-4A70-8478-51F178F3B18F}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "aprtoolkit", "libs\unimrcp\libs\apr-toolkit\aprtoolkit.2008.vcproj", "{13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}"
+ ProjectSection(ProjectDependencies) = postProject
+ {F057DA7F-79E5-4B00-845C-EF446EF055E3} = {F057DA7F-79E5-4B00-845C-EF446EF055E3}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mpf", "libs\unimrcp\libs\mpf\mpf.2008.vcproj", "{B5A00BFA-6083-4FAE-A097-71642D6473B5}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mrcp", "libs\unimrcp\libs\mrcp\mrcp.2008.vcproj", "{1C320193-46A6-4B34-9C56-8AB584FC1B56}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mrcpclient", "libs\unimrcp\libs\mrcp-client\mrcpclient.2008.vcproj", "{72782932-37CC-46AE-8C7F-9A7B1A6EE108}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mrcpsignaling", "libs\unimrcp\libs\mrcp-signaling\mrcpsignaling.2008.vcproj", "{12A49562-BAB9-43A3-A21D-15B60BBB4C31}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mrcpv2transport", "libs\unimrcp\libs\mrcpv2-transport\mrcpv2transport.2008.vcproj", "{A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unirtsp", "libs\unimrcp\libs\uni-rtsp\unirtsp.2008.vcproj", "{504B3154-7A4F-459D-9877-B951021C3F1F}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mrcpsofiasip", "libs\unimrcp\modules\mrcp-sofiasip\mrcpsofiasip.2008.vcproj", "{746F3632-5BB2-4570-9453-31D6D58A7D8E}"
+ ProjectSection(ProjectDependencies) = postProject
+ {70A49BC2-7500-41D0-B75D-EDCC5BE987A0} = {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mrcpunirtsp", "libs\unimrcp\modules\mrcp-unirtsp\mrcpunirtsp.2008.vcproj", "{DEB01ACB-D65F-4A62-AED9-58C1054499E9}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_unimrcp", "src\mod\asr_tts\mod_unimrcp\mod_unimrcp.2008.vcproj", "{D07C378A-F5F7-438F-ADF3-4AC4FB1883CD}"
+ ProjectSection(ProjectDependencies) = postProject
+ {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA} = {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}
+ {72782932-37CC-46AE-8C7F-9A7B1A6EE108} = {72782932-37CC-46AE-8C7F-9A7B1A6EE108}
+ {746F3632-5BB2-4570-9453-31D6D58A7D8E} = {746F3632-5BB2-4570-9453-31D6D58A7D8E}
+ {D331904D-A00A-4694-A5A3-FCFF64AB5DBE} = {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ {504B3154-7A4F-459D-9877-B951021C3F1F} = {504B3154-7A4F-459D-9877-B951021C3F1F}
+ {12A49562-BAB9-43A3-A21D-15B60BBB4C31} = {12A49562-BAB9-43A3-A21D-15B60BBB4C31}
+ {B4B62169-5AD4-4559-8707-3D933AC5DB39} = {B4B62169-5AD4-4559-8707-3D933AC5DB39}
+ {F057DA7F-79E5-4B00-845C-EF446EF055E3} = {F057DA7F-79E5-4B00-845C-EF446EF055E3}
+ {1C320193-46A6-4B34-9C56-8AB584FC1B56} = {1C320193-46A6-4B34-9C56-8AB584FC1B56}
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
+ {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2} = {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}
+ {70A49BC2-7500-41D0-B75D-EDCC5BE987A0} = {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}
+ {DEB01ACB-D65F-4A62-AED9-58C1054499E9} = {DEB01ACB-D65F-4A62-AED9-58C1054499E9}
+ {B5A00BFA-6083-4FAE-A097-71642D6473B5} = {B5A00BFA-6083-4FAE-A097-71642D6473B5}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download CELT", "libs\win32\Download CELT.vcproj", "{FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcelt", "libs\win32\celt\libcelt.vcproj", "{ABB71A76-42B0-47A4-973A-42E3D920C6FD}"
+ ProjectSection(ProjectDependencies) = postProject
+ {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19} = {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_celt", "src\mod\codecs\mod_celt\mod_celt.vcproj", "{4D418176-3B33-47E6-A63E-01BA34ADD21C}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ {ABB71A76-42B0-47A4-973A-42E3D920C6FD} = {ABB71A76-42B0-47A4-973A-42E3D920C6FD}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FSComm", "fscomm\FSComm.2008.vcproj", "{7D3122C7-C9D0-3748-81F8-F0DDCB40BF5E}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_curl", "src\mod\applications\mod_curl\mod_curl.2008.vcproj", "{EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ {87EE9DA4-DE1E-4448-8324-183C98DCA588} = {87EE9DA4-DE1E-4448-8324-183C98DCA588}
+ {9778F1C0-09BC-4698-8EBC-BD982247209A} = {9778F1C0-09BC-4698-8EBC-BD982247209A}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download JSON", "libs\win32\Download JSON.2008.vcproj", "{B808178B-82F0-4CF4-A2B1-921939FA24D0}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libjson", "libs\win32\json\libjson.2008.vcproj", "{9778F1C0-09BC-4698-8EBC-BD982247209A}"
+ ProjectSection(ProjectDependencies) = postProject
+ {B808178B-82F0-4CF4-A2B1-921939FA24D0} = {B808178B-82F0-4CF4-A2B1-921939FA24D0}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_silk", "src\mod\codecs\mod_silk\mod_silk.2008.vcproj", "{AFA983D6-4569-4F88-BA94-555ED00FD9A8}"
+ ProjectSection(ProjectDependencies) = postProject
+ {56B91D01-9150-4BBF-AFA1-5B68AB991B76} = {56B91D01-9150-4BBF-AFA1-5B68AB991B76}
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Silk_FIX", "libs\silk\src\Silk_FIX.2008.vcproj", "{56B91D01-9150-4BBF-AFA1-5B68AB991B76}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_avmd", "src\mod\applications\mod_avmd\mod_avmd.2008.vcproj", "{990BAA76-89D3-4E38-8479-C7B28784EFC8}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_spandsp", "src\mod\applications\mod_spandsp\mod_spandsp.2008.vcproj", "{1E21AFE0-6FDB-41D2-942D-863607C24B91}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5} = {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_hash", "src\mod\applications\mod_hash\mod_hash.2008.vcproj", "{2E250296-0C08-4342-9C8A-BCBDD0E7DF65}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ {CF405366-9558-4AE8-90EF-5E21B51CCB4E} = {CF405366-9558-4AE8-90EF-5E21B51CCB4E}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download OPENSSL", "libs\win32\Download OPENSSL.2008.vcproj", "{D578E676-7EC8-4548-BD8B-845C635F14AD}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "openssl", "openssl", "{B376D494-D7DD-4B2A-99E2-52916D5A8CD8}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libeay32", "libs\win32\openssl\libeay32.2008.vcproj", "{D331904D-A00A-4694-A5A3-FCFF64AB5DBE}"
+ ProjectSection(ProjectDependencies) = postProject
+ {D578E676-7EC8-4548-BD8B-845C635F14AD} = {D578E676-7EC8-4548-BD8B-845C635F14AD}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ssleay32", "libs\win32\openssl\ssleay32.2008.vcproj", "{B4B62169-5AD4-4559-8707-3D933AC5DB39}"
+ ProjectSection(ProjectDependencies) = postProject
+ {D331904D-A00A-4694-A5A3-FCFF64AB5DBE} = {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openssl", "libs\win32\openssl\openssl.2008.vcproj", "{25BD39B1-C8BF-4676-A738-9CABD9C6BC79}"
+ ProjectSection(ProjectDependencies) = postProject
+ {D331904D-A00A-4694-A5A3-FCFF64AB5DBE} = {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}
+ {B4B62169-5AD4-4559-8707-3D933AC5DB39} = {B4B62169-5AD4-4559-8707-3D933AC5DB39}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_directory", "src\mod\applications\mod_directory\mod_directory.2008.vcproj", "{42E721FD-43D6-4B04-A34B-42567199FFB8}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ldns", "libs\win32\ldns\ldns-lib\ldns-lib.2008.vcproj", "{23B4D303-79FC-49E0-89E2-2280E7E28940}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_httapi", "src\mod\applications\mod_httapi\mod_httapi.2008.vcproj", "{0807C5CB-F6FF-451D-89F0-1F7B2E1D9169}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_abstraction", "src\mod\applications\mod_abstraction\mod_abstraction.2008.vcproj", "{BDA173DB-F8EF-4270-9553-B453AF92E43A}"
+ ProjectSection(ProjectDependencies) = postProject
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_gsmopen", "src\mod\endpoints\mod_gsmopen\mod_gsmopen.2008.vcproj", "{74B120FF-6935-4DFE-A142-CDB6BEA99C90}"
+ ProjectSection(ProjectDependencies) = postProject
+ {26C82FCE-E0CF-4D10-A00C-D8E582FFEB53} = {26C82FCE-E0CF-4D10-A00C-D8E582FFEB53}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gsmlib", "src\mod\endpoints\mod_gsmopen\gsmlib\gsmlib-1.10-patched-13ubuntu\win32\gsmlib.vcproj", "{26C82FCE-E0CF-4D10-A00C-D8E582FFEB53}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libjpeg", "libs\win32\libjpeg\libjpeg.2008.vcproj", "{FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}"
+ ProjectSection(ProjectDependencies) = postProject
+ {21A7DA70-555E-49FA-942B-D84A38B61243} = {21A7DA70-555E-49FA-942B-D84A38B61243}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download libjpeg", "libs\win32\Download libjpeg.2008.vcproj", "{21A7DA70-555E-49FA-942B-D84A38B61243}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "xmlrpc-c", "xmlrpc-c", "{3783935D-7C0A-4166-A376-C3D8E64F3A9C}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "abyss", "libs\win32\xmlrpc-c\abyss.2008.vcproj", "{A4D67895-E709-40C7-82B6-DE1D12DDDE04}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gennmtab", "libs\win32\xmlrpc-c\gennmtab.2008.vcproj", "{2390F054-A7F1-4CB9-ACB0-F46EC6E77B5B}"
+ ProjectSection(ProjectDependencies) = postProject
+ {E5A9BCDA-B82D-4B08-B23E-9A782E367888} = {E5A9BCDA-B82D-4B08-B23E-9A782E367888}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xmlparse", "libs\win32\xmlrpc-c\xmlparse.2008.vcproj", "{E5A9BCDA-B82D-4B08-B23E-9A782E367888}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xmlrpc", "libs\win32\xmlrpc-c\xmlrpc.2008.vcproj", "{510BDAA8-C04D-47DB-8482-E6AF380D3E07}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xmltok", "libs\win32\xmlrpc-c\xmltok.2008.vcproj", "{3CF7C0E0-07C2-473A-A1E4-2274AEEC1268}"
+ ProjectSection(ProjectDependencies) = postProject
+ {2390F054-A7F1-4CB9-ACB0-F46EC6E77B5B} = {2390F054-A7F1-4CB9-ACB0-F46EC6E77B5B}
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ All|Win32 = All|Win32
+ All|x64 = All|x64
+ Debug|Win32 = Debug|Win32
+ Debug|x64 = Debug|x64
+ Release|Win32 = Release|Win32
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {1AF3A893-F7BE-43DD-B697-8AB2397C0D67}.All|Win32.ActiveCfg = Release|x64
+ {1AF3A893-F7BE-43DD-B697-8AB2397C0D67}.All|x64.ActiveCfg = Release|x64
+ {1AF3A893-F7BE-43DD-B697-8AB2397C0D67}.All|x64.Build.0 = Release|x64
+ {1AF3A893-F7BE-43DD-B697-8AB2397C0D67}.Debug|Win32.ActiveCfg = Debug|Win32
+ {1AF3A893-F7BE-43DD-B697-8AB2397C0D67}.Debug|Win32.Build.0 = Debug|Win32
+ {1AF3A893-F7BE-43DD-B697-8AB2397C0D67}.Debug|x64.ActiveCfg = Debug|x64
+ {1AF3A893-F7BE-43DD-B697-8AB2397C0D67}.Debug|x64.Build.0 = Debug|x64
+ {1AF3A893-F7BE-43DD-B697-8AB2397C0D67}.Release|Win32.ActiveCfg = Release|Win32
+ {1AF3A893-F7BE-43DD-B697-8AB2397C0D67}.Release|Win32.Build.0 = Release|Win32
+ {1AF3A893-F7BE-43DD-B697-8AB2397C0D67}.Release|x64.ActiveCfg = Release|x64
+ {1AF3A893-F7BE-43DD-B697-8AB2397C0D67}.Release|x64.Build.0 = Release|x64
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}.All|Win32.ActiveCfg = Release|x64
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}.All|x64.ActiveCfg = Release|x64
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}.All|x64.Build.0 = Release|x64
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}.Debug|Win32.ActiveCfg = Debug|Win32
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}.Debug|Win32.Build.0 = Debug|Win32
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}.Debug|x64.ActiveCfg = Debug|x64
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}.Debug|x64.Build.0 = Debug|x64
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}.Release|Win32.ActiveCfg = Release|Win32
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}.Release|Win32.Build.0 = Release|Win32
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}.Release|x64.ActiveCfg = Release|x64
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}.Release|x64.Build.0 = Release|x64
+ {1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0}.All|Win32.ActiveCfg = Release Passthrough|x64
+ {1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0}.All|x64.ActiveCfg = Release Passthrough|x64
+ {1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0}.All|x64.Build.0 = Release Passthrough|x64
+ {1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0}.Debug|Win32.ActiveCfg = Debug Passthrough|Win32
+ {1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0}.Debug|Win32.Build.0 = Debug Passthrough|Win32
+ {1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0}.Debug|x64.ActiveCfg = Debug Passthrough|x64
+ {1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0}.Debug|x64.Build.0 = Debug Passthrough|x64
+ {1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0}.Release|Win32.ActiveCfg = Release Passthrough|Win32
+ {1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0}.Release|Win32.Build.0 = Release Passthrough|Win32
+ {1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0}.Release|x64.ActiveCfg = Release Passthrough|x64
+ {1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0}.Release|x64.Build.0 = Release Passthrough|x64
+ {AFAC0568-7548-42D5-9F6A-8D3400A1E4F6}.All|Win32.ActiveCfg = Release|x64
+ {AFAC0568-7548-42D5-9F6A-8D3400A1E4F6}.All|x64.ActiveCfg = Release|x64
+ {AFAC0568-7548-42D5-9F6A-8D3400A1E4F6}.All|x64.Build.0 = Release|x64
+ {AFAC0568-7548-42D5-9F6A-8D3400A1E4F6}.Debug|Win32.ActiveCfg = Debug|Win32
+ {AFAC0568-7548-42D5-9F6A-8D3400A1E4F6}.Debug|Win32.Build.0 = Debug|Win32
+ {AFAC0568-7548-42D5-9F6A-8D3400A1E4F6}.Debug|x64.ActiveCfg = Debug|x64
+ {AFAC0568-7548-42D5-9F6A-8D3400A1E4F6}.Debug|x64.Build.0 = Debug|x64
+ {AFAC0568-7548-42D5-9F6A-8D3400A1E4F6}.Release|Win32.ActiveCfg = Release|Win32
+ {AFAC0568-7548-42D5-9F6A-8D3400A1E4F6}.Release|Win32.Build.0 = Release|Win32
+ {AFAC0568-7548-42D5-9F6A-8D3400A1E4F6}.Release|x64.ActiveCfg = Release|x64
+ {AFAC0568-7548-42D5-9F6A-8D3400A1E4F6}.Release|x64.Build.0 = Release|x64
+ {5FD31A25-5D83-4794-8BEE-904DAD84CE71}.All|Win32.ActiveCfg = Release|x64
+ {5FD31A25-5D83-4794-8BEE-904DAD84CE71}.All|x64.ActiveCfg = Release|x64
+ {5FD31A25-5D83-4794-8BEE-904DAD84CE71}.All|x64.Build.0 = Release|x64
+ {5FD31A25-5D83-4794-8BEE-904DAD84CE71}.Debug|Win32.ActiveCfg = Debug|Win32
+ {5FD31A25-5D83-4794-8BEE-904DAD84CE71}.Debug|Win32.Build.0 = Debug|Win32
+ {5FD31A25-5D83-4794-8BEE-904DAD84CE71}.Debug|x64.ActiveCfg = Debug|x64
+ {5FD31A25-5D83-4794-8BEE-904DAD84CE71}.Debug|x64.Build.0 = Debug|x64
+ {5FD31A25-5D83-4794-8BEE-904DAD84CE71}.Release|Win32.ActiveCfg = Release|Win32
+ {5FD31A25-5D83-4794-8BEE-904DAD84CE71}.Release|Win32.Build.0 = Release|Win32
+ {5FD31A25-5D83-4794-8BEE-904DAD84CE71}.Release|x64.ActiveCfg = Release|x64
+ {5FD31A25-5D83-4794-8BEE-904DAD84CE71}.Release|x64.Build.0 = Release|x64
+ {5580D60E-0F77-4716-9CD4-B8E5986FA375}.All|Win32.ActiveCfg = Release|x64
+ {5580D60E-0F77-4716-9CD4-B8E5986FA375}.All|x64.ActiveCfg = Release|x64
+ {5580D60E-0F77-4716-9CD4-B8E5986FA375}.All|x64.Build.0 = Release|x64
+ {5580D60E-0F77-4716-9CD4-B8E5986FA375}.Debug|Win32.ActiveCfg = Debug|Win32
+ {5580D60E-0F77-4716-9CD4-B8E5986FA375}.Debug|Win32.Build.0 = Debug|Win32
+ {5580D60E-0F77-4716-9CD4-B8E5986FA375}.Debug|x64.ActiveCfg = Debug|x64
+ {5580D60E-0F77-4716-9CD4-B8E5986FA375}.Debug|x64.Build.0 = Debug|x64
+ {5580D60E-0F77-4716-9CD4-B8E5986FA375}.Release|Win32.ActiveCfg = Release|Win32
+ {5580D60E-0F77-4716-9CD4-B8E5986FA375}.Release|Win32.Build.0 = Release|Win32
+ {5580D60E-0F77-4716-9CD4-B8E5986FA375}.Release|x64.ActiveCfg = Release|x64
+ {5580D60E-0F77-4716-9CD4-B8E5986FA375}.Release|x64.Build.0 = Release|x64
+ {1A1FF289-4FD6-4285-A422-D31DD67A4723}.All|Win32.ActiveCfg = Release|Win32
+ {1A1FF289-4FD6-4285-A422-D31DD67A4723}.All|x64.ActiveCfg = Release|Win32
+ {1A1FF289-4FD6-4285-A422-D31DD67A4723}.Debug|Win32.ActiveCfg = Debug|Win32
+ {1A1FF289-4FD6-4285-A422-D31DD67A4723}.Debug|x64.ActiveCfg = Debug|Win32
+ {1A1FF289-4FD6-4285-A422-D31DD67A4723}.Release|Win32.ActiveCfg = Release|Win32
+ {1A1FF289-4FD6-4285-A422-D31DD67A4723}.Release|x64.ActiveCfg = Release|Win32
+ {07113B25-D3AF-4E04-BA77-4CD1171F022C}.All|Win32.ActiveCfg = Release|x64
+ {07113B25-D3AF-4E04-BA77-4CD1171F022C}.All|x64.ActiveCfg = Release|x64
+ {07113B25-D3AF-4E04-BA77-4CD1171F022C}.All|x64.Build.0 = Release|x64
+ {07113B25-D3AF-4E04-BA77-4CD1171F022C}.Debug|Win32.ActiveCfg = Debug|Win32
+ {07113B25-D3AF-4E04-BA77-4CD1171F022C}.Debug|Win32.Build.0 = Debug|Win32
+ {07113B25-D3AF-4E04-BA77-4CD1171F022C}.Debug|x64.ActiveCfg = Debug|x64
+ {07113B25-D3AF-4E04-BA77-4CD1171F022C}.Debug|x64.Build.0 = Debug|x64
+ {07113B25-D3AF-4E04-BA77-4CD1171F022C}.Release|Win32.ActiveCfg = Release|Win32
+ {07113B25-D3AF-4E04-BA77-4CD1171F022C}.Release|Win32.Build.0 = Release|Win32
+ {07113B25-D3AF-4E04-BA77-4CD1171F022C}.Release|x64.ActiveCfg = Release|x64
+ {07113B25-D3AF-4E04-BA77-4CD1171F022C}.Release|x64.Build.0 = Release|x64
+ {EC3E5C7F-EE09-47E2-80FE-546363D14A98}.All|Win32.ActiveCfg = Release MS-LDAP|x64
+ {EC3E5C7F-EE09-47E2-80FE-546363D14A98}.All|x64.ActiveCfg = Release MS-LDAP|x64
+ {EC3E5C7F-EE09-47E2-80FE-546363D14A98}.All|x64.Build.0 = Release MS-LDAP|x64
+ {EC3E5C7F-EE09-47E2-80FE-546363D14A98}.Debug|Win32.ActiveCfg = Debug MS-LDAP|Win32
+ {EC3E5C7F-EE09-47E2-80FE-546363D14A98}.Debug|Win32.Build.0 = Debug MS-LDAP|Win32
+ {EC3E5C7F-EE09-47E2-80FE-546363D14A98}.Debug|x64.ActiveCfg = Debug MS-LDAP|x64
+ {EC3E5C7F-EE09-47E2-80FE-546363D14A98}.Debug|x64.Build.0 = Debug MS-LDAP|x64
+ {EC3E5C7F-EE09-47E2-80FE-546363D14A98}.Release|Win32.ActiveCfg = Release MS-LDAP|Win32
+ {EC3E5C7F-EE09-47E2-80FE-546363D14A98}.Release|Win32.Build.0 = Release MS-LDAP|Win32
+ {EC3E5C7F-EE09-47E2-80FE-546363D14A98}.Release|x64.ActiveCfg = Release MS-LDAP|x64
+ {EC3E5C7F-EE09-47E2-80FE-546363D14A98}.Release|x64.Build.0 = Release MS-LDAP|x64
+ {A27CCA23-1541-4337-81A4-F0A6413078A0}.All|Win32.ActiveCfg = Release|x64
+ {A27CCA23-1541-4337-81A4-F0A6413078A0}.All|x64.ActiveCfg = Release|x64
+ {A27CCA23-1541-4337-81A4-F0A6413078A0}.All|x64.Build.0 = Release|x64
+ {A27CCA23-1541-4337-81A4-F0A6413078A0}.Debug|Win32.ActiveCfg = Debug|Win32
+ {A27CCA23-1541-4337-81A4-F0A6413078A0}.Debug|Win32.Build.0 = Debug|Win32
+ {A27CCA23-1541-4337-81A4-F0A6413078A0}.Debug|x64.ActiveCfg = Debug|x64
+ {A27CCA23-1541-4337-81A4-F0A6413078A0}.Debug|x64.Build.0 = Debug|x64
+ {A27CCA23-1541-4337-81A4-F0A6413078A0}.Release|Win32.ActiveCfg = Release|Win32
+ {A27CCA23-1541-4337-81A4-F0A6413078A0}.Release|Win32.Build.0 = Release|Win32
+ {A27CCA23-1541-4337-81A4-F0A6413078A0}.Release|x64.ActiveCfg = Release|x64
+ {A27CCA23-1541-4337-81A4-F0A6413078A0}.Release|x64.Build.0 = Release|x64
+ {784113EF-44D9-4949-835D-7065D3C7AD08}.All|Win32.ActiveCfg = Release|x64
+ {784113EF-44D9-4949-835D-7065D3C7AD08}.All|x64.ActiveCfg = Release|x64
+ {784113EF-44D9-4949-835D-7065D3C7AD08}.All|x64.Build.0 = Release|x64
+ {784113EF-44D9-4949-835D-7065D3C7AD08}.Debug|Win32.ActiveCfg = Debug|Win32
+ {784113EF-44D9-4949-835D-7065D3C7AD08}.Debug|Win32.Build.0 = Debug|Win32
+ {784113EF-44D9-4949-835D-7065D3C7AD08}.Debug|x64.ActiveCfg = Debug|x64
+ {784113EF-44D9-4949-835D-7065D3C7AD08}.Debug|x64.Build.0 = Debug|x64
+ {784113EF-44D9-4949-835D-7065D3C7AD08}.Release|Win32.ActiveCfg = Release|Win32
+ {784113EF-44D9-4949-835D-7065D3C7AD08}.Release|Win32.Build.0 = Release|Win32
+ {784113EF-44D9-4949-835D-7065D3C7AD08}.Release|x64.ActiveCfg = Release|x64
+ {784113EF-44D9-4949-835D-7065D3C7AD08}.Release|x64.Build.0 = Release|x64
+ {89385C74-5860-4174-9CAF-A39E7C48909C}.All|Win32.ActiveCfg = Release|x64
+ {89385C74-5860-4174-9CAF-A39E7C48909C}.All|x64.ActiveCfg = Release|x64
+ {89385C74-5860-4174-9CAF-A39E7C48909C}.All|x64.Build.0 = Release|x64
+ {89385C74-5860-4174-9CAF-A39E7C48909C}.Debug|Win32.ActiveCfg = Debug|Win32
+ {89385C74-5860-4174-9CAF-A39E7C48909C}.Debug|Win32.Build.0 = Debug|Win32
+ {89385C74-5860-4174-9CAF-A39E7C48909C}.Debug|x64.ActiveCfg = Debug|x64
+ {89385C74-5860-4174-9CAF-A39E7C48909C}.Debug|x64.Build.0 = Debug|x64
+ {89385C74-5860-4174-9CAF-A39E7C48909C}.Release|Win32.ActiveCfg = Release|Win32
+ {89385C74-5860-4174-9CAF-A39E7C48909C}.Release|Win32.Build.0 = Release|Win32
+ {89385C74-5860-4174-9CAF-A39E7C48909C}.Release|x64.ActiveCfg = Release|x64
+ {89385C74-5860-4174-9CAF-A39E7C48909C}.Release|x64.Build.0 = Release|x64
+ {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}.All|Win32.ActiveCfg = Release|x64
+ {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}.All|x64.ActiveCfg = Release|x64
+ {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}.All|x64.Build.0 = Release|x64
+ {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}.Debug|Win32.ActiveCfg = Debug|Win32
+ {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}.Debug|Win32.Build.0 = Debug|Win32
+ {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}.Debug|x64.ActiveCfg = Debug|x64
+ {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}.Release|Win32.ActiveCfg = Release|Win32
+ {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}.Release|Win32.Build.0 = Release|Win32
+ {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}.Release|x64.ActiveCfg = Release|x64
+ {692F6330-4D87-4C82-81DF-40DB5892636E}.All|Win32.ActiveCfg = Release|x64
+ {692F6330-4D87-4C82-81DF-40DB5892636E}.All|x64.ActiveCfg = Release|x64
+ {692F6330-4D87-4C82-81DF-40DB5892636E}.All|x64.Build.0 = Release|x64
+ {692F6330-4D87-4C82-81DF-40DB5892636E}.Debug|Win32.ActiveCfg = Debug|Win32
+ {692F6330-4D87-4C82-81DF-40DB5892636E}.Debug|x64.ActiveCfg = Debug|x64
+ {692F6330-4D87-4C82-81DF-40DB5892636E}.Release|Win32.ActiveCfg = Release|Win32
+ {692F6330-4D87-4C82-81DF-40DB5892636E}.Release|x64.ActiveCfg = Release|x64
+ {D3EC0AFF-76FC-4210-A825-9A17410660A3}.All|Win32.ActiveCfg = Release|x64
+ {D3EC0AFF-76FC-4210-A825-9A17410660A3}.All|x64.ActiveCfg = Release|x64
+ {D3EC0AFF-76FC-4210-A825-9A17410660A3}.All|x64.Build.0 = Release|x64
+ {D3EC0AFF-76FC-4210-A825-9A17410660A3}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D3EC0AFF-76FC-4210-A825-9A17410660A3}.Debug|Win32.Build.0 = Debug|Win32
+ {D3EC0AFF-76FC-4210-A825-9A17410660A3}.Debug|x64.ActiveCfg = Debug|x64
+ {D3EC0AFF-76FC-4210-A825-9A17410660A3}.Debug|x64.Build.0 = Debug|x64
+ {D3EC0AFF-76FC-4210-A825-9A17410660A3}.Release|Win32.ActiveCfg = Release|Win32
+ {D3EC0AFF-76FC-4210-A825-9A17410660A3}.Release|Win32.Build.0 = Release|Win32
+ {D3EC0AFF-76FC-4210-A825-9A17410660A3}.Release|x64.ActiveCfg = Release|x64
+ {D3EC0AFF-76FC-4210-A825-9A17410660A3}.Release|x64.Build.0 = Release|x64
+ {FFAA4C52-3A53-4F99-90C1-D59D1F0427F3}.All|Win32.ActiveCfg = Release|x64
+ {FFAA4C52-3A53-4F99-90C1-D59D1F0427F3}.All|x64.ActiveCfg = Release|x64
+ {FFAA4C52-3A53-4F99-90C1-D59D1F0427F3}.All|x64.Build.0 = Release|x64
+ {FFAA4C52-3A53-4F99-90C1-D59D1F0427F3}.Debug|Win32.ActiveCfg = Debug|Win32
+ {FFAA4C52-3A53-4F99-90C1-D59D1F0427F3}.Debug|Win32.Build.0 = Debug|Win32
+ {FFAA4C52-3A53-4F99-90C1-D59D1F0427F3}.Debug|x64.ActiveCfg = Debug|x64
+ {FFAA4C52-3A53-4F99-90C1-D59D1F0427F3}.Debug|x64.Build.0 = Debug|x64
+ {FFAA4C52-3A53-4F99-90C1-D59D1F0427F3}.Release|Win32.ActiveCfg = Release|Win32
+ {FFAA4C52-3A53-4F99-90C1-D59D1F0427F3}.Release|Win32.Build.0 = Release|Win32
+ {FFAA4C52-3A53-4F99-90C1-D59D1F0427F3}.Release|x64.ActiveCfg = Release|x64
+ {FFAA4C52-3A53-4F99-90C1-D59D1F0427F3}.Release|x64.Build.0 = Release|x64
+ {30A5B29C-983E-4580-9FD0-D647CCDCC7EB}.All|Win32.ActiveCfg = Release|x64
+ {30A5B29C-983E-4580-9FD0-D647CCDCC7EB}.All|x64.ActiveCfg = Release|x64
+ {30A5B29C-983E-4580-9FD0-D647CCDCC7EB}.All|x64.Build.0 = Release|x64
+ {30A5B29C-983E-4580-9FD0-D647CCDCC7EB}.Debug|Win32.ActiveCfg = Debug|Win32
+ {30A5B29C-983E-4580-9FD0-D647CCDCC7EB}.Debug|Win32.Build.0 = Debug|Win32
+ {30A5B29C-983E-4580-9FD0-D647CCDCC7EB}.Debug|x64.ActiveCfg = Debug|x64
+ {30A5B29C-983E-4580-9FD0-D647CCDCC7EB}.Debug|x64.Build.0 = Debug|x64
+ {30A5B29C-983E-4580-9FD0-D647CCDCC7EB}.Release|Win32.ActiveCfg = Release|Win32
+ {30A5B29C-983E-4580-9FD0-D647CCDCC7EB}.Release|Win32.Build.0 = Release|Win32
+ {30A5B29C-983E-4580-9FD0-D647CCDCC7EB}.Release|x64.ActiveCfg = Release|x64
+ {30A5B29C-983E-4580-9FD0-D647CCDCC7EB}.Release|x64.Build.0 = Release|x64
+ {1C453396-D912-4213-89FD-9B489162B7B5}.All|Win32.ActiveCfg = Release|x64
+ {1C453396-D912-4213-89FD-9B489162B7B5}.All|x64.ActiveCfg = Release|x64
+ {1C453396-D912-4213-89FD-9B489162B7B5}.All|x64.Build.0 = Release|x64
+ {1C453396-D912-4213-89FD-9B489162B7B5}.Debug|Win32.ActiveCfg = Debug|Win32
+ {1C453396-D912-4213-89FD-9B489162B7B5}.Debug|Win32.Build.0 = Debug|Win32
+ {1C453396-D912-4213-89FD-9B489162B7B5}.Debug|x64.ActiveCfg = Debug|x64
+ {1C453396-D912-4213-89FD-9B489162B7B5}.Debug|x64.Build.0 = Debug|x64
+ {1C453396-D912-4213-89FD-9B489162B7B5}.Release|Win32.ActiveCfg = Release|Win32
+ {1C453396-D912-4213-89FD-9B489162B7B5}.Release|Win32.Build.0 = Release|Win32
+ {1C453396-D912-4213-89FD-9B489162B7B5}.Release|x64.ActiveCfg = Release|x64
+ {1C453396-D912-4213-89FD-9B489162B7B5}.Release|x64.Build.0 = Release|x64
+ {CBEC7225-0C21-4DA8-978E-1F158F8AD950}.All|Win32.ActiveCfg = Release|x64
+ {CBEC7225-0C21-4DA8-978E-1F158F8AD950}.All|x64.ActiveCfg = Release|x64
+ {CBEC7225-0C21-4DA8-978E-1F158F8AD950}.All|x64.Build.0 = Release|x64
+ {CBEC7225-0C21-4DA8-978E-1F158F8AD950}.Debug|Win32.ActiveCfg = Debug|Win32
+ {CBEC7225-0C21-4DA8-978E-1F158F8AD950}.Debug|Win32.Build.0 = Debug|Win32
+ {CBEC7225-0C21-4DA8-978E-1F158F8AD950}.Debug|x64.ActiveCfg = Debug|x64
+ {CBEC7225-0C21-4DA8-978E-1F158F8AD950}.Debug|x64.Build.0 = Debug|x64
+ {CBEC7225-0C21-4DA8-978E-1F158F8AD950}.Release|Win32.ActiveCfg = Release|Win32
+ {CBEC7225-0C21-4DA8-978E-1F158F8AD950}.Release|Win32.Build.0 = Release|Win32
+ {CBEC7225-0C21-4DA8-978E-1F158F8AD950}.Release|x64.ActiveCfg = Release|x64
+ {CBEC7225-0C21-4DA8-978E-1F158F8AD950}.Release|x64.Build.0 = Release|x64
+ {B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4}.All|Win32.ActiveCfg = Release|x64
+ {B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4}.All|x64.ActiveCfg = Release|x64
+ {B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4}.All|x64.Build.0 = Release|x64
+ {B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4}.Debug|Win32.ActiveCfg = Debug|Win32
+ {B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4}.Debug|Win32.Build.0 = Debug|Win32
+ {B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4}.Debug|x64.ActiveCfg = Debug|x64
+ {B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4}.Debug|x64.Build.0 = Debug|x64
+ {B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4}.Release|Win32.ActiveCfg = Release|Win32
+ {B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4}.Release|Win32.Build.0 = Release|Win32
+ {B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4}.Release|x64.ActiveCfg = Release|x64
+ {B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4}.Release|x64.Build.0 = Release|x64
+ {C24FB505-05D7-4319-8485-7540B44C8603}.All|Win32.ActiveCfg = Release|x64
+ {C24FB505-05D7-4319-8485-7540B44C8603}.All|x64.ActiveCfg = Release|x64
+ {C24FB505-05D7-4319-8485-7540B44C8603}.All|x64.Build.0 = Release|x64
+ {C24FB505-05D7-4319-8485-7540B44C8603}.Debug|Win32.ActiveCfg = Debug|Win32
+ {C24FB505-05D7-4319-8485-7540B44C8603}.Debug|Win32.Build.0 = Debug|Win32
+ {C24FB505-05D7-4319-8485-7540B44C8603}.Debug|x64.ActiveCfg = Debug|x64
+ {C24FB505-05D7-4319-8485-7540B44C8603}.Debug|x64.Build.0 = Debug|x64
+ {C24FB505-05D7-4319-8485-7540B44C8603}.Release|Win32.ActiveCfg = Release|Win32
+ {C24FB505-05D7-4319-8485-7540B44C8603}.Release|Win32.Build.0 = Release|Win32
+ {C24FB505-05D7-4319-8485-7540B44C8603}.Release|x64.ActiveCfg = Release|x64
+ {C24FB505-05D7-4319-8485-7540B44C8603}.Release|x64.Build.0 = Release|x64
+ {B5881A85-FE70-4F64-8607-2CAAE52669C6}.All|Win32.ActiveCfg = Release|x64
+ {B5881A85-FE70-4F64-8607-2CAAE52669C6}.All|x64.ActiveCfg = Release|x64
+ {B5881A85-FE70-4F64-8607-2CAAE52669C6}.All|x64.Build.0 = Release|x64
+ {B5881A85-FE70-4F64-8607-2CAAE52669C6}.Debug|Win32.ActiveCfg = Debug|Win32
+ {B5881A85-FE70-4F64-8607-2CAAE52669C6}.Debug|Win32.Build.0 = Debug|Win32
+ {B5881A85-FE70-4F64-8607-2CAAE52669C6}.Debug|x64.ActiveCfg = Debug|x64
+ {B5881A85-FE70-4F64-8607-2CAAE52669C6}.Debug|x64.Build.0 = Debug|x64
+ {B5881A85-FE70-4F64-8607-2CAAE52669C6}.Release|Win32.ActiveCfg = Release|Win32
+ {B5881A85-FE70-4F64-8607-2CAAE52669C6}.Release|Win32.Build.0 = Release|Win32
+ {B5881A85-FE70-4F64-8607-2CAAE52669C6}.Release|x64.ActiveCfg = Release|x64
+ {B5881A85-FE70-4F64-8607-2CAAE52669C6}.Release|x64.Build.0 = Release|x64
+ {05515420-16DE-4E63-BE73-85BE85BA5142}.All|Win32.ActiveCfg = Release|x64
+ {05515420-16DE-4E63-BE73-85BE85BA5142}.All|x64.ActiveCfg = Release|x64
+ {05515420-16DE-4E63-BE73-85BE85BA5142}.All|x64.Build.0 = Release|x64
+ {05515420-16DE-4E63-BE73-85BE85BA5142}.Debug|Win32.ActiveCfg = Debug|Win32
+ {05515420-16DE-4E63-BE73-85BE85BA5142}.Debug|Win32.Build.0 = Debug|Win32
+ {05515420-16DE-4E63-BE73-85BE85BA5142}.Debug|x64.ActiveCfg = Debug|x64
+ {05515420-16DE-4E63-BE73-85BE85BA5142}.Debug|x64.Build.0 = Debug|x64
+ {05515420-16DE-4E63-BE73-85BE85BA5142}.Release|Win32.ActiveCfg = Release|Win32
+ {05515420-16DE-4E63-BE73-85BE85BA5142}.Release|Win32.Build.0 = Release|Win32
+ {05515420-16DE-4E63-BE73-85BE85BA5142}.Release|x64.ActiveCfg = Release|x64
+ {05515420-16DE-4E63-BE73-85BE85BA5142}.Release|x64.Build.0 = Release|x64
+ {1906D736-08BD-4EE1-924F-B536249B9A54}.All|Win32.ActiveCfg = Release DLL|x64
+ {1906D736-08BD-4EE1-924F-B536249B9A54}.All|x64.ActiveCfg = Release DLL|x64
+ {1906D736-08BD-4EE1-924F-B536249B9A54}.All|x64.Build.0 = Release DLL|x64
+ {1906D736-08BD-4EE1-924F-B536249B9A54}.Debug|Win32.ActiveCfg = Debug|Win32
+ {1906D736-08BD-4EE1-924F-B536249B9A54}.Debug|Win32.Build.0 = Debug|Win32
+ {1906D736-08BD-4EE1-924F-B536249B9A54}.Debug|x64.ActiveCfg = Debug|x64
+ {1906D736-08BD-4EE1-924F-B536249B9A54}.Debug|x64.Build.0 = Debug|x64
+ {1906D736-08BD-4EE1-924F-B536249B9A54}.Release|Win32.ActiveCfg = Release|Win32
+ {1906D736-08BD-4EE1-924F-B536249B9A54}.Release|Win32.Build.0 = Release|Win32
+ {1906D736-08BD-4EE1-924F-B536249B9A54}.Release|x64.ActiveCfg = Release|x64
+ {1906D736-08BD-4EE1-924F-B536249B9A54}.Release|x64.Build.0 = Release|x64
+ {EEF031CB-FED8-451E-A471-91EC8D4F6750}.All|Win32.ActiveCfg = Release Dll|x64
+ {EEF031CB-FED8-451E-A471-91EC8D4F6750}.All|x64.ActiveCfg = Release Dll|x64
+ {EEF031CB-FED8-451E-A471-91EC8D4F6750}.All|x64.Build.0 = Release Dll|x64
+ {EEF031CB-FED8-451E-A471-91EC8D4F6750}.Debug|Win32.ActiveCfg = Debug|Win32
+ {EEF031CB-FED8-451E-A471-91EC8D4F6750}.Debug|Win32.Build.0 = Debug|Win32
+ {EEF031CB-FED8-451E-A471-91EC8D4F6750}.Debug|x64.ActiveCfg = Debug|x64
+ {EEF031CB-FED8-451E-A471-91EC8D4F6750}.Debug|x64.Build.0 = Debug|x64
+ {EEF031CB-FED8-451E-A471-91EC8D4F6750}.Release|Win32.ActiveCfg = Release|Win32
+ {EEF031CB-FED8-451E-A471-91EC8D4F6750}.Release|Win32.Build.0 = Release|Win32
+ {EEF031CB-FED8-451E-A471-91EC8D4F6750}.Release|x64.ActiveCfg = Release|x64
+ {EEF031CB-FED8-451E-A471-91EC8D4F6750}.Release|x64.Build.0 = Release|x64
+ {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3}.All|Win32.ActiveCfg = Release DLL|x64
+ {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3}.All|x64.ActiveCfg = Release DLL|x64
+ {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3}.All|x64.Build.0 = Release DLL|x64
+ {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3}.Debug|Win32.ActiveCfg = Debug|Win32
+ {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3}.Debug|Win32.Build.0 = Debug|Win32
+ {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3}.Debug|x64.ActiveCfg = Debug|x64
+ {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3}.Debug|x64.Build.0 = Debug|x64
+ {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3}.Release|Win32.ActiveCfg = Release|Win32
+ {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3}.Release|Win32.Build.0 = Release|Win32
+ {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3}.Release|x64.ActiveCfg = Release|x64
+ {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3}.Release|x64.Build.0 = Release|x64
+ {8D04B550-D240-4A44-8A18-35DA3F7038D9}.All|Win32.ActiveCfg = Release DLL|x64
+ {8D04B550-D240-4A44-8A18-35DA3F7038D9}.All|x64.ActiveCfg = Release DLL|x64
+ {8D04B550-D240-4A44-8A18-35DA3F7038D9}.All|x64.Build.0 = Release DLL|x64
+ {8D04B550-D240-4A44-8A18-35DA3F7038D9}.Debug|Win32.ActiveCfg = Debug|Win32
+ {8D04B550-D240-4A44-8A18-35DA3F7038D9}.Debug|Win32.Build.0 = Debug|Win32
+ {8D04B550-D240-4A44-8A18-35DA3F7038D9}.Debug|x64.ActiveCfg = Debug|x64
+ {8D04B550-D240-4A44-8A18-35DA3F7038D9}.Debug|x64.Build.0 = Debug|x64
+ {8D04B550-D240-4A44-8A18-35DA3F7038D9}.Release|Win32.ActiveCfg = Release|Win32
+ {8D04B550-D240-4A44-8A18-35DA3F7038D9}.Release|Win32.Build.0 = Release|Win32
+ {8D04B550-D240-4A44-8A18-35DA3F7038D9}.Release|x64.ActiveCfg = Release|x64
+ {8D04B550-D240-4A44-8A18-35DA3F7038D9}.Release|x64.Build.0 = Release|x64
+ {1CED5987-A529-46DC-B30F-870D85FF9C94}.All|Win32.ActiveCfg = Release|x64
+ {1CED5987-A529-46DC-B30F-870D85FF9C94}.All|x64.ActiveCfg = Release|x64
+ {1CED5987-A529-46DC-B30F-870D85FF9C94}.All|x64.Build.0 = Release|x64
+ {1CED5987-A529-46DC-B30F-870D85FF9C94}.Debug|Win32.ActiveCfg = Debug|Win32
+ {1CED5987-A529-46DC-B30F-870D85FF9C94}.Debug|Win32.Build.0 = Debug|Win32
+ {1CED5987-A529-46DC-B30F-870D85FF9C94}.Debug|x64.ActiveCfg = Debug|x64
+ {1CED5987-A529-46DC-B30F-870D85FF9C94}.Debug|x64.Build.0 = Debug|x64
+ {1CED5987-A529-46DC-B30F-870D85FF9C94}.Release|Win32.ActiveCfg = Release|Win32
+ {1CED5987-A529-46DC-B30F-870D85FF9C94}.Release|Win32.Build.0 = Release|Win32
+ {1CED5987-A529-46DC-B30F-870D85FF9C94}.Release|x64.ActiveCfg = Release|x64
+ {1CED5987-A529-46DC-B30F-870D85FF9C94}.Release|x64.Build.0 = Release|x64
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}.All|Win32.ActiveCfg = Release|x64
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}.All|x64.ActiveCfg = Release|x64
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}.All|x64.Build.0 = Release|x64
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}.Debug|Win32.ActiveCfg = Debug|Win32
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}.Debug|Win32.Build.0 = Debug|Win32
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}.Debug|x64.ActiveCfg = Debug|x64
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}.Debug|x64.Build.0 = Debug|x64
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}.Release|Win32.ActiveCfg = Release|Win32
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}.Release|Win32.Build.0 = Release|Win32
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}.Release|x64.ActiveCfg = Release|x64
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}.Release|x64.Build.0 = Release|x64
+ {F057DA7F-79E5-4B00-845C-EF446EF055E3}.All|Win32.ActiveCfg = Release|x64
+ {F057DA7F-79E5-4B00-845C-EF446EF055E3}.All|x64.ActiveCfg = Release|x64
+ {F057DA7F-79E5-4B00-845C-EF446EF055E3}.All|x64.Build.0 = Release|x64
+ {F057DA7F-79E5-4B00-845C-EF446EF055E3}.Debug|Win32.ActiveCfg = Debug|Win32
+ {F057DA7F-79E5-4B00-845C-EF446EF055E3}.Debug|Win32.Build.0 = Debug|Win32
+ {F057DA7F-79E5-4B00-845C-EF446EF055E3}.Debug|x64.ActiveCfg = Debug|x64
+ {F057DA7F-79E5-4B00-845C-EF446EF055E3}.Debug|x64.Build.0 = Debug|x64
+ {F057DA7F-79E5-4B00-845C-EF446EF055E3}.Release|Win32.ActiveCfg = Release|Win32
+ {F057DA7F-79E5-4B00-845C-EF446EF055E3}.Release|Win32.Build.0 = Release|Win32
+ {F057DA7F-79E5-4B00-845C-EF446EF055E3}.Release|x64.ActiveCfg = Release|x64
+ {F057DA7F-79E5-4B00-845C-EF446EF055E3}.Release|x64.Build.0 = Release|x64
+ {E727E8F6-935D-46FE-8B0E-37834748A0E3}.All|Win32.ActiveCfg = Release|x64
+ {E727E8F6-935D-46FE-8B0E-37834748A0E3}.All|x64.ActiveCfg = Release|x64
+ {E727E8F6-935D-46FE-8B0E-37834748A0E3}.All|x64.Build.0 = Release|x64
+ {E727E8F6-935D-46FE-8B0E-37834748A0E3}.Debug|Win32.ActiveCfg = Debug|Win32
+ {E727E8F6-935D-46FE-8B0E-37834748A0E3}.Debug|Win32.Build.0 = Debug|Win32
+ {E727E8F6-935D-46FE-8B0E-37834748A0E3}.Debug|x64.ActiveCfg = Debug|x64
+ {E727E8F6-935D-46FE-8B0E-37834748A0E3}.Debug|x64.Build.0 = Debug|x64
+ {E727E8F6-935D-46FE-8B0E-37834748A0E3}.Release|Win32.ActiveCfg = Release|Win32
+ {E727E8F6-935D-46FE-8B0E-37834748A0E3}.Release|Win32.Build.0 = Release|Win32
+ {E727E8F6-935D-46FE-8B0E-37834748A0E3}.Release|x64.ActiveCfg = Release|x64
+ {E727E8F6-935D-46FE-8B0E-37834748A0E3}.Release|x64.Build.0 = Release|x64
+ {3D0370CA-BED2-4657-A475-32375CBCB6E4}.All|Win32.ActiveCfg = Release|x64
+ {3D0370CA-BED2-4657-A475-32375CBCB6E4}.All|x64.ActiveCfg = Release|x64
+ {3D0370CA-BED2-4657-A475-32375CBCB6E4}.All|x64.Build.0 = Release|x64
+ {3D0370CA-BED2-4657-A475-32375CBCB6E4}.Debug|Win32.ActiveCfg = Debug|Win32
+ {3D0370CA-BED2-4657-A475-32375CBCB6E4}.Debug|Win32.Build.0 = Debug|Win32
+ {3D0370CA-BED2-4657-A475-32375CBCB6E4}.Debug|x64.ActiveCfg = Debug|x64
+ {3D0370CA-BED2-4657-A475-32375CBCB6E4}.Debug|x64.Build.0 = Debug|x64
+ {3D0370CA-BED2-4657-A475-32375CBCB6E4}.Release|Win32.ActiveCfg = Release|Win32
+ {3D0370CA-BED2-4657-A475-32375CBCB6E4}.Release|Win32.Build.0 = Release|Win32
+ {3D0370CA-BED2-4657-A475-32375CBCB6E4}.Release|x64.ActiveCfg = Release|x64
+ {3D0370CA-BED2-4657-A475-32375CBCB6E4}.Release|x64.Build.0 = Release|x64
+ {87EE9DA4-DE1E-4448-8324-183C98DCA588}.All|Win32.ActiveCfg = Debug|x64
+ {87EE9DA4-DE1E-4448-8324-183C98DCA588}.All|x64.ActiveCfg = Debug|x64
+ {87EE9DA4-DE1E-4448-8324-183C98DCA588}.All|x64.Build.0 = Debug|x64
+ {87EE9DA4-DE1E-4448-8324-183C98DCA588}.Debug|Win32.ActiveCfg = Debug|Win32
+ {87EE9DA4-DE1E-4448-8324-183C98DCA588}.Debug|Win32.Build.0 = Debug|Win32
+ {87EE9DA4-DE1E-4448-8324-183C98DCA588}.Debug|x64.ActiveCfg = Debug|x64
+ {87EE9DA4-DE1E-4448-8324-183C98DCA588}.Debug|x64.Build.0 = Debug|x64
+ {87EE9DA4-DE1E-4448-8324-183C98DCA588}.Release|Win32.ActiveCfg = Release|Win32
+ {87EE9DA4-DE1E-4448-8324-183C98DCA588}.Release|Win32.Build.0 = Release|Win32
+ {87EE9DA4-DE1E-4448-8324-183C98DCA588}.Release|x64.ActiveCfg = Release|x64
+ {87EE9DA4-DE1E-4448-8324-183C98DCA588}.Release|x64.Build.0 = Release|x64
+ {155844C3-EC5F-407F-97A4-A2DDADED9B2F}.All|Win32.ActiveCfg = Debug|x64
+ {155844C3-EC5F-407F-97A4-A2DDADED9B2F}.All|x64.ActiveCfg = Debug|x64
+ {155844C3-EC5F-407F-97A4-A2DDADED9B2F}.All|x64.Build.0 = Debug|x64
+ {155844C3-EC5F-407F-97A4-A2DDADED9B2F}.Debug|Win32.ActiveCfg = Debug|Win32
+ {155844C3-EC5F-407F-97A4-A2DDADED9B2F}.Debug|Win32.Build.0 = Debug|Win32
+ {155844C3-EC5F-407F-97A4-A2DDADED9B2F}.Debug|x64.ActiveCfg = Debug|x64
+ {155844C3-EC5F-407F-97A4-A2DDADED9B2F}.Debug|x64.Build.0 = Debug|x64
+ {155844C3-EC5F-407F-97A4-A2DDADED9B2F}.Release|Win32.ActiveCfg = Release|Win32
+ {155844C3-EC5F-407F-97A4-A2DDADED9B2F}.Release|Win32.Build.0 = Release|Win32
+ {155844C3-EC5F-407F-97A4-A2DDADED9B2F}.Release|x64.ActiveCfg = Release|x64
+ {155844C3-EC5F-407F-97A4-A2DDADED9B2F}.Release|x64.Build.0 = Release|x64
+ {204FA0DE-305D-4414-AE2E-F195A23F390D}.All|Win32.ActiveCfg = Debug|x64
+ {204FA0DE-305D-4414-AE2E-F195A23F390D}.All|x64.ActiveCfg = Debug|x64
+ {204FA0DE-305D-4414-AE2E-F195A23F390D}.All|x64.Build.0 = Debug|x64
+ {204FA0DE-305D-4414-AE2E-F195A23F390D}.Debug|Win32.ActiveCfg = Debug|Win32
+ {204FA0DE-305D-4414-AE2E-F195A23F390D}.Debug|Win32.Build.0 = Debug|Win32
+ {204FA0DE-305D-4414-AE2E-F195A23F390D}.Debug|x64.ActiveCfg = Debug|x64
+ {204FA0DE-305D-4414-AE2E-F195A23F390D}.Debug|x64.Build.0 = Debug|x64
+ {204FA0DE-305D-4414-AE2E-F195A23F390D}.Release|Win32.ActiveCfg = Release|Win32
+ {204FA0DE-305D-4414-AE2E-F195A23F390D}.Release|Win32.Build.0 = Release|Win32
+ {204FA0DE-305D-4414-AE2E-F195A23F390D}.Release|x64.ActiveCfg = Release|x64
+ {204FA0DE-305D-4414-AE2E-F195A23F390D}.Release|x64.Build.0 = Release|x64
+ {0DF3ABD0-DDC0-4265-B778-07C66780979B}.All|Win32.ActiveCfg = Release|x64
+ {0DF3ABD0-DDC0-4265-B778-07C66780979B}.All|x64.ActiveCfg = Release|x64
+ {0DF3ABD0-DDC0-4265-B778-07C66780979B}.All|x64.Build.0 = Release|x64
+ {0DF3ABD0-DDC0-4265-B778-07C66780979B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {0DF3ABD0-DDC0-4265-B778-07C66780979B}.Debug|Win32.Build.0 = Debug|Win32
+ {0DF3ABD0-DDC0-4265-B778-07C66780979B}.Debug|x64.ActiveCfg = Debug|x64
+ {0DF3ABD0-DDC0-4265-B778-07C66780979B}.Debug|x64.Build.0 = Debug|x64
+ {0DF3ABD0-DDC0-4265-B778-07C66780979B}.Release|Win32.ActiveCfg = Release|Win32
+ {0DF3ABD0-DDC0-4265-B778-07C66780979B}.Release|Win32.Build.0 = Release|Win32
+ {0DF3ABD0-DDC0-4265-B778-07C66780979B}.Release|x64.ActiveCfg = Release|x64
+ {0DF3ABD0-DDC0-4265-B778-07C66780979B}.Release|x64.Build.0 = Release|x64
+ {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}.All|Win32.ActiveCfg = Release|x64
+ {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}.All|x64.ActiveCfg = Release|x64
+ {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}.All|x64.Build.0 = Release|x64
+ {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}.Debug|Win32.ActiveCfg = Debug|Win32
+ {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}.Debug|Win32.Build.0 = Debug|Win32
+ {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}.Debug|x64.ActiveCfg = Debug|x64
+ {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}.Debug|x64.Build.0 = Debug|x64
+ {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}.Release|Win32.ActiveCfg = Release|Win32
+ {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}.Release|Win32.Build.0 = Release|Win32
+ {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}.Release|x64.ActiveCfg = Release|x64
+ {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}.Release|x64.Build.0 = Release|x64
+ {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}.All|Win32.ActiveCfg = Release|Win32
+ {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}.All|Win32.Build.0 = Release|Win32
+ {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}.All|x64.ActiveCfg = Release|Win32
+ {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}.All|x64.Build.0 = Release|Win32
+ {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}.Debug|Win32.ActiveCfg = Debug|Win32
+ {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}.Debug|Win32.Build.0 = Debug|Win32
+ {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}.Debug|x64.ActiveCfg = Debug|Win32
+ {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}.Debug|x64.Build.0 = Debug|Win32
+ {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}.Release|Win32.ActiveCfg = Release|Win32
+ {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}.Release|Win32.Build.0 = Release|Win32
+ {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}.Release|x64.ActiveCfg = Release|Win32
+ {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}.Release|x64.Build.0 = Release|Win32
+ {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}.All|Win32.ActiveCfg = Release DLL|x64
+ {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}.All|x64.ActiveCfg = Release DLL|x64
+ {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}.All|x64.Build.0 = Release DLL|x64
+ {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}.Debug|Win32.ActiveCfg = Debug DLL|Win32
+ {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}.Debug|Win32.Build.0 = Debug DLL|Win32
+ {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}.Debug|x64.ActiveCfg = Debug DLL|x64
+ {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}.Debug|x64.Build.0 = Debug DLL|x64
+ {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}.Release|Win32.ActiveCfg = Release DLL|Win32
+ {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}.Release|Win32.Build.0 = Release DLL|Win32
+ {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}.Release|x64.ActiveCfg = Release DLL|x64
+ {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}.Release|x64.Build.0 = Release DLL|x64
+ {FEA1EEF7-876F-48DE-88BF-C0E3E606D758}.All|Win32.ActiveCfg = Release Passthrough|x64
+ {FEA1EEF7-876F-48DE-88BF-C0E3E606D758}.All|x64.ActiveCfg = Release Passthrough|x64
+ {FEA1EEF7-876F-48DE-88BF-C0E3E606D758}.All|x64.Build.0 = Release Passthrough|x64
+ {FEA1EEF7-876F-48DE-88BF-C0E3E606D758}.Debug|Win32.ActiveCfg = Debug Passthrough|Win32
+ {FEA1EEF7-876F-48DE-88BF-C0E3E606D758}.Debug|Win32.Build.0 = Debug Passthrough|Win32
+ {FEA1EEF7-876F-48DE-88BF-C0E3E606D758}.Debug|x64.ActiveCfg = Debug Passthrough|x64
+ {FEA1EEF7-876F-48DE-88BF-C0E3E606D758}.Debug|x64.Build.0 = Debug Passthrough|x64
+ {FEA1EEF7-876F-48DE-88BF-C0E3E606D758}.Release|Win32.ActiveCfg = Release Passthrough|Win32
+ {FEA1EEF7-876F-48DE-88BF-C0E3E606D758}.Release|Win32.Build.0 = Release Passthrough|Win32
+ {FEA1EEF7-876F-48DE-88BF-C0E3E606D758}.Release|x64.ActiveCfg = Release Passthrough|x64
+ {FEA1EEF7-876F-48DE-88BF-C0E3E606D758}.Release|x64.Build.0 = Release Passthrough|x64
+ {9254C4B0-6F60-42B6-BB3A-36D63FC001C7}.All|Win32.ActiveCfg = Release|x64
+ {9254C4B0-6F60-42B6-BB3A-36D63FC001C7}.All|x64.ActiveCfg = Release|x64
+ {9254C4B0-6F60-42B6-BB3A-36D63FC001C7}.All|x64.Build.0 = Release|x64
+ {9254C4B0-6F60-42B6-BB3A-36D63FC001C7}.Debug|Win32.ActiveCfg = Debug|Win32
+ {9254C4B0-6F60-42B6-BB3A-36D63FC001C7}.Debug|Win32.Build.0 = Debug|Win32
+ {9254C4B0-6F60-42B6-BB3A-36D63FC001C7}.Debug|x64.ActiveCfg = Debug|x64
+ {9254C4B0-6F60-42B6-BB3A-36D63FC001C7}.Debug|x64.Build.0 = Debug|x64
+ {9254C4B0-6F60-42B6-BB3A-36D63FC001C7}.Release|Win32.ActiveCfg = Release|Win32
+ {9254C4B0-6F60-42B6-BB3A-36D63FC001C7}.Release|Win32.Build.0 = Release|Win32
+ {9254C4B0-6F60-42B6-BB3A-36D63FC001C7}.Release|x64.ActiveCfg = Release|x64
+ {9254C4B0-6F60-42B6-BB3A-36D63FC001C7}.Release|x64.Build.0 = Release|x64
+ {ACFFF684-4D19-4D48-AF12-88EA1D778BDF}.All|Win32.ActiveCfg = Release|x64
+ {ACFFF684-4D19-4D48-AF12-88EA1D778BDF}.All|x64.ActiveCfg = Release|x64
+ {ACFFF684-4D19-4D48-AF12-88EA1D778BDF}.All|x64.Build.0 = Release|x64
+ {ACFFF684-4D19-4D48-AF12-88EA1D778BDF}.Debug|Win32.ActiveCfg = Debug|Win32
+ {ACFFF684-4D19-4D48-AF12-88EA1D778BDF}.Debug|Win32.Build.0 = Debug|Win32
+ {ACFFF684-4D19-4D48-AF12-88EA1D778BDF}.Debug|x64.ActiveCfg = Debug|x64
+ {ACFFF684-4D19-4D48-AF12-88EA1D778BDF}.Release|Win32.ActiveCfg = Release|Win32
+ {ACFFF684-4D19-4D48-AF12-88EA1D778BDF}.Release|Win32.Build.0 = Release|Win32
+ {ACFFF684-4D19-4D48-AF12-88EA1D778BDF}.Release|x64.ActiveCfg = Release|x64
+ {8F992C49-6C51-412F-B2A3-34EAB708EB65}.All|Win32.ActiveCfg = Release|x64
+ {8F992C49-6C51-412F-B2A3-34EAB708EB65}.All|x64.ActiveCfg = Release|x64
+ {8F992C49-6C51-412F-B2A3-34EAB708EB65}.All|x64.Build.0 = Release|x64
+ {8F992C49-6C51-412F-B2A3-34EAB708EB65}.Debug|Win32.ActiveCfg = Debug|Win32
+ {8F992C49-6C51-412F-B2A3-34EAB708EB65}.Debug|Win32.Build.0 = Debug|Win32
+ {8F992C49-6C51-412F-B2A3-34EAB708EB65}.Debug|x64.ActiveCfg = Debug|x64
+ {8F992C49-6C51-412F-B2A3-34EAB708EB65}.Release|Win32.ActiveCfg = Release|Win32
+ {8F992C49-6C51-412F-B2A3-34EAB708EB65}.Release|Win32.Build.0 = Release|Win32
+ {8F992C49-6C51-412F-B2A3-34EAB708EB65}.Release|x64.ActiveCfg = Release|x64
+ {71A967D5-0E99-4CEF-A587-98836EE6F2EF}.All|Win32.ActiveCfg = Release|x64
+ {71A967D5-0E99-4CEF-A587-98836EE6F2EF}.All|x64.ActiveCfg = Release|x64
+ {71A967D5-0E99-4CEF-A587-98836EE6F2EF}.All|x64.Build.0 = Release|x64
+ {71A967D5-0E99-4CEF-A587-98836EE6F2EF}.Debug|Win32.ActiveCfg = Debug|Win32
+ {71A967D5-0E99-4CEF-A587-98836EE6F2EF}.Debug|Win32.Build.0 = Debug|Win32
+ {71A967D5-0E99-4CEF-A587-98836EE6F2EF}.Debug|x64.ActiveCfg = Debug|x64
+ {71A967D5-0E99-4CEF-A587-98836EE6F2EF}.Debug|x64.Build.0 = Debug|x64
+ {71A967D5-0E99-4CEF-A587-98836EE6F2EF}.Release|Win32.ActiveCfg = Release|Win32
+ {71A967D5-0E99-4CEF-A587-98836EE6F2EF}.Release|Win32.Build.0 = Release|Win32
+ {71A967D5-0E99-4CEF-A587-98836EE6F2EF}.Release|x64.ActiveCfg = Release|x64
+ {71A967D5-0E99-4CEF-A587-98836EE6F2EF}.Release|x64.Build.0 = Release|x64
+ {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}.All|Win32.ActiveCfg = Release|x64
+ {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}.All|x64.ActiveCfg = Release|x64
+ {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}.All|x64.Build.0 = Release|x64
+ {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}.Debug|Win32.ActiveCfg = Debug|Win32
+ {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}.Debug|Win32.Build.0 = Debug|Win32
+ {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}.Debug|x64.ActiveCfg = Debug|x64
+ {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}.Release|Win32.ActiveCfg = Release|Win32
+ {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}.Release|Win32.Build.0 = Release|Win32
+ {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}.Release|x64.ActiveCfg = Release|x64
+ {AB91A099-7690-4ECF-8994-E458F4EA1ED4}.All|Win32.ActiveCfg = Release|x64
+ {AB91A099-7690-4ECF-8994-E458F4EA1ED4}.All|x64.ActiveCfg = Release|x64
+ {AB91A099-7690-4ECF-8994-E458F4EA1ED4}.All|x64.Build.0 = Release|x64
+ {AB91A099-7690-4ECF-8994-E458F4EA1ED4}.Debug|Win32.ActiveCfg = Debug|Win32
+ {AB91A099-7690-4ECF-8994-E458F4EA1ED4}.Debug|Win32.Build.0 = Debug|Win32
+ {AB91A099-7690-4ECF-8994-E458F4EA1ED4}.Debug|x64.ActiveCfg = Debug|x64
+ {AB91A099-7690-4ECF-8994-E458F4EA1ED4}.Debug|x64.Build.0 = Debug|x64
+ {AB91A099-7690-4ECF-8994-E458F4EA1ED4}.Release|Win32.ActiveCfg = Release|Win32
+ {AB91A099-7690-4ECF-8994-E458F4EA1ED4}.Release|Win32.Build.0 = Release|Win32
+ {AB91A099-7690-4ECF-8994-E458F4EA1ED4}.Release|x64.ActiveCfg = Release|x64
+ {AB91A099-7690-4ECF-8994-E458F4EA1ED4}.Release|x64.Build.0 = Release|x64
+ {988CACF7-3FCB-4992-BE69-77872AE67DC8}.All|Win32.ActiveCfg = Release|x64
+ {988CACF7-3FCB-4992-BE69-77872AE67DC8}.All|x64.ActiveCfg = Release|x64
+ {988CACF7-3FCB-4992-BE69-77872AE67DC8}.All|x64.Build.0 = Release|x64
+ {988CACF7-3FCB-4992-BE69-77872AE67DC8}.Debug|Win32.ActiveCfg = Debug|Win32
+ {988CACF7-3FCB-4992-BE69-77872AE67DC8}.Debug|Win32.Build.0 = Debug|Win32
+ {988CACF7-3FCB-4992-BE69-77872AE67DC8}.Debug|x64.ActiveCfg = Debug|x64
+ {988CACF7-3FCB-4992-BE69-77872AE67DC8}.Debug|x64.Build.0 = Debug|x64
+ {988CACF7-3FCB-4992-BE69-77872AE67DC8}.Release|Win32.ActiveCfg = Release|Win32
+ {988CACF7-3FCB-4992-BE69-77872AE67DC8}.Release|Win32.Build.0 = Release|Win32
+ {988CACF7-3FCB-4992-BE69-77872AE67DC8}.Release|x64.ActiveCfg = Release|x64
+ {988CACF7-3FCB-4992-BE69-77872AE67DC8}.Release|x64.Build.0 = Release|x64
+ {0A18A071-125E-442F-AFF7-A3F68ABECF99}.All|Win32.ActiveCfg = Release DirectSound|x64
+ {0A18A071-125E-442F-AFF7-A3F68ABECF99}.All|x64.ActiveCfg = Release DirectSound|x64
+ {0A18A071-125E-442F-AFF7-A3F68ABECF99}.All|x64.Build.0 = Release DirectSound|x64
+ {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Debug|Win32.ActiveCfg = Debug|Win32
+ {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Debug|Win32.Build.0 = Debug|Win32
+ {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Debug|x64.ActiveCfg = Debug|x64
+ {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Debug|x64.Build.0 = Debug|x64
+ {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Release|Win32.ActiveCfg = Release|Win32
+ {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Release|Win32.Build.0 = Release|Win32
+ {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Release|x64.ActiveCfg = Release|x64
+ {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Release|x64.Build.0 = Release|x64
+ {08DAD348-9E0A-4A2E-97F1-F1E7E24A7836}.All|Win32.ActiveCfg = Release|x64
+ {08DAD348-9E0A-4A2E-97F1-F1E7E24A7836}.All|x64.ActiveCfg = Release|x64
+ {08DAD348-9E0A-4A2E-97F1-F1E7E24A7836}.All|x64.Build.0 = Release|x64
+ {08DAD348-9E0A-4A2E-97F1-F1E7E24A7836}.Debug|Win32.ActiveCfg = Debug|Win32
+ {08DAD348-9E0A-4A2E-97F1-F1E7E24A7836}.Debug|Win32.Build.0 = Debug|Win32
+ {08DAD348-9E0A-4A2E-97F1-F1E7E24A7836}.Debug|x64.ActiveCfg = Debug|x64
+ {08DAD348-9E0A-4A2E-97F1-F1E7E24A7836}.Debug|x64.Build.0 = Debug|x64
+ {08DAD348-9E0A-4A2E-97F1-F1E7E24A7836}.Release|Win32.ActiveCfg = Release|Win32
+ {08DAD348-9E0A-4A2E-97F1-F1E7E24A7836}.Release|Win32.Build.0 = Release|Win32
+ {08DAD348-9E0A-4A2E-97F1-F1E7E24A7836}.Release|x64.ActiveCfg = Release|x64
+ {08DAD348-9E0A-4A2E-97F1-F1E7E24A7836}.Release|x64.Build.0 = Release|x64
+ {8DEB383C-4091-4F42-A56F-C9E46D552D79}.All|Win32.ActiveCfg = Release Passthrough|x64
+ {8DEB383C-4091-4F42-A56F-C9E46D552D79}.All|x64.ActiveCfg = Release Passthrough|x64
+ {8DEB383C-4091-4F42-A56F-C9E46D552D79}.All|x64.Build.0 = Release Passthrough|x64
+ {8DEB383C-4091-4F42-A56F-C9E46D552D79}.Debug|Win32.ActiveCfg = Debug Passthrough|Win32
+ {8DEB383C-4091-4F42-A56F-C9E46D552D79}.Debug|Win32.Build.0 = Debug Passthrough|Win32
+ {8DEB383C-4091-4F42-A56F-C9E46D552D79}.Debug|x64.ActiveCfg = Debug Passthrough|x64
+ {8DEB383C-4091-4F42-A56F-C9E46D552D79}.Debug|x64.Build.0 = Debug Passthrough|x64
+ {8DEB383C-4091-4F42-A56F-C9E46D552D79}.Release|Win32.ActiveCfg = Release Passthrough|Win32
+ {8DEB383C-4091-4F42-A56F-C9E46D552D79}.Release|Win32.Build.0 = Release Passthrough|Win32
+ {8DEB383C-4091-4F42-A56F-C9E46D552D79}.Release|x64.ActiveCfg = Release Passthrough|x64
+ {8DEB383C-4091-4F42-A56F-C9E46D552D79}.Release|x64.Build.0 = Release Passthrough|x64
+ {2C3C2423-234B-4772-8899-D3B137E5CA35}.All|Win32.ActiveCfg = Release|x64
+ {2C3C2423-234B-4772-8899-D3B137E5CA35}.All|x64.ActiveCfg = Release|x64
+ {2C3C2423-234B-4772-8899-D3B137E5CA35}.All|x64.Build.0 = Release|x64
+ {2C3C2423-234B-4772-8899-D3B137E5CA35}.Debug|Win32.ActiveCfg = Debug|Win32
+ {2C3C2423-234B-4772-8899-D3B137E5CA35}.Debug|Win32.Build.0 = Debug|Win32
+ {2C3C2423-234B-4772-8899-D3B137E5CA35}.Debug|x64.ActiveCfg = Debug|x64
+ {2C3C2423-234B-4772-8899-D3B137E5CA35}.Debug|x64.Build.0 = Debug|x64
+ {2C3C2423-234B-4772-8899-D3B137E5CA35}.Release|Win32.ActiveCfg = Release|Win32
+ {2C3C2423-234B-4772-8899-D3B137E5CA35}.Release|Win32.Build.0 = Release|Win32
+ {2C3C2423-234B-4772-8899-D3B137E5CA35}.Release|x64.ActiveCfg = Release|x64
+ {2C3C2423-234B-4772-8899-D3B137E5CA35}.Release|x64.Build.0 = Release|x64
+ {3850D93A-5F24-4922-BC1C-74D08C37C256}.All|Win32.ActiveCfg = Release|x64
+ {3850D93A-5F24-4922-BC1C-74D08C37C256}.All|x64.ActiveCfg = Release|x64
+ {3850D93A-5F24-4922-BC1C-74D08C37C256}.All|x64.Build.0 = Release|x64
+ {3850D93A-5F24-4922-BC1C-74D08C37C256}.Debug|Win32.ActiveCfg = Debug|Win32
+ {3850D93A-5F24-4922-BC1C-74D08C37C256}.Debug|Win32.Build.0 = Debug|Win32
+ {3850D93A-5F24-4922-BC1C-74D08C37C256}.Debug|x64.ActiveCfg = Debug|x64
+ {3850D93A-5F24-4922-BC1C-74D08C37C256}.Debug|x64.Build.0 = Debug|x64
+ {3850D93A-5F24-4922-BC1C-74D08C37C256}.Release|Win32.ActiveCfg = Release|Win32
+ {3850D93A-5F24-4922-BC1C-74D08C37C256}.Release|Win32.Build.0 = Release|Win32
+ {3850D93A-5F24-4922-BC1C-74D08C37C256}.Release|x64.ActiveCfg = Release|x64
+ {3850D93A-5F24-4922-BC1C-74D08C37C256}.Release|x64.Build.0 = Release|x64
+ {2CA40887-1622-46A1-A7F9-17FD7E7E545B}.All|Win32.ActiveCfg = Release|x64
+ {2CA40887-1622-46A1-A7F9-17FD7E7E545B}.All|x64.ActiveCfg = Release|x64
+ {2CA40887-1622-46A1-A7F9-17FD7E7E545B}.All|x64.Build.0 = Release|x64
+ {2CA40887-1622-46A1-A7F9-17FD7E7E545B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {2CA40887-1622-46A1-A7F9-17FD7E7E545B}.Debug|Win32.Build.0 = Debug|Win32
+ {2CA40887-1622-46A1-A7F9-17FD7E7E545B}.Debug|x64.ActiveCfg = Debug|x64
+ {2CA40887-1622-46A1-A7F9-17FD7E7E545B}.Debug|x64.Build.0 = Debug|x64
+ {2CA40887-1622-46A1-A7F9-17FD7E7E545B}.Release|Win32.ActiveCfg = Release|Win32
+ {2CA40887-1622-46A1-A7F9-17FD7E7E545B}.Release|Win32.Build.0 = Release|Win32
+ {2CA40887-1622-46A1-A7F9-17FD7E7E545B}.Release|x64.ActiveCfg = Release|x64
+ {2CA40887-1622-46A1-A7F9-17FD7E7E545B}.Release|x64.Build.0 = Release|x64
+ {028C7278-05D7-4E18-82FE-BE231B844F41}.All|Win32.ActiveCfg = Release|x64
+ {028C7278-05D7-4E18-82FE-BE231B844F41}.All|x64.ActiveCfg = Release|x64
+ {028C7278-05D7-4E18-82FE-BE231B844F41}.All|x64.Build.0 = Release|x64
+ {028C7278-05D7-4E18-82FE-BE231B844F41}.Debug|Win32.ActiveCfg = Debug|Win32
+ {028C7278-05D7-4E18-82FE-BE231B844F41}.Debug|Win32.Build.0 = Debug|Win32
+ {028C7278-05D7-4E18-82FE-BE231B844F41}.Debug|x64.ActiveCfg = Debug|x64
+ {028C7278-05D7-4E18-82FE-BE231B844F41}.Release|Win32.ActiveCfg = Release|Win32
+ {028C7278-05D7-4E18-82FE-BE231B844F41}.Release|Win32.Build.0 = Release|Win32
+ {028C7278-05D7-4E18-82FE-BE231B844F41}.Release|x64.ActiveCfg = Release|x64
+ {D7F1E3F2-A3F4-474C-8555-15122571AF52}.All|Win32.ActiveCfg = Release|x64
+ {D7F1E3F2-A3F4-474C-8555-15122571AF52}.All|x64.ActiveCfg = Release|x64
+ {D7F1E3F2-A3F4-474C-8555-15122571AF52}.All|x64.Build.0 = Release|x64
+ {D7F1E3F2-A3F4-474C-8555-15122571AF52}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D7F1E3F2-A3F4-474C-8555-15122571AF52}.Debug|Win32.Build.0 = Debug|Win32
+ {D7F1E3F2-A3F4-474C-8555-15122571AF52}.Debug|x64.ActiveCfg = Debug|x64
+ {D7F1E3F2-A3F4-474C-8555-15122571AF52}.Debug|x64.Build.0 = Debug|x64
+ {D7F1E3F2-A3F4-474C-8555-15122571AF52}.Release|Win32.ActiveCfg = Release|Win32
+ {D7F1E3F2-A3F4-474C-8555-15122571AF52}.Release|Win32.Build.0 = Release|Win32
+ {D7F1E3F2-A3F4-474C-8555-15122571AF52}.Release|x64.ActiveCfg = Release|x64
+ {D7F1E3F2-A3F4-474C-8555-15122571AF52}.Release|x64.Build.0 = Release|x64
+ {5BC072DB-3826-48EA-AF34-FE32AA01E83B}.All|Win32.ActiveCfg = Release|x64
+ {5BC072DB-3826-48EA-AF34-FE32AA01E83B}.All|x64.ActiveCfg = Release|x64
+ {5BC072DB-3826-48EA-AF34-FE32AA01E83B}.All|x64.Build.0 = Release|x64
+ {5BC072DB-3826-48EA-AF34-FE32AA01E83B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {5BC072DB-3826-48EA-AF34-FE32AA01E83B}.Debug|Win32.Build.0 = Debug|Win32
+ {5BC072DB-3826-48EA-AF34-FE32AA01E83B}.Debug|x64.ActiveCfg = Debug|x64
+ {5BC072DB-3826-48EA-AF34-FE32AA01E83B}.Debug|x64.Build.0 = Debug|x64
+ {5BC072DB-3826-48EA-AF34-FE32AA01E83B}.Release|Win32.ActiveCfg = Release|Win32
+ {5BC072DB-3826-48EA-AF34-FE32AA01E83B}.Release|Win32.Build.0 = Release|Win32
+ {5BC072DB-3826-48EA-AF34-FE32AA01E83B}.Release|x64.ActiveCfg = Release|x64
+ {5BC072DB-3826-48EA-AF34-FE32AA01E83B}.Release|x64.Build.0 = Release|x64
+ {FA429E98-8B03-45E6-A096-A4BC5E821DE4}.All|Win32.ActiveCfg = Release|x64
+ {FA429E98-8B03-45E6-A096-A4BC5E821DE4}.All|x64.ActiveCfg = Release|x64
+ {FA429E98-8B03-45E6-A096-A4BC5E821DE4}.All|x64.Build.0 = Release|x64
+ {FA429E98-8B03-45E6-A096-A4BC5E821DE4}.Debug|Win32.ActiveCfg = Debug|Win32
+ {FA429E98-8B03-45E6-A096-A4BC5E821DE4}.Debug|Win32.Build.0 = Debug|Win32
+ {FA429E98-8B03-45E6-A096-A4BC5E821DE4}.Debug|x64.ActiveCfg = Debug|x64
+ {FA429E98-8B03-45E6-A096-A4BC5E821DE4}.Debug|x64.Build.0 = Debug|x64
+ {FA429E98-8B03-45E6-A096-A4BC5E821DE4}.Release|Win32.ActiveCfg = Release|Win32
+ {FA429E98-8B03-45E6-A096-A4BC5E821DE4}.Release|Win32.Build.0 = Release|Win32
+ {FA429E98-8B03-45E6-A096-A4BC5E821DE4}.Release|x64.ActiveCfg = Release|x64
+ {FA429E98-8B03-45E6-A096-A4BC5E821DE4}.Release|x64.Build.0 = Release|x64
+ {06E3A538-AB32-44F2-B477-755FF9CB5D37}.All|Win32.ActiveCfg = Release|x64
+ {06E3A538-AB32-44F2-B477-755FF9CB5D37}.All|x64.ActiveCfg = Release|x64
+ {06E3A538-AB32-44F2-B477-755FF9CB5D37}.All|x64.Build.0 = Release|x64
+ {06E3A538-AB32-44F2-B477-755FF9CB5D37}.Debug|Win32.ActiveCfg = Debug|Win32
+ {06E3A538-AB32-44F2-B477-755FF9CB5D37}.Debug|Win32.Build.0 = Debug|Win32
+ {06E3A538-AB32-44F2-B477-755FF9CB5D37}.Debug|x64.ActiveCfg = Debug|x64
+ {06E3A538-AB32-44F2-B477-755FF9CB5D37}.Debug|x64.Build.0 = Debug|x64
+ {06E3A538-AB32-44F2-B477-755FF9CB5D37}.Release|Win32.ActiveCfg = Release|Win32
+ {06E3A538-AB32-44F2-B477-755FF9CB5D37}.Release|Win32.Build.0 = Release|Win32
+ {06E3A538-AB32-44F2-B477-755FF9CB5D37}.Release|x64.ActiveCfg = Release|x64
+ {06E3A538-AB32-44F2-B477-755FF9CB5D37}.Release|x64.Build.0 = Release|x64
+ {6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05}.All|Win32.ActiveCfg = Release|x64
+ {6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05}.All|x64.ActiveCfg = Release|x64
+ {6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05}.All|x64.Build.0 = Release|x64
+ {6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05}.Debug|Win32.ActiveCfg = Debug|Win32
+ {6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05}.Debug|Win32.Build.0 = Debug|Win32
+ {6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05}.Debug|x64.ActiveCfg = Debug|x64
+ {6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05}.Debug|x64.Build.0 = Debug|x64
+ {6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05}.Release|Win32.ActiveCfg = Release|Win32
+ {6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05}.Release|Win32.Build.0 = Release|Win32
+ {6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05}.Release|x64.ActiveCfg = Release|x64
+ {6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05}.Release|x64.Build.0 = Release|x64
+ {A4B122CF-5196-476B-8C0E-D8BD59AC3C14}.All|Win32.ActiveCfg = Release|x64
+ {A4B122CF-5196-476B-8C0E-D8BD59AC3C14}.All|x64.ActiveCfg = Release|x64
+ {A4B122CF-5196-476B-8C0E-D8BD59AC3C14}.All|x64.Build.0 = Release|x64
+ {A4B122CF-5196-476B-8C0E-D8BD59AC3C14}.Debug|Win32.ActiveCfg = Debug|Win32
+ {A4B122CF-5196-476B-8C0E-D8BD59AC3C14}.Debug|Win32.Build.0 = Debug|Win32
+ {A4B122CF-5196-476B-8C0E-D8BD59AC3C14}.Debug|x64.ActiveCfg = Debug|x64
+ {A4B122CF-5196-476B-8C0E-D8BD59AC3C14}.Debug|x64.Build.0 = Debug|x64
+ {A4B122CF-5196-476B-8C0E-D8BD59AC3C14}.Release|Win32.ActiveCfg = Release|Win32
+ {A4B122CF-5196-476B-8C0E-D8BD59AC3C14}.Release|Win32.Build.0 = Release|Win32
+ {A4B122CF-5196-476B-8C0E-D8BD59AC3C14}.Release|x64.ActiveCfg = Release|x64
+ {A4B122CF-5196-476B-8C0E-D8BD59AC3C14}.Release|x64.Build.0 = Release|x64
+ {75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD}.All|Win32.ActiveCfg = Release|x64
+ {75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD}.All|x64.ActiveCfg = Release|x64
+ {75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD}.All|x64.Build.0 = Release|x64
+ {75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD}.Debug|Win32.ActiveCfg = Debug|Win32
+ {75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD}.Debug|Win32.Build.0 = Debug|Win32
+ {75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD}.Debug|x64.ActiveCfg = Debug|x64
+ {75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD}.Debug|x64.Build.0 = Debug|x64
+ {75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD}.Release|Win32.ActiveCfg = Release|Win32
+ {75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD}.Release|Win32.Build.0 = Release|Win32
+ {75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD}.Release|x64.ActiveCfg = Release|x64
+ {75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD}.Release|x64.Build.0 = Release|x64
+ {F6A33240-8F29-48BD-98F0-826995911799}.All|Win32.ActiveCfg = Release|x64
+ {F6A33240-8F29-48BD-98F0-826995911799}.All|x64.ActiveCfg = Release|x64
+ {F6A33240-8F29-48BD-98F0-826995911799}.All|x64.Build.0 = Release|x64
+ {F6A33240-8F29-48BD-98F0-826995911799}.Debug|Win32.ActiveCfg = Debug|Win32
+ {F6A33240-8F29-48BD-98F0-826995911799}.Debug|Win32.Build.0 = Debug|Win32
+ {F6A33240-8F29-48BD-98F0-826995911799}.Debug|x64.ActiveCfg = Debug|x64
+ {F6A33240-8F29-48BD-98F0-826995911799}.Debug|x64.Build.0 = Debug|x64
+ {F6A33240-8F29-48BD-98F0-826995911799}.Release|Win32.ActiveCfg = Release|Win32
+ {F6A33240-8F29-48BD-98F0-826995911799}.Release|Win32.Build.0 = Release|Win32
+ {F6A33240-8F29-48BD-98F0-826995911799}.Release|x64.ActiveCfg = Release|x64
+ {F6A33240-8F29-48BD-98F0-826995911799}.Release|x64.Build.0 = Release|x64
+ {65A6273D-FCAB-4C55-B09E-65100141A5D4}.All|Win32.ActiveCfg = Release|x64
+ {65A6273D-FCAB-4C55-B09E-65100141A5D4}.All|x64.ActiveCfg = Release|x64
+ {65A6273D-FCAB-4C55-B09E-65100141A5D4}.All|x64.Build.0 = Release|x64
+ {65A6273D-FCAB-4C55-B09E-65100141A5D4}.Debug|Win32.ActiveCfg = Debug|Win32
+ {65A6273D-FCAB-4C55-B09E-65100141A5D4}.Debug|Win32.Build.0 = Debug|Win32
+ {65A6273D-FCAB-4C55-B09E-65100141A5D4}.Debug|x64.ActiveCfg = Debug|x64
+ {65A6273D-FCAB-4C55-B09E-65100141A5D4}.Debug|x64.Build.0 = Debug|x64
+ {65A6273D-FCAB-4C55-B09E-65100141A5D4}.Release|Win32.ActiveCfg = Release|Win32
+ {65A6273D-FCAB-4C55-B09E-65100141A5D4}.Release|Win32.Build.0 = Release|Win32
+ {65A6273D-FCAB-4C55-B09E-65100141A5D4}.Release|x64.ActiveCfg = Release|x64
+ {65A6273D-FCAB-4C55-B09E-65100141A5D4}.Release|x64.Build.0 = Release|x64
+ {E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24}.All|Win32.ActiveCfg = Release|x64
+ {E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24}.All|x64.ActiveCfg = Release|x64
+ {E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24}.All|x64.Build.0 = Release|x64
+ {E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24}.Debug|Win32.ActiveCfg = Debug|Win32
+ {E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24}.Debug|Win32.Build.0 = Debug|Win32
+ {E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24}.Debug|x64.ActiveCfg = Debug|x64
+ {E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24}.Debug|x64.Build.0 = Debug|x64
+ {E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24}.Release|Win32.ActiveCfg = Release|Win32
+ {E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24}.Release|Win32.Build.0 = Release|Win32
+ {E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24}.Release|x64.ActiveCfg = Release|x64
+ {E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24}.Release|x64.Build.0 = Release|x64
+ {D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909}.All|Win32.ActiveCfg = Release|x64
+ {D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909}.All|x64.ActiveCfg = Release|x64
+ {D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909}.All|x64.Build.0 = Release|x64
+ {D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909}.Debug|Win32.Build.0 = Debug|Win32
+ {D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909}.Debug|x64.ActiveCfg = Debug|x64
+ {D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909}.Debug|x64.Build.0 = Debug|x64
+ {D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909}.Release|Win32.ActiveCfg = Release|Win32
+ {D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909}.Release|Win32.Build.0 = Release|Win32
+ {D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909}.Release|x64.ActiveCfg = Release|x64
+ {D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909}.Release|x64.Build.0 = Release|x64
+ {44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E}.All|Win32.ActiveCfg = Release|x64
+ {44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E}.All|x64.ActiveCfg = Release|x64
+ {44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E}.All|x64.Build.0 = Release|x64
+ {44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E}.Debug|Win32.ActiveCfg = Debug|Win32
+ {44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E}.Debug|Win32.Build.0 = Debug|Win32
+ {44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E}.Debug|x64.ActiveCfg = Debug|x64
+ {44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E}.Debug|x64.Build.0 = Debug|x64
+ {44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E}.Release|Win32.ActiveCfg = Release|Win32
+ {44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E}.Release|Win32.Build.0 = Release|Win32
+ {44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E}.Release|x64.ActiveCfg = Release|x64
+ {44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E}.Release|x64.Build.0 = Release|x64
+ {6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52}.All|Win32.ActiveCfg = Release|x64
+ {6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52}.All|x64.ActiveCfg = Release|x64
+ {6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52}.All|x64.Build.0 = Release|x64
+ {6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52}.Debug|Win32.ActiveCfg = Debug|Win32
+ {6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52}.Debug|Win32.Build.0 = Debug|Win32
+ {6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52}.Debug|x64.ActiveCfg = Debug|x64
+ {6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52}.Debug|x64.Build.0 = Debug|x64
+ {6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52}.Release|Win32.ActiveCfg = Release|Win32
+ {6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52}.Release|Win32.Build.0 = Release|Win32
+ {6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52}.Release|x64.ActiveCfg = Release|x64
+ {6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52}.Release|x64.Build.0 = Release|x64
+ {E3246D17-E29B-4AB5-962A-C69B0C5837BB}.All|Win32.ActiveCfg = Release|x64
+ {E3246D17-E29B-4AB5-962A-C69B0C5837BB}.All|x64.ActiveCfg = Release|x64
+ {E3246D17-E29B-4AB5-962A-C69B0C5837BB}.All|x64.Build.0 = Release|x64
+ {E3246D17-E29B-4AB5-962A-C69B0C5837BB}.Debug|Win32.ActiveCfg = Debug|Win32
+ {E3246D17-E29B-4AB5-962A-C69B0C5837BB}.Debug|Win32.Build.0 = Debug|Win32
+ {E3246D17-E29B-4AB5-962A-C69B0C5837BB}.Debug|x64.ActiveCfg = Debug|x64
+ {E3246D17-E29B-4AB5-962A-C69B0C5837BB}.Debug|x64.Build.0 = Debug|x64
+ {E3246D17-E29B-4AB5-962A-C69B0C5837BB}.Release|Win32.ActiveCfg = Release|Win32
+ {E3246D17-E29B-4AB5-962A-C69B0C5837BB}.Release|Win32.Build.0 = Release|Win32
+ {E3246D17-E29B-4AB5-962A-C69B0C5837BB}.Release|x64.ActiveCfg = Release|x64
+ {E3246D17-E29B-4AB5-962A-C69B0C5837BB}.Release|x64.Build.0 = Release|x64
+ {36E854E3-CE12-4348-A125-CCF3F9D74813}.All|Win32.ActiveCfg = Release|x64
+ {36E854E3-CE12-4348-A125-CCF3F9D74813}.All|x64.ActiveCfg = Release|x64
+ {36E854E3-CE12-4348-A125-CCF3F9D74813}.All|x64.Build.0 = Release|x64
+ {36E854E3-CE12-4348-A125-CCF3F9D74813}.Debug|Win32.ActiveCfg = Debug|Win32
+ {36E854E3-CE12-4348-A125-CCF3F9D74813}.Debug|Win32.Build.0 = Debug|Win32
+ {36E854E3-CE12-4348-A125-CCF3F9D74813}.Debug|x64.ActiveCfg = Debug|x64
+ {36E854E3-CE12-4348-A125-CCF3F9D74813}.Release|Win32.ActiveCfg = Release|Win32
+ {36E854E3-CE12-4348-A125-CCF3F9D74813}.Release|Win32.Build.0 = Release|Win32
+ {36E854E3-CE12-4348-A125-CCF3F9D74813}.Release|x64.ActiveCfg = Release|x64
+ {7B077E7F-1BE7-4291-AB86-55E527B25CAC}.All|Win32.ActiveCfg = Release|x64
+ {7B077E7F-1BE7-4291-AB86-55E527B25CAC}.All|x64.ActiveCfg = Release|x64
+ {7B077E7F-1BE7-4291-AB86-55E527B25CAC}.All|x64.Build.0 = Release|x64
+ {7B077E7F-1BE7-4291-AB86-55E527B25CAC}.Debug|Win32.ActiveCfg = Debug|Win32
+ {7B077E7F-1BE7-4291-AB86-55E527B25CAC}.Debug|Win32.Build.0 = Debug|Win32
+ {7B077E7F-1BE7-4291-AB86-55E527B25CAC}.Debug|x64.ActiveCfg = Debug|x64
+ {7B077E7F-1BE7-4291-AB86-55E527B25CAC}.Debug|x64.Build.0 = Debug|x64
+ {7B077E7F-1BE7-4291-AB86-55E527B25CAC}.Release|Win32.ActiveCfg = Release|Win32
+ {7B077E7F-1BE7-4291-AB86-55E527B25CAC}.Release|Win32.Build.0 = Release|Win32
+ {7B077E7F-1BE7-4291-AB86-55E527B25CAC}.Release|x64.ActiveCfg = Release|x64
+ {7B077E7F-1BE7-4291-AB86-55E527B25CAC}.Release|x64.Build.0 = Release|x64
+ {4F92B672-DADB-4047-8D6A-4BB3796733FD}.All|Win32.ActiveCfg = Release|Win32
+ {4F92B672-DADB-4047-8D6A-4BB3796733FD}.All|Win32.Build.0 = Release|Win32
+ {4F92B672-DADB-4047-8D6A-4BB3796733FD}.All|x64.ActiveCfg = Release|Win32
+ {4F92B672-DADB-4047-8D6A-4BB3796733FD}.All|x64.Build.0 = Release|Win32
+ {4F92B672-DADB-4047-8D6A-4BB3796733FD}.Debug|Win32.ActiveCfg = Debug|Win32
+ {4F92B672-DADB-4047-8D6A-4BB3796733FD}.Debug|Win32.Build.0 = Debug|Win32
+ {4F92B672-DADB-4047-8D6A-4BB3796733FD}.Debug|x64.ActiveCfg = Debug|Win32
+ {4F92B672-DADB-4047-8D6A-4BB3796733FD}.Debug|x64.Build.0 = Debug|Win32
+ {4F92B672-DADB-4047-8D6A-4BB3796733FD}.Release|Win32.ActiveCfg = Release|Win32
+ {4F92B672-DADB-4047-8D6A-4BB3796733FD}.Release|Win32.Build.0 = Release|Win32
+ {4F92B672-DADB-4047-8D6A-4BB3796733FD}.Release|x64.ActiveCfg = Release|Win32
+ {4F92B672-DADB-4047-8D6A-4BB3796733FD}.Release|x64.Build.0 = Release|Win32
+ {2DEE4895-1134-439C-B688-52203E57D878}.All|Win32.ActiveCfg = Release|Win32
+ {2DEE4895-1134-439C-B688-52203E57D878}.All|Win32.Build.0 = Release|Win32
+ {2DEE4895-1134-439C-B688-52203E57D878}.All|x64.ActiveCfg = Release|Win32
+ {2DEE4895-1134-439C-B688-52203E57D878}.All|x64.Build.0 = Release|Win32
+ {2DEE4895-1134-439C-B688-52203E57D878}.Debug|Win32.ActiveCfg = Debug|Win32
+ {2DEE4895-1134-439C-B688-52203E57D878}.Debug|Win32.Build.0 = Debug|Win32
+ {2DEE4895-1134-439C-B688-52203E57D878}.Debug|x64.ActiveCfg = Debug|Win32
+ {2DEE4895-1134-439C-B688-52203E57D878}.Debug|x64.Build.0 = Debug|Win32
+ {2DEE4895-1134-439C-B688-52203E57D878}.Release|Win32.ActiveCfg = Release|Win32
+ {2DEE4895-1134-439C-B688-52203E57D878}.Release|Win32.Build.0 = Release|Win32
+ {2DEE4895-1134-439C-B688-52203E57D878}.Release|x64.ActiveCfg = Release|Win32
+ {2DEE4895-1134-439C-B688-52203E57D878}.Release|x64.Build.0 = Release|Win32
+ {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}.All|Win32.ActiveCfg = Release|Win32
+ {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}.All|Win32.Build.0 = Release|Win32
+ {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}.All|x64.ActiveCfg = Release|Win32
+ {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}.All|x64.Build.0 = Release|Win32
+ {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}.Debug|Win32.ActiveCfg = Debug|Win32
+ {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}.Debug|Win32.Build.0 = Debug|Win32
+ {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}.Debug|x64.ActiveCfg = Debug|Win32
+ {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}.Debug|x64.Build.0 = Debug|Win32
+ {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}.Release|Win32.ActiveCfg = Release|Win32
+ {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}.Release|Win32.Build.0 = Release|Win32
+ {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}.Release|x64.ActiveCfg = Release|Win32
+ {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}.Release|x64.Build.0 = Release|Win32
+ {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}.All|Win32.ActiveCfg = Debug|x64
+ {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}.All|x64.ActiveCfg = Debug|x64
+ {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}.All|x64.Build.0 = Debug|x64
+ {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}.Debug|Win32.ActiveCfg = Debug|Win32
+ {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}.Debug|Win32.Build.0 = Debug|Win32
+ {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}.Debug|x64.ActiveCfg = Debug|x64
+ {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}.Debug|x64.Build.0 = Debug|x64
+ {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}.Release|Win32.ActiveCfg = Release|Win32
+ {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}.Release|Win32.Build.0 = Release|Win32
+ {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}.Release|x64.ActiveCfg = Release|x64
+ {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}.Release|x64.Build.0 = Release|x64
+ {94001A0E-A837-445C-8004-F918F10D0226}.All|Win32.ActiveCfg = Debug|x64
+ {94001A0E-A837-445C-8004-F918F10D0226}.All|x64.ActiveCfg = Debug|x64
+ {94001A0E-A837-445C-8004-F918F10D0226}.All|x64.Build.0 = Debug|x64
+ {94001A0E-A837-445C-8004-F918F10D0226}.Debug|Win32.ActiveCfg = Debug|Win32
+ {94001A0E-A837-445C-8004-F918F10D0226}.Debug|Win32.Build.0 = Debug|Win32
+ {94001A0E-A837-445C-8004-F918F10D0226}.Debug|x64.ActiveCfg = Debug|x64
+ {94001A0E-A837-445C-8004-F918F10D0226}.Debug|x64.Build.0 = Debug|x64
+ {94001A0E-A837-445C-8004-F918F10D0226}.Release|Win32.ActiveCfg = Release|Win32
+ {94001A0E-A837-445C-8004-F918F10D0226}.Release|Win32.Build.0 = Release|Win32
+ {94001A0E-A837-445C-8004-F918F10D0226}.Release|x64.ActiveCfg = Release|x64
+ {94001A0E-A837-445C-8004-F918F10D0226}.Release|x64.Build.0 = Release|x64
+ {2286DA73-9FC5-45BC-A508-85994C3317AB}.All|Win32.ActiveCfg = Release|x64
+ {2286DA73-9FC5-45BC-A508-85994C3317AB}.All|x64.ActiveCfg = Release|x64
+ {2286DA73-9FC5-45BC-A508-85994C3317AB}.All|x64.Build.0 = Release|x64
+ {2286DA73-9FC5-45BC-A508-85994C3317AB}.Debug|Win32.ActiveCfg = Debug|Win32
+ {2286DA73-9FC5-45BC-A508-85994C3317AB}.Debug|Win32.Build.0 = Debug|Win32
+ {2286DA73-9FC5-45BC-A508-85994C3317AB}.Debug|x64.ActiveCfg = Debug|x64
+ {2286DA73-9FC5-45BC-A508-85994C3317AB}.Debug|x64.Build.0 = Debug|x64
+ {2286DA73-9FC5-45BC-A508-85994C3317AB}.Release|Win32.ActiveCfg = Release|Win32
+ {2286DA73-9FC5-45BC-A508-85994C3317AB}.Release|Win32.Build.0 = Release|Win32
+ {2286DA73-9FC5-45BC-A508-85994C3317AB}.Release|x64.ActiveCfg = Release|x64
+ {2286DA73-9FC5-45BC-A508-85994C3317AB}.Release|x64.Build.0 = Release|x64
+ {3CE1DC99-8246-4DB1-A709-74F19F08EC67}.All|Win32.ActiveCfg = Release|Win32
+ {3CE1DC99-8246-4DB1-A709-74F19F08EC67}.All|Win32.Build.0 = Release|Win32
+ {3CE1DC99-8246-4DB1-A709-74F19F08EC67}.All|x64.ActiveCfg = Release|Win32
+ {3CE1DC99-8246-4DB1-A709-74F19F08EC67}.All|x64.Build.0 = Release|Win32
+ {3CE1DC99-8246-4DB1-A709-74F19F08EC67}.Debug|Win32.ActiveCfg = Debug|Win32
+ {3CE1DC99-8246-4DB1-A709-74F19F08EC67}.Debug|Win32.Build.0 = Debug|Win32
+ {3CE1DC99-8246-4DB1-A709-74F19F08EC67}.Debug|x64.ActiveCfg = Debug|Win32
+ {3CE1DC99-8246-4DB1-A709-74F19F08EC67}.Debug|x64.Build.0 = Debug|Win32
+ {3CE1DC99-8246-4DB1-A709-74F19F08EC67}.Release|Win32.ActiveCfg = Release|Win32
+ {3CE1DC99-8246-4DB1-A709-74F19F08EC67}.Release|Win32.Build.0 = Release|Win32
+ {3CE1DC99-8246-4DB1-A709-74F19F08EC67}.Release|x64.ActiveCfg = Release|Win32
+ {3CE1DC99-8246-4DB1-A709-74F19F08EC67}.Release|x64.Build.0 = Release|Win32
+ {87A1FE3D-F410-4C8E-9591-8C625985BC70}.All|Win32.ActiveCfg = Release|Win32
+ {87A1FE3D-F410-4C8E-9591-8C625985BC70}.All|x64.ActiveCfg = Release|Win32
+ {87A1FE3D-F410-4C8E-9591-8C625985BC70}.Debug|Win32.ActiveCfg = Debug|Win32
+ {87A1FE3D-F410-4C8E-9591-8C625985BC70}.Debug|x64.ActiveCfg = Debug|Win32
+ {87A1FE3D-F410-4C8E-9591-8C625985BC70}.Release|Win32.ActiveCfg = Release|Win32
+ {87A1FE3D-F410-4C8E-9591-8C625985BC70}.Release|x64.ActiveCfg = Release|Win32
+ {7A8D8174-B355-4114-AFC1-04777CB9DE0A}.All|Win32.ActiveCfg = Release|Win32
+ {7A8D8174-B355-4114-AFC1-04777CB9DE0A}.All|Win32.Build.0 = Release|Win32
+ {7A8D8174-B355-4114-AFC1-04777CB9DE0A}.All|x64.ActiveCfg = Release|Win32
+ {7A8D8174-B355-4114-AFC1-04777CB9DE0A}.All|x64.Build.0 = Release|Win32
+ {7A8D8174-B355-4114-AFC1-04777CB9DE0A}.Debug|Win32.ActiveCfg = Debug|Win32
+ {7A8D8174-B355-4114-AFC1-04777CB9DE0A}.Debug|Win32.Build.0 = Debug|Win32
+ {7A8D8174-B355-4114-AFC1-04777CB9DE0A}.Debug|x64.ActiveCfg = Debug|x64
+ {7A8D8174-B355-4114-AFC1-04777CB9DE0A}.Debug|x64.Build.0 = Debug|x64
+ {7A8D8174-B355-4114-AFC1-04777CB9DE0A}.Release|Win32.ActiveCfg = Release|Win32
+ {7A8D8174-B355-4114-AFC1-04777CB9DE0A}.Release|Win32.Build.0 = Release|Win32
+ {7A8D8174-B355-4114-AFC1-04777CB9DE0A}.Release|x64.ActiveCfg = Release|x64
+ {7A8D8174-B355-4114-AFC1-04777CB9DE0A}.Release|x64.Build.0 = Release|x64
+ {7EB71250-F002-4ED8-92CA-CA218114537A}.All|Win32.ActiveCfg = Release|Win32
+ {7EB71250-F002-4ED8-92CA-CA218114537A}.All|x64.ActiveCfg = Release|Win32
+ {7EB71250-F002-4ED8-92CA-CA218114537A}.Debug|Win32.ActiveCfg = Debug|Win32
+ {7EB71250-F002-4ED8-92CA-CA218114537A}.Debug|x64.ActiveCfg = Debug|x64
+ {7EB71250-F002-4ED8-92CA-CA218114537A}.Release|Win32.ActiveCfg = Release|Win32
+ {7EB71250-F002-4ED8-92CA-CA218114537A}.Release|x64.ActiveCfg = Release|x64
+ {6E49F6C2-ADDA-4BFB-81FE-AB9AF51B455F}.All|Win32.ActiveCfg = Release|Win32
+ {6E49F6C2-ADDA-4BFB-81FE-AB9AF51B455F}.All|x64.ActiveCfg = Release|Win32
+ {6E49F6C2-ADDA-4BFB-81FE-AB9AF51B455F}.Debug|Win32.ActiveCfg = Debug|Win32
+ {6E49F6C2-ADDA-4BFB-81FE-AB9AF51B455F}.Debug|x64.ActiveCfg = Debug|Win32
+ {6E49F6C2-ADDA-4BFB-81FE-AB9AF51B455F}.Release|Win32.ActiveCfg = Release|Win32
+ {6E49F6C2-ADDA-4BFB-81FE-AB9AF51B455F}.Release|x64.ActiveCfg = Release|Win32
+ {464AAB78-5489-4916-BE51-BF8D61822311}.All|Win32.ActiveCfg = Release|Win32
+ {464AAB78-5489-4916-BE51-BF8D61822311}.All|x64.ActiveCfg = Release|Win32
+ {464AAB78-5489-4916-BE51-BF8D61822311}.Debug|Win32.ActiveCfg = Debug|Win32
+ {464AAB78-5489-4916-BE51-BF8D61822311}.Debug|x64.ActiveCfg = Debug|x64
+ {464AAB78-5489-4916-BE51-BF8D61822311}.Release|Win32.ActiveCfg = Release|Win32
+ {464AAB78-5489-4916-BE51-BF8D61822311}.Release|x64.ActiveCfg = Release|x64
+ {0AD1177E-1FD8-4643-9391-431467A11084}.All|Win32.ActiveCfg = Release|x64
+ {0AD1177E-1FD8-4643-9391-431467A11084}.All|x64.ActiveCfg = Release|x64
+ {0AD1177E-1FD8-4643-9391-431467A11084}.All|x64.Build.0 = Release|x64
+ {0AD1177E-1FD8-4643-9391-431467A11084}.Debug|Win32.ActiveCfg = Debug|Win32
+ {0AD1177E-1FD8-4643-9391-431467A11084}.Debug|Win32.Build.0 = Debug|Win32
+ {0AD1177E-1FD8-4643-9391-431467A11084}.Debug|x64.ActiveCfg = Debug|x64
+ {0AD1177E-1FD8-4643-9391-431467A11084}.Debug|x64.Build.0 = Debug|x64
+ {0AD1177E-1FD8-4643-9391-431467A11084}.Release|Win32.ActiveCfg = Release|Win32
+ {0AD1177E-1FD8-4643-9391-431467A11084}.Release|Win32.Build.0 = Release|Win32
+ {0AD1177E-1FD8-4643-9391-431467A11084}.Release|x64.ActiveCfg = Release|x64
+ {0AD1177E-1FD8-4643-9391-431467A11084}.Release|x64.Build.0 = Release|x64
+ {66444AEE-554C-11DD-A9F0-8C5D56D89593}.All|Win32.ActiveCfg = Release Static|x64
+ {66444AEE-554C-11DD-A9F0-8C5D56D89593}.All|x64.ActiveCfg = Release Static|x64
+ {66444AEE-554C-11DD-A9F0-8C5D56D89593}.All|x64.Build.0 = Release Static|x64
+ {66444AEE-554C-11DD-A9F0-8C5D56D89593}.Debug|Win32.ActiveCfg = Debug|Win32
+ {66444AEE-554C-11DD-A9F0-8C5D56D89593}.Debug|x64.ActiveCfg = Debug|x64
+ {66444AEE-554C-11DD-A9F0-8C5D56D89593}.Release|Win32.ActiveCfg = Release|Win32
+ {66444AEE-554C-11DD-A9F0-8C5D56D89593}.Release|x64.ActiveCfg = Release|x64
+ {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}.All|Win32.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}.All|Win32.Build.0 = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}.All|x64.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}.All|x64.Build.0 = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}.Debug|Win32.Build.0 = Debug|Win32
+ {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}.Debug|x64.ActiveCfg = Debug|Win32
+ {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}.Debug|x64.Build.0 = Debug|Win32
+ {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}.Release|Win32.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}.Release|Win32.Build.0 = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}.Release|x64.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}.Release|x64.Build.0 = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.All|Win32.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.All|Win32.Build.0 = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.All|x64.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.All|x64.Build.0 = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.Debug|Win32.Build.0 = Debug|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.Debug|x64.ActiveCfg = Debug|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.Debug|x64.Build.0 = Debug|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.Release|Win32.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.Release|Win32.Build.0 = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.Release|x64.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.Release|x64.Build.0 = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}.All|Win32.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}.All|Win32.Build.0 = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}.All|x64.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}.All|x64.Build.0 = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}.Debug|Win32.Build.0 = Debug|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}.Debug|x64.ActiveCfg = Debug|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}.Debug|x64.Build.0 = Debug|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}.Release|Win32.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}.Release|Win32.Build.0 = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}.Release|x64.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}.Release|x64.Build.0 = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}.All|Win32.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}.All|Win32.Build.0 = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}.All|x64.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}.All|x64.Build.0 = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}.Debug|Win32.Build.0 = Debug|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}.Debug|x64.ActiveCfg = Debug|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}.Debug|x64.Build.0 = Debug|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}.Release|Win32.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}.Release|Win32.Build.0 = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}.Release|x64.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}.Release|x64.Build.0 = Release|Win32
+ {E316772F-5D8F-4F2A-8F71-094C3E859D34}.All|Win32.ActiveCfg = Debug|x64
+ {E316772F-5D8F-4F2A-8F71-094C3E859D34}.All|x64.ActiveCfg = Debug|x64
+ {E316772F-5D8F-4F2A-8F71-094C3E859D34}.All|x64.Build.0 = Debug|x64
+ {E316772F-5D8F-4F2A-8F71-094C3E859D34}.Debug|Win32.ActiveCfg = Debug|Win32
+ {E316772F-5D8F-4F2A-8F71-094C3E859D34}.Debug|Win32.Build.0 = Debug|Win32
+ {E316772F-5D8F-4F2A-8F71-094C3E859D34}.Debug|x64.ActiveCfg = Debug|x64
+ {E316772F-5D8F-4F2A-8F71-094C3E859D34}.Debug|x64.Build.0 = Debug|x64
+ {E316772F-5D8F-4F2A-8F71-094C3E859D34}.Release|Win32.ActiveCfg = Release|Win32
+ {E316772F-5D8F-4F2A-8F71-094C3E859D34}.Release|Win32.Build.0 = Release|Win32
+ {E316772F-5D8F-4F2A-8F71-094C3E859D34}.Release|x64.ActiveCfg = Release|x64
+ {E316772F-5D8F-4F2A-8F71-094C3E859D34}.Release|x64.Build.0 = Release|x64
+ {D3D8B329-20BE-475E-9E83-653CEA0E0EF5}.All|Win32.ActiveCfg = Debug|x64
+ {D3D8B329-20BE-475E-9E83-653CEA0E0EF5}.All|x64.ActiveCfg = Debug|x64
+ {D3D8B329-20BE-475E-9E83-653CEA0E0EF5}.All|x64.Build.0 = Debug|x64
+ {D3D8B329-20BE-475E-9E83-653CEA0E0EF5}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D3D8B329-20BE-475E-9E83-653CEA0E0EF5}.Debug|Win32.Build.0 = Debug|Win32
+ {D3D8B329-20BE-475E-9E83-653CEA0E0EF5}.Debug|x64.ActiveCfg = Debug|x64
+ {D3D8B329-20BE-475E-9E83-653CEA0E0EF5}.Debug|x64.Build.0 = Debug|x64
+ {D3D8B329-20BE-475E-9E83-653CEA0E0EF5}.Release|Win32.ActiveCfg = Release|Win32
+ {D3D8B329-20BE-475E-9E83-653CEA0E0EF5}.Release|Win32.Build.0 = Release|Win32
+ {D3D8B329-20BE-475E-9E83-653CEA0E0EF5}.Release|x64.ActiveCfg = Release|x64
+ {D3D8B329-20BE-475E-9E83-653CEA0E0EF5}.Release|x64.Build.0 = Release|x64
+ {38FE0559-9910-43A8-9E45-3E5004C27692}.All|Win32.ActiveCfg = Release|x64
+ {38FE0559-9910-43A8-9E45-3E5004C27692}.All|x64.ActiveCfg = Release|x64
+ {38FE0559-9910-43A8-9E45-3E5004C27692}.All|x64.Build.0 = Release|x64
+ {38FE0559-9910-43A8-9E45-3E5004C27692}.Debug|Win32.ActiveCfg = Debug|Win32
+ {38FE0559-9910-43A8-9E45-3E5004C27692}.Debug|Win32.Build.0 = Debug|Win32
+ {38FE0559-9910-43A8-9E45-3E5004C27692}.Debug|x64.ActiveCfg = Debug|x64
+ {38FE0559-9910-43A8-9E45-3E5004C27692}.Debug|x64.Build.0 = Debug|x64
+ {38FE0559-9910-43A8-9E45-3E5004C27692}.Release|Win32.ActiveCfg = Release|Win32
+ {38FE0559-9910-43A8-9E45-3E5004C27692}.Release|Win32.Build.0 = Release|Win32
+ {38FE0559-9910-43A8-9E45-3E5004C27692}.Release|x64.ActiveCfg = Release|x64
+ {38FE0559-9910-43A8-9E45-3E5004C27692}.Release|x64.Build.0 = Release|x64
+ {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4}.All|Win32.ActiveCfg = Debug|x64
+ {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4}.All|x64.ActiveCfg = Debug|x64
+ {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4}.All|x64.Build.0 = Debug|x64
+ {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4}.Debug|Win32.ActiveCfg = Debug|Win32
+ {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4}.Debug|Win32.Build.0 = Debug|Win32
+ {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4}.Debug|x64.ActiveCfg = Debug|x64
+ {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4}.Debug|x64.Build.0 = Debug|x64
+ {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4}.Release|Win32.ActiveCfg = Release|Win32
+ {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4}.Release|Win32.Build.0 = Release|Win32
+ {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4}.Release|x64.ActiveCfg = Release|x64
+ {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4}.Release|x64.Build.0 = Release|x64
+ {2A3D00C6-588D-4E86-81AC-9EF5EDE86E03}.All|Win32.ActiveCfg = Release|x64
+ {2A3D00C6-588D-4E86-81AC-9EF5EDE86E03}.All|x64.ActiveCfg = Release|x64
+ {2A3D00C6-588D-4E86-81AC-9EF5EDE86E03}.All|x64.Build.0 = Release|x64
+ {2A3D00C6-588D-4E86-81AC-9EF5EDE86E03}.Debug|Win32.ActiveCfg = Debug|Win32
+ {2A3D00C6-588D-4E86-81AC-9EF5EDE86E03}.Debug|Win32.Build.0 = Debug|Win32
+ {2A3D00C6-588D-4E86-81AC-9EF5EDE86E03}.Debug|x64.ActiveCfg = Debug|x64
+ {2A3D00C6-588D-4E86-81AC-9EF5EDE86E03}.Debug|x64.Build.0 = Debug|x64
+ {2A3D00C6-588D-4E86-81AC-9EF5EDE86E03}.Release|Win32.ActiveCfg = Release|Win32
+ {2A3D00C6-588D-4E86-81AC-9EF5EDE86E03}.Release|Win32.Build.0 = Release|Win32
+ {2A3D00C6-588D-4E86-81AC-9EF5EDE86E03}.Release|x64.ActiveCfg = Release|x64
+ {2A3D00C6-588D-4E86-81AC-9EF5EDE86E03}.Release|x64.Build.0 = Release|x64
+ {B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E}.All|Win32.ActiveCfg = Release|x64
+ {B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E}.All|x64.ActiveCfg = Release|x64
+ {B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E}.All|x64.Build.0 = Release|x64
+ {B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E}.Debug|Win32.ActiveCfg = Debug|Win32
+ {B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E}.Debug|Win32.Build.0 = Debug|Win32
+ {B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E}.Debug|x64.ActiveCfg = Debug|x64
+ {B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E}.Debug|x64.Build.0 = Debug|x64
+ {B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E}.Release|Win32.ActiveCfg = Release|Win32
+ {B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E}.Release|Win32.Build.0 = Release|Win32
+ {B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E}.Release|x64.ActiveCfg = Release|x64
+ {B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E}.Release|x64.Build.0 = Release|x64
+ {7B42BDA1-72C0-4378-A9B6-5C530F8CD61E}.All|Win32.ActiveCfg = Release_Mono|x64
+ {7B42BDA1-72C0-4378-A9B6-5C530F8CD61E}.All|x64.ActiveCfg = Release_Mono|x64
+ {7B42BDA1-72C0-4378-A9B6-5C530F8CD61E}.All|x64.Build.0 = Release_Mono|x64
+ {7B42BDA1-72C0-4378-A9B6-5C530F8CD61E}.Debug|Win32.ActiveCfg = Debug_CLR|Win32
+ {7B42BDA1-72C0-4378-A9B6-5C530F8CD61E}.Debug|Win32.Build.0 = Debug_CLR|Win32
+ {7B42BDA1-72C0-4378-A9B6-5C530F8CD61E}.Debug|x64.ActiveCfg = Debug_CLR|x64
+ {7B42BDA1-72C0-4378-A9B6-5C530F8CD61E}.Debug|x64.Build.0 = Debug_CLR|x64
+ {7B42BDA1-72C0-4378-A9B6-5C530F8CD61E}.Release|Win32.ActiveCfg = Release_CLR|Win32
+ {7B42BDA1-72C0-4378-A9B6-5C530F8CD61E}.Release|Win32.Build.0 = Release_CLR|Win32
+ {7B42BDA1-72C0-4378-A9B6-5C530F8CD61E}.Release|x64.ActiveCfg = Release_CLR|x64
+ {7B42BDA1-72C0-4378-A9B6-5C530F8CD61E}.Release|x64.Build.0 = Release_CLR|x64
+ {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.All|Win32.ActiveCfg = Release|Any CPU
+ {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.All|x64.ActiveCfg = Release|Any CPU
+ {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.Debug|Win32.Build.0 = Debug|Any CPU
+ {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.Debug|x64.ActiveCfg = Debug|x64
+ {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.Debug|x64.Build.0 = Debug|x64
+ {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.Release|Win32.ActiveCfg = Release|Any CPU
+ {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.Release|Win32.Build.0 = Release|Any CPU
+ {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.Release|x64.ActiveCfg = Release|x64
+ {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.Release|x64.Build.0 = Release|x64
+ {E796E337-DE78-4303-8614-9A590862EE95}.All|Win32.ActiveCfg = Release|Win32
+ {E796E337-DE78-4303-8614-9A590862EE95}.All|Win32.Build.0 = Release|Win32
+ {E796E337-DE78-4303-8614-9A590862EE95}.All|x64.ActiveCfg = Release|Win32
+ {E796E337-DE78-4303-8614-9A590862EE95}.All|x64.Build.0 = Release|Win32
+ {E796E337-DE78-4303-8614-9A590862EE95}.Debug|Win32.ActiveCfg = Debug|Win32
+ {E796E337-DE78-4303-8614-9A590862EE95}.Debug|Win32.Build.0 = Debug|Win32
+ {E796E337-DE78-4303-8614-9A590862EE95}.Debug|x64.ActiveCfg = Debug|Win32
+ {E796E337-DE78-4303-8614-9A590862EE95}.Debug|x64.Build.0 = Debug|Win32
+ {E796E337-DE78-4303-8614-9A590862EE95}.Release|Win32.ActiveCfg = Release|Win32
+ {E796E337-DE78-4303-8614-9A590862EE95}.Release|Win32.Build.0 = Release|Win32
+ {E796E337-DE78-4303-8614-9A590862EE95}.Release|x64.ActiveCfg = Release|Win32
+ {E796E337-DE78-4303-8614-9A590862EE95}.Release|x64.Build.0 = Release|Win32
+ {419C8F80-D858-4B48-A25C-AF4007608137}.All|Win32.ActiveCfg = Release|x64
+ {419C8F80-D858-4B48-A25C-AF4007608137}.All|x64.ActiveCfg = Release|x64
+ {419C8F80-D858-4B48-A25C-AF4007608137}.All|x64.Build.0 = Release|x64
+ {419C8F80-D858-4B48-A25C-AF4007608137}.Debug|Win32.ActiveCfg = Debug|Win32
+ {419C8F80-D858-4B48-A25C-AF4007608137}.Debug|Win32.Build.0 = Debug|Win32
+ {419C8F80-D858-4B48-A25C-AF4007608137}.Debug|x64.ActiveCfg = Debug|x64
+ {419C8F80-D858-4B48-A25C-AF4007608137}.Debug|x64.Build.0 = Debug|x64
+ {419C8F80-D858-4B48-A25C-AF4007608137}.Release|Win32.ActiveCfg = Release|Win32
+ {419C8F80-D858-4B48-A25C-AF4007608137}.Release|Win32.Build.0 = Release|Win32
+ {419C8F80-D858-4B48-A25C-AF4007608137}.Release|x64.ActiveCfg = Release|x64
+ {419C8F80-D858-4B48-A25C-AF4007608137}.Release|x64.Build.0 = Release|x64
+ {B3F424EC-3D8F-417C-B244-3919D5E1A577}.All|Win32.ActiveCfg = Release|x64
+ {B3F424EC-3D8F-417C-B244-3919D5E1A577}.All|x64.ActiveCfg = Release|x64
+ {B3F424EC-3D8F-417C-B244-3919D5E1A577}.All|x64.Build.0 = Release|x64
+ {B3F424EC-3D8F-417C-B244-3919D5E1A577}.Debug|Win32.ActiveCfg = Debug|Win32
+ {B3F424EC-3D8F-417C-B244-3919D5E1A577}.Debug|Win32.Build.0 = Debug|Win32
+ {B3F424EC-3D8F-417C-B244-3919D5E1A577}.Debug|x64.ActiveCfg = Debug|x64
+ {B3F424EC-3D8F-417C-B244-3919D5E1A577}.Debug|x64.Build.0 = Debug|x64
+ {B3F424EC-3D8F-417C-B244-3919D5E1A577}.Release|Win32.ActiveCfg = Release|Win32
+ {B3F424EC-3D8F-417C-B244-3919D5E1A577}.Release|Win32.Build.0 = Release|Win32
+ {B3F424EC-3D8F-417C-B244-3919D5E1A577}.Release|x64.ActiveCfg = Release|x64
+ {B3F424EC-3D8F-417C-B244-3919D5E1A577}.Release|x64.Build.0 = Release|x64
+ {14E4A972-9CFB-436D-B0A5-4943F3F80D47}.All|Win32.ActiveCfg = Release|x64
+ {14E4A972-9CFB-436D-B0A5-4943F3F80D47}.All|x64.ActiveCfg = Release|x64
+ {14E4A972-9CFB-436D-B0A5-4943F3F80D47}.All|x64.Build.0 = Release|x64
+ {14E4A972-9CFB-436D-B0A5-4943F3F80D47}.Debug|Win32.ActiveCfg = Debug|Win32
+ {14E4A972-9CFB-436D-B0A5-4943F3F80D47}.Debug|Win32.Build.0 = Debug|Win32
+ {14E4A972-9CFB-436D-B0A5-4943F3F80D47}.Debug|x64.ActiveCfg = Debug|x64
+ {14E4A972-9CFB-436D-B0A5-4943F3F80D47}.Debug|x64.Build.0 = Debug|x64
+ {14E4A972-9CFB-436D-B0A5-4943F3F80D47}.Release|Win32.ActiveCfg = Release|Win32
+ {14E4A972-9CFB-436D-B0A5-4943F3F80D47}.Release|Win32.Build.0 = Release|Win32
+ {14E4A972-9CFB-436D-B0A5-4943F3F80D47}.Release|x64.ActiveCfg = Release|x64
+ {14E4A972-9CFB-436D-B0A5-4943F3F80D47}.Release|x64.Build.0 = Release|x64
+ {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C}.All|Win32.ActiveCfg = Release|x64
+ {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C}.All|x64.ActiveCfg = Release|x64
+ {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C}.All|x64.Build.0 = Release|x64
+ {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C}.Debug|Win32.ActiveCfg = Debug|Win32
+ {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C}.Debug|Win32.Build.0 = Debug|Win32
+ {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C}.Debug|x64.ActiveCfg = Debug|x64
+ {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C}.Debug|x64.Build.0 = Debug|x64
+ {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C}.Release|Win32.ActiveCfg = Release|Win32
+ {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C}.Release|Win32.Build.0 = Release|Win32
+ {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C}.Release|x64.ActiveCfg = Release|x64
+ {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C}.Release|x64.Build.0 = Release|x64
+ {0B6C905B-142E-4999-B39D-92FF7951E921}.All|Win32.ActiveCfg = Release|x64
+ {0B6C905B-142E-4999-B39D-92FF7951E921}.All|x64.ActiveCfg = Release|x64
+ {0B6C905B-142E-4999-B39D-92FF7951E921}.All|x64.Build.0 = Release|x64
+ {0B6C905B-142E-4999-B39D-92FF7951E921}.Debug|Win32.ActiveCfg = Debug|Win32
+ {0B6C905B-142E-4999-B39D-92FF7951E921}.Debug|Win32.Build.0 = Debug|Win32
+ {0B6C905B-142E-4999-B39D-92FF7951E921}.Debug|x64.ActiveCfg = Debug|x64
+ {0B6C905B-142E-4999-B39D-92FF7951E921}.Debug|x64.Build.0 = Debug|x64
+ {0B6C905B-142E-4999-B39D-92FF7951E921}.Release|Win32.ActiveCfg = Release|Win32
+ {0B6C905B-142E-4999-B39D-92FF7951E921}.Release|Win32.Build.0 = Release|Win32
+ {0B6C905B-142E-4999-B39D-92FF7951E921}.Release|x64.ActiveCfg = Release|x64
+ {0B6C905B-142E-4999-B39D-92FF7951E921}.Release|x64.Build.0 = Release|x64
+ {CF405366-9558-4AE8-90EF-5E21B51CCB4E}.All|Win32.ActiveCfg = Release|x64
+ {CF405366-9558-4AE8-90EF-5E21B51CCB4E}.All|x64.ActiveCfg = Release|x64
+ {CF405366-9558-4AE8-90EF-5E21B51CCB4E}.All|x64.Build.0 = Release|x64
+ {CF405366-9558-4AE8-90EF-5E21B51CCB4E}.Debug|Win32.ActiveCfg = Debug|Win32
+ {CF405366-9558-4AE8-90EF-5E21B51CCB4E}.Debug|Win32.Build.0 = Debug|Win32
+ {CF405366-9558-4AE8-90EF-5E21B51CCB4E}.Debug|x64.ActiveCfg = Debug|x64
+ {CF405366-9558-4AE8-90EF-5E21B51CCB4E}.Debug|x64.Build.0 = Debug|x64
+ {CF405366-9558-4AE8-90EF-5E21B51CCB4E}.Release|Win32.ActiveCfg = Release|Win32
+ {CF405366-9558-4AE8-90EF-5E21B51CCB4E}.Release|Win32.Build.0 = Release|Win32
+ {CF405366-9558-4AE8-90EF-5E21B51CCB4E}.Release|x64.ActiveCfg = Release|x64
+ {CF405366-9558-4AE8-90EF-5E21B51CCB4E}.Release|x64.Build.0 = Release|x64
+ {D2FB8043-D208-4AEE-8F18-3B5857C871B9}.All|Win32.ActiveCfg = Release|x64
+ {D2FB8043-D208-4AEE-8F18-3B5857C871B9}.All|x64.ActiveCfg = Release|x64
+ {D2FB8043-D208-4AEE-8F18-3B5857C871B9}.All|x64.Build.0 = Release|x64
+ {D2FB8043-D208-4AEE-8F18-3B5857C871B9}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D2FB8043-D208-4AEE-8F18-3B5857C871B9}.Debug|Win32.Build.0 = Debug|Win32
+ {D2FB8043-D208-4AEE-8F18-3B5857C871B9}.Debug|x64.ActiveCfg = Debug|x64
+ {D2FB8043-D208-4AEE-8F18-3B5857C871B9}.Debug|x64.Build.0 = Debug|x64
+ {D2FB8043-D208-4AEE-8F18-3B5857C871B9}.Release|Win32.ActiveCfg = Release|Win32
+ {D2FB8043-D208-4AEE-8F18-3B5857C871B9}.Release|Win32.Build.0 = Release|Win32
+ {D2FB8043-D208-4AEE-8F18-3B5857C871B9}.Release|x64.ActiveCfg = Release|x64
+ {D2FB8043-D208-4AEE-8F18-3B5857C871B9}.Release|x64.Build.0 = Release|x64
+ {329FD5B0-EF28-4606-86D0-F6EA21CF8E36}.All|Win32.ActiveCfg = Release|x64
+ {329FD5B0-EF28-4606-86D0-F6EA21CF8E36}.All|x64.ActiveCfg = Release|x64
+ {329FD5B0-EF28-4606-86D0-F6EA21CF8E36}.All|x64.Build.0 = Release|x64
+ {329FD5B0-EF28-4606-86D0-F6EA21CF8E36}.Debug|Win32.ActiveCfg = Debug|Win32
+ {329FD5B0-EF28-4606-86D0-F6EA21CF8E36}.Debug|Win32.Build.0 = Debug|Win32
+ {329FD5B0-EF28-4606-86D0-F6EA21CF8E36}.Debug|x64.ActiveCfg = Debug|x64
+ {329FD5B0-EF28-4606-86D0-F6EA21CF8E36}.Debug|x64.Build.0 = Debug|x64
+ {329FD5B0-EF28-4606-86D0-F6EA21CF8E36}.Release|Win32.ActiveCfg = Release|Win32
+ {329FD5B0-EF28-4606-86D0-F6EA21CF8E36}.Release|Win32.Build.0 = Release|Win32
+ {329FD5B0-EF28-4606-86D0-F6EA21CF8E36}.Release|x64.ActiveCfg = Release|x64
+ {329FD5B0-EF28-4606-86D0-F6EA21CF8E36}.Release|x64.Build.0 = Release|x64
+ {1A3793D1-05D1-4B57-9B0F-5AF3E79DC439}.All|Win32.ActiveCfg = Release|x64
+ {1A3793D1-05D1-4B57-9B0F-5AF3E79DC439}.All|x64.ActiveCfg = Release|x64
+ {1A3793D1-05D1-4B57-9B0F-5AF3E79DC439}.All|x64.Build.0 = Release|x64
+ {1A3793D1-05D1-4B57-9B0F-5AF3E79DC439}.Debug|Win32.ActiveCfg = Debug|Win32
+ {1A3793D1-05D1-4B57-9B0F-5AF3E79DC439}.Debug|Win32.Build.0 = Debug|Win32
+ {1A3793D1-05D1-4B57-9B0F-5AF3E79DC439}.Debug|x64.ActiveCfg = Debug|x64
+ {1A3793D1-05D1-4B57-9B0F-5AF3E79DC439}.Debug|x64.Build.0 = Debug|x64
+ {1A3793D1-05D1-4B57-9B0F-5AF3E79DC439}.Release|Win32.ActiveCfg = Release|Win32
+ {1A3793D1-05D1-4B57-9B0F-5AF3E79DC439}.Release|Win32.Build.0 = Release|Win32
+ {1A3793D1-05D1-4B57-9B0F-5AF3E79DC439}.Release|x64.ActiveCfg = Release|x64
+ {1A3793D1-05D1-4B57-9B0F-5AF3E79DC439}.Release|x64.Build.0 = Release|x64
+ {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.All|Win32.ActiveCfg = Release|x64
+ {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.All|x64.ActiveCfg = Release|x64
+ {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.All|x64.Build.0 = Release|x64
+ {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.Debug|Win32.ActiveCfg = Debug|Win32
+ {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.Debug|Win32.Build.0 = Debug|Win32
+ {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.Debug|x64.ActiveCfg = Debug|x64
+ {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.Debug|x64.Build.0 = Debug|x64
+ {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.Release|Win32.ActiveCfg = Release|Win32
+ {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.Release|Win32.Build.0 = Release|Win32
+ {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.Release|x64.ActiveCfg = Release|x64
+ {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.Release|x64.Build.0 = Release|x64
+ {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.All|Win32.ActiveCfg = Release|x64
+ {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.All|x64.ActiveCfg = Release|x64
+ {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.All|x64.Build.0 = Release|x64
+ {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.Debug|Win32.ActiveCfg = Debug|Win32
+ {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.Debug|Win32.Build.0 = Debug|Win32
+ {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.Debug|x64.ActiveCfg = Debug|x64
+ {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.Debug|x64.Build.0 = Debug|x64
+ {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.Release|Win32.ActiveCfg = Release|Win32
+ {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.Release|Win32.Build.0 = Release|Win32
+ {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.Release|x64.ActiveCfg = Release|x64
+ {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.Release|x64.Build.0 = Release|x64
+ {E972C52F-9E85-4D65-B19C-031E511E9DB4}.All|Win32.ActiveCfg = Release_WM5_PPC_ARM|x64
+ {E972C52F-9E85-4D65-B19C-031E511E9DB4}.All|x64.ActiveCfg = Release_WM5_PPC_ARM|x64
+ {E972C52F-9E85-4D65-B19C-031E511E9DB4}.All|x64.Build.0 = Release_WM5_PPC_ARM|x64
+ {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug|Win32.ActiveCfg = Debug|Win32
+ {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug|Win32.Build.0 = Debug|Win32
+ {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug|x64.ActiveCfg = Debug|x64
+ {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug|x64.Build.0 = Debug|x64
+ {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release|Win32.ActiveCfg = Release|Win32
+ {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release|Win32.Build.0 = Release|Win32
+ {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release|x64.ActiveCfg = Release|x64
+ {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release|x64.Build.0 = Release|x64
+ {03207781-0D1C-4DB3-A71D-45C608F28DBD}.All|Win32.ActiveCfg = Release_Static_SSE|x64
+ {03207781-0D1C-4DB3-A71D-45C608F28DBD}.All|x64.ActiveCfg = Release_Static_SSE|x64
+ {03207781-0D1C-4DB3-A71D-45C608F28DBD}.All|x64.Build.0 = Release_Static_SSE|x64
+ {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Debug|Win32.ActiveCfg = Debug|Win32
+ {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Debug|Win32.Build.0 = Debug|Win32
+ {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Debug|x64.ActiveCfg = Debug|x64
+ {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Debug|x64.Build.0 = Debug|x64
+ {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release|Win32.ActiveCfg = Release|Win32
+ {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release|Win32.Build.0 = Release|Win32
+ {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release|x64.ActiveCfg = Release|x64
+ {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release|x64.Build.0 = Release|x64
+ {9A5DDF08-C88C-4A35-B7F6-D605228446BD}.All|Win32.ActiveCfg = Release|x64
+ {9A5DDF08-C88C-4A35-B7F6-D605228446BD}.All|x64.ActiveCfg = Release|x64
+ {9A5DDF08-C88C-4A35-B7F6-D605228446BD}.All|x64.Build.0 = Release|x64
+ {9A5DDF08-C88C-4A35-B7F6-D605228446BD}.Debug|Win32.ActiveCfg = Debug|Win32
+ {9A5DDF08-C88C-4A35-B7F6-D605228446BD}.Debug|Win32.Build.0 = Debug|Win32
+ {9A5DDF08-C88C-4A35-B7F6-D605228446BD}.Debug|x64.ActiveCfg = Debug|x64
+ {9A5DDF08-C88C-4A35-B7F6-D605228446BD}.Debug|x64.Build.0 = Debug|x64
+ {9A5DDF08-C88C-4A35-B7F6-D605228446BD}.Release|Win32.ActiveCfg = Release|Win32
+ {9A5DDF08-C88C-4A35-B7F6-D605228446BD}.Release|Win32.Build.0 = Release|Win32
+ {9A5DDF08-C88C-4A35-B7F6-D605228446BD}.Release|x64.ActiveCfg = Release|x64
+ {9A5DDF08-C88C-4A35-B7F6-D605228446BD}.Release|x64.Build.0 = Release|x64
+ {D0B36172-CD76-454A-9B89-990025266C2A}.All|Win32.ActiveCfg = Release|x64
+ {D0B36172-CD76-454A-9B89-990025266C2A}.All|x64.ActiveCfg = Release|x64
+ {D0B36172-CD76-454A-9B89-990025266C2A}.All|x64.Build.0 = Release|x64
+ {D0B36172-CD76-454A-9B89-990025266C2A}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D0B36172-CD76-454A-9B89-990025266C2A}.Debug|Win32.Build.0 = Debug|Win32
+ {D0B36172-CD76-454A-9B89-990025266C2A}.Debug|x64.ActiveCfg = Debug|x64
+ {D0B36172-CD76-454A-9B89-990025266C2A}.Debug|x64.Build.0 = Debug|x64
+ {D0B36172-CD76-454A-9B89-990025266C2A}.Release|Win32.ActiveCfg = Release|Win32
+ {D0B36172-CD76-454A-9B89-990025266C2A}.Release|Win32.Build.0 = Release|Win32
+ {D0B36172-CD76-454A-9B89-990025266C2A}.Release|x64.ActiveCfg = Release|x64
+ {D0B36172-CD76-454A-9B89-990025266C2A}.Release|x64.Build.0 = Release|x64
+ {05C9FB27-480E-4D53-B3B7-6338E2526666}.All|Win32.ActiveCfg = Release|Win32
+ {05C9FB27-480E-4D53-B3B7-6338E2526666}.All|Win32.Build.0 = Release|Win32
+ {05C9FB27-480E-4D53-B3B7-6338E2526666}.All|x64.ActiveCfg = Release|Win32
+ {05C9FB27-480E-4D53-B3B7-6338E2526666}.Debug|Win32.ActiveCfg = Debug|Win32
+ {05C9FB27-480E-4D53-B3B7-6338E2526666}.Debug|x64.ActiveCfg = Debug|Win32
+ {05C9FB27-480E-4D53-B3B7-6338E2526666}.Release|Win32.ActiveCfg = Release|Win32
+ {05C9FB27-480E-4D53-B3B7-6338E2526666}.Release|x64.ActiveCfg = Release|Win32
+ {05C9FB27-480E-4D53-B3B7-7338E2514666}.All|Win32.ActiveCfg = Release|Win32
+ {05C9FB27-480E-4D53-B3B7-7338E2514666}.All|Win32.Build.0 = Release|Win32
+ {05C9FB27-480E-4D53-B3B7-7338E2514666}.All|x64.ActiveCfg = Release|Win32
+ {05C9FB27-480E-4D53-B3B7-7338E2514666}.Debug|Win32.ActiveCfg = Debug|Win32
+ {05C9FB27-480E-4D53-B3B7-7338E2514666}.Debug|x64.ActiveCfg = Debug|x64
+ {05C9FB27-480E-4D53-B3B7-7338E2514666}.Release|Win32.ActiveCfg = Release|Win32
+ {05C9FB27-480E-4D53-B3B7-7338E2514666}.Release|x64.ActiveCfg = Release|Win32
+ {7F1610F1-DD5A-4CF7-8610-30AB12C60ADD}.All|Win32.ActiveCfg = All|Win32
+ {7F1610F1-DD5A-4CF7-8610-30AB12C60ADD}.All|Win32.Build.0 = All|Win32
+ {7F1610F1-DD5A-4CF7-8610-30AB12C60ADD}.All|x64.ActiveCfg = All|Win32
+ {7F1610F1-DD5A-4CF7-8610-30AB12C60ADD}.Debug|Win32.ActiveCfg = Debug|Win32
+ {7F1610F1-DD5A-4CF7-8610-30AB12C60ADD}.Debug|x64.ActiveCfg = Debug|x64
+ {7F1610F1-DD5A-4CF7-8610-30AB12C60ADD}.Release|Win32.ActiveCfg = Release|Win32
+ {7F1610F1-DD5A-4CF7-8610-30AB12C60ADD}.Release|x64.ActiveCfg = Release|x64
+ {CC1DD008-9406-448D-A0AD-33C3186CFADB}.All|Win32.ActiveCfg = Release|Win32
+ {CC1DD008-9406-448D-A0AD-33C3186CFADB}.All|x64.ActiveCfg = Release|Win32
+ {CC1DD008-9406-448D-A0AD-33C3186CFADB}.Debug|Win32.ActiveCfg = Debug|Win32
+ {CC1DD008-9406-448D-A0AD-33C3186CFADB}.Debug|x64.ActiveCfg = Debug|x64
+ {CC1DD008-9406-448D-A0AD-33C3186CFADB}.Release|Win32.ActiveCfg = Release|Win32
+ {CC1DD008-9406-448D-A0AD-33C3186CFADB}.Release|x64.ActiveCfg = Release|x64
+ {48414740-C693-4968-9846-EE058020C64F}.All|Win32.ActiveCfg = Release|Win32
+ {48414740-C693-4968-9846-EE058020C64F}.All|x64.ActiveCfg = Release|Win32
+ {48414740-C693-4968-9846-EE058020C64F}.Debug|Win32.ActiveCfg = Debug|Win32
+ {48414740-C693-4968-9846-EE058020C64F}.Debug|x64.ActiveCfg = Debug|x64
+ {48414740-C693-4968-9846-EE058020C64F}.Release|Win32.ActiveCfg = Release|Win32
+ {48414740-C693-4968-9846-EE058020C64F}.Release|x64.ActiveCfg = Release|x64
+ {DEE932AB-5911-4700-9EEB-8C7090A0A330}.All|Win32.ActiveCfg = All|Win32
+ {DEE932AB-5911-4700-9EEB-8C7090A0A330}.All|Win32.Build.0 = All|Win32
+ {DEE932AB-5911-4700-9EEB-8C7090A0A330}.All|x64.ActiveCfg = All|Win32
+ {DEE932AB-5911-4700-9EEB-8C7090A0A330}.Debug|Win32.ActiveCfg = All|Win32
+ {DEE932AB-5911-4700-9EEB-8C7090A0A330}.Debug|Win32.Build.0 = All|Win32
+ {DEE932AB-5911-4700-9EEB-8C7090A0A330}.Debug|x64.ActiveCfg = All|Win32
+ {DEE932AB-5911-4700-9EEB-8C7090A0A330}.Debug|x64.Build.0 = All|Win32
+ {DEE932AB-5911-4700-9EEB-8C7090A0A330}.Release|Win32.ActiveCfg = All|Win32
+ {DEE932AB-5911-4700-9EEB-8C7090A0A330}.Release|Win32.Build.0 = All|Win32
+ {DEE932AB-5911-4700-9EEB-8C7090A0A330}.Release|x64.ActiveCfg = All|Win32
+ {DEE932AB-5911-4700-9EEB-8C7090A0A330}.Release|x64.Build.0 = All|Win32
+ {329A6FA0-0FCC-4435-A950-E670AEFA9838}.All|Win32.ActiveCfg = All|Win32
+ {329A6FA0-0FCC-4435-A950-E670AEFA9838}.All|Win32.Build.0 = All|Win32
+ {329A6FA0-0FCC-4435-A950-E670AEFA9838}.All|x64.ActiveCfg = All|Win32
+ {329A6FA0-0FCC-4435-A950-E670AEFA9838}.Debug|Win32.ActiveCfg = All|Win32
+ {329A6FA0-0FCC-4435-A950-E670AEFA9838}.Debug|Win32.Build.0 = All|Win32
+ {329A6FA0-0FCC-4435-A950-E670AEFA9838}.Debug|x64.ActiveCfg = All|Win32
+ {329A6FA0-0FCC-4435-A950-E670AEFA9838}.Debug|x64.Build.0 = All|Win32
+ {329A6FA0-0FCC-4435-A950-E670AEFA9838}.Release|Win32.ActiveCfg = All|Win32
+ {329A6FA0-0FCC-4435-A950-E670AEFA9838}.Release|Win32.Build.0 = All|Win32
+ {329A6FA0-0FCC-4435-A950-E670AEFA9838}.Release|x64.ActiveCfg = All|Win32
+ {329A6FA0-0FCC-4435-A950-E670AEFA9838}.Release|x64.Build.0 = All|Win32
+ {11C9BC3D-45E9-46E3-BE84-B8CEE4685E39}.All|Win32.ActiveCfg = Release|x64
+ {11C9BC3D-45E9-46E3-BE84-B8CEE4685E39}.All|x64.ActiveCfg = Release|x64
+ {11C9BC3D-45E9-46E3-BE84-B8CEE4685E39}.All|x64.Build.0 = Release|x64
+ {11C9BC3D-45E9-46E3-BE84-B8CEE4685E39}.Debug|Win32.ActiveCfg = Debug|Win32
+ {11C9BC3D-45E9-46E3-BE84-B8CEE4685E39}.Debug|x64.ActiveCfg = Debug|x64
+ {11C9BC3D-45E9-46E3-BE84-B8CEE4685E39}.Release|Win32.ActiveCfg = Release|Win32
+ {11C9BC3D-45E9-46E3-BE84-B8CEE4685E39}.Release|x64.ActiveCfg = Release|x64
+ {C6E78A4C-DB1E-47F4-9B63-4DC27D86343F}.All|Win32.ActiveCfg = Release|Win32
+ {C6E78A4C-DB1E-47F4-9B63-4DC27D86343F}.All|Win32.Build.0 = Release|Win32
+ {C6E78A4C-DB1E-47F4-9B63-4DC27D86343F}.All|x64.ActiveCfg = Release|Win32
+ {C6E78A4C-DB1E-47F4-9B63-4DC27D86343F}.Debug|Win32.ActiveCfg = Debug|Win32
+ {C6E78A4C-DB1E-47F4-9B63-4DC27D86343F}.Debug|x64.ActiveCfg = Debug|Win32
+ {C6E78A4C-DB1E-47F4-9B63-4DC27D86343F}.Release|Win32.ActiveCfg = Release|Win32
+ {C6E78A4C-DB1E-47F4-9B63-4DC27D86343F}.Release|x64.ActiveCfg = Release|Win32
+ {1F0A8A77-E661-418F-BB92-82172AE43803}.All|Win32.ActiveCfg = Release|Win32
+ {1F0A8A77-E661-418F-BB92-82172AE43803}.All|x64.ActiveCfg = Release|Win32
+ {1F0A8A77-E661-418F-BB92-82172AE43803}.Debug|Win32.ActiveCfg = Debug|Win32
+ {1F0A8A77-E661-418F-BB92-82172AE43803}.Debug|x64.ActiveCfg = Debug|Win32
+ {1F0A8A77-E661-418F-BB92-82172AE43803}.Release|Win32.ActiveCfg = Release|Win32
+ {1F0A8A77-E661-418F-BB92-82172AE43803}.Release|x64.ActiveCfg = Release|Win32
+ {4F5C9D55-98EF-4256-8311-32D7BD360406}.All|Win32.ActiveCfg = Release|Win32
+ {4F5C9D55-98EF-4256-8311-32D7BD360406}.All|Win32.Build.0 = Release|Win32
+ {4F5C9D55-98EF-4256-8311-32D7BD360406}.All|x64.ActiveCfg = Release|Win32
+ {4F5C9D55-98EF-4256-8311-32D7BD360406}.All|x64.Build.0 = Release|Win32
+ {4F5C9D55-98EF-4256-8311-32D7BD360406}.Debug|Win32.ActiveCfg = Debug|Win32
+ {4F5C9D55-98EF-4256-8311-32D7BD360406}.Debug|Win32.Build.0 = Debug|Win32
+ {4F5C9D55-98EF-4256-8311-32D7BD360406}.Debug|x64.ActiveCfg = Debug|Win32
+ {4F5C9D55-98EF-4256-8311-32D7BD360406}.Debug|x64.Build.0 = Debug|Win32
+ {4F5C9D55-98EF-4256-8311-32D7BD360406}.Release|Win32.ActiveCfg = Release|Win32
+ {4F5C9D55-98EF-4256-8311-32D7BD360406}.Release|Win32.Build.0 = Release|Win32
+ {4F5C9D55-98EF-4256-8311-32D7BD360406}.Release|x64.ActiveCfg = Release|Win32
+ {4F5C9D55-98EF-4256-8311-32D7BD360406}.Release|x64.Build.0 = Release|Win32
+ {E10571C4-E7F4-4608-B5F2-B22E7EB95400}.All|Win32.ActiveCfg = Release|Win32
+ {E10571C4-E7F4-4608-B5F2-B22E7EB95400}.All|x64.ActiveCfg = Release|Win32
+ {E10571C4-E7F4-4608-B5F2-B22E7EB95400}.Debug|Win32.ActiveCfg = Debug|Win32
+ {E10571C4-E7F4-4608-B5F2-B22E7EB95400}.Debug|x64.ActiveCfg = Debug|Win32
+ {E10571C4-E7F4-4608-B5F2-B22E7EB95400}.Release|Win32.ActiveCfg = Release|Win32
+ {E10571C4-E7F4-4608-B5F2-B22E7EB95400}.Release|x64.ActiveCfg = Release|Win32
+ {D1ABE208-6442-4FB4-9AAD-1677E41BC870}.All|Win32.ActiveCfg = Release|Win32
+ {D1ABE208-6442-4FB4-9AAD-1677E41BC870}.All|Win32.Build.0 = Release|Win32
+ {D1ABE208-6442-4FB4-9AAD-1677E41BC870}.All|x64.ActiveCfg = Release|Win32
+ {D1ABE208-6442-4FB4-9AAD-1677E41BC870}.All|x64.Build.0 = Release|Win32
+ {D1ABE208-6442-4FB4-9AAD-1677E41BC870}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D1ABE208-6442-4FB4-9AAD-1677E41BC870}.Debug|Win32.Build.0 = Debug|Win32
+ {D1ABE208-6442-4FB4-9AAD-1677E41BC870}.Debug|x64.ActiveCfg = Debug|x64
+ {D1ABE208-6442-4FB4-9AAD-1677E41BC870}.Debug|x64.Build.0 = Debug|x64
+ {D1ABE208-6442-4FB4-9AAD-1677E41BC870}.Release|Win32.ActiveCfg = Release|Win32
+ {D1ABE208-6442-4FB4-9AAD-1677E41BC870}.Release|Win32.Build.0 = Release|Win32
+ {D1ABE208-6442-4FB4-9AAD-1677E41BC870}.Release|x64.ActiveCfg = Release|x64
+ {D1ABE208-6442-4FB4-9AAD-1677E41BC870}.Release|x64.Build.0 = Release|x64
+ {BA599D0A-4310-4505-91DA-6A6447B3E289}.All|Win32.ActiveCfg = Release|Win32
+ {BA599D0A-4310-4505-91DA-6A6447B3E289}.All|x64.ActiveCfg = Release|Win32
+ {BA599D0A-4310-4505-91DA-6A6447B3E289}.Debug|Win32.ActiveCfg = Debug|Win32
+ {BA599D0A-4310-4505-91DA-6A6447B3E289}.Debug|x64.ActiveCfg = Debug|x64
+ {BA599D0A-4310-4505-91DA-6A6447B3E289}.Release|Win32.ActiveCfg = Release|Win32
+ {BA599D0A-4310-4505-91DA-6A6447B3E289}.Release|x64.ActiveCfg = Release|x64
+ {EED13FC7-4F81-4E6F-93DB-CDB7DF5CF959}.All|Win32.ActiveCfg = Release|Win32
+ {EED13FC7-4F81-4E6F-93DB-CDB7DF5CF959}.All|x64.ActiveCfg = Release|Win32
+ {EED13FC7-4F81-4E6F-93DB-CDB7DF5CF959}.Debug|Win32.ActiveCfg = Debug|Win32
+ {EED13FC7-4F81-4E6F-93DB-CDB7DF5CF959}.Debug|x64.ActiveCfg = Debug|x64
+ {EED13FC7-4F81-4E6F-93DB-CDB7DF5CF959}.Release|Win32.ActiveCfg = Release|Win32
+ {EED13FC7-4F81-4E6F-93DB-CDB7DF5CF959}.Release|x64.ActiveCfg = Release|x64
+ {3C977801-FE88-48F2-83D3-FA2EBFF6688E}.All|Win32.ActiveCfg = Release|x64
+ {3C977801-FE88-48F2-83D3-FA2EBFF6688E}.All|x64.ActiveCfg = Release|x64
+ {3C977801-FE88-48F2-83D3-FA2EBFF6688E}.All|x64.Build.0 = Release|x64
+ {3C977801-FE88-48F2-83D3-FA2EBFF6688E}.Debug|Win32.ActiveCfg = Debug|Win32
+ {3C977801-FE88-48F2-83D3-FA2EBFF6688E}.Debug|Win32.Build.0 = Debug|Win32
+ {3C977801-FE88-48F2-83D3-FA2EBFF6688E}.Debug|x64.ActiveCfg = Debug|x64
+ {3C977801-FE88-48F2-83D3-FA2EBFF6688E}.Debug|x64.Build.0 = Debug|x64
+ {3C977801-FE88-48F2-83D3-FA2EBFF6688E}.Release|Win32.ActiveCfg = Release|Win32
+ {3C977801-FE88-48F2-83D3-FA2EBFF6688E}.Release|Win32.Build.0 = Release|Win32
+ {3C977801-FE88-48F2-83D3-FA2EBFF6688E}.Release|x64.ActiveCfg = Release|x64
+ {3C977801-FE88-48F2-83D3-FA2EBFF6688E}.Release|x64.Build.0 = Release|x64
+ {0382E8FD-CFDC-41C0-8B03-792C7C84FC31}.All|Win32.ActiveCfg = Release|x64
+ {0382E8FD-CFDC-41C0-8B03-792C7C84FC31}.All|Win32.Build.0 = Release|x64
+ {0382E8FD-CFDC-41C0-8B03-792C7C84FC31}.All|x64.ActiveCfg = Release|x64
+ {0382E8FD-CFDC-41C0-8B03-792C7C84FC31}.All|x64.Build.0 = Release|x64
+ {0382E8FD-CFDC-41C0-8B03-792C7C84FC31}.Debug|Win32.ActiveCfg = Debug|Win32
+ {0382E8FD-CFDC-41C0-8B03-792C7C84FC31}.Debug|Win32.Build.0 = Debug|Win32
+ {0382E8FD-CFDC-41C0-8B03-792C7C84FC31}.Debug|x64.ActiveCfg = Debug|x64
+ {0382E8FD-CFDC-41C0-8B03-792C7C84FC31}.Debug|x64.Build.0 = Debug|x64
+ {0382E8FD-CFDC-41C0-8B03-792C7C84FC31}.Release|Win32.ActiveCfg = Release|Win32
+ {0382E8FD-CFDC-41C0-8B03-792C7C84FC31}.Release|Win32.Build.0 = Release|Win32
+ {0382E8FD-CFDC-41C0-8B03-792C7C84FC31}.Release|x64.ActiveCfg = Release|x64
+ {0382E8FD-CFDC-41C0-8B03-792C7C84FC31}.Release|x64.Build.0 = Release|x64
+ {432DB165-1EB2-4781-A9C0-71E62610B20A}.All|Win32.ActiveCfg = Release|x64
+ {432DB165-1EB2-4781-A9C0-71E62610B20A}.All|x64.ActiveCfg = Release|x64
+ {432DB165-1EB2-4781-A9C0-71E62610B20A}.Debug|Win32.ActiveCfg = Debug|Win32
+ {432DB165-1EB2-4781-A9C0-71E62610B20A}.Debug|Win32.Build.0 = Debug|Win32
+ {432DB165-1EB2-4781-A9C0-71E62610B20A}.Debug|x64.ActiveCfg = Debug|x64
+ {432DB165-1EB2-4781-A9C0-71E62610B20A}.Debug|x64.Build.0 = Debug|x64
+ {432DB165-1EB2-4781-A9C0-71E62610B20A}.Release|Win32.ActiveCfg = Release|Win32
+ {432DB165-1EB2-4781-A9C0-71E62610B20A}.Release|Win32.Build.0 = Release|Win32
+ {432DB165-1EB2-4781-A9C0-71E62610B20A}.Release|x64.ActiveCfg = Release|x64
+ {432DB165-1EB2-4781-A9C0-71E62610B20A}.Release|x64.Build.0 = Release|x64
+ {CF70F278-3364-4395-A2E1-23501C9B8AD2}.All|Win32.ActiveCfg = Release|Win32
+ {CF70F278-3364-4395-A2E1-23501C9B8AD2}.All|Win32.Build.0 = Release|Win32
+ {CF70F278-3364-4395-A2E1-23501C9B8AD2}.All|x64.ActiveCfg = Release|Win32
+ {CF70F278-3364-4395-A2E1-23501C9B8AD2}.Debug|Win32.ActiveCfg = Debug|Win32
+ {CF70F278-3364-4395-A2E1-23501C9B8AD2}.Debug|Win32.Build.0 = Debug|Win32
+ {CF70F278-3364-4395-A2E1-23501C9B8AD2}.Debug|x64.ActiveCfg = Debug|x64
+ {CF70F278-3364-4395-A2E1-23501C9B8AD2}.Debug|x64.Build.0 = Debug|x64
+ {CF70F278-3364-4395-A2E1-23501C9B8AD2}.Release|Win32.ActiveCfg = Release|Win32
+ {CF70F278-3364-4395-A2E1-23501C9B8AD2}.Release|Win32.Build.0 = Release|Win32
+ {CF70F278-3364-4395-A2E1-23501C9B8AD2}.Release|x64.ActiveCfg = Release|x64
+ {CF70F278-3364-4395-A2E1-23501C9B8AD2}.Release|x64.Build.0 = Release|x64
+ {D5C87B19-150D-4EF3-A671-96589BD2D14A}.All|Win32.ActiveCfg = Release|x64
+ {D5C87B19-150D-4EF3-A671-96589BD2D14A}.All|x64.ActiveCfg = Release|x64
+ {D5C87B19-150D-4EF3-A671-96589BD2D14A}.All|x64.Build.0 = Release|x64
+ {D5C87B19-150D-4EF3-A671-96589BD2D14A}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D5C87B19-150D-4EF3-A671-96589BD2D14A}.Debug|Win32.Build.0 = Debug|Win32
+ {D5C87B19-150D-4EF3-A671-96589BD2D14A}.Debug|x64.ActiveCfg = Debug|x64
+ {D5C87B19-150D-4EF3-A671-96589BD2D14A}.Debug|x64.Build.0 = Debug|x64
+ {D5C87B19-150D-4EF3-A671-96589BD2D14A}.Release|Win32.ActiveCfg = Release|Win32
+ {D5C87B19-150D-4EF3-A671-96589BD2D14A}.Release|Win32.Build.0 = Release|Win32
+ {D5C87B19-150D-4EF3-A671-96589BD2D14A}.Release|x64.ActiveCfg = Release|x64
+ {D5C87B19-150D-4EF3-A671-96589BD2D14A}.Release|x64.Build.0 = Release|x64
+ {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}.All|Win32.ActiveCfg = Release|Win32
+ {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}.All|Win32.Build.0 = Release|Win32
+ {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}.All|x64.ActiveCfg = Release|Win32
+ {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}.Debug|Win32.ActiveCfg = Debug|Win32
+ {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}.Debug|Win32.Build.0 = Debug|Win32
+ {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}.Debug|x64.ActiveCfg = Debug|x64
+ {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}.Debug|x64.Build.0 = Debug|x64
+ {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}.Release|Win32.ActiveCfg = Release|Win32
+ {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}.Release|Win32.Build.0 = Release|Win32
+ {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}.Release|x64.ActiveCfg = Release|x64
+ {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}.Release|x64.Build.0 = Release|x64
+ {B5A00BFA-6083-4FAE-A097-71642D6473B5}.All|Win32.ActiveCfg = Release|Win32
+ {B5A00BFA-6083-4FAE-A097-71642D6473B5}.All|Win32.Build.0 = Release|Win32
+ {B5A00BFA-6083-4FAE-A097-71642D6473B5}.All|x64.ActiveCfg = Release|Win32
+ {B5A00BFA-6083-4FAE-A097-71642D6473B5}.Debug|Win32.ActiveCfg = Debug|Win32
+ {B5A00BFA-6083-4FAE-A097-71642D6473B5}.Debug|Win32.Build.0 = Debug|Win32
+ {B5A00BFA-6083-4FAE-A097-71642D6473B5}.Debug|x64.ActiveCfg = Debug|x64
+ {B5A00BFA-6083-4FAE-A097-71642D6473B5}.Debug|x64.Build.0 = Debug|x64
+ {B5A00BFA-6083-4FAE-A097-71642D6473B5}.Release|Win32.ActiveCfg = Release|Win32
+ {B5A00BFA-6083-4FAE-A097-71642D6473B5}.Release|Win32.Build.0 = Release|Win32
+ {B5A00BFA-6083-4FAE-A097-71642D6473B5}.Release|x64.ActiveCfg = Release|x64
+ {B5A00BFA-6083-4FAE-A097-71642D6473B5}.Release|x64.Build.0 = Release|x64
+ {1C320193-46A6-4B34-9C56-8AB584FC1B56}.All|Win32.ActiveCfg = Release|Win32
+ {1C320193-46A6-4B34-9C56-8AB584FC1B56}.All|Win32.Build.0 = Release|Win32
+ {1C320193-46A6-4B34-9C56-8AB584FC1B56}.All|x64.ActiveCfg = Release|Win32
+ {1C320193-46A6-4B34-9C56-8AB584FC1B56}.Debug|Win32.ActiveCfg = Debug|Win32
+ {1C320193-46A6-4B34-9C56-8AB584FC1B56}.Debug|Win32.Build.0 = Debug|Win32
+ {1C320193-46A6-4B34-9C56-8AB584FC1B56}.Debug|x64.ActiveCfg = Debug|x64
+ {1C320193-46A6-4B34-9C56-8AB584FC1B56}.Debug|x64.Build.0 = Debug|x64
+ {1C320193-46A6-4B34-9C56-8AB584FC1B56}.Release|Win32.ActiveCfg = Release|Win32
+ {1C320193-46A6-4B34-9C56-8AB584FC1B56}.Release|Win32.Build.0 = Release|Win32
+ {1C320193-46A6-4B34-9C56-8AB584FC1B56}.Release|x64.ActiveCfg = Release|x64
+ {1C320193-46A6-4B34-9C56-8AB584FC1B56}.Release|x64.Build.0 = Release|x64
+ {72782932-37CC-46AE-8C7F-9A7B1A6EE108}.All|Win32.ActiveCfg = Release|Win32
+ {72782932-37CC-46AE-8C7F-9A7B1A6EE108}.All|Win32.Build.0 = Release|Win32
+ {72782932-37CC-46AE-8C7F-9A7B1A6EE108}.All|x64.ActiveCfg = Release|Win32
+ {72782932-37CC-46AE-8C7F-9A7B1A6EE108}.Debug|Win32.ActiveCfg = Debug|Win32
+ {72782932-37CC-46AE-8C7F-9A7B1A6EE108}.Debug|Win32.Build.0 = Debug|Win32
+ {72782932-37CC-46AE-8C7F-9A7B1A6EE108}.Debug|x64.ActiveCfg = Debug|x64
+ {72782932-37CC-46AE-8C7F-9A7B1A6EE108}.Debug|x64.Build.0 = Debug|x64
+ {72782932-37CC-46AE-8C7F-9A7B1A6EE108}.Release|Win32.ActiveCfg = Release|Win32
+ {72782932-37CC-46AE-8C7F-9A7B1A6EE108}.Release|Win32.Build.0 = Release|Win32
+ {72782932-37CC-46AE-8C7F-9A7B1A6EE108}.Release|x64.ActiveCfg = Release|x64
+ {72782932-37CC-46AE-8C7F-9A7B1A6EE108}.Release|x64.Build.0 = Release|x64
+ {12A49562-BAB9-43A3-A21D-15B60BBB4C31}.All|Win32.ActiveCfg = Release|Win32
+ {12A49562-BAB9-43A3-A21D-15B60BBB4C31}.All|Win32.Build.0 = Release|Win32
+ {12A49562-BAB9-43A3-A21D-15B60BBB4C31}.All|x64.ActiveCfg = Release|Win32
+ {12A49562-BAB9-43A3-A21D-15B60BBB4C31}.Debug|Win32.ActiveCfg = Debug|Win32
+ {12A49562-BAB9-43A3-A21D-15B60BBB4C31}.Debug|Win32.Build.0 = Debug|Win32
+ {12A49562-BAB9-43A3-A21D-15B60BBB4C31}.Debug|x64.ActiveCfg = Debug|x64
+ {12A49562-BAB9-43A3-A21D-15B60BBB4C31}.Debug|x64.Build.0 = Debug|x64
+ {12A49562-BAB9-43A3-A21D-15B60BBB4C31}.Release|Win32.ActiveCfg = Release|Win32
+ {12A49562-BAB9-43A3-A21D-15B60BBB4C31}.Release|Win32.Build.0 = Release|Win32
+ {12A49562-BAB9-43A3-A21D-15B60BBB4C31}.Release|x64.ActiveCfg = Release|x64
+ {12A49562-BAB9-43A3-A21D-15B60BBB4C31}.Release|x64.Build.0 = Release|x64
+ {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}.All|Win32.ActiveCfg = Release|Win32
+ {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}.All|Win32.Build.0 = Release|Win32
+ {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}.All|x64.ActiveCfg = Release|Win32
+ {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}.Debug|Win32.ActiveCfg = Debug|Win32
+ {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}.Debug|Win32.Build.0 = Debug|Win32
+ {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}.Debug|x64.ActiveCfg = Debug|x64
+ {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}.Debug|x64.Build.0 = Debug|x64
+ {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}.Release|Win32.ActiveCfg = Release|Win32
+ {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}.Release|Win32.Build.0 = Release|Win32
+ {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}.Release|x64.ActiveCfg = Release|x64
+ {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}.Release|x64.Build.0 = Release|x64
+ {504B3154-7A4F-459D-9877-B951021C3F1F}.All|Win32.ActiveCfg = Release|Win32
+ {504B3154-7A4F-459D-9877-B951021C3F1F}.All|Win32.Build.0 = Release|Win32
+ {504B3154-7A4F-459D-9877-B951021C3F1F}.All|x64.ActiveCfg = Release|Win32
+ {504B3154-7A4F-459D-9877-B951021C3F1F}.Debug|Win32.ActiveCfg = Debug|Win32
+ {504B3154-7A4F-459D-9877-B951021C3F1F}.Debug|Win32.Build.0 = Debug|Win32
+ {504B3154-7A4F-459D-9877-B951021C3F1F}.Debug|x64.ActiveCfg = Debug|x64
+ {504B3154-7A4F-459D-9877-B951021C3F1F}.Debug|x64.Build.0 = Debug|x64
+ {504B3154-7A4F-459D-9877-B951021C3F1F}.Release|Win32.ActiveCfg = Release|Win32
+ {504B3154-7A4F-459D-9877-B951021C3F1F}.Release|Win32.Build.0 = Release|Win32
+ {504B3154-7A4F-459D-9877-B951021C3F1F}.Release|x64.ActiveCfg = Release|x64
+ {504B3154-7A4F-459D-9877-B951021C3F1F}.Release|x64.Build.0 = Release|x64
+ {746F3632-5BB2-4570-9453-31D6D58A7D8E}.All|Win32.ActiveCfg = Release|Win32
+ {746F3632-5BB2-4570-9453-31D6D58A7D8E}.All|Win32.Build.0 = Release|Win32
+ {746F3632-5BB2-4570-9453-31D6D58A7D8E}.All|x64.ActiveCfg = Release|Win32
+ {746F3632-5BB2-4570-9453-31D6D58A7D8E}.Debug|Win32.ActiveCfg = Debug|Win32
+ {746F3632-5BB2-4570-9453-31D6D58A7D8E}.Debug|Win32.Build.0 = Debug|Win32
+ {746F3632-5BB2-4570-9453-31D6D58A7D8E}.Debug|x64.ActiveCfg = Debug|x64
+ {746F3632-5BB2-4570-9453-31D6D58A7D8E}.Debug|x64.Build.0 = Debug|x64
+ {746F3632-5BB2-4570-9453-31D6D58A7D8E}.Release|Win32.ActiveCfg = Release|Win32
+ {746F3632-5BB2-4570-9453-31D6D58A7D8E}.Release|Win32.Build.0 = Release|Win32
+ {746F3632-5BB2-4570-9453-31D6D58A7D8E}.Release|x64.ActiveCfg = Release|x64
+ {746F3632-5BB2-4570-9453-31D6D58A7D8E}.Release|x64.Build.0 = Release|x64
+ {DEB01ACB-D65F-4A62-AED9-58C1054499E9}.All|Win32.ActiveCfg = Release|Win32
+ {DEB01ACB-D65F-4A62-AED9-58C1054499E9}.All|Win32.Build.0 = Release|Win32
+ {DEB01ACB-D65F-4A62-AED9-58C1054499E9}.All|x64.ActiveCfg = Release|Win32
+ {DEB01ACB-D65F-4A62-AED9-58C1054499E9}.Debug|Win32.ActiveCfg = Debug|Win32
+ {DEB01ACB-D65F-4A62-AED9-58C1054499E9}.Debug|Win32.Build.0 = Debug|Win32
+ {DEB01ACB-D65F-4A62-AED9-58C1054499E9}.Debug|x64.ActiveCfg = Debug|x64
+ {DEB01ACB-D65F-4A62-AED9-58C1054499E9}.Debug|x64.Build.0 = Debug|x64
+ {DEB01ACB-D65F-4A62-AED9-58C1054499E9}.Release|Win32.ActiveCfg = Release|Win32
+ {DEB01ACB-D65F-4A62-AED9-58C1054499E9}.Release|Win32.Build.0 = Release|Win32
+ {DEB01ACB-D65F-4A62-AED9-58C1054499E9}.Release|x64.ActiveCfg = Release|x64
+ {DEB01ACB-D65F-4A62-AED9-58C1054499E9}.Release|x64.Build.0 = Release|x64
+ {D07C378A-F5F7-438F-ADF3-4AC4FB1883CD}.All|Win32.ActiveCfg = Release|x64
+ {D07C378A-F5F7-438F-ADF3-4AC4FB1883CD}.All|x64.ActiveCfg = Release|x64
+ {D07C378A-F5F7-438F-ADF3-4AC4FB1883CD}.All|x64.Build.0 = Release|x64
+ {D07C378A-F5F7-438F-ADF3-4AC4FB1883CD}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D07C378A-F5F7-438F-ADF3-4AC4FB1883CD}.Debug|Win32.Build.0 = Debug|Win32
+ {D07C378A-F5F7-438F-ADF3-4AC4FB1883CD}.Debug|x64.ActiveCfg = Debug|x64
+ {D07C378A-F5F7-438F-ADF3-4AC4FB1883CD}.Debug|x64.Build.0 = Debug|x64
+ {D07C378A-F5F7-438F-ADF3-4AC4FB1883CD}.Release|Win32.ActiveCfg = Release|Win32
+ {D07C378A-F5F7-438F-ADF3-4AC4FB1883CD}.Release|Win32.Build.0 = Release|Win32
+ {D07C378A-F5F7-438F-ADF3-4AC4FB1883CD}.Release|x64.ActiveCfg = Release|x64
+ {D07C378A-F5F7-438F-ADF3-4AC4FB1883CD}.Release|x64.Build.0 = Release|x64
+ {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19}.All|Win32.ActiveCfg = Release|Win32
+ {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19}.All|Win32.Build.0 = Release|Win32
+ {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19}.All|x64.ActiveCfg = Release|Win32
+ {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19}.Debug|Win32.ActiveCfg = Debug|Win32
+ {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19}.Debug|Win32.Build.0 = Debug|Win32
+ {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19}.Debug|x64.ActiveCfg = Debug|Win32
+ {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19}.Debug|x64.Build.0 = Debug|Win32
+ {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19}.Release|Win32.ActiveCfg = Release|Win32
+ {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19}.Release|Win32.Build.0 = Release|Win32
+ {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19}.Release|x64.ActiveCfg = Release|Win32
+ {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19}.Release|x64.Build.0 = Release|Win32
+ {ABB71A76-42B0-47A4-973A-42E3D920C6FD}.All|Win32.ActiveCfg = Release|x64
+ {ABB71A76-42B0-47A4-973A-42E3D920C6FD}.All|x64.ActiveCfg = Release|x64
+ {ABB71A76-42B0-47A4-973A-42E3D920C6FD}.All|x64.Build.0 = Release|x64
+ {ABB71A76-42B0-47A4-973A-42E3D920C6FD}.Debug|Win32.ActiveCfg = Debug|Win32
+ {ABB71A76-42B0-47A4-973A-42E3D920C6FD}.Debug|Win32.Build.0 = Debug|Win32
+ {ABB71A76-42B0-47A4-973A-42E3D920C6FD}.Debug|x64.ActiveCfg = Debug|x64
+ {ABB71A76-42B0-47A4-973A-42E3D920C6FD}.Debug|x64.Build.0 = Debug|x64
+ {ABB71A76-42B0-47A4-973A-42E3D920C6FD}.Release|Win32.ActiveCfg = Release|Win32
+ {ABB71A76-42B0-47A4-973A-42E3D920C6FD}.Release|Win32.Build.0 = Release|Win32
+ {ABB71A76-42B0-47A4-973A-42E3D920C6FD}.Release|x64.ActiveCfg = Release|x64
+ {ABB71A76-42B0-47A4-973A-42E3D920C6FD}.Release|x64.Build.0 = Release|x64
+ {4D418176-3B33-47E6-A63E-01BA34ADD21C}.All|Win32.ActiveCfg = Release Passthrough|x64
+ {4D418176-3B33-47E6-A63E-01BA34ADD21C}.All|x64.ActiveCfg = Release Passthrough|x64
+ {4D418176-3B33-47E6-A63E-01BA34ADD21C}.All|x64.Build.0 = Release Passthrough|x64
+ {4D418176-3B33-47E6-A63E-01BA34ADD21C}.Debug|Win32.ActiveCfg = Debug|Win32
+ {4D418176-3B33-47E6-A63E-01BA34ADD21C}.Debug|Win32.Build.0 = Debug|Win32
+ {4D418176-3B33-47E6-A63E-01BA34ADD21C}.Debug|x64.ActiveCfg = Debug|x64
+ {4D418176-3B33-47E6-A63E-01BA34ADD21C}.Debug|x64.Build.0 = Debug|x64
+ {4D418176-3B33-47E6-A63E-01BA34ADD21C}.Release|Win32.ActiveCfg = Release|Win32
+ {4D418176-3B33-47E6-A63E-01BA34ADD21C}.Release|Win32.Build.0 = Release|Win32
+ {4D418176-3B33-47E6-A63E-01BA34ADD21C}.Release|x64.ActiveCfg = Release|x64
+ {4D418176-3B33-47E6-A63E-01BA34ADD21C}.Release|x64.Build.0 = Release|x64
+ {7D3122C7-C9D0-3748-81F8-F0DDCB40BF5E}.All|Win32.ActiveCfg = Release|Win32
+ {7D3122C7-C9D0-3748-81F8-F0DDCB40BF5E}.All|Win32.Build.0 = Release|Win32
+ {7D3122C7-C9D0-3748-81F8-F0DDCB40BF5E}.All|x64.ActiveCfg = Release|Win32
+ {7D3122C7-C9D0-3748-81F8-F0DDCB40BF5E}.Debug|Win32.ActiveCfg = Debug|Win32
+ {7D3122C7-C9D0-3748-81F8-F0DDCB40BF5E}.Debug|x64.ActiveCfg = Debug|Win32
+ {7D3122C7-C9D0-3748-81F8-F0DDCB40BF5E}.Release|Win32.ActiveCfg = Release|Win32
+ {7D3122C7-C9D0-3748-81F8-F0DDCB40BF5E}.Release|x64.ActiveCfg = Release|Win32
+ {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.All|Win32.ActiveCfg = Release|x64
+ {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.All|x64.ActiveCfg = Release|x64
+ {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.All|x64.Build.0 = Release|x64
+ {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.Debug|Win32.ActiveCfg = Debug|Win32
+ {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.Debug|Win32.Build.0 = Debug|Win32
+ {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.Debug|x64.ActiveCfg = Debug|x64
+ {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.Debug|x64.Build.0 = Debug|x64
+ {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.Release|Win32.ActiveCfg = Release|Win32
+ {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.Release|Win32.Build.0 = Release|Win32
+ {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.Release|x64.ActiveCfg = Release|x64
+ {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.Release|x64.Build.0 = Release|x64
+ {B808178B-82F0-4CF4-A2B1-921939FA24D0}.All|Win32.ActiveCfg = Release|Win32
+ {B808178B-82F0-4CF4-A2B1-921939FA24D0}.All|Win32.Build.0 = Release|Win32
+ {B808178B-82F0-4CF4-A2B1-921939FA24D0}.All|x64.ActiveCfg = Release|Win32
+ {B808178B-82F0-4CF4-A2B1-921939FA24D0}.Debug|Win32.ActiveCfg = Debug|Win32
+ {B808178B-82F0-4CF4-A2B1-921939FA24D0}.Debug|Win32.Build.0 = Debug|Win32
+ {B808178B-82F0-4CF4-A2B1-921939FA24D0}.Debug|x64.ActiveCfg = Debug|Win32
+ {B808178B-82F0-4CF4-A2B1-921939FA24D0}.Debug|x64.Build.0 = Debug|Win32
+ {B808178B-82F0-4CF4-A2B1-921939FA24D0}.Release|Win32.ActiveCfg = Release|Win32
+ {B808178B-82F0-4CF4-A2B1-921939FA24D0}.Release|Win32.Build.0 = Release|Win32
+ {B808178B-82F0-4CF4-A2B1-921939FA24D0}.Release|x64.ActiveCfg = Release|Win32
+ {B808178B-82F0-4CF4-A2B1-921939FA24D0}.Release|x64.Build.0 = Release|Win32
+ {9778F1C0-09BC-4698-8EBC-BD982247209A}.All|Win32.ActiveCfg = Release|x64
+ {9778F1C0-09BC-4698-8EBC-BD982247209A}.All|x64.ActiveCfg = Release|x64
+ {9778F1C0-09BC-4698-8EBC-BD982247209A}.All|x64.Build.0 = Release|x64
+ {9778F1C0-09BC-4698-8EBC-BD982247209A}.Debug|Win32.ActiveCfg = Debug|Win32
+ {9778F1C0-09BC-4698-8EBC-BD982247209A}.Debug|Win32.Build.0 = Debug|Win32
+ {9778F1C0-09BC-4698-8EBC-BD982247209A}.Debug|x64.ActiveCfg = Debug|x64
+ {9778F1C0-09BC-4698-8EBC-BD982247209A}.Debug|x64.Build.0 = Debug|x64
+ {9778F1C0-09BC-4698-8EBC-BD982247209A}.Release|Win32.ActiveCfg = Release|Win32
+ {9778F1C0-09BC-4698-8EBC-BD982247209A}.Release|Win32.Build.0 = Release|Win32
+ {9778F1C0-09BC-4698-8EBC-BD982247209A}.Release|x64.ActiveCfg = Release|x64
+ {9778F1C0-09BC-4698-8EBC-BD982247209A}.Release|x64.Build.0 = Release|x64
+ {AFA983D6-4569-4F88-BA94-555ED00FD9A8}.All|Win32.ActiveCfg = Release|x64
+ {AFA983D6-4569-4F88-BA94-555ED00FD9A8}.All|x64.ActiveCfg = Release|x64
+ {AFA983D6-4569-4F88-BA94-555ED00FD9A8}.All|x64.Build.0 = Release|x64
+ {AFA983D6-4569-4F88-BA94-555ED00FD9A8}.Debug|Win32.ActiveCfg = Debug|Win32
+ {AFA983D6-4569-4F88-BA94-555ED00FD9A8}.Debug|Win32.Build.0 = Debug|Win32
+ {AFA983D6-4569-4F88-BA94-555ED00FD9A8}.Debug|x64.ActiveCfg = Debug|x64
+ {AFA983D6-4569-4F88-BA94-555ED00FD9A8}.Debug|x64.Build.0 = Debug|x64
+ {AFA983D6-4569-4F88-BA94-555ED00FD9A8}.Release|Win32.ActiveCfg = Release|Win32
+ {AFA983D6-4569-4F88-BA94-555ED00FD9A8}.Release|Win32.Build.0 = Release|Win32
+ {AFA983D6-4569-4F88-BA94-555ED00FD9A8}.Release|x64.ActiveCfg = Release|x64
+ {AFA983D6-4569-4F88-BA94-555ED00FD9A8}.Release|x64.Build.0 = Release|x64
+ {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.All|Win32.ActiveCfg = Release|Win32
+ {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.All|Win32.Build.0 = Release|Win32
+ {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.All|x64.ActiveCfg = Release|Win32
+ {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.Debug|Win32.ActiveCfg = Debug|Win32
+ {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.Debug|Win32.Build.0 = Debug|Win32
+ {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.Debug|x64.ActiveCfg = Debug|x64
+ {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.Debug|x64.Build.0 = Debug|x64
+ {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.Release|Win32.ActiveCfg = Release|Win32
+ {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.Release|Win32.Build.0 = Release|Win32
+ {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.Release|x64.ActiveCfg = Release|x64
+ {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.Release|x64.Build.0 = Release|x64
+ {990BAA76-89D3-4E38-8479-C7B28784EFC8}.All|Win32.ActiveCfg = Release|Win32
+ {990BAA76-89D3-4E38-8479-C7B28784EFC8}.All|Win32.Build.0 = Release|Win32
+ {990BAA76-89D3-4E38-8479-C7B28784EFC8}.All|x64.ActiveCfg = Release|Win32
+ {990BAA76-89D3-4E38-8479-C7B28784EFC8}.Debug|Win32.ActiveCfg = Debug|Win32
+ {990BAA76-89D3-4E38-8479-C7B28784EFC8}.Debug|Win32.Build.0 = Debug|Win32
+ {990BAA76-89D3-4E38-8479-C7B28784EFC8}.Debug|x64.ActiveCfg = Debug|x64
+ {990BAA76-89D3-4E38-8479-C7B28784EFC8}.Debug|x64.Build.0 = Debug|x64
+ {990BAA76-89D3-4E38-8479-C7B28784EFC8}.Release|Win32.ActiveCfg = Release|Win32
+ {990BAA76-89D3-4E38-8479-C7B28784EFC8}.Release|Win32.Build.0 = Release|Win32
+ {990BAA76-89D3-4E38-8479-C7B28784EFC8}.Release|x64.ActiveCfg = Release|x64
+ {990BAA76-89D3-4E38-8479-C7B28784EFC8}.Release|x64.Build.0 = Release|x64
+ {1E21AFE0-6FDB-41D2-942D-863607C24B91}.All|Win32.ActiveCfg = Release|x64
+ {1E21AFE0-6FDB-41D2-942D-863607C24B91}.All|x64.ActiveCfg = Release|x64
+ {1E21AFE0-6FDB-41D2-942D-863607C24B91}.All|x64.Build.0 = Release|x64
+ {1E21AFE0-6FDB-41D2-942D-863607C24B91}.Debug|Win32.ActiveCfg = Debug|Win32
+ {1E21AFE0-6FDB-41D2-942D-863607C24B91}.Debug|Win32.Build.0 = Debug|Win32
+ {1E21AFE0-6FDB-41D2-942D-863607C24B91}.Debug|x64.ActiveCfg = Debug|x64
+ {1E21AFE0-6FDB-41D2-942D-863607C24B91}.Debug|x64.Build.0 = Debug|x64
+ {1E21AFE0-6FDB-41D2-942D-863607C24B91}.Release|Win32.ActiveCfg = Release|Win32
+ {1E21AFE0-6FDB-41D2-942D-863607C24B91}.Release|Win32.Build.0 = Release|Win32
+ {1E21AFE0-6FDB-41D2-942D-863607C24B91}.Release|x64.ActiveCfg = Release|x64
+ {1E21AFE0-6FDB-41D2-942D-863607C24B91}.Release|x64.Build.0 = Release|x64
+ {2E250296-0C08-4342-9C8A-BCBDD0E7DF65}.All|Win32.ActiveCfg = Release|x64
+ {2E250296-0C08-4342-9C8A-BCBDD0E7DF65}.All|x64.ActiveCfg = Release|x64
+ {2E250296-0C08-4342-9C8A-BCBDD0E7DF65}.All|x64.Build.0 = Release|x64
+ {2E250296-0C08-4342-9C8A-BCBDD0E7DF65}.Debug|Win32.ActiveCfg = Debug|Win32
+ {2E250296-0C08-4342-9C8A-BCBDD0E7DF65}.Debug|Win32.Build.0 = Debug|Win32
+ {2E250296-0C08-4342-9C8A-BCBDD0E7DF65}.Debug|x64.ActiveCfg = Debug|x64
+ {2E250296-0C08-4342-9C8A-BCBDD0E7DF65}.Debug|x64.Build.0 = Debug|x64
+ {2E250296-0C08-4342-9C8A-BCBDD0E7DF65}.Release|Win32.ActiveCfg = Release|Win32
+ {2E250296-0C08-4342-9C8A-BCBDD0E7DF65}.Release|Win32.Build.0 = Release|Win32
+ {2E250296-0C08-4342-9C8A-BCBDD0E7DF65}.Release|x64.ActiveCfg = Release|x64
+ {2E250296-0C08-4342-9C8A-BCBDD0E7DF65}.Release|x64.Build.0 = Release|x64
+ {D578E676-7EC8-4548-BD8B-845C635F14AD}.All|Win32.ActiveCfg = Release|Win32
+ {D578E676-7EC8-4548-BD8B-845C635F14AD}.All|Win32.Build.0 = Release|Win32
+ {D578E676-7EC8-4548-BD8B-845C635F14AD}.All|x64.ActiveCfg = Release|Win32
+ {D578E676-7EC8-4548-BD8B-845C635F14AD}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D578E676-7EC8-4548-BD8B-845C635F14AD}.Debug|Win32.Build.0 = Debug|Win32
+ {D578E676-7EC8-4548-BD8B-845C635F14AD}.Debug|x64.ActiveCfg = Debug|Win32
+ {D578E676-7EC8-4548-BD8B-845C635F14AD}.Debug|x64.Build.0 = Debug|Win32
+ {D578E676-7EC8-4548-BD8B-845C635F14AD}.Release|Win32.ActiveCfg = Release|Win32
+ {D578E676-7EC8-4548-BD8B-845C635F14AD}.Release|Win32.Build.0 = Release|Win32
+ {D578E676-7EC8-4548-BD8B-845C635F14AD}.Release|x64.ActiveCfg = Release|Win32
+ {D578E676-7EC8-4548-BD8B-845C635F14AD}.Release|x64.Build.0 = Release|Win32
+ {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.All|Win32.ActiveCfg = Release|Win32
+ {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.All|Win32.Build.0 = Release|Win32
+ {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.All|x64.ActiveCfg = Release|Win32
+ {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Debug|Win32.Build.0 = Debug|Win32
+ {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Debug|x64.ActiveCfg = Debug|x64
+ {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Debug|x64.Build.0 = Debug|x64
+ {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Release|Win32.ActiveCfg = Release|Win32
+ {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Release|Win32.Build.0 = Release|Win32
+ {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Release|x64.ActiveCfg = Release|x64
+ {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Release|x64.Build.0 = Release|x64
+ {B4B62169-5AD4-4559-8707-3D933AC5DB39}.All|Win32.ActiveCfg = Release|Win32
+ {B4B62169-5AD4-4559-8707-3D933AC5DB39}.All|Win32.Build.0 = Release|Win32
+ {B4B62169-5AD4-4559-8707-3D933AC5DB39}.All|x64.ActiveCfg = Release|Win32
+ {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Debug|Win32.ActiveCfg = Debug|Win32
+ {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Debug|Win32.Build.0 = Debug|Win32
+ {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Debug|x64.ActiveCfg = Debug|x64
+ {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Debug|x64.Build.0 = Debug|x64
+ {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Release|Win32.ActiveCfg = Release|Win32
+ {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Release|Win32.Build.0 = Release|Win32
+ {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Release|x64.ActiveCfg = Release|x64
+ {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Release|x64.Build.0 = Release|x64
+ {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.All|Win32.ActiveCfg = Release|Win32
+ {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.All|Win32.Build.0 = Release|Win32
+ {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.All|x64.ActiveCfg = Release|Win32
+ {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.Debug|Win32.ActiveCfg = Debug|Win32
+ {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.Debug|Win32.Build.0 = Debug|Win32
+ {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.Debug|x64.ActiveCfg = Debug|x64
+ {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.Debug|x64.Build.0 = Debug|x64
+ {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.Release|Win32.ActiveCfg = Release|Win32
+ {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.Release|Win32.Build.0 = Release|Win32
+ {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.Release|x64.ActiveCfg = Release|x64
+ {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.Release|x64.Build.0 = Release|x64
+ {42E721FD-43D6-4B04-A34B-42567199FFB8}.All|Win32.ActiveCfg = Release|x64
+ {42E721FD-43D6-4B04-A34B-42567199FFB8}.All|x64.ActiveCfg = Release|x64
+ {42E721FD-43D6-4B04-A34B-42567199FFB8}.All|x64.Build.0 = Release|x64
+ {42E721FD-43D6-4B04-A34B-42567199FFB8}.Debug|Win32.ActiveCfg = Debug|Win32
+ {42E721FD-43D6-4B04-A34B-42567199FFB8}.Debug|x64.ActiveCfg = Debug|x64
+ {42E721FD-43D6-4B04-A34B-42567199FFB8}.Release|Win32.ActiveCfg = Release|Win32
+ {42E721FD-43D6-4B04-A34B-42567199FFB8}.Release|x64.ActiveCfg = Release|x64
+ {23B4D303-79FC-49E0-89E2-2280E7E28940}.All|Win32.ActiveCfg = Release|x64
+ {23B4D303-79FC-49E0-89E2-2280E7E28940}.All|x64.ActiveCfg = Release|x64
+ {23B4D303-79FC-49E0-89E2-2280E7E28940}.All|x64.Build.0 = Release|x64
+ {23B4D303-79FC-49E0-89E2-2280E7E28940}.Debug|Win32.ActiveCfg = Debug|Win32
+ {23B4D303-79FC-49E0-89E2-2280E7E28940}.Debug|Win32.Build.0 = Debug|Win32
+ {23B4D303-79FC-49E0-89E2-2280E7E28940}.Debug|x64.ActiveCfg = Debug|x64
+ {23B4D303-79FC-49E0-89E2-2280E7E28940}.Debug|x64.Build.0 = Debug|x64
+ {23B4D303-79FC-49E0-89E2-2280E7E28940}.Release|Win32.ActiveCfg = Release|Win32
+ {23B4D303-79FC-49E0-89E2-2280E7E28940}.Release|Win32.Build.0 = Release|Win32
+ {23B4D303-79FC-49E0-89E2-2280E7E28940}.Release|x64.ActiveCfg = Release|x64
+ {23B4D303-79FC-49E0-89E2-2280E7E28940}.Release|x64.Build.0 = Release|x64
+ {0807C5CB-F6FF-451D-89F0-1F7B2E1D9169}.All|Win32.ActiveCfg = Release|x64
+ {0807C5CB-F6FF-451D-89F0-1F7B2E1D9169}.All|x64.ActiveCfg = Release|x64
+ {0807C5CB-F6FF-451D-89F0-1F7B2E1D9169}.All|x64.Build.0 = Release|x64
+ {0807C5CB-F6FF-451D-89F0-1F7B2E1D9169}.Debug|Win32.ActiveCfg = Debug|Win32
+ {0807C5CB-F6FF-451D-89F0-1F7B2E1D9169}.Debug|Win32.Build.0 = Debug|Win32
+ {0807C5CB-F6FF-451D-89F0-1F7B2E1D9169}.Debug|x64.ActiveCfg = Debug|x64
+ {0807C5CB-F6FF-451D-89F0-1F7B2E1D9169}.Debug|x64.Build.0 = Debug|x64
+ {0807C5CB-F6FF-451D-89F0-1F7B2E1D9169}.Release|Win32.ActiveCfg = Release|Win32
+ {0807C5CB-F6FF-451D-89F0-1F7B2E1D9169}.Release|Win32.Build.0 = Release|Win32
+ {0807C5CB-F6FF-451D-89F0-1F7B2E1D9169}.Release|x64.ActiveCfg = Release|x64
+ {0807C5CB-F6FF-451D-89F0-1F7B2E1D9169}.Release|x64.Build.0 = Release|x64
+ {BDA173DB-F8EF-4270-9553-B453AF92E43A}.All|Win32.ActiveCfg = Release|x64
+ {BDA173DB-F8EF-4270-9553-B453AF92E43A}.All|x64.ActiveCfg = Release|x64
+ {BDA173DB-F8EF-4270-9553-B453AF92E43A}.All|x64.Build.0 = Release|x64
+ {BDA173DB-F8EF-4270-9553-B453AF92E43A}.Debug|Win32.ActiveCfg = Debug|Win32
+ {BDA173DB-F8EF-4270-9553-B453AF92E43A}.Debug|Win32.Build.0 = Debug|Win32
+ {BDA173DB-F8EF-4270-9553-B453AF92E43A}.Debug|x64.ActiveCfg = Debug|x64
+ {BDA173DB-F8EF-4270-9553-B453AF92E43A}.Debug|x64.Build.0 = Debug|x64
+ {BDA173DB-F8EF-4270-9553-B453AF92E43A}.Release|Win32.ActiveCfg = Release|Win32
+ {BDA173DB-F8EF-4270-9553-B453AF92E43A}.Release|Win32.Build.0 = Release|Win32
+ {BDA173DB-F8EF-4270-9553-B453AF92E43A}.Release|x64.ActiveCfg = Release|x64
+ {BDA173DB-F8EF-4270-9553-B453AF92E43A}.Release|x64.Build.0 = Release|x64
+ {74B120FF-6935-4DFE-A142-CDB6BEA99C90}.All|Win32.ActiveCfg = Release|Win32
+ {74B120FF-6935-4DFE-A142-CDB6BEA99C90}.All|Win32.Build.0 = Release|Win32
+ {74B120FF-6935-4DFE-A142-CDB6BEA99C90}.All|x64.ActiveCfg = Release|Win32
+ {74B120FF-6935-4DFE-A142-CDB6BEA99C90}.Debug|Win32.ActiveCfg = Debug|Win32
+ {74B120FF-6935-4DFE-A142-CDB6BEA99C90}.Debug|x64.ActiveCfg = Debug|x64
+ {74B120FF-6935-4DFE-A142-CDB6BEA99C90}.Release|Win32.ActiveCfg = Release|Win32
+ {74B120FF-6935-4DFE-A142-CDB6BEA99C90}.Release|x64.ActiveCfg = Release|x64
+ {26C82FCE-E0CF-4D10-A00C-D8E582FFEB53}.All|Win32.ActiveCfg = Debug|Win32
+ {26C82FCE-E0CF-4D10-A00C-D8E582FFEB53}.All|Win32.Build.0 = Debug|Win32
+ {26C82FCE-E0CF-4D10-A00C-D8E582FFEB53}.All|x64.ActiveCfg = Debug|Win32
+ {26C82FCE-E0CF-4D10-A00C-D8E582FFEB53}.Debug|Win32.ActiveCfg = Debug|Win32
+ {26C82FCE-E0CF-4D10-A00C-D8E582FFEB53}.Debug|x64.ActiveCfg = Debug|x64
+ {26C82FCE-E0CF-4D10-A00C-D8E582FFEB53}.Release|Win32.ActiveCfg = Release|Win32
+ {26C82FCE-E0CF-4D10-A00C-D8E582FFEB53}.Release|x64.ActiveCfg = Release|x64
+ {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}.All|Win32.ActiveCfg = Debug|x64
+ {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}.All|x64.ActiveCfg = Debug|x64
+ {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}.All|x64.Build.0 = Debug|x64
+ {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}.Debug|Win32.ActiveCfg = Debug|Win32
+ {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}.Debug|Win32.Build.0 = Debug|Win32
+ {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}.Debug|x64.ActiveCfg = Debug|x64
+ {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}.Debug|x64.Build.0 = Debug|x64
+ {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}.Release|Win32.ActiveCfg = Release|Win32
+ {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}.Release|Win32.Build.0 = Release|Win32
+ {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}.Release|x64.ActiveCfg = Release|x64
+ {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A}.Release|x64.Build.0 = Release|x64
+ {21A7DA70-555E-49FA-942B-D84A38B61243}.All|Win32.ActiveCfg = Release|Win32
+ {21A7DA70-555E-49FA-942B-D84A38B61243}.All|Win32.Build.0 = Release|Win32
+ {21A7DA70-555E-49FA-942B-D84A38B61243}.All|x64.ActiveCfg = Release|Win32
+ {21A7DA70-555E-49FA-942B-D84A38B61243}.Debug|Win32.ActiveCfg = Debug|Win32
+ {21A7DA70-555E-49FA-942B-D84A38B61243}.Debug|Win32.Build.0 = Debug|Win32
+ {21A7DA70-555E-49FA-942B-D84A38B61243}.Debug|x64.ActiveCfg = Debug|Win32
+ {21A7DA70-555E-49FA-942B-D84A38B61243}.Debug|x64.Build.0 = Debug|Win32
+ {21A7DA70-555E-49FA-942B-D84A38B61243}.Release|Win32.ActiveCfg = Release|Win32
+ {21A7DA70-555E-49FA-942B-D84A38B61243}.Release|Win32.Build.0 = Release|Win32
+ {21A7DA70-555E-49FA-942B-D84A38B61243}.Release|x64.ActiveCfg = Release|Win32
+ {21A7DA70-555E-49FA-942B-D84A38B61243}.Release|x64.Build.0 = Release|Win32
+ {A4D67895-E709-40C7-82B6-DE1D12DDDE04}.All|Win32.ActiveCfg = Release|x64
+ {A4D67895-E709-40C7-82B6-DE1D12DDDE04}.All|x64.ActiveCfg = Release|x64
+ {A4D67895-E709-40C7-82B6-DE1D12DDDE04}.All|x64.Build.0 = Release|x64
+ {A4D67895-E709-40C7-82B6-DE1D12DDDE04}.Debug|Win32.ActiveCfg = Debug|Win32
+ {A4D67895-E709-40C7-82B6-DE1D12DDDE04}.Debug|Win32.Build.0 = Debug|Win32
+ {A4D67895-E709-40C7-82B6-DE1D12DDDE04}.Debug|x64.ActiveCfg = Debug|x64
+ {A4D67895-E709-40C7-82B6-DE1D12DDDE04}.Debug|x64.Build.0 = Debug|x64
+ {A4D67895-E709-40C7-82B6-DE1D12DDDE04}.Release|Win32.ActiveCfg = Release|Win32
+ {A4D67895-E709-40C7-82B6-DE1D12DDDE04}.Release|Win32.Build.0 = Release|Win32
+ {A4D67895-E709-40C7-82B6-DE1D12DDDE04}.Release|x64.ActiveCfg = Release|x64
+ {A4D67895-E709-40C7-82B6-DE1D12DDDE04}.Release|x64.Build.0 = Release|x64
+ {2390F054-A7F1-4CB9-ACB0-F46EC6E77B5B}.All|Win32.ActiveCfg = Release|x64
+ {2390F054-A7F1-4CB9-ACB0-F46EC6E77B5B}.All|x64.ActiveCfg = Release|x64
+ {2390F054-A7F1-4CB9-ACB0-F46EC6E77B5B}.All|x64.Build.0 = Release|x64
+ {2390F054-A7F1-4CB9-ACB0-F46EC6E77B5B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {2390F054-A7F1-4CB9-ACB0-F46EC6E77B5B}.Debug|Win32.Build.0 = Debug|Win32
+ {2390F054-A7F1-4CB9-ACB0-F46EC6E77B5B}.Debug|x64.ActiveCfg = Debug|x64
+ {2390F054-A7F1-4CB9-ACB0-F46EC6E77B5B}.Debug|x64.Build.0 = Debug|x64
+ {2390F054-A7F1-4CB9-ACB0-F46EC6E77B5B}.Release|Win32.ActiveCfg = Release|Win32
+ {2390F054-A7F1-4CB9-ACB0-F46EC6E77B5B}.Release|Win32.Build.0 = Release|Win32
+ {2390F054-A7F1-4CB9-ACB0-F46EC6E77B5B}.Release|x64.ActiveCfg = Release|x64
+ {2390F054-A7F1-4CB9-ACB0-F46EC6E77B5B}.Release|x64.Build.0 = Release|x64
+ {E5A9BCDA-B82D-4B08-B23E-9A782E367888}.All|Win32.ActiveCfg = Debug|x64
+ {E5A9BCDA-B82D-4B08-B23E-9A782E367888}.All|x64.ActiveCfg = Debug|x64
+ {E5A9BCDA-B82D-4B08-B23E-9A782E367888}.All|x64.Build.0 = Debug|x64
+ {E5A9BCDA-B82D-4B08-B23E-9A782E367888}.Debug|Win32.ActiveCfg = Debug|Win32
+ {E5A9BCDA-B82D-4B08-B23E-9A782E367888}.Debug|Win32.Build.0 = Debug|Win32
+ {E5A9BCDA-B82D-4B08-B23E-9A782E367888}.Debug|x64.ActiveCfg = Debug|x64
+ {E5A9BCDA-B82D-4B08-B23E-9A782E367888}.Debug|x64.Build.0 = Debug|x64
+ {E5A9BCDA-B82D-4B08-B23E-9A782E367888}.Release|Win32.ActiveCfg = Release|Win32
+ {E5A9BCDA-B82D-4B08-B23E-9A782E367888}.Release|Win32.Build.0 = Release|Win32
+ {E5A9BCDA-B82D-4B08-B23E-9A782E367888}.Release|x64.ActiveCfg = Release|x64
+ {E5A9BCDA-B82D-4B08-B23E-9A782E367888}.Release|x64.Build.0 = Release|x64
+ {510BDAA8-C04D-47DB-8482-E6AF380D3E07}.All|Win32.ActiveCfg = Release|x64
+ {510BDAA8-C04D-47DB-8482-E6AF380D3E07}.All|x64.ActiveCfg = Release|x64
+ {510BDAA8-C04D-47DB-8482-E6AF380D3E07}.All|x64.Build.0 = Release|x64
+ {510BDAA8-C04D-47DB-8482-E6AF380D3E07}.Debug|Win32.ActiveCfg = Debug|Win32
+ {510BDAA8-C04D-47DB-8482-E6AF380D3E07}.Debug|Win32.Build.0 = Debug|Win32
+ {510BDAA8-C04D-47DB-8482-E6AF380D3E07}.Debug|x64.ActiveCfg = Debug|x64
+ {510BDAA8-C04D-47DB-8482-E6AF380D3E07}.Debug|x64.Build.0 = Debug|x64
+ {510BDAA8-C04D-47DB-8482-E6AF380D3E07}.Release|Win32.ActiveCfg = Release|Win32
+ {510BDAA8-C04D-47DB-8482-E6AF380D3E07}.Release|Win32.Build.0 = Release|Win32
+ {510BDAA8-C04D-47DB-8482-E6AF380D3E07}.Release|x64.ActiveCfg = Release|x64
+ {510BDAA8-C04D-47DB-8482-E6AF380D3E07}.Release|x64.Build.0 = Release|x64
+ {3CF7C0E0-07C2-473A-A1E4-2274AEEC1268}.All|Win32.ActiveCfg = Release|x64
+ {3CF7C0E0-07C2-473A-A1E4-2274AEEC1268}.All|x64.ActiveCfg = Release|x64
+ {3CF7C0E0-07C2-473A-A1E4-2274AEEC1268}.All|x64.Build.0 = Release|x64
+ {3CF7C0E0-07C2-473A-A1E4-2274AEEC1268}.Debug|Win32.ActiveCfg = Debug|Win32
+ {3CF7C0E0-07C2-473A-A1E4-2274AEEC1268}.Debug|Win32.Build.0 = Debug|Win32
+ {3CF7C0E0-07C2-473A-A1E4-2274AEEC1268}.Debug|x64.ActiveCfg = Debug|x64
+ {3CF7C0E0-07C2-473A-A1E4-2274AEEC1268}.Debug|x64.Build.0 = Debug|x64
+ {3CF7C0E0-07C2-473A-A1E4-2274AEEC1268}.Release|Win32.ActiveCfg = Release|Win32
+ {3CF7C0E0-07C2-473A-A1E4-2274AEEC1268}.Release|Win32.Build.0 = Release|Win32
+ {3CF7C0E0-07C2-473A-A1E4-2274AEEC1268}.Release|x64.ActiveCfg = Release|x64
+ {3CF7C0E0-07C2-473A-A1E4-2274AEEC1268}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0} = {F881ADA2-2F1A-4046-9FEB-191D9422D781}
+ {5580D60E-0F77-4716-9CD4-B8E5986FA375} = {F881ADA2-2F1A-4046-9FEB-191D9422D781}
+ {D3EC0AFF-76FC-4210-A825-9A17410660A3} = {F881ADA2-2F1A-4046-9FEB-191D9422D781}
+ {FEA1EEF7-876F-48DE-88BF-C0E3E606D758} = {F881ADA2-2F1A-4046-9FEB-191D9422D781}
+ {8DEB383C-4091-4F42-A56F-C9E46D552D79} = {F881ADA2-2F1A-4046-9FEB-191D9422D781}
+ {2C3C2423-234B-4772-8899-D3B137E5CA35} = {F881ADA2-2F1A-4046-9FEB-191D9422D781}
+ {0B6C905B-142E-4999-B39D-92FF7951E921} = {F881ADA2-2F1A-4046-9FEB-191D9422D781}
+ {7F1610F1-DD5A-4CF7-8610-30AB12C60ADD} = {F881ADA2-2F1A-4046-9FEB-191D9422D781}
+ {D5C87B19-150D-4EF3-A671-96589BD2D14A} = {F881ADA2-2F1A-4046-9FEB-191D9422D781}
+ {4D418176-3B33-47E6-A63E-01BA34ADD21C} = {F881ADA2-2F1A-4046-9FEB-191D9422D781}
+ {AFA983D6-4569-4F88-BA94-555ED00FD9A8} = {F881ADA2-2F1A-4046-9FEB-191D9422D781}
+ {5FD31A25-5D83-4794-8BEE-904DAD84CE71} = {9460B5F1-0A95-41C4-BEB7-9C2C96459A7C}
+ {FFAA4C52-3A53-4F99-90C1-D59D1F0427F3} = {9460B5F1-0A95-41C4-BEB7-9C2C96459A7C}
+ {0DF3ABD0-DDC0-4265-B778-07C66780979B} = {9460B5F1-0A95-41C4-BEB7-9C2C96459A7C}
+ {B3F424EC-3D8F-417C-B244-3919D5E1A577} = {9460B5F1-0A95-41C4-BEB7-9C2C96459A7C}
+ {05C9FB27-480E-4D53-B3B7-6338E2526666} = {9460B5F1-0A95-41C4-BEB7-9C2C96459A7C}
+ {05C9FB27-480E-4D53-B3B7-7338E2514666} = {9460B5F1-0A95-41C4-BEB7-9C2C96459A7C}
+ {CC1DD008-9406-448D-A0AD-33C3186CFADB} = {9460B5F1-0A95-41C4-BEB7-9C2C96459A7C}
+ {48414740-C693-4968-9846-EE058020C64F} = {9460B5F1-0A95-41C4-BEB7-9C2C96459A7C}
+ {C6E78A4C-DB1E-47F4-9B63-4DC27D86343F} = {9460B5F1-0A95-41C4-BEB7-9C2C96459A7C}
+ {74B120FF-6935-4DFE-A142-CDB6BEA99C90} = {9460B5F1-0A95-41C4-BEB7-9C2C96459A7C}
+ {30A5B29C-983E-4580-9FD0-D647CCDCC7EB} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {C24FB505-05D7-4319-8485-7540B44C8603} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {B5881A85-FE70-4F64-8607-2CAAE52669C6} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {71A967D5-0E99-4CEF-A587-98836EE6F2EF} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {3850D93A-5F24-4922-BC1C-74D08C37C256} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {D7F1E3F2-A3F4-474C-8555-15122571AF52} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {F6A33240-8F29-48BD-98F0-826995911799} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {65A6273D-FCAB-4C55-B09E-65100141A5D4} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {E3246D17-E29B-4AB5-962A-C69B0C5837BB} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {2A3D00C6-588D-4E86-81AC-9EF5EDE86E03} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {14E4A972-9CFB-436D-B0A5-4943F3F80D47} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {329FD5B0-EF28-4606-86D0-F6EA21CF8E36} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {1A3793D1-05D1-4B57-9B0F-5AF3E79DC439} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {11C9BC3D-45E9-46E3-BE84-B8CEE4685E39} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {3C977801-FE88-48F2-83D3-FA2EBFF6688E} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {432DB165-1EB2-4781-A9C0-71E62610B20A} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {990BAA76-89D3-4E38-8479-C7B28784EFC8} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {1E21AFE0-6FDB-41D2-942D-863607C24B91} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {2E250296-0C08-4342-9C8A-BCBDD0E7DF65} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {42E721FD-43D6-4B04-A34B-42567199FFB8} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {0807C5CB-F6FF-451D-89F0-1F7B2E1D9169} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {BDA173DB-F8EF-4270-9553-B453AF92E43A} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {07113B25-D3AF-4E04-BA77-4CD1171F022C} = {C5F182F9-754A-4EC5-B50F-76ED02BE13F4}
+ {A27CCA23-1541-4337-81A4-F0A6413078A0} = {C5F182F9-754A-4EC5-B50F-76ED02BE13F4}
+ {E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24} = {C5F182F9-754A-4EC5-B50F-76ED02BE13F4}
+ {784113EF-44D9-4949-835D-7065D3C7AD08} = {9ADF1E48-2F5C-4ED7-A893-596259FABFE0}
+ {05515420-16DE-4E63-BE73-85BE85BA5142} = {9ADF1E48-2F5C-4ED7-A893-596259FABFE0}
+ {44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E} = {9ADF1E48-2F5C-4ED7-A893-596259FABFE0}
+ {AFAC0568-7548-42D5-9F6A-8D3400A1E4F6} = {A5A27244-AD24-46E5-B01B-840CD296C91D}
+ {9254C4B0-6F60-42B6-BB3A-36D63FC001C7} = {A5A27244-AD24-46E5-B01B-840CD296C91D}
+ {2CA40887-1622-46A1-A7F9-17FD7E7E545B} = {A5A27244-AD24-46E5-B01B-840CD296C91D}
+ {6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52} = {A5A27244-AD24-46E5-B01B-840CD296C91D}
+ {38FE0559-9910-43A8-9E45-3E5004C27692} = {A5A27244-AD24-46E5-B01B-840CD296C91D}
+ {1A1FF289-4FD6-4285-A422-D31DD67A4723} = {CBD81696-EFB4-4D2F-8451-1B8DAA86155A}
+ {EC3E5C7F-EE09-47E2-80FE-546363D14A98} = {B8F5B47B-8568-46EB-B320-64C17D2A98BC}
+ {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F} = {0C808854-54D1-4230-BFF5-77B5FD905000}
+ {ACFFF684-4D19-4D48-AF12-88EA1D778BDF} = {0C808854-54D1-4230-BFF5-77B5FD905000}
+ {8F992C49-6C51-412F-B2A3-34EAB708EB65} = {0C808854-54D1-4230-BFF5-77B5FD905000}
+ {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF} = {0C808854-54D1-4230-BFF5-77B5FD905000}
+ {028C7278-05D7-4E18-82FE-BE231B844F41} = {0C808854-54D1-4230-BFF5-77B5FD905000}
+ {36E854E3-CE12-4348-A125-CCF3F9D74813} = {0C808854-54D1-4230-BFF5-77B5FD905000}
+ {7B077E7F-1BE7-4291-AB86-55E527B25CAC} = {0C808854-54D1-4230-BFF5-77B5FD905000}
+ {7B42BDA1-72C0-4378-A9B6-5C530F8CD61E} = {0C808854-54D1-4230-BFF5-77B5FD905000}
+ {692F6330-4D87-4C82-81DF-40DB5892636E} = {4CF6A6AC-07DE-4B9E-ABE1-7F98B64E0BB0}
+ {2286DA73-9FC5-45BC-A508-85994C3317AB} = {4CF6A6AC-07DE-4B9E-ABE1-7F98B64E0BB0}
+ {66444AEE-554C-11DD-A9F0-8C5D56D89593} = {4CF6A6AC-07DE-4B9E-ABE1-7F98B64E0BB0}
+ {D07C378A-F5F7-438F-ADF3-4AC4FB1883CD} = {4CF6A6AC-07DE-4B9E-ABE1-7F98B64E0BB0}
+ {1C453396-D912-4213-89FD-9B489162B7B5} = {A7AB4405-FDB7-4853-9FBB-1516B1C3D80A}
+ {D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909} = {A7AB4405-FDB7-4853-9FBB-1516B1C3D80A}
+ {CBEC7225-0C21-4DA8-978E-1F158F8AD950} = {F69A4A6B-9360-4EBB-A280-22AA3C455AC5}
+ {AB91A099-7690-4ECF-8994-E458F4EA1ED4} = {F69A4A6B-9360-4EBB-A280-22AA3C455AC5}
+ {08DAD348-9E0A-4A2E-97F1-F1E7E24A7836} = {F69A4A6B-9360-4EBB-A280-22AA3C455AC5}
+ {89385C74-5860-4174-9CAF-A39E7C48909C} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {1906D736-08BD-4EE1-924F-B536249B9A54} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {EEF031CB-FED8-451E-A471-91EC8D4F6750} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {8D04B550-D240-4A44-8A18-35DA3F7038D9} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {1CED5987-A529-46DC-B30F-870D85FF9C94} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {F057DA7F-79E5-4B00-845C-EF446EF055E3} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {E727E8F6-935D-46FE-8B0E-37834748A0E3} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {3D0370CA-BED2-4657-A475-32375CBCB6E4} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {87EE9DA4-DE1E-4448-8324-183C98DCA588} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {155844C3-EC5F-407F-97A4-A2DDADED9B2F} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {204FA0DE-305D-4414-AE2E-F195A23F390D} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {70A49BC2-7500-41D0-B75D-EDCC5BE987A0} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {0A18A071-125E-442F-AFF7-A3F68ABECF99} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {94001A0E-A837-445C-8004-F918F10D0226} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {0AD1177E-1FD8-4643-9391-431467A11084} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {E316772F-5D8F-4F2A-8F71-094C3E859D34} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {D3D8B329-20BE-475E-9E83-653CEA0E0EF5} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {419C8F80-D858-4B48-A25C-AF4007608137} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {CF405366-9558-4AE8-90EF-5E21B51CCB4E} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {401A40CD-5DB4-4E34-AC68-FA99E9FAC014} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {E972C52F-9E85-4D65-B19C-031E511E9DB4} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {03207781-0D1C-4DB3-A71D-45C608F28DBD} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {9A5DDF08-C88C-4A35-B7F6-D605228446BD} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {D0B36172-CD76-454A-9B89-990025266C2A} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {DEE932AB-5911-4700-9EEB-8C7090A0A330} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {329A6FA0-0FCC-4435-A950-E670AEFA9838} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {CF70F278-3364-4395-A2E1-23501C9B8AD2} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {62F27B1A-C919-4A70-8478-51F178F3B18F} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {ABB71A76-42B0-47A4-973A-42E3D920C6FD} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {9778F1C0-09BC-4698-8EBC-BD982247209A} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {56B91D01-9150-4BBF-AFA1-5B68AB991B76} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {B376D494-D7DD-4B2A-99E2-52916D5A8CD8} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {23B4D303-79FC-49E0-89E2-2280E7E28940} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {26C82FCE-E0CF-4D10-A00C-D8E582FFEB53} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {FE02CD06-DD97-489C-8F61-B5E7F89BCC0A} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {3783935D-7C0A-4166-A376-C3D8E64F3A9C} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A} = {C120A020-773F-4EA3-923F-B67AF28B750D}
+ {4F92B672-DADB-4047-8D6A-4BB3796733FD} = {C120A020-773F-4EA3-923F-B67AF28B750D}
+ {2DEE4895-1134-439C-B688-52203E57D878} = {C120A020-773F-4EA3-923F-B67AF28B750D}
+ {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E} = {C120A020-773F-4EA3-923F-B67AF28B750D}
+ {3CE1DC99-8246-4DB1-A709-74F19F08EC67} = {C120A020-773F-4EA3-923F-B67AF28B750D}
+ {87A1FE3D-F410-4C8E-9591-8C625985BC70} = {C120A020-773F-4EA3-923F-B67AF28B750D}
+ {6E49F6C2-ADDA-4BFB-81FE-AB9AF51B455F} = {C120A020-773F-4EA3-923F-B67AF28B750D}
+ {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B} = {C120A020-773F-4EA3-923F-B67AF28B750D}
+ {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B} = {C120A020-773F-4EA3-923F-B67AF28B750D}
+ {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B} = {C120A020-773F-4EA3-923F-B67AF28B750D}
+ {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B} = {C120A020-773F-4EA3-923F-B67AF28B750D}
+ {E796E337-DE78-4303-8614-9A590862EE95} = {C120A020-773F-4EA3-923F-B67AF28B750D}
+ {1F0A8A77-E661-418F-BB92-82172AE43803} = {C120A020-773F-4EA3-923F-B67AF28B750D}
+ {4F5C9D55-98EF-4256-8311-32D7BD360406} = {C120A020-773F-4EA3-923F-B67AF28B750D}
+ {E10571C4-E7F4-4608-B5F2-B22E7EB95400} = {C120A020-773F-4EA3-923F-B67AF28B750D}
+ {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19} = {C120A020-773F-4EA3-923F-B67AF28B750D}
+ {B808178B-82F0-4CF4-A2B1-921939FA24D0} = {C120A020-773F-4EA3-923F-B67AF28B750D}
+ {D578E676-7EC8-4548-BD8B-845C635F14AD} = {C120A020-773F-4EA3-923F-B67AF28B750D}
+ {21A7DA70-555E-49FA-942B-D84A38B61243} = {C120A020-773F-4EA3-923F-B67AF28B750D}
+ {988CACF7-3FCB-4992-BE69-77872AE67DC8} = {6CD61A1D-797C-470A-BE08-8C31B68BB336}
+ {5BC072DB-3826-48EA-AF34-FE32AA01E83B} = {6CD61A1D-797C-470A-BE08-8C31B68BB336}
+ {FA429E98-8B03-45E6-A096-A4BC5E821DE4} = {6CD61A1D-797C-470A-BE08-8C31B68BB336}
+ {06E3A538-AB32-44F2-B477-755FF9CB5D37} = {6CD61A1D-797C-470A-BE08-8C31B68BB336}
+ {6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05} = {6CD61A1D-797C-470A-BE08-8C31B68BB336}
+ {A4B122CF-5196-476B-8C0E-D8BD59AC3C14} = {6CD61A1D-797C-470A-BE08-8C31B68BB336}
+ {B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E} = {6CD61A1D-797C-470A-BE08-8C31B68BB336}
+ {0382E8FD-CFDC-41C0-8B03-792C7C84FC31} = {6CD61A1D-797C-470A-BE08-8C31B68BB336}
+ {3B08FEFD-4D3D-4C16-BA94-EE83509E32A0} = {57D119DC-484F-420F-B9E9-8589FD9A8DF8}
+ {3C90CCF0-2CDD-4A7A-ACFF-208C1E271692} = {3B08FEFD-4D3D-4C16-BA94-EE83509E32A0}
+ {C7E2382E-2C22-4D18-BF93-80C6A1FFA7AC} = {3B08FEFD-4D3D-4C16-BA94-EE83509E32A0}
+ {FC71C66E-E268-4EAD-B1F5-F008DC382E83} = {3B08FEFD-4D3D-4C16-BA94-EE83509E32A0}
+ {8E2E8798-8B6F-4A55-8E4F-4E6FDE40ED26} = {3B08FEFD-4D3D-4C16-BA94-EE83509E32A0}
+ {09455AA9-C243-4F16-A1A1-A016881A2765} = {3B08FEFD-4D3D-4C16-BA94-EE83509E32A0}
+ {CDE9B06A-3C27-4987-8FAE-DF1006BC705D} = {DB1024A8-41BF-4AD7-9AE6-13202230D1F3}
+ {57199684-EC63-4A60-9DC6-11815AF6B413} = {09455AA9-C243-4F16-A1A1-A016881A2765}
+ {2DED4BA2-D6B0-4064-BB2A-76DE3AA49E7C} = {09455AA9-C243-4F16-A1A1-A016881A2765}
+ {D4A12E4C-DBDA-4614-BA26-3425AE9F60F5} = {09455AA9-C243-4F16-A1A1-A016881A2765}
+ {765EF1B9-5027-4820-BC37-A44466A51631} = {57199684-EC63-4A60-9DC6-11815AF6B413}
+ {713E4747-1126-40B1-BD84-58F9A7745423} = {57199684-EC63-4A60-9DC6-11815AF6B413}
+ {D3E5C8ED-3A6A-4FEA-92A2-48A0BA865358} = {2DED4BA2-D6B0-4064-BB2A-76DE3AA49E7C}
+ {CC3E7F48-2590-49CB-AD8B-BE3650F55462} = {2DED4BA2-D6B0-4064-BB2A-76DE3AA49E7C}
+ {F1B71990-EB04-4EB5-B28A-BC3EB6F7E843} = {D4A12E4C-DBDA-4614-BA26-3425AE9F60F5}
+ {3DAF028C-AB5B-4183-A01B-DCC43F5A87F0} = {D4A12E4C-DBDA-4614-BA26-3425AE9F60F5}
+ {7A8D8174-B355-4114-AFC1-04777CB9DE0A} = {4F227C26-768F-46A3-8684-1D08A46FB374}
+ {7EB71250-F002-4ED8-92CA-CA218114537A} = {4F227C26-768F-46A3-8684-1D08A46FB374}
+ {464AAB78-5489-4916-BE51-BF8D61822311} = {4F227C26-768F-46A3-8684-1D08A46FB374}
+ {D1ABE208-6442-4FB4-9AAD-1677E41BC870} = {4F227C26-768F-46A3-8684-1D08A46FB374}
+ {BA599D0A-4310-4505-91DA-6A6447B3E289} = {4F227C26-768F-46A3-8684-1D08A46FB374}
+ {EED13FC7-4F81-4E6F-93DB-CDB7DF5CF959} = {4F227C26-768F-46A3-8684-1D08A46FB374}
+ {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2} = {62F27B1A-C919-4A70-8478-51F178F3B18F}
+ {B5A00BFA-6083-4FAE-A097-71642D6473B5} = {62F27B1A-C919-4A70-8478-51F178F3B18F}
+ {1C320193-46A6-4B34-9C56-8AB584FC1B56} = {62F27B1A-C919-4A70-8478-51F178F3B18F}
+ {72782932-37CC-46AE-8C7F-9A7B1A6EE108} = {62F27B1A-C919-4A70-8478-51F178F3B18F}
+ {12A49562-BAB9-43A3-A21D-15B60BBB4C31} = {62F27B1A-C919-4A70-8478-51F178F3B18F}
+ {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA} = {62F27B1A-C919-4A70-8478-51F178F3B18F}
+ {504B3154-7A4F-459D-9877-B951021C3F1F} = {62F27B1A-C919-4A70-8478-51F178F3B18F}
+ {746F3632-5BB2-4570-9453-31D6D58A7D8E} = {62F27B1A-C919-4A70-8478-51F178F3B18F}
+ {DEB01ACB-D65F-4A62-AED9-58C1054499E9} = {62F27B1A-C919-4A70-8478-51F178F3B18F}
+ {D331904D-A00A-4694-A5A3-FCFF64AB5DBE} = {B376D494-D7DD-4B2A-99E2-52916D5A8CD8}
+ {B4B62169-5AD4-4559-8707-3D933AC5DB39} = {B376D494-D7DD-4B2A-99E2-52916D5A8CD8}
+ {25BD39B1-C8BF-4676-A738-9CABD9C6BC79} = {B376D494-D7DD-4B2A-99E2-52916D5A8CD8}
+ {A4D67895-E709-40C7-82B6-DE1D12DDDE04} = {3783935D-7C0A-4166-A376-C3D8E64F3A9C}
+ {2390F054-A7F1-4CB9-ACB0-F46EC6E77B5B} = {3783935D-7C0A-4166-A376-C3D8E64F3A9C}
+ {E5A9BCDA-B82D-4B08-B23E-9A782E367888} = {3783935D-7C0A-4166-A376-C3D8E64F3A9C}
+ {510BDAA8-C04D-47DB-8482-E6AF380D3E07} = {3783935D-7C0A-4166-A376-C3D8E64F3A9C}
+ {3CF7C0E0-07C2-473A-A1E4-2274AEEC1268} = {3783935D-7C0A-4166-A376-C3D8E64F3A9C}
+ EndGlobalSection
+EndGlobal
diff --git a/Freeswitch.2010.express.sln b/Freeswitch.2010.express.sln
index 79f8d2ed56..1c5b97257c 100644
--- a/Freeswitch.2010.express.sln
+++ b/Freeswitch.2010.express.sln
@@ -168,7 +168,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "8khz", "libs\win32\Sound_Fi
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "16khz", "libs\win32\Sound_Files\16khz.2010.vcxproj", "{7EB71250-F002-4ED8-92CA-CA218114537A}"
EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download 32khzsound", "libs\win32\Dowload 32khz Sounds.2010.vcxproj", "{6E49F6C2-ADDA-4BFB-81FE-AB9AF51B455F}"
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download 32khzsound", "libs\win32\Download 32khz Sounds.2010.vcxproj", "{6E49F6C2-ADDA-4BFB-81FE-AB9AF51B455F}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "32khz", "libs\win32\Sound_Files\32khz.2010.vcxproj", "{464AAB78-5489-4916-BE51-BF8D61822311}"
EndProject
@@ -245,7 +245,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_spy", "src\mod\applicat
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_skypopen", "src\mod\endpoints\mod_skypopen\mod_skypopen.2010.vcxproj", "{C6E78A4C-DB1E-47F4-9B63-4DC27D86343F}"
EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download 32khz music", "libs\win32\Dowload 32khz music.2010.vcxproj", "{1F0A8A77-E661-418F-BB92-82172AE43803}"
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download 32khz music", "libs\win32\Download 32khz music.2010.vcxproj", "{1F0A8A77-E661-418F-BB92-82172AE43803}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download 8khz music", "libs\win32\Download 8khz music.2010.vcxproj", "{4F5C9D55-98EF-4256-8311-32D7BD360406}"
EndProject
diff --git a/Freeswitch.2010.sln b/Freeswitch.2010.sln
index 440e4e841c..f18b43b352 100644
--- a/Freeswitch.2010.sln
+++ b/Freeswitch.2010.sln
@@ -338,7 +338,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "8khz", "libs\win32\Sound_Fi
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "16khz", "libs\win32\Sound_Files\16khz.2010.vcxproj", "{7EB71250-F002-4ED8-92CA-CA218114537A}"
EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download 32khzsound", "libs\win32\Dowload 32khz Sounds.2010.vcxproj", "{6E49F6C2-ADDA-4BFB-81FE-AB9AF51B455F}"
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download 32khzsound", "libs\win32\Download 32khz Sounds.2010.vcxproj", "{6E49F6C2-ADDA-4BFB-81FE-AB9AF51B455F}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "32khz", "libs\win32\Sound_Files\32khz.2010.vcxproj", "{464AAB78-5489-4916-BE51-BF8D61822311}"
EndProject
@@ -416,7 +416,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_skel", "src\mod\applica
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_skypopen", "src\mod\endpoints\mod_skypopen\mod_skypopen.2010.vcxproj", "{C6E78A4C-DB1E-47F4-9B63-4DC27D86343F}"
EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download 32khz music", "libs\win32\Dowload 32khz music.2010.vcxproj", "{1F0A8A77-E661-418F-BB92-82172AE43803}"
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download 32khz music", "libs\win32\Download 32khz music.2010.vcxproj", "{1F0A8A77-E661-418F-BB92-82172AE43803}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download 8khz music", "libs\win32\Download 8khz music.2010.vcxproj", "{4F5C9D55-98EF-4256-8311-32D7BD360406}"
EndProject
@@ -1058,22 +1058,22 @@ Global
{8D04B550-D240-4A44-8A18-35DA3F7038D9}.Release|x64.Build.0 = Release|x64
{8D04B550-D240-4A44-8A18-35DA3F7038D9}.Release|x64 Setup.ActiveCfg = Release|x64
{8D04B550-D240-4A44-8A18-35DA3F7038D9}.Release|x86 Setup.ActiveCfg = Release|Win32
- {1CED5987-A529-46DC-B30F-870D85FF9C94}.All|Win32.ActiveCfg = Release|x64
- {1CED5987-A529-46DC-B30F-870D85FF9C94}.All|x64.ActiveCfg = Release|x64
- {1CED5987-A529-46DC-B30F-870D85FF9C94}.All|x64.Build.0 = Release|x64
+ {1CED5987-A529-46DC-B30F-870D85FF9C94}.All|Win32.ActiveCfg = Release|Win32
+ {1CED5987-A529-46DC-B30F-870D85FF9C94}.All|x64.ActiveCfg = Release|Win32
+ {1CED5987-A529-46DC-B30F-870D85FF9C94}.All|x64.Build.0 = Release|Win32
{1CED5987-A529-46DC-B30F-870D85FF9C94}.All|x64 Setup.ActiveCfg = Release|x64
{1CED5987-A529-46DC-B30F-870D85FF9C94}.All|x64 Setup.Build.0 = Release|x64
{1CED5987-A529-46DC-B30F-870D85FF9C94}.All|x86 Setup.ActiveCfg = Release|x64
{1CED5987-A529-46DC-B30F-870D85FF9C94}.Debug|Win32.ActiveCfg = Debug|Win32
{1CED5987-A529-46DC-B30F-870D85FF9C94}.Debug|Win32.Build.0 = Debug|Win32
- {1CED5987-A529-46DC-B30F-870D85FF9C94}.Debug|x64.ActiveCfg = Debug|x64
- {1CED5987-A529-46DC-B30F-870D85FF9C94}.Debug|x64.Build.0 = Debug|x64
+ {1CED5987-A529-46DC-B30F-870D85FF9C94}.Debug|x64.ActiveCfg = Debug|Win32
+ {1CED5987-A529-46DC-B30F-870D85FF9C94}.Debug|x64.Build.0 = Debug|Win32
{1CED5987-A529-46DC-B30F-870D85FF9C94}.Debug|x64 Setup.ActiveCfg = Debug|x64
{1CED5987-A529-46DC-B30F-870D85FF9C94}.Debug|x86 Setup.ActiveCfg = Debug|Win32
{1CED5987-A529-46DC-B30F-870D85FF9C94}.Release|Win32.ActiveCfg = Release|Win32
{1CED5987-A529-46DC-B30F-870D85FF9C94}.Release|Win32.Build.0 = Release|Win32
- {1CED5987-A529-46DC-B30F-870D85FF9C94}.Release|x64.ActiveCfg = Release|x64
- {1CED5987-A529-46DC-B30F-870D85FF9C94}.Release|x64.Build.0 = Release|x64
+ {1CED5987-A529-46DC-B30F-870D85FF9C94}.Release|x64.ActiveCfg = Release|Win32
+ {1CED5987-A529-46DC-B30F-870D85FF9C94}.Release|x64.Build.0 = Release|Win32
{1CED5987-A529-46DC-B30F-870D85FF9C94}.Release|x64 Setup.ActiveCfg = Release|x64
{1CED5987-A529-46DC-B30F-870D85FF9C94}.Release|x86 Setup.ActiveCfg = Release|Win32
{F6C55D93-B927-4483-BB69-15AEF3DD2DFF}.All|Win32.ActiveCfg = Release|x64
diff --git a/Freeswitch.2012.sln b/Freeswitch.2012.sln
new file mode 100644
index 0000000000..f621731b85
--- /dev/null
+++ b/Freeswitch.2012.sln
@@ -0,0 +1,3958 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2012
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Codecs", "Codecs", "{F881ADA2-2F1A-4046-9FEB-191D9422D781}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Endpoints", "Endpoints", "{9460B5F1-0A95-41C4-BEB7-9C2C96459A7C}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Applications", "Applications", "{E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Dialplans", "Dialplans", "{C5F182F9-754A-4EC5-B50F-76ED02BE13F4}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Event Handlers", "Event Handlers", "{9ADF1E48-2F5C-4ED7-A893-596259FABFE0}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Formats", "Formats", "{A5A27244-AD24-46E5-B01B-840CD296C91D}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docs", "Docs", "{CBD81696-EFB4-4D2F-8451-1B8DAA86155A}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Directories", "Directories", "{B8F5B47B-8568-46EB-B320-64C17D2A98BC}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Languages", "Languages", "{0C808854-54D1-4230-BFF5-77B5FD905000}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ASR-TTS", "ASR-TTS", "{4CF6A6AC-07DE-4B9E-ABE1-7F98B64E0BB0}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Loggers", "Loggers", "{A7AB4405-FDB7-4853-9FBB-1516B1C3D80A}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "XML Interfaces", "XML Interfaces", "{F69A4A6B-9360-4EBB-A280-22AA3C455AC5}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_Libraries", "_Libraries", "{EB910B0D-F27D-4B62-B67B-DE834C99AC5B}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_Downloads", "_Downloads", "{C120A020-773F-4EA3-923F-B67AF28B750D}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "say", "say", "{6CD61A1D-797C-470A-BE08-8C31B68BB336}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_Config", "_Config", "{57D119DC-484F-420F-B9E9-8589FD9A8DF8}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Default", "Default", "{3B08FEFD-4D3D-4C16-BA94-EE83509E32A0}"
+ ProjectSection(SolutionItems) = preProject
+ conf\vanilla\freeswitch.xml = conf\vanilla\freeswitch.xml
+ conf\vanilla\vars.xml = conf\vanilla\vars.xml
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_Build System", "_Build System", "{DB1024A8-41BF-4AD7-9AE6-13202230D1F3}"
+ ProjectSection(SolutionItems) = preProject
+ acsite.m4 = acsite.m4
+ bootstrap.sh = bootstrap.sh
+ build\buildlib.sh = build\buildlib.sh
+ configure.in = configure.in
+ Makefile.am = Makefile.am
+ build\modmake.rules.in = build\modmake.rules.in
+ build\modules.conf.in = build\modules.conf.in
+ libs\win32\util.vbs = libs\win32\util.vbs
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "m4", "m4", "{CDE9B06A-3C27-4987-8FAE-DF1006BC705D}"
+ ProjectSection(SolutionItems) = preProject
+ build\config\ac_cflags_gcc_option.m4 = build\config\ac_cflags_gcc_option.m4
+ build\config\ac_cflags_sun_option.m4 = build\config\ac_cflags_sun_option.m4
+ build\config\ac_gcc_archflag.m4 = build\config\ac_gcc_archflag.m4
+ build\config\ac_gcc_x86_cpuid.m4 = build\config\ac_gcc_x86_cpuid.m4
+ build\config\ac_prog_gzip.m4 = build\config\ac_prog_gzip.m4
+ build\config\ac_prog_wget.m4 = build\config\ac_prog_wget.m4
+ build\config\ax_cc_maxopt.m4 = build\config\ax_cc_maxopt.m4
+ build\config\ax_cflags_warn_all_ansi.m4 = build\config\ax_cflags_warn_all_ansi.m4
+ build\config\ax_check_compiler_flags.m4 = build\config\ax_check_compiler_flags.m4
+ build\config\ax_compiler_vendor.m4 = build\config\ax_compiler_vendor.m4
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "autoload_configs", "autoload_configs", "{3C90CCF0-2CDD-4A7A-ACFF-208C1E271692}"
+ ProjectSection(SolutionItems) = preProject
+ conf\vanilla\autoload_configs\alsa.conf.xml = conf\vanilla\autoload_configs\alsa.conf.xml
+ conf\vanilla\autoload_configs\conference.conf.xml = conf\vanilla\autoload_configs\conference.conf.xml
+ conf\vanilla\autoload_configs\console.conf.xml = conf\vanilla\autoload_configs\console.conf.xml
+ conf\vanilla\autoload_configs\dialplan_directory.conf.xml = conf\vanilla\autoload_configs\dialplan_directory.conf.xml
+ conf\vanilla\autoload_configs\dingaling.conf.xml = conf\vanilla\autoload_configs\dingaling.conf.xml
+ conf\vanilla\autoload_configs\enum.conf.xml = conf\vanilla\autoload_configs\enum.conf.xml
+ conf\vanilla\autoload_configs\event_multicast.conf.xml = conf\vanilla\autoload_configs\event_multicast.conf.xml
+ conf\vanilla\autoload_configs\event_socket.conf.xml = conf\vanilla\autoload_configs\event_socket.conf.xml
+ conf\vanilla\autoload_configs\ivr.conf.xml = conf\vanilla\autoload_configs\ivr.conf.xml
+ conf\vanilla\autoload_configs\java.conf.xml = conf\vanilla\autoload_configs\java.conf.xml
+ conf\vanilla\autoload_configs\limit.conf.xml = conf\vanilla\autoload_configs\limit.conf.xml
+ conf\vanilla\autoload_configs\local_stream.conf.xml = conf\vanilla\autoload_configs\local_stream.conf.xml
+ conf\vanilla\autoload_configs\logfile.conf.xml = conf\vanilla\autoload_configs\logfile.conf.xml
+ conf\vanilla\autoload_configs\modules.conf.xml = conf\vanilla\autoload_configs\modules.conf.xml
+ conf\vanilla\autoload_configs\openmrcp.conf.xml = conf\vanilla\autoload_configs\openmrcp.conf.xml
+ conf\vanilla\autoload_configs\portaudio.conf.xml = conf\vanilla\autoload_configs\portaudio.conf.xml
+ conf\vanilla\autoload_configs\rss.conf.xml = conf\vanilla\autoload_configs\rss.conf.xml
+ conf\vanilla\autoload_configs\sofia.conf.xml = conf\vanilla\autoload_configs\sofia.conf.xml
+ conf\vanilla\autoload_configs\spidermonkey.conf.xml = conf\vanilla\autoload_configs\spidermonkey.conf.xml
+ conf\vanilla\autoload_configs\switch.conf.xml = conf\vanilla\autoload_configs\switch.conf.xml
+ conf\vanilla\autoload_configs\syslog.conf.xml = conf\vanilla\autoload_configs\syslog.conf.xml
+ conf\vanilla\autoload_configs\voicemail.conf.xml = conf\vanilla\autoload_configs\voicemail.conf.xml
+ conf\vanilla\autoload_configs\wanpipe.conf.xml = conf\vanilla\autoload_configs\wanpipe.conf.xml
+ conf\vanilla\autoload_configs\woomera.conf.xml = conf\vanilla\autoload_configs\woomera.conf.xml
+ conf\vanilla\autoload_configs\xml_cdr.conf.xml = conf\vanilla\autoload_configs\xml_cdr.conf.xml
+ conf\vanilla\autoload_configs\xml_curl.conf.xml = conf\vanilla\autoload_configs\xml_curl.conf.xml
+ conf\vanilla\autoload_configs\xml_rpc.conf.xml = conf\vanilla\autoload_configs\xml_rpc.conf.xml
+ conf\vanilla\autoload_configs\zeroconf.conf.xml = conf\vanilla\autoload_configs\zeroconf.conf.xml
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dialplan", "dialplan", "{C7E2382E-2C22-4D18-BF93-80C6A1FFA7AC}"
+ ProjectSection(SolutionItems) = preProject
+ conf\vanilla\dialplan\default.xml = conf\vanilla\dialplan\default.xml
+ conf\vanilla\dialplan\public.xml = conf\vanilla\dialplan\public.xml
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "directory", "directory", "{FC71C66E-E268-4EAD-B1F5-F008DC382E83}"
+ ProjectSection(SolutionItems) = preProject
+ conf\vanilla\directory\default.xml = conf\vanilla\directory\default.xml
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "sip_profiles", "sip_profiles", "{8E2E8798-8B6F-4A55-8E4F-4E6FDE40ED26}"
+ ProjectSection(SolutionItems) = preProject
+ conf\vanilla\sip_profiles\external.xml = conf\vanilla\sip_profiles\external.xml
+ conf\vanilla\sip_profiles\internal.xml = conf\vanilla\sip_profiles\internal.xml
+ conf\vanilla\sip_profiles\nat.xml = conf\vanilla\sip_profiles\nat.xml
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "lang", "lang", "{09455AA9-C243-4F16-A1A1-A016881A2765}"
+ ProjectSection(SolutionItems) = preProject
+ conf\vanilla\directory\default.xml = conf\vanilla\directory\default.xml
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "en", "en", "{57199684-EC63-4A60-9DC6-11815AF6B413}"
+ ProjectSection(SolutionItems) = preProject
+ conf\vanilla\lang\en\en.xml = conf\vanilla\lang\en\en.xml
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "de", "de", "{2DED4BA2-D6B0-4064-BB2A-76DE3AA49E7C}"
+ ProjectSection(SolutionItems) = preProject
+ conf\vanilla\lang\de\de.xml = conf\vanilla\lang\de\de.xml
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "fr", "fr", "{D4A12E4C-DBDA-4614-BA26-3425AE9F60F5}"
+ ProjectSection(SolutionItems) = preProject
+ conf\vanilla\lang\fr\fr.xml = conf\vanilla\lang\fr\fr.xml
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "demo", "demo", "{D3E5C8ED-3A6A-4FEA-92A2-48A0BA865358}"
+ ProjectSection(SolutionItems) = preProject
+ conf\vanilla\lang\de\demo\demo.xml = conf\vanilla\lang\de\demo\demo.xml
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "vm", "vm", "{CC3E7F48-2590-49CB-AD8B-BE3650F55462}"
+ ProjectSection(SolutionItems) = preProject
+ conf\vanilla\lang\de\vm\tts.xml = conf\vanilla\lang\de\vm\tts.xml
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "demo", "demo", "{765EF1B9-5027-4820-BC37-A44466A51631}"
+ ProjectSection(SolutionItems) = preProject
+ conf\vanilla\lang\en\demo\demo.xml = conf\vanilla\lang\en\demo\demo.xml
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "vm", "vm", "{713E4747-1126-40B1-BD84-58F9A7745423}"
+ ProjectSection(SolutionItems) = preProject
+ conf\vanilla\lang\en\vm\sounds.xml = conf\vanilla\lang\en\vm\sounds.xml
+ conf\vanilla\lang\en\vm\tts.xml = conf\vanilla\lang\en\vm\tts.xml
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "demo", "demo", "{F1B71990-EB04-4EB5-B28A-BC3EB6F7E843}"
+ ProjectSection(SolutionItems) = preProject
+ conf\vanilla\lang\fr\demo\demo.xml = conf\vanilla\lang\fr\demo\demo.xml
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "vm", "vm", "{3DAF028C-AB5B-4183-A01B-DCC43F5A87F0}"
+ ProjectSection(SolutionItems) = preProject
+ conf\vanilla\lang\fr\vm\sounds.xml = conf\vanilla\lang\fr\vm\sounds.xml
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sound Files", "Sound Files", "{4F227C26-768F-46A3-8684-1D08A46FB374}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "unimrcp", "unimrcp", "{62F27B1A-C919-4A70-8478-51F178F3B18F}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FreeSwitchConsole", "w32\Console\FreeSwitchConsole.2012.vcxproj", "{1AF3A893-F7BE-43DD-B697-8AB2397C0D67}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FreeSwitchCoreLib", "w32\Library\FreeSwitchCore.2012.vcxproj", "{202D7A4E-760D-4D0E-AFA1-D7459CED30FF}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_g729", "src\mod\codecs\mod_g729\mod_g729.2012.vcxproj", "{1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_sndfile", "src\mod\formats\mod_sndfile\mod_sndfile.2012.vcxproj", "{AFAC0568-7548-42D5-9F6A-8D3400A1E4F6}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_PortAudio", "src\mod\endpoints\mod_portaudio\mod_PortAudio.2012.vcxproj", "{5FD31A25-5D83-4794-8BEE-904DAD84CE71}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_speex", "src\mod\codecs\mod_speex\mod_speex.2012.vcxproj", "{5580D60E-0F77-4716-9CD4-B8E5986FA375}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "docs", "docs\docs.2012.vcxproj", "{1A1FF289-4FD6-4285-A422-D31DD67A4723}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_dialplan_xml", "src\mod\dialplans\mod_dialplan_xml\mod_dialplan_xml.2012.vcxproj", "{07113B25-D3AF-4E04-BA77-4CD1171F022C}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_ldap", "src\mod\directories\mod_ldap\mod_ldap.2012.vcxproj", "{EC3E5C7F-EE09-47E2-80FE-546363D14A98}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_dialplan_directory", "src\mod\dialplans\mod_dialplan_directory\mod_dialplan_directory.2012.vcxproj", "{A27CCA23-1541-4337-81A4-F0A6413078A0}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_event_multicast", "src\mod\event_handlers\mod_event_multicast\mod_event_multicast.2012.vcxproj", "{784113EF-44D9-4949-835D-7065D3C7AD08}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libteletone", "libs\libteletone\libteletone.2012.vcxproj", "{89385C74-5860-4174-9CAF-A39E7C48909C}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_spidermonkey", "src\mod\languages\mod_spidermonkey\mod_spidermonkey.2012.vcxproj", "{1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_cepstral", "src\mod\asr_tts\mod_cepstral\mod_cepstral.2012.vcxproj", "{692F6330-4D87-4C82-81DF-40DB5892636E}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_ilbc", "src\mod\codecs\mod_ilbc\mod_ilbc.2012.vcxproj", "{D3EC0AFF-76FC-4210-A825-9A17410660A3}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_dingaling", "src\mod\endpoints\mod_dingaling\mod_dingaling.2012.vcxproj", "{FFAA4C52-3A53-4F99-90C1-D59D1F0427F3}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_commands", "src\mod\applications\mod_commands\mod_commands.2012.vcxproj", "{30A5B29C-983E-4580-9FD0-D647CCDCC7EB}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_console", "src\mod\loggers\mod_console\mod_console.2012.vcxproj", "{1C453396-D912-4213-89FD-9B489162B7B5}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_xml_rpc", "src\mod\xml_int\mod_xml_rpc\mod_xml_rpc.2012.vcxproj", "{CBEC7225-0C21-4DA8-978E-1F158F8AD950}"
+ ProjectSection(ProjectDependencies) = postProject
+ {BED7539C-0099-4A14-AD5D-30828F15A171} = {BED7539C-0099-4A14-AD5D-30828F15A171}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_rss", "src\mod\applications\mod_rss\mod_rss.2012.vcxproj", "{B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_conference", "src\mod\applications\mod_conference\mod_conference.2012.vcxproj", "{C24FB505-05D7-4319-8485-7540B44C8603}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_dptools", "src\mod\applications\mod_dptools\mod_dptools.2012.vcxproj", "{B5881A85-FE70-4F64-8607-2CAAE52669C6}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_event_socket", "src\mod\event_handlers\mod_event_socket\mod_event_socket.2012.vcxproj", "{05515420-16DE-4E63-BE73-85BE85BA5142}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libdingaling", "libs\libdingaling\libdingaling.2012.vcxproj", "{1906D736-08BD-4EE1-924F-B536249B9A54}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libsrtp", "libs\srtp\libsrtp.2012.vcxproj", "{EEF031CB-FED8-451E-A471-91EC8D4F6750}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libsqlite", "libs\win32\sqlite\sqlite.2012.vcxproj", "{6EDFEFD5-3596-4FA9-8EBA-B331547B35A3}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpcre", "libs\win32\pcre\libpcre.2012.vcxproj", "{8D04B550-D240-4A44-8A18-35DA3F7038D9}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpcre Generate pcre_chartables.c", "libs\win32\pcre\pcre_chartables.c.2012.vcxproj", "{1CED5987-A529-46DC-B30F-870D85FF9C94}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libapr", "libs\win32\apr\libapr.2012.vcxproj", "{F6C55D93-B927-4483-BB69-15AEF3DD2DFF}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libaprutil", "libs\win32\apr-util\libaprutil.2012.vcxproj", "{F057DA7F-79E5-4B00-845C-EF446EF055E3}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "iksemel", "libs\win32\iksemel\iksemel.2012.vcxproj", "{E727E8F6-935D-46FE-8B0E-37834748A0E3}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libsndfile", "libs\win32\libsndfile\libsndfile.2012.vcxproj", "{3D0370CA-BED2-4657-A475-32375CBCB6E4}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "curllib", "libs\win32\curl\curllib.2012.vcxproj", "{87EE9DA4-DE1E-4448-8324-183C98DCA588}"
+ ProjectSection(ProjectDependencies) = postProject
+ {25BD39B1-C8BF-4676-A738-9CABD9C6BC79} = {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xml", "libs\win32\apr-util\xml.2012.vcxproj", "{155844C3-EC5F-407F-97A4-A2DDADED9B2F}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "js", "libs\win32\js\js.2012.vcxproj", "{204FA0DE-305D-4414-AE2E-F195A23F390D}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_sofia", "src\mod\endpoints\mod_sofia\mod_sofia.2012.vcxproj", "{0DF3ABD0-DDC0-4265-B778-07C66780979B}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download PTHREAD", "libs\win32\Download PTHREAD.2012.vcxproj", "{8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pthread", "libs\win32\pthread\pthread.2012.vcxproj", "{DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_g723_1", "src\mod\codecs\mod_g723_1\mod_g723_1.2012.vcxproj", "{FEA1EEF7-876F-48DE-88BF-C0E3E606D758}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_iSAC", "src\mod\codecs\mod_isac\mod_iSAC.2012.vcxproj", "{7F1610F1-DD5A-4CF7-8610-30AB12C60ADD}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_native_file", "src\mod\formats\mod_native_file\mod_native_file.2012.vcxproj", "{9254C4B0-6F60-42B6-BB3A-36D63FC001C7}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_spidermonkey_core_db", "src\mod\languages\mod_spidermonkey\mod_spidermonkey_core_db.2012.vcxproj", "{ACFFF684-4D19-4D48-AF12-88EA1D778BDF}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_spidermonkey_teletone", "src\mod\languages\mod_spidermonkey\mod_spidermonkey_teletone.2012.vcxproj", "{8F992C49-6C51-412F-B2A3-34EAB708EB65}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libudns", "libs\win32\udns\libudns.2012.vcxproj", "{4043FC6A-9A30-4577-8AD5-9B233C9575D8}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_enum", "src\mod\applications\mod_enum\mod_enum.2012.vcxproj", "{71A967D5-0E99-4CEF-A587-98836EE6F2EF}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_spidermonkey_odbc", "src\mod\languages\mod_spidermonkey\mod_spidermonkey_odbc.2012.vcxproj", "{0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_xml_curl", "src\mod\xml_int\mod_xml_curl\mod_xml_curl.2012.vcxproj", "{AB91A099-7690-4ECF-8994-E458F4EA1ED4}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_say_en", "src\mod\say\mod_say_en\mod_say_en.2012.vcxproj", "{988CACF7-3FCB-4992-BE69-77872AE67DC8}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "portaudio", "libs\portaudio\build\msvc\portaudio.2012.vcxproj", "{0A18A071-125E-442F-AFF7-A3F68ABECF99}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_xml_cdr", "src\mod\xml_int\mod_xml_cdr\mod_xml_cdr.2012.vcxproj", "{08DAD348-9E0A-4A2E-97F1-F1E7E24A7836}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_amr", "src\mod\codecs\mod_amr\mod_amr.2012.vcxproj", "{8DEB383C-4091-4F42-A56F-C9E46D552D79}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_h26x", "src\mod\codecs\mod_h26x\mod_h26x.2012.vcxproj", "{2C3C2423-234B-4772-8899-D3B137E5CA35}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_esf", "src\mod\applications\mod_esf\mod_esf.2012.vcxproj", "{3850D93A-5F24-4922-BC1C-74D08C37C256}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_local_stream", "src\mod\formats\mod_local_stream\mod_local_stream.2012.vcxproj", "{2CA40887-1622-46A1-A7F9-17FD7E7E545B}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_spidermonkey_socket", "src\mod\languages\mod_spidermonkey\mod_spidermonkey_socket.2012.vcxproj", "{028C7278-05D7-4E18-82FE-BE231B844F41}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_voicemail", "src\mod\applications\mod_voicemail\mod_voicemail.2012.vcxproj", "{D7F1E3F2-A3F4-474C-8555-15122571AF52}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_say_de", "src\mod\say\mod_say_de\mod_say_de.2012.vcxproj", "{5BC072DB-3826-48EA-AF34-FE32AA01E83B}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_say_es", "src\mod\say\mod_say_es\mod_say_es.2012.vcxproj", "{FA429E98-8B03-45E6-A096-A4BC5E821DE4}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_say_fr", "src\mod\say\mod_say_fr\mod_say_fr.2012.vcxproj", "{06E3A538-AB32-44F2-B477-755FF9CB5D37}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_say_it", "src\mod\say\mod_say_it\mod_say_it.2012.vcxproj", "{6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_say_nl", "src\mod\say\mod_say_nl\mod_say_nl.2012.vcxproj", "{A4B122CF-5196-476B-8C0E-D8BD59AC3C14}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_fifo", "src\mod\applications\mod_fifo\mod_fifo.2012.vcxproj", "{75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_db", "src\mod\applications\mod_db\mod_db.2012.vcxproj", "{F6A33240-8F29-48BD-98F0-826995911799}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_expr", "src\mod\applications\mod_expr\mod_expr.2012.vcxproj", "{65A6273D-FCAB-4C55-B09E-65100141A5D4}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_dialplan_asterisk", "src\mod\dialplans\mod_dialplan_asterisk\mod_dialplan_asterisk.2012.vcxproj", "{E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_logfile", "src\mod\loggers\mod_logfile\mod_logfile.2012.vcxproj", "{D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_cdr_csv", "src\mod\event_handlers\mod_cdr_csv\mod_cdr_csv.2012.vcxproj", "{44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_tone_stream", "src\mod\formats\mod_tone_stream\mod_tone_stream.2012.vcxproj", "{6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_fsv", "src\mod\applications\mod_fsv\mod_fsv.2012.vcxproj", "{E3246D17-E29B-4AB5-962A-C69B0C5837BB}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_spidermonkey_curl", "src\mod\languages\mod_spidermonkey\mod_spidermonkey_curl.2012.vcxproj", "{36E854E3-CE12-4348-A125-CCF3F9D74813}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_lua", "src\mod\languages\mod_lua\mod_lua.2012.vcxproj", "{7B077E7F-1BE7-4291-AB86-55E527B25CAC}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download sphinxbase", "libs\win32\Download sphinxbase.2012.vcxproj", "{4F92B672-DADB-4047-8D6A-4BB3796733FD}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download sphinxmodel", "libs\win32\Download sphinxmodel.2012.vcxproj", "{2DEE4895-1134-439C-B688-52203E57D878}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download pocketsphinx", "libs\win32\Download pocketsphinx.2012.vcxproj", "{AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sphinxbase", "libs\win32\sphinxbase\sphinxbase.2012.vcxproj", "{2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pocketsphinx", "libs\win32\pocketsphinx\pocketsphinx.2012.vcxproj", "{94001A0E-A837-445C-8004-F918F10D0226}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_pocketsphinx", "src\mod\asr_tts\mod_pocketsphinx\mod_pocketsphinx.2012.vcxproj", "{2286DA73-9FC5-45BC-A508-85994C3317AB}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download 8khzsound", "libs\win32\Download 8khz Sounds.2012.vcxproj", "{3CE1DC99-8246-4DB1-A709-74F19F08EC67}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download 16khzsound", "libs\win32\Download 16khz Sounds.2012.vcxproj", "{87A1FE3D-F410-4C8E-9591-8C625985BC70}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "8khz", "libs\win32\Sound_Files\8khz.2012.vcxproj", "{7A8D8174-B355-4114-AFC1-04777CB9DE0A}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "16khz", "libs\win32\Sound_Files\16khz.2012.vcxproj", "{7EB71250-F002-4ED8-92CA-CA218114537A}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download 32khzsound", "libs\win32\Download 32khz Sounds.2012.vcxproj", "{6E49F6C2-ADDA-4BFB-81FE-AB9AF51B455F}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "32khz", "libs\win32\Sound_Files\32khz.2012.vcxproj", "{464AAB78-5489-4916-BE51-BF8D61822311}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "flite", "libs\win32\flite\flite.2012.vcxproj", "{0AD1177E-1FD8-4643-9391-431467A11084}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_flite", "src\mod\asr_tts\mod_flite\mod_flite.2012.vcxproj", "{66444AEE-554C-11DD-A9F0-8C5D56D89593}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download FLITE", "libs\win32\Download FLITE.2012.vcxproj", "{D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download LAME", "libs\win32\Download LAME.2012.vcxproj", "{D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download LIBSHOUT", "libs\win32\Download LIBSHOUT.2012.vcxproj", "{D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download OGG", "libs\win32\Download OGG.2012.vcxproj", "{D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmp3lame", "libs\win32\libmp3lame\libmp3lame.2012.vcxproj", "{E316772F-5D8F-4F2A-8F71-094C3E859D34}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libshout", "libs\win32\libshout\libshout.2012.vcxproj", "{D3D8B329-20BE-475E-9E83-653CEA0E0EF5}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_shout", "src\mod\formats\mod_shout\mod_shout.2012.vcxproj", "{38FE0559-9910-43A8-9E45-3E5004C27692}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libogg", "libs\win32\libogg\libogg.2012.vcxproj", "{0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_snom", "src\mod\applications\mod_snom\mod_snom.2012.vcxproj", "{2A3D00C6-588D-4E86-81AC-9EF5EDE86E03}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_say_zh", "src\mod\say\mod_say_zh\mod_say_zh.2012.vcxproj", "{B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_managed", "src\mod\languages\mod_managed\mod_managed.2012.vcxproj", "{7B42BDA1-72C0-4378-A9B6-5C530F8CD61E}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FreeSWITCH.Managed.2012", "src\mod\languages\mod_managed\managed\FreeSWITCH.Managed.2012.csproj", "{834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download mpg123", "libs\win32\Download mpg123.2012.vcxproj", "{E796E337-DE78-4303-8614-9A590862EE95}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmpg123", "libs\win32\mpg123\libmpg123.2012.vcxproj", "{419C8F80-D858-4B48-A25C-AF4007608137}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_loopback", "src\mod\endpoints\mod_loopback\mod_loopback.2012.vcxproj", "{B3F424EC-3D8F-417C-B244-3919D5E1A577}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_vmd", "src\mod\applications\mod_vmd\mod_vmd.2012.vcxproj", "{14E4A972-9CFB-436D-B0A5-4943F3F80D47}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libg722_1", "libs\win32\libg722_1\libg722_1.2012.vcxproj", "{1BC8A8EC-E03B-44DF-BCD9-088650F4D29C}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_siren", "src\mod\codecs\mod_siren\mod_siren.2012.vcxproj", "{0B6C905B-142E-4999-B39D-92FF7951E921}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "esl", "libs\esl\src\esl.2012.vcxproj", "{CF405366-9558-4AE8-90EF-5E21B51CCB4E}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fs_cli", "libs\esl\fs_cli.2012.vcxproj", "{D2FB8043-D208-4AEE-8F18-3B5857C871B9}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_easyroute", "src\mod\applications\mod_easyroute\mod_easyroute.2012.vcxproj", "{329FD5B0-EF28-4606-86D0-F6EA21CF8E36}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_lcr", "src\mod\applications\mod_lcr\mod_lcr.2012.vcxproj", "{1A3793D1-05D1-4B57-9B0F-5AF3E79DC439}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libtiff", "libs\spandsp\src\libtiff.2012.vcxproj", "{401A40CD-5DB4-4E34-AC68-FA99E9FAC014}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libspandsp", "libs\spandsp\src\libspandsp.2012.vcxproj", "{1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libspeex", "libs\speex\win32\VS2012\libspeex\libspeex.vcxproj", "{E972C52F-9E85-4D65-B19C-031E511E9DB4}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libspeexdsp", "libs\speex\win32\VS2012\libspeexdsp\libspeexdsp.vcxproj", "{03207781-0D1C-4DB3-A71D-45C608F28DBD}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libilbc", "libs\ilbc\libilbc.2012.vcxproj", "{9A5DDF08-C88C-4A35-B7F6-D605228446BD}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lua51", "src\mod\languages\mod_lua\lua\lua.2012.vcxproj", "{D0B36172-CD76-454A-9B89-990025266C2A}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_opal", "src\mod\endpoints\mod_opal\mod_opal.2012.vcxproj", "{05C9FB27-480E-4D53-B3B7-6338E2526666}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_skinny", "src\mod\endpoints\mod_skinny\mod_skinny.2012.vcxproj", "{CC1DD008-9406-448D-A0AD-33C3186CFADB}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_rtmp", "src\mod\endpoints\mod_rtmp\mod_rtmp.2012.vcxproj", "{48414740-C693-4968-9846-EE058020C64F}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "make_at_dictionary", "libs\spandsp\src\msvc\make_at_dictionary.2012.vcxproj", "{DEE932AB-5911-4700-9EEB-8C7090A0A330}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "make_modem_filter", "libs\spandsp\src\msvc\make_modem_filter.2012.vcxproj", "{329A6FA0-0FCC-4435-A950-E670AEFA9838}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_skel", "src\mod\applications\mod_skel\mod_skel.2012.vcxproj", "{11C9BC3D-45E9-46E3-BE84-B8CEE4685E39}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_skypopen", "src\mod\endpoints\mod_skypopen\mod_skypopen.2012.vcxproj", "{C6E78A4C-DB1E-47F4-9B63-4DC27D86343F}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download 32khz music", "libs\win32\Download 32khz music.2012.vcxproj", "{1F0A8A77-E661-418F-BB92-82172AE43803}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download 8khz music", "libs\win32\Download 8khz music.2012.vcxproj", "{4F5C9D55-98EF-4256-8311-32D7BD360406}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download 16khz music", "libs\win32\Download 16khz music.2012.vcxproj", "{E10571C4-E7F4-4608-B5F2-B22E7EB95400}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "8khz music", "libs\win32\Sound_Files\8khzmusic.2012.vcxproj", "{D1ABE208-6442-4FB4-9AAD-1677E41BC870}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "16khz music", "libs\win32\Sound_Files\16khzmusic.2012.vcxproj", "{BA599D0A-4310-4505-91DA-6A6447B3E289}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "32khz music", "libs\win32\Sound_Files\32khzmusic.2012.vcxproj", "{EED13FC7-4F81-4E6F-93DB-CDB7DF5CF959}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_nibblebill", "src\mod\applications\mod_nibblebill\mod_nibblebill.2012.vcxproj", "{3C977801-FE88-48F2-83D3-FA2EBFF6688E}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_say_ru", "src\mod\say\mod_say_ru\mod_say_ru.2012.vcxproj", "{0382E8FD-CFDC-41C0-8B03-792C7C84FC31}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_valet_parking", "src\mod\applications\mod_valet_parking\mod_valet_parking.2012.vcxproj", "{432DB165-1EB2-4781-A9C0-71E62610B20A}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libbroadvoice", "libs\broadvoice\src\libbroadvoice.2012.vcxproj", "{CF70F278-3364-4395-A2E1-23501C9B8AD2}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_bv", "src\mod\codecs\mod_bv\mod_bv.2012.vcxproj", "{D5C87B19-150D-4EF3-A671-96589BD2D14A}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "aprtoolkit", "libs\unimrcp\libs\apr-toolkit\aprtoolkit.2012.vcxproj", "{13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}"
+ ProjectSection(ProjectDependencies) = postProject
+ {155844C3-EC5F-407F-97A4-A2DDADED9B2F} = {155844C3-EC5F-407F-97A4-A2DDADED9B2F}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mpf", "libs\unimrcp\libs\mpf\mpf.2012.vcxproj", "{B5A00BFA-6083-4FAE-A097-71642D6473B5}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mrcp", "libs\unimrcp\libs\mrcp\mrcp.2012.vcxproj", "{1C320193-46A6-4B34-9C56-8AB584FC1B56}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mrcpclient", "libs\unimrcp\libs\mrcp-client\mrcpclient.2012.vcxproj", "{72782932-37CC-46AE-8C7F-9A7B1A6EE108}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mrcpsignaling", "libs\unimrcp\libs\mrcp-signaling\mrcpsignaling.2012.vcxproj", "{12A49562-BAB9-43A3-A21D-15B60BBB4C31}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mrcpv2transport", "libs\unimrcp\libs\mrcpv2-transport\mrcpv2transport.2012.vcxproj", "{A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unirtsp", "libs\unimrcp\libs\uni-rtsp\unirtsp.2012.vcxproj", "{504B3154-7A4F-459D-9877-B951021C3F1F}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mrcpsofiasip", "libs\unimrcp\modules\mrcp-sofiasip\mrcpsofiasip.2012.vcxproj", "{746F3632-5BB2-4570-9453-31D6D58A7D8E}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mrcpunirtsp", "libs\unimrcp\modules\mrcp-unirtsp\mrcpunirtsp.2012.vcxproj", "{DEB01ACB-D65F-4A62-AED9-58C1054499E9}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_unimrcp", "src\mod\asr_tts\mod_unimrcp\mod_unimrcp.2012.vcxproj", "{D07C378A-F5F7-438F-ADF3-4AC4FB1883CD}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download CELT", "libs\win32\Download CELT.2012.vcxproj", "{FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcelt", "libs\win32\celt\libcelt.2012.vcxproj", "{ABB71A76-42B0-47A4-973A-42E3D920C6FD}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_celt", "src\mod\codecs\mod_celt\mod_celt.2012.vcxproj", "{4D418176-3B33-47E6-A63E-01BA34ADD21C}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FSComm", "fscomm\FSComm.2012.vcxproj", "{7D3122C7-C9D0-3748-81F8-F0DDCB40BF5E}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_curl", "src\mod\applications\mod_curl\mod_curl.2012.vcxproj", "{EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download JSON", "libs\win32\Download JSON.2012.vcxproj", "{B808178B-82F0-4CF4-A2B1-921939FA24D0}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libjson", "libs\win32\json\libjson.2012.vcxproj", "{9778F1C0-09BC-4698-8EBC-BD982247209A}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_silk", "src\mod\codecs\mod_silk\mod_silk.2012.vcxproj", "{AFA983D6-4569-4F88-BA94-555ED00FD9A8}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Silk_FIX", "libs\silk\src\Silk_FIX.2012.vcxproj", "{56B91D01-9150-4BBF-AFA1-5B68AB991B76}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_avmd", "src\mod\applications\mod_avmd\mod_avmd.2012.vcxproj", "{990BAA76-89D3-4E38-8479-C7B28784EFC8}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_spandsp", "src\mod\applications\mod_spandsp\mod_spandsp.2012.vcxproj", "{1E21AFE0-6FDB-41D2-942D-863607C24B91}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_hash", "src\mod\applications\mod_hash\mod_hash.2012.vcxproj", "{2E250296-0C08-4342-9C8A-BCBDD0E7DF65}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "openssl", "openssl", "{E4D29906-8B73-4F8A-B5F4-CA8BFA648F5A}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libeay32", "libs\win32\openssl\libeay32.2012.vcxproj", "{D331904D-A00A-4694-A5A3-FCFF64AB5DBE}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ssleay32", "libs\win32\openssl\ssleay32.2012.vcxproj", "{B4B62169-5AD4-4559-8707-3D933AC5DB39}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openssl", "libs\win32\openssl\openssl.2012.vcxproj", "{25BD39B1-C8BF-4676-A738-9CABD9C6BC79}"
+ ProjectSection(ProjectDependencies) = postProject
+ {D578E676-7EC8-4548-BD8B-845C635F14AD} = {D578E676-7EC8-4548-BD8B-845C635F14AD}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download OPENSSL", "libs\win32\Download OPENSSL.2012.vcxproj", "{D578E676-7EC8-4548-BD8B-845C635F14AD}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libsofia_sip_ua_static", "libs\win32\sofia\libsofia_sip_ua_static.2012.vcxproj", "{70A49BC2-7500-41D0-B75D-EDCC5BE987A0}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_directory", "src\mod\applications\mod_directory\mod_directory.2012.vcxproj", "{B889A18E-70A7-44B5-B2C9-47798D4F43B3}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_h323", "src\mod\endpoints\mod_h323\mod_h323.2012.vcxproj", "{05C9FB27-480E-4D53-B3B7-7338E2514666}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_distributor", "src\mod\applications\mod_distributor\mod_distributor.2012.vcxproj", "{5C2B4D88-3BEA-4FE0-90DF-FA9836099D5F}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_say_pt", "src\mod\say\mod_say_pt\mod_say_pt.2012.vcxproj", "{7C22BDFF-CC09-400C-8A09-660733980028}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ldns", "libs\win32\ldns\ldns-lib\ldns-lib.2012.vcxproj", "{23B4D303-79FC-49E0-89E2-2280E7E28940}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_callcenter", "src\mod\applications\mod_callcenter\mod_callcenter.2012.vcxproj", "{47886A6C-CCA6-4F9F-A7D4-F97D06FB2B1A}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_blacklist", "src\mod\applications\mod_blacklist\mod_blacklist.2012.vcxproj", "{50AAC2CE-BFC9-4912-87CC-C6381850D735}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_spy", "src\mod\applications\mod_spy\mod_spy.2012.vcxproj", "{A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_httapi", "src\mod\applications\mod_httapi\mod_httapi.2012.vcxproj", "{4748FF56-CA85-4809-97D6-A94C0FAC1D77}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_abstraction", "src\mod\applications\mod_abstraction\mod_abstraction.2012.vcxproj", "{60C542EE-6882-4EA2-8C21-5AB6DB1BA73F}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_sms", "src\mod\applications\mod_sms\mod_sms.2012.vcxproj", "{2469B306-B027-4FF2-8815-C9C1EA2CAE79}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "xmlrpc-c", "xmlrpc-c", "{9DE35039-A8F6-4FBF-B1B6-EB527F802411}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gsmlib", "src\mod\endpoints\mod_gsmopen\gsmlib\gsmlib-1.10-patched-13ubuntu\win32\gsmlib.2012.vcxproj", "{26C82FCE-E0CF-4D10-A00C-D8E582FFEB53}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_gsmopen", "src\mod\endpoints\mod_gsmopen\mod_gsmopen.2012.vcxproj", "{74B120FF-6935-4DFE-A142-CDB6BEA99C90}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libzrtp", "libs\libzrtp\projects\win\libzrtp.2012.vcxproj", "{C13CC324-0032-4492-9A30-310A6BD64FF5}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_redis", "src\mod\applications\mod_redis\mod_redis.2012.vcxproj", "{886B5E9D-F2C2-4AF2-98C8-EF98C4C770E6}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download libjpeg", "libs\win32\Download libjpeg.2012.vcxproj", "{652AD5F7-8488-489F-AAD0-7FBE064703B6}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libjpeg", "libs\win32\libjpeg\libjpeg.2012.vcxproj", "{019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}"
+ ProjectSection(ProjectDependencies) = postProject
+ {652AD5F7-8488-489F-AAD0-7FBE064703B6} = {652AD5F7-8488-489F-AAD0-7FBE064703B6}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "abyss", "libs\win32\xmlrpc-c\abyss.2012.vcxproj", "{D2396DD7-7D38-473A-ABB7-6F96D65AE1B9}"
+ ProjectSection(ProjectDependencies) = postProject
+ {0D108721-EAE8-4BAF-8102-D8960EC93647} = {0D108721-EAE8-4BAF-8102-D8960EC93647}
+ {B535402E-38D2-4D54-8360-423ACBD17192} = {B535402E-38D2-4D54-8360-423ACBD17192}
+ {CEE544A9-0303-44C2-8ECE-EFA7D7BCBBBA} = {CEE544A9-0303-44C2-8ECE-EFA7D7BCBBBA}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gennmtab", "libs\win32\xmlrpc-c\gennmtab.2012.vcxproj", "{BED7539C-0099-4A14-AD5D-30828F15A171}"
+ ProjectSection(ProjectDependencies) = postProject
+ {0D108721-EAE8-4BAF-8102-D8960EC93647} = {0D108721-EAE8-4BAF-8102-D8960EC93647}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xmlparse", "libs\win32\xmlrpc-c\xmlparse.2012.vcxproj", "{0D108721-EAE8-4BAF-8102-D8960EC93647}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xmlrpc", "libs\win32\xmlrpc-c\xmlrpc.2012.vcxproj", "{CEE544A9-0303-44C2-8ECE-EFA7D7BCBBBA}"
+ ProjectSection(ProjectDependencies) = postProject
+ {0D108721-EAE8-4BAF-8102-D8960EC93647} = {0D108721-EAE8-4BAF-8102-D8960EC93647}
+ {B535402E-38D2-4D54-8360-423ACBD17192} = {B535402E-38D2-4D54-8360-423ACBD17192}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xmltok", "libs\win32\xmlrpc-c\xmltok.2012.vcxproj", "{B535402E-38D2-4D54-8360-423ACBD17192}"
+ ProjectSection(ProjectDependencies) = postProject
+ {BED7539C-0099-4A14-AD5D-30828F15A171} = {BED7539C-0099-4A14-AD5D-30828F15A171}
+ EndProjectSection
+EndProject
+Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "Setup.2012", "w32\Setup\Setup.2012.wixproj", "{47213370-B933-487D-9F45-BCA26D7E2B6F}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ All|Win32 = All|Win32
+ All|x64 = All|x64
+ All|x64 Setup = All|x64 Setup
+ All|x86 Setup = All|x86 Setup
+ Debug|Win32 = Debug|Win32
+ Debug|x64 = Debug|x64
+ Debug|x64 Setup = Debug|x64 Setup
+ Debug|x86 Setup = Debug|x86 Setup
+ Release|Win32 = Release|Win32
+ Release|x64 = Release|x64
+ Release|x64 Setup = Release|x64 Setup
+ Release|x86 Setup = Release|x86 Setup
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {1AF3A893-F7BE-43DD-B697-8AB2397C0D67}.All|Win32.ActiveCfg = Release|x64
+ {1AF3A893-F7BE-43DD-B697-8AB2397C0D67}.All|x64.ActiveCfg = Release|x64
+ {1AF3A893-F7BE-43DD-B697-8AB2397C0D67}.All|x64.Build.0 = Release|x64
+ {1AF3A893-F7BE-43DD-B697-8AB2397C0D67}.All|x64 Setup.ActiveCfg = Release|x64
+ {1AF3A893-F7BE-43DD-B697-8AB2397C0D67}.All|x64 Setup.Build.0 = Release|x64
+ {1AF3A893-F7BE-43DD-B697-8AB2397C0D67}.All|x86 Setup.ActiveCfg = Release|x64
+ {1AF3A893-F7BE-43DD-B697-8AB2397C0D67}.Debug|Win32.ActiveCfg = Debug|Win32
+ {1AF3A893-F7BE-43DD-B697-8AB2397C0D67}.Debug|Win32.Build.0 = Debug|Win32
+ {1AF3A893-F7BE-43DD-B697-8AB2397C0D67}.Debug|x64.ActiveCfg = Debug|x64
+ {1AF3A893-F7BE-43DD-B697-8AB2397C0D67}.Debug|x64.Build.0 = Debug|x64
+ {1AF3A893-F7BE-43DD-B697-8AB2397C0D67}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {1AF3A893-F7BE-43DD-B697-8AB2397C0D67}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {1AF3A893-F7BE-43DD-B697-8AB2397C0D67}.Release|Win32.ActiveCfg = Release|Win32
+ {1AF3A893-F7BE-43DD-B697-8AB2397C0D67}.Release|Win32.Build.0 = Release|Win32
+ {1AF3A893-F7BE-43DD-B697-8AB2397C0D67}.Release|x64.ActiveCfg = Release|x64
+ {1AF3A893-F7BE-43DD-B697-8AB2397C0D67}.Release|x64.Build.0 = Release|x64
+ {1AF3A893-F7BE-43DD-B697-8AB2397C0D67}.Release|x64 Setup.ActiveCfg = Release|x64
+ {1AF3A893-F7BE-43DD-B697-8AB2397C0D67}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}.All|Win32.ActiveCfg = Release|x64
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}.All|x64.ActiveCfg = Release|x64
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}.All|x64.Build.0 = Release|x64
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}.All|x64 Setup.ActiveCfg = Release|x64
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}.All|x64 Setup.Build.0 = Release|x64
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}.All|x86 Setup.ActiveCfg = Release|x64
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}.Debug|Win32.ActiveCfg = Debug|Win32
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}.Debug|Win32.Build.0 = Debug|Win32
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}.Debug|x64.ActiveCfg = Debug|x64
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}.Debug|x64.Build.0 = Debug|x64
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}.Release|Win32.ActiveCfg = Release|Win32
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}.Release|Win32.Build.0 = Release|Win32
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}.Release|x64.ActiveCfg = Release|x64
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}.Release|x64.Build.0 = Release|x64
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}.Release|x64 Setup.ActiveCfg = Release|x64
+ {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0}.All|Win32.ActiveCfg = Release Passthrough|x64
+ {1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0}.All|x64.ActiveCfg = Release Passthrough|x64
+ {1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0}.All|x64.Build.0 = Release Passthrough|x64
+ {1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0}.All|x64 Setup.ActiveCfg = Release Passthrough|x64
+ {1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0}.All|x64 Setup.Build.0 = Release Passthrough|x64
+ {1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0}.All|x86 Setup.ActiveCfg = Release Passthrough|x64
+ {1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0}.Debug|Win32.ActiveCfg = Debug Passthrough|Win32
+ {1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0}.Debug|Win32.Build.0 = Debug Passthrough|Win32
+ {1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0}.Debug|x64.ActiveCfg = Debug Passthrough|x64
+ {1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0}.Debug|x64.Build.0 = Debug Passthrough|x64
+ {1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0}.Debug|x64 Setup.ActiveCfg = Debug Passthrough|x64
+ {1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0}.Debug|x86 Setup.ActiveCfg = Debug Passthrough|Win32
+ {1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0}.Release|Win32.ActiveCfg = Release Passthrough|Win32
+ {1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0}.Release|Win32.Build.0 = Release Passthrough|Win32
+ {1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0}.Release|x64.ActiveCfg = Release Passthrough|x64
+ {1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0}.Release|x64.Build.0 = Release Passthrough|x64
+ {1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0}.Release|x64 Setup.ActiveCfg = Release Passthrough|x64
+ {1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0}.Release|x86 Setup.ActiveCfg = Release Passthrough|Win32
+ {AFAC0568-7548-42D5-9F6A-8D3400A1E4F6}.All|Win32.ActiveCfg = Release|x64
+ {AFAC0568-7548-42D5-9F6A-8D3400A1E4F6}.All|x64.ActiveCfg = Release|x64
+ {AFAC0568-7548-42D5-9F6A-8D3400A1E4F6}.All|x64.Build.0 = Release|x64
+ {AFAC0568-7548-42D5-9F6A-8D3400A1E4F6}.All|x64 Setup.ActiveCfg = Release|x64
+ {AFAC0568-7548-42D5-9F6A-8D3400A1E4F6}.All|x64 Setup.Build.0 = Release|x64
+ {AFAC0568-7548-42D5-9F6A-8D3400A1E4F6}.All|x86 Setup.ActiveCfg = Release|x64
+ {AFAC0568-7548-42D5-9F6A-8D3400A1E4F6}.Debug|Win32.ActiveCfg = Debug|Win32
+ {AFAC0568-7548-42D5-9F6A-8D3400A1E4F6}.Debug|Win32.Build.0 = Debug|Win32
+ {AFAC0568-7548-42D5-9F6A-8D3400A1E4F6}.Debug|x64.ActiveCfg = Debug|x64
+ {AFAC0568-7548-42D5-9F6A-8D3400A1E4F6}.Debug|x64.Build.0 = Debug|x64
+ {AFAC0568-7548-42D5-9F6A-8D3400A1E4F6}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {AFAC0568-7548-42D5-9F6A-8D3400A1E4F6}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {AFAC0568-7548-42D5-9F6A-8D3400A1E4F6}.Release|Win32.ActiveCfg = Release|Win32
+ {AFAC0568-7548-42D5-9F6A-8D3400A1E4F6}.Release|Win32.Build.0 = Release|Win32
+ {AFAC0568-7548-42D5-9F6A-8D3400A1E4F6}.Release|x64.ActiveCfg = Release|x64
+ {AFAC0568-7548-42D5-9F6A-8D3400A1E4F6}.Release|x64.Build.0 = Release|x64
+ {AFAC0568-7548-42D5-9F6A-8D3400A1E4F6}.Release|x64 Setup.ActiveCfg = Release|x64
+ {AFAC0568-7548-42D5-9F6A-8D3400A1E4F6}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {5FD31A25-5D83-4794-8BEE-904DAD84CE71}.All|Win32.ActiveCfg = Release|x64
+ {5FD31A25-5D83-4794-8BEE-904DAD84CE71}.All|x64.ActiveCfg = Release|x64
+ {5FD31A25-5D83-4794-8BEE-904DAD84CE71}.All|x64.Build.0 = Release|x64
+ {5FD31A25-5D83-4794-8BEE-904DAD84CE71}.All|x64 Setup.ActiveCfg = Release|x64
+ {5FD31A25-5D83-4794-8BEE-904DAD84CE71}.All|x64 Setup.Build.0 = Release|x64
+ {5FD31A25-5D83-4794-8BEE-904DAD84CE71}.All|x86 Setup.ActiveCfg = Release|x64
+ {5FD31A25-5D83-4794-8BEE-904DAD84CE71}.Debug|Win32.ActiveCfg = Debug|Win32
+ {5FD31A25-5D83-4794-8BEE-904DAD84CE71}.Debug|Win32.Build.0 = Debug|Win32
+ {5FD31A25-5D83-4794-8BEE-904DAD84CE71}.Debug|x64.ActiveCfg = Debug|x64
+ {5FD31A25-5D83-4794-8BEE-904DAD84CE71}.Debug|x64.Build.0 = Debug|x64
+ {5FD31A25-5D83-4794-8BEE-904DAD84CE71}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {5FD31A25-5D83-4794-8BEE-904DAD84CE71}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {5FD31A25-5D83-4794-8BEE-904DAD84CE71}.Release|Win32.ActiveCfg = Release|Win32
+ {5FD31A25-5D83-4794-8BEE-904DAD84CE71}.Release|Win32.Build.0 = Release|Win32
+ {5FD31A25-5D83-4794-8BEE-904DAD84CE71}.Release|x64.ActiveCfg = Release|x64
+ {5FD31A25-5D83-4794-8BEE-904DAD84CE71}.Release|x64.Build.0 = Release|x64
+ {5FD31A25-5D83-4794-8BEE-904DAD84CE71}.Release|x64 Setup.ActiveCfg = Release|x64
+ {5FD31A25-5D83-4794-8BEE-904DAD84CE71}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {5580D60E-0F77-4716-9CD4-B8E5986FA375}.All|Win32.ActiveCfg = Release|x64
+ {5580D60E-0F77-4716-9CD4-B8E5986FA375}.All|x64.ActiveCfg = Release|x64
+ {5580D60E-0F77-4716-9CD4-B8E5986FA375}.All|x64.Build.0 = Release|x64
+ {5580D60E-0F77-4716-9CD4-B8E5986FA375}.All|x64 Setup.ActiveCfg = Release|x64
+ {5580D60E-0F77-4716-9CD4-B8E5986FA375}.All|x64 Setup.Build.0 = Release|x64
+ {5580D60E-0F77-4716-9CD4-B8E5986FA375}.All|x86 Setup.ActiveCfg = Release|x64
+ {5580D60E-0F77-4716-9CD4-B8E5986FA375}.Debug|Win32.ActiveCfg = Debug|Win32
+ {5580D60E-0F77-4716-9CD4-B8E5986FA375}.Debug|Win32.Build.0 = Debug|Win32
+ {5580D60E-0F77-4716-9CD4-B8E5986FA375}.Debug|x64.ActiveCfg = Debug|x64
+ {5580D60E-0F77-4716-9CD4-B8E5986FA375}.Debug|x64.Build.0 = Debug|x64
+ {5580D60E-0F77-4716-9CD4-B8E5986FA375}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {5580D60E-0F77-4716-9CD4-B8E5986FA375}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {5580D60E-0F77-4716-9CD4-B8E5986FA375}.Release|Win32.ActiveCfg = Release|Win32
+ {5580D60E-0F77-4716-9CD4-B8E5986FA375}.Release|Win32.Build.0 = Release|Win32
+ {5580D60E-0F77-4716-9CD4-B8E5986FA375}.Release|x64.ActiveCfg = Release|x64
+ {5580D60E-0F77-4716-9CD4-B8E5986FA375}.Release|x64.Build.0 = Release|x64
+ {5580D60E-0F77-4716-9CD4-B8E5986FA375}.Release|x64 Setup.ActiveCfg = Release|x64
+ {5580D60E-0F77-4716-9CD4-B8E5986FA375}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {1A1FF289-4FD6-4285-A422-D31DD67A4723}.All|Win32.ActiveCfg = Release|Win32
+ {1A1FF289-4FD6-4285-A422-D31DD67A4723}.All|x64.ActiveCfg = Release|Win32
+ {1A1FF289-4FD6-4285-A422-D31DD67A4723}.All|x64 Setup.ActiveCfg = Release|Win32
+ {1A1FF289-4FD6-4285-A422-D31DD67A4723}.All|x86 Setup.ActiveCfg = Release|Win32
+ {1A1FF289-4FD6-4285-A422-D31DD67A4723}.Debug|Win32.ActiveCfg = Debug|Win32
+ {1A1FF289-4FD6-4285-A422-D31DD67A4723}.Debug|x64.ActiveCfg = Debug|Win32
+ {1A1FF289-4FD6-4285-A422-D31DD67A4723}.Debug|x64 Setup.ActiveCfg = Debug|Win32
+ {1A1FF289-4FD6-4285-A422-D31DD67A4723}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {1A1FF289-4FD6-4285-A422-D31DD67A4723}.Release|Win32.ActiveCfg = Release|Win32
+ {1A1FF289-4FD6-4285-A422-D31DD67A4723}.Release|x64.ActiveCfg = Release|Win32
+ {1A1FF289-4FD6-4285-A422-D31DD67A4723}.Release|x64 Setup.ActiveCfg = Release|Win32
+ {1A1FF289-4FD6-4285-A422-D31DD67A4723}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {07113B25-D3AF-4E04-BA77-4CD1171F022C}.All|Win32.ActiveCfg = Release|x64
+ {07113B25-D3AF-4E04-BA77-4CD1171F022C}.All|x64.ActiveCfg = Release|x64
+ {07113B25-D3AF-4E04-BA77-4CD1171F022C}.All|x64.Build.0 = Release|x64
+ {07113B25-D3AF-4E04-BA77-4CD1171F022C}.All|x64 Setup.ActiveCfg = Release|x64
+ {07113B25-D3AF-4E04-BA77-4CD1171F022C}.All|x64 Setup.Build.0 = Release|x64
+ {07113B25-D3AF-4E04-BA77-4CD1171F022C}.All|x86 Setup.ActiveCfg = Release|x64
+ {07113B25-D3AF-4E04-BA77-4CD1171F022C}.Debug|Win32.ActiveCfg = Debug|Win32
+ {07113B25-D3AF-4E04-BA77-4CD1171F022C}.Debug|Win32.Build.0 = Debug|Win32
+ {07113B25-D3AF-4E04-BA77-4CD1171F022C}.Debug|x64.ActiveCfg = Debug|x64
+ {07113B25-D3AF-4E04-BA77-4CD1171F022C}.Debug|x64.Build.0 = Debug|x64
+ {07113B25-D3AF-4E04-BA77-4CD1171F022C}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {07113B25-D3AF-4E04-BA77-4CD1171F022C}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {07113B25-D3AF-4E04-BA77-4CD1171F022C}.Release|Win32.ActiveCfg = Release|Win32
+ {07113B25-D3AF-4E04-BA77-4CD1171F022C}.Release|Win32.Build.0 = Release|Win32
+ {07113B25-D3AF-4E04-BA77-4CD1171F022C}.Release|x64.ActiveCfg = Release|x64
+ {07113B25-D3AF-4E04-BA77-4CD1171F022C}.Release|x64.Build.0 = Release|x64
+ {07113B25-D3AF-4E04-BA77-4CD1171F022C}.Release|x64 Setup.ActiveCfg = Release|x64
+ {07113B25-D3AF-4E04-BA77-4CD1171F022C}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {EC3E5C7F-EE09-47E2-80FE-546363D14A98}.All|Win32.ActiveCfg = Release MS-LDAP|x64
+ {EC3E5C7F-EE09-47E2-80FE-546363D14A98}.All|x64.ActiveCfg = Release MS-LDAP|x64
+ {EC3E5C7F-EE09-47E2-80FE-546363D14A98}.All|x64.Build.0 = Release MS-LDAP|x64
+ {EC3E5C7F-EE09-47E2-80FE-546363D14A98}.All|x64 Setup.ActiveCfg = Release MS-LDAP|x64
+ {EC3E5C7F-EE09-47E2-80FE-546363D14A98}.All|x64 Setup.Build.0 = Release MS-LDAP|x64
+ {EC3E5C7F-EE09-47E2-80FE-546363D14A98}.All|x86 Setup.ActiveCfg = Release MS-LDAP|x64
+ {EC3E5C7F-EE09-47E2-80FE-546363D14A98}.Debug|Win32.ActiveCfg = Debug MS-LDAP|Win32
+ {EC3E5C7F-EE09-47E2-80FE-546363D14A98}.Debug|Win32.Build.0 = Debug MS-LDAP|Win32
+ {EC3E5C7F-EE09-47E2-80FE-546363D14A98}.Debug|x64.ActiveCfg = Debug MS-LDAP|x64
+ {EC3E5C7F-EE09-47E2-80FE-546363D14A98}.Debug|x64.Build.0 = Debug MS-LDAP|x64
+ {EC3E5C7F-EE09-47E2-80FE-546363D14A98}.Debug|x64 Setup.ActiveCfg = Debug MS-LDAP|x64
+ {EC3E5C7F-EE09-47E2-80FE-546363D14A98}.Debug|x86 Setup.ActiveCfg = Debug MS-LDAP|Win32
+ {EC3E5C7F-EE09-47E2-80FE-546363D14A98}.Release|Win32.ActiveCfg = Release MS-LDAP|Win32
+ {EC3E5C7F-EE09-47E2-80FE-546363D14A98}.Release|Win32.Build.0 = Release MS-LDAP|Win32
+ {EC3E5C7F-EE09-47E2-80FE-546363D14A98}.Release|x64.ActiveCfg = Release MS-LDAP|x64
+ {EC3E5C7F-EE09-47E2-80FE-546363D14A98}.Release|x64.Build.0 = Release MS-LDAP|x64
+ {EC3E5C7F-EE09-47E2-80FE-546363D14A98}.Release|x64 Setup.ActiveCfg = Release MS-LDAP|x64
+ {EC3E5C7F-EE09-47E2-80FE-546363D14A98}.Release|x86 Setup.ActiveCfg = Release MS-LDAP|Win32
+ {A27CCA23-1541-4337-81A4-F0A6413078A0}.All|Win32.ActiveCfg = Release|x64
+ {A27CCA23-1541-4337-81A4-F0A6413078A0}.All|x64.ActiveCfg = Release|x64
+ {A27CCA23-1541-4337-81A4-F0A6413078A0}.All|x64.Build.0 = Release|x64
+ {A27CCA23-1541-4337-81A4-F0A6413078A0}.All|x64 Setup.ActiveCfg = Release|x64
+ {A27CCA23-1541-4337-81A4-F0A6413078A0}.All|x64 Setup.Build.0 = Release|x64
+ {A27CCA23-1541-4337-81A4-F0A6413078A0}.All|x86 Setup.ActiveCfg = Release|x64
+ {A27CCA23-1541-4337-81A4-F0A6413078A0}.Debug|Win32.ActiveCfg = Debug|Win32
+ {A27CCA23-1541-4337-81A4-F0A6413078A0}.Debug|Win32.Build.0 = Debug|Win32
+ {A27CCA23-1541-4337-81A4-F0A6413078A0}.Debug|x64.ActiveCfg = Debug|x64
+ {A27CCA23-1541-4337-81A4-F0A6413078A0}.Debug|x64.Build.0 = Debug|x64
+ {A27CCA23-1541-4337-81A4-F0A6413078A0}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {A27CCA23-1541-4337-81A4-F0A6413078A0}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {A27CCA23-1541-4337-81A4-F0A6413078A0}.Release|Win32.ActiveCfg = Release|Win32
+ {A27CCA23-1541-4337-81A4-F0A6413078A0}.Release|Win32.Build.0 = Release|Win32
+ {A27CCA23-1541-4337-81A4-F0A6413078A0}.Release|x64.ActiveCfg = Release|x64
+ {A27CCA23-1541-4337-81A4-F0A6413078A0}.Release|x64.Build.0 = Release|x64
+ {A27CCA23-1541-4337-81A4-F0A6413078A0}.Release|x64 Setup.ActiveCfg = Release|x64
+ {A27CCA23-1541-4337-81A4-F0A6413078A0}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {784113EF-44D9-4949-835D-7065D3C7AD08}.All|Win32.ActiveCfg = Release|x64
+ {784113EF-44D9-4949-835D-7065D3C7AD08}.All|x64.ActiveCfg = Release|x64
+ {784113EF-44D9-4949-835D-7065D3C7AD08}.All|x64.Build.0 = Release|x64
+ {784113EF-44D9-4949-835D-7065D3C7AD08}.All|x64 Setup.ActiveCfg = Release|x64
+ {784113EF-44D9-4949-835D-7065D3C7AD08}.All|x64 Setup.Build.0 = Release|x64
+ {784113EF-44D9-4949-835D-7065D3C7AD08}.All|x86 Setup.ActiveCfg = Release|x64
+ {784113EF-44D9-4949-835D-7065D3C7AD08}.Debug|Win32.ActiveCfg = Debug|Win32
+ {784113EF-44D9-4949-835D-7065D3C7AD08}.Debug|Win32.Build.0 = Debug|Win32
+ {784113EF-44D9-4949-835D-7065D3C7AD08}.Debug|x64.ActiveCfg = Debug|x64
+ {784113EF-44D9-4949-835D-7065D3C7AD08}.Debug|x64.Build.0 = Debug|x64
+ {784113EF-44D9-4949-835D-7065D3C7AD08}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {784113EF-44D9-4949-835D-7065D3C7AD08}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {784113EF-44D9-4949-835D-7065D3C7AD08}.Release|Win32.ActiveCfg = Release|Win32
+ {784113EF-44D9-4949-835D-7065D3C7AD08}.Release|Win32.Build.0 = Release|Win32
+ {784113EF-44D9-4949-835D-7065D3C7AD08}.Release|x64.ActiveCfg = Release|x64
+ {784113EF-44D9-4949-835D-7065D3C7AD08}.Release|x64.Build.0 = Release|x64
+ {784113EF-44D9-4949-835D-7065D3C7AD08}.Release|x64 Setup.ActiveCfg = Release|x64
+ {784113EF-44D9-4949-835D-7065D3C7AD08}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {89385C74-5860-4174-9CAF-A39E7C48909C}.All|Win32.ActiveCfg = Release|x64
+ {89385C74-5860-4174-9CAF-A39E7C48909C}.All|x64.ActiveCfg = Release|x64
+ {89385C74-5860-4174-9CAF-A39E7C48909C}.All|x64.Build.0 = Release|x64
+ {89385C74-5860-4174-9CAF-A39E7C48909C}.All|x64 Setup.ActiveCfg = Release|x64
+ {89385C74-5860-4174-9CAF-A39E7C48909C}.All|x64 Setup.Build.0 = Release|x64
+ {89385C74-5860-4174-9CAF-A39E7C48909C}.All|x86 Setup.ActiveCfg = Release|x64
+ {89385C74-5860-4174-9CAF-A39E7C48909C}.Debug|Win32.ActiveCfg = Debug|Win32
+ {89385C74-5860-4174-9CAF-A39E7C48909C}.Debug|Win32.Build.0 = Debug|Win32
+ {89385C74-5860-4174-9CAF-A39E7C48909C}.Debug|x64.ActiveCfg = Debug|x64
+ {89385C74-5860-4174-9CAF-A39E7C48909C}.Debug|x64.Build.0 = Debug|x64
+ {89385C74-5860-4174-9CAF-A39E7C48909C}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {89385C74-5860-4174-9CAF-A39E7C48909C}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {89385C74-5860-4174-9CAF-A39E7C48909C}.Release|Win32.ActiveCfg = Release|Win32
+ {89385C74-5860-4174-9CAF-A39E7C48909C}.Release|Win32.Build.0 = Release|Win32
+ {89385C74-5860-4174-9CAF-A39E7C48909C}.Release|x64.ActiveCfg = Release|x64
+ {89385C74-5860-4174-9CAF-A39E7C48909C}.Release|x64.Build.0 = Release|x64
+ {89385C74-5860-4174-9CAF-A39E7C48909C}.Release|x64 Setup.ActiveCfg = Release|x64
+ {89385C74-5860-4174-9CAF-A39E7C48909C}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}.All|Win32.ActiveCfg = Release|x64
+ {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}.All|x64.ActiveCfg = Release|x64
+ {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}.All|x64.Build.0 = Release|x64
+ {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}.All|x64 Setup.ActiveCfg = Release|x64
+ {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}.All|x64 Setup.Build.0 = Release|x64
+ {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}.All|x86 Setup.ActiveCfg = Release|x64
+ {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}.Debug|Win32.ActiveCfg = Debug|Win32
+ {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}.Debug|Win32.Build.0 = Debug|Win32
+ {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}.Debug|x64.ActiveCfg = Debug|x64
+ {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}.Debug|x64.Build.0 = Debug|x64
+ {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}.Release|Win32.ActiveCfg = Release|Win32
+ {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}.Release|Win32.Build.0 = Release|Win32
+ {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}.Release|x64.ActiveCfg = Release|x64
+ {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}.Release|x64.Build.0 = Release|x64
+ {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}.Release|x64 Setup.ActiveCfg = Release|x64
+ {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {692F6330-4D87-4C82-81DF-40DB5892636E}.All|Win32.ActiveCfg = Release|x64
+ {692F6330-4D87-4C82-81DF-40DB5892636E}.All|x64.ActiveCfg = Release|x64
+ {692F6330-4D87-4C82-81DF-40DB5892636E}.All|x64.Build.0 = Release|x64
+ {692F6330-4D87-4C82-81DF-40DB5892636E}.All|x64 Setup.ActiveCfg = Release|x64
+ {692F6330-4D87-4C82-81DF-40DB5892636E}.All|x64 Setup.Build.0 = Release|x64
+ {692F6330-4D87-4C82-81DF-40DB5892636E}.All|x86 Setup.ActiveCfg = Release|x64
+ {692F6330-4D87-4C82-81DF-40DB5892636E}.Debug|Win32.ActiveCfg = Debug|Win32
+ {692F6330-4D87-4C82-81DF-40DB5892636E}.Debug|x64.ActiveCfg = Debug|x64
+ {692F6330-4D87-4C82-81DF-40DB5892636E}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {692F6330-4D87-4C82-81DF-40DB5892636E}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {692F6330-4D87-4C82-81DF-40DB5892636E}.Release|Win32.ActiveCfg = Release|Win32
+ {692F6330-4D87-4C82-81DF-40DB5892636E}.Release|x64.ActiveCfg = Release|x64
+ {692F6330-4D87-4C82-81DF-40DB5892636E}.Release|x64 Setup.ActiveCfg = Release|x64
+ {692F6330-4D87-4C82-81DF-40DB5892636E}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {D3EC0AFF-76FC-4210-A825-9A17410660A3}.All|Win32.ActiveCfg = Release|x64
+ {D3EC0AFF-76FC-4210-A825-9A17410660A3}.All|x64.ActiveCfg = Release|x64
+ {D3EC0AFF-76FC-4210-A825-9A17410660A3}.All|x64.Build.0 = Release|x64
+ {D3EC0AFF-76FC-4210-A825-9A17410660A3}.All|x64 Setup.ActiveCfg = Release|x64
+ {D3EC0AFF-76FC-4210-A825-9A17410660A3}.All|x64 Setup.Build.0 = Release|x64
+ {D3EC0AFF-76FC-4210-A825-9A17410660A3}.All|x86 Setup.ActiveCfg = Release|x64
+ {D3EC0AFF-76FC-4210-A825-9A17410660A3}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D3EC0AFF-76FC-4210-A825-9A17410660A3}.Debug|Win32.Build.0 = Debug|Win32
+ {D3EC0AFF-76FC-4210-A825-9A17410660A3}.Debug|x64.ActiveCfg = Debug|x64
+ {D3EC0AFF-76FC-4210-A825-9A17410660A3}.Debug|x64.Build.0 = Debug|x64
+ {D3EC0AFF-76FC-4210-A825-9A17410660A3}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {D3EC0AFF-76FC-4210-A825-9A17410660A3}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {D3EC0AFF-76FC-4210-A825-9A17410660A3}.Release|Win32.ActiveCfg = Release|Win32
+ {D3EC0AFF-76FC-4210-A825-9A17410660A3}.Release|Win32.Build.0 = Release|Win32
+ {D3EC0AFF-76FC-4210-A825-9A17410660A3}.Release|x64.ActiveCfg = Release|x64
+ {D3EC0AFF-76FC-4210-A825-9A17410660A3}.Release|x64.Build.0 = Release|x64
+ {D3EC0AFF-76FC-4210-A825-9A17410660A3}.Release|x64 Setup.ActiveCfg = Release|x64
+ {D3EC0AFF-76FC-4210-A825-9A17410660A3}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {FFAA4C52-3A53-4F99-90C1-D59D1F0427F3}.All|Win32.ActiveCfg = Release|x64
+ {FFAA4C52-3A53-4F99-90C1-D59D1F0427F3}.All|x64.ActiveCfg = Release|x64
+ {FFAA4C52-3A53-4F99-90C1-D59D1F0427F3}.All|x64.Build.0 = Release|x64
+ {FFAA4C52-3A53-4F99-90C1-D59D1F0427F3}.All|x64 Setup.ActiveCfg = Release|x64
+ {FFAA4C52-3A53-4F99-90C1-D59D1F0427F3}.All|x64 Setup.Build.0 = Release|x64
+ {FFAA4C52-3A53-4F99-90C1-D59D1F0427F3}.All|x86 Setup.ActiveCfg = Release|x64
+ {FFAA4C52-3A53-4F99-90C1-D59D1F0427F3}.Debug|Win32.ActiveCfg = Debug|Win32
+ {FFAA4C52-3A53-4F99-90C1-D59D1F0427F3}.Debug|Win32.Build.0 = Debug|Win32
+ {FFAA4C52-3A53-4F99-90C1-D59D1F0427F3}.Debug|x64.ActiveCfg = Debug|x64
+ {FFAA4C52-3A53-4F99-90C1-D59D1F0427F3}.Debug|x64.Build.0 = Debug|x64
+ {FFAA4C52-3A53-4F99-90C1-D59D1F0427F3}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {FFAA4C52-3A53-4F99-90C1-D59D1F0427F3}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {FFAA4C52-3A53-4F99-90C1-D59D1F0427F3}.Release|Win32.ActiveCfg = Release|Win32
+ {FFAA4C52-3A53-4F99-90C1-D59D1F0427F3}.Release|Win32.Build.0 = Release|Win32
+ {FFAA4C52-3A53-4F99-90C1-D59D1F0427F3}.Release|x64.ActiveCfg = Release|x64
+ {FFAA4C52-3A53-4F99-90C1-D59D1F0427F3}.Release|x64.Build.0 = Release|x64
+ {FFAA4C52-3A53-4F99-90C1-D59D1F0427F3}.Release|x64 Setup.ActiveCfg = Release|x64
+ {FFAA4C52-3A53-4F99-90C1-D59D1F0427F3}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {30A5B29C-983E-4580-9FD0-D647CCDCC7EB}.All|Win32.ActiveCfg = Release|x64
+ {30A5B29C-983E-4580-9FD0-D647CCDCC7EB}.All|x64.ActiveCfg = Release|x64
+ {30A5B29C-983E-4580-9FD0-D647CCDCC7EB}.All|x64.Build.0 = Release|x64
+ {30A5B29C-983E-4580-9FD0-D647CCDCC7EB}.All|x64 Setup.ActiveCfg = Release|x64
+ {30A5B29C-983E-4580-9FD0-D647CCDCC7EB}.All|x64 Setup.Build.0 = Release|x64
+ {30A5B29C-983E-4580-9FD0-D647CCDCC7EB}.All|x86 Setup.ActiveCfg = Release|x64
+ {30A5B29C-983E-4580-9FD0-D647CCDCC7EB}.Debug|Win32.ActiveCfg = Debug|Win32
+ {30A5B29C-983E-4580-9FD0-D647CCDCC7EB}.Debug|Win32.Build.0 = Debug|Win32
+ {30A5B29C-983E-4580-9FD0-D647CCDCC7EB}.Debug|x64.ActiveCfg = Debug|x64
+ {30A5B29C-983E-4580-9FD0-D647CCDCC7EB}.Debug|x64.Build.0 = Debug|x64
+ {30A5B29C-983E-4580-9FD0-D647CCDCC7EB}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {30A5B29C-983E-4580-9FD0-D647CCDCC7EB}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {30A5B29C-983E-4580-9FD0-D647CCDCC7EB}.Release|Win32.ActiveCfg = Release|Win32
+ {30A5B29C-983E-4580-9FD0-D647CCDCC7EB}.Release|Win32.Build.0 = Release|Win32
+ {30A5B29C-983E-4580-9FD0-D647CCDCC7EB}.Release|x64.ActiveCfg = Release|x64
+ {30A5B29C-983E-4580-9FD0-D647CCDCC7EB}.Release|x64.Build.0 = Release|x64
+ {30A5B29C-983E-4580-9FD0-D647CCDCC7EB}.Release|x64 Setup.ActiveCfg = Release|x64
+ {30A5B29C-983E-4580-9FD0-D647CCDCC7EB}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {1C453396-D912-4213-89FD-9B489162B7B5}.All|Win32.ActiveCfg = Release|x64
+ {1C453396-D912-4213-89FD-9B489162B7B5}.All|x64.ActiveCfg = Release|x64
+ {1C453396-D912-4213-89FD-9B489162B7B5}.All|x64.Build.0 = Release|x64
+ {1C453396-D912-4213-89FD-9B489162B7B5}.All|x64 Setup.ActiveCfg = Release|x64
+ {1C453396-D912-4213-89FD-9B489162B7B5}.All|x64 Setup.Build.0 = Release|x64
+ {1C453396-D912-4213-89FD-9B489162B7B5}.All|x86 Setup.ActiveCfg = Release|x64
+ {1C453396-D912-4213-89FD-9B489162B7B5}.Debug|Win32.ActiveCfg = Debug|Win32
+ {1C453396-D912-4213-89FD-9B489162B7B5}.Debug|Win32.Build.0 = Debug|Win32
+ {1C453396-D912-4213-89FD-9B489162B7B5}.Debug|x64.ActiveCfg = Debug|x64
+ {1C453396-D912-4213-89FD-9B489162B7B5}.Debug|x64.Build.0 = Debug|x64
+ {1C453396-D912-4213-89FD-9B489162B7B5}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {1C453396-D912-4213-89FD-9B489162B7B5}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {1C453396-D912-4213-89FD-9B489162B7B5}.Release|Win32.ActiveCfg = Release|Win32
+ {1C453396-D912-4213-89FD-9B489162B7B5}.Release|Win32.Build.0 = Release|Win32
+ {1C453396-D912-4213-89FD-9B489162B7B5}.Release|x64.ActiveCfg = Release|x64
+ {1C453396-D912-4213-89FD-9B489162B7B5}.Release|x64.Build.0 = Release|x64
+ {1C453396-D912-4213-89FD-9B489162B7B5}.Release|x64 Setup.ActiveCfg = Release|x64
+ {1C453396-D912-4213-89FD-9B489162B7B5}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {CBEC7225-0C21-4DA8-978E-1F158F8AD950}.All|Win32.ActiveCfg = Release|x64
+ {CBEC7225-0C21-4DA8-978E-1F158F8AD950}.All|x64.ActiveCfg = Release|x64
+ {CBEC7225-0C21-4DA8-978E-1F158F8AD950}.All|x64.Build.0 = Release|x64
+ {CBEC7225-0C21-4DA8-978E-1F158F8AD950}.All|x64 Setup.ActiveCfg = Release|x64
+ {CBEC7225-0C21-4DA8-978E-1F158F8AD950}.All|x64 Setup.Build.0 = Release|x64
+ {CBEC7225-0C21-4DA8-978E-1F158F8AD950}.All|x86 Setup.ActiveCfg = Release|x64
+ {CBEC7225-0C21-4DA8-978E-1F158F8AD950}.Debug|Win32.ActiveCfg = Debug|Win32
+ {CBEC7225-0C21-4DA8-978E-1F158F8AD950}.Debug|Win32.Build.0 = Debug|Win32
+ {CBEC7225-0C21-4DA8-978E-1F158F8AD950}.Debug|x64.ActiveCfg = Debug|x64
+ {CBEC7225-0C21-4DA8-978E-1F158F8AD950}.Debug|x64.Build.0 = Debug|x64
+ {CBEC7225-0C21-4DA8-978E-1F158F8AD950}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {CBEC7225-0C21-4DA8-978E-1F158F8AD950}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {CBEC7225-0C21-4DA8-978E-1F158F8AD950}.Release|Win32.ActiveCfg = Release|Win32
+ {CBEC7225-0C21-4DA8-978E-1F158F8AD950}.Release|Win32.Build.0 = Release|Win32
+ {CBEC7225-0C21-4DA8-978E-1F158F8AD950}.Release|x64.ActiveCfg = Release|x64
+ {CBEC7225-0C21-4DA8-978E-1F158F8AD950}.Release|x64.Build.0 = Release|x64
+ {CBEC7225-0C21-4DA8-978E-1F158F8AD950}.Release|x64 Setup.ActiveCfg = Release|x64
+ {CBEC7225-0C21-4DA8-978E-1F158F8AD950}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4}.All|Win32.ActiveCfg = Release|x64
+ {B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4}.All|x64.ActiveCfg = Release|x64
+ {B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4}.All|x64.Build.0 = Release|x64
+ {B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4}.All|x64 Setup.ActiveCfg = Release|x64
+ {B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4}.All|x64 Setup.Build.0 = Release|x64
+ {B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4}.All|x86 Setup.ActiveCfg = Release|x64
+ {B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4}.Debug|Win32.ActiveCfg = Debug|Win32
+ {B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4}.Debug|Win32.Build.0 = Debug|Win32
+ {B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4}.Debug|x64.ActiveCfg = Debug|x64
+ {B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4}.Debug|x64.Build.0 = Debug|x64
+ {B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4}.Release|Win32.ActiveCfg = Release|Win32
+ {B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4}.Release|Win32.Build.0 = Release|Win32
+ {B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4}.Release|x64.ActiveCfg = Release|x64
+ {B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4}.Release|x64.Build.0 = Release|x64
+ {B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4}.Release|x64 Setup.ActiveCfg = Release|x64
+ {B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {C24FB505-05D7-4319-8485-7540B44C8603}.All|Win32.ActiveCfg = Release|x64
+ {C24FB505-05D7-4319-8485-7540B44C8603}.All|x64.ActiveCfg = Release|x64
+ {C24FB505-05D7-4319-8485-7540B44C8603}.All|x64.Build.0 = Release|x64
+ {C24FB505-05D7-4319-8485-7540B44C8603}.All|x64 Setup.ActiveCfg = Release|x64
+ {C24FB505-05D7-4319-8485-7540B44C8603}.All|x64 Setup.Build.0 = Release|x64
+ {C24FB505-05D7-4319-8485-7540B44C8603}.All|x86 Setup.ActiveCfg = Release|x64
+ {C24FB505-05D7-4319-8485-7540B44C8603}.Debug|Win32.ActiveCfg = Debug|Win32
+ {C24FB505-05D7-4319-8485-7540B44C8603}.Debug|Win32.Build.0 = Debug|Win32
+ {C24FB505-05D7-4319-8485-7540B44C8603}.Debug|x64.ActiveCfg = Debug|x64
+ {C24FB505-05D7-4319-8485-7540B44C8603}.Debug|x64.Build.0 = Debug|x64
+ {C24FB505-05D7-4319-8485-7540B44C8603}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {C24FB505-05D7-4319-8485-7540B44C8603}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {C24FB505-05D7-4319-8485-7540B44C8603}.Release|Win32.ActiveCfg = Release|Win32
+ {C24FB505-05D7-4319-8485-7540B44C8603}.Release|Win32.Build.0 = Release|Win32
+ {C24FB505-05D7-4319-8485-7540B44C8603}.Release|x64.ActiveCfg = Release|x64
+ {C24FB505-05D7-4319-8485-7540B44C8603}.Release|x64.Build.0 = Release|x64
+ {C24FB505-05D7-4319-8485-7540B44C8603}.Release|x64 Setup.ActiveCfg = Release|x64
+ {C24FB505-05D7-4319-8485-7540B44C8603}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {B5881A85-FE70-4F64-8607-2CAAE52669C6}.All|Win32.ActiveCfg = Release|x64
+ {B5881A85-FE70-4F64-8607-2CAAE52669C6}.All|x64.ActiveCfg = Release|x64
+ {B5881A85-FE70-4F64-8607-2CAAE52669C6}.All|x64.Build.0 = Release|x64
+ {B5881A85-FE70-4F64-8607-2CAAE52669C6}.All|x64 Setup.ActiveCfg = Release|x64
+ {B5881A85-FE70-4F64-8607-2CAAE52669C6}.All|x64 Setup.Build.0 = Release|x64
+ {B5881A85-FE70-4F64-8607-2CAAE52669C6}.All|x86 Setup.ActiveCfg = Release|x64
+ {B5881A85-FE70-4F64-8607-2CAAE52669C6}.Debug|Win32.ActiveCfg = Debug|Win32
+ {B5881A85-FE70-4F64-8607-2CAAE52669C6}.Debug|Win32.Build.0 = Debug|Win32
+ {B5881A85-FE70-4F64-8607-2CAAE52669C6}.Debug|x64.ActiveCfg = Debug|x64
+ {B5881A85-FE70-4F64-8607-2CAAE52669C6}.Debug|x64.Build.0 = Debug|x64
+ {B5881A85-FE70-4F64-8607-2CAAE52669C6}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {B5881A85-FE70-4F64-8607-2CAAE52669C6}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {B5881A85-FE70-4F64-8607-2CAAE52669C6}.Release|Win32.ActiveCfg = Release|Win32
+ {B5881A85-FE70-4F64-8607-2CAAE52669C6}.Release|Win32.Build.0 = Release|Win32
+ {B5881A85-FE70-4F64-8607-2CAAE52669C6}.Release|x64.ActiveCfg = Release|x64
+ {B5881A85-FE70-4F64-8607-2CAAE52669C6}.Release|x64.Build.0 = Release|x64
+ {B5881A85-FE70-4F64-8607-2CAAE52669C6}.Release|x64 Setup.ActiveCfg = Release|x64
+ {B5881A85-FE70-4F64-8607-2CAAE52669C6}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {05515420-16DE-4E63-BE73-85BE85BA5142}.All|Win32.ActiveCfg = Release|x64
+ {05515420-16DE-4E63-BE73-85BE85BA5142}.All|x64.ActiveCfg = Release|x64
+ {05515420-16DE-4E63-BE73-85BE85BA5142}.All|x64.Build.0 = Release|x64
+ {05515420-16DE-4E63-BE73-85BE85BA5142}.All|x64 Setup.ActiveCfg = Release|x64
+ {05515420-16DE-4E63-BE73-85BE85BA5142}.All|x64 Setup.Build.0 = Release|x64
+ {05515420-16DE-4E63-BE73-85BE85BA5142}.All|x86 Setup.ActiveCfg = Release|x64
+ {05515420-16DE-4E63-BE73-85BE85BA5142}.Debug|Win32.ActiveCfg = Debug|Win32
+ {05515420-16DE-4E63-BE73-85BE85BA5142}.Debug|Win32.Build.0 = Debug|Win32
+ {05515420-16DE-4E63-BE73-85BE85BA5142}.Debug|x64.ActiveCfg = Debug|x64
+ {05515420-16DE-4E63-BE73-85BE85BA5142}.Debug|x64.Build.0 = Debug|x64
+ {05515420-16DE-4E63-BE73-85BE85BA5142}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {05515420-16DE-4E63-BE73-85BE85BA5142}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {05515420-16DE-4E63-BE73-85BE85BA5142}.Release|Win32.ActiveCfg = Release|Win32
+ {05515420-16DE-4E63-BE73-85BE85BA5142}.Release|Win32.Build.0 = Release|Win32
+ {05515420-16DE-4E63-BE73-85BE85BA5142}.Release|x64.ActiveCfg = Release|x64
+ {05515420-16DE-4E63-BE73-85BE85BA5142}.Release|x64.Build.0 = Release|x64
+ {05515420-16DE-4E63-BE73-85BE85BA5142}.Release|x64 Setup.ActiveCfg = Release|x64
+ {05515420-16DE-4E63-BE73-85BE85BA5142}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {1906D736-08BD-4EE1-924F-B536249B9A54}.All|Win32.ActiveCfg = Release DLL|x64
+ {1906D736-08BD-4EE1-924F-B536249B9A54}.All|x64.ActiveCfg = Release DLL|x64
+ {1906D736-08BD-4EE1-924F-B536249B9A54}.All|x64.Build.0 = Release DLL|x64
+ {1906D736-08BD-4EE1-924F-B536249B9A54}.All|x64 Setup.ActiveCfg = Release DLL|x64
+ {1906D736-08BD-4EE1-924F-B536249B9A54}.All|x64 Setup.Build.0 = Release DLL|x64
+ {1906D736-08BD-4EE1-924F-B536249B9A54}.All|x86 Setup.ActiveCfg = Release DLL|x64
+ {1906D736-08BD-4EE1-924F-B536249B9A54}.Debug|Win32.ActiveCfg = Debug|Win32
+ {1906D736-08BD-4EE1-924F-B536249B9A54}.Debug|Win32.Build.0 = Debug|Win32
+ {1906D736-08BD-4EE1-924F-B536249B9A54}.Debug|x64.ActiveCfg = Debug|x64
+ {1906D736-08BD-4EE1-924F-B536249B9A54}.Debug|x64.Build.0 = Debug|x64
+ {1906D736-08BD-4EE1-924F-B536249B9A54}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {1906D736-08BD-4EE1-924F-B536249B9A54}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {1906D736-08BD-4EE1-924F-B536249B9A54}.Release|Win32.ActiveCfg = Release|Win32
+ {1906D736-08BD-4EE1-924F-B536249B9A54}.Release|Win32.Build.0 = Release|Win32
+ {1906D736-08BD-4EE1-924F-B536249B9A54}.Release|x64.ActiveCfg = Release|x64
+ {1906D736-08BD-4EE1-924F-B536249B9A54}.Release|x64.Build.0 = Release|x64
+ {1906D736-08BD-4EE1-924F-B536249B9A54}.Release|x64 Setup.ActiveCfg = Release|x64
+ {1906D736-08BD-4EE1-924F-B536249B9A54}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {EEF031CB-FED8-451E-A471-91EC8D4F6750}.All|Win32.ActiveCfg = Release Dll|x64
+ {EEF031CB-FED8-451E-A471-91EC8D4F6750}.All|x64.ActiveCfg = Release Dll|x64
+ {EEF031CB-FED8-451E-A471-91EC8D4F6750}.All|x64.Build.0 = Release Dll|x64
+ {EEF031CB-FED8-451E-A471-91EC8D4F6750}.All|x64 Setup.ActiveCfg = Release Dll|x64
+ {EEF031CB-FED8-451E-A471-91EC8D4F6750}.All|x64 Setup.Build.0 = Release Dll|x64
+ {EEF031CB-FED8-451E-A471-91EC8D4F6750}.All|x86 Setup.ActiveCfg = Release Dll|x64
+ {EEF031CB-FED8-451E-A471-91EC8D4F6750}.Debug|Win32.ActiveCfg = Debug|Win32
+ {EEF031CB-FED8-451E-A471-91EC8D4F6750}.Debug|Win32.Build.0 = Debug|Win32
+ {EEF031CB-FED8-451E-A471-91EC8D4F6750}.Debug|x64.ActiveCfg = Debug|x64
+ {EEF031CB-FED8-451E-A471-91EC8D4F6750}.Debug|x64.Build.0 = Debug|x64
+ {EEF031CB-FED8-451E-A471-91EC8D4F6750}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {EEF031CB-FED8-451E-A471-91EC8D4F6750}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {EEF031CB-FED8-451E-A471-91EC8D4F6750}.Release|Win32.ActiveCfg = Release|Win32
+ {EEF031CB-FED8-451E-A471-91EC8D4F6750}.Release|Win32.Build.0 = Release|Win32
+ {EEF031CB-FED8-451E-A471-91EC8D4F6750}.Release|x64.ActiveCfg = Release|x64
+ {EEF031CB-FED8-451E-A471-91EC8D4F6750}.Release|x64.Build.0 = Release|x64
+ {EEF031CB-FED8-451E-A471-91EC8D4F6750}.Release|x64 Setup.ActiveCfg = Release|x64
+ {EEF031CB-FED8-451E-A471-91EC8D4F6750}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3}.All|Win32.ActiveCfg = Release DLL|x64
+ {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3}.All|x64.ActiveCfg = Release DLL|x64
+ {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3}.All|x64.Build.0 = Release DLL|x64
+ {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3}.All|x64 Setup.ActiveCfg = Release DLL|x64
+ {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3}.All|x64 Setup.Build.0 = Release DLL|x64
+ {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3}.All|x86 Setup.ActiveCfg = Release DLL|x64
+ {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3}.Debug|Win32.ActiveCfg = Debug|Win32
+ {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3}.Debug|Win32.Build.0 = Debug|Win32
+ {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3}.Debug|x64.ActiveCfg = Debug|x64
+ {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3}.Debug|x64.Build.0 = Debug|x64
+ {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3}.Release|Win32.ActiveCfg = Release|Win32
+ {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3}.Release|Win32.Build.0 = Release|Win32
+ {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3}.Release|x64.ActiveCfg = Release|x64
+ {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3}.Release|x64.Build.0 = Release|x64
+ {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3}.Release|x64 Setup.ActiveCfg = Release|x64
+ {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {8D04B550-D240-4A44-8A18-35DA3F7038D9}.All|Win32.ActiveCfg = Release DLL|x64
+ {8D04B550-D240-4A44-8A18-35DA3F7038D9}.All|x64.ActiveCfg = Release DLL|x64
+ {8D04B550-D240-4A44-8A18-35DA3F7038D9}.All|x64.Build.0 = Release DLL|x64
+ {8D04B550-D240-4A44-8A18-35DA3F7038D9}.All|x64 Setup.ActiveCfg = Release DLL|x64
+ {8D04B550-D240-4A44-8A18-35DA3F7038D9}.All|x64 Setup.Build.0 = Release DLL|x64
+ {8D04B550-D240-4A44-8A18-35DA3F7038D9}.All|x86 Setup.ActiveCfg = Release DLL|x64
+ {8D04B550-D240-4A44-8A18-35DA3F7038D9}.Debug|Win32.ActiveCfg = Debug|Win32
+ {8D04B550-D240-4A44-8A18-35DA3F7038D9}.Debug|Win32.Build.0 = Debug|Win32
+ {8D04B550-D240-4A44-8A18-35DA3F7038D9}.Debug|x64.ActiveCfg = Debug|x64
+ {8D04B550-D240-4A44-8A18-35DA3F7038D9}.Debug|x64.Build.0 = Debug|x64
+ {8D04B550-D240-4A44-8A18-35DA3F7038D9}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {8D04B550-D240-4A44-8A18-35DA3F7038D9}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {8D04B550-D240-4A44-8A18-35DA3F7038D9}.Release|Win32.ActiveCfg = Release|Win32
+ {8D04B550-D240-4A44-8A18-35DA3F7038D9}.Release|Win32.Build.0 = Release|Win32
+ {8D04B550-D240-4A44-8A18-35DA3F7038D9}.Release|x64.ActiveCfg = Release|x64
+ {8D04B550-D240-4A44-8A18-35DA3F7038D9}.Release|x64.Build.0 = Release|x64
+ {8D04B550-D240-4A44-8A18-35DA3F7038D9}.Release|x64 Setup.ActiveCfg = Release|x64
+ {8D04B550-D240-4A44-8A18-35DA3F7038D9}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {1CED5987-A529-46DC-B30F-870D85FF9C94}.All|Win32.ActiveCfg = Release|x64
+ {1CED5987-A529-46DC-B30F-870D85FF9C94}.All|x64.ActiveCfg = Release|Win32
+ {1CED5987-A529-46DC-B30F-870D85FF9C94}.All|x64.Build.0 = Release|Win32
+ {1CED5987-A529-46DC-B30F-870D85FF9C94}.All|x64 Setup.ActiveCfg = Release|x64
+ {1CED5987-A529-46DC-B30F-870D85FF9C94}.All|x64 Setup.Build.0 = Release|x64
+ {1CED5987-A529-46DC-B30F-870D85FF9C94}.All|x86 Setup.ActiveCfg = Release|x64
+ {1CED5987-A529-46DC-B30F-870D85FF9C94}.Debug|Win32.ActiveCfg = Debug|Win32
+ {1CED5987-A529-46DC-B30F-870D85FF9C94}.Debug|Win32.Build.0 = Debug|Win32
+ {1CED5987-A529-46DC-B30F-870D85FF9C94}.Debug|x64.ActiveCfg = Debug|Win32
+ {1CED5987-A529-46DC-B30F-870D85FF9C94}.Debug|x64.Build.0 = Debug|Win32
+ {1CED5987-A529-46DC-B30F-870D85FF9C94}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {1CED5987-A529-46DC-B30F-870D85FF9C94}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {1CED5987-A529-46DC-B30F-870D85FF9C94}.Release|Win32.ActiveCfg = Release|Win32
+ {1CED5987-A529-46DC-B30F-870D85FF9C94}.Release|Win32.Build.0 = Release|Win32
+ {1CED5987-A529-46DC-B30F-870D85FF9C94}.Release|x64.ActiveCfg = Release|Win32
+ {1CED5987-A529-46DC-B30F-870D85FF9C94}.Release|x64.Build.0 = Release|Win32
+ {1CED5987-A529-46DC-B30F-870D85FF9C94}.Release|x64 Setup.ActiveCfg = Release|x64
+ {1CED5987-A529-46DC-B30F-870D85FF9C94}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}.All|Win32.ActiveCfg = Release|x64
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}.All|x64.ActiveCfg = Release|x64
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}.All|x64.Build.0 = Release|x64
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}.All|x64 Setup.ActiveCfg = Release|x64
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}.All|x64 Setup.Build.0 = Release|x64
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}.All|x86 Setup.ActiveCfg = Release|x64
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}.Debug|Win32.ActiveCfg = Debug|Win32
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}.Debug|Win32.Build.0 = Debug|Win32
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}.Debug|x64.ActiveCfg = Debug|x64
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}.Debug|x64.Build.0 = Debug|x64
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}.Release|Win32.ActiveCfg = Release|Win32
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}.Release|Win32.Build.0 = Release|Win32
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}.Release|x64.ActiveCfg = Release|x64
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}.Release|x64.Build.0 = Release|x64
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}.Release|x64 Setup.ActiveCfg = Release|x64
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {F057DA7F-79E5-4B00-845C-EF446EF055E3}.All|Win32.ActiveCfg = Release|x64
+ {F057DA7F-79E5-4B00-845C-EF446EF055E3}.All|x64.ActiveCfg = Release|x64
+ {F057DA7F-79E5-4B00-845C-EF446EF055E3}.All|x64.Build.0 = Release|x64
+ {F057DA7F-79E5-4B00-845C-EF446EF055E3}.All|x64 Setup.ActiveCfg = Release|x64
+ {F057DA7F-79E5-4B00-845C-EF446EF055E3}.All|x64 Setup.Build.0 = Release|x64
+ {F057DA7F-79E5-4B00-845C-EF446EF055E3}.All|x86 Setup.ActiveCfg = Release|x64
+ {F057DA7F-79E5-4B00-845C-EF446EF055E3}.Debug|Win32.ActiveCfg = Debug|Win32
+ {F057DA7F-79E5-4B00-845C-EF446EF055E3}.Debug|Win32.Build.0 = Debug|Win32
+ {F057DA7F-79E5-4B00-845C-EF446EF055E3}.Debug|x64.ActiveCfg = Debug|x64
+ {F057DA7F-79E5-4B00-845C-EF446EF055E3}.Debug|x64.Build.0 = Debug|x64
+ {F057DA7F-79E5-4B00-845C-EF446EF055E3}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {F057DA7F-79E5-4B00-845C-EF446EF055E3}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {F057DA7F-79E5-4B00-845C-EF446EF055E3}.Release|Win32.ActiveCfg = Release|Win32
+ {F057DA7F-79E5-4B00-845C-EF446EF055E3}.Release|Win32.Build.0 = Release|Win32
+ {F057DA7F-79E5-4B00-845C-EF446EF055E3}.Release|x64.ActiveCfg = Release|x64
+ {F057DA7F-79E5-4B00-845C-EF446EF055E3}.Release|x64.Build.0 = Release|x64
+ {F057DA7F-79E5-4B00-845C-EF446EF055E3}.Release|x64 Setup.ActiveCfg = Release|x64
+ {F057DA7F-79E5-4B00-845C-EF446EF055E3}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {E727E8F6-935D-46FE-8B0E-37834748A0E3}.All|Win32.ActiveCfg = Release|x64
+ {E727E8F6-935D-46FE-8B0E-37834748A0E3}.All|x64.ActiveCfg = Release|x64
+ {E727E8F6-935D-46FE-8B0E-37834748A0E3}.All|x64.Build.0 = Release|x64
+ {E727E8F6-935D-46FE-8B0E-37834748A0E3}.All|x64 Setup.ActiveCfg = Release|x64
+ {E727E8F6-935D-46FE-8B0E-37834748A0E3}.All|x64 Setup.Build.0 = Release|x64
+ {E727E8F6-935D-46FE-8B0E-37834748A0E3}.All|x86 Setup.ActiveCfg = Release|x64
+ {E727E8F6-935D-46FE-8B0E-37834748A0E3}.Debug|Win32.ActiveCfg = Debug|Win32
+ {E727E8F6-935D-46FE-8B0E-37834748A0E3}.Debug|Win32.Build.0 = Debug|Win32
+ {E727E8F6-935D-46FE-8B0E-37834748A0E3}.Debug|x64.ActiveCfg = Debug|x64
+ {E727E8F6-935D-46FE-8B0E-37834748A0E3}.Debug|x64.Build.0 = Debug|x64
+ {E727E8F6-935D-46FE-8B0E-37834748A0E3}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {E727E8F6-935D-46FE-8B0E-37834748A0E3}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {E727E8F6-935D-46FE-8B0E-37834748A0E3}.Release|Win32.ActiveCfg = Release|Win32
+ {E727E8F6-935D-46FE-8B0E-37834748A0E3}.Release|Win32.Build.0 = Release|Win32
+ {E727E8F6-935D-46FE-8B0E-37834748A0E3}.Release|x64.ActiveCfg = Release|x64
+ {E727E8F6-935D-46FE-8B0E-37834748A0E3}.Release|x64.Build.0 = Release|x64
+ {E727E8F6-935D-46FE-8B0E-37834748A0E3}.Release|x64 Setup.ActiveCfg = Release|x64
+ {E727E8F6-935D-46FE-8B0E-37834748A0E3}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {3D0370CA-BED2-4657-A475-32375CBCB6E4}.All|Win32.ActiveCfg = Release|x64
+ {3D0370CA-BED2-4657-A475-32375CBCB6E4}.All|x64.ActiveCfg = Release|x64
+ {3D0370CA-BED2-4657-A475-32375CBCB6E4}.All|x64.Build.0 = Release|x64
+ {3D0370CA-BED2-4657-A475-32375CBCB6E4}.All|x64 Setup.ActiveCfg = Release|x64
+ {3D0370CA-BED2-4657-A475-32375CBCB6E4}.All|x64 Setup.Build.0 = Release|x64
+ {3D0370CA-BED2-4657-A475-32375CBCB6E4}.All|x86 Setup.ActiveCfg = Release|x64
+ {3D0370CA-BED2-4657-A475-32375CBCB6E4}.Debug|Win32.ActiveCfg = Debug|Win32
+ {3D0370CA-BED2-4657-A475-32375CBCB6E4}.Debug|Win32.Build.0 = Debug|Win32
+ {3D0370CA-BED2-4657-A475-32375CBCB6E4}.Debug|x64.ActiveCfg = Debug|x64
+ {3D0370CA-BED2-4657-A475-32375CBCB6E4}.Debug|x64.Build.0 = Debug|x64
+ {3D0370CA-BED2-4657-A475-32375CBCB6E4}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {3D0370CA-BED2-4657-A475-32375CBCB6E4}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {3D0370CA-BED2-4657-A475-32375CBCB6E4}.Release|Win32.ActiveCfg = Release|Win32
+ {3D0370CA-BED2-4657-A475-32375CBCB6E4}.Release|Win32.Build.0 = Release|Win32
+ {3D0370CA-BED2-4657-A475-32375CBCB6E4}.Release|x64.ActiveCfg = Release|x64
+ {3D0370CA-BED2-4657-A475-32375CBCB6E4}.Release|x64.Build.0 = Release|x64
+ {3D0370CA-BED2-4657-A475-32375CBCB6E4}.Release|x64 Setup.ActiveCfg = Release|x64
+ {3D0370CA-BED2-4657-A475-32375CBCB6E4}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {87EE9DA4-DE1E-4448-8324-183C98DCA588}.All|Win32.ActiveCfg = Debug|x64
+ {87EE9DA4-DE1E-4448-8324-183C98DCA588}.All|x64.ActiveCfg = Debug|x64
+ {87EE9DA4-DE1E-4448-8324-183C98DCA588}.All|x64.Build.0 = Debug|x64
+ {87EE9DA4-DE1E-4448-8324-183C98DCA588}.All|x64 Setup.ActiveCfg = Debug|x64
+ {87EE9DA4-DE1E-4448-8324-183C98DCA588}.All|x64 Setup.Build.0 = Debug|x64
+ {87EE9DA4-DE1E-4448-8324-183C98DCA588}.All|x86 Setup.ActiveCfg = Debug|x64
+ {87EE9DA4-DE1E-4448-8324-183C98DCA588}.Debug|Win32.ActiveCfg = Debug|Win32
+ {87EE9DA4-DE1E-4448-8324-183C98DCA588}.Debug|Win32.Build.0 = Debug|Win32
+ {87EE9DA4-DE1E-4448-8324-183C98DCA588}.Debug|x64.ActiveCfg = Debug|x64
+ {87EE9DA4-DE1E-4448-8324-183C98DCA588}.Debug|x64.Build.0 = Debug|x64
+ {87EE9DA4-DE1E-4448-8324-183C98DCA588}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {87EE9DA4-DE1E-4448-8324-183C98DCA588}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {87EE9DA4-DE1E-4448-8324-183C98DCA588}.Release|Win32.ActiveCfg = Release|Win32
+ {87EE9DA4-DE1E-4448-8324-183C98DCA588}.Release|Win32.Build.0 = Release|Win32
+ {87EE9DA4-DE1E-4448-8324-183C98DCA588}.Release|x64.ActiveCfg = Release|x64
+ {87EE9DA4-DE1E-4448-8324-183C98DCA588}.Release|x64.Build.0 = Release|x64
+ {87EE9DA4-DE1E-4448-8324-183C98DCA588}.Release|x64 Setup.ActiveCfg = Release|x64
+ {87EE9DA4-DE1E-4448-8324-183C98DCA588}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {155844C3-EC5F-407F-97A4-A2DDADED9B2F}.All|Win32.ActiveCfg = Debug|x64
+ {155844C3-EC5F-407F-97A4-A2DDADED9B2F}.All|x64.ActiveCfg = Debug|x64
+ {155844C3-EC5F-407F-97A4-A2DDADED9B2F}.All|x64.Build.0 = Debug|x64
+ {155844C3-EC5F-407F-97A4-A2DDADED9B2F}.All|x64 Setup.ActiveCfg = Debug|x64
+ {155844C3-EC5F-407F-97A4-A2DDADED9B2F}.All|x64 Setup.Build.0 = Debug|x64
+ {155844C3-EC5F-407F-97A4-A2DDADED9B2F}.All|x86 Setup.ActiveCfg = Debug|x64
+ {155844C3-EC5F-407F-97A4-A2DDADED9B2F}.Debug|Win32.ActiveCfg = Debug|Win32
+ {155844C3-EC5F-407F-97A4-A2DDADED9B2F}.Debug|Win32.Build.0 = Debug|Win32
+ {155844C3-EC5F-407F-97A4-A2DDADED9B2F}.Debug|x64.ActiveCfg = Debug|x64
+ {155844C3-EC5F-407F-97A4-A2DDADED9B2F}.Debug|x64.Build.0 = Debug|x64
+ {155844C3-EC5F-407F-97A4-A2DDADED9B2F}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {155844C3-EC5F-407F-97A4-A2DDADED9B2F}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {155844C3-EC5F-407F-97A4-A2DDADED9B2F}.Release|Win32.ActiveCfg = Release|Win32
+ {155844C3-EC5F-407F-97A4-A2DDADED9B2F}.Release|Win32.Build.0 = Release|Win32
+ {155844C3-EC5F-407F-97A4-A2DDADED9B2F}.Release|x64.ActiveCfg = Release|x64
+ {155844C3-EC5F-407F-97A4-A2DDADED9B2F}.Release|x64.Build.0 = Release|x64
+ {155844C3-EC5F-407F-97A4-A2DDADED9B2F}.Release|x64 Setup.ActiveCfg = Release|x64
+ {155844C3-EC5F-407F-97A4-A2DDADED9B2F}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {204FA0DE-305D-4414-AE2E-F195A23F390D}.All|Win32.ActiveCfg = Debug|x64
+ {204FA0DE-305D-4414-AE2E-F195A23F390D}.All|x64.ActiveCfg = Debug|x64
+ {204FA0DE-305D-4414-AE2E-F195A23F390D}.All|x64.Build.0 = Debug|x64
+ {204FA0DE-305D-4414-AE2E-F195A23F390D}.All|x64 Setup.ActiveCfg = Debug|x64
+ {204FA0DE-305D-4414-AE2E-F195A23F390D}.All|x64 Setup.Build.0 = Debug|x64
+ {204FA0DE-305D-4414-AE2E-F195A23F390D}.All|x86 Setup.ActiveCfg = Debug|x64
+ {204FA0DE-305D-4414-AE2E-F195A23F390D}.Debug|Win32.ActiveCfg = Debug|Win32
+ {204FA0DE-305D-4414-AE2E-F195A23F390D}.Debug|Win32.Build.0 = Debug|Win32
+ {204FA0DE-305D-4414-AE2E-F195A23F390D}.Debug|x64.ActiveCfg = Debug|x64
+ {204FA0DE-305D-4414-AE2E-F195A23F390D}.Debug|x64.Build.0 = Debug|x64
+ {204FA0DE-305D-4414-AE2E-F195A23F390D}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {204FA0DE-305D-4414-AE2E-F195A23F390D}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {204FA0DE-305D-4414-AE2E-F195A23F390D}.Release|Win32.ActiveCfg = Release|Win32
+ {204FA0DE-305D-4414-AE2E-F195A23F390D}.Release|Win32.Build.0 = Release|Win32
+ {204FA0DE-305D-4414-AE2E-F195A23F390D}.Release|x64.ActiveCfg = Release|x64
+ {204FA0DE-305D-4414-AE2E-F195A23F390D}.Release|x64.Build.0 = Release|x64
+ {204FA0DE-305D-4414-AE2E-F195A23F390D}.Release|x64 Setup.ActiveCfg = Release|x64
+ {204FA0DE-305D-4414-AE2E-F195A23F390D}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {0DF3ABD0-DDC0-4265-B778-07C66780979B}.All|Win32.ActiveCfg = Release|x64
+ {0DF3ABD0-DDC0-4265-B778-07C66780979B}.All|x64.ActiveCfg = Release|x64
+ {0DF3ABD0-DDC0-4265-B778-07C66780979B}.All|x64.Build.0 = Release|x64
+ {0DF3ABD0-DDC0-4265-B778-07C66780979B}.All|x64 Setup.ActiveCfg = Release|x64
+ {0DF3ABD0-DDC0-4265-B778-07C66780979B}.All|x64 Setup.Build.0 = Release|x64
+ {0DF3ABD0-DDC0-4265-B778-07C66780979B}.All|x86 Setup.ActiveCfg = Release|x64
+ {0DF3ABD0-DDC0-4265-B778-07C66780979B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {0DF3ABD0-DDC0-4265-B778-07C66780979B}.Debug|Win32.Build.0 = Debug|Win32
+ {0DF3ABD0-DDC0-4265-B778-07C66780979B}.Debug|x64.ActiveCfg = Debug|x64
+ {0DF3ABD0-DDC0-4265-B778-07C66780979B}.Debug|x64.Build.0 = Debug|x64
+ {0DF3ABD0-DDC0-4265-B778-07C66780979B}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {0DF3ABD0-DDC0-4265-B778-07C66780979B}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {0DF3ABD0-DDC0-4265-B778-07C66780979B}.Release|Win32.ActiveCfg = Release|Win32
+ {0DF3ABD0-DDC0-4265-B778-07C66780979B}.Release|Win32.Build.0 = Release|Win32
+ {0DF3ABD0-DDC0-4265-B778-07C66780979B}.Release|x64.ActiveCfg = Release|x64
+ {0DF3ABD0-DDC0-4265-B778-07C66780979B}.Release|x64.Build.0 = Release|x64
+ {0DF3ABD0-DDC0-4265-B778-07C66780979B}.Release|x64 Setup.ActiveCfg = Release|x64
+ {0DF3ABD0-DDC0-4265-B778-07C66780979B}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}.All|Win32.ActiveCfg = Release|Win32
+ {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}.All|Win32.Build.0 = Release|Win32
+ {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}.All|x64.ActiveCfg = Release|Win32
+ {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}.All|x64.Build.0 = Release|Win32
+ {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}.All|x64 Setup.ActiveCfg = Release|Win32
+ {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}.All|x64 Setup.Build.0 = Release|Win32
+ {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}.All|x86 Setup.ActiveCfg = Release|Win32
+ {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}.All|x86 Setup.Build.0 = Release|Win32
+ {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}.Debug|Win32.ActiveCfg = Debug|Win32
+ {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}.Debug|Win32.Build.0 = Debug|Win32
+ {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}.Debug|x64.ActiveCfg = Debug|Win32
+ {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}.Debug|x64.Build.0 = Debug|Win32
+ {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}.Debug|x64 Setup.ActiveCfg = Debug|Win32
+ {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}.Release|Win32.ActiveCfg = Release|Win32
+ {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}.Release|Win32.Build.0 = Release|Win32
+ {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}.Release|x64.ActiveCfg = Release|Win32
+ {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}.Release|x64.Build.0 = Release|Win32
+ {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}.Release|x64 Setup.ActiveCfg = Release|Win32
+ {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}.All|Win32.ActiveCfg = Release DLL|x64
+ {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}.All|x64.ActiveCfg = Release DLL|x64
+ {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}.All|x64.Build.0 = Release DLL|x64
+ {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}.All|x64 Setup.ActiveCfg = Release DLL|x64
+ {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}.All|x64 Setup.Build.0 = Release DLL|x64
+ {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}.All|x86 Setup.ActiveCfg = Release DLL|x64
+ {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}.Debug|Win32.ActiveCfg = Debug DLL|Win32
+ {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}.Debug|Win32.Build.0 = Debug DLL|Win32
+ {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}.Debug|x64.ActiveCfg = Debug DLL|x64
+ {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}.Debug|x64.Build.0 = Debug DLL|x64
+ {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}.Debug|x64 Setup.ActiveCfg = Debug DLL|x64
+ {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}.Debug|x86 Setup.ActiveCfg = Debug DLL|Win32
+ {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}.Release|Win32.ActiveCfg = Release DLL|Win32
+ {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}.Release|Win32.Build.0 = Release DLL|Win32
+ {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}.Release|x64.ActiveCfg = Release DLL|x64
+ {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}.Release|x64.Build.0 = Release DLL|x64
+ {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}.Release|x64 Setup.ActiveCfg = Release DLL|x64
+ {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4}.Release|x86 Setup.ActiveCfg = Release DLL|Win32
+ {FEA1EEF7-876F-48DE-88BF-C0E3E606D758}.All|Win32.ActiveCfg = Release Passthrough|x64
+ {FEA1EEF7-876F-48DE-88BF-C0E3E606D758}.All|x64.ActiveCfg = Release Passthrough|x64
+ {FEA1EEF7-876F-48DE-88BF-C0E3E606D758}.All|x64.Build.0 = Release Passthrough|x64
+ {FEA1EEF7-876F-48DE-88BF-C0E3E606D758}.All|x64 Setup.ActiveCfg = Release Passthrough|x64
+ {FEA1EEF7-876F-48DE-88BF-C0E3E606D758}.All|x64 Setup.Build.0 = Release Passthrough|x64
+ {FEA1EEF7-876F-48DE-88BF-C0E3E606D758}.All|x86 Setup.ActiveCfg = Release Passthrough|x64
+ {FEA1EEF7-876F-48DE-88BF-C0E3E606D758}.Debug|Win32.ActiveCfg = Debug Passthrough|Win32
+ {FEA1EEF7-876F-48DE-88BF-C0E3E606D758}.Debug|Win32.Build.0 = Debug Passthrough|Win32
+ {FEA1EEF7-876F-48DE-88BF-C0E3E606D758}.Debug|x64.ActiveCfg = Debug Passthrough|x64
+ {FEA1EEF7-876F-48DE-88BF-C0E3E606D758}.Debug|x64.Build.0 = Debug Passthrough|x64
+ {FEA1EEF7-876F-48DE-88BF-C0E3E606D758}.Debug|x64 Setup.ActiveCfg = Debug Passthrough|x64
+ {FEA1EEF7-876F-48DE-88BF-C0E3E606D758}.Debug|x86 Setup.ActiveCfg = Debug Passthrough|Win32
+ {FEA1EEF7-876F-48DE-88BF-C0E3E606D758}.Release|Win32.ActiveCfg = Release Passthrough|Win32
+ {FEA1EEF7-876F-48DE-88BF-C0E3E606D758}.Release|Win32.Build.0 = Release Passthrough|Win32
+ {FEA1EEF7-876F-48DE-88BF-C0E3E606D758}.Release|x64.ActiveCfg = Release Passthrough|x64
+ {FEA1EEF7-876F-48DE-88BF-C0E3E606D758}.Release|x64.Build.0 = Release Passthrough|x64
+ {FEA1EEF7-876F-48DE-88BF-C0E3E606D758}.Release|x64 Setup.ActiveCfg = Release Passthrough|x64
+ {FEA1EEF7-876F-48DE-88BF-C0E3E606D758}.Release|x86 Setup.ActiveCfg = Release Passthrough|Win32
+ {7F1610F1-DD5A-4CF7-8610-30AB12C60ADD}.All|Win32.ActiveCfg = Release|x64
+ {7F1610F1-DD5A-4CF7-8610-30AB12C60ADD}.All|x64.ActiveCfg = Release|x64
+ {7F1610F1-DD5A-4CF7-8610-30AB12C60ADD}.All|x64.Build.0 = Release|x64
+ {7F1610F1-DD5A-4CF7-8610-30AB12C60ADD}.All|x64 Setup.ActiveCfg = Release|x64
+ {7F1610F1-DD5A-4CF7-8610-30AB12C60ADD}.All|x64 Setup.Build.0 = Release|x64
+ {7F1610F1-DD5A-4CF7-8610-30AB12C60ADD}.All|x86 Setup.ActiveCfg = Release|x64
+ {7F1610F1-DD5A-4CF7-8610-30AB12C60ADD}.Debug|Win32.ActiveCfg = Debug|Win32
+ {7F1610F1-DD5A-4CF7-8610-30AB12C60ADD}.Debug|Win32.Build.0 = Debug|Win32
+ {7F1610F1-DD5A-4CF7-8610-30AB12C60ADD}.Debug|x64.ActiveCfg = Debug|x64
+ {7F1610F1-DD5A-4CF7-8610-30AB12C60ADD}.Debug|x64.Build.0 = Debug|x64
+ {7F1610F1-DD5A-4CF7-8610-30AB12C60ADD}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {7F1610F1-DD5A-4CF7-8610-30AB12C60ADD}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {7F1610F1-DD5A-4CF7-8610-30AB12C60ADD}.Release|Win32.ActiveCfg = Release|Win32
+ {7F1610F1-DD5A-4CF7-8610-30AB12C60ADD}.Release|Win32.Build.0 = Release|Win32
+ {7F1610F1-DD5A-4CF7-8610-30AB12C60ADD}.Release|x64.ActiveCfg = Release|x64
+ {7F1610F1-DD5A-4CF7-8610-30AB12C60ADD}.Release|x64.Build.0 = Release|x64
+ {7F1610F1-DD5A-4CF7-8610-30AB12C60ADD}.Release|x64 Setup.ActiveCfg = Release|x64
+ {7F1610F1-DD5A-4CF7-8610-30AB12C60ADD}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {9254C4B0-6F60-42B6-BB3A-36D63FC001C7}.All|Win32.ActiveCfg = Release|x64
+ {9254C4B0-6F60-42B6-BB3A-36D63FC001C7}.All|x64.ActiveCfg = Release|x64
+ {9254C4B0-6F60-42B6-BB3A-36D63FC001C7}.All|x64.Build.0 = Release|x64
+ {9254C4B0-6F60-42B6-BB3A-36D63FC001C7}.All|x64 Setup.ActiveCfg = Release|x64
+ {9254C4B0-6F60-42B6-BB3A-36D63FC001C7}.All|x64 Setup.Build.0 = Release|x64
+ {9254C4B0-6F60-42B6-BB3A-36D63FC001C7}.All|x86 Setup.ActiveCfg = Release|x64
+ {9254C4B0-6F60-42B6-BB3A-36D63FC001C7}.Debug|Win32.ActiveCfg = Debug|Win32
+ {9254C4B0-6F60-42B6-BB3A-36D63FC001C7}.Debug|Win32.Build.0 = Debug|Win32
+ {9254C4B0-6F60-42B6-BB3A-36D63FC001C7}.Debug|x64.ActiveCfg = Debug|x64
+ {9254C4B0-6F60-42B6-BB3A-36D63FC001C7}.Debug|x64.Build.0 = Debug|x64
+ {9254C4B0-6F60-42B6-BB3A-36D63FC001C7}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {9254C4B0-6F60-42B6-BB3A-36D63FC001C7}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {9254C4B0-6F60-42B6-BB3A-36D63FC001C7}.Release|Win32.ActiveCfg = Release|Win32
+ {9254C4B0-6F60-42B6-BB3A-36D63FC001C7}.Release|Win32.Build.0 = Release|Win32
+ {9254C4B0-6F60-42B6-BB3A-36D63FC001C7}.Release|x64.ActiveCfg = Release|x64
+ {9254C4B0-6F60-42B6-BB3A-36D63FC001C7}.Release|x64.Build.0 = Release|x64
+ {9254C4B0-6F60-42B6-BB3A-36D63FC001C7}.Release|x64 Setup.ActiveCfg = Release|x64
+ {9254C4B0-6F60-42B6-BB3A-36D63FC001C7}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {ACFFF684-4D19-4D48-AF12-88EA1D778BDF}.All|Win32.ActiveCfg = Release|x64
+ {ACFFF684-4D19-4D48-AF12-88EA1D778BDF}.All|x64.ActiveCfg = Release|x64
+ {ACFFF684-4D19-4D48-AF12-88EA1D778BDF}.All|x64.Build.0 = Release|x64
+ {ACFFF684-4D19-4D48-AF12-88EA1D778BDF}.All|x64 Setup.ActiveCfg = Release|x64
+ {ACFFF684-4D19-4D48-AF12-88EA1D778BDF}.All|x64 Setup.Build.0 = Release|x64
+ {ACFFF684-4D19-4D48-AF12-88EA1D778BDF}.All|x86 Setup.ActiveCfg = Release|x64
+ {ACFFF684-4D19-4D48-AF12-88EA1D778BDF}.Debug|Win32.ActiveCfg = Debug|Win32
+ {ACFFF684-4D19-4D48-AF12-88EA1D778BDF}.Debug|Win32.Build.0 = Debug|Win32
+ {ACFFF684-4D19-4D48-AF12-88EA1D778BDF}.Debug|x64.ActiveCfg = Debug|x64
+ {ACFFF684-4D19-4D48-AF12-88EA1D778BDF}.Debug|x64.Build.0 = Debug|x64
+ {ACFFF684-4D19-4D48-AF12-88EA1D778BDF}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {ACFFF684-4D19-4D48-AF12-88EA1D778BDF}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {ACFFF684-4D19-4D48-AF12-88EA1D778BDF}.Release|Win32.ActiveCfg = Release|Win32
+ {ACFFF684-4D19-4D48-AF12-88EA1D778BDF}.Release|Win32.Build.0 = Release|Win32
+ {ACFFF684-4D19-4D48-AF12-88EA1D778BDF}.Release|x64.ActiveCfg = Release|x64
+ {ACFFF684-4D19-4D48-AF12-88EA1D778BDF}.Release|x64.Build.0 = Release|x64
+ {ACFFF684-4D19-4D48-AF12-88EA1D778BDF}.Release|x64 Setup.ActiveCfg = Release|x64
+ {ACFFF684-4D19-4D48-AF12-88EA1D778BDF}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {8F992C49-6C51-412F-B2A3-34EAB708EB65}.All|Win32.ActiveCfg = Release|x64
+ {8F992C49-6C51-412F-B2A3-34EAB708EB65}.All|x64.ActiveCfg = Release|x64
+ {8F992C49-6C51-412F-B2A3-34EAB708EB65}.All|x64.Build.0 = Release|x64
+ {8F992C49-6C51-412F-B2A3-34EAB708EB65}.All|x64 Setup.ActiveCfg = Release|x64
+ {8F992C49-6C51-412F-B2A3-34EAB708EB65}.All|x64 Setup.Build.0 = Release|x64
+ {8F992C49-6C51-412F-B2A3-34EAB708EB65}.All|x86 Setup.ActiveCfg = Release|x64
+ {8F992C49-6C51-412F-B2A3-34EAB708EB65}.Debug|Win32.ActiveCfg = Debug|Win32
+ {8F992C49-6C51-412F-B2A3-34EAB708EB65}.Debug|Win32.Build.0 = Debug|Win32
+ {8F992C49-6C51-412F-B2A3-34EAB708EB65}.Debug|x64.ActiveCfg = Debug|x64
+ {8F992C49-6C51-412F-B2A3-34EAB708EB65}.Debug|x64.Build.0 = Debug|x64
+ {8F992C49-6C51-412F-B2A3-34EAB708EB65}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {8F992C49-6C51-412F-B2A3-34EAB708EB65}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {8F992C49-6C51-412F-B2A3-34EAB708EB65}.Release|Win32.ActiveCfg = Release|Win32
+ {8F992C49-6C51-412F-B2A3-34EAB708EB65}.Release|Win32.Build.0 = Release|Win32
+ {8F992C49-6C51-412F-B2A3-34EAB708EB65}.Release|x64.ActiveCfg = Release|x64
+ {8F992C49-6C51-412F-B2A3-34EAB708EB65}.Release|x64.Build.0 = Release|x64
+ {8F992C49-6C51-412F-B2A3-34EAB708EB65}.Release|x64 Setup.ActiveCfg = Release|x64
+ {8F992C49-6C51-412F-B2A3-34EAB708EB65}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {4043FC6A-9A30-4577-8AD5-9B233C9575D8}.All|Win32.ActiveCfg = Release|x64
+ {4043FC6A-9A30-4577-8AD5-9B233C9575D8}.All|x64.ActiveCfg = Release|x64
+ {4043FC6A-9A30-4577-8AD5-9B233C9575D8}.All|x64.Build.0 = Release|x64
+ {4043FC6A-9A30-4577-8AD5-9B233C9575D8}.All|x64 Setup.ActiveCfg = Release|x64
+ {4043FC6A-9A30-4577-8AD5-9B233C9575D8}.All|x64 Setup.Build.0 = Release|x64
+ {4043FC6A-9A30-4577-8AD5-9B233C9575D8}.All|x86 Setup.ActiveCfg = Release|x64
+ {4043FC6A-9A30-4577-8AD5-9B233C9575D8}.Debug|Win32.ActiveCfg = Debug|Win32
+ {4043FC6A-9A30-4577-8AD5-9B233C9575D8}.Debug|x64.ActiveCfg = Debug|x64
+ {4043FC6A-9A30-4577-8AD5-9B233C9575D8}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {4043FC6A-9A30-4577-8AD5-9B233C9575D8}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {4043FC6A-9A30-4577-8AD5-9B233C9575D8}.Release|Win32.ActiveCfg = Release|Win32
+ {4043FC6A-9A30-4577-8AD5-9B233C9575D8}.Release|x64.ActiveCfg = Release|x64
+ {4043FC6A-9A30-4577-8AD5-9B233C9575D8}.Release|x64 Setup.ActiveCfg = Release|x64
+ {4043FC6A-9A30-4577-8AD5-9B233C9575D8}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {71A967D5-0E99-4CEF-A587-98836EE6F2EF}.All|Win32.ActiveCfg = Release|x64
+ {71A967D5-0E99-4CEF-A587-98836EE6F2EF}.All|x64.ActiveCfg = Release|x64
+ {71A967D5-0E99-4CEF-A587-98836EE6F2EF}.All|x64.Build.0 = Release|x64
+ {71A967D5-0E99-4CEF-A587-98836EE6F2EF}.All|x64 Setup.ActiveCfg = Release|x64
+ {71A967D5-0E99-4CEF-A587-98836EE6F2EF}.All|x64 Setup.Build.0 = Release|x64
+ {71A967D5-0E99-4CEF-A587-98836EE6F2EF}.All|x86 Setup.ActiveCfg = Release|x64
+ {71A967D5-0E99-4CEF-A587-98836EE6F2EF}.Debug|Win32.ActiveCfg = Debug|Win32
+ {71A967D5-0E99-4CEF-A587-98836EE6F2EF}.Debug|Win32.Build.0 = Debug|Win32
+ {71A967D5-0E99-4CEF-A587-98836EE6F2EF}.Debug|x64.ActiveCfg = Debug|x64
+ {71A967D5-0E99-4CEF-A587-98836EE6F2EF}.Debug|x64.Build.0 = Debug|x64
+ {71A967D5-0E99-4CEF-A587-98836EE6F2EF}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {71A967D5-0E99-4CEF-A587-98836EE6F2EF}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {71A967D5-0E99-4CEF-A587-98836EE6F2EF}.Release|Win32.ActiveCfg = Release|Win32
+ {71A967D5-0E99-4CEF-A587-98836EE6F2EF}.Release|Win32.Build.0 = Release|Win32
+ {71A967D5-0E99-4CEF-A587-98836EE6F2EF}.Release|x64.ActiveCfg = Release|x64
+ {71A967D5-0E99-4CEF-A587-98836EE6F2EF}.Release|x64.Build.0 = Release|x64
+ {71A967D5-0E99-4CEF-A587-98836EE6F2EF}.Release|x64 Setup.ActiveCfg = Release|x64
+ {71A967D5-0E99-4CEF-A587-98836EE6F2EF}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}.All|Win32.ActiveCfg = Release|x64
+ {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}.All|x64.ActiveCfg = Release|x64
+ {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}.All|x64.Build.0 = Release|x64
+ {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}.All|x64 Setup.ActiveCfg = Release|x64
+ {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}.All|x64 Setup.Build.0 = Release|x64
+ {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}.All|x86 Setup.ActiveCfg = Release|x64
+ {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}.Debug|Win32.ActiveCfg = Debug|Win32
+ {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}.Debug|Win32.Build.0 = Debug|Win32
+ {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}.Debug|x64.ActiveCfg = Debug|x64
+ {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}.Debug|x64.Build.0 = Debug|x64
+ {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}.Release|Win32.ActiveCfg = Release|Win32
+ {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}.Release|Win32.Build.0 = Release|Win32
+ {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}.Release|x64.ActiveCfg = Release|x64
+ {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}.Release|x64.Build.0 = Release|x64
+ {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}.Release|x64 Setup.ActiveCfg = Release|x64
+ {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {AB91A099-7690-4ECF-8994-E458F4EA1ED4}.All|Win32.ActiveCfg = Release|x64
+ {AB91A099-7690-4ECF-8994-E458F4EA1ED4}.All|x64.ActiveCfg = Release|x64
+ {AB91A099-7690-4ECF-8994-E458F4EA1ED4}.All|x64.Build.0 = Release|x64
+ {AB91A099-7690-4ECF-8994-E458F4EA1ED4}.All|x64 Setup.ActiveCfg = Release|x64
+ {AB91A099-7690-4ECF-8994-E458F4EA1ED4}.All|x64 Setup.Build.0 = Release|x64
+ {AB91A099-7690-4ECF-8994-E458F4EA1ED4}.All|x86 Setup.ActiveCfg = Release|x64
+ {AB91A099-7690-4ECF-8994-E458F4EA1ED4}.Debug|Win32.ActiveCfg = Debug|Win32
+ {AB91A099-7690-4ECF-8994-E458F4EA1ED4}.Debug|Win32.Build.0 = Debug|Win32
+ {AB91A099-7690-4ECF-8994-E458F4EA1ED4}.Debug|x64.ActiveCfg = Debug|x64
+ {AB91A099-7690-4ECF-8994-E458F4EA1ED4}.Debug|x64.Build.0 = Debug|x64
+ {AB91A099-7690-4ECF-8994-E458F4EA1ED4}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {AB91A099-7690-4ECF-8994-E458F4EA1ED4}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {AB91A099-7690-4ECF-8994-E458F4EA1ED4}.Release|Win32.ActiveCfg = Release|Win32
+ {AB91A099-7690-4ECF-8994-E458F4EA1ED4}.Release|Win32.Build.0 = Release|Win32
+ {AB91A099-7690-4ECF-8994-E458F4EA1ED4}.Release|x64.ActiveCfg = Release|x64
+ {AB91A099-7690-4ECF-8994-E458F4EA1ED4}.Release|x64.Build.0 = Release|x64
+ {AB91A099-7690-4ECF-8994-E458F4EA1ED4}.Release|x64 Setup.ActiveCfg = Release|x64
+ {AB91A099-7690-4ECF-8994-E458F4EA1ED4}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {988CACF7-3FCB-4992-BE69-77872AE67DC8}.All|Win32.ActiveCfg = Release|x64
+ {988CACF7-3FCB-4992-BE69-77872AE67DC8}.All|x64.ActiveCfg = Release|x64
+ {988CACF7-3FCB-4992-BE69-77872AE67DC8}.All|x64.Build.0 = Release|x64
+ {988CACF7-3FCB-4992-BE69-77872AE67DC8}.All|x64 Setup.ActiveCfg = Release|x64
+ {988CACF7-3FCB-4992-BE69-77872AE67DC8}.All|x64 Setup.Build.0 = Release|x64
+ {988CACF7-3FCB-4992-BE69-77872AE67DC8}.All|x86 Setup.ActiveCfg = Release|x64
+ {988CACF7-3FCB-4992-BE69-77872AE67DC8}.Debug|Win32.ActiveCfg = Debug|Win32
+ {988CACF7-3FCB-4992-BE69-77872AE67DC8}.Debug|Win32.Build.0 = Debug|Win32
+ {988CACF7-3FCB-4992-BE69-77872AE67DC8}.Debug|x64.ActiveCfg = Debug|x64
+ {988CACF7-3FCB-4992-BE69-77872AE67DC8}.Debug|x64.Build.0 = Debug|x64
+ {988CACF7-3FCB-4992-BE69-77872AE67DC8}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {988CACF7-3FCB-4992-BE69-77872AE67DC8}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {988CACF7-3FCB-4992-BE69-77872AE67DC8}.Release|Win32.ActiveCfg = Release|Win32
+ {988CACF7-3FCB-4992-BE69-77872AE67DC8}.Release|Win32.Build.0 = Release|Win32
+ {988CACF7-3FCB-4992-BE69-77872AE67DC8}.Release|x64.ActiveCfg = Release|x64
+ {988CACF7-3FCB-4992-BE69-77872AE67DC8}.Release|x64.Build.0 = Release|x64
+ {988CACF7-3FCB-4992-BE69-77872AE67DC8}.Release|x64 Setup.ActiveCfg = Release|x64
+ {988CACF7-3FCB-4992-BE69-77872AE67DC8}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {0A18A071-125E-442F-AFF7-A3F68ABECF99}.All|Win32.ActiveCfg = Release DirectSound|x64
+ {0A18A071-125E-442F-AFF7-A3F68ABECF99}.All|x64.ActiveCfg = Release DirectSound|x64
+ {0A18A071-125E-442F-AFF7-A3F68ABECF99}.All|x64.Build.0 = Release DirectSound|x64
+ {0A18A071-125E-442F-AFF7-A3F68ABECF99}.All|x64 Setup.ActiveCfg = Release DirectSound|x64
+ {0A18A071-125E-442F-AFF7-A3F68ABECF99}.All|x64 Setup.Build.0 = Release DirectSound|x64
+ {0A18A071-125E-442F-AFF7-A3F68ABECF99}.All|x86 Setup.ActiveCfg = Release DirectSound|x64
+ {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Debug|Win32.ActiveCfg = Debug DirectSound|Win32
+ {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Debug|Win32.Build.0 = Debug DirectSound|Win32
+ {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Debug|x64.ActiveCfg = Debug DirectSound|x64
+ {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Debug|x64.Build.0 = Debug DirectSound|x64
+ {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Debug|x64 Setup.ActiveCfg = Debug DirectSound|x64
+ {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Debug|x86 Setup.ActiveCfg = Debug DirectSound|Win32
+ {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Release|Win32.ActiveCfg = Release DirectSound|Win32
+ {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Release|Win32.Build.0 = Release DirectSound|Win32
+ {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Release|x64.ActiveCfg = Release DirectSound|x64
+ {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Release|x64.Build.0 = Release DirectSound|x64
+ {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Release|x64 Setup.ActiveCfg = Release DirectSound|x64
+ {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Release|x86 Setup.ActiveCfg = Release DirectSound|Win32
+ {08DAD348-9E0A-4A2E-97F1-F1E7E24A7836}.All|Win32.ActiveCfg = Release|x64
+ {08DAD348-9E0A-4A2E-97F1-F1E7E24A7836}.All|x64.ActiveCfg = Release|x64
+ {08DAD348-9E0A-4A2E-97F1-F1E7E24A7836}.All|x64.Build.0 = Release|x64
+ {08DAD348-9E0A-4A2E-97F1-F1E7E24A7836}.All|x64 Setup.ActiveCfg = Release|x64
+ {08DAD348-9E0A-4A2E-97F1-F1E7E24A7836}.All|x64 Setup.Build.0 = Release|x64
+ {08DAD348-9E0A-4A2E-97F1-F1E7E24A7836}.All|x86 Setup.ActiveCfg = Release|x64
+ {08DAD348-9E0A-4A2E-97F1-F1E7E24A7836}.Debug|Win32.ActiveCfg = Debug|Win32
+ {08DAD348-9E0A-4A2E-97F1-F1E7E24A7836}.Debug|Win32.Build.0 = Debug|Win32
+ {08DAD348-9E0A-4A2E-97F1-F1E7E24A7836}.Debug|x64.ActiveCfg = Debug|x64
+ {08DAD348-9E0A-4A2E-97F1-F1E7E24A7836}.Debug|x64.Build.0 = Debug|x64
+ {08DAD348-9E0A-4A2E-97F1-F1E7E24A7836}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {08DAD348-9E0A-4A2E-97F1-F1E7E24A7836}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {08DAD348-9E0A-4A2E-97F1-F1E7E24A7836}.Release|Win32.ActiveCfg = Release|Win32
+ {08DAD348-9E0A-4A2E-97F1-F1E7E24A7836}.Release|Win32.Build.0 = Release|Win32
+ {08DAD348-9E0A-4A2E-97F1-F1E7E24A7836}.Release|x64.ActiveCfg = Release|x64
+ {08DAD348-9E0A-4A2E-97F1-F1E7E24A7836}.Release|x64.Build.0 = Release|x64
+ {08DAD348-9E0A-4A2E-97F1-F1E7E24A7836}.Release|x64 Setup.ActiveCfg = Release|x64
+ {08DAD348-9E0A-4A2E-97F1-F1E7E24A7836}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {8DEB383C-4091-4F42-A56F-C9E46D552D79}.All|Win32.ActiveCfg = Release Passthrough|x64
+ {8DEB383C-4091-4F42-A56F-C9E46D552D79}.All|x64.ActiveCfg = Release Passthrough|x64
+ {8DEB383C-4091-4F42-A56F-C9E46D552D79}.All|x64.Build.0 = Release Passthrough|x64
+ {8DEB383C-4091-4F42-A56F-C9E46D552D79}.All|x64 Setup.ActiveCfg = Release Passthrough|x64
+ {8DEB383C-4091-4F42-A56F-C9E46D552D79}.All|x64 Setup.Build.0 = Release Passthrough|x64
+ {8DEB383C-4091-4F42-A56F-C9E46D552D79}.All|x86 Setup.ActiveCfg = Release Passthrough|x64
+ {8DEB383C-4091-4F42-A56F-C9E46D552D79}.Debug|Win32.ActiveCfg = Debug Passthrough|Win32
+ {8DEB383C-4091-4F42-A56F-C9E46D552D79}.Debug|Win32.Build.0 = Debug Passthrough|Win32
+ {8DEB383C-4091-4F42-A56F-C9E46D552D79}.Debug|x64.ActiveCfg = Debug Passthrough|x64
+ {8DEB383C-4091-4F42-A56F-C9E46D552D79}.Debug|x64.Build.0 = Debug Passthrough|x64
+ {8DEB383C-4091-4F42-A56F-C9E46D552D79}.Debug|x64 Setup.ActiveCfg = Debug Passthrough|x64
+ {8DEB383C-4091-4F42-A56F-C9E46D552D79}.Debug|x86 Setup.ActiveCfg = Debug Passthrough|Win32
+ {8DEB383C-4091-4F42-A56F-C9E46D552D79}.Release|Win32.ActiveCfg = Release Passthrough|Win32
+ {8DEB383C-4091-4F42-A56F-C9E46D552D79}.Release|Win32.Build.0 = Release Passthrough|Win32
+ {8DEB383C-4091-4F42-A56F-C9E46D552D79}.Release|x64.ActiveCfg = Release Passthrough|x64
+ {8DEB383C-4091-4F42-A56F-C9E46D552D79}.Release|x64.Build.0 = Release Passthrough|x64
+ {8DEB383C-4091-4F42-A56F-C9E46D552D79}.Release|x64 Setup.ActiveCfg = Release Passthrough|x64
+ {8DEB383C-4091-4F42-A56F-C9E46D552D79}.Release|x86 Setup.ActiveCfg = Release Passthrough|Win32
+ {2C3C2423-234B-4772-8899-D3B137E5CA35}.All|Win32.ActiveCfg = Release|x64
+ {2C3C2423-234B-4772-8899-D3B137E5CA35}.All|x64.ActiveCfg = Release|x64
+ {2C3C2423-234B-4772-8899-D3B137E5CA35}.All|x64.Build.0 = Release|x64
+ {2C3C2423-234B-4772-8899-D3B137E5CA35}.All|x64 Setup.ActiveCfg = Release|x64
+ {2C3C2423-234B-4772-8899-D3B137E5CA35}.All|x64 Setup.Build.0 = Release|x64
+ {2C3C2423-234B-4772-8899-D3B137E5CA35}.All|x86 Setup.ActiveCfg = Release|x64
+ {2C3C2423-234B-4772-8899-D3B137E5CA35}.Debug|Win32.ActiveCfg = Debug|Win32
+ {2C3C2423-234B-4772-8899-D3B137E5CA35}.Debug|Win32.Build.0 = Debug|Win32
+ {2C3C2423-234B-4772-8899-D3B137E5CA35}.Debug|x64.ActiveCfg = Debug|x64
+ {2C3C2423-234B-4772-8899-D3B137E5CA35}.Debug|x64.Build.0 = Debug|x64
+ {2C3C2423-234B-4772-8899-D3B137E5CA35}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {2C3C2423-234B-4772-8899-D3B137E5CA35}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {2C3C2423-234B-4772-8899-D3B137E5CA35}.Release|Win32.ActiveCfg = Release|Win32
+ {2C3C2423-234B-4772-8899-D3B137E5CA35}.Release|Win32.Build.0 = Release|Win32
+ {2C3C2423-234B-4772-8899-D3B137E5CA35}.Release|x64.ActiveCfg = Release|x64
+ {2C3C2423-234B-4772-8899-D3B137E5CA35}.Release|x64.Build.0 = Release|x64
+ {2C3C2423-234B-4772-8899-D3B137E5CA35}.Release|x64 Setup.ActiveCfg = Release|x64
+ {2C3C2423-234B-4772-8899-D3B137E5CA35}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {3850D93A-5F24-4922-BC1C-74D08C37C256}.All|Win32.ActiveCfg = Release|x64
+ {3850D93A-5F24-4922-BC1C-74D08C37C256}.All|x64.ActiveCfg = Release|x64
+ {3850D93A-5F24-4922-BC1C-74D08C37C256}.All|x64.Build.0 = Release|x64
+ {3850D93A-5F24-4922-BC1C-74D08C37C256}.All|x64 Setup.ActiveCfg = Release|x64
+ {3850D93A-5F24-4922-BC1C-74D08C37C256}.All|x64 Setup.Build.0 = Release|x64
+ {3850D93A-5F24-4922-BC1C-74D08C37C256}.All|x86 Setup.ActiveCfg = Release|x64
+ {3850D93A-5F24-4922-BC1C-74D08C37C256}.Debug|Win32.ActiveCfg = Debug|Win32
+ {3850D93A-5F24-4922-BC1C-74D08C37C256}.Debug|Win32.Build.0 = Debug|Win32
+ {3850D93A-5F24-4922-BC1C-74D08C37C256}.Debug|x64.ActiveCfg = Debug|x64
+ {3850D93A-5F24-4922-BC1C-74D08C37C256}.Debug|x64.Build.0 = Debug|x64
+ {3850D93A-5F24-4922-BC1C-74D08C37C256}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {3850D93A-5F24-4922-BC1C-74D08C37C256}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {3850D93A-5F24-4922-BC1C-74D08C37C256}.Release|Win32.ActiveCfg = Release|Win32
+ {3850D93A-5F24-4922-BC1C-74D08C37C256}.Release|Win32.Build.0 = Release|Win32
+ {3850D93A-5F24-4922-BC1C-74D08C37C256}.Release|x64.ActiveCfg = Release|x64
+ {3850D93A-5F24-4922-BC1C-74D08C37C256}.Release|x64.Build.0 = Release|x64
+ {3850D93A-5F24-4922-BC1C-74D08C37C256}.Release|x64 Setup.ActiveCfg = Release|x64
+ {3850D93A-5F24-4922-BC1C-74D08C37C256}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {2CA40887-1622-46A1-A7F9-17FD7E7E545B}.All|Win32.ActiveCfg = Release|x64
+ {2CA40887-1622-46A1-A7F9-17FD7E7E545B}.All|x64.ActiveCfg = Release|x64
+ {2CA40887-1622-46A1-A7F9-17FD7E7E545B}.All|x64.Build.0 = Release|x64
+ {2CA40887-1622-46A1-A7F9-17FD7E7E545B}.All|x64 Setup.ActiveCfg = Release|x64
+ {2CA40887-1622-46A1-A7F9-17FD7E7E545B}.All|x64 Setup.Build.0 = Release|x64
+ {2CA40887-1622-46A1-A7F9-17FD7E7E545B}.All|x86 Setup.ActiveCfg = Release|x64
+ {2CA40887-1622-46A1-A7F9-17FD7E7E545B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {2CA40887-1622-46A1-A7F9-17FD7E7E545B}.Debug|Win32.Build.0 = Debug|Win32
+ {2CA40887-1622-46A1-A7F9-17FD7E7E545B}.Debug|x64.ActiveCfg = Debug|x64
+ {2CA40887-1622-46A1-A7F9-17FD7E7E545B}.Debug|x64.Build.0 = Debug|x64
+ {2CA40887-1622-46A1-A7F9-17FD7E7E545B}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {2CA40887-1622-46A1-A7F9-17FD7E7E545B}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {2CA40887-1622-46A1-A7F9-17FD7E7E545B}.Release|Win32.ActiveCfg = Release|Win32
+ {2CA40887-1622-46A1-A7F9-17FD7E7E545B}.Release|Win32.Build.0 = Release|Win32
+ {2CA40887-1622-46A1-A7F9-17FD7E7E545B}.Release|x64.ActiveCfg = Release|x64
+ {2CA40887-1622-46A1-A7F9-17FD7E7E545B}.Release|x64.Build.0 = Release|x64
+ {2CA40887-1622-46A1-A7F9-17FD7E7E545B}.Release|x64 Setup.ActiveCfg = Release|x64
+ {2CA40887-1622-46A1-A7F9-17FD7E7E545B}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {028C7278-05D7-4E18-82FE-BE231B844F41}.All|Win32.ActiveCfg = Release|x64
+ {028C7278-05D7-4E18-82FE-BE231B844F41}.All|x64.ActiveCfg = Release|x64
+ {028C7278-05D7-4E18-82FE-BE231B844F41}.All|x64.Build.0 = Release|x64
+ {028C7278-05D7-4E18-82FE-BE231B844F41}.All|x64 Setup.ActiveCfg = Release|x64
+ {028C7278-05D7-4E18-82FE-BE231B844F41}.All|x64 Setup.Build.0 = Release|x64
+ {028C7278-05D7-4E18-82FE-BE231B844F41}.All|x86 Setup.ActiveCfg = Release|x64
+ {028C7278-05D7-4E18-82FE-BE231B844F41}.Debug|Win32.ActiveCfg = Debug|Win32
+ {028C7278-05D7-4E18-82FE-BE231B844F41}.Debug|Win32.Build.0 = Debug|Win32
+ {028C7278-05D7-4E18-82FE-BE231B844F41}.Debug|x64.ActiveCfg = Debug|x64
+ {028C7278-05D7-4E18-82FE-BE231B844F41}.Debug|x64.Build.0 = Debug|x64
+ {028C7278-05D7-4E18-82FE-BE231B844F41}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {028C7278-05D7-4E18-82FE-BE231B844F41}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {028C7278-05D7-4E18-82FE-BE231B844F41}.Release|Win32.ActiveCfg = Release|Win32
+ {028C7278-05D7-4E18-82FE-BE231B844F41}.Release|Win32.Build.0 = Release|Win32
+ {028C7278-05D7-4E18-82FE-BE231B844F41}.Release|x64.ActiveCfg = Release|x64
+ {028C7278-05D7-4E18-82FE-BE231B844F41}.Release|x64.Build.0 = Release|x64
+ {028C7278-05D7-4E18-82FE-BE231B844F41}.Release|x64 Setup.ActiveCfg = Release|x64
+ {028C7278-05D7-4E18-82FE-BE231B844F41}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {D7F1E3F2-A3F4-474C-8555-15122571AF52}.All|Win32.ActiveCfg = Release|x64
+ {D7F1E3F2-A3F4-474C-8555-15122571AF52}.All|x64.ActiveCfg = Release|x64
+ {D7F1E3F2-A3F4-474C-8555-15122571AF52}.All|x64.Build.0 = Release|x64
+ {D7F1E3F2-A3F4-474C-8555-15122571AF52}.All|x64 Setup.ActiveCfg = Release|x64
+ {D7F1E3F2-A3F4-474C-8555-15122571AF52}.All|x64 Setup.Build.0 = Release|x64
+ {D7F1E3F2-A3F4-474C-8555-15122571AF52}.All|x86 Setup.ActiveCfg = Release|x64
+ {D7F1E3F2-A3F4-474C-8555-15122571AF52}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D7F1E3F2-A3F4-474C-8555-15122571AF52}.Debug|Win32.Build.0 = Debug|Win32
+ {D7F1E3F2-A3F4-474C-8555-15122571AF52}.Debug|x64.ActiveCfg = Debug|x64
+ {D7F1E3F2-A3F4-474C-8555-15122571AF52}.Debug|x64.Build.0 = Debug|x64
+ {D7F1E3F2-A3F4-474C-8555-15122571AF52}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {D7F1E3F2-A3F4-474C-8555-15122571AF52}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {D7F1E3F2-A3F4-474C-8555-15122571AF52}.Release|Win32.ActiveCfg = Release|Win32
+ {D7F1E3F2-A3F4-474C-8555-15122571AF52}.Release|Win32.Build.0 = Release|Win32
+ {D7F1E3F2-A3F4-474C-8555-15122571AF52}.Release|x64.ActiveCfg = Release|x64
+ {D7F1E3F2-A3F4-474C-8555-15122571AF52}.Release|x64.Build.0 = Release|x64
+ {D7F1E3F2-A3F4-474C-8555-15122571AF52}.Release|x64 Setup.ActiveCfg = Release|x64
+ {D7F1E3F2-A3F4-474C-8555-15122571AF52}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {5BC072DB-3826-48EA-AF34-FE32AA01E83B}.All|Win32.ActiveCfg = Release|x64
+ {5BC072DB-3826-48EA-AF34-FE32AA01E83B}.All|x64.ActiveCfg = Release|x64
+ {5BC072DB-3826-48EA-AF34-FE32AA01E83B}.All|x64.Build.0 = Release|x64
+ {5BC072DB-3826-48EA-AF34-FE32AA01E83B}.All|x64 Setup.ActiveCfg = Release|x64
+ {5BC072DB-3826-48EA-AF34-FE32AA01E83B}.All|x64 Setup.Build.0 = Release|x64
+ {5BC072DB-3826-48EA-AF34-FE32AA01E83B}.All|x86 Setup.ActiveCfg = Release|x64
+ {5BC072DB-3826-48EA-AF34-FE32AA01E83B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {5BC072DB-3826-48EA-AF34-FE32AA01E83B}.Debug|Win32.Build.0 = Debug|Win32
+ {5BC072DB-3826-48EA-AF34-FE32AA01E83B}.Debug|x64.ActiveCfg = Debug|x64
+ {5BC072DB-3826-48EA-AF34-FE32AA01E83B}.Debug|x64.Build.0 = Debug|x64
+ {5BC072DB-3826-48EA-AF34-FE32AA01E83B}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {5BC072DB-3826-48EA-AF34-FE32AA01E83B}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {5BC072DB-3826-48EA-AF34-FE32AA01E83B}.Release|Win32.ActiveCfg = Release|Win32
+ {5BC072DB-3826-48EA-AF34-FE32AA01E83B}.Release|Win32.Build.0 = Release|Win32
+ {5BC072DB-3826-48EA-AF34-FE32AA01E83B}.Release|x64.ActiveCfg = Release|x64
+ {5BC072DB-3826-48EA-AF34-FE32AA01E83B}.Release|x64.Build.0 = Release|x64
+ {5BC072DB-3826-48EA-AF34-FE32AA01E83B}.Release|x64 Setup.ActiveCfg = Release|x64
+ {5BC072DB-3826-48EA-AF34-FE32AA01E83B}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {FA429E98-8B03-45E6-A096-A4BC5E821DE4}.All|Win32.ActiveCfg = Release|x64
+ {FA429E98-8B03-45E6-A096-A4BC5E821DE4}.All|x64.ActiveCfg = Release|x64
+ {FA429E98-8B03-45E6-A096-A4BC5E821DE4}.All|x64.Build.0 = Release|x64
+ {FA429E98-8B03-45E6-A096-A4BC5E821DE4}.All|x64 Setup.ActiveCfg = Release|x64
+ {FA429E98-8B03-45E6-A096-A4BC5E821DE4}.All|x64 Setup.Build.0 = Release|x64
+ {FA429E98-8B03-45E6-A096-A4BC5E821DE4}.All|x86 Setup.ActiveCfg = Release|x64
+ {FA429E98-8B03-45E6-A096-A4BC5E821DE4}.Debug|Win32.ActiveCfg = Debug|Win32
+ {FA429E98-8B03-45E6-A096-A4BC5E821DE4}.Debug|Win32.Build.0 = Debug|Win32
+ {FA429E98-8B03-45E6-A096-A4BC5E821DE4}.Debug|x64.ActiveCfg = Debug|x64
+ {FA429E98-8B03-45E6-A096-A4BC5E821DE4}.Debug|x64.Build.0 = Debug|x64
+ {FA429E98-8B03-45E6-A096-A4BC5E821DE4}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {FA429E98-8B03-45E6-A096-A4BC5E821DE4}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {FA429E98-8B03-45E6-A096-A4BC5E821DE4}.Release|Win32.ActiveCfg = Release|Win32
+ {FA429E98-8B03-45E6-A096-A4BC5E821DE4}.Release|Win32.Build.0 = Release|Win32
+ {FA429E98-8B03-45E6-A096-A4BC5E821DE4}.Release|x64.ActiveCfg = Release|x64
+ {FA429E98-8B03-45E6-A096-A4BC5E821DE4}.Release|x64.Build.0 = Release|x64
+ {FA429E98-8B03-45E6-A096-A4BC5E821DE4}.Release|x64 Setup.ActiveCfg = Release|x64
+ {FA429E98-8B03-45E6-A096-A4BC5E821DE4}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {06E3A538-AB32-44F2-B477-755FF9CB5D37}.All|Win32.ActiveCfg = Release|x64
+ {06E3A538-AB32-44F2-B477-755FF9CB5D37}.All|x64.ActiveCfg = Release|x64
+ {06E3A538-AB32-44F2-B477-755FF9CB5D37}.All|x64.Build.0 = Release|x64
+ {06E3A538-AB32-44F2-B477-755FF9CB5D37}.All|x64 Setup.ActiveCfg = Release|x64
+ {06E3A538-AB32-44F2-B477-755FF9CB5D37}.All|x64 Setup.Build.0 = Release|x64
+ {06E3A538-AB32-44F2-B477-755FF9CB5D37}.All|x86 Setup.ActiveCfg = Release|x64
+ {06E3A538-AB32-44F2-B477-755FF9CB5D37}.Debug|Win32.ActiveCfg = Debug|Win32
+ {06E3A538-AB32-44F2-B477-755FF9CB5D37}.Debug|Win32.Build.0 = Debug|Win32
+ {06E3A538-AB32-44F2-B477-755FF9CB5D37}.Debug|x64.ActiveCfg = Debug|x64
+ {06E3A538-AB32-44F2-B477-755FF9CB5D37}.Debug|x64.Build.0 = Debug|x64
+ {06E3A538-AB32-44F2-B477-755FF9CB5D37}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {06E3A538-AB32-44F2-B477-755FF9CB5D37}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {06E3A538-AB32-44F2-B477-755FF9CB5D37}.Release|Win32.ActiveCfg = Release|Win32
+ {06E3A538-AB32-44F2-B477-755FF9CB5D37}.Release|Win32.Build.0 = Release|Win32
+ {06E3A538-AB32-44F2-B477-755FF9CB5D37}.Release|x64.ActiveCfg = Release|x64
+ {06E3A538-AB32-44F2-B477-755FF9CB5D37}.Release|x64.Build.0 = Release|x64
+ {06E3A538-AB32-44F2-B477-755FF9CB5D37}.Release|x64 Setup.ActiveCfg = Release|x64
+ {06E3A538-AB32-44F2-B477-755FF9CB5D37}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05}.All|Win32.ActiveCfg = Release|x64
+ {6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05}.All|x64.ActiveCfg = Release|x64
+ {6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05}.All|x64.Build.0 = Release|x64
+ {6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05}.All|x64 Setup.ActiveCfg = Release|x64
+ {6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05}.All|x64 Setup.Build.0 = Release|x64
+ {6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05}.All|x86 Setup.ActiveCfg = Release|x64
+ {6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05}.Debug|Win32.ActiveCfg = Debug|Win32
+ {6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05}.Debug|Win32.Build.0 = Debug|Win32
+ {6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05}.Debug|x64.ActiveCfg = Debug|x64
+ {6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05}.Debug|x64.Build.0 = Debug|x64
+ {6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05}.Release|Win32.ActiveCfg = Release|Win32
+ {6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05}.Release|Win32.Build.0 = Release|Win32
+ {6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05}.Release|x64.ActiveCfg = Release|x64
+ {6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05}.Release|x64.Build.0 = Release|x64
+ {6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05}.Release|x64 Setup.ActiveCfg = Release|x64
+ {6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {A4B122CF-5196-476B-8C0E-D8BD59AC3C14}.All|Win32.ActiveCfg = Release|x64
+ {A4B122CF-5196-476B-8C0E-D8BD59AC3C14}.All|x64.ActiveCfg = Release|x64
+ {A4B122CF-5196-476B-8C0E-D8BD59AC3C14}.All|x64.Build.0 = Release|x64
+ {A4B122CF-5196-476B-8C0E-D8BD59AC3C14}.All|x64 Setup.ActiveCfg = Release|x64
+ {A4B122CF-5196-476B-8C0E-D8BD59AC3C14}.All|x64 Setup.Build.0 = Release|x64
+ {A4B122CF-5196-476B-8C0E-D8BD59AC3C14}.All|x86 Setup.ActiveCfg = Release|x64
+ {A4B122CF-5196-476B-8C0E-D8BD59AC3C14}.Debug|Win32.ActiveCfg = Debug|Win32
+ {A4B122CF-5196-476B-8C0E-D8BD59AC3C14}.Debug|Win32.Build.0 = Debug|Win32
+ {A4B122CF-5196-476B-8C0E-D8BD59AC3C14}.Debug|x64.ActiveCfg = Debug|x64
+ {A4B122CF-5196-476B-8C0E-D8BD59AC3C14}.Debug|x64.Build.0 = Debug|x64
+ {A4B122CF-5196-476B-8C0E-D8BD59AC3C14}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {A4B122CF-5196-476B-8C0E-D8BD59AC3C14}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {A4B122CF-5196-476B-8C0E-D8BD59AC3C14}.Release|Win32.ActiveCfg = Release|Win32
+ {A4B122CF-5196-476B-8C0E-D8BD59AC3C14}.Release|Win32.Build.0 = Release|Win32
+ {A4B122CF-5196-476B-8C0E-D8BD59AC3C14}.Release|x64.ActiveCfg = Release|x64
+ {A4B122CF-5196-476B-8C0E-D8BD59AC3C14}.Release|x64.Build.0 = Release|x64
+ {A4B122CF-5196-476B-8C0E-D8BD59AC3C14}.Release|x64 Setup.ActiveCfg = Release|x64
+ {A4B122CF-5196-476B-8C0E-D8BD59AC3C14}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD}.All|Win32.ActiveCfg = Release|x64
+ {75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD}.All|x64.ActiveCfg = Release|x64
+ {75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD}.All|x64.Build.0 = Release|x64
+ {75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD}.All|x64 Setup.ActiveCfg = Release|x64
+ {75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD}.All|x64 Setup.Build.0 = Release|x64
+ {75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD}.All|x86 Setup.ActiveCfg = Release|x64
+ {75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD}.Debug|Win32.ActiveCfg = Debug|Win32
+ {75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD}.Debug|Win32.Build.0 = Debug|Win32
+ {75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD}.Debug|x64.ActiveCfg = Debug|x64
+ {75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD}.Debug|x64.Build.0 = Debug|x64
+ {75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD}.Release|Win32.ActiveCfg = Release|Win32
+ {75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD}.Release|Win32.Build.0 = Release|Win32
+ {75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD}.Release|x64.ActiveCfg = Release|x64
+ {75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD}.Release|x64.Build.0 = Release|x64
+ {75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD}.Release|x64 Setup.ActiveCfg = Release|x64
+ {75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {F6A33240-8F29-48BD-98F0-826995911799}.All|Win32.ActiveCfg = Release|x64
+ {F6A33240-8F29-48BD-98F0-826995911799}.All|x64.ActiveCfg = Release|x64
+ {F6A33240-8F29-48BD-98F0-826995911799}.All|x64.Build.0 = Release|x64
+ {F6A33240-8F29-48BD-98F0-826995911799}.All|x64 Setup.ActiveCfg = Release|x64
+ {F6A33240-8F29-48BD-98F0-826995911799}.All|x64 Setup.Build.0 = Release|x64
+ {F6A33240-8F29-48BD-98F0-826995911799}.All|x86 Setup.ActiveCfg = Release|x64
+ {F6A33240-8F29-48BD-98F0-826995911799}.Debug|Win32.ActiveCfg = Debug|Win32
+ {F6A33240-8F29-48BD-98F0-826995911799}.Debug|Win32.Build.0 = Debug|Win32
+ {F6A33240-8F29-48BD-98F0-826995911799}.Debug|x64.ActiveCfg = Debug|x64
+ {F6A33240-8F29-48BD-98F0-826995911799}.Debug|x64.Build.0 = Debug|x64
+ {F6A33240-8F29-48BD-98F0-826995911799}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {F6A33240-8F29-48BD-98F0-826995911799}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {F6A33240-8F29-48BD-98F0-826995911799}.Release|Win32.ActiveCfg = Release|Win32
+ {F6A33240-8F29-48BD-98F0-826995911799}.Release|Win32.Build.0 = Release|Win32
+ {F6A33240-8F29-48BD-98F0-826995911799}.Release|x64.ActiveCfg = Release|x64
+ {F6A33240-8F29-48BD-98F0-826995911799}.Release|x64.Build.0 = Release|x64
+ {F6A33240-8F29-48BD-98F0-826995911799}.Release|x64 Setup.ActiveCfg = Release|x64
+ {F6A33240-8F29-48BD-98F0-826995911799}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {65A6273D-FCAB-4C55-B09E-65100141A5D4}.All|Win32.ActiveCfg = Release|x64
+ {65A6273D-FCAB-4C55-B09E-65100141A5D4}.All|x64.ActiveCfg = Release|x64
+ {65A6273D-FCAB-4C55-B09E-65100141A5D4}.All|x64.Build.0 = Release|x64
+ {65A6273D-FCAB-4C55-B09E-65100141A5D4}.All|x64 Setup.ActiveCfg = Release|x64
+ {65A6273D-FCAB-4C55-B09E-65100141A5D4}.All|x64 Setup.Build.0 = Release|x64
+ {65A6273D-FCAB-4C55-B09E-65100141A5D4}.All|x86 Setup.ActiveCfg = Release|x64
+ {65A6273D-FCAB-4C55-B09E-65100141A5D4}.Debug|Win32.ActiveCfg = Debug|Win32
+ {65A6273D-FCAB-4C55-B09E-65100141A5D4}.Debug|Win32.Build.0 = Debug|Win32
+ {65A6273D-FCAB-4C55-B09E-65100141A5D4}.Debug|x64.ActiveCfg = Debug|x64
+ {65A6273D-FCAB-4C55-B09E-65100141A5D4}.Debug|x64.Build.0 = Debug|x64
+ {65A6273D-FCAB-4C55-B09E-65100141A5D4}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {65A6273D-FCAB-4C55-B09E-65100141A5D4}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {65A6273D-FCAB-4C55-B09E-65100141A5D4}.Release|Win32.ActiveCfg = Release|Win32
+ {65A6273D-FCAB-4C55-B09E-65100141A5D4}.Release|Win32.Build.0 = Release|Win32
+ {65A6273D-FCAB-4C55-B09E-65100141A5D4}.Release|x64.ActiveCfg = Release|x64
+ {65A6273D-FCAB-4C55-B09E-65100141A5D4}.Release|x64.Build.0 = Release|x64
+ {65A6273D-FCAB-4C55-B09E-65100141A5D4}.Release|x64 Setup.ActiveCfg = Release|x64
+ {65A6273D-FCAB-4C55-B09E-65100141A5D4}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24}.All|Win32.ActiveCfg = Release|x64
+ {E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24}.All|x64.ActiveCfg = Release|x64
+ {E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24}.All|x64.Build.0 = Release|x64
+ {E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24}.All|x64 Setup.ActiveCfg = Release|x64
+ {E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24}.All|x64 Setup.Build.0 = Release|x64
+ {E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24}.All|x86 Setup.ActiveCfg = Release|x64
+ {E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24}.Debug|Win32.ActiveCfg = Debug|Win32
+ {E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24}.Debug|Win32.Build.0 = Debug|Win32
+ {E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24}.Debug|x64.ActiveCfg = Debug|x64
+ {E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24}.Debug|x64.Build.0 = Debug|x64
+ {E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24}.Release|Win32.ActiveCfg = Release|Win32
+ {E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24}.Release|Win32.Build.0 = Release|Win32
+ {E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24}.Release|x64.ActiveCfg = Release|x64
+ {E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24}.Release|x64.Build.0 = Release|x64
+ {E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24}.Release|x64 Setup.ActiveCfg = Release|x64
+ {E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909}.All|Win32.ActiveCfg = Release|x64
+ {D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909}.All|x64.ActiveCfg = Release|x64
+ {D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909}.All|x64.Build.0 = Release|x64
+ {D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909}.All|x64 Setup.ActiveCfg = Release|x64
+ {D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909}.All|x64 Setup.Build.0 = Release|x64
+ {D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909}.All|x86 Setup.ActiveCfg = Release|x64
+ {D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909}.Debug|Win32.Build.0 = Debug|Win32
+ {D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909}.Debug|x64.ActiveCfg = Debug|x64
+ {D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909}.Debug|x64.Build.0 = Debug|x64
+ {D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909}.Release|Win32.ActiveCfg = Release|Win32
+ {D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909}.Release|Win32.Build.0 = Release|Win32
+ {D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909}.Release|x64.ActiveCfg = Release|x64
+ {D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909}.Release|x64.Build.0 = Release|x64
+ {D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909}.Release|x64 Setup.ActiveCfg = Release|x64
+ {D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E}.All|Win32.ActiveCfg = Release|x64
+ {44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E}.All|x64.ActiveCfg = Release|x64
+ {44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E}.All|x64.Build.0 = Release|x64
+ {44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E}.All|x64 Setup.ActiveCfg = Release|x64
+ {44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E}.All|x64 Setup.Build.0 = Release|x64
+ {44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E}.All|x86 Setup.ActiveCfg = Release|x64
+ {44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E}.Debug|Win32.ActiveCfg = Debug|Win32
+ {44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E}.Debug|Win32.Build.0 = Debug|Win32
+ {44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E}.Debug|x64.ActiveCfg = Debug|x64
+ {44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E}.Debug|x64.Build.0 = Debug|x64
+ {44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E}.Release|Win32.ActiveCfg = Release|Win32
+ {44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E}.Release|Win32.Build.0 = Release|Win32
+ {44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E}.Release|x64.ActiveCfg = Release|x64
+ {44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E}.Release|x64.Build.0 = Release|x64
+ {44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E}.Release|x64 Setup.ActiveCfg = Release|x64
+ {44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52}.All|Win32.ActiveCfg = Release|x64
+ {6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52}.All|x64.ActiveCfg = Release|x64
+ {6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52}.All|x64.Build.0 = Release|x64
+ {6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52}.All|x64 Setup.ActiveCfg = Release|x64
+ {6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52}.All|x64 Setup.Build.0 = Release|x64
+ {6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52}.All|x86 Setup.ActiveCfg = Release|x64
+ {6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52}.Debug|Win32.ActiveCfg = Debug|Win32
+ {6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52}.Debug|Win32.Build.0 = Debug|Win32
+ {6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52}.Debug|x64.ActiveCfg = Debug|x64
+ {6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52}.Debug|x64.Build.0 = Debug|x64
+ {6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52}.Release|Win32.ActiveCfg = Release|Win32
+ {6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52}.Release|Win32.Build.0 = Release|Win32
+ {6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52}.Release|x64.ActiveCfg = Release|x64
+ {6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52}.Release|x64.Build.0 = Release|x64
+ {6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52}.Release|x64 Setup.ActiveCfg = Release|x64
+ {6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {E3246D17-E29B-4AB5-962A-C69B0C5837BB}.All|Win32.ActiveCfg = Release|x64
+ {E3246D17-E29B-4AB5-962A-C69B0C5837BB}.All|x64.ActiveCfg = Release|x64
+ {E3246D17-E29B-4AB5-962A-C69B0C5837BB}.All|x64.Build.0 = Release|x64
+ {E3246D17-E29B-4AB5-962A-C69B0C5837BB}.All|x64 Setup.ActiveCfg = Release|x64
+ {E3246D17-E29B-4AB5-962A-C69B0C5837BB}.All|x64 Setup.Build.0 = Release|x64
+ {E3246D17-E29B-4AB5-962A-C69B0C5837BB}.All|x86 Setup.ActiveCfg = Release|x64
+ {E3246D17-E29B-4AB5-962A-C69B0C5837BB}.Debug|Win32.ActiveCfg = Debug|Win32
+ {E3246D17-E29B-4AB5-962A-C69B0C5837BB}.Debug|Win32.Build.0 = Debug|Win32
+ {E3246D17-E29B-4AB5-962A-C69B0C5837BB}.Debug|x64.ActiveCfg = Debug|x64
+ {E3246D17-E29B-4AB5-962A-C69B0C5837BB}.Debug|x64.Build.0 = Debug|x64
+ {E3246D17-E29B-4AB5-962A-C69B0C5837BB}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {E3246D17-E29B-4AB5-962A-C69B0C5837BB}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {E3246D17-E29B-4AB5-962A-C69B0C5837BB}.Release|Win32.ActiveCfg = Release|Win32
+ {E3246D17-E29B-4AB5-962A-C69B0C5837BB}.Release|Win32.Build.0 = Release|Win32
+ {E3246D17-E29B-4AB5-962A-C69B0C5837BB}.Release|x64.ActiveCfg = Release|x64
+ {E3246D17-E29B-4AB5-962A-C69B0C5837BB}.Release|x64.Build.0 = Release|x64
+ {E3246D17-E29B-4AB5-962A-C69B0C5837BB}.Release|x64 Setup.ActiveCfg = Release|x64
+ {E3246D17-E29B-4AB5-962A-C69B0C5837BB}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {36E854E3-CE12-4348-A125-CCF3F9D74813}.All|Win32.ActiveCfg = Release|x64
+ {36E854E3-CE12-4348-A125-CCF3F9D74813}.All|x64.ActiveCfg = Release|x64
+ {36E854E3-CE12-4348-A125-CCF3F9D74813}.All|x64.Build.0 = Release|x64
+ {36E854E3-CE12-4348-A125-CCF3F9D74813}.All|x64 Setup.ActiveCfg = Release|x64
+ {36E854E3-CE12-4348-A125-CCF3F9D74813}.All|x64 Setup.Build.0 = Release|x64
+ {36E854E3-CE12-4348-A125-CCF3F9D74813}.All|x86 Setup.ActiveCfg = Release|x64
+ {36E854E3-CE12-4348-A125-CCF3F9D74813}.Debug|Win32.ActiveCfg = Debug|Win32
+ {36E854E3-CE12-4348-A125-CCF3F9D74813}.Debug|Win32.Build.0 = Debug|Win32
+ {36E854E3-CE12-4348-A125-CCF3F9D74813}.Debug|x64.ActiveCfg = Debug|x64
+ {36E854E3-CE12-4348-A125-CCF3F9D74813}.Debug|x64.Build.0 = Debug|x64
+ {36E854E3-CE12-4348-A125-CCF3F9D74813}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {36E854E3-CE12-4348-A125-CCF3F9D74813}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {36E854E3-CE12-4348-A125-CCF3F9D74813}.Release|Win32.ActiveCfg = Release|Win32
+ {36E854E3-CE12-4348-A125-CCF3F9D74813}.Release|Win32.Build.0 = Release|Win32
+ {36E854E3-CE12-4348-A125-CCF3F9D74813}.Release|x64.ActiveCfg = Release|x64
+ {36E854E3-CE12-4348-A125-CCF3F9D74813}.Release|x64.Build.0 = Release|x64
+ {36E854E3-CE12-4348-A125-CCF3F9D74813}.Release|x64 Setup.ActiveCfg = Release|x64
+ {36E854E3-CE12-4348-A125-CCF3F9D74813}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {7B077E7F-1BE7-4291-AB86-55E527B25CAC}.All|Win32.ActiveCfg = Release|x64
+ {7B077E7F-1BE7-4291-AB86-55E527B25CAC}.All|x64.ActiveCfg = Release|x64
+ {7B077E7F-1BE7-4291-AB86-55E527B25CAC}.All|x64.Build.0 = Release|x64
+ {7B077E7F-1BE7-4291-AB86-55E527B25CAC}.All|x64 Setup.ActiveCfg = Release|x64
+ {7B077E7F-1BE7-4291-AB86-55E527B25CAC}.All|x64 Setup.Build.0 = Release|x64
+ {7B077E7F-1BE7-4291-AB86-55E527B25CAC}.All|x86 Setup.ActiveCfg = Release|x64
+ {7B077E7F-1BE7-4291-AB86-55E527B25CAC}.Debug|Win32.ActiveCfg = Debug|Win32
+ {7B077E7F-1BE7-4291-AB86-55E527B25CAC}.Debug|Win32.Build.0 = Debug|Win32
+ {7B077E7F-1BE7-4291-AB86-55E527B25CAC}.Debug|x64.ActiveCfg = Debug|x64
+ {7B077E7F-1BE7-4291-AB86-55E527B25CAC}.Debug|x64.Build.0 = Debug|x64
+ {7B077E7F-1BE7-4291-AB86-55E527B25CAC}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {7B077E7F-1BE7-4291-AB86-55E527B25CAC}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {7B077E7F-1BE7-4291-AB86-55E527B25CAC}.Release|Win32.ActiveCfg = Release|Win32
+ {7B077E7F-1BE7-4291-AB86-55E527B25CAC}.Release|Win32.Build.0 = Release|Win32
+ {7B077E7F-1BE7-4291-AB86-55E527B25CAC}.Release|x64.ActiveCfg = Release|x64
+ {7B077E7F-1BE7-4291-AB86-55E527B25CAC}.Release|x64.Build.0 = Release|x64
+ {7B077E7F-1BE7-4291-AB86-55E527B25CAC}.Release|x64 Setup.ActiveCfg = Release|x64
+ {7B077E7F-1BE7-4291-AB86-55E527B25CAC}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {4F92B672-DADB-4047-8D6A-4BB3796733FD}.All|Win32.ActiveCfg = Release|Win32
+ {4F92B672-DADB-4047-8D6A-4BB3796733FD}.All|Win32.Build.0 = Release|Win32
+ {4F92B672-DADB-4047-8D6A-4BB3796733FD}.All|x64.ActiveCfg = Release|Win32
+ {4F92B672-DADB-4047-8D6A-4BB3796733FD}.All|x64.Build.0 = Release|Win32
+ {4F92B672-DADB-4047-8D6A-4BB3796733FD}.All|x64 Setup.ActiveCfg = Release|Win32
+ {4F92B672-DADB-4047-8D6A-4BB3796733FD}.All|x64 Setup.Build.0 = Release|Win32
+ {4F92B672-DADB-4047-8D6A-4BB3796733FD}.All|x86 Setup.ActiveCfg = Release|Win32
+ {4F92B672-DADB-4047-8D6A-4BB3796733FD}.All|x86 Setup.Build.0 = Release|Win32
+ {4F92B672-DADB-4047-8D6A-4BB3796733FD}.Debug|Win32.ActiveCfg = Debug|Win32
+ {4F92B672-DADB-4047-8D6A-4BB3796733FD}.Debug|Win32.Build.0 = Debug|Win32
+ {4F92B672-DADB-4047-8D6A-4BB3796733FD}.Debug|x64.ActiveCfg = Debug|Win32
+ {4F92B672-DADB-4047-8D6A-4BB3796733FD}.Debug|x64.Build.0 = Debug|Win32
+ {4F92B672-DADB-4047-8D6A-4BB3796733FD}.Debug|x64 Setup.ActiveCfg = Debug|Win32
+ {4F92B672-DADB-4047-8D6A-4BB3796733FD}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {4F92B672-DADB-4047-8D6A-4BB3796733FD}.Release|Win32.ActiveCfg = Release|Win32
+ {4F92B672-DADB-4047-8D6A-4BB3796733FD}.Release|Win32.Build.0 = Release|Win32
+ {4F92B672-DADB-4047-8D6A-4BB3796733FD}.Release|x64.ActiveCfg = Release|Win32
+ {4F92B672-DADB-4047-8D6A-4BB3796733FD}.Release|x64.Build.0 = Release|Win32
+ {4F92B672-DADB-4047-8D6A-4BB3796733FD}.Release|x64 Setup.ActiveCfg = Release|Win32
+ {4F92B672-DADB-4047-8D6A-4BB3796733FD}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {2DEE4895-1134-439C-B688-52203E57D878}.All|Win32.ActiveCfg = Release|Win32
+ {2DEE4895-1134-439C-B688-52203E57D878}.All|Win32.Build.0 = Release|Win32
+ {2DEE4895-1134-439C-B688-52203E57D878}.All|x64.ActiveCfg = Release|Win32
+ {2DEE4895-1134-439C-B688-52203E57D878}.All|x64.Build.0 = Release|Win32
+ {2DEE4895-1134-439C-B688-52203E57D878}.All|x64 Setup.ActiveCfg = Release|Win32
+ {2DEE4895-1134-439C-B688-52203E57D878}.All|x64 Setup.Build.0 = Release|Win32
+ {2DEE4895-1134-439C-B688-52203E57D878}.All|x86 Setup.ActiveCfg = Release|Win32
+ {2DEE4895-1134-439C-B688-52203E57D878}.All|x86 Setup.Build.0 = Release|Win32
+ {2DEE4895-1134-439C-B688-52203E57D878}.Debug|Win32.ActiveCfg = Debug|Win32
+ {2DEE4895-1134-439C-B688-52203E57D878}.Debug|Win32.Build.0 = Debug|Win32
+ {2DEE4895-1134-439C-B688-52203E57D878}.Debug|x64.ActiveCfg = Debug|Win32
+ {2DEE4895-1134-439C-B688-52203E57D878}.Debug|x64.Build.0 = Debug|Win32
+ {2DEE4895-1134-439C-B688-52203E57D878}.Debug|x64 Setup.ActiveCfg = Debug|Win32
+ {2DEE4895-1134-439C-B688-52203E57D878}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {2DEE4895-1134-439C-B688-52203E57D878}.Release|Win32.ActiveCfg = Release|Win32
+ {2DEE4895-1134-439C-B688-52203E57D878}.Release|Win32.Build.0 = Release|Win32
+ {2DEE4895-1134-439C-B688-52203E57D878}.Release|x64.ActiveCfg = Release|Win32
+ {2DEE4895-1134-439C-B688-52203E57D878}.Release|x64.Build.0 = Release|Win32
+ {2DEE4895-1134-439C-B688-52203E57D878}.Release|x64 Setup.ActiveCfg = Release|Win32
+ {2DEE4895-1134-439C-B688-52203E57D878}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}.All|Win32.ActiveCfg = Release|Win32
+ {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}.All|Win32.Build.0 = Release|Win32
+ {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}.All|x64.ActiveCfg = Release|Win32
+ {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}.All|x64.Build.0 = Release|Win32
+ {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}.All|x64 Setup.ActiveCfg = Release|Win32
+ {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}.All|x64 Setup.Build.0 = Release|Win32
+ {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}.All|x86 Setup.ActiveCfg = Release|Win32
+ {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}.All|x86 Setup.Build.0 = Release|Win32
+ {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}.Debug|Win32.ActiveCfg = Debug|Win32
+ {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}.Debug|Win32.Build.0 = Debug|Win32
+ {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}.Debug|x64.ActiveCfg = Debug|Win32
+ {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}.Debug|x64.Build.0 = Debug|Win32
+ {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}.Debug|x64 Setup.ActiveCfg = Debug|Win32
+ {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}.Release|Win32.ActiveCfg = Release|Win32
+ {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}.Release|Win32.Build.0 = Release|Win32
+ {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}.Release|x64.ActiveCfg = Release|Win32
+ {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}.Release|x64.Build.0 = Release|Win32
+ {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}.Release|x64 Setup.ActiveCfg = Release|Win32
+ {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}.All|Win32.ActiveCfg = Debug|x64
+ {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}.All|x64.ActiveCfg = Debug|x64
+ {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}.All|x64.Build.0 = Debug|x64
+ {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}.All|x64 Setup.ActiveCfg = Debug|x64
+ {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}.All|x64 Setup.Build.0 = Debug|x64
+ {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}.All|x86 Setup.ActiveCfg = Debug|x64
+ {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}.Debug|Win32.ActiveCfg = Debug|Win32
+ {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}.Debug|Win32.Build.0 = Debug|Win32
+ {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}.Debug|x64.ActiveCfg = Debug|x64
+ {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}.Debug|x64.Build.0 = Debug|x64
+ {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}.Release|Win32.ActiveCfg = Release|Win32
+ {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}.Release|Win32.Build.0 = Release|Win32
+ {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}.Release|x64.ActiveCfg = Release|x64
+ {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}.Release|x64.Build.0 = Release|x64
+ {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}.Release|x64 Setup.ActiveCfg = Release|x64
+ {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {94001A0E-A837-445C-8004-F918F10D0226}.All|Win32.ActiveCfg = Debug|x64
+ {94001A0E-A837-445C-8004-F918F10D0226}.All|x64.ActiveCfg = Debug|x64
+ {94001A0E-A837-445C-8004-F918F10D0226}.All|x64.Build.0 = Debug|x64
+ {94001A0E-A837-445C-8004-F918F10D0226}.All|x64 Setup.ActiveCfg = Debug|x64
+ {94001A0E-A837-445C-8004-F918F10D0226}.All|x64 Setup.Build.0 = Debug|x64
+ {94001A0E-A837-445C-8004-F918F10D0226}.All|x86 Setup.ActiveCfg = Debug|x64
+ {94001A0E-A837-445C-8004-F918F10D0226}.Debug|Win32.ActiveCfg = Debug|Win32
+ {94001A0E-A837-445C-8004-F918F10D0226}.Debug|Win32.Build.0 = Debug|Win32
+ {94001A0E-A837-445C-8004-F918F10D0226}.Debug|x64.ActiveCfg = Debug|x64
+ {94001A0E-A837-445C-8004-F918F10D0226}.Debug|x64.Build.0 = Debug|x64
+ {94001A0E-A837-445C-8004-F918F10D0226}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {94001A0E-A837-445C-8004-F918F10D0226}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {94001A0E-A837-445C-8004-F918F10D0226}.Release|Win32.ActiveCfg = Release|Win32
+ {94001A0E-A837-445C-8004-F918F10D0226}.Release|Win32.Build.0 = Release|Win32
+ {94001A0E-A837-445C-8004-F918F10D0226}.Release|x64.ActiveCfg = Release|x64
+ {94001A0E-A837-445C-8004-F918F10D0226}.Release|x64.Build.0 = Release|x64
+ {94001A0E-A837-445C-8004-F918F10D0226}.Release|x64 Setup.ActiveCfg = Release|x64
+ {94001A0E-A837-445C-8004-F918F10D0226}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {2286DA73-9FC5-45BC-A508-85994C3317AB}.All|Win32.ActiveCfg = Release|x64
+ {2286DA73-9FC5-45BC-A508-85994C3317AB}.All|x64.ActiveCfg = Release|x64
+ {2286DA73-9FC5-45BC-A508-85994C3317AB}.All|x64.Build.0 = Release|x64
+ {2286DA73-9FC5-45BC-A508-85994C3317AB}.All|x64 Setup.ActiveCfg = Release|x64
+ {2286DA73-9FC5-45BC-A508-85994C3317AB}.All|x64 Setup.Build.0 = Release|x64
+ {2286DA73-9FC5-45BC-A508-85994C3317AB}.All|x86 Setup.ActiveCfg = Release|x64
+ {2286DA73-9FC5-45BC-A508-85994C3317AB}.Debug|Win32.ActiveCfg = Debug|Win32
+ {2286DA73-9FC5-45BC-A508-85994C3317AB}.Debug|Win32.Build.0 = Debug|Win32
+ {2286DA73-9FC5-45BC-A508-85994C3317AB}.Debug|x64.ActiveCfg = Debug|x64
+ {2286DA73-9FC5-45BC-A508-85994C3317AB}.Debug|x64.Build.0 = Debug|x64
+ {2286DA73-9FC5-45BC-A508-85994C3317AB}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {2286DA73-9FC5-45BC-A508-85994C3317AB}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {2286DA73-9FC5-45BC-A508-85994C3317AB}.Release|Win32.ActiveCfg = Release|Win32
+ {2286DA73-9FC5-45BC-A508-85994C3317AB}.Release|Win32.Build.0 = Release|Win32
+ {2286DA73-9FC5-45BC-A508-85994C3317AB}.Release|x64.ActiveCfg = Release|x64
+ {2286DA73-9FC5-45BC-A508-85994C3317AB}.Release|x64.Build.0 = Release|x64
+ {2286DA73-9FC5-45BC-A508-85994C3317AB}.Release|x64 Setup.ActiveCfg = Release|x64
+ {2286DA73-9FC5-45BC-A508-85994C3317AB}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {3CE1DC99-8246-4DB1-A709-74F19F08EC67}.All|Win32.ActiveCfg = Release|Win32
+ {3CE1DC99-8246-4DB1-A709-74F19F08EC67}.All|Win32.Build.0 = Release|Win32
+ {3CE1DC99-8246-4DB1-A709-74F19F08EC67}.All|x64.ActiveCfg = Release|Win32
+ {3CE1DC99-8246-4DB1-A709-74F19F08EC67}.All|x64.Build.0 = Release|Win32
+ {3CE1DC99-8246-4DB1-A709-74F19F08EC67}.All|x64 Setup.ActiveCfg = Release|Win32
+ {3CE1DC99-8246-4DB1-A709-74F19F08EC67}.All|x64 Setup.Build.0 = Release|Win32
+ {3CE1DC99-8246-4DB1-A709-74F19F08EC67}.All|x86 Setup.ActiveCfg = Release|Win32
+ {3CE1DC99-8246-4DB1-A709-74F19F08EC67}.All|x86 Setup.Build.0 = Release|Win32
+ {3CE1DC99-8246-4DB1-A709-74F19F08EC67}.Debug|Win32.ActiveCfg = Debug|Win32
+ {3CE1DC99-8246-4DB1-A709-74F19F08EC67}.Debug|Win32.Build.0 = Debug|Win32
+ {3CE1DC99-8246-4DB1-A709-74F19F08EC67}.Debug|x64.ActiveCfg = Debug|Win32
+ {3CE1DC99-8246-4DB1-A709-74F19F08EC67}.Debug|x64.Build.0 = Debug|Win32
+ {3CE1DC99-8246-4DB1-A709-74F19F08EC67}.Debug|x64 Setup.ActiveCfg = Debug|Win32
+ {3CE1DC99-8246-4DB1-A709-74F19F08EC67}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {3CE1DC99-8246-4DB1-A709-74F19F08EC67}.Release|Win32.ActiveCfg = Release|Win32
+ {3CE1DC99-8246-4DB1-A709-74F19F08EC67}.Release|Win32.Build.0 = Release|Win32
+ {3CE1DC99-8246-4DB1-A709-74F19F08EC67}.Release|x64.ActiveCfg = Release|Win32
+ {3CE1DC99-8246-4DB1-A709-74F19F08EC67}.Release|x64.Build.0 = Release|Win32
+ {3CE1DC99-8246-4DB1-A709-74F19F08EC67}.Release|x64 Setup.ActiveCfg = Release|Win32
+ {3CE1DC99-8246-4DB1-A709-74F19F08EC67}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {87A1FE3D-F410-4C8E-9591-8C625985BC70}.All|Win32.ActiveCfg = Release|Win32
+ {87A1FE3D-F410-4C8E-9591-8C625985BC70}.All|x64.ActiveCfg = Release|Win32
+ {87A1FE3D-F410-4C8E-9591-8C625985BC70}.All|x64 Setup.ActiveCfg = Release|Win32
+ {87A1FE3D-F410-4C8E-9591-8C625985BC70}.All|x86 Setup.ActiveCfg = Release|Win32
+ {87A1FE3D-F410-4C8E-9591-8C625985BC70}.Debug|Win32.ActiveCfg = Debug|Win32
+ {87A1FE3D-F410-4C8E-9591-8C625985BC70}.Debug|x64.ActiveCfg = Debug|Win32
+ {87A1FE3D-F410-4C8E-9591-8C625985BC70}.Debug|x64 Setup.ActiveCfg = Debug|Win32
+ {87A1FE3D-F410-4C8E-9591-8C625985BC70}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {87A1FE3D-F410-4C8E-9591-8C625985BC70}.Release|Win32.ActiveCfg = Release|Win32
+ {87A1FE3D-F410-4C8E-9591-8C625985BC70}.Release|x64.ActiveCfg = Release|Win32
+ {87A1FE3D-F410-4C8E-9591-8C625985BC70}.Release|x64 Setup.ActiveCfg = Release|Win32
+ {87A1FE3D-F410-4C8E-9591-8C625985BC70}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {7A8D8174-B355-4114-AFC1-04777CB9DE0A}.All|Win32.ActiveCfg = Release|Win32
+ {7A8D8174-B355-4114-AFC1-04777CB9DE0A}.All|Win32.Build.0 = Release|Win32
+ {7A8D8174-B355-4114-AFC1-04777CB9DE0A}.All|x64.ActiveCfg = Release|Win32
+ {7A8D8174-B355-4114-AFC1-04777CB9DE0A}.All|x64.Build.0 = Release|Win32
+ {7A8D8174-B355-4114-AFC1-04777CB9DE0A}.All|x64 Setup.ActiveCfg = Release|Win32
+ {7A8D8174-B355-4114-AFC1-04777CB9DE0A}.All|x64 Setup.Build.0 = Release|Win32
+ {7A8D8174-B355-4114-AFC1-04777CB9DE0A}.All|x86 Setup.ActiveCfg = Release|Win32
+ {7A8D8174-B355-4114-AFC1-04777CB9DE0A}.All|x86 Setup.Build.0 = Release|Win32
+ {7A8D8174-B355-4114-AFC1-04777CB9DE0A}.Debug|Win32.ActiveCfg = Debug|Win32
+ {7A8D8174-B355-4114-AFC1-04777CB9DE0A}.Debug|Win32.Build.0 = Debug|Win32
+ {7A8D8174-B355-4114-AFC1-04777CB9DE0A}.Debug|x64.ActiveCfg = Debug|x64
+ {7A8D8174-B355-4114-AFC1-04777CB9DE0A}.Debug|x64.Build.0 = Debug|x64
+ {7A8D8174-B355-4114-AFC1-04777CB9DE0A}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {7A8D8174-B355-4114-AFC1-04777CB9DE0A}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {7A8D8174-B355-4114-AFC1-04777CB9DE0A}.Release|Win32.ActiveCfg = Release|Win32
+ {7A8D8174-B355-4114-AFC1-04777CB9DE0A}.Release|Win32.Build.0 = Release|Win32
+ {7A8D8174-B355-4114-AFC1-04777CB9DE0A}.Release|x64.ActiveCfg = Release|x64
+ {7A8D8174-B355-4114-AFC1-04777CB9DE0A}.Release|x64.Build.0 = Release|x64
+ {7A8D8174-B355-4114-AFC1-04777CB9DE0A}.Release|x64 Setup.ActiveCfg = Release|x64
+ {7A8D8174-B355-4114-AFC1-04777CB9DE0A}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {7EB71250-F002-4ED8-92CA-CA218114537A}.All|Win32.ActiveCfg = Release|Win32
+ {7EB71250-F002-4ED8-92CA-CA218114537A}.All|x64.ActiveCfg = Release|Win32
+ {7EB71250-F002-4ED8-92CA-CA218114537A}.All|x64 Setup.ActiveCfg = Release|Win32
+ {7EB71250-F002-4ED8-92CA-CA218114537A}.All|x86 Setup.ActiveCfg = Release|Win32
+ {7EB71250-F002-4ED8-92CA-CA218114537A}.Debug|Win32.ActiveCfg = Debug|Win32
+ {7EB71250-F002-4ED8-92CA-CA218114537A}.Debug|x64.ActiveCfg = Debug|x64
+ {7EB71250-F002-4ED8-92CA-CA218114537A}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {7EB71250-F002-4ED8-92CA-CA218114537A}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {7EB71250-F002-4ED8-92CA-CA218114537A}.Release|Win32.ActiveCfg = Release|Win32
+ {7EB71250-F002-4ED8-92CA-CA218114537A}.Release|x64.ActiveCfg = Release|x64
+ {7EB71250-F002-4ED8-92CA-CA218114537A}.Release|x64 Setup.ActiveCfg = Release|x64
+ {7EB71250-F002-4ED8-92CA-CA218114537A}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {6E49F6C2-ADDA-4BFB-81FE-AB9AF51B455F}.All|Win32.ActiveCfg = Release|Win32
+ {6E49F6C2-ADDA-4BFB-81FE-AB9AF51B455F}.All|x64.ActiveCfg = Release|Win32
+ {6E49F6C2-ADDA-4BFB-81FE-AB9AF51B455F}.All|x64 Setup.ActiveCfg = Release|Win32
+ {6E49F6C2-ADDA-4BFB-81FE-AB9AF51B455F}.All|x86 Setup.ActiveCfg = Release|Win32
+ {6E49F6C2-ADDA-4BFB-81FE-AB9AF51B455F}.Debug|Win32.ActiveCfg = Debug|Win32
+ {6E49F6C2-ADDA-4BFB-81FE-AB9AF51B455F}.Debug|x64.ActiveCfg = Debug|Win32
+ {6E49F6C2-ADDA-4BFB-81FE-AB9AF51B455F}.Debug|x64 Setup.ActiveCfg = Debug|Win32
+ {6E49F6C2-ADDA-4BFB-81FE-AB9AF51B455F}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {6E49F6C2-ADDA-4BFB-81FE-AB9AF51B455F}.Release|Win32.ActiveCfg = Release|Win32
+ {6E49F6C2-ADDA-4BFB-81FE-AB9AF51B455F}.Release|x64.ActiveCfg = Release|Win32
+ {6E49F6C2-ADDA-4BFB-81FE-AB9AF51B455F}.Release|x64 Setup.ActiveCfg = Release|Win32
+ {6E49F6C2-ADDA-4BFB-81FE-AB9AF51B455F}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {464AAB78-5489-4916-BE51-BF8D61822311}.All|Win32.ActiveCfg = Release|Win32
+ {464AAB78-5489-4916-BE51-BF8D61822311}.All|x64.ActiveCfg = Release|Win32
+ {464AAB78-5489-4916-BE51-BF8D61822311}.All|x64 Setup.ActiveCfg = Release|Win32
+ {464AAB78-5489-4916-BE51-BF8D61822311}.All|x86 Setup.ActiveCfg = Release|Win32
+ {464AAB78-5489-4916-BE51-BF8D61822311}.Debug|Win32.ActiveCfg = Debug|Win32
+ {464AAB78-5489-4916-BE51-BF8D61822311}.Debug|x64.ActiveCfg = Debug|x64
+ {464AAB78-5489-4916-BE51-BF8D61822311}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {464AAB78-5489-4916-BE51-BF8D61822311}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {464AAB78-5489-4916-BE51-BF8D61822311}.Release|Win32.ActiveCfg = Release|Win32
+ {464AAB78-5489-4916-BE51-BF8D61822311}.Release|x64.ActiveCfg = Release|x64
+ {464AAB78-5489-4916-BE51-BF8D61822311}.Release|x64 Setup.ActiveCfg = Release|x64
+ {464AAB78-5489-4916-BE51-BF8D61822311}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {0AD1177E-1FD8-4643-9391-431467A11084}.All|Win32.ActiveCfg = Release|x64
+ {0AD1177E-1FD8-4643-9391-431467A11084}.All|x64.ActiveCfg = Release|x64
+ {0AD1177E-1FD8-4643-9391-431467A11084}.All|x64.Build.0 = Release|x64
+ {0AD1177E-1FD8-4643-9391-431467A11084}.All|x64 Setup.ActiveCfg = Release|x64
+ {0AD1177E-1FD8-4643-9391-431467A11084}.All|x64 Setup.Build.0 = Release|x64
+ {0AD1177E-1FD8-4643-9391-431467A11084}.All|x86 Setup.ActiveCfg = Release|x64
+ {0AD1177E-1FD8-4643-9391-431467A11084}.Debug|Win32.ActiveCfg = Debug|Win32
+ {0AD1177E-1FD8-4643-9391-431467A11084}.Debug|Win32.Build.0 = Debug|Win32
+ {0AD1177E-1FD8-4643-9391-431467A11084}.Debug|x64.ActiveCfg = Debug|x64
+ {0AD1177E-1FD8-4643-9391-431467A11084}.Debug|x64.Build.0 = Debug|x64
+ {0AD1177E-1FD8-4643-9391-431467A11084}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {0AD1177E-1FD8-4643-9391-431467A11084}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {0AD1177E-1FD8-4643-9391-431467A11084}.Release|Win32.ActiveCfg = Release|Win32
+ {0AD1177E-1FD8-4643-9391-431467A11084}.Release|Win32.Build.0 = Release|Win32
+ {0AD1177E-1FD8-4643-9391-431467A11084}.Release|x64.ActiveCfg = Release|x64
+ {0AD1177E-1FD8-4643-9391-431467A11084}.Release|x64.Build.0 = Release|x64
+ {0AD1177E-1FD8-4643-9391-431467A11084}.Release|x64 Setup.ActiveCfg = Release|x64
+ {0AD1177E-1FD8-4643-9391-431467A11084}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {66444AEE-554C-11DD-A9F0-8C5D56D89593}.All|Win32.ActiveCfg = Release Static|x64
+ {66444AEE-554C-11DD-A9F0-8C5D56D89593}.All|x64.ActiveCfg = Release Static|x64
+ {66444AEE-554C-11DD-A9F0-8C5D56D89593}.All|x64.Build.0 = Release Static|x64
+ {66444AEE-554C-11DD-A9F0-8C5D56D89593}.All|x64 Setup.ActiveCfg = Release Static|x64
+ {66444AEE-554C-11DD-A9F0-8C5D56D89593}.All|x64 Setup.Build.0 = Release Static|x64
+ {66444AEE-554C-11DD-A9F0-8C5D56D89593}.All|x86 Setup.ActiveCfg = Release Static|x64
+ {66444AEE-554C-11DD-A9F0-8C5D56D89593}.Debug|Win32.ActiveCfg = Debug|Win32
+ {66444AEE-554C-11DD-A9F0-8C5D56D89593}.Debug|Win32.Build.0 = Debug|Win32
+ {66444AEE-554C-11DD-A9F0-8C5D56D89593}.Debug|x64.ActiveCfg = Debug|x64
+ {66444AEE-554C-11DD-A9F0-8C5D56D89593}.Debug|x64.Build.0 = Debug|x64
+ {66444AEE-554C-11DD-A9F0-8C5D56D89593}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {66444AEE-554C-11DD-A9F0-8C5D56D89593}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {66444AEE-554C-11DD-A9F0-8C5D56D89593}.Release|Win32.ActiveCfg = Release|Win32
+ {66444AEE-554C-11DD-A9F0-8C5D56D89593}.Release|Win32.Build.0 = Release|Win32
+ {66444AEE-554C-11DD-A9F0-8C5D56D89593}.Release|x64.ActiveCfg = Release|x64
+ {66444AEE-554C-11DD-A9F0-8C5D56D89593}.Release|x64.Build.0 = Release|x64
+ {66444AEE-554C-11DD-A9F0-8C5D56D89593}.Release|x64 Setup.ActiveCfg = Release|x64
+ {66444AEE-554C-11DD-A9F0-8C5D56D89593}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}.All|Win32.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}.All|Win32.Build.0 = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}.All|x64.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}.All|x64.Build.0 = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}.All|x64 Setup.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}.All|x64 Setup.Build.0 = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}.All|x86 Setup.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}.All|x86 Setup.Build.0 = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}.Debug|Win32.Build.0 = Debug|Win32
+ {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}.Debug|x64.ActiveCfg = Debug|Win32
+ {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}.Debug|x64.Build.0 = Debug|Win32
+ {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}.Debug|x64 Setup.ActiveCfg = Debug|Win32
+ {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}.Release|Win32.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}.Release|Win32.Build.0 = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}.Release|x64.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}.Release|x64.Build.0 = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}.Release|x64 Setup.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.All|Win32.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.All|Win32.Build.0 = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.All|x64.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.All|x64.Build.0 = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.All|x64 Setup.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.All|x64 Setup.Build.0 = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.All|x86 Setup.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.All|x86 Setup.Build.0 = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.Debug|Win32.Build.0 = Debug|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.Debug|x64.ActiveCfg = Debug|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.Debug|x64.Build.0 = Debug|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.Debug|x64 Setup.ActiveCfg = Debug|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.Release|Win32.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.Release|Win32.Build.0 = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.Release|x64.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.Release|x64.Build.0 = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.Release|x64 Setup.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}.All|Win32.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}.All|Win32.Build.0 = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}.All|x64.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}.All|x64.Build.0 = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}.All|x64 Setup.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}.All|x64 Setup.Build.0 = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}.All|x86 Setup.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}.All|x86 Setup.Build.0 = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}.Debug|Win32.Build.0 = Debug|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}.Debug|x64.ActiveCfg = Debug|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}.Debug|x64.Build.0 = Debug|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}.Debug|x64 Setup.ActiveCfg = Debug|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}.Release|Win32.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}.Release|Win32.Build.0 = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}.Release|x64.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}.Release|x64.Build.0 = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}.Release|x64 Setup.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}.All|Win32.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}.All|Win32.Build.0 = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}.All|x64.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}.All|x64.Build.0 = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}.All|x64 Setup.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}.All|x64 Setup.Build.0 = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}.All|x86 Setup.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}.All|x86 Setup.Build.0 = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}.Debug|Win32.Build.0 = Debug|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}.Debug|x64.ActiveCfg = Debug|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}.Debug|x64.Build.0 = Debug|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}.Debug|x64 Setup.ActiveCfg = Debug|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}.Release|Win32.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}.Release|Win32.Build.0 = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}.Release|x64.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}.Release|x64.Build.0 = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}.Release|x64 Setup.ActiveCfg = Release|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {E316772F-5D8F-4F2A-8F71-094C3E859D34}.All|Win32.ActiveCfg = Debug|x64
+ {E316772F-5D8F-4F2A-8F71-094C3E859D34}.All|x64.ActiveCfg = Debug|x64
+ {E316772F-5D8F-4F2A-8F71-094C3E859D34}.All|x64.Build.0 = Debug|x64
+ {E316772F-5D8F-4F2A-8F71-094C3E859D34}.All|x64 Setup.ActiveCfg = Debug|x64
+ {E316772F-5D8F-4F2A-8F71-094C3E859D34}.All|x64 Setup.Build.0 = Debug|x64
+ {E316772F-5D8F-4F2A-8F71-094C3E859D34}.All|x86 Setup.ActiveCfg = Debug|x64
+ {E316772F-5D8F-4F2A-8F71-094C3E859D34}.Debug|Win32.ActiveCfg = Debug|Win32
+ {E316772F-5D8F-4F2A-8F71-094C3E859D34}.Debug|Win32.Build.0 = Debug|Win32
+ {E316772F-5D8F-4F2A-8F71-094C3E859D34}.Debug|x64.ActiveCfg = Debug|x64
+ {E316772F-5D8F-4F2A-8F71-094C3E859D34}.Debug|x64.Build.0 = Debug|x64
+ {E316772F-5D8F-4F2A-8F71-094C3E859D34}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {E316772F-5D8F-4F2A-8F71-094C3E859D34}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {E316772F-5D8F-4F2A-8F71-094C3E859D34}.Release|Win32.ActiveCfg = Release|Win32
+ {E316772F-5D8F-4F2A-8F71-094C3E859D34}.Release|Win32.Build.0 = Release|Win32
+ {E316772F-5D8F-4F2A-8F71-094C3E859D34}.Release|x64.ActiveCfg = Release|x64
+ {E316772F-5D8F-4F2A-8F71-094C3E859D34}.Release|x64.Build.0 = Release|x64
+ {E316772F-5D8F-4F2A-8F71-094C3E859D34}.Release|x64 Setup.ActiveCfg = Release|x64
+ {E316772F-5D8F-4F2A-8F71-094C3E859D34}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {D3D8B329-20BE-475E-9E83-653CEA0E0EF5}.All|Win32.ActiveCfg = Debug|x64
+ {D3D8B329-20BE-475E-9E83-653CEA0E0EF5}.All|x64.ActiveCfg = Debug|x64
+ {D3D8B329-20BE-475E-9E83-653CEA0E0EF5}.All|x64.Build.0 = Debug|x64
+ {D3D8B329-20BE-475E-9E83-653CEA0E0EF5}.All|x64 Setup.ActiveCfg = Debug|x64
+ {D3D8B329-20BE-475E-9E83-653CEA0E0EF5}.All|x64 Setup.Build.0 = Debug|x64
+ {D3D8B329-20BE-475E-9E83-653CEA0E0EF5}.All|x86 Setup.ActiveCfg = Debug|x64
+ {D3D8B329-20BE-475E-9E83-653CEA0E0EF5}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D3D8B329-20BE-475E-9E83-653CEA0E0EF5}.Debug|Win32.Build.0 = Debug|Win32
+ {D3D8B329-20BE-475E-9E83-653CEA0E0EF5}.Debug|x64.ActiveCfg = Debug|x64
+ {D3D8B329-20BE-475E-9E83-653CEA0E0EF5}.Debug|x64.Build.0 = Debug|x64
+ {D3D8B329-20BE-475E-9E83-653CEA0E0EF5}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {D3D8B329-20BE-475E-9E83-653CEA0E0EF5}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {D3D8B329-20BE-475E-9E83-653CEA0E0EF5}.Release|Win32.ActiveCfg = Release|Win32
+ {D3D8B329-20BE-475E-9E83-653CEA0E0EF5}.Release|Win32.Build.0 = Release|Win32
+ {D3D8B329-20BE-475E-9E83-653CEA0E0EF5}.Release|x64.ActiveCfg = Release|x64
+ {D3D8B329-20BE-475E-9E83-653CEA0E0EF5}.Release|x64.Build.0 = Release|x64
+ {D3D8B329-20BE-475E-9E83-653CEA0E0EF5}.Release|x64 Setup.ActiveCfg = Release|x64
+ {D3D8B329-20BE-475E-9E83-653CEA0E0EF5}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {38FE0559-9910-43A8-9E45-3E5004C27692}.All|Win32.ActiveCfg = Release|x64
+ {38FE0559-9910-43A8-9E45-3E5004C27692}.All|x64.ActiveCfg = Release|x64
+ {38FE0559-9910-43A8-9E45-3E5004C27692}.All|x64.Build.0 = Release|x64
+ {38FE0559-9910-43A8-9E45-3E5004C27692}.All|x64 Setup.ActiveCfg = Release|x64
+ {38FE0559-9910-43A8-9E45-3E5004C27692}.All|x64 Setup.Build.0 = Release|x64
+ {38FE0559-9910-43A8-9E45-3E5004C27692}.All|x86 Setup.ActiveCfg = Release|x64
+ {38FE0559-9910-43A8-9E45-3E5004C27692}.Debug|Win32.ActiveCfg = Debug|Win32
+ {38FE0559-9910-43A8-9E45-3E5004C27692}.Debug|Win32.Build.0 = Debug|Win32
+ {38FE0559-9910-43A8-9E45-3E5004C27692}.Debug|x64.ActiveCfg = Debug|x64
+ {38FE0559-9910-43A8-9E45-3E5004C27692}.Debug|x64.Build.0 = Debug|x64
+ {38FE0559-9910-43A8-9E45-3E5004C27692}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {38FE0559-9910-43A8-9E45-3E5004C27692}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {38FE0559-9910-43A8-9E45-3E5004C27692}.Release|Win32.ActiveCfg = Release|Win32
+ {38FE0559-9910-43A8-9E45-3E5004C27692}.Release|Win32.Build.0 = Release|Win32
+ {38FE0559-9910-43A8-9E45-3E5004C27692}.Release|x64.ActiveCfg = Release|x64
+ {38FE0559-9910-43A8-9E45-3E5004C27692}.Release|x64.Build.0 = Release|x64
+ {38FE0559-9910-43A8-9E45-3E5004C27692}.Release|x64 Setup.ActiveCfg = Release|x64
+ {38FE0559-9910-43A8-9E45-3E5004C27692}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4}.All|Win32.ActiveCfg = Debug|x64
+ {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4}.All|x64.ActiveCfg = Debug|x64
+ {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4}.All|x64.Build.0 = Debug|x64
+ {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4}.All|x64 Setup.ActiveCfg = Debug|x64
+ {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4}.All|x64 Setup.Build.0 = Debug|x64
+ {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4}.All|x86 Setup.ActiveCfg = Debug|x64
+ {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4}.Debug|Win32.ActiveCfg = Debug|Win32
+ {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4}.Debug|Win32.Build.0 = Debug|Win32
+ {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4}.Debug|x64.ActiveCfg = Debug|x64
+ {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4}.Debug|x64.Build.0 = Debug|x64
+ {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4}.Release|Win32.ActiveCfg = Release|Win32
+ {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4}.Release|Win32.Build.0 = Release|Win32
+ {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4}.Release|x64.ActiveCfg = Release|x64
+ {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4}.Release|x64.Build.0 = Release|x64
+ {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4}.Release|x64 Setup.ActiveCfg = Release|x64
+ {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {2A3D00C6-588D-4E86-81AC-9EF5EDE86E03}.All|Win32.ActiveCfg = Release|x64
+ {2A3D00C6-588D-4E86-81AC-9EF5EDE86E03}.All|x64.ActiveCfg = Release|x64
+ {2A3D00C6-588D-4E86-81AC-9EF5EDE86E03}.All|x64.Build.0 = Release|x64
+ {2A3D00C6-588D-4E86-81AC-9EF5EDE86E03}.All|x64 Setup.ActiveCfg = Release|x64
+ {2A3D00C6-588D-4E86-81AC-9EF5EDE86E03}.All|x64 Setup.Build.0 = Release|x64
+ {2A3D00C6-588D-4E86-81AC-9EF5EDE86E03}.All|x86 Setup.ActiveCfg = Release|x64
+ {2A3D00C6-588D-4E86-81AC-9EF5EDE86E03}.Debug|Win32.ActiveCfg = Debug|Win32
+ {2A3D00C6-588D-4E86-81AC-9EF5EDE86E03}.Debug|Win32.Build.0 = Debug|Win32
+ {2A3D00C6-588D-4E86-81AC-9EF5EDE86E03}.Debug|x64.ActiveCfg = Debug|x64
+ {2A3D00C6-588D-4E86-81AC-9EF5EDE86E03}.Debug|x64.Build.0 = Debug|x64
+ {2A3D00C6-588D-4E86-81AC-9EF5EDE86E03}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {2A3D00C6-588D-4E86-81AC-9EF5EDE86E03}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {2A3D00C6-588D-4E86-81AC-9EF5EDE86E03}.Release|Win32.ActiveCfg = Release|Win32
+ {2A3D00C6-588D-4E86-81AC-9EF5EDE86E03}.Release|Win32.Build.0 = Release|Win32
+ {2A3D00C6-588D-4E86-81AC-9EF5EDE86E03}.Release|x64.ActiveCfg = Release|x64
+ {2A3D00C6-588D-4E86-81AC-9EF5EDE86E03}.Release|x64.Build.0 = Release|x64
+ {2A3D00C6-588D-4E86-81AC-9EF5EDE86E03}.Release|x64 Setup.ActiveCfg = Release|x64
+ {2A3D00C6-588D-4E86-81AC-9EF5EDE86E03}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E}.All|Win32.ActiveCfg = Release|x64
+ {B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E}.All|x64.ActiveCfg = Release|x64
+ {B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E}.All|x64.Build.0 = Release|x64
+ {B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E}.All|x64 Setup.ActiveCfg = Release|x64
+ {B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E}.All|x64 Setup.Build.0 = Release|x64
+ {B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E}.All|x86 Setup.ActiveCfg = Release|x64
+ {B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E}.Debug|Win32.ActiveCfg = Debug|Win32
+ {B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E}.Debug|Win32.Build.0 = Debug|Win32
+ {B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E}.Debug|x64.ActiveCfg = Debug|x64
+ {B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E}.Debug|x64.Build.0 = Debug|x64
+ {B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E}.Release|Win32.ActiveCfg = Release|Win32
+ {B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E}.Release|Win32.Build.0 = Release|Win32
+ {B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E}.Release|x64.ActiveCfg = Release|x64
+ {B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E}.Release|x64.Build.0 = Release|x64
+ {B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E}.Release|x64 Setup.ActiveCfg = Release|x64
+ {B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {7B42BDA1-72C0-4378-A9B6-5C530F8CD61E}.All|Win32.ActiveCfg = Release_Mono|x64
+ {7B42BDA1-72C0-4378-A9B6-5C530F8CD61E}.All|x64.ActiveCfg = Release_Mono|x64
+ {7B42BDA1-72C0-4378-A9B6-5C530F8CD61E}.All|x64.Build.0 = Release_Mono|x64
+ {7B42BDA1-72C0-4378-A9B6-5C530F8CD61E}.All|x64 Setup.ActiveCfg = Release_Mono|x64
+ {7B42BDA1-72C0-4378-A9B6-5C530F8CD61E}.All|x64 Setup.Build.0 = Release_Mono|x64
+ {7B42BDA1-72C0-4378-A9B6-5C530F8CD61E}.All|x86 Setup.ActiveCfg = Release_Mono|x64
+ {7B42BDA1-72C0-4378-A9B6-5C530F8CD61E}.Debug|Win32.ActiveCfg = Debug_CLR|Win32
+ {7B42BDA1-72C0-4378-A9B6-5C530F8CD61E}.Debug|Win32.Build.0 = Debug_CLR|Win32
+ {7B42BDA1-72C0-4378-A9B6-5C530F8CD61E}.Debug|x64.ActiveCfg = Debug_CLR|x64
+ {7B42BDA1-72C0-4378-A9B6-5C530F8CD61E}.Debug|x64.Build.0 = Debug_CLR|x64
+ {7B42BDA1-72C0-4378-A9B6-5C530F8CD61E}.Debug|x64 Setup.ActiveCfg = Debug_CLR|x64
+ {7B42BDA1-72C0-4378-A9B6-5C530F8CD61E}.Debug|x86 Setup.ActiveCfg = Debug_CLR|Win32
+ {7B42BDA1-72C0-4378-A9B6-5C530F8CD61E}.Release|Win32.ActiveCfg = Release_CLR|Win32
+ {7B42BDA1-72C0-4378-A9B6-5C530F8CD61E}.Release|Win32.Build.0 = Release_CLR|Win32
+ {7B42BDA1-72C0-4378-A9B6-5C530F8CD61E}.Release|x64.ActiveCfg = Release_CLR|x64
+ {7B42BDA1-72C0-4378-A9B6-5C530F8CD61E}.Release|x64.Build.0 = Release_CLR|x64
+ {7B42BDA1-72C0-4378-A9B6-5C530F8CD61E}.Release|x64 Setup.ActiveCfg = Release_CLR|x64
+ {7B42BDA1-72C0-4378-A9B6-5C530F8CD61E}.Release|x86 Setup.ActiveCfg = Release_CLR|Win32
+ {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.All|Win32.ActiveCfg = Release|Any CPU
+ {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.All|x64.ActiveCfg = Release|Any CPU
+ {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.All|x64 Setup.ActiveCfg = Release|Any CPU
+ {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.All|x86 Setup.ActiveCfg = Release|Any CPU
+ {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.Debug|Win32.Build.0 = Debug|Any CPU
+ {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.Debug|x64.ActiveCfg = Debug|x64
+ {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.Debug|x64.Build.0 = Debug|x64
+ {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.Debug|x86 Setup.ActiveCfg = Debug|Any CPU
+ {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.Release|Win32.ActiveCfg = Release|Any CPU
+ {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.Release|Win32.Build.0 = Release|Any CPU
+ {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.Release|x64.ActiveCfg = Release|x64
+ {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.Release|x64.Build.0 = Release|x64
+ {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.Release|x64 Setup.ActiveCfg = Release|x64
+ {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.Release|x86 Setup.ActiveCfg = Release|Any CPU
+ {E796E337-DE78-4303-8614-9A590862EE95}.All|Win32.ActiveCfg = Release|Win32
+ {E796E337-DE78-4303-8614-9A590862EE95}.All|Win32.Build.0 = Release|Win32
+ {E796E337-DE78-4303-8614-9A590862EE95}.All|x64.ActiveCfg = Release|Win32
+ {E796E337-DE78-4303-8614-9A590862EE95}.All|x64.Build.0 = Release|Win32
+ {E796E337-DE78-4303-8614-9A590862EE95}.All|x64 Setup.ActiveCfg = Release|Win32
+ {E796E337-DE78-4303-8614-9A590862EE95}.All|x64 Setup.Build.0 = Release|Win32
+ {E796E337-DE78-4303-8614-9A590862EE95}.All|x86 Setup.ActiveCfg = Release|Win32
+ {E796E337-DE78-4303-8614-9A590862EE95}.All|x86 Setup.Build.0 = Release|Win32
+ {E796E337-DE78-4303-8614-9A590862EE95}.Debug|Win32.ActiveCfg = Debug|Win32
+ {E796E337-DE78-4303-8614-9A590862EE95}.Debug|Win32.Build.0 = Debug|Win32
+ {E796E337-DE78-4303-8614-9A590862EE95}.Debug|x64.ActiveCfg = Debug|Win32
+ {E796E337-DE78-4303-8614-9A590862EE95}.Debug|x64.Build.0 = Debug|Win32
+ {E796E337-DE78-4303-8614-9A590862EE95}.Debug|x64 Setup.ActiveCfg = Debug|Win32
+ {E796E337-DE78-4303-8614-9A590862EE95}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {E796E337-DE78-4303-8614-9A590862EE95}.Release|Win32.ActiveCfg = Release|Win32
+ {E796E337-DE78-4303-8614-9A590862EE95}.Release|Win32.Build.0 = Release|Win32
+ {E796E337-DE78-4303-8614-9A590862EE95}.Release|x64.ActiveCfg = Release|Win32
+ {E796E337-DE78-4303-8614-9A590862EE95}.Release|x64.Build.0 = Release|Win32
+ {E796E337-DE78-4303-8614-9A590862EE95}.Release|x64 Setup.ActiveCfg = Release|Win32
+ {E796E337-DE78-4303-8614-9A590862EE95}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {419C8F80-D858-4B48-A25C-AF4007608137}.All|Win32.ActiveCfg = Debug_Generic_Dll|Win32
+ {419C8F80-D858-4B48-A25C-AF4007608137}.All|Win32.Build.0 = Debug_Generic_Dll|Win32
+ {419C8F80-D858-4B48-A25C-AF4007608137}.All|x64.ActiveCfg = Debug_Generic_Dll|Win32
+ {419C8F80-D858-4B48-A25C-AF4007608137}.All|x64 Setup.ActiveCfg = Debug_Generic_Dll|Win32
+ {419C8F80-D858-4B48-A25C-AF4007608137}.All|x86 Setup.ActiveCfg = Debug_Generic_Dll|Win32
+ {419C8F80-D858-4B48-A25C-AF4007608137}.Debug|Win32.ActiveCfg = Debug_Generic|Win32
+ {419C8F80-D858-4B48-A25C-AF4007608137}.Debug|Win32.Build.0 = Debug_Generic|Win32
+ {419C8F80-D858-4B48-A25C-AF4007608137}.Debug|x64.ActiveCfg = Debug_Generic|x64
+ {419C8F80-D858-4B48-A25C-AF4007608137}.Debug|x64.Build.0 = Debug_Generic|x64
+ {419C8F80-D858-4B48-A25C-AF4007608137}.Debug|x64 Setup.ActiveCfg = Debug_Generic_Dll|Win32
+ {419C8F80-D858-4B48-A25C-AF4007608137}.Debug|x86 Setup.ActiveCfg = Debug_Generic_Dll|Win32
+ {419C8F80-D858-4B48-A25C-AF4007608137}.Release|Win32.ActiveCfg = Release_Generic|Win32
+ {419C8F80-D858-4B48-A25C-AF4007608137}.Release|Win32.Build.0 = Release_Generic|Win32
+ {419C8F80-D858-4B48-A25C-AF4007608137}.Release|x64.ActiveCfg = Release_Generic|x64
+ {419C8F80-D858-4B48-A25C-AF4007608137}.Release|x64.Build.0 = Release_Generic|x64
+ {419C8F80-D858-4B48-A25C-AF4007608137}.Release|x64 Setup.ActiveCfg = Release_Generic_Dll|Win32
+ {419C8F80-D858-4B48-A25C-AF4007608137}.Release|x86 Setup.ActiveCfg = Release_Generic_Dll|Win32
+ {B3F424EC-3D8F-417C-B244-3919D5E1A577}.All|Win32.ActiveCfg = Release|x64
+ {B3F424EC-3D8F-417C-B244-3919D5E1A577}.All|x64.ActiveCfg = Release|x64
+ {B3F424EC-3D8F-417C-B244-3919D5E1A577}.All|x64.Build.0 = Release|x64
+ {B3F424EC-3D8F-417C-B244-3919D5E1A577}.All|x64 Setup.ActiveCfg = Release|x64
+ {B3F424EC-3D8F-417C-B244-3919D5E1A577}.All|x64 Setup.Build.0 = Release|x64
+ {B3F424EC-3D8F-417C-B244-3919D5E1A577}.All|x86 Setup.ActiveCfg = Release|x64
+ {B3F424EC-3D8F-417C-B244-3919D5E1A577}.Debug|Win32.ActiveCfg = Debug|Win32
+ {B3F424EC-3D8F-417C-B244-3919D5E1A577}.Debug|Win32.Build.0 = Debug|Win32
+ {B3F424EC-3D8F-417C-B244-3919D5E1A577}.Debug|x64.ActiveCfg = Debug|x64
+ {B3F424EC-3D8F-417C-B244-3919D5E1A577}.Debug|x64.Build.0 = Debug|x64
+ {B3F424EC-3D8F-417C-B244-3919D5E1A577}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {B3F424EC-3D8F-417C-B244-3919D5E1A577}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {B3F424EC-3D8F-417C-B244-3919D5E1A577}.Release|Win32.ActiveCfg = Release|Win32
+ {B3F424EC-3D8F-417C-B244-3919D5E1A577}.Release|Win32.Build.0 = Release|Win32
+ {B3F424EC-3D8F-417C-B244-3919D5E1A577}.Release|x64.ActiveCfg = Release|x64
+ {B3F424EC-3D8F-417C-B244-3919D5E1A577}.Release|x64.Build.0 = Release|x64
+ {B3F424EC-3D8F-417C-B244-3919D5E1A577}.Release|x64 Setup.ActiveCfg = Release|x64
+ {B3F424EC-3D8F-417C-B244-3919D5E1A577}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {14E4A972-9CFB-436D-B0A5-4943F3F80D47}.All|Win32.ActiveCfg = Release|x64
+ {14E4A972-9CFB-436D-B0A5-4943F3F80D47}.All|x64.ActiveCfg = Release|x64
+ {14E4A972-9CFB-436D-B0A5-4943F3F80D47}.All|x64.Build.0 = Release|x64
+ {14E4A972-9CFB-436D-B0A5-4943F3F80D47}.All|x64 Setup.ActiveCfg = Release|x64
+ {14E4A972-9CFB-436D-B0A5-4943F3F80D47}.All|x64 Setup.Build.0 = Release|x64
+ {14E4A972-9CFB-436D-B0A5-4943F3F80D47}.All|x86 Setup.ActiveCfg = Release|x64
+ {14E4A972-9CFB-436D-B0A5-4943F3F80D47}.Debug|Win32.ActiveCfg = Debug|Win32
+ {14E4A972-9CFB-436D-B0A5-4943F3F80D47}.Debug|Win32.Build.0 = Debug|Win32
+ {14E4A972-9CFB-436D-B0A5-4943F3F80D47}.Debug|x64.ActiveCfg = Debug|x64
+ {14E4A972-9CFB-436D-B0A5-4943F3F80D47}.Debug|x64.Build.0 = Debug|x64
+ {14E4A972-9CFB-436D-B0A5-4943F3F80D47}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {14E4A972-9CFB-436D-B0A5-4943F3F80D47}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {14E4A972-9CFB-436D-B0A5-4943F3F80D47}.Release|Win32.ActiveCfg = Release|Win32
+ {14E4A972-9CFB-436D-B0A5-4943F3F80D47}.Release|Win32.Build.0 = Release|Win32
+ {14E4A972-9CFB-436D-B0A5-4943F3F80D47}.Release|x64.ActiveCfg = Release|x64
+ {14E4A972-9CFB-436D-B0A5-4943F3F80D47}.Release|x64.Build.0 = Release|x64
+ {14E4A972-9CFB-436D-B0A5-4943F3F80D47}.Release|x64 Setup.ActiveCfg = Release|x64
+ {14E4A972-9CFB-436D-B0A5-4943F3F80D47}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C}.All|Win32.ActiveCfg = Release|x64
+ {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C}.All|x64.ActiveCfg = Release|x64
+ {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C}.All|x64.Build.0 = Release|x64
+ {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C}.All|x64 Setup.ActiveCfg = Release|x64
+ {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C}.All|x64 Setup.Build.0 = Release|x64
+ {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C}.All|x86 Setup.ActiveCfg = Release|x64
+ {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C}.Debug|Win32.ActiveCfg = Debug|Win32
+ {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C}.Debug|Win32.Build.0 = Debug|Win32
+ {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C}.Debug|x64.ActiveCfg = Debug|x64
+ {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C}.Debug|x64.Build.0 = Debug|x64
+ {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C}.Release|Win32.ActiveCfg = Release|Win32
+ {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C}.Release|Win32.Build.0 = Release|Win32
+ {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C}.Release|x64.ActiveCfg = Release|x64
+ {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C}.Release|x64.Build.0 = Release|x64
+ {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C}.Release|x64 Setup.ActiveCfg = Release|x64
+ {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {0B6C905B-142E-4999-B39D-92FF7951E921}.All|Win32.ActiveCfg = Release|x64
+ {0B6C905B-142E-4999-B39D-92FF7951E921}.All|x64.ActiveCfg = Release|x64
+ {0B6C905B-142E-4999-B39D-92FF7951E921}.All|x64.Build.0 = Release|x64
+ {0B6C905B-142E-4999-B39D-92FF7951E921}.All|x64 Setup.ActiveCfg = Release|x64
+ {0B6C905B-142E-4999-B39D-92FF7951E921}.All|x64 Setup.Build.0 = Release|x64
+ {0B6C905B-142E-4999-B39D-92FF7951E921}.All|x86 Setup.ActiveCfg = Release|x64
+ {0B6C905B-142E-4999-B39D-92FF7951E921}.Debug|Win32.ActiveCfg = Debug|Win32
+ {0B6C905B-142E-4999-B39D-92FF7951E921}.Debug|Win32.Build.0 = Debug|Win32
+ {0B6C905B-142E-4999-B39D-92FF7951E921}.Debug|x64.ActiveCfg = Debug|x64
+ {0B6C905B-142E-4999-B39D-92FF7951E921}.Debug|x64.Build.0 = Debug|x64
+ {0B6C905B-142E-4999-B39D-92FF7951E921}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {0B6C905B-142E-4999-B39D-92FF7951E921}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {0B6C905B-142E-4999-B39D-92FF7951E921}.Release|Win32.ActiveCfg = Release|Win32
+ {0B6C905B-142E-4999-B39D-92FF7951E921}.Release|Win32.Build.0 = Release|Win32
+ {0B6C905B-142E-4999-B39D-92FF7951E921}.Release|x64.ActiveCfg = Release|x64
+ {0B6C905B-142E-4999-B39D-92FF7951E921}.Release|x64.Build.0 = Release|x64
+ {0B6C905B-142E-4999-B39D-92FF7951E921}.Release|x64 Setup.ActiveCfg = Release|x64
+ {0B6C905B-142E-4999-B39D-92FF7951E921}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {CF405366-9558-4AE8-90EF-5E21B51CCB4E}.All|Win32.ActiveCfg = Release|x64
+ {CF405366-9558-4AE8-90EF-5E21B51CCB4E}.All|x64.ActiveCfg = Release|x64
+ {CF405366-9558-4AE8-90EF-5E21B51CCB4E}.All|x64.Build.0 = Release|x64
+ {CF405366-9558-4AE8-90EF-5E21B51CCB4E}.All|x64 Setup.ActiveCfg = Release|x64
+ {CF405366-9558-4AE8-90EF-5E21B51CCB4E}.All|x64 Setup.Build.0 = Release|x64
+ {CF405366-9558-4AE8-90EF-5E21B51CCB4E}.All|x86 Setup.ActiveCfg = Release|x64
+ {CF405366-9558-4AE8-90EF-5E21B51CCB4E}.Debug|Win32.ActiveCfg = Debug|Win32
+ {CF405366-9558-4AE8-90EF-5E21B51CCB4E}.Debug|Win32.Build.0 = Debug|Win32
+ {CF405366-9558-4AE8-90EF-5E21B51CCB4E}.Debug|x64.ActiveCfg = Debug|x64
+ {CF405366-9558-4AE8-90EF-5E21B51CCB4E}.Debug|x64.Build.0 = Debug|x64
+ {CF405366-9558-4AE8-90EF-5E21B51CCB4E}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {CF405366-9558-4AE8-90EF-5E21B51CCB4E}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {CF405366-9558-4AE8-90EF-5E21B51CCB4E}.Release|Win32.ActiveCfg = Release|Win32
+ {CF405366-9558-4AE8-90EF-5E21B51CCB4E}.Release|Win32.Build.0 = Release|Win32
+ {CF405366-9558-4AE8-90EF-5E21B51CCB4E}.Release|x64.ActiveCfg = Release|x64
+ {CF405366-9558-4AE8-90EF-5E21B51CCB4E}.Release|x64.Build.0 = Release|x64
+ {CF405366-9558-4AE8-90EF-5E21B51CCB4E}.Release|x64 Setup.ActiveCfg = Release|x64
+ {CF405366-9558-4AE8-90EF-5E21B51CCB4E}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {D2FB8043-D208-4AEE-8F18-3B5857C871B9}.All|Win32.ActiveCfg = Release|x64
+ {D2FB8043-D208-4AEE-8F18-3B5857C871B9}.All|x64.ActiveCfg = Release|x64
+ {D2FB8043-D208-4AEE-8F18-3B5857C871B9}.All|x64.Build.0 = Release|x64
+ {D2FB8043-D208-4AEE-8F18-3B5857C871B9}.All|x64 Setup.ActiveCfg = Release|x64
+ {D2FB8043-D208-4AEE-8F18-3B5857C871B9}.All|x64 Setup.Build.0 = Release|x64
+ {D2FB8043-D208-4AEE-8F18-3B5857C871B9}.All|x86 Setup.ActiveCfg = Release|x64
+ {D2FB8043-D208-4AEE-8F18-3B5857C871B9}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D2FB8043-D208-4AEE-8F18-3B5857C871B9}.Debug|Win32.Build.0 = Debug|Win32
+ {D2FB8043-D208-4AEE-8F18-3B5857C871B9}.Debug|x64.ActiveCfg = Debug|x64
+ {D2FB8043-D208-4AEE-8F18-3B5857C871B9}.Debug|x64.Build.0 = Debug|x64
+ {D2FB8043-D208-4AEE-8F18-3B5857C871B9}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {D2FB8043-D208-4AEE-8F18-3B5857C871B9}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {D2FB8043-D208-4AEE-8F18-3B5857C871B9}.Release|Win32.ActiveCfg = Release|Win32
+ {D2FB8043-D208-4AEE-8F18-3B5857C871B9}.Release|Win32.Build.0 = Release|Win32
+ {D2FB8043-D208-4AEE-8F18-3B5857C871B9}.Release|x64.ActiveCfg = Release|x64
+ {D2FB8043-D208-4AEE-8F18-3B5857C871B9}.Release|x64.Build.0 = Release|x64
+ {D2FB8043-D208-4AEE-8F18-3B5857C871B9}.Release|x64 Setup.ActiveCfg = Release|x64
+ {D2FB8043-D208-4AEE-8F18-3B5857C871B9}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {329FD5B0-EF28-4606-86D0-F6EA21CF8E36}.All|Win32.ActiveCfg = Release|x64
+ {329FD5B0-EF28-4606-86D0-F6EA21CF8E36}.All|x64.ActiveCfg = Release|x64
+ {329FD5B0-EF28-4606-86D0-F6EA21CF8E36}.All|x64.Build.0 = Release|x64
+ {329FD5B0-EF28-4606-86D0-F6EA21CF8E36}.All|x64 Setup.ActiveCfg = Release|x64
+ {329FD5B0-EF28-4606-86D0-F6EA21CF8E36}.All|x64 Setup.Build.0 = Release|x64
+ {329FD5B0-EF28-4606-86D0-F6EA21CF8E36}.All|x86 Setup.ActiveCfg = Release|x64
+ {329FD5B0-EF28-4606-86D0-F6EA21CF8E36}.Debug|Win32.ActiveCfg = Debug|Win32
+ {329FD5B0-EF28-4606-86D0-F6EA21CF8E36}.Debug|Win32.Build.0 = Debug|Win32
+ {329FD5B0-EF28-4606-86D0-F6EA21CF8E36}.Debug|x64.ActiveCfg = Debug|x64
+ {329FD5B0-EF28-4606-86D0-F6EA21CF8E36}.Debug|x64.Build.0 = Debug|x64
+ {329FD5B0-EF28-4606-86D0-F6EA21CF8E36}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {329FD5B0-EF28-4606-86D0-F6EA21CF8E36}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {329FD5B0-EF28-4606-86D0-F6EA21CF8E36}.Release|Win32.ActiveCfg = Release|Win32
+ {329FD5B0-EF28-4606-86D0-F6EA21CF8E36}.Release|Win32.Build.0 = Release|Win32
+ {329FD5B0-EF28-4606-86D0-F6EA21CF8E36}.Release|x64.ActiveCfg = Release|x64
+ {329FD5B0-EF28-4606-86D0-F6EA21CF8E36}.Release|x64.Build.0 = Release|x64
+ {329FD5B0-EF28-4606-86D0-F6EA21CF8E36}.Release|x64 Setup.ActiveCfg = Release|x64
+ {329FD5B0-EF28-4606-86D0-F6EA21CF8E36}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {1A3793D1-05D1-4B57-9B0F-5AF3E79DC439}.All|Win32.ActiveCfg = Release|x64
+ {1A3793D1-05D1-4B57-9B0F-5AF3E79DC439}.All|x64.ActiveCfg = Release|x64
+ {1A3793D1-05D1-4B57-9B0F-5AF3E79DC439}.All|x64.Build.0 = Release|x64
+ {1A3793D1-05D1-4B57-9B0F-5AF3E79DC439}.All|x64 Setup.ActiveCfg = Release|x64
+ {1A3793D1-05D1-4B57-9B0F-5AF3E79DC439}.All|x64 Setup.Build.0 = Release|x64
+ {1A3793D1-05D1-4B57-9B0F-5AF3E79DC439}.All|x86 Setup.ActiveCfg = Release|x64
+ {1A3793D1-05D1-4B57-9B0F-5AF3E79DC439}.Debug|Win32.ActiveCfg = Debug|Win32
+ {1A3793D1-05D1-4B57-9B0F-5AF3E79DC439}.Debug|Win32.Build.0 = Debug|Win32
+ {1A3793D1-05D1-4B57-9B0F-5AF3E79DC439}.Debug|x64.ActiveCfg = Debug|x64
+ {1A3793D1-05D1-4B57-9B0F-5AF3E79DC439}.Debug|x64.Build.0 = Debug|x64
+ {1A3793D1-05D1-4B57-9B0F-5AF3E79DC439}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {1A3793D1-05D1-4B57-9B0F-5AF3E79DC439}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {1A3793D1-05D1-4B57-9B0F-5AF3E79DC439}.Release|Win32.ActiveCfg = Release|Win32
+ {1A3793D1-05D1-4B57-9B0F-5AF3E79DC439}.Release|Win32.Build.0 = Release|Win32
+ {1A3793D1-05D1-4B57-9B0F-5AF3E79DC439}.Release|x64.ActiveCfg = Release|x64
+ {1A3793D1-05D1-4B57-9B0F-5AF3E79DC439}.Release|x64.Build.0 = Release|x64
+ {1A3793D1-05D1-4B57-9B0F-5AF3E79DC439}.Release|x64 Setup.ActiveCfg = Release|x64
+ {1A3793D1-05D1-4B57-9B0F-5AF3E79DC439}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.All|Win32.ActiveCfg = Release|x64
+ {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.All|x64.ActiveCfg = Release|x64
+ {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.All|x64.Build.0 = Release|x64
+ {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.All|x64 Setup.ActiveCfg = Release|x64
+ {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.All|x64 Setup.Build.0 = Release|x64
+ {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.All|x86 Setup.ActiveCfg = Release|x64
+ {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.Debug|Win32.ActiveCfg = Debug|Win32
+ {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.Debug|Win32.Build.0 = Debug|Win32
+ {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.Debug|x64.ActiveCfg = Debug|x64
+ {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.Debug|x64.Build.0 = Debug|x64
+ {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.Release|Win32.ActiveCfg = Release|Win32
+ {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.Release|Win32.Build.0 = Release|Win32
+ {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.Release|x64.ActiveCfg = Release|x64
+ {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.Release|x64.Build.0 = Release|x64
+ {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.Release|x64 Setup.ActiveCfg = Release|x64
+ {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.All|Win32.ActiveCfg = Release|x64
+ {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.All|x64.ActiveCfg = Release|x64
+ {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.All|x64.Build.0 = Release|x64
+ {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.All|x64 Setup.ActiveCfg = Release|x64
+ {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.All|x64 Setup.Build.0 = Release|x64
+ {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.All|x86 Setup.ActiveCfg = Release|x64
+ {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.Debug|Win32.ActiveCfg = Debug|Win32
+ {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.Debug|Win32.Build.0 = Debug|Win32
+ {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.Debug|x64.ActiveCfg = Debug|x64
+ {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.Debug|x64.Build.0 = Debug|x64
+ {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.Release|Win32.ActiveCfg = Release|Win32
+ {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.Release|Win32.Build.0 = Release|Win32
+ {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.Release|x64.ActiveCfg = Release|x64
+ {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.Release|x64.Build.0 = Release|x64
+ {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.Release|x64 Setup.ActiveCfg = Release|x64
+ {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {E972C52F-9E85-4D65-B19C-031E511E9DB4}.All|Win32.ActiveCfg = Release_Dynamic|Win32
+ {E972C52F-9E85-4D65-B19C-031E511E9DB4}.All|Win32.Build.0 = Release_Dynamic|Win32
+ {E972C52F-9E85-4D65-B19C-031E511E9DB4}.All|x64.ActiveCfg = Release_Dynamic|x64
+ {E972C52F-9E85-4D65-B19C-031E511E9DB4}.All|x64.Build.0 = Release_Dynamic|x64
+ {E972C52F-9E85-4D65-B19C-031E511E9DB4}.All|x64 Setup.ActiveCfg = Release_Dynamic|Win32
+ {E972C52F-9E85-4D65-B19C-031E511E9DB4}.All|x86 Setup.ActiveCfg = Release_Dynamic|Win32
+ {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug|Win32.ActiveCfg = Debug|Win32
+ {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug|Win32.Build.0 = Debug|Win32
+ {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug|x64.ActiveCfg = Debug|x64
+ {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug|x64.Build.0 = Debug|x64
+ {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release|Win32.ActiveCfg = Release|Win32
+ {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release|Win32.Build.0 = Release|Win32
+ {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release|x64.ActiveCfg = Release|x64
+ {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release|x64.Build.0 = Release|x64
+ {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release|x64 Setup.ActiveCfg = Release|x64
+ {E972C52F-9E85-4D65-B19C-031E511E9DB4}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {03207781-0D1C-4DB3-A71D-45C608F28DBD}.All|Win32.ActiveCfg = Release_Static_SSE|x64
+ {03207781-0D1C-4DB3-A71D-45C608F28DBD}.All|x64.ActiveCfg = Release_Static_SSE|x64
+ {03207781-0D1C-4DB3-A71D-45C608F28DBD}.All|x64.Build.0 = Release_Static_SSE|x64
+ {03207781-0D1C-4DB3-A71D-45C608F28DBD}.All|x64 Setup.ActiveCfg = Release_Static_SSE|x64
+ {03207781-0D1C-4DB3-A71D-45C608F28DBD}.All|x64 Setup.Build.0 = Release_Static_SSE|x64
+ {03207781-0D1C-4DB3-A71D-45C608F28DBD}.All|x86 Setup.ActiveCfg = Release_Static_SSE|x64
+ {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Debug|Win32.ActiveCfg = Debug|Win32
+ {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Debug|Win32.Build.0 = Debug|Win32
+ {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Debug|x64.ActiveCfg = Debug|x64
+ {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Debug|x64.Build.0 = Debug|x64
+ {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release|Win32.ActiveCfg = Release|Win32
+ {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release|Win32.Build.0 = Release|Win32
+ {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release|x64.ActiveCfg = Release|x64
+ {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release|x64.Build.0 = Release|x64
+ {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release|x64 Setup.ActiveCfg = Release|x64
+ {03207781-0D1C-4DB3-A71D-45C608F28DBD}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {9A5DDF08-C88C-4A35-B7F6-D605228446BD}.All|Win32.ActiveCfg = Release|x64
+ {9A5DDF08-C88C-4A35-B7F6-D605228446BD}.All|x64.ActiveCfg = Release|x64
+ {9A5DDF08-C88C-4A35-B7F6-D605228446BD}.All|x64.Build.0 = Release|x64
+ {9A5DDF08-C88C-4A35-B7F6-D605228446BD}.All|x64 Setup.ActiveCfg = Release|x64
+ {9A5DDF08-C88C-4A35-B7F6-D605228446BD}.All|x64 Setup.Build.0 = Release|x64
+ {9A5DDF08-C88C-4A35-B7F6-D605228446BD}.All|x86 Setup.ActiveCfg = Release|x64
+ {9A5DDF08-C88C-4A35-B7F6-D605228446BD}.Debug|Win32.ActiveCfg = Debug|Win32
+ {9A5DDF08-C88C-4A35-B7F6-D605228446BD}.Debug|Win32.Build.0 = Debug|Win32
+ {9A5DDF08-C88C-4A35-B7F6-D605228446BD}.Debug|x64.ActiveCfg = Debug|x64
+ {9A5DDF08-C88C-4A35-B7F6-D605228446BD}.Debug|x64.Build.0 = Debug|x64
+ {9A5DDF08-C88C-4A35-B7F6-D605228446BD}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {9A5DDF08-C88C-4A35-B7F6-D605228446BD}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {9A5DDF08-C88C-4A35-B7F6-D605228446BD}.Release|Win32.ActiveCfg = Release|Win32
+ {9A5DDF08-C88C-4A35-B7F6-D605228446BD}.Release|Win32.Build.0 = Release|Win32
+ {9A5DDF08-C88C-4A35-B7F6-D605228446BD}.Release|x64.ActiveCfg = Release|x64
+ {9A5DDF08-C88C-4A35-B7F6-D605228446BD}.Release|x64.Build.0 = Release|x64
+ {9A5DDF08-C88C-4A35-B7F6-D605228446BD}.Release|x64 Setup.ActiveCfg = Release|x64
+ {9A5DDF08-C88C-4A35-B7F6-D605228446BD}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {D0B36172-CD76-454A-9B89-990025266C2A}.All|Win32.ActiveCfg = Release|x64
+ {D0B36172-CD76-454A-9B89-990025266C2A}.All|x64.ActiveCfg = Release|x64
+ {D0B36172-CD76-454A-9B89-990025266C2A}.All|x64.Build.0 = Release|x64
+ {D0B36172-CD76-454A-9B89-990025266C2A}.All|x64 Setup.ActiveCfg = Release|x64
+ {D0B36172-CD76-454A-9B89-990025266C2A}.All|x64 Setup.Build.0 = Release|x64
+ {D0B36172-CD76-454A-9B89-990025266C2A}.All|x86 Setup.ActiveCfg = Release|x64
+ {D0B36172-CD76-454A-9B89-990025266C2A}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D0B36172-CD76-454A-9B89-990025266C2A}.Debug|Win32.Build.0 = Debug|Win32
+ {D0B36172-CD76-454A-9B89-990025266C2A}.Debug|x64.ActiveCfg = Debug|x64
+ {D0B36172-CD76-454A-9B89-990025266C2A}.Debug|x64.Build.0 = Debug|x64
+ {D0B36172-CD76-454A-9B89-990025266C2A}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {D0B36172-CD76-454A-9B89-990025266C2A}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {D0B36172-CD76-454A-9B89-990025266C2A}.Release|Win32.ActiveCfg = Release|Win32
+ {D0B36172-CD76-454A-9B89-990025266C2A}.Release|Win32.Build.0 = Release|Win32
+ {D0B36172-CD76-454A-9B89-990025266C2A}.Release|x64.ActiveCfg = Release|x64
+ {D0B36172-CD76-454A-9B89-990025266C2A}.Release|x64.Build.0 = Release|x64
+ {D0B36172-CD76-454A-9B89-990025266C2A}.Release|x64 Setup.ActiveCfg = Release|x64
+ {D0B36172-CD76-454A-9B89-990025266C2A}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {05C9FB27-480E-4D53-B3B7-6338E2526666}.All|Win32.ActiveCfg = Release|Win32
+ {05C9FB27-480E-4D53-B3B7-6338E2526666}.All|Win32.Build.0 = Release|Win32
+ {05C9FB27-480E-4D53-B3B7-6338E2526666}.All|x64.ActiveCfg = Release|Win32
+ {05C9FB27-480E-4D53-B3B7-6338E2526666}.All|x64 Setup.ActiveCfg = Release|Win32
+ {05C9FB27-480E-4D53-B3B7-6338E2526666}.All|x86 Setup.ActiveCfg = Release|Win32
+ {05C9FB27-480E-4D53-B3B7-6338E2526666}.All|x86 Setup.Build.0 = Release|Win32
+ {05C9FB27-480E-4D53-B3B7-6338E2526666}.Debug|Win32.ActiveCfg = Debug|Win32
+ {05C9FB27-480E-4D53-B3B7-6338E2526666}.Debug|x64.ActiveCfg = Debug|Win32
+ {05C9FB27-480E-4D53-B3B7-6338E2526666}.Debug|x64 Setup.ActiveCfg = Debug|Win32
+ {05C9FB27-480E-4D53-B3B7-6338E2526666}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {05C9FB27-480E-4D53-B3B7-6338E2526666}.Release|Win32.ActiveCfg = Release|Win32
+ {05C9FB27-480E-4D53-B3B7-6338E2526666}.Release|x64.ActiveCfg = Release|Win32
+ {05C9FB27-480E-4D53-B3B7-6338E2526666}.Release|x64 Setup.ActiveCfg = Release|Win32
+ {05C9FB27-480E-4D53-B3B7-6338E2526666}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {CC1DD008-9406-448D-A0AD-33C3186CFADB}.All|Win32.ActiveCfg = Release|Win32
+ {CC1DD008-9406-448D-A0AD-33C3186CFADB}.All|x64.ActiveCfg = Release|Win32
+ {CC1DD008-9406-448D-A0AD-33C3186CFADB}.All|x64 Setup.ActiveCfg = Release|Win32
+ {CC1DD008-9406-448D-A0AD-33C3186CFADB}.All|x86 Setup.ActiveCfg = Release|Win32
+ {CC1DD008-9406-448D-A0AD-33C3186CFADB}.Debug|Win32.ActiveCfg = Debug|Win32
+ {CC1DD008-9406-448D-A0AD-33C3186CFADB}.Debug|Win32.Build.0 = Debug|Win32
+ {CC1DD008-9406-448D-A0AD-33C3186CFADB}.Debug|x64.ActiveCfg = Debug|x64
+ {CC1DD008-9406-448D-A0AD-33C3186CFADB}.Debug|x64.Build.0 = Debug|x64
+ {CC1DD008-9406-448D-A0AD-33C3186CFADB}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {CC1DD008-9406-448D-A0AD-33C3186CFADB}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {CC1DD008-9406-448D-A0AD-33C3186CFADB}.Release|Win32.ActiveCfg = Release|Win32
+ {CC1DD008-9406-448D-A0AD-33C3186CFADB}.Release|Win32.Build.0 = Release|Win32
+ {CC1DD008-9406-448D-A0AD-33C3186CFADB}.Release|x64.ActiveCfg = Release|x64
+ {CC1DD008-9406-448D-A0AD-33C3186CFADB}.Release|x64.Build.0 = Release|x64
+ {CC1DD008-9406-448D-A0AD-33C3186CFADB}.Release|x64 Setup.ActiveCfg = Release|x64
+ {CC1DD008-9406-448D-A0AD-33C3186CFADB}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {48414740-C693-4968-9846-EE058020C64F}.All|Win32.ActiveCfg = Release|Win32
+ {48414740-C693-4968-9846-EE058020C64F}.All|x64.ActiveCfg = Release|Win32
+ {48414740-C693-4968-9846-EE058020C64F}.All|x64 Setup.ActiveCfg = Release|Win32
+ {48414740-C693-4968-9846-EE058020C64F}.All|x86 Setup.ActiveCfg = Release|Win32
+ {48414740-C693-4968-9846-EE058020C64F}.Debug|Win32.ActiveCfg = Debug|Win32
+ {48414740-C693-4968-9846-EE058020C64F}.Debug|Win32.Build.0 = Debug|Win32
+ {48414740-C693-4968-9846-EE058020C64F}.Debug|x64.ActiveCfg = Debug|x64
+ {48414740-C693-4968-9846-EE058020C64F}.Debug|x64.Build.0 = Debug|x64
+ {48414740-C693-4968-9846-EE058020C64F}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {48414740-C693-4968-9846-EE058020C64F}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {48414740-C693-4968-9846-EE058020C64F}.Release|Win32.ActiveCfg = Release|Win32
+ {48414740-C693-4968-9846-EE058020C64F}.Release|Win32.Build.0 = Release|Win32
+ {48414740-C693-4968-9846-EE058020C64F}.Release|x64.ActiveCfg = Release|x64
+ {48414740-C693-4968-9846-EE058020C64F}.Release|x64.Build.0 = Release|x64
+ {48414740-C693-4968-9846-EE058020C64F}.Release|x64 Setup.ActiveCfg = Release|x64
+ {48414740-C693-4968-9846-EE058020C64F}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {DEE932AB-5911-4700-9EEB-8C7090A0A330}.All|Win32.ActiveCfg = All|Win32
+ {DEE932AB-5911-4700-9EEB-8C7090A0A330}.All|Win32.Build.0 = All|Win32
+ {DEE932AB-5911-4700-9EEB-8C7090A0A330}.All|x64.ActiveCfg = All|Win32
+ {DEE932AB-5911-4700-9EEB-8C7090A0A330}.All|x64 Setup.ActiveCfg = All|Win32
+ {DEE932AB-5911-4700-9EEB-8C7090A0A330}.All|x86 Setup.ActiveCfg = All|Win32
+ {DEE932AB-5911-4700-9EEB-8C7090A0A330}.All|x86 Setup.Build.0 = All|Win32
+ {DEE932AB-5911-4700-9EEB-8C7090A0A330}.Debug|Win32.ActiveCfg = All|Win32
+ {DEE932AB-5911-4700-9EEB-8C7090A0A330}.Debug|Win32.Build.0 = All|Win32
+ {DEE932AB-5911-4700-9EEB-8C7090A0A330}.Debug|x64.ActiveCfg = All|Win32
+ {DEE932AB-5911-4700-9EEB-8C7090A0A330}.Debug|x64.Build.0 = All|Win32
+ {DEE932AB-5911-4700-9EEB-8C7090A0A330}.Debug|x64 Setup.ActiveCfg = All|Win32
+ {DEE932AB-5911-4700-9EEB-8C7090A0A330}.Debug|x86 Setup.ActiveCfg = All|Win32
+ {DEE932AB-5911-4700-9EEB-8C7090A0A330}.Release|Win32.ActiveCfg = All|Win32
+ {DEE932AB-5911-4700-9EEB-8C7090A0A330}.Release|Win32.Build.0 = All|Win32
+ {DEE932AB-5911-4700-9EEB-8C7090A0A330}.Release|x64.ActiveCfg = All|Win32
+ {DEE932AB-5911-4700-9EEB-8C7090A0A330}.Release|x64.Build.0 = All|Win32
+ {DEE932AB-5911-4700-9EEB-8C7090A0A330}.Release|x64 Setup.ActiveCfg = All|Win32
+ {DEE932AB-5911-4700-9EEB-8C7090A0A330}.Release|x86 Setup.ActiveCfg = All|Win32
+ {329A6FA0-0FCC-4435-A950-E670AEFA9838}.All|Win32.ActiveCfg = All|Win32
+ {329A6FA0-0FCC-4435-A950-E670AEFA9838}.All|Win32.Build.0 = All|Win32
+ {329A6FA0-0FCC-4435-A950-E670AEFA9838}.All|x64.ActiveCfg = All|Win32
+ {329A6FA0-0FCC-4435-A950-E670AEFA9838}.All|x64 Setup.ActiveCfg = All|Win32
+ {329A6FA0-0FCC-4435-A950-E670AEFA9838}.All|x86 Setup.ActiveCfg = All|Win32
+ {329A6FA0-0FCC-4435-A950-E670AEFA9838}.All|x86 Setup.Build.0 = All|Win32
+ {329A6FA0-0FCC-4435-A950-E670AEFA9838}.Debug|Win32.ActiveCfg = All|Win32
+ {329A6FA0-0FCC-4435-A950-E670AEFA9838}.Debug|Win32.Build.0 = All|Win32
+ {329A6FA0-0FCC-4435-A950-E670AEFA9838}.Debug|x64.ActiveCfg = All|Win32
+ {329A6FA0-0FCC-4435-A950-E670AEFA9838}.Debug|x64.Build.0 = All|Win32
+ {329A6FA0-0FCC-4435-A950-E670AEFA9838}.Debug|x64 Setup.ActiveCfg = All|Win32
+ {329A6FA0-0FCC-4435-A950-E670AEFA9838}.Debug|x86 Setup.ActiveCfg = All|Win32
+ {329A6FA0-0FCC-4435-A950-E670AEFA9838}.Release|Win32.ActiveCfg = All|Win32
+ {329A6FA0-0FCC-4435-A950-E670AEFA9838}.Release|Win32.Build.0 = All|Win32
+ {329A6FA0-0FCC-4435-A950-E670AEFA9838}.Release|x64.ActiveCfg = All|Win32
+ {329A6FA0-0FCC-4435-A950-E670AEFA9838}.Release|x64.Build.0 = All|Win32
+ {329A6FA0-0FCC-4435-A950-E670AEFA9838}.Release|x64 Setup.ActiveCfg = All|Win32
+ {329A6FA0-0FCC-4435-A950-E670AEFA9838}.Release|x86 Setup.ActiveCfg = All|Win32
+ {11C9BC3D-45E9-46E3-BE84-B8CEE4685E39}.All|Win32.ActiveCfg = Release|x64
+ {11C9BC3D-45E9-46E3-BE84-B8CEE4685E39}.All|x64.ActiveCfg = Release|x64
+ {11C9BC3D-45E9-46E3-BE84-B8CEE4685E39}.All|x64.Build.0 = Release|x64
+ {11C9BC3D-45E9-46E3-BE84-B8CEE4685E39}.All|x64 Setup.ActiveCfg = Release|x64
+ {11C9BC3D-45E9-46E3-BE84-B8CEE4685E39}.All|x64 Setup.Build.0 = Release|x64
+ {11C9BC3D-45E9-46E3-BE84-B8CEE4685E39}.All|x86 Setup.ActiveCfg = Release|x64
+ {11C9BC3D-45E9-46E3-BE84-B8CEE4685E39}.Debug|Win32.ActiveCfg = Debug|Win32
+ {11C9BC3D-45E9-46E3-BE84-B8CEE4685E39}.Debug|x64.ActiveCfg = Debug|x64
+ {11C9BC3D-45E9-46E3-BE84-B8CEE4685E39}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {11C9BC3D-45E9-46E3-BE84-B8CEE4685E39}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {11C9BC3D-45E9-46E3-BE84-B8CEE4685E39}.Release|Win32.ActiveCfg = Release|Win32
+ {11C9BC3D-45E9-46E3-BE84-B8CEE4685E39}.Release|x64.ActiveCfg = Release|x64
+ {11C9BC3D-45E9-46E3-BE84-B8CEE4685E39}.Release|x64 Setup.ActiveCfg = Release|x64
+ {11C9BC3D-45E9-46E3-BE84-B8CEE4685E39}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {C6E78A4C-DB1E-47F4-9B63-4DC27D86343F}.All|Win32.ActiveCfg = Release|Win32
+ {C6E78A4C-DB1E-47F4-9B63-4DC27D86343F}.All|Win32.Build.0 = Release|Win32
+ {C6E78A4C-DB1E-47F4-9B63-4DC27D86343F}.All|x64.ActiveCfg = Release|Win32
+ {C6E78A4C-DB1E-47F4-9B63-4DC27D86343F}.All|x64 Setup.ActiveCfg = Release|Win32
+ {C6E78A4C-DB1E-47F4-9B63-4DC27D86343F}.All|x86 Setup.ActiveCfg = Release|Win32
+ {C6E78A4C-DB1E-47F4-9B63-4DC27D86343F}.All|x86 Setup.Build.0 = Release|Win32
+ {C6E78A4C-DB1E-47F4-9B63-4DC27D86343F}.Debug|Win32.ActiveCfg = Debug|Win32
+ {C6E78A4C-DB1E-47F4-9B63-4DC27D86343F}.Debug|Win32.Build.0 = Debug|Win32
+ {C6E78A4C-DB1E-47F4-9B63-4DC27D86343F}.Debug|x64.ActiveCfg = Debug|x64
+ {C6E78A4C-DB1E-47F4-9B63-4DC27D86343F}.Debug|x64.Build.0 = Debug|x64
+ {C6E78A4C-DB1E-47F4-9B63-4DC27D86343F}.Debug|x64 Setup.ActiveCfg = Debug|Win32
+ {C6E78A4C-DB1E-47F4-9B63-4DC27D86343F}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {C6E78A4C-DB1E-47F4-9B63-4DC27D86343F}.Release|Win32.ActiveCfg = Release|Win32
+ {C6E78A4C-DB1E-47F4-9B63-4DC27D86343F}.Release|Win32.Build.0 = Release|Win32
+ {C6E78A4C-DB1E-47F4-9B63-4DC27D86343F}.Release|x64.ActiveCfg = Release|x64
+ {C6E78A4C-DB1E-47F4-9B63-4DC27D86343F}.Release|x64.Build.0 = Release|x64
+ {C6E78A4C-DB1E-47F4-9B63-4DC27D86343F}.Release|x64 Setup.ActiveCfg = Release|Win32
+ {C6E78A4C-DB1E-47F4-9B63-4DC27D86343F}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {1F0A8A77-E661-418F-BB92-82172AE43803}.All|Win32.ActiveCfg = Release|Win32
+ {1F0A8A77-E661-418F-BB92-82172AE43803}.All|x64.ActiveCfg = Release|Win32
+ {1F0A8A77-E661-418F-BB92-82172AE43803}.All|x64 Setup.ActiveCfg = Release|Win32
+ {1F0A8A77-E661-418F-BB92-82172AE43803}.All|x86 Setup.ActiveCfg = Release|Win32
+ {1F0A8A77-E661-418F-BB92-82172AE43803}.Debug|Win32.ActiveCfg = Debug|Win32
+ {1F0A8A77-E661-418F-BB92-82172AE43803}.Debug|x64.ActiveCfg = Debug|Win32
+ {1F0A8A77-E661-418F-BB92-82172AE43803}.Debug|x64 Setup.ActiveCfg = Debug|Win32
+ {1F0A8A77-E661-418F-BB92-82172AE43803}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {1F0A8A77-E661-418F-BB92-82172AE43803}.Release|Win32.ActiveCfg = Release|Win32
+ {1F0A8A77-E661-418F-BB92-82172AE43803}.Release|x64.ActiveCfg = Release|Win32
+ {1F0A8A77-E661-418F-BB92-82172AE43803}.Release|x64 Setup.ActiveCfg = Release|Win32
+ {1F0A8A77-E661-418F-BB92-82172AE43803}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {4F5C9D55-98EF-4256-8311-32D7BD360406}.All|Win32.ActiveCfg = Release|Win32
+ {4F5C9D55-98EF-4256-8311-32D7BD360406}.All|Win32.Build.0 = Release|Win32
+ {4F5C9D55-98EF-4256-8311-32D7BD360406}.All|x64.ActiveCfg = Release|Win32
+ {4F5C9D55-98EF-4256-8311-32D7BD360406}.All|x64.Build.0 = Release|Win32
+ {4F5C9D55-98EF-4256-8311-32D7BD360406}.All|x64 Setup.ActiveCfg = Release|Win32
+ {4F5C9D55-98EF-4256-8311-32D7BD360406}.All|x64 Setup.Build.0 = Release|Win32
+ {4F5C9D55-98EF-4256-8311-32D7BD360406}.All|x86 Setup.ActiveCfg = Release|Win32
+ {4F5C9D55-98EF-4256-8311-32D7BD360406}.All|x86 Setup.Build.0 = Release|Win32
+ {4F5C9D55-98EF-4256-8311-32D7BD360406}.Debug|Win32.ActiveCfg = Debug|Win32
+ {4F5C9D55-98EF-4256-8311-32D7BD360406}.Debug|Win32.Build.0 = Debug|Win32
+ {4F5C9D55-98EF-4256-8311-32D7BD360406}.Debug|x64.ActiveCfg = Debug|Win32
+ {4F5C9D55-98EF-4256-8311-32D7BD360406}.Debug|x64.Build.0 = Debug|Win32
+ {4F5C9D55-98EF-4256-8311-32D7BD360406}.Debug|x64 Setup.ActiveCfg = Debug|Win32
+ {4F5C9D55-98EF-4256-8311-32D7BD360406}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {4F5C9D55-98EF-4256-8311-32D7BD360406}.Release|Win32.ActiveCfg = Release|Win32
+ {4F5C9D55-98EF-4256-8311-32D7BD360406}.Release|Win32.Build.0 = Release|Win32
+ {4F5C9D55-98EF-4256-8311-32D7BD360406}.Release|x64.ActiveCfg = Release|Win32
+ {4F5C9D55-98EF-4256-8311-32D7BD360406}.Release|x64.Build.0 = Release|Win32
+ {4F5C9D55-98EF-4256-8311-32D7BD360406}.Release|x64 Setup.ActiveCfg = Release|Win32
+ {4F5C9D55-98EF-4256-8311-32D7BD360406}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {E10571C4-E7F4-4608-B5F2-B22E7EB95400}.All|Win32.ActiveCfg = Release|Win32
+ {E10571C4-E7F4-4608-B5F2-B22E7EB95400}.All|x64.ActiveCfg = Release|Win32
+ {E10571C4-E7F4-4608-B5F2-B22E7EB95400}.All|x64 Setup.ActiveCfg = Release|Win32
+ {E10571C4-E7F4-4608-B5F2-B22E7EB95400}.All|x86 Setup.ActiveCfg = Release|Win32
+ {E10571C4-E7F4-4608-B5F2-B22E7EB95400}.Debug|Win32.ActiveCfg = Debug|Win32
+ {E10571C4-E7F4-4608-B5F2-B22E7EB95400}.Debug|x64.ActiveCfg = Debug|Win32
+ {E10571C4-E7F4-4608-B5F2-B22E7EB95400}.Debug|x64 Setup.ActiveCfg = Debug|Win32
+ {E10571C4-E7F4-4608-B5F2-B22E7EB95400}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {E10571C4-E7F4-4608-B5F2-B22E7EB95400}.Release|Win32.ActiveCfg = Release|Win32
+ {E10571C4-E7F4-4608-B5F2-B22E7EB95400}.Release|x64.ActiveCfg = Release|Win32
+ {E10571C4-E7F4-4608-B5F2-B22E7EB95400}.Release|x64 Setup.ActiveCfg = Release|Win32
+ {E10571C4-E7F4-4608-B5F2-B22E7EB95400}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {D1ABE208-6442-4FB4-9AAD-1677E41BC870}.All|Win32.ActiveCfg = Release|Win32
+ {D1ABE208-6442-4FB4-9AAD-1677E41BC870}.All|Win32.Build.0 = Release|Win32
+ {D1ABE208-6442-4FB4-9AAD-1677E41BC870}.All|x64.ActiveCfg = Release|Win32
+ {D1ABE208-6442-4FB4-9AAD-1677E41BC870}.All|x64.Build.0 = Release|Win32
+ {D1ABE208-6442-4FB4-9AAD-1677E41BC870}.All|x64 Setup.ActiveCfg = Release|Win32
+ {D1ABE208-6442-4FB4-9AAD-1677E41BC870}.All|x64 Setup.Build.0 = Release|Win32
+ {D1ABE208-6442-4FB4-9AAD-1677E41BC870}.All|x86 Setup.ActiveCfg = Release|Win32
+ {D1ABE208-6442-4FB4-9AAD-1677E41BC870}.All|x86 Setup.Build.0 = Release|Win32
+ {D1ABE208-6442-4FB4-9AAD-1677E41BC870}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D1ABE208-6442-4FB4-9AAD-1677E41BC870}.Debug|Win32.Build.0 = Debug|Win32
+ {D1ABE208-6442-4FB4-9AAD-1677E41BC870}.Debug|x64.ActiveCfg = Debug|x64
+ {D1ABE208-6442-4FB4-9AAD-1677E41BC870}.Debug|x64.Build.0 = Debug|x64
+ {D1ABE208-6442-4FB4-9AAD-1677E41BC870}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {D1ABE208-6442-4FB4-9AAD-1677E41BC870}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {D1ABE208-6442-4FB4-9AAD-1677E41BC870}.Release|Win32.ActiveCfg = Release|Win32
+ {D1ABE208-6442-4FB4-9AAD-1677E41BC870}.Release|Win32.Build.0 = Release|Win32
+ {D1ABE208-6442-4FB4-9AAD-1677E41BC870}.Release|x64.ActiveCfg = Release|x64
+ {D1ABE208-6442-4FB4-9AAD-1677E41BC870}.Release|x64.Build.0 = Release|x64
+ {D1ABE208-6442-4FB4-9AAD-1677E41BC870}.Release|x64 Setup.ActiveCfg = Release|x64
+ {D1ABE208-6442-4FB4-9AAD-1677E41BC870}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {BA599D0A-4310-4505-91DA-6A6447B3E289}.All|Win32.ActiveCfg = Release|Win32
+ {BA599D0A-4310-4505-91DA-6A6447B3E289}.All|x64.ActiveCfg = Release|Win32
+ {BA599D0A-4310-4505-91DA-6A6447B3E289}.All|x64 Setup.ActiveCfg = Release|Win32
+ {BA599D0A-4310-4505-91DA-6A6447B3E289}.All|x86 Setup.ActiveCfg = Release|Win32
+ {BA599D0A-4310-4505-91DA-6A6447B3E289}.Debug|Win32.ActiveCfg = Debug|Win32
+ {BA599D0A-4310-4505-91DA-6A6447B3E289}.Debug|x64.ActiveCfg = Debug|x64
+ {BA599D0A-4310-4505-91DA-6A6447B3E289}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {BA599D0A-4310-4505-91DA-6A6447B3E289}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {BA599D0A-4310-4505-91DA-6A6447B3E289}.Release|Win32.ActiveCfg = Release|Win32
+ {BA599D0A-4310-4505-91DA-6A6447B3E289}.Release|x64.ActiveCfg = Release|x64
+ {BA599D0A-4310-4505-91DA-6A6447B3E289}.Release|x64 Setup.ActiveCfg = Release|x64
+ {BA599D0A-4310-4505-91DA-6A6447B3E289}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {EED13FC7-4F81-4E6F-93DB-CDB7DF5CF959}.All|Win32.ActiveCfg = Release|Win32
+ {EED13FC7-4F81-4E6F-93DB-CDB7DF5CF959}.All|x64.ActiveCfg = Release|Win32
+ {EED13FC7-4F81-4E6F-93DB-CDB7DF5CF959}.All|x64 Setup.ActiveCfg = Release|Win32
+ {EED13FC7-4F81-4E6F-93DB-CDB7DF5CF959}.All|x86 Setup.ActiveCfg = Release|Win32
+ {EED13FC7-4F81-4E6F-93DB-CDB7DF5CF959}.Debug|Win32.ActiveCfg = Debug|Win32
+ {EED13FC7-4F81-4E6F-93DB-CDB7DF5CF959}.Debug|x64.ActiveCfg = Debug|x64
+ {EED13FC7-4F81-4E6F-93DB-CDB7DF5CF959}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {EED13FC7-4F81-4E6F-93DB-CDB7DF5CF959}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {EED13FC7-4F81-4E6F-93DB-CDB7DF5CF959}.Release|Win32.ActiveCfg = Release|Win32
+ {EED13FC7-4F81-4E6F-93DB-CDB7DF5CF959}.Release|x64.ActiveCfg = Release|x64
+ {EED13FC7-4F81-4E6F-93DB-CDB7DF5CF959}.Release|x64 Setup.ActiveCfg = Release|x64
+ {EED13FC7-4F81-4E6F-93DB-CDB7DF5CF959}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {3C977801-FE88-48F2-83D3-FA2EBFF6688E}.All|Win32.ActiveCfg = Release|x64
+ {3C977801-FE88-48F2-83D3-FA2EBFF6688E}.All|x64.ActiveCfg = Release|x64
+ {3C977801-FE88-48F2-83D3-FA2EBFF6688E}.All|x64.Build.0 = Release|x64
+ {3C977801-FE88-48F2-83D3-FA2EBFF6688E}.All|x64 Setup.ActiveCfg = Release|x64
+ {3C977801-FE88-48F2-83D3-FA2EBFF6688E}.All|x64 Setup.Build.0 = Release|x64
+ {3C977801-FE88-48F2-83D3-FA2EBFF6688E}.All|x86 Setup.ActiveCfg = Release|x64
+ {3C977801-FE88-48F2-83D3-FA2EBFF6688E}.Debug|Win32.ActiveCfg = Debug|Win32
+ {3C977801-FE88-48F2-83D3-FA2EBFF6688E}.Debug|Win32.Build.0 = Debug|Win32
+ {3C977801-FE88-48F2-83D3-FA2EBFF6688E}.Debug|x64.ActiveCfg = Debug|x64
+ {3C977801-FE88-48F2-83D3-FA2EBFF6688E}.Debug|x64.Build.0 = Debug|x64
+ {3C977801-FE88-48F2-83D3-FA2EBFF6688E}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {3C977801-FE88-48F2-83D3-FA2EBFF6688E}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {3C977801-FE88-48F2-83D3-FA2EBFF6688E}.Release|Win32.ActiveCfg = Release|Win32
+ {3C977801-FE88-48F2-83D3-FA2EBFF6688E}.Release|Win32.Build.0 = Release|Win32
+ {3C977801-FE88-48F2-83D3-FA2EBFF6688E}.Release|x64.ActiveCfg = Release|x64
+ {3C977801-FE88-48F2-83D3-FA2EBFF6688E}.Release|x64.Build.0 = Release|x64
+ {3C977801-FE88-48F2-83D3-FA2EBFF6688E}.Release|x64 Setup.ActiveCfg = Release|x64
+ {3C977801-FE88-48F2-83D3-FA2EBFF6688E}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {0382E8FD-CFDC-41C0-8B03-792C7C84FC31}.All|Win32.ActiveCfg = Release|x64
+ {0382E8FD-CFDC-41C0-8B03-792C7C84FC31}.All|Win32.Build.0 = Release|x64
+ {0382E8FD-CFDC-41C0-8B03-792C7C84FC31}.All|x64.ActiveCfg = Release|x64
+ {0382E8FD-CFDC-41C0-8B03-792C7C84FC31}.All|x64.Build.0 = Release|x64
+ {0382E8FD-CFDC-41C0-8B03-792C7C84FC31}.All|x64 Setup.ActiveCfg = Release|x64
+ {0382E8FD-CFDC-41C0-8B03-792C7C84FC31}.All|x64 Setup.Build.0 = Release|x64
+ {0382E8FD-CFDC-41C0-8B03-792C7C84FC31}.All|x86 Setup.ActiveCfg = Release|x64
+ {0382E8FD-CFDC-41C0-8B03-792C7C84FC31}.All|x86 Setup.Build.0 = Release|x64
+ {0382E8FD-CFDC-41C0-8B03-792C7C84FC31}.Debug|Win32.ActiveCfg = Debug|Win32
+ {0382E8FD-CFDC-41C0-8B03-792C7C84FC31}.Debug|Win32.Build.0 = Debug|Win32
+ {0382E8FD-CFDC-41C0-8B03-792C7C84FC31}.Debug|x64.ActiveCfg = Debug|x64
+ {0382E8FD-CFDC-41C0-8B03-792C7C84FC31}.Debug|x64.Build.0 = Debug|x64
+ {0382E8FD-CFDC-41C0-8B03-792C7C84FC31}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {0382E8FD-CFDC-41C0-8B03-792C7C84FC31}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {0382E8FD-CFDC-41C0-8B03-792C7C84FC31}.Release|Win32.ActiveCfg = Release|Win32
+ {0382E8FD-CFDC-41C0-8B03-792C7C84FC31}.Release|Win32.Build.0 = Release|Win32
+ {0382E8FD-CFDC-41C0-8B03-792C7C84FC31}.Release|x64.ActiveCfg = Release|x64
+ {0382E8FD-CFDC-41C0-8B03-792C7C84FC31}.Release|x64.Build.0 = Release|x64
+ {0382E8FD-CFDC-41C0-8B03-792C7C84FC31}.Release|x64 Setup.ActiveCfg = Release|x64
+ {0382E8FD-CFDC-41C0-8B03-792C7C84FC31}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {432DB165-1EB2-4781-A9C0-71E62610B20A}.All|Win32.ActiveCfg = Release|x64
+ {432DB165-1EB2-4781-A9C0-71E62610B20A}.All|x64.ActiveCfg = Release|x64
+ {432DB165-1EB2-4781-A9C0-71E62610B20A}.All|x64 Setup.ActiveCfg = Release|x64
+ {432DB165-1EB2-4781-A9C0-71E62610B20A}.All|x86 Setup.ActiveCfg = Release|x64
+ {432DB165-1EB2-4781-A9C0-71E62610B20A}.Debug|Win32.ActiveCfg = Debug|Win32
+ {432DB165-1EB2-4781-A9C0-71E62610B20A}.Debug|Win32.Build.0 = Debug|Win32
+ {432DB165-1EB2-4781-A9C0-71E62610B20A}.Debug|x64.ActiveCfg = Debug|x64
+ {432DB165-1EB2-4781-A9C0-71E62610B20A}.Debug|x64.Build.0 = Debug|x64
+ {432DB165-1EB2-4781-A9C0-71E62610B20A}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {432DB165-1EB2-4781-A9C0-71E62610B20A}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {432DB165-1EB2-4781-A9C0-71E62610B20A}.Release|Win32.ActiveCfg = Release|Win32
+ {432DB165-1EB2-4781-A9C0-71E62610B20A}.Release|Win32.Build.0 = Release|Win32
+ {432DB165-1EB2-4781-A9C0-71E62610B20A}.Release|x64.ActiveCfg = Release|x64
+ {432DB165-1EB2-4781-A9C0-71E62610B20A}.Release|x64.Build.0 = Release|x64
+ {432DB165-1EB2-4781-A9C0-71E62610B20A}.Release|x64 Setup.ActiveCfg = Release|x64
+ {432DB165-1EB2-4781-A9C0-71E62610B20A}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {CF70F278-3364-4395-A2E1-23501C9B8AD2}.All|Win32.ActiveCfg = Release|Win32
+ {CF70F278-3364-4395-A2E1-23501C9B8AD2}.All|Win32.Build.0 = Release|Win32
+ {CF70F278-3364-4395-A2E1-23501C9B8AD2}.All|x64.ActiveCfg = Release|Win32
+ {CF70F278-3364-4395-A2E1-23501C9B8AD2}.All|x64 Setup.ActiveCfg = Release|Win32
+ {CF70F278-3364-4395-A2E1-23501C9B8AD2}.All|x86 Setup.ActiveCfg = Release|Win32
+ {CF70F278-3364-4395-A2E1-23501C9B8AD2}.All|x86 Setup.Build.0 = Release|Win32
+ {CF70F278-3364-4395-A2E1-23501C9B8AD2}.Debug|Win32.ActiveCfg = Debug|Win32
+ {CF70F278-3364-4395-A2E1-23501C9B8AD2}.Debug|Win32.Build.0 = Debug|Win32
+ {CF70F278-3364-4395-A2E1-23501C9B8AD2}.Debug|x64.ActiveCfg = Debug|x64
+ {CF70F278-3364-4395-A2E1-23501C9B8AD2}.Debug|x64.Build.0 = Debug|x64
+ {CF70F278-3364-4395-A2E1-23501C9B8AD2}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {CF70F278-3364-4395-A2E1-23501C9B8AD2}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {CF70F278-3364-4395-A2E1-23501C9B8AD2}.Release|Win32.ActiveCfg = Release|Win32
+ {CF70F278-3364-4395-A2E1-23501C9B8AD2}.Release|Win32.Build.0 = Release|Win32
+ {CF70F278-3364-4395-A2E1-23501C9B8AD2}.Release|x64.ActiveCfg = Release|x64
+ {CF70F278-3364-4395-A2E1-23501C9B8AD2}.Release|x64.Build.0 = Release|x64
+ {CF70F278-3364-4395-A2E1-23501C9B8AD2}.Release|x64 Setup.ActiveCfg = Release|x64
+ {CF70F278-3364-4395-A2E1-23501C9B8AD2}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {D5C87B19-150D-4EF3-A671-96589BD2D14A}.All|Win32.ActiveCfg = Release|x64
+ {D5C87B19-150D-4EF3-A671-96589BD2D14A}.All|x64.ActiveCfg = Release|x64
+ {D5C87B19-150D-4EF3-A671-96589BD2D14A}.All|x64.Build.0 = Release|x64
+ {D5C87B19-150D-4EF3-A671-96589BD2D14A}.All|x64 Setup.ActiveCfg = Release|x64
+ {D5C87B19-150D-4EF3-A671-96589BD2D14A}.All|x64 Setup.Build.0 = Release|x64
+ {D5C87B19-150D-4EF3-A671-96589BD2D14A}.All|x86 Setup.ActiveCfg = Release|x64
+ {D5C87B19-150D-4EF3-A671-96589BD2D14A}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D5C87B19-150D-4EF3-A671-96589BD2D14A}.Debug|Win32.Build.0 = Debug|Win32
+ {D5C87B19-150D-4EF3-A671-96589BD2D14A}.Debug|x64.ActiveCfg = Debug|x64
+ {D5C87B19-150D-4EF3-A671-96589BD2D14A}.Debug|x64.Build.0 = Debug|x64
+ {D5C87B19-150D-4EF3-A671-96589BD2D14A}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {D5C87B19-150D-4EF3-A671-96589BD2D14A}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {D5C87B19-150D-4EF3-A671-96589BD2D14A}.Release|Win32.ActiveCfg = Release|Win32
+ {D5C87B19-150D-4EF3-A671-96589BD2D14A}.Release|Win32.Build.0 = Release|Win32
+ {D5C87B19-150D-4EF3-A671-96589BD2D14A}.Release|x64.ActiveCfg = Release|x64
+ {D5C87B19-150D-4EF3-A671-96589BD2D14A}.Release|x64.Build.0 = Release|x64
+ {D5C87B19-150D-4EF3-A671-96589BD2D14A}.Release|x64 Setup.ActiveCfg = Release|x64
+ {D5C87B19-150D-4EF3-A671-96589BD2D14A}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}.All|Win32.ActiveCfg = Release|Win32
+ {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}.All|Win32.Build.0 = Release|Win32
+ {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}.All|x64.ActiveCfg = Release|Win32
+ {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}.All|x64 Setup.ActiveCfg = Release|Win32
+ {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}.All|x86 Setup.ActiveCfg = Release|Win32
+ {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}.All|x86 Setup.Build.0 = Release|Win32
+ {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}.Debug|Win32.ActiveCfg = Debug|Win32
+ {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}.Debug|Win32.Build.0 = Debug|Win32
+ {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}.Debug|x64.ActiveCfg = Debug|x64
+ {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}.Debug|x64.Build.0 = Debug|x64
+ {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}.Release|Win32.ActiveCfg = Release|Win32
+ {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}.Release|Win32.Build.0 = Release|Win32
+ {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}.Release|x64.ActiveCfg = Release|x64
+ {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}.Release|x64.Build.0 = Release|x64
+ {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}.Release|x64 Setup.ActiveCfg = Release|x64
+ {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {B5A00BFA-6083-4FAE-A097-71642D6473B5}.All|Win32.ActiveCfg = Release|Win32
+ {B5A00BFA-6083-4FAE-A097-71642D6473B5}.All|Win32.Build.0 = Release|Win32
+ {B5A00BFA-6083-4FAE-A097-71642D6473B5}.All|x64.ActiveCfg = Release|Win32
+ {B5A00BFA-6083-4FAE-A097-71642D6473B5}.All|x64 Setup.ActiveCfg = Release|Win32
+ {B5A00BFA-6083-4FAE-A097-71642D6473B5}.All|x86 Setup.ActiveCfg = Release|Win32
+ {B5A00BFA-6083-4FAE-A097-71642D6473B5}.All|x86 Setup.Build.0 = Release|Win32
+ {B5A00BFA-6083-4FAE-A097-71642D6473B5}.Debug|Win32.ActiveCfg = Debug|Win32
+ {B5A00BFA-6083-4FAE-A097-71642D6473B5}.Debug|Win32.Build.0 = Debug|Win32
+ {B5A00BFA-6083-4FAE-A097-71642D6473B5}.Debug|x64.ActiveCfg = Debug|x64
+ {B5A00BFA-6083-4FAE-A097-71642D6473B5}.Debug|x64.Build.0 = Debug|x64
+ {B5A00BFA-6083-4FAE-A097-71642D6473B5}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {B5A00BFA-6083-4FAE-A097-71642D6473B5}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {B5A00BFA-6083-4FAE-A097-71642D6473B5}.Release|Win32.ActiveCfg = Release|Win32
+ {B5A00BFA-6083-4FAE-A097-71642D6473B5}.Release|Win32.Build.0 = Release|Win32
+ {B5A00BFA-6083-4FAE-A097-71642D6473B5}.Release|x64.ActiveCfg = Release|x64
+ {B5A00BFA-6083-4FAE-A097-71642D6473B5}.Release|x64.Build.0 = Release|x64
+ {B5A00BFA-6083-4FAE-A097-71642D6473B5}.Release|x64 Setup.ActiveCfg = Release|x64
+ {B5A00BFA-6083-4FAE-A097-71642D6473B5}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {1C320193-46A6-4B34-9C56-8AB584FC1B56}.All|Win32.ActiveCfg = Release|Win32
+ {1C320193-46A6-4B34-9C56-8AB584FC1B56}.All|Win32.Build.0 = Release|Win32
+ {1C320193-46A6-4B34-9C56-8AB584FC1B56}.All|x64.ActiveCfg = Release|Win32
+ {1C320193-46A6-4B34-9C56-8AB584FC1B56}.All|x64 Setup.ActiveCfg = Release|Win32
+ {1C320193-46A6-4B34-9C56-8AB584FC1B56}.All|x86 Setup.ActiveCfg = Release|Win32
+ {1C320193-46A6-4B34-9C56-8AB584FC1B56}.All|x86 Setup.Build.0 = Release|Win32
+ {1C320193-46A6-4B34-9C56-8AB584FC1B56}.Debug|Win32.ActiveCfg = Debug|Win32
+ {1C320193-46A6-4B34-9C56-8AB584FC1B56}.Debug|Win32.Build.0 = Debug|Win32
+ {1C320193-46A6-4B34-9C56-8AB584FC1B56}.Debug|x64.ActiveCfg = Debug|x64
+ {1C320193-46A6-4B34-9C56-8AB584FC1B56}.Debug|x64.Build.0 = Debug|x64
+ {1C320193-46A6-4B34-9C56-8AB584FC1B56}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {1C320193-46A6-4B34-9C56-8AB584FC1B56}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {1C320193-46A6-4B34-9C56-8AB584FC1B56}.Release|Win32.ActiveCfg = Release|Win32
+ {1C320193-46A6-4B34-9C56-8AB584FC1B56}.Release|Win32.Build.0 = Release|Win32
+ {1C320193-46A6-4B34-9C56-8AB584FC1B56}.Release|x64.ActiveCfg = Release|x64
+ {1C320193-46A6-4B34-9C56-8AB584FC1B56}.Release|x64.Build.0 = Release|x64
+ {1C320193-46A6-4B34-9C56-8AB584FC1B56}.Release|x64 Setup.ActiveCfg = Release|x64
+ {1C320193-46A6-4B34-9C56-8AB584FC1B56}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {72782932-37CC-46AE-8C7F-9A7B1A6EE108}.All|Win32.ActiveCfg = Release|Win32
+ {72782932-37CC-46AE-8C7F-9A7B1A6EE108}.All|Win32.Build.0 = Release|Win32
+ {72782932-37CC-46AE-8C7F-9A7B1A6EE108}.All|x64.ActiveCfg = Release|Win32
+ {72782932-37CC-46AE-8C7F-9A7B1A6EE108}.All|x64 Setup.ActiveCfg = Release|Win32
+ {72782932-37CC-46AE-8C7F-9A7B1A6EE108}.All|x86 Setup.ActiveCfg = Release|Win32
+ {72782932-37CC-46AE-8C7F-9A7B1A6EE108}.All|x86 Setup.Build.0 = Release|Win32
+ {72782932-37CC-46AE-8C7F-9A7B1A6EE108}.Debug|Win32.ActiveCfg = Debug|Win32
+ {72782932-37CC-46AE-8C7F-9A7B1A6EE108}.Debug|Win32.Build.0 = Debug|Win32
+ {72782932-37CC-46AE-8C7F-9A7B1A6EE108}.Debug|x64.ActiveCfg = Debug|x64
+ {72782932-37CC-46AE-8C7F-9A7B1A6EE108}.Debug|x64.Build.0 = Debug|x64
+ {72782932-37CC-46AE-8C7F-9A7B1A6EE108}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {72782932-37CC-46AE-8C7F-9A7B1A6EE108}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {72782932-37CC-46AE-8C7F-9A7B1A6EE108}.Release|Win32.ActiveCfg = Release|Win32
+ {72782932-37CC-46AE-8C7F-9A7B1A6EE108}.Release|Win32.Build.0 = Release|Win32
+ {72782932-37CC-46AE-8C7F-9A7B1A6EE108}.Release|x64.ActiveCfg = Release|x64
+ {72782932-37CC-46AE-8C7F-9A7B1A6EE108}.Release|x64.Build.0 = Release|x64
+ {72782932-37CC-46AE-8C7F-9A7B1A6EE108}.Release|x64 Setup.ActiveCfg = Release|x64
+ {72782932-37CC-46AE-8C7F-9A7B1A6EE108}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {12A49562-BAB9-43A3-A21D-15B60BBB4C31}.All|Win32.ActiveCfg = Release|Win32
+ {12A49562-BAB9-43A3-A21D-15B60BBB4C31}.All|Win32.Build.0 = Release|Win32
+ {12A49562-BAB9-43A3-A21D-15B60BBB4C31}.All|x64.ActiveCfg = Release|Win32
+ {12A49562-BAB9-43A3-A21D-15B60BBB4C31}.All|x64 Setup.ActiveCfg = Release|Win32
+ {12A49562-BAB9-43A3-A21D-15B60BBB4C31}.All|x86 Setup.ActiveCfg = Release|Win32
+ {12A49562-BAB9-43A3-A21D-15B60BBB4C31}.All|x86 Setup.Build.0 = Release|Win32
+ {12A49562-BAB9-43A3-A21D-15B60BBB4C31}.Debug|Win32.ActiveCfg = Debug|Win32
+ {12A49562-BAB9-43A3-A21D-15B60BBB4C31}.Debug|Win32.Build.0 = Debug|Win32
+ {12A49562-BAB9-43A3-A21D-15B60BBB4C31}.Debug|x64.ActiveCfg = Debug|x64
+ {12A49562-BAB9-43A3-A21D-15B60BBB4C31}.Debug|x64.Build.0 = Debug|x64
+ {12A49562-BAB9-43A3-A21D-15B60BBB4C31}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {12A49562-BAB9-43A3-A21D-15B60BBB4C31}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {12A49562-BAB9-43A3-A21D-15B60BBB4C31}.Release|Win32.ActiveCfg = Release|Win32
+ {12A49562-BAB9-43A3-A21D-15B60BBB4C31}.Release|Win32.Build.0 = Release|Win32
+ {12A49562-BAB9-43A3-A21D-15B60BBB4C31}.Release|x64.ActiveCfg = Release|x64
+ {12A49562-BAB9-43A3-A21D-15B60BBB4C31}.Release|x64.Build.0 = Release|x64
+ {12A49562-BAB9-43A3-A21D-15B60BBB4C31}.Release|x64 Setup.ActiveCfg = Release|x64
+ {12A49562-BAB9-43A3-A21D-15B60BBB4C31}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}.All|Win32.ActiveCfg = Release|Win32
+ {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}.All|Win32.Build.0 = Release|Win32
+ {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}.All|x64.ActiveCfg = Release|Win32
+ {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}.All|x64 Setup.ActiveCfg = Release|Win32
+ {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}.All|x86 Setup.ActiveCfg = Release|Win32
+ {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}.All|x86 Setup.Build.0 = Release|Win32
+ {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}.Debug|Win32.ActiveCfg = Debug|Win32
+ {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}.Debug|Win32.Build.0 = Debug|Win32
+ {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}.Debug|x64.ActiveCfg = Debug|x64
+ {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}.Debug|x64.Build.0 = Debug|x64
+ {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}.Release|Win32.ActiveCfg = Release|Win32
+ {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}.Release|Win32.Build.0 = Release|Win32
+ {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}.Release|x64.ActiveCfg = Release|x64
+ {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}.Release|x64.Build.0 = Release|x64
+ {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}.Release|x64 Setup.ActiveCfg = Release|x64
+ {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {504B3154-7A4F-459D-9877-B951021C3F1F}.All|Win32.ActiveCfg = Release|Win32
+ {504B3154-7A4F-459D-9877-B951021C3F1F}.All|Win32.Build.0 = Release|Win32
+ {504B3154-7A4F-459D-9877-B951021C3F1F}.All|x64.ActiveCfg = Release|Win32
+ {504B3154-7A4F-459D-9877-B951021C3F1F}.All|x64 Setup.ActiveCfg = Release|Win32
+ {504B3154-7A4F-459D-9877-B951021C3F1F}.All|x86 Setup.ActiveCfg = Release|Win32
+ {504B3154-7A4F-459D-9877-B951021C3F1F}.All|x86 Setup.Build.0 = Release|Win32
+ {504B3154-7A4F-459D-9877-B951021C3F1F}.Debug|Win32.ActiveCfg = Debug|Win32
+ {504B3154-7A4F-459D-9877-B951021C3F1F}.Debug|Win32.Build.0 = Debug|Win32
+ {504B3154-7A4F-459D-9877-B951021C3F1F}.Debug|x64.ActiveCfg = Debug|x64
+ {504B3154-7A4F-459D-9877-B951021C3F1F}.Debug|x64.Build.0 = Debug|x64
+ {504B3154-7A4F-459D-9877-B951021C3F1F}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {504B3154-7A4F-459D-9877-B951021C3F1F}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {504B3154-7A4F-459D-9877-B951021C3F1F}.Release|Win32.ActiveCfg = Release|Win32
+ {504B3154-7A4F-459D-9877-B951021C3F1F}.Release|Win32.Build.0 = Release|Win32
+ {504B3154-7A4F-459D-9877-B951021C3F1F}.Release|x64.ActiveCfg = Release|x64
+ {504B3154-7A4F-459D-9877-B951021C3F1F}.Release|x64.Build.0 = Release|x64
+ {504B3154-7A4F-459D-9877-B951021C3F1F}.Release|x64 Setup.ActiveCfg = Release|x64
+ {504B3154-7A4F-459D-9877-B951021C3F1F}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {746F3632-5BB2-4570-9453-31D6D58A7D8E}.All|Win32.ActiveCfg = Release|Win32
+ {746F3632-5BB2-4570-9453-31D6D58A7D8E}.All|Win32.Build.0 = Release|Win32
+ {746F3632-5BB2-4570-9453-31D6D58A7D8E}.All|x64.ActiveCfg = Release|Win32
+ {746F3632-5BB2-4570-9453-31D6D58A7D8E}.All|x64 Setup.ActiveCfg = Release|Win32
+ {746F3632-5BB2-4570-9453-31D6D58A7D8E}.All|x86 Setup.ActiveCfg = Release|Win32
+ {746F3632-5BB2-4570-9453-31D6D58A7D8E}.All|x86 Setup.Build.0 = Release|Win32
+ {746F3632-5BB2-4570-9453-31D6D58A7D8E}.Debug|Win32.ActiveCfg = Debug|Win32
+ {746F3632-5BB2-4570-9453-31D6D58A7D8E}.Debug|Win32.Build.0 = Debug|Win32
+ {746F3632-5BB2-4570-9453-31D6D58A7D8E}.Debug|x64.ActiveCfg = Debug|x64
+ {746F3632-5BB2-4570-9453-31D6D58A7D8E}.Debug|x64.Build.0 = Debug|x64
+ {746F3632-5BB2-4570-9453-31D6D58A7D8E}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {746F3632-5BB2-4570-9453-31D6D58A7D8E}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {746F3632-5BB2-4570-9453-31D6D58A7D8E}.Release|Win32.ActiveCfg = Release|Win32
+ {746F3632-5BB2-4570-9453-31D6D58A7D8E}.Release|Win32.Build.0 = Release|Win32
+ {746F3632-5BB2-4570-9453-31D6D58A7D8E}.Release|x64.ActiveCfg = Release|x64
+ {746F3632-5BB2-4570-9453-31D6D58A7D8E}.Release|x64.Build.0 = Release|x64
+ {746F3632-5BB2-4570-9453-31D6D58A7D8E}.Release|x64 Setup.ActiveCfg = Release|x64
+ {746F3632-5BB2-4570-9453-31D6D58A7D8E}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {DEB01ACB-D65F-4A62-AED9-58C1054499E9}.All|Win32.ActiveCfg = Release|Win32
+ {DEB01ACB-D65F-4A62-AED9-58C1054499E9}.All|Win32.Build.0 = Release|Win32
+ {DEB01ACB-D65F-4A62-AED9-58C1054499E9}.All|x64.ActiveCfg = Release|Win32
+ {DEB01ACB-D65F-4A62-AED9-58C1054499E9}.All|x64 Setup.ActiveCfg = Release|Win32
+ {DEB01ACB-D65F-4A62-AED9-58C1054499E9}.All|x86 Setup.ActiveCfg = Release|Win32
+ {DEB01ACB-D65F-4A62-AED9-58C1054499E9}.All|x86 Setup.Build.0 = Release|Win32
+ {DEB01ACB-D65F-4A62-AED9-58C1054499E9}.Debug|Win32.ActiveCfg = Debug|Win32
+ {DEB01ACB-D65F-4A62-AED9-58C1054499E9}.Debug|Win32.Build.0 = Debug|Win32
+ {DEB01ACB-D65F-4A62-AED9-58C1054499E9}.Debug|x64.ActiveCfg = Debug|x64
+ {DEB01ACB-D65F-4A62-AED9-58C1054499E9}.Debug|x64.Build.0 = Debug|x64
+ {DEB01ACB-D65F-4A62-AED9-58C1054499E9}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {DEB01ACB-D65F-4A62-AED9-58C1054499E9}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {DEB01ACB-D65F-4A62-AED9-58C1054499E9}.Release|Win32.ActiveCfg = Release|Win32
+ {DEB01ACB-D65F-4A62-AED9-58C1054499E9}.Release|Win32.Build.0 = Release|Win32
+ {DEB01ACB-D65F-4A62-AED9-58C1054499E9}.Release|x64.ActiveCfg = Release|x64
+ {DEB01ACB-D65F-4A62-AED9-58C1054499E9}.Release|x64.Build.0 = Release|x64
+ {DEB01ACB-D65F-4A62-AED9-58C1054499E9}.Release|x64 Setup.ActiveCfg = Release|x64
+ {DEB01ACB-D65F-4A62-AED9-58C1054499E9}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {D07C378A-F5F7-438F-ADF3-4AC4FB1883CD}.All|Win32.ActiveCfg = Release|x64
+ {D07C378A-F5F7-438F-ADF3-4AC4FB1883CD}.All|x64.ActiveCfg = Release|x64
+ {D07C378A-F5F7-438F-ADF3-4AC4FB1883CD}.All|x64.Build.0 = Release|x64
+ {D07C378A-F5F7-438F-ADF3-4AC4FB1883CD}.All|x64 Setup.ActiveCfg = Release|x64
+ {D07C378A-F5F7-438F-ADF3-4AC4FB1883CD}.All|x64 Setup.Build.0 = Release|x64
+ {D07C378A-F5F7-438F-ADF3-4AC4FB1883CD}.All|x86 Setup.ActiveCfg = Release|x64
+ {D07C378A-F5F7-438F-ADF3-4AC4FB1883CD}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D07C378A-F5F7-438F-ADF3-4AC4FB1883CD}.Debug|Win32.Build.0 = Debug|Win32
+ {D07C378A-F5F7-438F-ADF3-4AC4FB1883CD}.Debug|x64.ActiveCfg = Debug|x64
+ {D07C378A-F5F7-438F-ADF3-4AC4FB1883CD}.Debug|x64.Build.0 = Debug|x64
+ {D07C378A-F5F7-438F-ADF3-4AC4FB1883CD}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {D07C378A-F5F7-438F-ADF3-4AC4FB1883CD}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {D07C378A-F5F7-438F-ADF3-4AC4FB1883CD}.Release|Win32.ActiveCfg = Release|Win32
+ {D07C378A-F5F7-438F-ADF3-4AC4FB1883CD}.Release|Win32.Build.0 = Release|Win32
+ {D07C378A-F5F7-438F-ADF3-4AC4FB1883CD}.Release|x64.ActiveCfg = Release|x64
+ {D07C378A-F5F7-438F-ADF3-4AC4FB1883CD}.Release|x64.Build.0 = Release|x64
+ {D07C378A-F5F7-438F-ADF3-4AC4FB1883CD}.Release|x64 Setup.ActiveCfg = Release|x64
+ {D07C378A-F5F7-438F-ADF3-4AC4FB1883CD}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19}.All|Win32.ActiveCfg = Release|Win32
+ {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19}.All|Win32.Build.0 = Release|Win32
+ {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19}.All|x64.ActiveCfg = Release|Win32
+ {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19}.All|x64 Setup.ActiveCfg = Release|Win32
+ {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19}.All|x86 Setup.ActiveCfg = Release|Win32
+ {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19}.All|x86 Setup.Build.0 = Release|Win32
+ {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19}.Debug|Win32.ActiveCfg = Debug|Win32
+ {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19}.Debug|Win32.Build.0 = Debug|Win32
+ {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19}.Debug|x64.ActiveCfg = Debug|Win32
+ {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19}.Debug|x64.Build.0 = Debug|Win32
+ {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19}.Debug|x64 Setup.ActiveCfg = Debug|Win32
+ {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19}.Release|Win32.ActiveCfg = Release|Win32
+ {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19}.Release|Win32.Build.0 = Release|Win32
+ {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19}.Release|x64.ActiveCfg = Release|Win32
+ {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19}.Release|x64.Build.0 = Release|Win32
+ {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19}.Release|x64 Setup.ActiveCfg = Release|Win32
+ {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {ABB71A76-42B0-47A4-973A-42E3D920C6FD}.All|Win32.ActiveCfg = Release|x64
+ {ABB71A76-42B0-47A4-973A-42E3D920C6FD}.All|x64.ActiveCfg = Release|x64
+ {ABB71A76-42B0-47A4-973A-42E3D920C6FD}.All|x64.Build.0 = Release|x64
+ {ABB71A76-42B0-47A4-973A-42E3D920C6FD}.All|x64 Setup.ActiveCfg = Release|x64
+ {ABB71A76-42B0-47A4-973A-42E3D920C6FD}.All|x64 Setup.Build.0 = Release|x64
+ {ABB71A76-42B0-47A4-973A-42E3D920C6FD}.All|x86 Setup.ActiveCfg = Release|x64
+ {ABB71A76-42B0-47A4-973A-42E3D920C6FD}.Debug|Win32.ActiveCfg = Debug|Win32
+ {ABB71A76-42B0-47A4-973A-42E3D920C6FD}.Debug|Win32.Build.0 = Debug|Win32
+ {ABB71A76-42B0-47A4-973A-42E3D920C6FD}.Debug|x64.ActiveCfg = Debug|x64
+ {ABB71A76-42B0-47A4-973A-42E3D920C6FD}.Debug|x64.Build.0 = Debug|x64
+ {ABB71A76-42B0-47A4-973A-42E3D920C6FD}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {ABB71A76-42B0-47A4-973A-42E3D920C6FD}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {ABB71A76-42B0-47A4-973A-42E3D920C6FD}.Release|Win32.ActiveCfg = Release|Win32
+ {ABB71A76-42B0-47A4-973A-42E3D920C6FD}.Release|Win32.Build.0 = Release|Win32
+ {ABB71A76-42B0-47A4-973A-42E3D920C6FD}.Release|x64.ActiveCfg = Release|x64
+ {ABB71A76-42B0-47A4-973A-42E3D920C6FD}.Release|x64.Build.0 = Release|x64
+ {ABB71A76-42B0-47A4-973A-42E3D920C6FD}.Release|x64 Setup.ActiveCfg = Release|x64
+ {ABB71A76-42B0-47A4-973A-42E3D920C6FD}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {4D418176-3B33-47E6-A63E-01BA34ADD21C}.All|Win32.ActiveCfg = Release|Win32
+ {4D418176-3B33-47E6-A63E-01BA34ADD21C}.All|Win32.Build.0 = Release|Win32
+ {4D418176-3B33-47E6-A63E-01BA34ADD21C}.All|x64.ActiveCfg = Release|x64
+ {4D418176-3B33-47E6-A63E-01BA34ADD21C}.All|x64.Build.0 = Release|x64
+ {4D418176-3B33-47E6-A63E-01BA34ADD21C}.All|x64 Setup.ActiveCfg = Release|Win32
+ {4D418176-3B33-47E6-A63E-01BA34ADD21C}.All|x86 Setup.ActiveCfg = Release|Win32
+ {4D418176-3B33-47E6-A63E-01BA34ADD21C}.Debug|Win32.ActiveCfg = Debug|Win32
+ {4D418176-3B33-47E6-A63E-01BA34ADD21C}.Debug|Win32.Build.0 = Debug|Win32
+ {4D418176-3B33-47E6-A63E-01BA34ADD21C}.Debug|x64.ActiveCfg = Debug|x64
+ {4D418176-3B33-47E6-A63E-01BA34ADD21C}.Debug|x64.Build.0 = Debug|x64
+ {4D418176-3B33-47E6-A63E-01BA34ADD21C}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {4D418176-3B33-47E6-A63E-01BA34ADD21C}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {4D418176-3B33-47E6-A63E-01BA34ADD21C}.Release|Win32.ActiveCfg = Release|Win32
+ {4D418176-3B33-47E6-A63E-01BA34ADD21C}.Release|Win32.Build.0 = Release|Win32
+ {4D418176-3B33-47E6-A63E-01BA34ADD21C}.Release|x64.ActiveCfg = Release|x64
+ {4D418176-3B33-47E6-A63E-01BA34ADD21C}.Release|x64.Build.0 = Release|x64
+ {4D418176-3B33-47E6-A63E-01BA34ADD21C}.Release|x64 Setup.ActiveCfg = Release|x64
+ {4D418176-3B33-47E6-A63E-01BA34ADD21C}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {7D3122C7-C9D0-3748-81F8-F0DDCB40BF5E}.All|Win32.ActiveCfg = Release|Win32
+ {7D3122C7-C9D0-3748-81F8-F0DDCB40BF5E}.All|Win32.Build.0 = Release|Win32
+ {7D3122C7-C9D0-3748-81F8-F0DDCB40BF5E}.All|x64.ActiveCfg = Release|Win32
+ {7D3122C7-C9D0-3748-81F8-F0DDCB40BF5E}.All|x64 Setup.ActiveCfg = Release|Win32
+ {7D3122C7-C9D0-3748-81F8-F0DDCB40BF5E}.All|x86 Setup.ActiveCfg = Release|Win32
+ {7D3122C7-C9D0-3748-81F8-F0DDCB40BF5E}.All|x86 Setup.Build.0 = Release|Win32
+ {7D3122C7-C9D0-3748-81F8-F0DDCB40BF5E}.Debug|Win32.ActiveCfg = Debug|Win32
+ {7D3122C7-C9D0-3748-81F8-F0DDCB40BF5E}.Debug|x64.ActiveCfg = Debug|Win32
+ {7D3122C7-C9D0-3748-81F8-F0DDCB40BF5E}.Debug|x64 Setup.ActiveCfg = Debug|Win32
+ {7D3122C7-C9D0-3748-81F8-F0DDCB40BF5E}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {7D3122C7-C9D0-3748-81F8-F0DDCB40BF5E}.Release|Win32.ActiveCfg = Release|Win32
+ {7D3122C7-C9D0-3748-81F8-F0DDCB40BF5E}.Release|x64.ActiveCfg = Release|Win32
+ {7D3122C7-C9D0-3748-81F8-F0DDCB40BF5E}.Release|x64 Setup.ActiveCfg = Release|Win32
+ {7D3122C7-C9D0-3748-81F8-F0DDCB40BF5E}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.All|Win32.ActiveCfg = Release|x64
+ {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.All|x64.ActiveCfg = Release|x64
+ {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.All|x64.Build.0 = Release|x64
+ {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.All|x64 Setup.ActiveCfg = Release|x64
+ {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.All|x64 Setup.Build.0 = Release|x64
+ {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.All|x86 Setup.ActiveCfg = Release|x64
+ {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.Debug|Win32.ActiveCfg = Debug|Win32
+ {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.Debug|Win32.Build.0 = Debug|Win32
+ {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.Debug|x64.ActiveCfg = Debug|x64
+ {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.Debug|x64.Build.0 = Debug|x64
+ {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.Release|Win32.ActiveCfg = Release|Win32
+ {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.Release|Win32.Build.0 = Release|Win32
+ {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.Release|x64.ActiveCfg = Release|x64
+ {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.Release|x64.Build.0 = Release|x64
+ {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.Release|x64 Setup.ActiveCfg = Release|x64
+ {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {B808178B-82F0-4CF4-A2B1-921939FA24D0}.All|Win32.ActiveCfg = Release|Win32
+ {B808178B-82F0-4CF4-A2B1-921939FA24D0}.All|Win32.Build.0 = Release|Win32
+ {B808178B-82F0-4CF4-A2B1-921939FA24D0}.All|x64.ActiveCfg = Release|Win32
+ {B808178B-82F0-4CF4-A2B1-921939FA24D0}.All|x64 Setup.ActiveCfg = Release|Win32
+ {B808178B-82F0-4CF4-A2B1-921939FA24D0}.All|x86 Setup.ActiveCfg = Release|Win32
+ {B808178B-82F0-4CF4-A2B1-921939FA24D0}.All|x86 Setup.Build.0 = Release|Win32
+ {B808178B-82F0-4CF4-A2B1-921939FA24D0}.Debug|Win32.ActiveCfg = Debug|Win32
+ {B808178B-82F0-4CF4-A2B1-921939FA24D0}.Debug|Win32.Build.0 = Debug|Win32
+ {B808178B-82F0-4CF4-A2B1-921939FA24D0}.Debug|x64.ActiveCfg = Debug|Win32
+ {B808178B-82F0-4CF4-A2B1-921939FA24D0}.Debug|x64.Build.0 = Debug|Win32
+ {B808178B-82F0-4CF4-A2B1-921939FA24D0}.Debug|x64 Setup.ActiveCfg = Debug|Win32
+ {B808178B-82F0-4CF4-A2B1-921939FA24D0}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {B808178B-82F0-4CF4-A2B1-921939FA24D0}.Release|Win32.ActiveCfg = Release|Win32
+ {B808178B-82F0-4CF4-A2B1-921939FA24D0}.Release|Win32.Build.0 = Release|Win32
+ {B808178B-82F0-4CF4-A2B1-921939FA24D0}.Release|x64.ActiveCfg = Release|Win32
+ {B808178B-82F0-4CF4-A2B1-921939FA24D0}.Release|x64.Build.0 = Release|Win32
+ {B808178B-82F0-4CF4-A2B1-921939FA24D0}.Release|x64 Setup.ActiveCfg = Release|Win32
+ {B808178B-82F0-4CF4-A2B1-921939FA24D0}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {9778F1C0-09BC-4698-8EBC-BD982247209A}.All|Win32.ActiveCfg = Release|x64
+ {9778F1C0-09BC-4698-8EBC-BD982247209A}.All|x64.ActiveCfg = Release|x64
+ {9778F1C0-09BC-4698-8EBC-BD982247209A}.All|x64.Build.0 = Release|x64
+ {9778F1C0-09BC-4698-8EBC-BD982247209A}.All|x64 Setup.ActiveCfg = Release|x64
+ {9778F1C0-09BC-4698-8EBC-BD982247209A}.All|x64 Setup.Build.0 = Release|x64
+ {9778F1C0-09BC-4698-8EBC-BD982247209A}.All|x86 Setup.ActiveCfg = Release|x64
+ {9778F1C0-09BC-4698-8EBC-BD982247209A}.Debug|Win32.ActiveCfg = Debug|Win32
+ {9778F1C0-09BC-4698-8EBC-BD982247209A}.Debug|Win32.Build.0 = Debug|Win32
+ {9778F1C0-09BC-4698-8EBC-BD982247209A}.Debug|x64.ActiveCfg = Debug|x64
+ {9778F1C0-09BC-4698-8EBC-BD982247209A}.Debug|x64.Build.0 = Debug|x64
+ {9778F1C0-09BC-4698-8EBC-BD982247209A}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {9778F1C0-09BC-4698-8EBC-BD982247209A}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {9778F1C0-09BC-4698-8EBC-BD982247209A}.Release|Win32.ActiveCfg = Release|Win32
+ {9778F1C0-09BC-4698-8EBC-BD982247209A}.Release|Win32.Build.0 = Release|Win32
+ {9778F1C0-09BC-4698-8EBC-BD982247209A}.Release|x64.ActiveCfg = Release|x64
+ {9778F1C0-09BC-4698-8EBC-BD982247209A}.Release|x64.Build.0 = Release|x64
+ {9778F1C0-09BC-4698-8EBC-BD982247209A}.Release|x64 Setup.ActiveCfg = Release|x64
+ {9778F1C0-09BC-4698-8EBC-BD982247209A}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {AFA983D6-4569-4F88-BA94-555ED00FD9A8}.All|Win32.ActiveCfg = Release|x64
+ {AFA983D6-4569-4F88-BA94-555ED00FD9A8}.All|x64.ActiveCfg = Release|x64
+ {AFA983D6-4569-4F88-BA94-555ED00FD9A8}.All|x64.Build.0 = Release|x64
+ {AFA983D6-4569-4F88-BA94-555ED00FD9A8}.All|x64 Setup.ActiveCfg = Release|x64
+ {AFA983D6-4569-4F88-BA94-555ED00FD9A8}.All|x64 Setup.Build.0 = Release|x64
+ {AFA983D6-4569-4F88-BA94-555ED00FD9A8}.All|x86 Setup.ActiveCfg = Release|x64
+ {AFA983D6-4569-4F88-BA94-555ED00FD9A8}.Debug|Win32.ActiveCfg = Debug|Win32
+ {AFA983D6-4569-4F88-BA94-555ED00FD9A8}.Debug|Win32.Build.0 = Debug|Win32
+ {AFA983D6-4569-4F88-BA94-555ED00FD9A8}.Debug|x64.ActiveCfg = Debug|x64
+ {AFA983D6-4569-4F88-BA94-555ED00FD9A8}.Debug|x64.Build.0 = Debug|x64
+ {AFA983D6-4569-4F88-BA94-555ED00FD9A8}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {AFA983D6-4569-4F88-BA94-555ED00FD9A8}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {AFA983D6-4569-4F88-BA94-555ED00FD9A8}.Release|Win32.ActiveCfg = Release|Win32
+ {AFA983D6-4569-4F88-BA94-555ED00FD9A8}.Release|Win32.Build.0 = Release|Win32
+ {AFA983D6-4569-4F88-BA94-555ED00FD9A8}.Release|x64.ActiveCfg = Release|x64
+ {AFA983D6-4569-4F88-BA94-555ED00FD9A8}.Release|x64.Build.0 = Release|x64
+ {AFA983D6-4569-4F88-BA94-555ED00FD9A8}.Release|x64 Setup.ActiveCfg = Release|x64
+ {AFA983D6-4569-4F88-BA94-555ED00FD9A8}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.All|Win32.ActiveCfg = Release|Win32
+ {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.All|Win32.Build.0 = Release|Win32
+ {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.All|x64.ActiveCfg = Release|Win32
+ {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.All|x64 Setup.ActiveCfg = Release|Win32
+ {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.All|x86 Setup.ActiveCfg = Release|Win32
+ {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.All|x86 Setup.Build.0 = Release|Win32
+ {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.Debug|Win32.ActiveCfg = Debug|Win32
+ {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.Debug|Win32.Build.0 = Debug|Win32
+ {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.Debug|x64.ActiveCfg = Debug|x64
+ {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.Debug|x64.Build.0 = Debug|x64
+ {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.Release|Win32.ActiveCfg = Release|Win32
+ {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.Release|Win32.Build.0 = Release|Win32
+ {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.Release|x64.ActiveCfg = Release|x64
+ {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.Release|x64.Build.0 = Release|x64
+ {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.Release|x64 Setup.ActiveCfg = Release|x64
+ {56B91D01-9150-4BBF-AFA1-5B68AB991B76}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {990BAA76-89D3-4E38-8479-C7B28784EFC8}.All|Win32.ActiveCfg = Release|Win32
+ {990BAA76-89D3-4E38-8479-C7B28784EFC8}.All|Win32.Build.0 = Release|Win32
+ {990BAA76-89D3-4E38-8479-C7B28784EFC8}.All|x64.ActiveCfg = Release|Win32
+ {990BAA76-89D3-4E38-8479-C7B28784EFC8}.All|x64 Setup.ActiveCfg = Release|Win32
+ {990BAA76-89D3-4E38-8479-C7B28784EFC8}.All|x86 Setup.ActiveCfg = Release|Win32
+ {990BAA76-89D3-4E38-8479-C7B28784EFC8}.All|x86 Setup.Build.0 = Release|Win32
+ {990BAA76-89D3-4E38-8479-C7B28784EFC8}.Debug|Win32.ActiveCfg = Debug|Win32
+ {990BAA76-89D3-4E38-8479-C7B28784EFC8}.Debug|Win32.Build.0 = Debug|Win32
+ {990BAA76-89D3-4E38-8479-C7B28784EFC8}.Debug|x64.ActiveCfg = Debug|x64
+ {990BAA76-89D3-4E38-8479-C7B28784EFC8}.Debug|x64.Build.0 = Debug|x64
+ {990BAA76-89D3-4E38-8479-C7B28784EFC8}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {990BAA76-89D3-4E38-8479-C7B28784EFC8}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {990BAA76-89D3-4E38-8479-C7B28784EFC8}.Release|Win32.ActiveCfg = Release|Win32
+ {990BAA76-89D3-4E38-8479-C7B28784EFC8}.Release|Win32.Build.0 = Release|Win32
+ {990BAA76-89D3-4E38-8479-C7B28784EFC8}.Release|x64.ActiveCfg = Release|x64
+ {990BAA76-89D3-4E38-8479-C7B28784EFC8}.Release|x64.Build.0 = Release|x64
+ {990BAA76-89D3-4E38-8479-C7B28784EFC8}.Release|x64 Setup.ActiveCfg = Release|x64
+ {990BAA76-89D3-4E38-8479-C7B28784EFC8}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {1E21AFE0-6FDB-41D2-942D-863607C24B91}.All|Win32.ActiveCfg = Release|x64
+ {1E21AFE0-6FDB-41D2-942D-863607C24B91}.All|x64.ActiveCfg = Release|x64
+ {1E21AFE0-6FDB-41D2-942D-863607C24B91}.All|x64.Build.0 = Release|x64
+ {1E21AFE0-6FDB-41D2-942D-863607C24B91}.All|x64 Setup.ActiveCfg = Release|x64
+ {1E21AFE0-6FDB-41D2-942D-863607C24B91}.All|x64 Setup.Build.0 = Release|x64
+ {1E21AFE0-6FDB-41D2-942D-863607C24B91}.All|x86 Setup.ActiveCfg = Release|x64
+ {1E21AFE0-6FDB-41D2-942D-863607C24B91}.Debug|Win32.ActiveCfg = Debug|Win32
+ {1E21AFE0-6FDB-41D2-942D-863607C24B91}.Debug|Win32.Build.0 = Debug|Win32
+ {1E21AFE0-6FDB-41D2-942D-863607C24B91}.Debug|x64.ActiveCfg = Debug|x64
+ {1E21AFE0-6FDB-41D2-942D-863607C24B91}.Debug|x64.Build.0 = Debug|x64
+ {1E21AFE0-6FDB-41D2-942D-863607C24B91}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {1E21AFE0-6FDB-41D2-942D-863607C24B91}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {1E21AFE0-6FDB-41D2-942D-863607C24B91}.Release|Win32.ActiveCfg = Release|Win32
+ {1E21AFE0-6FDB-41D2-942D-863607C24B91}.Release|Win32.Build.0 = Release|Win32
+ {1E21AFE0-6FDB-41D2-942D-863607C24B91}.Release|x64.ActiveCfg = Release|x64
+ {1E21AFE0-6FDB-41D2-942D-863607C24B91}.Release|x64.Build.0 = Release|x64
+ {1E21AFE0-6FDB-41D2-942D-863607C24B91}.Release|x64 Setup.ActiveCfg = Release|x64
+ {1E21AFE0-6FDB-41D2-942D-863607C24B91}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {2E250296-0C08-4342-9C8A-BCBDD0E7DF65}.All|Win32.ActiveCfg = Release|x64
+ {2E250296-0C08-4342-9C8A-BCBDD0E7DF65}.All|x64.ActiveCfg = Release|x64
+ {2E250296-0C08-4342-9C8A-BCBDD0E7DF65}.All|x64.Build.0 = Release|x64
+ {2E250296-0C08-4342-9C8A-BCBDD0E7DF65}.All|x64 Setup.ActiveCfg = Release|x64
+ {2E250296-0C08-4342-9C8A-BCBDD0E7DF65}.All|x64 Setup.Build.0 = Release|x64
+ {2E250296-0C08-4342-9C8A-BCBDD0E7DF65}.All|x86 Setup.ActiveCfg = Release|x64
+ {2E250296-0C08-4342-9C8A-BCBDD0E7DF65}.Debug|Win32.ActiveCfg = Debug|Win32
+ {2E250296-0C08-4342-9C8A-BCBDD0E7DF65}.Debug|Win32.Build.0 = Debug|Win32
+ {2E250296-0C08-4342-9C8A-BCBDD0E7DF65}.Debug|x64.ActiveCfg = Debug|x64
+ {2E250296-0C08-4342-9C8A-BCBDD0E7DF65}.Debug|x64.Build.0 = Debug|x64
+ {2E250296-0C08-4342-9C8A-BCBDD0E7DF65}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {2E250296-0C08-4342-9C8A-BCBDD0E7DF65}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {2E250296-0C08-4342-9C8A-BCBDD0E7DF65}.Release|Win32.ActiveCfg = Release|Win32
+ {2E250296-0C08-4342-9C8A-BCBDD0E7DF65}.Release|Win32.Build.0 = Release|Win32
+ {2E250296-0C08-4342-9C8A-BCBDD0E7DF65}.Release|x64.ActiveCfg = Release|x64
+ {2E250296-0C08-4342-9C8A-BCBDD0E7DF65}.Release|x64.Build.0 = Release|x64
+ {2E250296-0C08-4342-9C8A-BCBDD0E7DF65}.Release|x64 Setup.ActiveCfg = Release|x64
+ {2E250296-0C08-4342-9C8A-BCBDD0E7DF65}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.All|Win32.ActiveCfg = Release|x64
+ {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.All|x64.ActiveCfg = Release|x64
+ {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.All|x64.Build.0 = Release|x64
+ {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.All|x64 Setup.ActiveCfg = Release|x64
+ {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.All|x64 Setup.Build.0 = Release|x64
+ {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.All|x86 Setup.ActiveCfg = Release|x64
+ {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Debug|Win32.Build.0 = Debug|Win32
+ {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Debug|x64.ActiveCfg = Debug|x64
+ {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Debug|x64.Build.0 = Debug|x64
+ {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Release|Win32.ActiveCfg = Release|Win32
+ {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Release|Win32.Build.0 = Release|Win32
+ {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Release|x64.ActiveCfg = Release|x64
+ {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Release|x64.Build.0 = Release|x64
+ {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Release|x64 Setup.ActiveCfg = Release|x64
+ {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {B4B62169-5AD4-4559-8707-3D933AC5DB39}.All|Win32.ActiveCfg = Release|x64
+ {B4B62169-5AD4-4559-8707-3D933AC5DB39}.All|x64.ActiveCfg = Release|x64
+ {B4B62169-5AD4-4559-8707-3D933AC5DB39}.All|x64.Build.0 = Release|x64
+ {B4B62169-5AD4-4559-8707-3D933AC5DB39}.All|x64 Setup.ActiveCfg = Release|x64
+ {B4B62169-5AD4-4559-8707-3D933AC5DB39}.All|x64 Setup.Build.0 = Release|x64
+ {B4B62169-5AD4-4559-8707-3D933AC5DB39}.All|x86 Setup.ActiveCfg = Release|x64
+ {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Debug|Win32.ActiveCfg = Debug|Win32
+ {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Debug|Win32.Build.0 = Debug|Win32
+ {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Debug|x64.ActiveCfg = Debug|x64
+ {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Debug|x64.Build.0 = Debug|x64
+ {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Release|Win32.ActiveCfg = Release|Win32
+ {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Release|Win32.Build.0 = Release|Win32
+ {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Release|x64.ActiveCfg = Release|x64
+ {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Release|x64.Build.0 = Release|x64
+ {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Release|x64 Setup.ActiveCfg = Release|x64
+ {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.All|Win32.ActiveCfg = Release|x64
+ {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.All|x64.ActiveCfg = Release|x64
+ {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.All|x64.Build.0 = Release|x64
+ {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.All|x64 Setup.ActiveCfg = Release|x64
+ {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.All|x64 Setup.Build.0 = Release|x64
+ {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.All|x86 Setup.ActiveCfg = Release|x64
+ {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.Debug|Win32.ActiveCfg = Debug|Win32
+ {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.Debug|Win32.Build.0 = Debug|Win32
+ {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.Debug|x64.ActiveCfg = Debug|x64
+ {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.Debug|x64.Build.0 = Debug|x64
+ {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.Release|Win32.ActiveCfg = Release|Win32
+ {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.Release|Win32.Build.0 = Release|Win32
+ {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.Release|x64.ActiveCfg = Release|x64
+ {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.Release|x64.Build.0 = Release|x64
+ {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.Release|x64 Setup.ActiveCfg = Release|x64
+ {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {D578E676-7EC8-4548-BD8B-845C635F14AD}.All|Win32.ActiveCfg = Release|Win32
+ {D578E676-7EC8-4548-BD8B-845C635F14AD}.All|Win32.Build.0 = Release|Win32
+ {D578E676-7EC8-4548-BD8B-845C635F14AD}.All|x64.ActiveCfg = Release|Win32
+ {D578E676-7EC8-4548-BD8B-845C635F14AD}.All|x64 Setup.ActiveCfg = Release|Win32
+ {D578E676-7EC8-4548-BD8B-845C635F14AD}.All|x86 Setup.ActiveCfg = Release|Win32
+ {D578E676-7EC8-4548-BD8B-845C635F14AD}.All|x86 Setup.Build.0 = Release|Win32
+ {D578E676-7EC8-4548-BD8B-845C635F14AD}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D578E676-7EC8-4548-BD8B-845C635F14AD}.Debug|Win32.Build.0 = Debug|Win32
+ {D578E676-7EC8-4548-BD8B-845C635F14AD}.Debug|x64.ActiveCfg = Debug|Win32
+ {D578E676-7EC8-4548-BD8B-845C635F14AD}.Debug|x64.Build.0 = Debug|Win32
+ {D578E676-7EC8-4548-BD8B-845C635F14AD}.Debug|x64 Setup.ActiveCfg = Debug|Win32
+ {D578E676-7EC8-4548-BD8B-845C635F14AD}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {D578E676-7EC8-4548-BD8B-845C635F14AD}.Release|Win32.ActiveCfg = Release|Win32
+ {D578E676-7EC8-4548-BD8B-845C635F14AD}.Release|Win32.Build.0 = Release|Win32
+ {D578E676-7EC8-4548-BD8B-845C635F14AD}.Release|x64.ActiveCfg = Release|Win32
+ {D578E676-7EC8-4548-BD8B-845C635F14AD}.Release|x64.Build.0 = Release|Win32
+ {D578E676-7EC8-4548-BD8B-845C635F14AD}.Release|x64 Setup.ActiveCfg = Release|Win32
+ {D578E676-7EC8-4548-BD8B-845C635F14AD}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}.All|Win32.ActiveCfg = Release|x64
+ {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}.All|x64.ActiveCfg = Release|x64
+ {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}.All|x64.Build.0 = Release|x64
+ {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}.All|x64 Setup.ActiveCfg = Release|x64
+ {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}.All|x64 Setup.Build.0 = Release|x64
+ {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}.All|x86 Setup.ActiveCfg = Release|x64
+ {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}.Debug|Win32.ActiveCfg = Debug|Win32
+ {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}.Debug|Win32.Build.0 = Debug|Win32
+ {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}.Debug|x64.ActiveCfg = Debug|x64
+ {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}.Debug|x64.Build.0 = Debug|x64
+ {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}.Release|Win32.ActiveCfg = Release|Win32
+ {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}.Release|Win32.Build.0 = Release|Win32
+ {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}.Release|x64.ActiveCfg = Release|x64
+ {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}.Release|x64.Build.0 = Release|x64
+ {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}.Release|x64 Setup.ActiveCfg = Release|x64
+ {70A49BC2-7500-41D0-B75D-EDCC5BE987A0}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {B889A18E-70A7-44B5-B2C9-47798D4F43B3}.All|Win32.ActiveCfg = Release|x64
+ {B889A18E-70A7-44B5-B2C9-47798D4F43B3}.All|x64.ActiveCfg = Release|x64
+ {B889A18E-70A7-44B5-B2C9-47798D4F43B3}.All|x64.Build.0 = Release|x64
+ {B889A18E-70A7-44B5-B2C9-47798D4F43B3}.All|x64 Setup.ActiveCfg = Release|x64
+ {B889A18E-70A7-44B5-B2C9-47798D4F43B3}.All|x64 Setup.Build.0 = Release|x64
+ {B889A18E-70A7-44B5-B2C9-47798D4F43B3}.All|x86 Setup.ActiveCfg = Release|x64
+ {B889A18E-70A7-44B5-B2C9-47798D4F43B3}.Debug|Win32.ActiveCfg = Debug|Win32
+ {B889A18E-70A7-44B5-B2C9-47798D4F43B3}.Debug|Win32.Build.0 = Debug|Win32
+ {B889A18E-70A7-44B5-B2C9-47798D4F43B3}.Debug|x64.ActiveCfg = Debug|x64
+ {B889A18E-70A7-44B5-B2C9-47798D4F43B3}.Debug|x64.Build.0 = Debug|x64
+ {B889A18E-70A7-44B5-B2C9-47798D4F43B3}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {B889A18E-70A7-44B5-B2C9-47798D4F43B3}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {B889A18E-70A7-44B5-B2C9-47798D4F43B3}.Release|Win32.ActiveCfg = Release|Win32
+ {B889A18E-70A7-44B5-B2C9-47798D4F43B3}.Release|Win32.Build.0 = Release|Win32
+ {B889A18E-70A7-44B5-B2C9-47798D4F43B3}.Release|x64.ActiveCfg = Release|x64
+ {B889A18E-70A7-44B5-B2C9-47798D4F43B3}.Release|x64.Build.0 = Release|x64
+ {B889A18E-70A7-44B5-B2C9-47798D4F43B3}.Release|x64 Setup.ActiveCfg = Release|x64
+ {B889A18E-70A7-44B5-B2C9-47798D4F43B3}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {05C9FB27-480E-4D53-B3B7-7338E2514666}.All|Win32.ActiveCfg = Release|Win32
+ {05C9FB27-480E-4D53-B3B7-7338E2514666}.All|Win32.Build.0 = Release|Win32
+ {05C9FB27-480E-4D53-B3B7-7338E2514666}.All|x64.ActiveCfg = Release|Win32
+ {05C9FB27-480E-4D53-B3B7-7338E2514666}.All|x64 Setup.ActiveCfg = Release|Win32
+ {05C9FB27-480E-4D53-B3B7-7338E2514666}.All|x86 Setup.ActiveCfg = Release|Win32
+ {05C9FB27-480E-4D53-B3B7-7338E2514666}.All|x86 Setup.Build.0 = Release|Win32
+ {05C9FB27-480E-4D53-B3B7-7338E2514666}.Debug|Win32.ActiveCfg = Debug|Win32
+ {05C9FB27-480E-4D53-B3B7-7338E2514666}.Debug|x64.ActiveCfg = Debug|x64
+ {05C9FB27-480E-4D53-B3B7-7338E2514666}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {05C9FB27-480E-4D53-B3B7-7338E2514666}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {05C9FB27-480E-4D53-B3B7-7338E2514666}.Release|Win32.ActiveCfg = Release|Win32
+ {05C9FB27-480E-4D53-B3B7-7338E2514666}.Release|x64.ActiveCfg = Release|x64
+ {05C9FB27-480E-4D53-B3B7-7338E2514666}.Release|x64 Setup.ActiveCfg = Release|x64
+ {05C9FB27-480E-4D53-B3B7-7338E2514666}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {5C2B4D88-3BEA-4FE0-90DF-FA9836099D5F}.All|Win32.ActiveCfg = Release|x64
+ {5C2B4D88-3BEA-4FE0-90DF-FA9836099D5F}.All|x64.ActiveCfg = Release|x64
+ {5C2B4D88-3BEA-4FE0-90DF-FA9836099D5F}.All|x64.Build.0 = Release|x64
+ {5C2B4D88-3BEA-4FE0-90DF-FA9836099D5F}.All|x64 Setup.ActiveCfg = Release|x64
+ {5C2B4D88-3BEA-4FE0-90DF-FA9836099D5F}.All|x64 Setup.Build.0 = Release|x64
+ {5C2B4D88-3BEA-4FE0-90DF-FA9836099D5F}.All|x86 Setup.ActiveCfg = Release|x64
+ {5C2B4D88-3BEA-4FE0-90DF-FA9836099D5F}.Debug|Win32.ActiveCfg = Debug|Win32
+ {5C2B4D88-3BEA-4FE0-90DF-FA9836099D5F}.Debug|Win32.Build.0 = Debug|Win32
+ {5C2B4D88-3BEA-4FE0-90DF-FA9836099D5F}.Debug|x64.ActiveCfg = Debug|x64
+ {5C2B4D88-3BEA-4FE0-90DF-FA9836099D5F}.Debug|x64.Build.0 = Debug|x64
+ {5C2B4D88-3BEA-4FE0-90DF-FA9836099D5F}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {5C2B4D88-3BEA-4FE0-90DF-FA9836099D5F}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {5C2B4D88-3BEA-4FE0-90DF-FA9836099D5F}.Release|Win32.ActiveCfg = Release|Win32
+ {5C2B4D88-3BEA-4FE0-90DF-FA9836099D5F}.Release|Win32.Build.0 = Release|Win32
+ {5C2B4D88-3BEA-4FE0-90DF-FA9836099D5F}.Release|x64.ActiveCfg = Release|x64
+ {5C2B4D88-3BEA-4FE0-90DF-FA9836099D5F}.Release|x64.Build.0 = Release|x64
+ {5C2B4D88-3BEA-4FE0-90DF-FA9836099D5F}.Release|x64 Setup.ActiveCfg = Release|x64
+ {5C2B4D88-3BEA-4FE0-90DF-FA9836099D5F}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {7C22BDFF-CC09-400C-8A09-660733980028}.All|Win32.ActiveCfg = Release|x64
+ {7C22BDFF-CC09-400C-8A09-660733980028}.All|x64.ActiveCfg = Release|x64
+ {7C22BDFF-CC09-400C-8A09-660733980028}.All|x64.Build.0 = Release|x64
+ {7C22BDFF-CC09-400C-8A09-660733980028}.All|x64 Setup.ActiveCfg = Release|x64
+ {7C22BDFF-CC09-400C-8A09-660733980028}.All|x86 Setup.ActiveCfg = Release|x64
+ {7C22BDFF-CC09-400C-8A09-660733980028}.Debug|Win32.ActiveCfg = Debug|Win32
+ {7C22BDFF-CC09-400C-8A09-660733980028}.Debug|Win32.Build.0 = Debug|Win32
+ {7C22BDFF-CC09-400C-8A09-660733980028}.Debug|x64.ActiveCfg = Debug|x64
+ {7C22BDFF-CC09-400C-8A09-660733980028}.Debug|x64.Build.0 = Debug|x64
+ {7C22BDFF-CC09-400C-8A09-660733980028}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {7C22BDFF-CC09-400C-8A09-660733980028}.Debug|x86 Setup.ActiveCfg = Debug|x64
+ {7C22BDFF-CC09-400C-8A09-660733980028}.Release|Win32.ActiveCfg = Release|Win32
+ {7C22BDFF-CC09-400C-8A09-660733980028}.Release|Win32.Build.0 = Release|Win32
+ {7C22BDFF-CC09-400C-8A09-660733980028}.Release|x64.ActiveCfg = Release|x64
+ {7C22BDFF-CC09-400C-8A09-660733980028}.Release|x64.Build.0 = Release|x64
+ {7C22BDFF-CC09-400C-8A09-660733980028}.Release|x64 Setup.ActiveCfg = Release|x64
+ {7C22BDFF-CC09-400C-8A09-660733980028}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {23B4D303-79FC-49E0-89E2-2280E7E28940}.All|Win32.ActiveCfg = Release|x64
+ {23B4D303-79FC-49E0-89E2-2280E7E28940}.All|x64.ActiveCfg = Release|x64
+ {23B4D303-79FC-49E0-89E2-2280E7E28940}.All|x64.Build.0 = Release|x64
+ {23B4D303-79FC-49E0-89E2-2280E7E28940}.All|x64 Setup.ActiveCfg = Release|x64
+ {23B4D303-79FC-49E0-89E2-2280E7E28940}.All|x86 Setup.ActiveCfg = Release|x64
+ {23B4D303-79FC-49E0-89E2-2280E7E28940}.Debug|Win32.ActiveCfg = Debug|Win32
+ {23B4D303-79FC-49E0-89E2-2280E7E28940}.Debug|Win32.Build.0 = Debug|Win32
+ {23B4D303-79FC-49E0-89E2-2280E7E28940}.Debug|x64.ActiveCfg = Debug|x64
+ {23B4D303-79FC-49E0-89E2-2280E7E28940}.Debug|x64.Build.0 = Debug|x64
+ {23B4D303-79FC-49E0-89E2-2280E7E28940}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {23B4D303-79FC-49E0-89E2-2280E7E28940}.Debug|x86 Setup.ActiveCfg = Debug|x64
+ {23B4D303-79FC-49E0-89E2-2280E7E28940}.Release|Win32.ActiveCfg = Release|Win32
+ {23B4D303-79FC-49E0-89E2-2280E7E28940}.Release|Win32.Build.0 = Release|Win32
+ {23B4D303-79FC-49E0-89E2-2280E7E28940}.Release|x64.ActiveCfg = Release|x64
+ {23B4D303-79FC-49E0-89E2-2280E7E28940}.Release|x64.Build.0 = Release|x64
+ {23B4D303-79FC-49E0-89E2-2280E7E28940}.Release|x64 Setup.ActiveCfg = Release|x64
+ {23B4D303-79FC-49E0-89E2-2280E7E28940}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {47886A6C-CCA6-4F9F-A7D4-F97D06FB2B1A}.All|Win32.ActiveCfg = Release|x64
+ {47886A6C-CCA6-4F9F-A7D4-F97D06FB2B1A}.All|x64.ActiveCfg = Release|x64
+ {47886A6C-CCA6-4F9F-A7D4-F97D06FB2B1A}.All|x64.Build.0 = Release|x64
+ {47886A6C-CCA6-4F9F-A7D4-F97D06FB2B1A}.All|x64 Setup.ActiveCfg = Release|x64
+ {47886A6C-CCA6-4F9F-A7D4-F97D06FB2B1A}.All|x86 Setup.ActiveCfg = Release|x64
+ {47886A6C-CCA6-4F9F-A7D4-F97D06FB2B1A}.Debug|Win32.ActiveCfg = Debug|Win32
+ {47886A6C-CCA6-4F9F-A7D4-F97D06FB2B1A}.Debug|Win32.Build.0 = Debug|Win32
+ {47886A6C-CCA6-4F9F-A7D4-F97D06FB2B1A}.Debug|x64.ActiveCfg = Debug|x64
+ {47886A6C-CCA6-4F9F-A7D4-F97D06FB2B1A}.Debug|x64.Build.0 = Debug|x64
+ {47886A6C-CCA6-4F9F-A7D4-F97D06FB2B1A}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {47886A6C-CCA6-4F9F-A7D4-F97D06FB2B1A}.Debug|x86 Setup.ActiveCfg = Debug|x64
+ {47886A6C-CCA6-4F9F-A7D4-F97D06FB2B1A}.Release|Win32.ActiveCfg = Release|Win32
+ {47886A6C-CCA6-4F9F-A7D4-F97D06FB2B1A}.Release|Win32.Build.0 = Release|Win32
+ {47886A6C-CCA6-4F9F-A7D4-F97D06FB2B1A}.Release|x64.ActiveCfg = Release|x64
+ {47886A6C-CCA6-4F9F-A7D4-F97D06FB2B1A}.Release|x64.Build.0 = Release|x64
+ {47886A6C-CCA6-4F9F-A7D4-F97D06FB2B1A}.Release|x64 Setup.ActiveCfg = Release|x64
+ {47886A6C-CCA6-4F9F-A7D4-F97D06FB2B1A}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {50AAC2CE-BFC9-4912-87CC-C6381850D735}.All|Win32.ActiveCfg = Release|x64
+ {50AAC2CE-BFC9-4912-87CC-C6381850D735}.All|x64.ActiveCfg = Release|x64
+ {50AAC2CE-BFC9-4912-87CC-C6381850D735}.All|x64.Build.0 = Release|x64
+ {50AAC2CE-BFC9-4912-87CC-C6381850D735}.All|x64 Setup.ActiveCfg = Release|x64
+ {50AAC2CE-BFC9-4912-87CC-C6381850D735}.All|x86 Setup.ActiveCfg = Release|x64
+ {50AAC2CE-BFC9-4912-87CC-C6381850D735}.Debug|Win32.ActiveCfg = Debug|Win32
+ {50AAC2CE-BFC9-4912-87CC-C6381850D735}.Debug|Win32.Build.0 = Debug|Win32
+ {50AAC2CE-BFC9-4912-87CC-C6381850D735}.Debug|x64.ActiveCfg = Debug|x64
+ {50AAC2CE-BFC9-4912-87CC-C6381850D735}.Debug|x64.Build.0 = Debug|x64
+ {50AAC2CE-BFC9-4912-87CC-C6381850D735}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {50AAC2CE-BFC9-4912-87CC-C6381850D735}.Debug|x86 Setup.ActiveCfg = Debug|x64
+ {50AAC2CE-BFC9-4912-87CC-C6381850D735}.Release|Win32.ActiveCfg = Release|Win32
+ {50AAC2CE-BFC9-4912-87CC-C6381850D735}.Release|Win32.Build.0 = Release|Win32
+ {50AAC2CE-BFC9-4912-87CC-C6381850D735}.Release|x64.ActiveCfg = Release|x64
+ {50AAC2CE-BFC9-4912-87CC-C6381850D735}.Release|x64.Build.0 = Release|x64
+ {50AAC2CE-BFC9-4912-87CC-C6381850D735}.Release|x64 Setup.ActiveCfg = Release|x64
+ {50AAC2CE-BFC9-4912-87CC-C6381850D735}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}.All|Win32.ActiveCfg = Release|x64
+ {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}.All|x64.ActiveCfg = Release|x64
+ {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}.All|x64.Build.0 = Release|x64
+ {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}.All|x64 Setup.ActiveCfg = Release|x64
+ {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}.All|x86 Setup.ActiveCfg = Release|x64
+ {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}.Debug|Win32.ActiveCfg = Debug|Win32
+ {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}.Debug|Win32.Build.0 = Debug|Win32
+ {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}.Debug|x64.ActiveCfg = Debug|x64
+ {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}.Debug|x64.Build.0 = Debug|x64
+ {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}.Debug|x86 Setup.ActiveCfg = Debug|x64
+ {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}.Release|Win32.ActiveCfg = Release|Win32
+ {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}.Release|Win32.Build.0 = Release|Win32
+ {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}.Release|x64.ActiveCfg = Release|x64
+ {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}.Release|x64.Build.0 = Release|x64
+ {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}.Release|x64 Setup.ActiveCfg = Release|x64
+ {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {4748FF56-CA85-4809-97D6-A94C0FAC1D77}.All|Win32.ActiveCfg = Release|x64
+ {4748FF56-CA85-4809-97D6-A94C0FAC1D77}.All|x64.ActiveCfg = Release|x64
+ {4748FF56-CA85-4809-97D6-A94C0FAC1D77}.All|x64.Build.0 = Release|x64
+ {4748FF56-CA85-4809-97D6-A94C0FAC1D77}.All|x64 Setup.ActiveCfg = Release|x64
+ {4748FF56-CA85-4809-97D6-A94C0FAC1D77}.All|x86 Setup.ActiveCfg = Release|x64
+ {4748FF56-CA85-4809-97D6-A94C0FAC1D77}.Debug|Win32.ActiveCfg = Debug|Win32
+ {4748FF56-CA85-4809-97D6-A94C0FAC1D77}.Debug|Win32.Build.0 = Debug|Win32
+ {4748FF56-CA85-4809-97D6-A94C0FAC1D77}.Debug|x64.ActiveCfg = Debug|x64
+ {4748FF56-CA85-4809-97D6-A94C0FAC1D77}.Debug|x64.Build.0 = Debug|x64
+ {4748FF56-CA85-4809-97D6-A94C0FAC1D77}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {4748FF56-CA85-4809-97D6-A94C0FAC1D77}.Debug|x86 Setup.ActiveCfg = Debug|x64
+ {4748FF56-CA85-4809-97D6-A94C0FAC1D77}.Release|Win32.ActiveCfg = Release|Win32
+ {4748FF56-CA85-4809-97D6-A94C0FAC1D77}.Release|Win32.Build.0 = Release|Win32
+ {4748FF56-CA85-4809-97D6-A94C0FAC1D77}.Release|x64.ActiveCfg = Release|x64
+ {4748FF56-CA85-4809-97D6-A94C0FAC1D77}.Release|x64.Build.0 = Release|x64
+ {4748FF56-CA85-4809-97D6-A94C0FAC1D77}.Release|x64 Setup.ActiveCfg = Release|x64
+ {4748FF56-CA85-4809-97D6-A94C0FAC1D77}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {60C542EE-6882-4EA2-8C21-5AB6DB1BA73F}.All|Win32.ActiveCfg = Release|x64
+ {60C542EE-6882-4EA2-8C21-5AB6DB1BA73F}.All|x64.ActiveCfg = Release|x64
+ {60C542EE-6882-4EA2-8C21-5AB6DB1BA73F}.All|x64.Build.0 = Release|x64
+ {60C542EE-6882-4EA2-8C21-5AB6DB1BA73F}.All|x64 Setup.ActiveCfg = Release|x64
+ {60C542EE-6882-4EA2-8C21-5AB6DB1BA73F}.All|x86 Setup.ActiveCfg = Release|x64
+ {60C542EE-6882-4EA2-8C21-5AB6DB1BA73F}.Debug|Win32.ActiveCfg = Debug|Win32
+ {60C542EE-6882-4EA2-8C21-5AB6DB1BA73F}.Debug|Win32.Build.0 = Debug|Win32
+ {60C542EE-6882-4EA2-8C21-5AB6DB1BA73F}.Debug|x64.ActiveCfg = Debug|x64
+ {60C542EE-6882-4EA2-8C21-5AB6DB1BA73F}.Debug|x64.Build.0 = Debug|x64
+ {60C542EE-6882-4EA2-8C21-5AB6DB1BA73F}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {60C542EE-6882-4EA2-8C21-5AB6DB1BA73F}.Debug|x86 Setup.ActiveCfg = Debug|x64
+ {60C542EE-6882-4EA2-8C21-5AB6DB1BA73F}.Release|Win32.ActiveCfg = Release|Win32
+ {60C542EE-6882-4EA2-8C21-5AB6DB1BA73F}.Release|Win32.Build.0 = Release|Win32
+ {60C542EE-6882-4EA2-8C21-5AB6DB1BA73F}.Release|x64.ActiveCfg = Release|x64
+ {60C542EE-6882-4EA2-8C21-5AB6DB1BA73F}.Release|x64.Build.0 = Release|x64
+ {60C542EE-6882-4EA2-8C21-5AB6DB1BA73F}.Release|x64 Setup.ActiveCfg = Release|x64
+ {60C542EE-6882-4EA2-8C21-5AB6DB1BA73F}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {2469B306-B027-4FF2-8815-C9C1EA2CAE79}.All|Win32.ActiveCfg = Release|x64
+ {2469B306-B027-4FF2-8815-C9C1EA2CAE79}.All|x64.ActiveCfg = Release|x64
+ {2469B306-B027-4FF2-8815-C9C1EA2CAE79}.All|x64.Build.0 = Release|x64
+ {2469B306-B027-4FF2-8815-C9C1EA2CAE79}.All|x64 Setup.ActiveCfg = Release|x64
+ {2469B306-B027-4FF2-8815-C9C1EA2CAE79}.All|x86 Setup.ActiveCfg = Release|x64
+ {2469B306-B027-4FF2-8815-C9C1EA2CAE79}.Debug|Win32.ActiveCfg = Debug|Win32
+ {2469B306-B027-4FF2-8815-C9C1EA2CAE79}.Debug|Win32.Build.0 = Debug|Win32
+ {2469B306-B027-4FF2-8815-C9C1EA2CAE79}.Debug|x64.ActiveCfg = Debug|x64
+ {2469B306-B027-4FF2-8815-C9C1EA2CAE79}.Debug|x64.Build.0 = Debug|x64
+ {2469B306-B027-4FF2-8815-C9C1EA2CAE79}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {2469B306-B027-4FF2-8815-C9C1EA2CAE79}.Debug|x86 Setup.ActiveCfg = Debug|x64
+ {2469B306-B027-4FF2-8815-C9C1EA2CAE79}.Release|Win32.ActiveCfg = Release|Win32
+ {2469B306-B027-4FF2-8815-C9C1EA2CAE79}.Release|Win32.Build.0 = Release|Win32
+ {2469B306-B027-4FF2-8815-C9C1EA2CAE79}.Release|x64.ActiveCfg = Release|x64
+ {2469B306-B027-4FF2-8815-C9C1EA2CAE79}.Release|x64.Build.0 = Release|x64
+ {2469B306-B027-4FF2-8815-C9C1EA2CAE79}.Release|x64 Setup.ActiveCfg = Release|x64
+ {2469B306-B027-4FF2-8815-C9C1EA2CAE79}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {26C82FCE-E0CF-4D10-A00C-D8E582FFEB53}.All|Win32.ActiveCfg = Release|x64
+ {26C82FCE-E0CF-4D10-A00C-D8E582FFEB53}.All|x64.ActiveCfg = Release|x64
+ {26C82FCE-E0CF-4D10-A00C-D8E582FFEB53}.All|x64.Build.0 = Release|x64
+ {26C82FCE-E0CF-4D10-A00C-D8E582FFEB53}.All|x64 Setup.ActiveCfg = Release|x64
+ {26C82FCE-E0CF-4D10-A00C-D8E582FFEB53}.All|x86 Setup.ActiveCfg = Release|x64
+ {26C82FCE-E0CF-4D10-A00C-D8E582FFEB53}.Debug|Win32.ActiveCfg = Debug|Win32
+ {26C82FCE-E0CF-4D10-A00C-D8E582FFEB53}.Debug|x64.ActiveCfg = Debug|x64
+ {26C82FCE-E0CF-4D10-A00C-D8E582FFEB53}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {26C82FCE-E0CF-4D10-A00C-D8E582FFEB53}.Debug|x86 Setup.ActiveCfg = Debug|x64
+ {26C82FCE-E0CF-4D10-A00C-D8E582FFEB53}.Release|Win32.ActiveCfg = Release|Win32
+ {26C82FCE-E0CF-4D10-A00C-D8E582FFEB53}.Release|x64.ActiveCfg = Release|x64
+ {26C82FCE-E0CF-4D10-A00C-D8E582FFEB53}.Release|x64 Setup.ActiveCfg = Release|x64
+ {26C82FCE-E0CF-4D10-A00C-D8E582FFEB53}.Release|x86 Setup.ActiveCfg = Release|x64
+ {74B120FF-6935-4DFE-A142-CDB6BEA99C90}.All|Win32.ActiveCfg = Release|x64
+ {74B120FF-6935-4DFE-A142-CDB6BEA99C90}.All|x64.ActiveCfg = Release|x64
+ {74B120FF-6935-4DFE-A142-CDB6BEA99C90}.All|x64.Build.0 = Release|x64
+ {74B120FF-6935-4DFE-A142-CDB6BEA99C90}.All|x64 Setup.ActiveCfg = Release|x64
+ {74B120FF-6935-4DFE-A142-CDB6BEA99C90}.All|x86 Setup.ActiveCfg = Release|x64
+ {74B120FF-6935-4DFE-A142-CDB6BEA99C90}.Debug|Win32.ActiveCfg = Debug|Win32
+ {74B120FF-6935-4DFE-A142-CDB6BEA99C90}.Debug|x64.ActiveCfg = Debug|x64
+ {74B120FF-6935-4DFE-A142-CDB6BEA99C90}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {74B120FF-6935-4DFE-A142-CDB6BEA99C90}.Debug|x86 Setup.ActiveCfg = Debug|x64
+ {74B120FF-6935-4DFE-A142-CDB6BEA99C90}.Release|Win32.ActiveCfg = Release|Win32
+ {74B120FF-6935-4DFE-A142-CDB6BEA99C90}.Release|x64.ActiveCfg = Release|x64
+ {74B120FF-6935-4DFE-A142-CDB6BEA99C90}.Release|x64 Setup.ActiveCfg = Release|x64
+ {74B120FF-6935-4DFE-A142-CDB6BEA99C90}.Release|x86 Setup.ActiveCfg = Release|x64
+ {C13CC324-0032-4492-9A30-310A6BD64FF5}.All|Win32.ActiveCfg = Release|Win32
+ {C13CC324-0032-4492-9A30-310A6BD64FF5}.All|Win32.Build.0 = Release|Win32
+ {C13CC324-0032-4492-9A30-310A6BD64FF5}.All|x64.ActiveCfg = Release|Win32
+ {C13CC324-0032-4492-9A30-310A6BD64FF5}.All|x64 Setup.ActiveCfg = Release|Win32
+ {C13CC324-0032-4492-9A30-310A6BD64FF5}.All|x86 Setup.ActiveCfg = Release|Win32
+ {C13CC324-0032-4492-9A30-310A6BD64FF5}.Debug|Win32.ActiveCfg = Debug|Win32
+ {C13CC324-0032-4492-9A30-310A6BD64FF5}.Debug|Win32.Build.0 = Debug|Win32
+ {C13CC324-0032-4492-9A30-310A6BD64FF5}.Debug|x64.ActiveCfg = Debug|x64
+ {C13CC324-0032-4492-9A30-310A6BD64FF5}.Debug|x64.Build.0 = Debug|x64
+ {C13CC324-0032-4492-9A30-310A6BD64FF5}.Debug|x64 Setup.ActiveCfg = Debug|Win32
+ {C13CC324-0032-4492-9A30-310A6BD64FF5}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {C13CC324-0032-4492-9A30-310A6BD64FF5}.Release|Win32.ActiveCfg = Release|Win32
+ {C13CC324-0032-4492-9A30-310A6BD64FF5}.Release|Win32.Build.0 = Release|Win32
+ {C13CC324-0032-4492-9A30-310A6BD64FF5}.Release|x64.ActiveCfg = Release|x64
+ {C13CC324-0032-4492-9A30-310A6BD64FF5}.Release|x64.Build.0 = Release|x64
+ {C13CC324-0032-4492-9A30-310A6BD64FF5}.Release|x64 Setup.ActiveCfg = Release|Win32
+ {C13CC324-0032-4492-9A30-310A6BD64FF5}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {886B5E9D-F2C2-4AF2-98C8-EF98C4C770E6}.All|Win32.ActiveCfg = Release|x64
+ {886B5E9D-F2C2-4AF2-98C8-EF98C4C770E6}.All|x64.ActiveCfg = Release|x64
+ {886B5E9D-F2C2-4AF2-98C8-EF98C4C770E6}.All|x64.Build.0 = Release|x64
+ {886B5E9D-F2C2-4AF2-98C8-EF98C4C770E6}.All|x64 Setup.ActiveCfg = Release|x64
+ {886B5E9D-F2C2-4AF2-98C8-EF98C4C770E6}.All|x86 Setup.ActiveCfg = Release|x64
+ {886B5E9D-F2C2-4AF2-98C8-EF98C4C770E6}.Debug|Win32.ActiveCfg = Debug|Win32
+ {886B5E9D-F2C2-4AF2-98C8-EF98C4C770E6}.Debug|Win32.Build.0 = Debug|Win32
+ {886B5E9D-F2C2-4AF2-98C8-EF98C4C770E6}.Debug|x64.ActiveCfg = Debug|x64
+ {886B5E9D-F2C2-4AF2-98C8-EF98C4C770E6}.Debug|x64.Build.0 = Debug|x64
+ {886B5E9D-F2C2-4AF2-98C8-EF98C4C770E6}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {886B5E9D-F2C2-4AF2-98C8-EF98C4C770E6}.Debug|x86 Setup.ActiveCfg = Debug|x64
+ {886B5E9D-F2C2-4AF2-98C8-EF98C4C770E6}.Release|Win32.ActiveCfg = Release|Win32
+ {886B5E9D-F2C2-4AF2-98C8-EF98C4C770E6}.Release|Win32.Build.0 = Release|Win32
+ {886B5E9D-F2C2-4AF2-98C8-EF98C4C770E6}.Release|x64.ActiveCfg = Release|x64
+ {886B5E9D-F2C2-4AF2-98C8-EF98C4C770E6}.Release|x64.Build.0 = Release|x64
+ {886B5E9D-F2C2-4AF2-98C8-EF98C4C770E6}.Release|x64 Setup.ActiveCfg = Release|x64
+ {886B5E9D-F2C2-4AF2-98C8-EF98C4C770E6}.Release|x86 Setup.ActiveCfg = Release|x64
+ {652AD5F7-8488-489F-AAD0-7FBE064703B6}.All|Win32.ActiveCfg = Release|Win32
+ {652AD5F7-8488-489F-AAD0-7FBE064703B6}.All|Win32.Build.0 = Release|Win32
+ {652AD5F7-8488-489F-AAD0-7FBE064703B6}.All|x64.ActiveCfg = Release|Win32
+ {652AD5F7-8488-489F-AAD0-7FBE064703B6}.All|x64 Setup.ActiveCfg = Release|Win32
+ {652AD5F7-8488-489F-AAD0-7FBE064703B6}.All|x86 Setup.ActiveCfg = Release|Win32
+ {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Debug|Win32.ActiveCfg = Debug|Win32
+ {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Debug|Win32.Build.0 = Debug|Win32
+ {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Debug|x64.ActiveCfg = Debug|Win32
+ {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Debug|x64.Build.0 = Debug|Win32
+ {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Debug|x64 Setup.ActiveCfg = Debug|Win32
+ {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Debug|x86 Setup.ActiveCfg = Debug|Win32
+ {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Release|Win32.ActiveCfg = Release|Win32
+ {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Release|Win32.Build.0 = Release|Win32
+ {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Release|x64.ActiveCfg = Release|Win32
+ {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Release|x64.Build.0 = Release|Win32
+ {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Release|x64 Setup.ActiveCfg = Release|Win32
+ {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.All|Win32.ActiveCfg = Release|Win32
+ {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.All|Win32.Build.0 = Release|Win32
+ {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.All|x64.ActiveCfg = Release|Win32
+ {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.All|x64 Setup.ActiveCfg = Release|Win32
+ {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.All|x86 Setup.ActiveCfg = Release|Win32
+ {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.Debug|Win32.ActiveCfg = Debug|Win32
+ {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.Debug|Win32.Build.0 = Debug|Win32
+ {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.Debug|x64.ActiveCfg = Debug|x64
+ {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.Debug|x64.Build.0 = Debug|x64
+ {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.Debug|x64 Setup.ActiveCfg = Release|Win32
+ {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.Debug|x86 Setup.ActiveCfg = Release|Win32
+ {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.Release|Win32.ActiveCfg = Release|Win32
+ {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.Release|Win32.Build.0 = Release|Win32
+ {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.Release|x64.ActiveCfg = Release|x64
+ {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.Release|x64.Build.0 = Release|x64
+ {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.Release|x64 Setup.ActiveCfg = Release|Win32
+ {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {D2396DD7-7D38-473A-ABB7-6F96D65AE1B9}.All|Win32.ActiveCfg = Release|x64
+ {D2396DD7-7D38-473A-ABB7-6F96D65AE1B9}.All|x64.ActiveCfg = Release|x64
+ {D2396DD7-7D38-473A-ABB7-6F96D65AE1B9}.All|x64.Build.0 = Release|x64
+ {D2396DD7-7D38-473A-ABB7-6F96D65AE1B9}.All|x64 Setup.ActiveCfg = Release|x64
+ {D2396DD7-7D38-473A-ABB7-6F96D65AE1B9}.All|x86 Setup.ActiveCfg = Release|x64
+ {D2396DD7-7D38-473A-ABB7-6F96D65AE1B9}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D2396DD7-7D38-473A-ABB7-6F96D65AE1B9}.Debug|Win32.Build.0 = Debug|Win32
+ {D2396DD7-7D38-473A-ABB7-6F96D65AE1B9}.Debug|x64.ActiveCfg = Debug|x64
+ {D2396DD7-7D38-473A-ABB7-6F96D65AE1B9}.Debug|x64.Build.0 = Debug|x64
+ {D2396DD7-7D38-473A-ABB7-6F96D65AE1B9}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {D2396DD7-7D38-473A-ABB7-6F96D65AE1B9}.Debug|x86 Setup.ActiveCfg = Debug|x64
+ {D2396DD7-7D38-473A-ABB7-6F96D65AE1B9}.Release|Win32.ActiveCfg = Release|Win32
+ {D2396DD7-7D38-473A-ABB7-6F96D65AE1B9}.Release|Win32.Build.0 = Release|Win32
+ {D2396DD7-7D38-473A-ABB7-6F96D65AE1B9}.Release|x64.ActiveCfg = Release|x64
+ {D2396DD7-7D38-473A-ABB7-6F96D65AE1B9}.Release|x64.Build.0 = Release|x64
+ {D2396DD7-7D38-473A-ABB7-6F96D65AE1B9}.Release|x64 Setup.ActiveCfg = Release|x64
+ {D2396DD7-7D38-473A-ABB7-6F96D65AE1B9}.Release|x86 Setup.ActiveCfg = Release|x64
+ {BED7539C-0099-4A14-AD5D-30828F15A171}.All|Win32.ActiveCfg = Release|x64
+ {BED7539C-0099-4A14-AD5D-30828F15A171}.All|x64.ActiveCfg = Release|x64
+ {BED7539C-0099-4A14-AD5D-30828F15A171}.All|x64.Build.0 = Release|x64
+ {BED7539C-0099-4A14-AD5D-30828F15A171}.All|x64 Setup.ActiveCfg = Release|x64
+ {BED7539C-0099-4A14-AD5D-30828F15A171}.All|x86 Setup.ActiveCfg = Release|x64
+ {BED7539C-0099-4A14-AD5D-30828F15A171}.Debug|Win32.ActiveCfg = Debug|Win32
+ {BED7539C-0099-4A14-AD5D-30828F15A171}.Debug|Win32.Build.0 = Debug|Win32
+ {BED7539C-0099-4A14-AD5D-30828F15A171}.Debug|x64.ActiveCfg = Debug|Win32
+ {BED7539C-0099-4A14-AD5D-30828F15A171}.Debug|x64.Build.0 = Debug|Win32
+ {BED7539C-0099-4A14-AD5D-30828F15A171}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {BED7539C-0099-4A14-AD5D-30828F15A171}.Debug|x86 Setup.ActiveCfg = Debug|x64
+ {BED7539C-0099-4A14-AD5D-30828F15A171}.Release|Win32.ActiveCfg = Release|Win32
+ {BED7539C-0099-4A14-AD5D-30828F15A171}.Release|Win32.Build.0 = Release|Win32
+ {BED7539C-0099-4A14-AD5D-30828F15A171}.Release|x64.ActiveCfg = Release|Win32
+ {BED7539C-0099-4A14-AD5D-30828F15A171}.Release|x64.Build.0 = Release|Win32
+ {BED7539C-0099-4A14-AD5D-30828F15A171}.Release|x64 Setup.ActiveCfg = Release|x64
+ {BED7539C-0099-4A14-AD5D-30828F15A171}.Release|x86 Setup.ActiveCfg = Release|x64
+ {0D108721-EAE8-4BAF-8102-D8960EC93647}.All|Win32.ActiveCfg = Release|x64
+ {0D108721-EAE8-4BAF-8102-D8960EC93647}.All|x64.ActiveCfg = Release|x64
+ {0D108721-EAE8-4BAF-8102-D8960EC93647}.All|x64.Build.0 = Release|x64
+ {0D108721-EAE8-4BAF-8102-D8960EC93647}.All|x64 Setup.ActiveCfg = Release|x64
+ {0D108721-EAE8-4BAF-8102-D8960EC93647}.All|x86 Setup.ActiveCfg = Release|x64
+ {0D108721-EAE8-4BAF-8102-D8960EC93647}.Debug|Win32.ActiveCfg = Debug|Win32
+ {0D108721-EAE8-4BAF-8102-D8960EC93647}.Debug|Win32.Build.0 = Debug|Win32
+ {0D108721-EAE8-4BAF-8102-D8960EC93647}.Debug|x64.ActiveCfg = Debug|x64
+ {0D108721-EAE8-4BAF-8102-D8960EC93647}.Debug|x64.Build.0 = Debug|x64
+ {0D108721-EAE8-4BAF-8102-D8960EC93647}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {0D108721-EAE8-4BAF-8102-D8960EC93647}.Debug|x86 Setup.ActiveCfg = Debug|x64
+ {0D108721-EAE8-4BAF-8102-D8960EC93647}.Release|Win32.ActiveCfg = Release|Win32
+ {0D108721-EAE8-4BAF-8102-D8960EC93647}.Release|Win32.Build.0 = Release|Win32
+ {0D108721-EAE8-4BAF-8102-D8960EC93647}.Release|x64.ActiveCfg = Release|x64
+ {0D108721-EAE8-4BAF-8102-D8960EC93647}.Release|x64.Build.0 = Release|x64
+ {0D108721-EAE8-4BAF-8102-D8960EC93647}.Release|x64 Setup.ActiveCfg = Release|x64
+ {0D108721-EAE8-4BAF-8102-D8960EC93647}.Release|x86 Setup.ActiveCfg = Release|x64
+ {CEE544A9-0303-44C2-8ECE-EFA7D7BCBBBA}.All|Win32.ActiveCfg = Release|x64
+ {CEE544A9-0303-44C2-8ECE-EFA7D7BCBBBA}.All|x64.ActiveCfg = Release|x64
+ {CEE544A9-0303-44C2-8ECE-EFA7D7BCBBBA}.All|x64.Build.0 = Release|x64
+ {CEE544A9-0303-44C2-8ECE-EFA7D7BCBBBA}.All|x64 Setup.ActiveCfg = Release|x64
+ {CEE544A9-0303-44C2-8ECE-EFA7D7BCBBBA}.All|x86 Setup.ActiveCfg = Release|x64
+ {CEE544A9-0303-44C2-8ECE-EFA7D7BCBBBA}.Debug|Win32.ActiveCfg = Debug|Win32
+ {CEE544A9-0303-44C2-8ECE-EFA7D7BCBBBA}.Debug|Win32.Build.0 = Debug|Win32
+ {CEE544A9-0303-44C2-8ECE-EFA7D7BCBBBA}.Debug|x64.ActiveCfg = Debug|x64
+ {CEE544A9-0303-44C2-8ECE-EFA7D7BCBBBA}.Debug|x64.Build.0 = Debug|x64
+ {CEE544A9-0303-44C2-8ECE-EFA7D7BCBBBA}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {CEE544A9-0303-44C2-8ECE-EFA7D7BCBBBA}.Debug|x86 Setup.ActiveCfg = Debug|x64
+ {CEE544A9-0303-44C2-8ECE-EFA7D7BCBBBA}.Release|Win32.ActiveCfg = Release|Win32
+ {CEE544A9-0303-44C2-8ECE-EFA7D7BCBBBA}.Release|Win32.Build.0 = Release|Win32
+ {CEE544A9-0303-44C2-8ECE-EFA7D7BCBBBA}.Release|x64.ActiveCfg = Release|x64
+ {CEE544A9-0303-44C2-8ECE-EFA7D7BCBBBA}.Release|x64.Build.0 = Release|x64
+ {CEE544A9-0303-44C2-8ECE-EFA7D7BCBBBA}.Release|x64 Setup.ActiveCfg = Release|x64
+ {CEE544A9-0303-44C2-8ECE-EFA7D7BCBBBA}.Release|x86 Setup.ActiveCfg = Release|x64
+ {B535402E-38D2-4D54-8360-423ACBD17192}.All|Win32.ActiveCfg = Release|x64
+ {B535402E-38D2-4D54-8360-423ACBD17192}.All|x64.ActiveCfg = Release|x64
+ {B535402E-38D2-4D54-8360-423ACBD17192}.All|x64.Build.0 = Release|x64
+ {B535402E-38D2-4D54-8360-423ACBD17192}.All|x64 Setup.ActiveCfg = Release|x64
+ {B535402E-38D2-4D54-8360-423ACBD17192}.All|x86 Setup.ActiveCfg = Release|x64
+ {B535402E-38D2-4D54-8360-423ACBD17192}.Debug|Win32.ActiveCfg = Debug|Win32
+ {B535402E-38D2-4D54-8360-423ACBD17192}.Debug|Win32.Build.0 = Debug|Win32
+ {B535402E-38D2-4D54-8360-423ACBD17192}.Debug|x64.ActiveCfg = Debug|x64
+ {B535402E-38D2-4D54-8360-423ACBD17192}.Debug|x64.Build.0 = Debug|x64
+ {B535402E-38D2-4D54-8360-423ACBD17192}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {B535402E-38D2-4D54-8360-423ACBD17192}.Debug|x86 Setup.ActiveCfg = Debug|x64
+ {B535402E-38D2-4D54-8360-423ACBD17192}.Release|Win32.ActiveCfg = Release|Win32
+ {B535402E-38D2-4D54-8360-423ACBD17192}.Release|Win32.Build.0 = Release|Win32
+ {B535402E-38D2-4D54-8360-423ACBD17192}.Release|x64.ActiveCfg = Release|x64
+ {B535402E-38D2-4D54-8360-423ACBD17192}.Release|x64.Build.0 = Release|x64
+ {B535402E-38D2-4D54-8360-423ACBD17192}.Release|x64 Setup.ActiveCfg = Release|x64
+ {B535402E-38D2-4D54-8360-423ACBD17192}.Release|x86 Setup.ActiveCfg = Release|x64
+ {47213370-B933-487D-9F45-BCA26D7E2B6F}.All|Win32.ActiveCfg = Release|x86
+ {47213370-B933-487D-9F45-BCA26D7E2B6F}.All|Win32.Build.0 = Release|x86
+ {47213370-B933-487D-9F45-BCA26D7E2B6F}.All|x64.ActiveCfg = Release|x64
+ {47213370-B933-487D-9F45-BCA26D7E2B6F}.All|x64.Build.0 = Release|x64
+ {47213370-B933-487D-9F45-BCA26D7E2B6F}.All|x64 Setup.ActiveCfg = Release|x86
+ {47213370-B933-487D-9F45-BCA26D7E2B6F}.All|x86 Setup.ActiveCfg = Release|x86
+ {47213370-B933-487D-9F45-BCA26D7E2B6F}.Debug|Win32.ActiveCfg = Debug|x86
+ {47213370-B933-487D-9F45-BCA26D7E2B6F}.Debug|x64.ActiveCfg = Debug|x64
+ {47213370-B933-487D-9F45-BCA26D7E2B6F}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {47213370-B933-487D-9F45-BCA26D7E2B6F}.Debug|x64 Setup.Build.0 = Debug|x64
+ {47213370-B933-487D-9F45-BCA26D7E2B6F}.Debug|x86 Setup.ActiveCfg = Debug|x86
+ {47213370-B933-487D-9F45-BCA26D7E2B6F}.Debug|x86 Setup.Build.0 = Debug|x86
+ {47213370-B933-487D-9F45-BCA26D7E2B6F}.Release|Win32.ActiveCfg = Release|x86
+ {47213370-B933-487D-9F45-BCA26D7E2B6F}.Release|x64.ActiveCfg = Release|x64
+ {47213370-B933-487D-9F45-BCA26D7E2B6F}.Release|x64 Setup.ActiveCfg = Release|x64
+ {47213370-B933-487D-9F45-BCA26D7E2B6F}.Release|x64 Setup.Build.0 = Release|x64
+ {47213370-B933-487D-9F45-BCA26D7E2B6F}.Release|x86 Setup.ActiveCfg = Release|x86
+ {47213370-B933-487D-9F45-BCA26D7E2B6F}.Release|x86 Setup.Build.0 = Release|x86
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0} = {F881ADA2-2F1A-4046-9FEB-191D9422D781}
+ {5580D60E-0F77-4716-9CD4-B8E5986FA375} = {F881ADA2-2F1A-4046-9FEB-191D9422D781}
+ {D3EC0AFF-76FC-4210-A825-9A17410660A3} = {F881ADA2-2F1A-4046-9FEB-191D9422D781}
+ {FEA1EEF7-876F-48DE-88BF-C0E3E606D758} = {F881ADA2-2F1A-4046-9FEB-191D9422D781}
+ {7F1610F1-DD5A-4CF7-8610-30AB12C60ADD} = {F881ADA2-2F1A-4046-9FEB-191D9422D781}
+ {8DEB383C-4091-4F42-A56F-C9E46D552D79} = {F881ADA2-2F1A-4046-9FEB-191D9422D781}
+ {2C3C2423-234B-4772-8899-D3B137E5CA35} = {F881ADA2-2F1A-4046-9FEB-191D9422D781}
+ {0B6C905B-142E-4999-B39D-92FF7951E921} = {F881ADA2-2F1A-4046-9FEB-191D9422D781}
+ {D5C87B19-150D-4EF3-A671-96589BD2D14A} = {F881ADA2-2F1A-4046-9FEB-191D9422D781}
+ {4D418176-3B33-47E6-A63E-01BA34ADD21C} = {F881ADA2-2F1A-4046-9FEB-191D9422D781}
+ {AFA983D6-4569-4F88-BA94-555ED00FD9A8} = {F881ADA2-2F1A-4046-9FEB-191D9422D781}
+ {5FD31A25-5D83-4794-8BEE-904DAD84CE71} = {9460B5F1-0A95-41C4-BEB7-9C2C96459A7C}
+ {FFAA4C52-3A53-4F99-90C1-D59D1F0427F3} = {9460B5F1-0A95-41C4-BEB7-9C2C96459A7C}
+ {0DF3ABD0-DDC0-4265-B778-07C66780979B} = {9460B5F1-0A95-41C4-BEB7-9C2C96459A7C}
+ {B3F424EC-3D8F-417C-B244-3919D5E1A577} = {9460B5F1-0A95-41C4-BEB7-9C2C96459A7C}
+ {05C9FB27-480E-4D53-B3B7-6338E2526666} = {9460B5F1-0A95-41C4-BEB7-9C2C96459A7C}
+ {CC1DD008-9406-448D-A0AD-33C3186CFADB} = {9460B5F1-0A95-41C4-BEB7-9C2C96459A7C}
+ {48414740-C693-4968-9846-EE058020C64F} = {9460B5F1-0A95-41C4-BEB7-9C2C96459A7C}
+ {C6E78A4C-DB1E-47F4-9B63-4DC27D86343F} = {9460B5F1-0A95-41C4-BEB7-9C2C96459A7C}
+ {05C9FB27-480E-4D53-B3B7-7338E2514666} = {9460B5F1-0A95-41C4-BEB7-9C2C96459A7C}
+ {74B120FF-6935-4DFE-A142-CDB6BEA99C90} = {9460B5F1-0A95-41C4-BEB7-9C2C96459A7C}
+ {30A5B29C-983E-4580-9FD0-D647CCDCC7EB} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {B69247FA-ECD6-40ED-8E44-5CA6C3BAF9A4} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {C24FB505-05D7-4319-8485-7540B44C8603} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {B5881A85-FE70-4F64-8607-2CAAE52669C6} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {71A967D5-0E99-4CEF-A587-98836EE6F2EF} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {3850D93A-5F24-4922-BC1C-74D08C37C256} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {D7F1E3F2-A3F4-474C-8555-15122571AF52} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {75DF7F29-2FBF-47F7-B5AF-5B4952DC1ABD} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {F6A33240-8F29-48BD-98F0-826995911799} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {65A6273D-FCAB-4C55-B09E-65100141A5D4} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {E3246D17-E29B-4AB5-962A-C69B0C5837BB} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {2A3D00C6-588D-4E86-81AC-9EF5EDE86E03} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {14E4A972-9CFB-436D-B0A5-4943F3F80D47} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {329FD5B0-EF28-4606-86D0-F6EA21CF8E36} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {1A3793D1-05D1-4B57-9B0F-5AF3E79DC439} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {11C9BC3D-45E9-46E3-BE84-B8CEE4685E39} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {3C977801-FE88-48F2-83D3-FA2EBFF6688E} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {432DB165-1EB2-4781-A9C0-71E62610B20A} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {990BAA76-89D3-4E38-8479-C7B28784EFC8} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {1E21AFE0-6FDB-41D2-942D-863607C24B91} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {2E250296-0C08-4342-9C8A-BCBDD0E7DF65} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {B889A18E-70A7-44B5-B2C9-47798D4F43B3} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {5C2B4D88-3BEA-4FE0-90DF-FA9836099D5F} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {47886A6C-CCA6-4F9F-A7D4-F97D06FB2B1A} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {50AAC2CE-BFC9-4912-87CC-C6381850D735} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {A61D7CB4-75A5-4A55-8CA1-BE5AF615D921} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {4748FF56-CA85-4809-97D6-A94C0FAC1D77} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {60C542EE-6882-4EA2-8C21-5AB6DB1BA73F} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {2469B306-B027-4FF2-8815-C9C1EA2CAE79} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {886B5E9D-F2C2-4AF2-98C8-EF98C4C770E6} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
+ {07113B25-D3AF-4E04-BA77-4CD1171F022C} = {C5F182F9-754A-4EC5-B50F-76ED02BE13F4}
+ {A27CCA23-1541-4337-81A4-F0A6413078A0} = {C5F182F9-754A-4EC5-B50F-76ED02BE13F4}
+ {E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24} = {C5F182F9-754A-4EC5-B50F-76ED02BE13F4}
+ {784113EF-44D9-4949-835D-7065D3C7AD08} = {9ADF1E48-2F5C-4ED7-A893-596259FABFE0}
+ {05515420-16DE-4E63-BE73-85BE85BA5142} = {9ADF1E48-2F5C-4ED7-A893-596259FABFE0}
+ {44D7DEAF-FDA5-495E-8B9D-1439E4F4C21E} = {9ADF1E48-2F5C-4ED7-A893-596259FABFE0}
+ {AFAC0568-7548-42D5-9F6A-8D3400A1E4F6} = {A5A27244-AD24-46E5-B01B-840CD296C91D}
+ {9254C4B0-6F60-42B6-BB3A-36D63FC001C7} = {A5A27244-AD24-46E5-B01B-840CD296C91D}
+ {2CA40887-1622-46A1-A7F9-17FD7E7E545B} = {A5A27244-AD24-46E5-B01B-840CD296C91D}
+ {6FF941AC-82C5-429F-AA4C-AD2FB9E5DA52} = {A5A27244-AD24-46E5-B01B-840CD296C91D}
+ {38FE0559-9910-43A8-9E45-3E5004C27692} = {A5A27244-AD24-46E5-B01B-840CD296C91D}
+ {CBD81696-EFB4-4D2F-8451-1B8DAA86155A} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {62F27B1A-C919-4A70-8478-51F178F3B18F} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {89385C74-5860-4174-9CAF-A39E7C48909C} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {1906D736-08BD-4EE1-924F-B536249B9A54} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {EEF031CB-FED8-451E-A471-91EC8D4F6750} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {6EDFEFD5-3596-4FA9-8EBA-B331547B35A3} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {8D04B550-D240-4A44-8A18-35DA3F7038D9} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {1CED5987-A529-46DC-B30F-870D85FF9C94} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {F057DA7F-79E5-4B00-845C-EF446EF055E3} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {E727E8F6-935D-46FE-8B0E-37834748A0E3} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {3D0370CA-BED2-4657-A475-32375CBCB6E4} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {87EE9DA4-DE1E-4448-8324-183C98DCA588} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {155844C3-EC5F-407F-97A4-A2DDADED9B2F} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {204FA0DE-305D-4414-AE2E-F195A23F390D} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {DF018947-0FFF-4EB3-BDEE-441DC81DA7A4} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {4043FC6A-9A30-4577-8AD5-9B233C9575D8} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {0A18A071-125E-442F-AFF7-A3F68ABECF99} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {2F025EAD-99BD-40F5-B2CC-F0A28CAD7F2D} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {94001A0E-A837-445C-8004-F918F10D0226} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {0AD1177E-1FD8-4643-9391-431467A11084} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {E316772F-5D8F-4F2A-8F71-094C3E859D34} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {D3D8B329-20BE-475E-9E83-653CEA0E0EF5} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {0FEEAEC6-4399-4C46-B7DB-62ECE80D15B4} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {419C8F80-D858-4B48-A25C-AF4007608137} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {1BC8A8EC-E03B-44DF-BCD9-088650F4D29C} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {CF405366-9558-4AE8-90EF-5E21B51CCB4E} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {401A40CD-5DB4-4E34-AC68-FA99E9FAC014} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {E972C52F-9E85-4D65-B19C-031E511E9DB4} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {03207781-0D1C-4DB3-A71D-45C608F28DBD} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {9A5DDF08-C88C-4A35-B7F6-D605228446BD} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {D0B36172-CD76-454A-9B89-990025266C2A} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {DEE932AB-5911-4700-9EEB-8C7090A0A330} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {329A6FA0-0FCC-4435-A950-E670AEFA9838} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {CF70F278-3364-4395-A2E1-23501C9B8AD2} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {ABB71A76-42B0-47A4-973A-42E3D920C6FD} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {9778F1C0-09BC-4698-8EBC-BD982247209A} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {56B91D01-9150-4BBF-AFA1-5B68AB991B76} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {E4D29906-8B73-4F8A-B5F4-CA8BFA648F5A} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {70A49BC2-7500-41D0-B75D-EDCC5BE987A0} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {23B4D303-79FC-49E0-89E2-2280E7E28940} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {9DE35039-A8F6-4FBF-B1B6-EB527F802411} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {26C82FCE-E0CF-4D10-A00C-D8E582FFEB53} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {C13CC324-0032-4492-9A30-310A6BD64FF5} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B}
+ {EC3E5C7F-EE09-47E2-80FE-546363D14A98} = {B8F5B47B-8568-46EB-B320-64C17D2A98BC}
+ {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F} = {0C808854-54D1-4230-BFF5-77B5FD905000}
+ {ACFFF684-4D19-4D48-AF12-88EA1D778BDF} = {0C808854-54D1-4230-BFF5-77B5FD905000}
+ {8F992C49-6C51-412F-B2A3-34EAB708EB65} = {0C808854-54D1-4230-BFF5-77B5FD905000}
+ {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF} = {0C808854-54D1-4230-BFF5-77B5FD905000}
+ {028C7278-05D7-4E18-82FE-BE231B844F41} = {0C808854-54D1-4230-BFF5-77B5FD905000}
+ {36E854E3-CE12-4348-A125-CCF3F9D74813} = {0C808854-54D1-4230-BFF5-77B5FD905000}
+ {7B077E7F-1BE7-4291-AB86-55E527B25CAC} = {0C808854-54D1-4230-BFF5-77B5FD905000}
+ {7B42BDA1-72C0-4378-A9B6-5C530F8CD61E} = {0C808854-54D1-4230-BFF5-77B5FD905000}
+ {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0} = {0C808854-54D1-4230-BFF5-77B5FD905000}
+ {692F6330-4D87-4C82-81DF-40DB5892636E} = {4CF6A6AC-07DE-4B9E-ABE1-7F98B64E0BB0}
+ {2286DA73-9FC5-45BC-A508-85994C3317AB} = {4CF6A6AC-07DE-4B9E-ABE1-7F98B64E0BB0}
+ {66444AEE-554C-11DD-A9F0-8C5D56D89593} = {4CF6A6AC-07DE-4B9E-ABE1-7F98B64E0BB0}
+ {D07C378A-F5F7-438F-ADF3-4AC4FB1883CD} = {4CF6A6AC-07DE-4B9E-ABE1-7F98B64E0BB0}
+ {1C453396-D912-4213-89FD-9B489162B7B5} = {A7AB4405-FDB7-4853-9FBB-1516B1C3D80A}
+ {D0BCAC02-D94B-46B8-9B49-CDDCC2BD7909} = {A7AB4405-FDB7-4853-9FBB-1516B1C3D80A}
+ {CBEC7225-0C21-4DA8-978E-1F158F8AD950} = {F69A4A6B-9360-4EBB-A280-22AA3C455AC5}
+ {AB91A099-7690-4ECF-8994-E458F4EA1ED4} = {F69A4A6B-9360-4EBB-A280-22AA3C455AC5}
+ {08DAD348-9E0A-4A2E-97F1-F1E7E24A7836} = {F69A4A6B-9360-4EBB-A280-22AA3C455AC5}
+ {1A1FF289-4FD6-4285-A422-D31DD67A4723} = {CBD81696-EFB4-4D2F-8451-1B8DAA86155A}
+ {8B3B4C4C-13C2-446C-BEB0-F412CC2CFB9A} = {C120A020-773F-4EA3-923F-B67AF28B750D}
+ {4F92B672-DADB-4047-8D6A-4BB3796733FD} = {C120A020-773F-4EA3-923F-B67AF28B750D}
+ {2DEE4895-1134-439C-B688-52203E57D878} = {C120A020-773F-4EA3-923F-B67AF28B750D}
+ {AF8163EE-FA76-4904-A11D-7D70A1B5BA2E} = {C120A020-773F-4EA3-923F-B67AF28B750D}
+ {3CE1DC99-8246-4DB1-A709-74F19F08EC67} = {C120A020-773F-4EA3-923F-B67AF28B750D}
+ {87A1FE3D-F410-4C8E-9591-8C625985BC70} = {C120A020-773F-4EA3-923F-B67AF28B750D}
+ {6E49F6C2-ADDA-4BFB-81FE-AB9AF51B455F} = {C120A020-773F-4EA3-923F-B67AF28B750D}
+ {D5D2BF72-29FE-4982-A9FA-82FDD086DB1B} = {C120A020-773F-4EA3-923F-B67AF28B750D}
+ {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B} = {C120A020-773F-4EA3-923F-B67AF28B750D}
+ {D5D2BF72-29FE-4982-A9FA-82AB3086DB1B} = {C120A020-773F-4EA3-923F-B67AF28B750D}
+ {D5D2BF72-29FE-4982-A9FA-82AB1086DB1B} = {C120A020-773F-4EA3-923F-B67AF28B750D}
+ {E796E337-DE78-4303-8614-9A590862EE95} = {C120A020-773F-4EA3-923F-B67AF28B750D}
+ {1F0A8A77-E661-418F-BB92-82172AE43803} = {C120A020-773F-4EA3-923F-B67AF28B750D}
+ {4F5C9D55-98EF-4256-8311-32D7BD360406} = {C120A020-773F-4EA3-923F-B67AF28B750D}
+ {E10571C4-E7F4-4608-B5F2-B22E7EB95400} = {C120A020-773F-4EA3-923F-B67AF28B750D}
+ {FFF82F9B-6A2B-4BE3-95D8-DC5A4FC71E19} = {C120A020-773F-4EA3-923F-B67AF28B750D}
+ {B808178B-82F0-4CF4-A2B1-921939FA24D0} = {C120A020-773F-4EA3-923F-B67AF28B750D}
+ {D578E676-7EC8-4548-BD8B-845C635F14AD} = {C120A020-773F-4EA3-923F-B67AF28B750D}
+ {652AD5F7-8488-489F-AAD0-7FBE064703B6} = {C120A020-773F-4EA3-923F-B67AF28B750D}
+ {988CACF7-3FCB-4992-BE69-77872AE67DC8} = {6CD61A1D-797C-470A-BE08-8C31B68BB336}
+ {5BC072DB-3826-48EA-AF34-FE32AA01E83B} = {6CD61A1D-797C-470A-BE08-8C31B68BB336}
+ {FA429E98-8B03-45E6-A096-A4BC5E821DE4} = {6CD61A1D-797C-470A-BE08-8C31B68BB336}
+ {06E3A538-AB32-44F2-B477-755FF9CB5D37} = {6CD61A1D-797C-470A-BE08-8C31B68BB336}
+ {6D1BEC70-4DCD-4FE9-ADBD-4A43A67E4D05} = {6CD61A1D-797C-470A-BE08-8C31B68BB336}
+ {A4B122CF-5196-476B-8C0E-D8BD59AC3C14} = {6CD61A1D-797C-470A-BE08-8C31B68BB336}
+ {B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E} = {6CD61A1D-797C-470A-BE08-8C31B68BB336}
+ {0382E8FD-CFDC-41C0-8B03-792C7C84FC31} = {6CD61A1D-797C-470A-BE08-8C31B68BB336}
+ {7C22BDFF-CC09-400C-8A09-660733980028} = {6CD61A1D-797C-470A-BE08-8C31B68BB336}
+ {3B08FEFD-4D3D-4C16-BA94-EE83509E32A0} = {57D119DC-484F-420F-B9E9-8589FD9A8DF8}
+ {3C90CCF0-2CDD-4A7A-ACFF-208C1E271692} = {3B08FEFD-4D3D-4C16-BA94-EE83509E32A0}
+ {C7E2382E-2C22-4D18-BF93-80C6A1FFA7AC} = {3B08FEFD-4D3D-4C16-BA94-EE83509E32A0}
+ {FC71C66E-E268-4EAD-B1F5-F008DC382E83} = {3B08FEFD-4D3D-4C16-BA94-EE83509E32A0}
+ {8E2E8798-8B6F-4A55-8E4F-4E6FDE40ED26} = {3B08FEFD-4D3D-4C16-BA94-EE83509E32A0}
+ {09455AA9-C243-4F16-A1A1-A016881A2765} = {3B08FEFD-4D3D-4C16-BA94-EE83509E32A0}
+ {CDE9B06A-3C27-4987-8FAE-DF1006BC705D} = {DB1024A8-41BF-4AD7-9AE6-13202230D1F3}
+ {57199684-EC63-4A60-9DC6-11815AF6B413} = {09455AA9-C243-4F16-A1A1-A016881A2765}
+ {2DED4BA2-D6B0-4064-BB2A-76DE3AA49E7C} = {09455AA9-C243-4F16-A1A1-A016881A2765}
+ {D4A12E4C-DBDA-4614-BA26-3425AE9F60F5} = {09455AA9-C243-4F16-A1A1-A016881A2765}
+ {765EF1B9-5027-4820-BC37-A44466A51631} = {57199684-EC63-4A60-9DC6-11815AF6B413}
+ {713E4747-1126-40B1-BD84-58F9A7745423} = {57199684-EC63-4A60-9DC6-11815AF6B413}
+ {D3E5C8ED-3A6A-4FEA-92A2-48A0BA865358} = {2DED4BA2-D6B0-4064-BB2A-76DE3AA49E7C}
+ {CC3E7F48-2590-49CB-AD8B-BE3650F55462} = {2DED4BA2-D6B0-4064-BB2A-76DE3AA49E7C}
+ {F1B71990-EB04-4EB5-B28A-BC3EB6F7E843} = {D4A12E4C-DBDA-4614-BA26-3425AE9F60F5}
+ {3DAF028C-AB5B-4183-A01B-DCC43F5A87F0} = {D4A12E4C-DBDA-4614-BA26-3425AE9F60F5}
+ {7A8D8174-B355-4114-AFC1-04777CB9DE0A} = {4F227C26-768F-46A3-8684-1D08A46FB374}
+ {7EB71250-F002-4ED8-92CA-CA218114537A} = {4F227C26-768F-46A3-8684-1D08A46FB374}
+ {464AAB78-5489-4916-BE51-BF8D61822311} = {4F227C26-768F-46A3-8684-1D08A46FB374}
+ {D1ABE208-6442-4FB4-9AAD-1677E41BC870} = {4F227C26-768F-46A3-8684-1D08A46FB374}
+ {BA599D0A-4310-4505-91DA-6A6447B3E289} = {4F227C26-768F-46A3-8684-1D08A46FB374}
+ {EED13FC7-4F81-4E6F-93DB-CDB7DF5CF959} = {4F227C26-768F-46A3-8684-1D08A46FB374}
+ {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2} = {62F27B1A-C919-4A70-8478-51F178F3B18F}
+ {B5A00BFA-6083-4FAE-A097-71642D6473B5} = {62F27B1A-C919-4A70-8478-51F178F3B18F}
+ {1C320193-46A6-4B34-9C56-8AB584FC1B56} = {62F27B1A-C919-4A70-8478-51F178F3B18F}
+ {72782932-37CC-46AE-8C7F-9A7B1A6EE108} = {62F27B1A-C919-4A70-8478-51F178F3B18F}
+ {12A49562-BAB9-43A3-A21D-15B60BBB4C31} = {62F27B1A-C919-4A70-8478-51F178F3B18F}
+ {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA} = {62F27B1A-C919-4A70-8478-51F178F3B18F}
+ {504B3154-7A4F-459D-9877-B951021C3F1F} = {62F27B1A-C919-4A70-8478-51F178F3B18F}
+ {746F3632-5BB2-4570-9453-31D6D58A7D8E} = {62F27B1A-C919-4A70-8478-51F178F3B18F}
+ {DEB01ACB-D65F-4A62-AED9-58C1054499E9} = {62F27B1A-C919-4A70-8478-51F178F3B18F}
+ {D331904D-A00A-4694-A5A3-FCFF64AB5DBE} = {E4D29906-8B73-4F8A-B5F4-CA8BFA648F5A}
+ {B4B62169-5AD4-4559-8707-3D933AC5DB39} = {E4D29906-8B73-4F8A-B5F4-CA8BFA648F5A}
+ {25BD39B1-C8BF-4676-A738-9CABD9C6BC79} = {E4D29906-8B73-4F8A-B5F4-CA8BFA648F5A}
+ {D2396DD7-7D38-473A-ABB7-6F96D65AE1B9} = {9DE35039-A8F6-4FBF-B1B6-EB527F802411}
+ {BED7539C-0099-4A14-AD5D-30828F15A171} = {9DE35039-A8F6-4FBF-B1B6-EB527F802411}
+ {0D108721-EAE8-4BAF-8102-D8960EC93647} = {9DE35039-A8F6-4FBF-B1B6-EB527F802411}
+ {CEE544A9-0303-44C2-8ECE-EFA7D7BCBBBA} = {9DE35039-A8F6-4FBF-B1B6-EB527F802411}
+ {B535402E-38D2-4D54-8360-423ACBD17192} = {9DE35039-A8F6-4FBF-B1B6-EB527F802411}
+ EndGlobalSection
+EndGlobal
diff --git a/Makefile.am b/Makefile.am
index ddcf2fca06..c792e0caf4 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -3,8 +3,8 @@ SUBDIRS = . src
AUTOMAKE_OPTIONS = foreign
NAME = freeswitch
-AM_CFLAGS = $(SWITCH_AM_CFLAGS) $(SWITCH_ANSI_CFLAGS)
-AM_CPPFLAGS = $(SWITCH_AM_CXXFLAGS)
+AM_CFLAGS = $(SWITCH_AM_CFLAGS) $(SWITCH_ANSI_CFLAGS)
+AM_CPPFLAGS = $(SWITCH_AM_CXXFLAGS) -Ilibs/sofia-sip/libsofia-sip-ua/sdp/sofia-sip -Ilibs/sofia-sip/libsofia-sip-ua/su
AM_LDFLAGS = $(SWITCH_AM_LDFLAGS)
DEFAULT_SOUNDS=en-us-callie-8000
@@ -159,11 +159,11 @@ CORE_CFLAGS += -I$(switch_srcdir)/libs/libzrtp/third_party/bgaes
CORE_CFLAGS += -I$(switch_srcdir)/libs/libzrtp/third_party/bnlib
CORE_CFLAGS += -isystem $(switch_srcdir)/libs/libzrtp/include
ZRTP_LDFLAGS = -L$(switch_srcdir)/libs/libzrtp/third_party/bnlib
-ZRTP_LDFLAGS += -L$(switch_srcdir)/libs/libzrtp/projects/gnu/build
+ZRTP_LDFLAGS += -L$(switch_srcdir)/libs/libzrtp
ZRTP_LIBS = -lbn -lzrtp
libfreeswitch_la_LDFLAGS += $(ZRTP_LDFLAGS)
libfreeswitch_la_LIBADD += $(ZRTP_LIBS)
-CORE_LIBS += libs/libzrtp/projects/gnu/build/libzrtp.a
+CORE_LIBS += libs/libzrtp/libzrtp.a
LIBS += libs/libzrtp/third_party/bnlib/libbn.a
endif
@@ -441,8 +441,16 @@ src/include/switch_version.h: src/include/switch_version.h.in Makefile build/pri
libs/libedit/src/.libs/libedit.a:
cd libs/libedit && $(MAKE)
-libs/libzrtp/projects/gnu/build/libzrtp.a:
- cd libs/libzrtp/projects/gnu && $(MAKE)
+libs/libzrtp/libzrtp.a:
+ cd libs/libzrtp && $(MAKE)
+
+libs/sofia-sip/Makefile:
+ cd libs/sofia-sip && sh ./configure.gnu --prefix=$(prefix)
+
+libs/sofia-sip/libsofia-sip-ua/sdp/.libs/libsdp.a libs/sofia-sip/libsofia-sip-ua/su/.libs/libsu.a: libs/sofia-sip/.update libs/sofia-sip/Makefile
+ @cd libs/sofia-sip && $(MAKE) noop
+ @cd libs/sofia-sip && $(MAKE) SOFIA_CFLAGS="$(SWITCH_AM_CFLAGS)"
+ @$(TOUCH_TARGET)
libs/curl/Makefile:
cd libs/curl && sh ./configure.gnu --prefix=$(prefix)
diff --git a/bootstrap.sh b/bootstrap.sh
index f6d4cfd05a..cdf0711a7b 100755
--- a/bootstrap.sh
+++ b/bootstrap.sh
@@ -347,7 +347,7 @@ bootstrap_apr() {
}
bootstrap_libzrtp() {
- (cd ${LIBDIR}/libzrtp/projects/gnu && ./bootstrap.sh)
+ (cd ${LIBDIR}/libzrtp && ./bootstrap.sh)
}
# Libs automake automation function
diff --git a/conf/vanilla/autoload_configs/modules.conf.xml b/conf/vanilla/autoload_configs/modules.conf.xml
index a12b9684ba..d271b2ea96 100644
--- a/conf/vanilla/autoload_configs/modules.conf.xml
+++ b/conf/vanilla/autoload_configs/modules.conf.xml
@@ -48,6 +48,7 @@
+
diff --git a/conf/vanilla/autoload_configs/voicemail_ivr.conf.xml b/conf/vanilla/autoload_configs/voicemail_ivr.conf.xml
index 529509a495..1cdf3c222e 100644
--- a/conf/vanilla/autoload_configs/voicemail_ivr.conf.xml
+++ b/conf/vanilla/autoload_configs/voicemail_ivr.conf.xml
@@ -26,6 +26,7 @@
+
@@ -57,11 +58,14 @@
@@ -105,7 +108,7 @@
-
+
@@ -117,7 +120,7 @@
-
+
@@ -132,7 +135,7 @@
-
+
@@ -146,7 +149,7 @@
-
+
diff --git a/conf/vanilla/lang/en/vm/voicemail_ivr.xml b/conf/vanilla/lang/en/vm/voicemail_ivr.xml
index 590026a29d..1c48299430 100644
--- a/conf/vanilla/lang/en/vm/voicemail_ivr.xml
+++ b/conf/vanilla/lang/en/vm/voicemail_ivr.xml
@@ -11,8 +11,8 @@
-
-
+
+
@@ -89,7 +89,7 @@
-
+
@@ -97,7 +97,7 @@
-
+
@@ -105,16 +105,24 @@
-
+
-
-
+
+
+
+
+
+
+
+
+
+
@@ -264,6 +272,7 @@
+
diff --git a/conf/vanilla/vars.xml b/conf/vanilla/vars.xml
index f6b3431e9c..2792a567ce 100644
--- a/conf/vanilla/vars.xml
+++ b/conf/vanilla/vars.xml
@@ -231,6 +231,7 @@
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -635,6 +660,16 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/phrase/phrase_zh_CN.xml b/docs/phrase/phrase_zh_CN.xml
new file mode 100644
index 0000000000..112032d71c
--- /dev/null
+++ b/docs/phrase/phrase_zh_CN.xml
@@ -0,0 +1,515 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/fscomm/FSComm.2012.vcxproj b/fscomm/FSComm.2012.vcxproj
new file mode 100644
index 0000000000..8fe6f059c9
--- /dev/null
+++ b/fscomm/FSComm.2012.vcxproj
@@ -0,0 +1,541 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+
+ FSComm
+ {7D3122C7-C9D0-3748-81F8-F0DDCB40BF5E}
+ FSComm
+ Qt4VSv1.0
+
+
+
+ Application
+ false
+ v110
+
+
+ Application
+ false
+ v110
+
+
+
+
+
+
+
+
+
+
+
+
+ <_ProjectFileVersion>10.0.30319.1
+ .\
+ debug\
+ true
+ .\
+ release\
+ true
+ false
+
+
+
+ 0
+ Unsigned
+ None
+
+
+ -Zm200 -w34100 -w34189 -w34100 -w34189 %(AdditionalOptions)
+ Disabled
+ $(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include;.;$(QTDIR)\include\ActiveQt;debug;$(QTDIR)\mkspecs\win32-msvc2008;..\src\include;$(QTDIR)\include\QtXml;%(AdditionalIncludeDirectories)
+ _WINDOWS;UNICODE;WIN32;QT_LARGEFILE_SUPPORT;QT_DLL;QT_GUI_LIB;QT_CORE_LIB;QT_THREAD_SUPPORT;%(PreprocessorDefinitions)
+ false
+ false
+ Sync
+ MultiThreadedDebugDLL
+ false
+ false
+ true
+
+
+ $(IntDir)
+ $(IntDir)
+ Level3
+ true
+ ProgramDatabase
+
+
+ _WINDOWS;UNICODE;WIN32;QT_LARGEFILE_SUPPORT;QT_DLL;QT_GUI_LIB;QT_CORE_LIB;QT_THREAD_SUPPORT;_DEBUG;%(PreprocessorDefinitions)
+
+
+ "/MANIFESTDEPENDENCY:type=%27win32%27 name=%27Microsoft.Windows.Common-Controls%27 version=%276.0.0.0%27 publicKeyToken=%276595b64144ccf1df%27 language=%27*%27 processorArchitecture=%27*%27" "/MANIFESTDEPENDENCY:type=%27win32%27 name=%27Microsoft.Windows.Common-Controls%27 version=%276.0.0.0%27 publicKeyToken=%276595b64144ccf1df%27 language=%27*%27 processorArchitecture=%27*%27" %(AdditionalOptions)
+ $(QTDIR)\lib\qtmaind.lib;$(QTDIR)\lib\QtGuid4.lib;$(QTDIR)\lib\QtCored4.lib;$(QTDIR)\lib\QtXml4.lib;%(AdditionalDependencies)
+ debug\FSComm.exe
+ true
+ $(QTDIR)\lib;%(AdditionalLibraryDirectories)
+ true
+
+
+ Windows
+
+
+
+
+
+
+ 0
+ Unsigned
+ None
+
+
+ -Zm200 -w34100 -w34189 -w34100 -w34189 %(AdditionalOptions)
+ MaxSpeed
+ $(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include;.;$(QTDIR)\include\ActiveQt;release;$(QTDIR)\mkspecs\win32-msvc2008;..\src\include;$(QTDIR)\include\QtXml;%(AdditionalIncludeDirectories)
+ QT_NO_DEBUG;NDEBUG;_WINDOWS;UNICODE;WIN32;QT_LARGEFILE_SUPPORT;QT_DLL;QT_NO_DEBUG;QT_GUI_LIB;QT_CORE_LIB;QT_THREAD_SUPPORT;NDEBUG;%(PreprocessorDefinitions)
+ false
+ false
+ Sync
+ MultiThreadedDLL
+ false
+ false
+ true
+
+
+ $(IntDir)
+ $(IntDir)
+ Level3
+ true
+
+
+
+
+ QT_NO_DEBUG;NDEBUG;_WINDOWS;UNICODE;WIN32;QT_LARGEFILE_SUPPORT;QT_DLL;QT_NO_DEBUG;QT_GUI_LIB;QT_CORE_LIB;QT_THREAD_SUPPORT;%(PreprocessorDefinitions)
+
+
+ "/MANIFESTDEPENDENCY:type=%27win32%27 name=%27Microsoft.Windows.Common-Controls%27 version=%276.0.0.0%27 publicKeyToken=%276595b64144ccf1df%27 language=%27*%27 processorArchitecture=%27*%27" "/MANIFESTDEPENDENCY:type=%27win32%27 name=%27Microsoft.Windows.Common-Controls%27 version=%276.0.0.0%27 publicKeyToken=%276595b64144ccf1df%27 language=%27*%27 processorArchitecture=%27*%27" %(AdditionalOptions)
+ $(QTDIR)\lib\qtmain.lib;$(QTDIR)\lib\QtGui4.lib;$(QTDIR)\lib\QtCore4.lib;$(QTDIR)\lib\QtXml4.lib;%(AdditionalDependencies)
+ release\FSComm.exe
+ true
+ $(QTDIR)\lib;%(AdditionalLibraryDirectories)
+ false
+
+
+ Windows
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+
+
+
+ MOC accountdialog.h
+ Rem IncrediBuild_AllowRemote
+Rem IncrediBuild_OutputFile debug\moc_accountdialog.cpp
+$(QTDIR)\bin\moc.exe -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_GUI_LIB -DQT_CORE_LIB -DQT_THREAD_SUPPORT -I"$(QTDIR)\include\QtCore" -I"$(QTDIR)\include\QtGui" -I"$(QTDIR)\include" -I"." -I"$(QTDIR)\include\ActiveQt" -I"debug" -I"." -I$(QTDIR)\mkspecs\win32-msvc2008 -D_MSC_VER=1500 -DWIN32 preferences\accountdialog.h -o debug\moc_accountdialog.cpp
+
+ Rem;accountdialog.h;%(AdditionalInputs)
+ debug\moc_accountdialog.cpp;%(Outputs)
+ MOC accountdialog.h
+ Rem IncrediBuild_AllowRemote
+Rem IncrediBuild_OutputFile release\moc_accountdialog.cpp
+$(QTDIR)\bin\moc.exe -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_THREAD_SUPPORT -I"$(QTDIR)\include\QtCore" -I"$(QTDIR)\include\QtGui" -I"$(QTDIR)\include" -I"." -I"$(QTDIR)\include\ActiveQt" -I"release" -I"." -I$(QTDIR)\mkspecs\win32-msvc2008 -D_MSC_VER=1500 -DWIN32 preferences\accountdialog.h -o release\moc_accountdialog.cpp
+
+ Rem;accountdialog.h;%(AdditionalInputs)
+ release\moc_accountdialog.cpp;%(Outputs)
+
+
+
+
+ MOC codecwidget.h
+ Rem IncrediBuild_AllowRemote
+Rem IncrediBuild_OutputFile debug\moc_codecwidget.cpp
+$(QTDIR)\bin\moc.exe -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_GUI_LIB -DQT_CORE_LIB -DQT_THREAD_SUPPORT -I"$(QTDIR)\include\QtCore" -I"$(QTDIR)\include\QtGui" -I"$(QTDIR)\include" -I"." -I"$(QTDIR)\include\ActiveQt" -I"debug" -I"." -I$(QTDIR)\mkspecs\win32-msvc2008 -D_MSC_VER=1500 -DWIN32 widgets\codecwidget.h -o debug\moc_codecwidget.cpp
+
+ Rem;codecwidget.h;%(AdditionalInputs)
+ debug\moc_codecwidget.cpp;%(Outputs)
+ MOC prefportaudio.h
+ Rem IncrediBuild_AllowRemote
+Rem IncrediBuild_OutputFile release\moc_codecwidget.cpp
+$(QTDIR)\bin\moc.exe -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_THREAD_SUPPORT -I"$(QTDIR)\include\QtCore" -I"$(QTDIR)\include\QtGui" -I"$(QTDIR)\include" -I"." -I"$(QTDIR)\include\ActiveQt" -I"release" -I"." -I$(QTDIR)\mkspecs\win32-msvc2008 -D_MSC_VER=1500 -DWIN32 widgets\codecwidget.h -o release\moc_codecwidget.cpp
+
+ Rem;codecwidget.h;%(AdditionalInputs)
+ release\moc_codecwidget.cpp;%(Outputs)
+
+
+ MOC consolewindow.h
+ Rem IncrediBuild_AllowRemote
+Rem IncrediBuild_OutputFile debug\moc_consolewindow.cpp
+$(QTDIR)\bin\moc.exe -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_GUI_LIB -DQT_CORE_LIB -DQT_THREAD_SUPPORT -I"$(QTDIR)\include\QtCore" -I"$(QTDIR)\include\QtGui" -I"$(QTDIR)\include" -I"." -I"$(QTDIR)\include\ActiveQt" -I"debug" -I"." -I$(QTDIR)\mkspecs\win32-msvc2008 -D_MSC_VER=1500 -DWIN32 debugtools\consolewindow.h -o debug\moc_consolewindow.cpp
+
+ Rem;consolewindow.h;%(AdditionalInputs)
+ debug\moc_consolewindow.cpp;%(Outputs)
+ MOC consolewindow.h
+ Rem IncrediBuild_AllowRemote
+Rem IncrediBuild_OutputFile release\moc_consolewindow.cpp
+$(QTDIR)\bin\moc.exe -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_THREAD_SUPPORT -I"$(QTDIR)\include\QtCore" -I"$(QTDIR)\include\QtGui" -I"$(QTDIR)\include" -I"." -I"$(QTDIR)\include\ActiveQt" -I"release" -I"." -I$(QTDIR)\mkspecs\win32-msvc2008 -D_MSC_VER=1500 -DWIN32 debugtools\consolewindow.h -o release\moc_consolewindow.cpp
+
+ Rem;consolewindow.h;%(AdditionalInputs)
+ release\moc_consolewindow.cpp;%(Outputs)
+
+
+ MOC fshost.h
+ Rem IncrediBuild_AllowRemote
+Rem IncrediBuild_OutputFile debug\moc_fshost.cpp
+$(QTDIR)\bin\moc.exe -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_GUI_LIB -DQT_CORE_LIB -DQT_THREAD_SUPPORT -I"$(QTDIR)\include\QtCore" -I"$(QTDIR)\include\QtGui" -I"$(QTDIR)\include" -I"." -I"$(QTDIR)\include\ActiveQt" -I"debug" -I"." -I$(QTDIR)\mkspecs\win32-msvc2008 -D_MSC_VER=1500 -DWIN32 fshost.h -o debug\moc_fshost.cpp
+
+ Rem;fshost.h;%(AdditionalInputs)
+ debug\moc_fshost.cpp;%(Outputs)
+ MOC fshost.h
+ Rem IncrediBuild_AllowRemote
+Rem IncrediBuild_OutputFile release\moc_fshost.cpp
+$(QTDIR)\bin\moc.exe -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_THREAD_SUPPORT -I"$(QTDIR)\include\QtCore" -I"$(QTDIR)\include\QtGui" -I"$(QTDIR)\include" -I"." -I"$(QTDIR)\include\ActiveQt" -I"release" -I"." -I$(QTDIR)\mkspecs\win32-msvc2008 -D_MSC_VER=1500 -DWIN32 fshost.h -o release\moc_fshost.cpp
+
+ Rem;fshost.h;%(AdditionalInputs)
+ release\moc_fshost.cpp;%(Outputs)
+
+
+ MOC mainwindow.h
+ Rem IncrediBuild_AllowRemote
+Rem IncrediBuild_OutputFile debug\moc_mainwindow.cpp
+$(QTDIR)\bin\moc.exe -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_GUI_LIB -DQT_CORE_LIB -DQT_THREAD_SUPPORT -I"$(QTDIR)\include\QtCore" -I"$(QTDIR)\include\QtGui" -I"$(QTDIR)\include" -I"." -I"$(QTDIR)\include\ActiveQt" -I"debug" -I"." -I$(QTDIR)\mkspecs\win32-msvc2008 -D_MSC_VER=1500 -DWIN32 mainwindow.h -o debug\moc_mainwindow.cpp
+
+ Rem;mainwindow.h;%(AdditionalInputs)
+ debug\moc_mainwindow.cpp;%(Outputs)
+ MOC mainwindow.h
+ Rem IncrediBuild_AllowRemote
+Rem IncrediBuild_OutputFile release\moc_mainwindow.cpp
+$(QTDIR)\bin\moc.exe -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_THREAD_SUPPORT -I"$(QTDIR)\include\QtCore" -I"$(QTDIR)\include\QtGui" -I"$(QTDIR)\include" -I"." -I"$(QTDIR)\include\ActiveQt" -I"release" -I"." -I$(QTDIR)\mkspecs\win32-msvc2008 -D_MSC_VER=1500 -DWIN32 mainwindow.h -o release\moc_mainwindow.cpp
+
+ Rem;mainwindow.h;%(AdditionalInputs)
+ release\moc_mainwindow.cpp;%(Outputs)
+
+
+
+ MOC prefaccounts.h
+ Rem IncrediBuild_AllowRemote
+Rem IncrediBuild_OutputFile debug\moc_prefaccounts.cpp
+$(QTDIR)\bin\moc.exe -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_GUI_LIB -DQT_CORE_LIB -DQT_THREAD_SUPPORT -I"$(QTDIR)\include\QtCore" -I"$(QTDIR)\include\QtGui" -I"$(QTDIR)\include" -I"." -I"$(QTDIR)\include\ActiveQt" -I"debug" -I"." -I$(QTDIR)\mkspecs\win32-msvc2008 -D_MSC_VER=1500 -DWIN32 preferences\prefaccounts.h -o debug\moc_prefaccounts.cpp
+
+ Rem;prefaccounts.h;%(AdditionalInputs)
+ debug\moc_prefaccounts.cpp;%(Outputs)
+ MOC prefaccounts.h
+ Rem IncrediBuild_AllowRemote
+Rem IncrediBuild_OutputFile release\moc_prefaccounts.cpp
+$(QTDIR)\bin\moc.exe -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_THREAD_SUPPORT -I"$(QTDIR)\include\QtCore" -I"$(QTDIR)\include\QtGui" -I"$(QTDIR)\include" -I"." -I"$(QTDIR)\include\ActiveQt" -I"release" -I"." -I$(QTDIR)\mkspecs\win32-msvc2008 -D_MSC_VER=1500 -DWIN32 preferences\prefaccounts.h -o release\moc_prefaccounts.cpp
+
+ Rem;prefaccounts.h;%(AdditionalInputs)
+ release\moc_prefaccounts.cpp;%(Outputs)
+
+
+ MOC prefdialog.h
+ Rem IncrediBuild_AllowRemote
+Rem IncrediBuild_OutputFile debug\moc_prefdialog.cpp
+$(QTDIR)\bin\moc.exe -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_GUI_LIB -DQT_CORE_LIB -DQT_THREAD_SUPPORT -I"$(QTDIR)\include\QtCore" -I"$(QTDIR)\include\QtGui" -I"$(QTDIR)\include" -I"." -I"$(QTDIR)\include\ActiveQt" -I"debug" -I"." -I$(QTDIR)\mkspecs\win32-msvc2008 -D_MSC_VER=1500 -DWIN32 preferences\prefdialog.h -o debug\moc_prefdialog.cpp
+
+ Rem;prefdialog.h;%(AdditionalInputs)
+ debug\moc_prefdialog.cpp;%(Outputs)
+ MOC prefdialog.h
+ Rem IncrediBuild_AllowRemote
+Rem IncrediBuild_OutputFile release\moc_prefdialog.cpp
+$(QTDIR)\bin\moc.exe -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_THREAD_SUPPORT -I"$(QTDIR)\include\QtCore" -I"$(QTDIR)\include\QtGui" -I"$(QTDIR)\include" -I"." -I"$(QTDIR)\include\ActiveQt" -I"release" -I"." -I$(QTDIR)\mkspecs\win32-msvc2008 -D_MSC_VER=1500 -DWIN32 preferences\prefdialog.h -o release\moc_prefdialog.cpp
+
+ Rem;prefdialog.h;%(AdditionalInputs)
+ release\moc_prefdialog.cpp;%(Outputs)
+
+
+ MOC prefportaudio.h
+ Rem IncrediBuild_AllowRemote
+Rem IncrediBuild_OutputFile debug\moc_prefportaudio.cpp
+$(QTDIR)\bin\moc.exe -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_GUI_LIB -DQT_CORE_LIB -DQT_THREAD_SUPPORT -I"$(QTDIR)\include\QtCore" -I"$(QTDIR)\include\QtGui" -I"$(QTDIR)\include" -I"." -I"$(QTDIR)\include\ActiveQt" -I"debug" -I"." -I$(QTDIR)\mkspecs\win32-msvc2008 -D_MSC_VER=1500 -DWIN32 preferences\prefportaudio.h -o debug\moc_prefportaudio.cpp
+
+ Rem;prefportaudio.h;%(AdditionalInputs)
+ debug\moc_prefportaudio.cpp;%(Outputs)
+ MOC prefportaudio.h
+ Rem IncrediBuild_AllowRemote
+Rem IncrediBuild_OutputFile release\moc_prefportaudio.cpp
+$(QTDIR)\bin\moc.exe -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_THREAD_SUPPORT -I"$(QTDIR)\include\QtCore" -I"$(QTDIR)\include\QtGui" -I"$(QTDIR)\include" -I"." -I"$(QTDIR)\include\ActiveQt" -I"release" -I"." -I$(QTDIR)\mkspecs\win32-msvc2008 -D_MSC_VER=1500 -DWIN32 preferences\prefportaudio.h -o release\moc_prefportaudio.cpp
+
+ Rem;prefportaudio.h;%(AdditionalInputs)
+ release\moc_prefportaudio.cpp;%(Outputs)
+
+
+ MOC prefsofia.h
+ Rem IncrediBuild_AllowRemote
+Rem IncrediBuild_OutputFile debug\moc_prefsofia.cpp
+$(QTDIR)\bin\moc.exe -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_GUI_LIB -DQT_CORE_LIB -DQT_THREAD_SUPPORT -I"$(QTDIR)\include\QtCore" -I"$(QTDIR)\include\QtGui" -I"$(QTDIR)\include" -I"." -I"$(QTDIR)\include\ActiveQt" -I"debug" -I"." -I$(QTDIR)\mkspecs\win32-msvc2008 -D_MSC_VER=1500 -DWIN32 preferences\prefsofia.h -o debug\moc_prefsofia.cpp
+
+ Rem;prefsofia.h;%(AdditionalInputs)
+ debug\moc_prefsofia.cpp;%(Outputs)
+ MOC prefportaudio.h
+ Rem IncrediBuild_AllowRemote
+Rem IncrediBuild_OutputFile release\moc_prefsofia.cpp
+$(QTDIR)\bin\moc.exe -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_THREAD_SUPPORT -I"$(QTDIR)\include\QtCore" -I"$(QTDIR)\include\QtGui" -I"$(QTDIR)\include" -I"." -I"$(QTDIR)\include\ActiveQt" -I"release" -I"." -I$(QTDIR)\mkspecs\win32-msvc2008 -D_MSC_VER=1500 -DWIN32 preferences\prefsofia.h -o release\moc_prefsofia.cpp
+
+ Rem;prefsofia.h;%(AdditionalInputs)
+ release\moc_prefsofia.cpp;%(Outputs)
+
+
+ MOC sortfilterproxymodel.h
+ Rem IncrediBuild_AllowRemote
+Rem IncrediBuild_OutputFile debug\moc_sortfilterproxymodel.cpp
+$(QTDIR)\bin\moc.exe -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_GUI_LIB -DQT_CORE_LIB -DQT_THREAD_SUPPORT -I"$(QTDIR)\include\QtCore" -I"$(QTDIR)\include\QtGui" -I"$(QTDIR)\include" -I"." -I"$(QTDIR)\include\ActiveQt" -I"debug" -I"." -I$(QTDIR)\mkspecs\win32-msvc2008 -D_MSC_VER=1500 -DWIN32 debugtools\sortfilterproxymodel.h -o debug\moc_sortfilterproxymodel.cpp
+
+ Rem;sortfilterproxymodel.h;%(AdditionalInputs)
+ debug\moc_sortfilterproxymodel.cpp;%(Outputs)
+ MOC sortfilterproxymodel.h
+ Rem IncrediBuild_AllowRemote
+Rem IncrediBuild_OutputFile release\moc_sortfilterproxymodel.cpp
+$(QTDIR)\bin\moc.exe -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_THREAD_SUPPORT -I"$(QTDIR)\include\QtCore" -I"$(QTDIR)\include\QtGui" -I"$(QTDIR)\include" -I"." -I"$(QTDIR)\include\ActiveQt" -I"release" -I"." -I$(QTDIR)\mkspecs\win32-msvc2008 -D_MSC_VER=1500 -DWIN32 debugtools\sortfilterproxymodel.h -o release\moc_sortfilterproxymodel.cpp
+
+ Rem;sortfilterproxymodel.h;%(AdditionalInputs)
+ release\moc_sortfilterproxymodel.cpp;%(Outputs)
+
+
+ MOC statedebugdialog.h
+ Rem IncrediBuild_AllowRemote
+Rem IncrediBuild_OutputFile debug\moc_statedebugdialog.cpp
+$(QTDIR)\bin\moc.exe -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_GUI_LIB -DQT_CORE_LIB -DQT_THREAD_SUPPORT -I"$(QTDIR)\include\QtCore" -I"$(QTDIR)\include\QtGui" -I"$(QTDIR)\include" -I"." -I"$(QTDIR)\include\ActiveQt" -I"debug" -I"." -I$(QTDIR)\mkspecs\win32-msvc2008 -D_MSC_VER=1500 -DWIN32 debugtools\statedebugdialog.h -o debug\moc_statedebugdialog.cpp
+
+ Rem;statedebugdialog.h;%(AdditionalInputs)
+ debug\moc_statedebugdialog.cpp;%(Outputs)
+ MOC prefportaudio.h
+ Rem IncrediBuild_AllowRemote
+Rem IncrediBuild_OutputFile release\moc_statedebugdialog.cpp
+$(QTDIR)\bin\moc.exe -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_THREAD_SUPPORT -I"$(QTDIR)\include\QtCore" -I"$(QTDIR)\include\QtGui" -I"$(QTDIR)\include" -I"." -I"$(QTDIR)\include\ActiveQt" -I"release" -I"." -I$(QTDIR)\mkspecs\win32-msvc2008 -D_MSC_VER=1500 -DWIN32 debugtools\statedebugdialog.h -o release\moc_statedebugdialog.cpp
+
+ Rem;statedebugdialog.h;%(AdditionalInputs)
+ release\moc_statedebugdialog.cpp;%(Outputs)
+
+
+
+
+
+
+
+
+
+
+ UIC accountdialog.ui
+ Rem IncrediBuild_AllowRemote
+Rem IncrediBuild_OutputFile .\ui_accountdialog.h
+$(QTDIR)\bin\uic.exe preferences\accountdialog.ui -o ui_accountdialog.h
+
+ Rem;accountdialog.ui;%(AdditionalInputs)
+ ui_accountdialog.h;%(Outputs)
+ UIC accountdialog.ui
+ Rem IncrediBuild_AllowRemote
+Rem IncrediBuild_OutputFile .\ui_accountdialog.h
+$(QTDIR)\bin\uic.exe preferences\accountdialog.ui -o ui_accountdialog.h
+
+ Rem;accountdialog.ui;%(AdditionalInputs)
+ ui_accountdialog.h;%(Outputs)
+
+
+ UIC codecwidget.ui
+ Rem IncrediBuild_AllowRemote
+Rem IncrediBuild_OutputFile .\ui_codecwidget.h
+$(QTDIR)\bin\uic.exe widgets\codecwidget.ui -o ui_codecwidget.h
+
+ Rem;codecwidgets.ui;%(AdditionalInputs)
+ ui_codecwidget.h;%(Outputs)
+ UIC codecwidget.ui
+ Rem IncrediBuild_AllowRemote
+Rem IncrediBuild_OutputFile .\ui_codecwidget.h
+$(QTDIR)\bin\uic.exe widgets\codecwidget.ui -o ui_codecwidget.h
+
+ Rem;codecwidget.ui;%(AdditionalInputs)
+ ui_codecwidget.h;%(Outputs)
+
+
+ UIC consolewindow.ui
+ Rem IncrediBuild_AllowRemote
+Rem IncrediBuild_OutputFile .\ui_consolewindow.h
+$(QTDIR)\bin\uic.exe debugtools\consolewindow.ui -o ui_consolewindow.h
+
+ Rem;consolewindow.ui;%(AdditionalInputs)
+ ui_consolewindow.h;%(Outputs)
+ UIC accountdialog.ui
+ Rem IncrediBuild_AllowRemote
+Rem IncrediBuild_OutputFile .\ui_consolewindow.h
+$(QTDIR)\bin\uic.exe debugtools\consolewindow.ui -o ui_consolewindow.h
+
+ Rem;accountdialog.ui;%(AdditionalInputs)
+ ui_consolewindow.h;%(Outputs)
+
+
+ UIC mainwindow.ui
+ Rem IncrediBuild_AllowRemote
+Rem IncrediBuild_OutputFile .\ui_mainwindow.h
+$(QTDIR)\bin\uic.exe mainwindow.ui -o ui_mainwindow.h
+
+ Rem;mainwindow.ui;%(AdditionalInputs)
+ ui_mainwindow.h;%(Outputs)
+ UIC mainwindow.ui
+ Rem IncrediBuild_AllowRemote
+Rem IncrediBuild_OutputFile .\ui_mainwindow.h
+$(QTDIR)\bin\uic.exe mainwindow.ui -o ui_mainwindow.h
+
+ Rem;mainwindow.ui;%(AdditionalInputs)
+ ui_mainwindow.h;%(Outputs)
+
+
+ UIC prefdialog.ui
+ Rem IncrediBuild_AllowRemote
+Rem IncrediBuild_OutputFile .\ui_prefdialog.h
+$(QTDIR)\bin\uic.exe preferences\prefdialog.ui -o ui_prefdialog.h
+
+ Rem;prefdialog.ui;%(AdditionalInputs)
+ ui_prefdialog.h;%(Outputs)
+ UIC prefdialog.ui
+ Rem IncrediBuild_AllowRemote
+Rem IncrediBuild_OutputFile .\ui_prefdialog.h
+$(QTDIR)\bin\uic.exe preferences\prefdialog.ui -o ui_prefdialog.h
+
+ Rem;prefdialog.ui;%(AdditionalInputs)
+ ui_prefdialog.h;%(Outputs)
+
+
+ UIC statedebugdialog.ui
+ Rem IncrediBuild_AllowRemote
+Rem IncrediBuild_OutputFile .\ui_statedebugdialog.h
+$(QTDIR)\bin\uic.exe debugtools\statedebugdialog.ui -o ui_statedebugdialog.h
+
+ Rem;statedebugdialog.ui;%(AdditionalInputs)
+ ui_statedebugdialog.h;%(Outputs)
+ UIC statedebugdialog.ui
+ Rem IncrediBuild_AllowRemote
+Rem IncrediBuild_OutputFile .\ui_statedebugdialog.h
+$(QTDIR)\bin\uic.exe debugtools\statedebugdialog.ui -o ui_statedebugdialog.h
+
+ Rem;statedebugdialog.ui;%(AdditionalInputs)
+ ui_statedebugdialog.h;%(Outputs)
+
+
+
+
+
+
+
+
+ RCC resources.qrc
+ $(QTDIR)\bin\rcc.exe -name resources resources.qrc -o debug\qrc_resources.cpp
+
+ $(QTDIR)\bin\rcc.exe;conf\accounts\example.xml;conf\event_socket.conf.xml;conf\freeswitch.xml;conf\portaudio.conf.xml;resources.qrc;resources\pref_audio.gif;resources\pref_sip.png;resources\splash.png;%(AdditionalInputs)
+ debug\qrc_resources.cpp;%(Outputs)
+ RCC resources.qrc
+ $(QTDIR)\bin\rcc.exe -name resources resources.qrc -o release\qrc_resources.cpp
+
+ $(QTDIR)\bin\rcc.exe;conf\accounts\example.xml;conf\event_socket.conf.xml;conf\freeswitch.xml;conf\portaudio.conf.xml;resources.qrc;resources\pref_audio.gif;resources\pref_sip.png;resources\splash.png;%(AdditionalInputs)
+ release\qrc_resources.cpp;%(Outputs)
+
+
+
+
+
+ {202d7a4e-760d-4d0e-afa1-d7459ced30ff}
+ false
+
+
+
+
+
+
diff --git a/libs/.gitignore b/libs/.gitignore
index 746a59991f..d01a5736f3 100644
--- a/libs/.gitignore
+++ b/libs/.gitignore
@@ -357,6 +357,7 @@ opal
/libwebsockets/test-server/Makefile.in
/mongo-cxx-driver-v*/
/mpg123/
+/libmpg123/
/openldap-*/
/openssl-*/
/openzap/build/compile
@@ -918,6 +919,8 @@ opal
/xmlrpc-c/tools/lib/blddir
/xmlrpc-c/tools/lib/depend.mk
/xmlrpc-c/tools/lib/srcdir
+/sipcc/Makefile
+/sipcc/Makefile.in
/yaml/
/yaml/config.h
diff --git a/libs/broadvoice/src/floating/bv16/bv16encoder.c b/libs/broadvoice/src/floating/bv16/bv16encoder.c
index 2b9b5372ee..2eccf7124c 100644
--- a/libs/broadvoice/src/floating/bv16/bv16encoder.c
+++ b/libs/broadvoice/src/floating/bv16/bv16encoder.c
@@ -103,7 +103,6 @@ BV_DECLARE(int) bv16_encode(bv16_encode_state_t *cs,
Float gainq;
Float lg;
Float ppt;
- Float lth;
Float dummy;
int pp;
int cpp;
@@ -189,8 +188,15 @@ BV_DECLARE(int) bv16_encode(bv16_encode_state_t *cs,
/* Level estimation */
dummy = estl_alpha;
- lth = estlevel(cs->prevlg[0], &cs->level, &cs->lmax, &cs->lmin,
- &cs->lmean, &cs->x1, LGPORDER + 1, Nfdm + 1, &dummy);
+ estlevel(cs->prevlg[0],
+ &cs->level,
+ &cs->lmax,
+ &cs->lmin,
+ &cs->lmean,
+ &cs->x1,
+ LGPORDER + 1,
+ Nfdm + 1,
+ &dummy);
/* Scale the scalar quantizer codebook */
for (i = 0; i < (VDIM*CBSZ); i++)
diff --git a/libs/broadvoice/src/floating/bv32/bv32encoder.c b/libs/broadvoice/src/floating/bv32/bv32encoder.c
index d7a78c44e6..d6ec9b7306 100644
--- a/libs/broadvoice/src/floating/bv32/bv32encoder.c
+++ b/libs/broadvoice/src/floating/bv32/bv32encoder.c
@@ -103,7 +103,6 @@ BV_DECLARE(int) bv32_encode(bv32_encode_state_t *cs,
Float e;
Float ee;
Float ppt;
- Float lth;
int pp;
int cpp;
int i;
@@ -193,8 +192,8 @@ BV_DECLARE(int) bv32_encode(bv32_encode_state_t *cs,
lg = (ee < TMinE) ? MinE : log(ee/SFRSZ)/log(2.0);
bs.gidx[issf] = bv32_gainquan(gainq + issf, lg, cs->lgpm, cs->prevlg, cs->level);
- /* Level Estimation */
- lth = bv32_estlevel(cs->prevlg[0], &cs->level, &cs->lmax, &cs->lmin, &cs->lmean, &cs->x1);
+ /* Level estimation */
+ bv32_estlevel(cs->prevlg[0], &cs->level, &cs->lmax, &cs->lmin, &cs->lmean, &cs->x1);
/* Scale the excitation codebook */
for (i = 0; i < (VDIM*CBSZ); i++)
diff --git a/libs/broadvoice/src/libbroadvoice.2012.vcxproj b/libs/broadvoice/src/libbroadvoice.2012.vcxproj
new file mode 100644
index 0000000000..a01905aa7a
--- /dev/null
+++ b/libs/broadvoice/src/libbroadvoice.2012.vcxproj
@@ -0,0 +1,206 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ libbroadvoice
+ {CF70F278-3364-4395-A2E1-23501C9B8AD2}
+ libbroadvoice
+ Win32Proj
+
+
+
+ DynamicLibrary
+ Unicode
+ true
+ v110
+
+
+ DynamicLibrary
+ Unicode
+ v110
+
+
+ DynamicLibrary
+ Unicode
+ true
+ v110
+
+
+ DynamicLibrary
+ Unicode
+ v110
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <_ProjectFileVersion>10.0.30319.1
+ true
+ false
+ true
+ false
+
+
+
+ Disabled
+ .; .\floating\common; .\floating\bv16; .\floating\bv32; .\broadvoice; .\msvc;%(AdditionalIncludeDirectories)
+ WIN32;_DEBUG;_WINDOWS;_USRDLL;BROADVOICE_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;HAVE_TGMATH_H;%(PreprocessorDefinitions)
+ true
+ EnableFastChecks
+ MultiThreadedDebugDLL
+ Level4
+ CompileAsC
+
+
+ true
+ Windows
+ false
+ MachineX86
+
+
+
+
+ .; .\floating\common; .\floating\bv16; .\floating\bv32; .\broadvoice; .\msvc;%(AdditionalIncludeDirectories)
+ WIN32;NDEBUG;_WINDOWS;_USRDLL;BROADVOICE_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;HAVE_TGMATH_H;%(PreprocessorDefinitions)
+ MultiThreadedDLL
+ Level4
+
+
+ true
+ Windows
+ true
+ true
+ false
+ MachineX86
+
+
+
+
+ X64
+
+
+ Disabled
+ .; .\floating\common; .\floating\bv16; .\floating\bv32; .\broadvoice; .\msvc;%(AdditionalIncludeDirectories)
+ WIN32;_DEBUG;_WINDOWS;_USRDLL;BROADVOICE_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;HAVE_TGMATH_H;%(PreprocessorDefinitions)
+ true
+ EnableFastChecks
+ MultiThreadedDebugDLL
+ CompileAsC
+
+
+ true
+ Windows
+ false
+ MachineX64
+
+
+
+
+ X64
+
+
+ .; .\floating\common; .\floating\bv16; .\floating\bv32; .\broadvoice; .\msvc;%(AdditionalIncludeDirectories)
+ WIN32;NDEBUG;_WINDOWS;_USRDLL;BROADVOICE_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;HAVE_TGMATH_H;%(PreprocessorDefinitions)
+ MultiThreadedDLL
+ Level4
+
+
+ true
+ Windows
+ true
+ true
+ false
+ MachineX64
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/libs/esl/fs_cli.2012.vcxproj b/libs/esl/fs_cli.2012.vcxproj
new file mode 100644
index 0000000000..0f3747eeae
--- /dev/null
+++ b/libs/esl/fs_cli.2012.vcxproj
@@ -0,0 +1,211 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ fs_cli
+ {D2FB8043-D208-4AEE-8F18-3B5857C871B9}
+ fs_cli
+ Win32Proj
+
+
+
+ Application
+ MultiByte
+ v110
+
+
+ Application
+ MultiByte
+ v110
+
+
+ Application
+ MultiByte
+ v110
+
+
+ Application
+ MultiByte
+ v110
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <_ProjectFileVersion>10.0.30319.1
+ $(SolutionDir)$(PlatformName)\$(Configuration)\
+ $(PlatformName)\$(Configuration)\
+ false
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ false
+ $(SolutionDir)$(PlatformName)\$(Configuration)\
+ $(PlatformName)\$(Configuration)\
+ false
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(PlatformName)\$(Configuration)\
+ false
+
+
+
+
+ Disabled
+ $(ProjectDir)getopt;$(ProjectDir)src/include;%(AdditionalIncludeDirectories)
+ WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ESL_DECLARE_STATIC;%(PreprocessorDefinitions)
+ true
+ EnableFastChecks
+ MultiThreadedDebugDLL
+
+
+ Level4
+ true
+ ProgramDatabase
+ 4100;6053;4706;%(DisableSpecificWarnings)
+
+
+ Ws2_32.lib;%(AdditionalDependencies)
+ $(OutDir);%(AdditionalLibraryDirectories)
+ true
+ $(OutDir)fs_cli.pdb
+ Console
+ true
+
+
+ MachineX86
+
+
+
+
+
+ X64
+
+
+ Disabled
+ $(ProjectDir)getopt;$(ProjectDir)src/include;%(AdditionalIncludeDirectories)
+ WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ESL_DECLARE_STATIC;%(PreprocessorDefinitions)
+ true
+ EnableFastChecks
+ MultiThreadedDebugDLL
+
+
+ Level4
+ true
+ ProgramDatabase
+ 4100;6053;4706;%(DisableSpecificWarnings)
+
+
+ Ws2_32.lib;%(AdditionalDependencies)
+ $(OutDir);%(AdditionalLibraryDirectories)
+ true
+ $(OutDir)fs_cli.pdb
+ Console
+ true
+
+
+ MachineX64
+
+
+
+
+
+ $(ProjectDir)getopt;$(ProjectDir)src/include;%(AdditionalIncludeDirectories)
+ WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ESL_DECLARE_STATIC;%(PreprocessorDefinitions)
+ MultiThreadedDLL
+
+
+ Level4
+ true
+ ProgramDatabase
+ 4100;6053;4706;%(DisableSpecificWarnings)
+
+
+ Ws2_32.lib;%(AdditionalDependencies)
+ $(OutDir);%(AdditionalLibraryDirectories)
+ true
+ $(OutDir)fs_cli.pdb
+ Console
+ true
+ true
+ true
+
+
+ MachineX86
+
+
+
+
+
+ X64
+
+
+ $(ProjectDir)getopt;$(ProjectDir)src/include;%(AdditionalIncludeDirectories)
+ WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ESL_DECLARE_STATIC;%(PreprocessorDefinitions)
+ MultiThreadedDLL
+
+
+ Level4
+ true
+ ProgramDatabase
+ 4100;6053;4706;%(DisableSpecificWarnings)
+
+
+ Ws2_32.lib;%(AdditionalDependencies)
+ $(OutDir);%(AdditionalLibraryDirectories)
+ true
+ $(OutDir)fs_cli.pdb
+ Console
+ true
+ true
+ true
+
+
+ MachineX64
+
+
+
+
+
+
+
+
+
+
+
+ {cf405366-9558-4ae8-90ef-5e21b51ccb4e}
+ false
+
+
+
+
+
+
diff --git a/libs/esl/fs_cli.c b/libs/esl/fs_cli.c
index 9986c7c613..d7156ee365 100644
--- a/libs/esl/fs_cli.c
+++ b/libs/esl/fs_cli.c
@@ -64,6 +64,7 @@ typedef struct {
char output_text_color[12];
} cli_profile_t;
+static int is_color = 1;
static int warn_stop = 0;
static int connected = 0;
static int allow_ctl_c = 0;
@@ -598,7 +599,8 @@ static const char *usage_str =
" -R, --reconnect Reconnect if disconnected\n"
" -d, --debug=level Debug Level (0 - 7)\n"
" -b, --batchmode Batch mode\n"
- " -t, --timeout Timeout for API commands (in miliseconds)\n\n";
+ " -t, --timeout Timeout for API commands (in miliseconds)\n"
+ " -n, --no-color Disable color\n\n";
static int usage(char *name){
printf(usage_str, name);
@@ -966,7 +968,7 @@ static const char *banner =
static const char *inf = "Type /help to see a list of commands\n\n\n";
-static void print_banner(FILE *stream)
+static void print_banner(FILE *stream, int color)
{
int x;
const char *use = NULL;
@@ -978,22 +980,36 @@ static void print_banner(FILE *stream)
#ifdef WIN32
/* Print banner in yellow with blue background */
- SetConsoleTextAttribute(hStdout, ESL_SEQ_FYELLOW | BACKGROUND_BLUE);
+ if (color) {
+ SetConsoleTextAttribute(hStdout, ESL_SEQ_FYELLOW | BACKGROUND_BLUE);
+ }
WriteFile(hStdout, banner, (DWORD) strlen(banner), NULL, NULL);
WriteFile(hStdout, use, (DWORD) strlen(use), NULL, NULL);
- SetConsoleTextAttribute(hStdout, wOldColorAttrs);
+ if (color) {
+ SetConsoleTextAttribute(hStdout, wOldColorAttrs);
+ }
/* Print the rest info in default colors */
fprintf(stream, "\n%s\n", inf);
#else
- fprintf(stream,
- "%s%s%s%s%s%s\n%s\n",
- ESL_SEQ_DEFAULT_COLOR,
- ESL_SEQ_FYELLOW, ESL_SEQ_BBLUE,
- banner,
- use, ESL_SEQ_DEFAULT_COLOR, inf);
- fprintf(stream, "%s", output_text_color);
+ if (color) {
+ fprintf(stream, "%s%s%s", ESL_SEQ_DEFAULT_COLOR, ESL_SEQ_FYELLOW, ESL_SEQ_BBLUE);
+ }
+
+ fprintf(stream, "%s%s", banner, use);
+
+
+ if (color) {
+ fprintf(stream, "%s", ESL_SEQ_DEFAULT_COLOR);
+ }
+
+ fprintf(stream, "\n%s\n", inf);
+
+
+ if (color) {
+ fprintf(stream, "%s", output_text_color);
+ }
#endif
if (x < 160) {
@@ -1238,6 +1254,7 @@ int main(int argc, char *argv[])
int opt;
static struct option options[] = {
{"help", 0, 0, 'h'},
+ {"no-color", 0, 0, 'n'},
{"host", 1, 0, 'H'},
{"port", 1, 0, 'P'},
{"user", 1, 0, 'u'},
@@ -1269,7 +1286,7 @@ int main(int argc, char *argv[])
int argv_quiet = 0;
int argv_batch = 0;
int loops = 2, reconnect = 0, timeout = 0;
-
+ char *ccheck;
#ifdef WIN32
feature_level = 0;
@@ -1277,6 +1294,10 @@ int main(int argc, char *argv[])
feature_level = 1;
#endif
+ if ((ccheck = getenv("FS_CLI_COLOR"))) {
+ is_color = esl_true(ccheck);
+ }
+
strncpy(internal_profile.host, "127.0.0.1", sizeof(internal_profile.host));
strncpy(internal_profile.pass, "ClueCon", sizeof(internal_profile.pass));
strncpy(internal_profile.name, "internal", sizeof(internal_profile.name));
@@ -1299,7 +1320,7 @@ int main(int argc, char *argv[])
esl_global_set_default_logger(6); /* default debug level to 6 (info) */
for(;;) {
int option_index = 0;
- opt = getopt_long(argc, argv, "H:U:P:S:u:p:d:x:l:t:qrRhib?", options, &option_index);
+ opt = getopt_long(argc, argv, "H:U:P:S:u:p:d:x:l:t:qrRhib?n", options, &option_index);
if (opt == -1) break;
switch (opt) {
case 'H':
@@ -1315,6 +1336,9 @@ int main(int argc, char *argv[])
argv_error = 1;
}
break;
+ case 'n':
+ is_color = 0;
+ break;
case 'u':
esl_set_string(temp_user, optarg);
argv_user = 1;
@@ -1359,7 +1383,7 @@ int main(int argc, char *argv[])
break;
case 'h':
case '?':
- print_banner(stdout);
+ print_banner(stdout, is_color);
usage(argv[0]);
return 0;
default:
@@ -1501,6 +1525,14 @@ int main(int argc, char *argv[])
el_set(el, EL_BIND, "\033OQ", "f2-key", NULL);
el_set(el, EL_BIND, "\033OR", "f3-key", NULL);
el_set(el, EL_BIND, "\033OS", "f4-key", NULL);
+ el_set(el, EL_BIND, "\033OT", "f5-key", NULL);
+ el_set(el, EL_BIND, "\033OU", "f6-key", NULL);
+ el_set(el, EL_BIND, "\033OV", "f7-key", NULL);
+ el_set(el, EL_BIND, "\033OW", "f8-key", NULL);
+ el_set(el, EL_BIND, "\033OX", "f9-key", NULL);
+ el_set(el, EL_BIND, "\033OY", "f10-key", NULL);
+ el_set(el, EL_BIND, "\033OZ", "f11-key", NULL);
+ el_set(el, EL_BIND, "\033O[", "f12-key", NULL);
el_set(el, EL_BIND, "\033[11~", "f1-key", NULL);
el_set(el, EL_BIND, "\033[12~", "f2-key", NULL);
@@ -1545,7 +1577,7 @@ int main(int argc, char *argv[])
if (global_profile->batch_mode) {
setvbuf(stdout, (char*)NULL, _IONBF, 0);
}
- print_banner(stdout);
+ print_banner(stdout, is_color);
esl_log(ESL_LOG_INFO, "FS CLI Ready.\nenter /help for a list of commands.\n");
output_printf("%s\n", handle.last_sr_reply);
while (running > 0) {
diff --git a/libs/esl/managed/ESL.2012.vcxproj b/libs/esl/managed/ESL.2012.vcxproj
new file mode 100644
index 0000000000..8b4f099c26
--- /dev/null
+++ b/libs/esl/managed/ESL.2012.vcxproj
@@ -0,0 +1,199 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ ESL
+ {FEA2D0AE-6713-4E41-A473-A143849BC7FF}
+ ESL
+ ManagedCProj
+
+
+
+ DynamicLibrary
+ Unicode
+ true
+ true
+ v110
+
+
+ DynamicLibrary
+ MultiByte
+ true
+ v110
+
+
+ DynamicLibrary
+ Unicode
+ true
+ true
+ v110
+
+
+ DynamicLibrary
+ MultiByte
+ true
+ v110
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <_ProjectFileVersion>10.0.30319.1
+ $(SolutionDir)$(Configuration)\
+ $(Configuration)\
+ true
+ $(SolutionDir)$(Configuration)\
+ $(Configuration)\
+ false
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ true
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ false
+ AllRules.ruleset
+
+
+ AllRules.ruleset
+
+
+ AllRules.ruleset
+
+
+ AllRules.ruleset
+
+
+
+
+
+ Disabled
+ ..\src\include;%(AdditionalIncludeDirectories)
+ WIN32;_DEBUG;%(PreprocessorDefinitions)
+ MultiThreadedDebugDLL
+
+
+ Level4
+ ProgramDatabase
+
+
+ esl.lib;Ws2_32.lib;%(AdditionalDependencies)
+ ..\..\..\libs\esl\src\$(Platform)\$(Configuration)\;%(AdditionalLibraryDirectories)
+ true
+ true
+ NotSet
+
+
+
+
+ ..\src\include;%(AdditionalIncludeDirectories)
+ WIN32;NDEBUG;%(PreprocessorDefinitions)
+ MultiThreadedDLL
+
+
+ Level3
+ ProgramDatabase
+
+
+ esl.lib;Ws2_32.lib;%(AdditionalDependencies)
+ ..\..\..\libs\esl\src\$(Platform)\$(Configuration)\;%(AdditionalLibraryDirectories)
+ true
+ MachineX86
+
+
+
+
+ X64
+
+
+ Disabled
+ ..\src\include;%(AdditionalIncludeDirectories)
+ WIN32;_DEBUG;%(PreprocessorDefinitions)
+ MultiThreadedDebugDLL
+
+
+ Level4
+ ProgramDatabase
+
+
+ esl.lib;Ws2_32.lib;%(AdditionalDependencies)
+ ..\..\..\libs\esl\src\$(Platform)\$(Configuration)\;%(AdditionalLibraryDirectories)
+ true
+ true
+ MachineX64
+
+
+
+
+ X64
+
+
+ ..\src\include;%(AdditionalIncludeDirectories)
+ WIN32;NDEBUG;%(PreprocessorDefinitions)
+ MultiThreadedDLL
+
+
+ Level3
+ ProgramDatabase
+
+
+ esl.lib;Ws2_32.lib;%(AdditionalDependencies)
+ ..\..\..\libs\esl\src\$(Platform)\$(Configuration)\;%(AdditionalLibraryDirectories)
+ true
+ MachineX64
+
+
+
+
+ true
+ true
+
+
+ true
+ true
+
+
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/libs/esl/managed/ESL.2012.vcxproj.filters b/libs/esl/managed/ESL.2012.vcxproj.filters
new file mode 100644
index 0000000000..0f46492f09
--- /dev/null
+++ b/libs/esl/managed/ESL.2012.vcxproj.filters
@@ -0,0 +1,30 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hpp;hxx;hm;inl;inc;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+ Header Files
+
+
+
\ No newline at end of file
diff --git a/libs/esl/managed/ManagedEsl.2012.csproj b/libs/esl/managed/ManagedEsl.2012.csproj
new file mode 100644
index 0000000000..7be21f44cb
--- /dev/null
+++ b/libs/esl/managed/ManagedEsl.2012.csproj
@@ -0,0 +1,93 @@
+
+
+
+ Debug
+ AnyCPU
+ 9.0.30729
+ 2.0
+ {DEE5837B-E01D-4223-B351-EDF9418F3F8E}
+ Library
+ Properties
+ ManagedEsl
+ ManagedEsl
+ v4.0
+ 512
+
+
+ 3.5
+
+ publish\
+ true
+ Disk
+ false
+ Foreground
+ 7
+ Days
+ false
+ false
+ true
+ 0
+ 1.0.0.%2a
+ false
+ false
+ true
+
+
+
+ true
+ full
+ false
+ Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ AllRules.ruleset
+
+
+ pdbonly
+ true
+ Release\
+ TRACE
+ prompt
+ 4
+ AllRules.ruleset
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ False
+ .NET Framework 3.5 SP1 Client Profile
+ false
+
+
+ False
+ .NET Framework 3.5 SP1
+ true
+
+
+ False
+ Windows Installer 3.1
+ true
+
+
+
+
+
\ No newline at end of file
diff --git a/libs/esl/managed/ManagedEslTest/ManagedEslTest.2012.csproj b/libs/esl/managed/ManagedEslTest/ManagedEslTest.2012.csproj
new file mode 100644
index 0000000000..8b97ffc2df
--- /dev/null
+++ b/libs/esl/managed/ManagedEslTest/ManagedEslTest.2012.csproj
@@ -0,0 +1,98 @@
+
+
+
+ Debug
+ AnyCPU
+ 9.0.30729
+ 2.0
+ {2321D01A-D64B-4461-9837-FACF38652212}
+ Exe
+ Properties
+ ManagedEslTest
+ ManagedEslTest
+ v4.0
+ 512
+
+
+ 3.5
+
+ publish\
+ true
+ Disk
+ false
+ Foreground
+ 7
+ Days
+ false
+ false
+ true
+ 0
+ 1.0.0.%2a
+ false
+ false
+ true
+
+
+
+ true
+ full
+ false
+ ..\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ AllRules.ruleset
+
+
+ pdbonly
+ true
+ ..\Release\
+ TRACE
+ prompt
+ 4
+ AllRules.ruleset
+
+
+
+
+
+
+
+
+
+
+
+ {DEE5837B-E01D-4223-B351-EDF9418F3F8E}
+ ManagedEsl
+ True
+
+
+
+
+ False
+ .NET Framework 3.5 SP1 Client Profile
+ false
+
+
+ False
+ .NET Framework 3.5 SP1
+ true
+
+
+ False
+ Windows Installer 3.1
+ true
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/libs/esl/managed/managed_esl.2012.sln b/libs/esl/managed/managed_esl.2012.sln
new file mode 100644
index 0000000000..cdda83b58d
--- /dev/null
+++ b/libs/esl/managed/managed_esl.2012.sln
@@ -0,0 +1,74 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ESL", "ESL.2012.vcxproj", "{FEA2D0AE-6713-4E41-A473-A143849BC7FF}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ManagedEsl.2012", "ManagedEsl.2012.csproj", "{DEE5837B-E01D-4223-B351-EDF9418F3F8E}"
+ ProjectSection(ProjectDependencies) = postProject
+ {FEA2D0AE-6713-4E41-A473-A143849BC7FF} = {FEA2D0AE-6713-4E41-A473-A143849BC7FF}
+ EndProjectSection
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ManagedEslTest.2012", "ManagedEslTest\ManagedEslTest.2012.csproj", "{2321D01A-D64B-4461-9837-FACF38652212}"
+ ProjectSection(ProjectDependencies) = postProject
+ {FEA2D0AE-6713-4E41-A473-A143849BC7FF} = {FEA2D0AE-6713-4E41-A473-A143849BC7FF}
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Debug|Mixed Platforms = Debug|Mixed Platforms
+ Debug|Win32 = Debug|Win32
+ Debug|x64 = Debug|x64
+ Release|Any CPU = Release|Any CPU
+ Release|Mixed Platforms = Release|Mixed Platforms
+ Release|Win32 = Release|Win32
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {FEA2D0AE-6713-4E41-A473-A143849BC7FF}.Debug|Any CPU.ActiveCfg = Debug|Win32
+ {FEA2D0AE-6713-4E41-A473-A143849BC7FF}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
+ {FEA2D0AE-6713-4E41-A473-A143849BC7FF}.Debug|Mixed Platforms.Build.0 = Debug|Win32
+ {FEA2D0AE-6713-4E41-A473-A143849BC7FF}.Debug|Win32.ActiveCfg = Debug|Win32
+ {FEA2D0AE-6713-4E41-A473-A143849BC7FF}.Debug|Win32.Build.0 = Debug|Win32
+ {FEA2D0AE-6713-4E41-A473-A143849BC7FF}.Debug|x64.ActiveCfg = Debug|x64
+ {FEA2D0AE-6713-4E41-A473-A143849BC7FF}.Debug|x64.Build.0 = Debug|x64
+ {FEA2D0AE-6713-4E41-A473-A143849BC7FF}.Release|Any CPU.ActiveCfg = Release|Win32
+ {FEA2D0AE-6713-4E41-A473-A143849BC7FF}.Release|Mixed Platforms.ActiveCfg = Release|Win32
+ {FEA2D0AE-6713-4E41-A473-A143849BC7FF}.Release|Mixed Platforms.Build.0 = Release|Win32
+ {FEA2D0AE-6713-4E41-A473-A143849BC7FF}.Release|Win32.ActiveCfg = Release|Win32
+ {FEA2D0AE-6713-4E41-A473-A143849BC7FF}.Release|Win32.Build.0 = Release|Win32
+ {FEA2D0AE-6713-4E41-A473-A143849BC7FF}.Release|x64.ActiveCfg = Release|x64
+ {FEA2D0AE-6713-4E41-A473-A143849BC7FF}.Release|x64.Build.0 = Release|x64
+ {DEE5837B-E01D-4223-B351-EDF9418F3F8E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {DEE5837B-E01D-4223-B351-EDF9418F3F8E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {DEE5837B-E01D-4223-B351-EDF9418F3F8E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {DEE5837B-E01D-4223-B351-EDF9418F3F8E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {DEE5837B-E01D-4223-B351-EDF9418F3F8E}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {DEE5837B-E01D-4223-B351-EDF9418F3F8E}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {DEE5837B-E01D-4223-B351-EDF9418F3F8E}.Debug|x64.Build.0 = Debug|Any CPU
+ {DEE5837B-E01D-4223-B351-EDF9418F3F8E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {DEE5837B-E01D-4223-B351-EDF9418F3F8E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {DEE5837B-E01D-4223-B351-EDF9418F3F8E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {DEE5837B-E01D-4223-B351-EDF9418F3F8E}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {DEE5837B-E01D-4223-B351-EDF9418F3F8E}.Release|Win32.ActiveCfg = Release|Any CPU
+ {DEE5837B-E01D-4223-B351-EDF9418F3F8E}.Release|x64.ActiveCfg = Release|Any CPU
+ {DEE5837B-E01D-4223-B351-EDF9418F3F8E}.Release|x64.Build.0 = Release|Any CPU
+ {2321D01A-D64B-4461-9837-FACF38652212}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2321D01A-D64B-4461-9837-FACF38652212}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2321D01A-D64B-4461-9837-FACF38652212}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {2321D01A-D64B-4461-9837-FACF38652212}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {2321D01A-D64B-4461-9837-FACF38652212}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {2321D01A-D64B-4461-9837-FACF38652212}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {2321D01A-D64B-4461-9837-FACF38652212}.Debug|x64.Build.0 = Debug|Any CPU
+ {2321D01A-D64B-4461-9837-FACF38652212}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2321D01A-D64B-4461-9837-FACF38652212}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2321D01A-D64B-4461-9837-FACF38652212}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {2321D01A-D64B-4461-9837-FACF38652212}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {2321D01A-D64B-4461-9837-FACF38652212}.Release|Win32.ActiveCfg = Release|Any CPU
+ {2321D01A-D64B-4461-9837-FACF38652212}.Release|x64.ActiveCfg = Release|Any CPU
+ {2321D01A-D64B-4461-9837-FACF38652212}.Release|x64.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/libs/esl/src/esl.2012.vcxproj b/libs/esl/src/esl.2012.vcxproj
new file mode 100644
index 0000000000..90021628b6
--- /dev/null
+++ b/libs/esl/src/esl.2012.vcxproj
@@ -0,0 +1,158 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ esl
+ {CF405366-9558-4AE8-90EF-5E21B51CCB4E}
+ esl
+ Win32Proj
+
+
+
+ StaticLibrary
+ Unicode
+ true
+ v110
+
+
+ StaticLibrary
+ Unicode
+ v110
+
+
+ StaticLibrary
+ Unicode
+ true
+ v110
+
+
+ StaticLibrary
+ Unicode
+ v110
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <_ProjectFileVersion>10.0.30319.1
+
+
+
+ Disabled
+ include;%(AdditionalIncludeDirectories)
+ WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;ESL_DECLARE_STATIC;%(PreprocessorDefinitions)
+ true
+ EnableFastChecks
+ MultiThreadedDebugDLL
+ Level4
+ true
+ 4706;4100;%(DisableSpecificWarnings)
+ true
+
+
+
+
+ X64
+
+
+ Disabled
+ include;%(AdditionalIncludeDirectories)
+ WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;ESL_DECLARE_STATIC;%(PreprocessorDefinitions)
+ true
+ EnableFastChecks
+ MultiThreadedDebugDLL
+ Level4
+ false
+ 4706;4100;%(DisableSpecificWarnings)
+ true
+
+
+
+
+ include;%(AdditionalIncludeDirectories)
+ WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;ESL_DECLARE_STATIC;%(PreprocessorDefinitions)
+ MultiThreadedDLL
+ Level4
+ true
+ 4706;4100;%(DisableSpecificWarnings)
+ true
+
+
+
+
+ X64
+
+
+ include;%(AdditionalIncludeDirectories)
+ WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;ESL_DECLARE_STATIC;%(PreprocessorDefinitions)
+ MultiThreadedDLL
+ Level4
+ false
+ 4706;4100;%(DisableSpecificWarnings)
+ true
+
+
+
+
+
+
+ 6001;%(DisableSpecificWarnings)
+ 6001;%(DisableSpecificWarnings)
+ 6001;%(DisableSpecificWarnings)
+ 6001;%(DisableSpecificWarnings)
+
+
+
+ 28125;%(DisableSpecificWarnings)
+ 28125;%(DisableSpecificWarnings)
+ 28125;%(DisableSpecificWarnings)
+ 28125;%(DisableSpecificWarnings)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/libs/esl/src/esl.2012.vcxproj.filters b/libs/esl/src/esl.2012.vcxproj.filters
new file mode 100644
index 0000000000..d1ff43979a
--- /dev/null
+++ b/libs/esl/src/esl.2012.vcxproj.filters
@@ -0,0 +1,53 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hpp;hxx;hm;inl;inc;xsd
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+
diff --git a/libs/esl/src/esl.c b/libs/esl/src/esl.c
index 59da3d0ab9..103f9156c9 100644
--- a/libs/esl/src/esl.c
+++ b/libs/esl/src/esl.c
@@ -506,6 +506,11 @@ ESL_DECLARE(esl_status_t) esl_sendevent(esl_handle_t *handle, esl_event_t *event
len = strlen(txt) + 100;
event_buf = malloc(len);
assert(event_buf);
+
+ if (!event_buf) {
+ return ESL_FAIL;
+ }
+
memset(event_buf, 0, len);
snprintf(event_buf, len, "sendevent %s\n%s", esl_event_name(event->event_id), txt);
@@ -566,6 +571,11 @@ ESL_DECLARE(esl_status_t) esl_sendmsg(esl_handle_t *handle, esl_event_t *event,
len = strlen(txt) + 100;
cmd_buf = malloc(len);
assert(cmd_buf);
+
+ if (!cmd_buf) {
+ return ESL_FAIL;
+ }
+
memset(cmd_buf, 0, len);
if (uuid) {
diff --git a/libs/freetdm/conf/freetdm.conf.xml b/libs/freetdm/conf/freetdm.conf.xml
index 6177f7d0f5..dcbaafe2db 100644
--- a/libs/freetdm/conf/freetdm.conf.xml
+++ b/libs/freetdm/conf/freetdm.conf.xml
@@ -499,6 +499,18 @@ with the signaling protocols that you can run on top of your I/O interfaces.
-->
+
+
+ * Before changing this code, please read the following:
+ *
+ * The Configuration system for the TNP phones is simply a cache
+ * that exists for the GSM/SIP DLL to use. The property values are
+ * sent from Java across the JNI to the cache. This prevents
+ * the SIP and GSM code from having to suffer through a JNI call
+ * every time they wish to retrieve a configuration parameter.
+ *
+ * These ID's need to match the definitions in JplatConfigConstants.java
+ *
+ * To add a new value to the table,
+ * In general, you will have to:
+ *
+ * 1) Create an index for the new CFG param below
+ * 2) Update prot_cfg_table either in prot_cfgmgr_private.h
+ * or in prot_configmgr.c (for line specific params)
+ * 3) Update JPlatConfigConstants.h with the new ID
+ * 4) Create a property on JAVA side and update it from XML config
+ * 5) Update show_cfg_cmd if adding a new line param
+ *
+ *!!!!!!!!!!!!!!!!!!!!!!WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ *********************************************************/
+
+/* Keep non line specific params here */
+
+#define CFGID_MEDIA_PORT_RANGE_START CFGID_MEDIA_PORT_RANGE_START_INT
+#define CFGID_MEDIA_PORT_RANGE_END CFGID_MEDIA_PORT_RANGE_END_INT
+#define CFGID_CALLERID_BLOCKING CFGID_CALLERID_BLOCKING_BOOL
+#define CFGID_ANONYMOUS_CALL_BLOCK CFGID_ANONYMOUS_CALL_BLOCK_BOOL
+#define CFGID_DND_CALL_ALERT CFGID_DND_CALL_ALERT_BYTE
+#define CFGID_DND_REMINDER_TIMER CFGID_DND_REMINDER_TIMER_INT
+#define CFGID_PREFERRED_CODEC CFGID_PREFERRED_CODEC_STRING
+#define CFGID_DTMF_OUTOFBAND CFGID_DTMF_OUTOFBAND_STRING
+#define CFGID_DTMF_AVT_PAYLOAD CFGID_DTMF_AVT_PAYLOAD_INT
+#define CFGID_DTMF_DB_LEVEL CFGID_DTMF_DB_LEVEL_INT
+
+#define CFGID_SIP_RETX CFGID_SIP_RETX_INT
+#define CFGID_SIP_INVITE_RETX CFGID_SIP_INVITE_RETX_INT
+#define CFGID_TIMER_T1 CFGID_TIMER_T1_INT
+#define CFGID_TIMER_T2 CFGID_TIMER_T2_INT
+#define CFGID_TIMER_INVITE_EXPIRES CFGID_TIMER_INVITE_EXPIRES_INT
+#define CFGID_TIMER_REGISTER_EXPIRES CFGID_TIMER_REGISTER_EXPIRES_INT
+
+#define CFGID_PROXY_REGISTER CFGID_PROXY_REGISTER_BOOL
+#define CFGID_PROXY_BACKUP CFGID_PROXY_BACKUP_STRING
+#define CFGID_PROXY_BACKUP_PORT CFGID_PROXY_BACKUP_PORT_INT
+#define CFGID_PROXY_EMERGENCY CFGID_PROXY_EMERGENCY_STRING
+#define CFGID_PROXY_EMERGENCY_PORT CFGID_PROXY_EMERGENCY_PORT_INT
+#define CFGID_OUTBOUND_PROXY CFGID_OUTBOUND_PROXY_STRING
+#define CFGID_OUTBOUND_PROXY_PORT CFGID_OUTBOUND_PROXY_PORT_INT
+
+#define CFGID_NAT_RECEIVED_PROCESSING CFGID_NAT_RECEIVED_PROCESSING_BOOL
+#define CFGID_REG_USER_INFO CFGID_REG_USER_INFO_STRING
+#define CFGID_CNF_JOIN_ENABLE CFGID_CNF_JOIN_ENABLE_BOOL
+#define CFGID_REMOTE_PARTY_ID CFGID_REMOTE_PARTY_ID_BOOL
+#define CFGID_SEMI_XFER CFGID_SEMI_XFER_BOOL
+#define CFGID_CALL_HOLD_RINGBACK CFGID_CALL_HOLD_RINGBACK_BOOL
+#define CFGID_STUTTER_MSG_WAITING CFGID_STUTTER_MSG_WAITING_BOOL
+/**
+ * The CFGID_CFWD_URL was consolidated for RT and CIUS and should be for TNP as well.
+ */
+#define CFGID_CFWD_URL CFGID_CFWD_URL_STRING
+
+#define CFGID_CALL_STATS CFGID_CALL_STATS_BOOL
+#define CFGID_LOCAL_CFWD_ENABLE CFGID_LOCAL_CFWD_ENABLE_BOOL
+#define CFGID_TIMER_REGISTER_DELTA CFGID_TIMER_REGISTER_DELTA_INT
+#define CFGID_SIP_MAX_FORWARDS CFGID_SIP_MAX_FORWARDS_INT
+#define CFGID_2543_HOLD CFGID_2543_HOLD_BOOL
+
+#define CFGID_CCM1_ADDRESS CFGID_CCM1_ADDRESS_STRING
+#define CFGID_CCM2_ADDRESS CFGID_CCM2_ADDRESS_STRING
+#define CFGID_CCM3_ADDRESS CFGID_CCM3_ADDRESS_STRING
+
+// Note: IPv6 Not currently supported on Cius
+#define CFGID_CCM1_IPV6_ADDRESS CFGID_CCM1_IPV6_ADDRESS_STRING
+#define CFGID_CCM2_IPV6_ADDRESS CFGID_CCM2_IPV6_ADDRESS_STRING
+#define CFGID_CCM3_IPV6_ADDRESS CFGID_CCM3_IPV6_ADDRESS_STRING
+
+#define CFGID_CCM1_SIP_PORT CFGID_CCM1_SIP_PORT_INT
+#define CFGID_CCM2_SIP_PORT CFGID_CCM2_SIP_PORT_INT
+#define CFGID_CCM3_SIP_PORT CFGID_CCM3_SIP_PORT_INT
+
+#define CFGID_CCM1_SEC_LEVEL CFGID_CCM1_SEC_LEVEL_INT
+#define CFGID_CCM2_SEC_LEVEL CFGID_CCM2_SEC_LEVEL_INT
+#define CFGID_CCM3_SEC_LEVEL CFGID_CCM3_SEC_LEVEL_INT
+
+#define CFGID_CCM1_IS_VALID CFGID_CCM1_IS_VALID_BOOL
+#define CFGID_CCM2_IS_VALID CFGID_CCM2_IS_VALID_BOOL
+#define CFGID_CCM3_IS_VALID CFGID_CCM3_IS_VALID_BOOL
+
+#define CFGID_CCM_TFTP_IP_ADDR CFGID_CCM_TFTP_IP_ADDR_STRING
+#define CFGID_CCM_TFTP_PORT CFGID_CCM_TFTP_PORT_INT
+#define CFGID_CCM_TFTP_IS_VALID CFGID_CCM_TFTP_IS_VALID_BOOL
+#define CFGID_CCM_TFTP_SEC_LEVEL CFGID_CCM_TFTP_SEC_LEVEL_INT
+
+#define CFGID_CONN_MONITOR_DURATION CFGID_CONN_MONITOR_DURATION_INT
+#define CFGID_CALL_PICKUP_URI CFGID_CALL_PICKUP_URI_STRING
+#define CFGID_CALL_PICKUP_LIST_URI CFGID_CALL_PICKUP_LIST_URI_STRING
+#define CFGID_CALL_PICKUP_GROUP_URI CFGID_CALL_PICKUP_GROUP_URI_STRING
+#define CFGID_MEET_ME_SERVICE_URI CFGID_MEET_ME_SERVICE_URI_STRING
+#define CFGID_CALL_FORWARD_URI CFGID_CALL_FORWARD_URI_STRING
+#define CFGID_ABBREVIATED_DIAL_URI CFGID_ABBREVIATED_DIAL_URI_STRING
+#define CFGID_CALL_LOG_BLF_ENABLED CFGID_CALL_LOG_BLF_ENABLED_BOOL
+#define CFGID_REMOTE_CC_ENABLED CFGID_REMOTE_CC_ENABLED_BOOL
+#define CFGID_RETAIN_FORWARD_INFORMATION CFGID_RETAIN_FORWARD_INFORMATION_BOOL
+
+#define CFGID_TIMER_KEEPALIVE_EXPIRES CFGID_TIMER_KEEPALIVE_EXPIRES_INT
+#define CFGID_TIMER_SUBSCRIBE_EXPIRES CFGID_TIMER_SUBSCRIBE_EXPIRES_INT
+#define CFGID_TIMER_SUBSCRIBE_DELTA CFGID_TIMER_SUBSCRIBE_DELTA_INT
+#define CFGID_TRANSPORT_LAYER_PROT CFGID_TRANSPORT_LAYER_PROT_INT
+#define CFGID_KPML_ENABLED CFGID_KPML_ENABLED_INT
+
+#define CFGID_NAT_ENABLE CFGID_NAT_ENABLE_BOOL
+#define CFGID_NAT_ADDRESS CFGID_NAT_ADDRESS_STRING
+#define CFGID_VOIP_CONTROL_PORT CFGID_VOIP_CONTROL_PORT_INT
+#define CFGID_MY_IP_ADDR CFGID_MY_IP_ADDR_STRING
+#define CFGID_MY_MAC_ADDR CFGID_MY_MAC_ADDR_STRING
+#define CFGID_ENABLE_VAD CFGID_ENABLE_VAD_BOOL
+
+#define CFGID_AUTOANSWER_IDLE_ALTERNATE CFGID_AUTOANSWER_IDLE_ALTERNATE_BOOL
+#define CFGID_AUTOANSWER_TIMER CFGID_AUTOANSWER_TIMER_INT
+#define CFGID_AUTOANSWER_OVERRIDE CFGID_AUTOANSWER_OVERRIDE_BOOL
+
+#define CFGID_OFFHOOK_TO_FIRST_DIGIT_TIMER CFGID_OFFHOOK_TO_FIRST_DIGIT_TIMER_INT
+#define CFGID_CALL_WAITING_SILENT_PERIOD CFGID_CALL_WAITING_SILENT_PERIOD_INT
+#define CFGID_RING_SETTING_BUSY_POLICY CFGID_RING_SETTING_BUSY_POLICY_INT
+#define CFGID_DSCP_FOR_CALL_CONTROL CFGID_DSCP_FOR_CALL_CONTROL_INT
+#define CFGID_SPEAKER_ENABLED CFGID_SPEAKER_ENABLED_BOOL
+#define CFGID_XFR_ONHOOK_ENABLED CFGID_XFR_ONHOOK_ENABLED_BOOL
+#define CFGID_ROLLOVER CFGID_ROLLOVER_INT
+#define CFGID_LOAD_FILE CFGID_LOAD_FILE_STRING
+
+#define CFGID_BLF_ALERT_TONE_IDLE CFGID_BLF_ALERT_TONE_IDLE_INT
+#define CFGID_BLF_ALERT_TONE_BUSY CFGID_BLF_ALERT_TONE_BUSY_INT
+#define CFGID_AUTO_PICKUP_ENABLED CFGID_AUTO_PICKUP_ENABLED_BOOL
+
+#define CFGID_JOIN_ACROSS_LINES CFGID_JOIN_ACROSS_LINES_INT
+
+#define CFGID_MY_ACTIVE_MAC_ADDR CFGID_MY_ACTIVE_MAC_ADDR_STRING
+#define CFGID_DSCP_AUDIO CFGID_DSCP_AUDIO_INT
+#define CFGID_DEVICE_NAME CFGID_DEVICE_NAME_STRING
+#define CFGID_USER_AGENT CFGID_USER_AGENT_STRING
+#define CFGID_MODEL_NUMBER CFGID_MODEL_NUMBER_STRING
+#define CFGID_DSCP_VIDEO CFGID_DSCP_VIDEO_INT
+
+#define CFGID_IP_ADDR_MODE CFGID_IP_ADDR_MODE_INT
+#define CFGID_INTER_DIGIT_TIMER CFGID_INTER_DIGIT_TIMER_INT
+
+// Note - EMCC not currently supported on CIUS
+#define CFGID_EMCC_MODE CFGID_EMCC_MODE_BOOL
+#define CFGID_VISITING_EM_PORT CFGID_VISITING_EM_PORT_INT
+#define CFGID_VISITING_EM_IP CFGID_VISITING_EM_IP_STRING
+
+#define CFGID_CCM_EXTERNAL_NUMBER_MASK CFGID_CCM_EXTERNAL_NUMBER_MASK_STRING
+#define CFGID_MEDIA_IP_ADDR CFGID_MEDIA_IP_ADDR_STRING
+
+/* All non Line specific params should be added above */
+/* All Line specific params should be added below */
+
+#define CFGID_LINE_FEATURE CFGID_LINE_FEATURE_INT
+#define CFGID_LINE_INDEX CFGID_LINE_INDEX_INT
+#define CFGID_LINE_MAXNUMCALLS CFGID_LINE_MAXNUMCALLS_INT
+#define CFGID_LINE_NAME CFGID_LINE_NAME_STRING
+#define CFGID_LINE_AUTHNAME CFGID_LINE_AUTHNAME_STRING
+#define CFGID_LINE_PASSWORD CFGID_LINE_PASSWORD_STRING
+#define CFGID_LINE_DISPLAYNAME CFGID_LINE_DISPLAYNAME_STRING
+#define CFGID_LINE_CONTACT CFGID_LINE_CONTACT_STRING
+#define CFGID_PROXY_ADDRESS CFGID_PROXY_ADDRESS_STRING
+#define CFGID_PROXY_PORT CFGID_PROXY_PORT_INT
+#define CFGID_LINE_AUTOANSWER_ENABLED CFGID_LINE_AUTOANSWER_ENABLED_BYTE
+#define CFGID_LINE_AUTOANSWER_MODE CFGID_LINE_AUTOANSWER_MODE_STRING
+#define CFGID_LINE_CALL_WAITING CFGID_LINE_CALL_WAITING_BYTE
+#define CFGID_LINE_MSG_WAITING_LAMP CFGID_LINE_MSG_WAITING_LAMP_BYTE
+#define CFGID_LINE_MESSAGE_WAITING_AMWI CFGID_LINE_MESSAGE_WAITING_AMWI_BYTE
+#define CFGID_LINE_RING_SETTING_IDLE CFGID_LINE_RING_SETTING_IDLE_BYTE
+#define CFGID_LINE_RING_SETTING_ACTIVE CFGID_LINE_RING_SETTING_ACTIVE_BYTE
+#define CFGID_LINE_BUSY_TRIGGER CFGID_LINE_BUSY_TRIGGER_INT
+#define CFGID_LINE_CFWDALL CFGID_LINE_CFWDALL_STRING
+
+#define CFGID_LINE_SPEEDDIAL_NUMBER CFGID_LINE_SPEEDDIAL_NUMBER_STRING
+#define CFGID_LINE_RETRIEVAL_PREFIX CFGID_LINE_RETRIEVAL_PREFIX_STRING
+#define CFGID_LINE_MESSAGES_NUMBER CFGID_LINE_MESSAGES_NUMBER_STRING
+#define CFGID_LINE_FWD_CALLER_NAME_DIPLAY CFGID_LINE_FWD_CALLER_NAME_DIPLAY_BOOL
+#define CFGID_LINE_FWD_CALLER_NUMBER_DIPLAY CFGID_LINE_FWD_CALLER_NUMBER_DIPLAY_BOOL
+#define CFGID_LINE_FWD_REDIRECTED_NUMBER_DIPLAY CFGID_LINE_FWD_REDIRECTED_NUMBER_DIPLAY_BOOL
+#define CFGID_LINE_FWD_DIALED_NUMBER_DIPLAY CFGID_LINE_FWD_DIALED_NUMBER_DIPLAY_BOOL
+#define CFGID_LINE_FEATURE_OPTION_MASK CFGID_LINE_FEATURE_OPTION_MASK_INT
+#define CFGID_P2PSIP CFGID_P2PSIP_BOOL
+#define CFGID_VERSION CFGID_VERSION_STRING
+#define CFGID_SDPMODE CFGID_SDPMODE_BOOL
+#define CFGID_RTCPMUX CFGID_RTCPMUX_BOOL
+#define CFGID_RTPSAVPF CFGID_RTPSAVPF_BOOL
+#define CFGID_MAXAVBITRATE CFGID_MAXAVBITRATE_BOOL
+#define CFGID_MAXCODEDAUDIOBW CFGID_MAXCODEDAUDIOBW_BOOL
+#define CFGID_USEDTX CFGID_USEDTX_BOOL
+#define CFGID_STEREO CFGID_STEREO_BOOL
+#define CFGID_USEINBANDFEC CFGID_USEINBANDFEC_BOOL
+#define CFGID_CBR CFGID_CBR_BOOL
+#define CFGID_MAXPTIME CFGID_MAXPTIME_BOOL
+#define CFGID_SCTP_PORT CFGID_SCTP_PORT_INT
+#define CFGID_NUM_DATA_STREAMS CFGID_NUM_DATA_STREAMS_INT
+
+/*********************************************************
+ *
+ * Value Definitions
+ *
+ *********************************************************/
+// Line feature
+typedef enum {
+ cfgLineFeatureNone = CC_LINE_FEATURE_NONE,
+ cfgLineFeatureRedial = CC_LINE_FEATURE_REDIAL,
+ cfgLineFeatureSpeedDial = CC_LINE_FEATURE_SPEEDDIAL,
+ cfgLineFeatureDN = CC_LINE_FEATURE_DN,
+ cfgLineFeatureService = CC_LINE_FEATURE_SERVICE,
+ cfgLineFeatureSpeedDialBLF = CC_LINE_FEATURE_SPEEDDIALBLF,
+ cfgLineFeatureMaliciousCallID = CC_LINE_FEATURE_MALICIOUSCALLID,
+ cfgLineFeatureAllCalls = CC_LINE_FEATURE_ALLCALLS,
+ cfgLineFeatureAnswerOldest = CC_LINE_FEATURE_ANSWEROLDEST,
+ cfgLineFeatureServices = CC_LINE_FEATURE_SERVICES,
+ cfgLineFeatureBLF = CC_LINE_FEATURE_BLF
+} cfgLineFeatureType_e;
+
+/*********************************************************
+ *
+ * Function Prototypes
+ *
+ *********************************************************/
+void protocol_cfg_init(void);
+void sip_config_get_net_device_ipaddr(cpr_ip_addr_t *ip_addr);
+void sip_config_get_net_ipv6_device_ipaddr(cpr_ip_addr_t *ip_addr);
+void sip_config_get_nat_ipaddr(cpr_ip_addr_t *ip_addr);
+void sip_config_set_nat_ipaddr(cpr_ip_addr_t *ip_address);
+uint16_t sip_config_local_supported_codecs_get(rtp_ptype aSupportedCodecs[],
+ uint16_t supportedCodecsLen);
+uint16_t sip_config_video_supported_codecs_get(rtp_ptype aSupportedCodecs[],
+ uint16_t supportedCodecsLen, boolean isOffer);
+
+boolean prot_config_check_line_name(char *line_name);
+//const key_table_entry_t * sip_config_local_codec_entry_find(const rtp_ptype codec);
+line_t sip_config_get_button_from_line(line_t line);
+line_t sip_config_get_line_from_button(line_t button);
+boolean sip_config_check_line(line_t line);
+line_t sip_config_local_line_get(void);
+void sip_config_get_display_name(line_t line, char *buffer, int buffer_len);
+line_t sip_config_get_line_by_called_number(line_t start_line, const char *called_number);
+int sip_minimum_config_check(void);
+void config_set_codec_table(int codec_mask);
+int sip_config_get_keepalive_expires();
+rtp_ptype sip_config_preferred_codec(void);
+
+#endif /* PROT_CONFIGMGR_H_ */
diff --git a/libs/sipcc/core/common/resource_manager.c b/libs/sipcc/core/common/resource_manager.c
new file mode 100644
index 0000000000..6e969a1ecf
--- /dev/null
+++ b/libs/sipcc/core/common/resource_manager.c
@@ -0,0 +1,300 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "cpr_types.h"
+#include "cpr_stdlib.h"
+#include "resource_manager.h"
+#include "phone_debug.h"
+
+#define RM_NUM_ELEMENTS_PER_MAP 32
+#define rm_get_table_index(a) (a / RM_NUM_ELEMENTS_PER_MAP)
+#define rm_get_map_offset(a) (a % RM_NUM_ELEMENTS_PER_MAP)
+
+/*
+ * rm_clear_all_elements
+ *
+ * Description:
+ * This function clears all members of the specified resource manager
+ *
+ * Parameters:
+ * rm_p - pointer to the resource manager to be cleared
+ *
+ * Returns:
+ * None
+ */
+void
+rm_clear_all_elements (resource_manager_t *rm_p)
+{
+ static const char fname[] = "rm_clear_all_elements";
+ uint16_t i;
+
+ if (!rm_p) {
+ PLAT_ERROR(PLAT_COMMON_F_PREFIX"null resource manager received.\n", fname);
+ return;
+ }
+
+ for (i = 0; i < rm_p->max_index; i++) {
+ rm_p->table[i] = 0;
+ }
+}
+
+/*
+ * rm_clear_element
+ *
+ * Description:
+ * This function clears a single element from the specified resource manager
+ *
+ * Parameters:
+ * rm_p - pointer to the resource manager to be cleared
+ * element - element id of element to be cleared
+ *
+ * Returns:
+ * None
+ */
+void
+rm_clear_element (resource_manager_t * rm_p, int16_t element)
+{
+ static const char fname[] = "rm_clear_elements";
+
+ if (!rm_p) {
+ PLAT_ERROR(PLAT_COMMON_F_PREFIX"null resource manager received.\n", fname);
+ return;
+ }
+
+ if (element < 0 || element >= rm_p->max_element) {
+ PLAT_ERROR(PLAT_COMMON_F_PREFIX"element value %d invalid. Max value is %d.\n",
+ fname, element, rm_p->max_element - 1);
+ return;
+ }
+
+ rm_p->table[rm_get_table_index(element)] &=
+ (~(1 << rm_get_map_offset(element)));
+}
+
+/*
+ * rm_set_element
+ *
+ * Description:
+ * This function sets the bit representing the specified element
+ * in the specified resource manager.
+ *
+ * Parameters:
+ * rm_p - pointer to the resource manager
+ * element - element id of element to be set
+ *
+ * Returns:
+ * None
+ */
+void
+rm_set_element (resource_manager_t *rm_p, int16_t element)
+{
+ static const char fname[] = "rm_set_element";
+
+ if (!rm_p) {
+ PLAT_ERROR(PLAT_COMMON_F_PREFIX"null resource manager received.\n", fname);
+ return;
+ }
+
+ if (element < 0 || element >= rm_p->max_element) {
+ PLAT_ERROR(PLAT_COMMON_F_PREFIX"element value %d invalid. Max value %d.\n",
+ fname, element, rm_p->max_element - 1);
+ return;
+ }
+
+ rm_p->table[rm_get_table_index(element)] |=
+ (1 << rm_get_map_offset(element));
+}
+
+/*
+ * rm_is_element_set
+ *
+ * Description:
+ * This function checks if the specified element in the specified
+ * resource manager is set.
+ *
+ * Parameters:
+ * rm_p - pointer to the resource manager.
+ * element - element id of element to be checked.
+ *
+ * Returns:
+ * TRUE if element is set, else FALSE
+ */
+boolean
+rm_is_element_set (resource_manager_t *rm_p, int16_t element)
+{
+ static const char fname[] = "rm_is_element_set";
+
+ if (!rm_p) {
+ PLAT_ERROR(PLAT_COMMON_F_PREFIX"null resource manager received.\n", fname);
+ return FALSE;
+ }
+
+ if (element < 0 || element >= rm_p->max_element) {
+ PLAT_ERROR(PLAT_COMMON_F_PREFIX"element value %d invalid. Max value %d.\n",
+ fname, element, rm_p->max_element - 1);
+ return FALSE;
+ }
+
+ if (rm_p->table[rm_get_table_index(element)] &
+ (1 << rm_get_map_offset(element))) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*
+ * rm_get_free_element
+ *
+ * Description:
+ * This function walks through the members of the resource manager and
+ * attempts to locate a free element. If a free element is found, the
+ * element's associated bit is set in the resource manager and the
+ * element id is returned.
+ *
+ * Parameters:
+ * rm_p - pointer to the resource manager.
+ *
+ * Returns:
+ * If an element is available, a element id (from zero to max element)
+ * If no element is available, -1 is returned.
+ */
+int16_t
+rm_get_free_element (resource_manager_t *rm_p)
+{
+ static const char fname[] = "rm_get_free_element";
+ int16_t element = -1;
+ uint16_t i, j;
+ uint32_t max_map = 0;
+
+ max_map = ~max_map;
+
+ if (!rm_p) {
+ PLAT_ERROR(PLAT_COMMON_F_PREFIX"null resource manager received.\n", fname);
+ return -1;
+ }
+
+ for (i = 0; i < rm_p->max_index && element == -1; i++) {
+ if (rm_p->table[i] != max_map) {
+ for (j = 0; j < RM_NUM_ELEMENTS_PER_MAP && element == -1; j++) {
+ if (!(rm_p->table[i] & (1 << j))) {
+ element = i * RM_NUM_ELEMENTS_PER_MAP + j;
+ if (element < rm_p->max_element) {
+ rm_set_element(rm_p, element);
+ }
+ }
+ }
+ }
+ }
+
+ if (element >= rm_p->max_element) {
+ element = -1;
+ }
+ return (element);
+}
+
+/*
+ * rm_show
+ *
+ * Description:
+ * Utility function used to dump the contents of the resource manager.
+ *
+ * Parameters:
+ * rm_p - pointer to the resource manager.
+ *
+ * Returns:
+ * none
+ */
+void
+rm_show (resource_manager_t *rm_p)
+{
+ static const char fname[] = "rm_show";
+ int16_t element = 0;
+ uint16_t i, j;
+
+ if (!rm_p) {
+ PLAT_ERROR(PLAT_COMMON_F_PREFIX"null resource manager received.\n", fname);
+ return;
+ }
+
+ for (i = 0; i < rm_p->max_index; i++) {
+ for (j = 0; j < RM_NUM_ELEMENTS_PER_MAP; j++) {
+ if (rm_p->table[i] & (1 << j)) {
+ element = (i * RM_NUM_ELEMENTS_PER_MAP) + j;
+ TNP_DEBUG(DEB_F_PREFIX"rm map: %d\n", DEB_F_PREFIX_ARGS(RM, fname), element);
+ }
+ }
+ }
+}
+
+/*
+ * rm_create
+ *
+ * Description:
+ * Allocates and initializes a new resource manager
+ *
+ * Parameters:
+ * max_element - Maximum number of elements the resource manager
+ * is required to track
+ *
+ * Returns:
+ * If successful, pointer to the newly allocated resource manager
+ * If not successful, NULL
+ */
+resource_manager_t *
+rm_create (int16_t max_element)
+{
+ static const char fname[] = "rm_create";
+ resource_manager_t *rm_p;
+
+ if (max_element < 0) {
+ PLAT_ERROR(PLAT_COMMON_F_PREFIX"invalid max element %d received.\n", fname,
+ max_element);
+ return NULL;
+ }
+
+ rm_p = (resource_manager_t *) cpr_malloc(sizeof(resource_manager_t));
+ if (!rm_p) {
+ PLAT_ERROR(PLAT_COMMON_F_PREFIX"unable to allocate resource manager.\n", fname);
+ return NULL;
+ }
+
+ rm_p->max_element = max_element;
+ rm_p->max_index = max_element / RM_NUM_ELEMENTS_PER_MAP + 1;
+
+ rm_p->table = (uint32_t *)
+ cpr_malloc(rm_p->max_index * RM_NUM_ELEMENTS_PER_MAP);
+ if (!rm_p->table) {
+ free(rm_p);
+ return NULL;
+ }
+ rm_clear_all_elements(rm_p);
+ return rm_p;
+}
+
+/*
+ * rm_free
+ *
+ * Description:
+ * This function frees the memory allocated for the specified resource manager.
+ *
+ * Parameters:
+ * rm_p - pointer to the resource manager.
+ *
+ * Returns:
+ * none
+ */
+void
+rm_destroy (resource_manager_t *rm_p)
+{
+ static const char fname[] = "rm_destroy";
+
+ if (!rm_p) {
+ PLAT_ERROR(PLAT_COMMON_F_PREFIX"null resource manager received.\n", fname);
+ return;
+ }
+
+ cpr_free(rm_p->table);
+ cpr_free(rm_p);
+}
diff --git a/libs/sipcc/core/common/resource_manager.h b/libs/sipcc/core/common/resource_manager.h
new file mode 100644
index 0000000000..4d34be59dc
--- /dev/null
+++ b/libs/sipcc/core/common/resource_manager.h
@@ -0,0 +1,23 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _RM_MGR_H__
+#define _RM_MGR_H_
+
+typedef struct resource_manager {
+ int16_t max_element;
+ int16_t max_index;
+ uint32_t *table;
+} resource_manager_t;
+
+void rm_clear_all_elements(resource_manager_t *rm);
+void rm_clear_element(resource_manager_t *rm, int16_t element);
+void rm_set_element(resource_manager_t *rm, int16_t element);
+boolean rm_is_element_set(resource_manager_t *rm, int16_t element);
+int16_t rm_get_free_element(resource_manager_t *rm);
+void rm_show(resource_manager_t *rm);
+resource_manager_t *rm_create(int16_t max_element);
+void rm_destroy(resource_manager_t *rm);
+
+#endif
diff --git a/libs/sipcc/core/common/sip_socket_api.c b/libs/sipcc/core/common/sip_socket_api.c
new file mode 100755
index 0000000000..15952840f1
--- /dev/null
+++ b/libs/sipcc/core/common/sip_socket_api.c
@@ -0,0 +1,100 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "cpr.h"
+#include "cpr_socket.h"
+#include "errno.h"
+#include "plat_api.h"
+
+/**
+ * sipSocketSend
+ *
+ * @brief The sipSocketSend() function is a wrapper used by the sipstack to send
+ * data over a socket. This function decides to use the secure versus unsecure
+ * connection based on the "secure" flag.
+ *
+ * @note - The implementation of both secure/non-secure is the same in RT/TNP
+ * products. It is different for the other vendors and hence we need this
+ * flexibility.
+ *
+ * @param[in] soc Specifies the socket created with cprSocket() to send
+ * @param[in] buf A pointer to the buffer of the message to send.
+ * @param[in] len Specifies the length in bytes of the message pointed to by the buffer argument.
+ * @param[in] flags - The options used for the send.
+ *
+ *
+ */
+ssize_t
+sipSocketSend (cpr_socket_t soc,
+ CONST void *buf,
+ size_t len,
+ int32_t flags,
+ boolean secure)
+{
+// if (secure) {
+// return platSecSocSend (soc, buf, len);
+// } else {
+ return cprSend(soc, buf, len, flags);
+// }
+}
+
+/**
+ * sipSocketRecv
+ *
+ * @brief The sipSocketRecv() function is a wrapper used by the sipstack to send
+ * data over a socket. This function decides to use the secure versus unsecure
+ * connection based on the "secure" flag.
+ *
+ * @note - The implementation of both secure/non-secure is the same in RT/TNP
+ * products. It is different for the other vendors and hence we need this
+ * flexibility.
+ *
+ * @param[in] soc Specifies the socket created with cprSocket() to send
+ * @param[in] buf A pointer to the buffer of the message to send.
+ * @param[in] len Specifies the length in bytes of the message pointed to by the buffer argument.
+ * @param[in] flags - The options used for the recv.
+ */
+ssize_t
+sipSocketRecv (cpr_socket_t soc,
+ void * RESTRICT buf,
+ size_t len,
+ int32_t flags,
+ boolean secure)
+{
+// if (secure) {
+// return platSecSocRecv (soc, buf, len);
+// } else {
+ return cprRecv(soc, buf, len, flags);
+// }
+}
+
+/**
+ * sipSocketClose
+ *
+ * @brief The sipSocketClose() function is a wrapper used by the sipstack to
+ * close a socket. This function decides to use the secure versus unsecure
+ * connection based on the "secure" flag.
+ *
+ * @note - The implementation of both secure/non-secure is the same in RT/TNP
+ * products. It is different for the other vendors and hence we need this
+ * flexibility.
+ *
+ * @param[in] soc - The socket that needs to be destroyed
+ *
+ * @return CPR_SUCCESS on success otherwise, CPR_FAILURE. cpr_errno needs to be set in this case.
+ *
+ * @note The possible error values this function should return are
+ * @li [CPR_EBADF] socket is not a valid socket descriptor.
+ */
+cpr_status_e
+sipSocketClose (cpr_socket_t soc,
+ boolean secure)
+{
+// if (secure) {
+// return platSecSocClose (soc);
+// } else {
+ return cprCloseSocket(soc);
+// }
+}
+
diff --git a/libs/sipcc/core/common/subscription_handler.c b/libs/sipcc/core/common/subscription_handler.c
new file mode 100755
index 0000000000..f587379ccb
--- /dev/null
+++ b/libs/sipcc/core/common/subscription_handler.c
@@ -0,0 +1,342 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "cpr_types.h"
+#include "cc_types.h"
+#include "phone_platform_constants.h"
+#include "cc_constants.h"
+#include "phone_debug.h"
+#include "prot_configmgr.h"
+#include "cc_blf.h"
+#include "ccapi_snapshot.h"
+
+#define SPEEDDIAL_START_BUTTON_NUMBER 2
+
+static unsigned char transactionIds[MAX_REG_LINES];
+static boolean displayBLFState = TRUE;
+static cc_blf_state_t blfStates[MAX_REG_LINES];
+static boolean isBLFHandlerRunning = FALSE;
+static boolean isAvailable = FALSE;
+
+#ifndef INT_MAX
+#define INT_MAX 2147483647
+#endif
+
+static void ccBLFHandlerInitialized();
+
+/*
+ * Function: sub_hndlr_isAlertingBLFState
+ *
+ * Description: returns if the BLF state is "alerting"
+ *
+ * Parameters:
+ * inst - line button number.
+ *
+ * Returns: TRUE/FALSE
+ */
+boolean sub_hndlr_isAlertingBLFState(int inst)
+{
+ static const char fname[] = "sub_hndlr_isAlertingBLFState";
+
+ if ((displayBLFState == TRUE) && (blfStates[inst - 1] == CC_SIP_BLF_ALERTING)) {
+ CCAPP_DEBUG(DEB_F_PREFIX"inst=%d, isAlerting=TRUE\n",
+ DEB_F_PREFIX_ARGS(SIP_CC_PROV, fname),
+ inst);
+
+ return TRUE;
+ }
+ CCAPP_DEBUG(DEB_F_PREFIX"inst=%d, isAlerting=FALSE\n",
+ DEB_F_PREFIX_ARGS(SIP_CC_PROV, fname),
+ inst);
+ return FALSE;
+}
+
+/*
+ * Function: sub_hndlr_isInUseBLFState
+ *
+ * Description: returns if the BLF state is "in use"
+ *
+ * Parameters:
+ * inst - line button number.
+ *
+ * Returns: TRUE/FALSE
+ */
+boolean sub_hndlr_isInUseBLFState(int inst)
+{
+ static const char fname[] = "sub_hndlr_isInUseBLFState";
+
+ if ((displayBLFState == TRUE) && (blfStates[inst - 1] == CC_SIP_BLF_INUSE)) {
+ CCAPP_DEBUG(DEB_F_PREFIX"inst=%d, isInUse=TRUE\n",
+ DEB_F_PREFIX_ARGS(SIP_CC_PROV, fname),
+ inst);
+ return TRUE;
+ }
+ CCAPP_DEBUG(DEB_F_PREFIX"inst=%d, isInUse=FALSE\n",
+ DEB_F_PREFIX_ARGS(SIP_CC_PROV, fname),
+ inst);
+ return FALSE;
+}
+
+/*
+ * Function: sub_hndlr_isAvailable
+ *
+ * Description: returns if the subscription handler is available.
+ *
+ * Parameters: none.
+ *
+ * Returns: TRUE/FALSE
+ */
+boolean sub_hndlr_isAvailable()
+{
+ static const char fname[] = "sub_hndlr_isAvailable";
+
+ CCAPP_DEBUG(DEB_F_PREFIX"isAvailable=%d\n",
+ DEB_F_PREFIX_ARGS(SIP_CC_PROV, fname),
+ isAvailable);
+ return isAvailable;
+}
+
+static unsigned short get_new_trans_id()
+{
+ static unsigned short curr_trans_id = 0;
+
+ if (++curr_trans_id == 0) {
+ curr_trans_id = 1;
+ }
+
+ return curr_trans_id;
+}
+
+/*
+ * Function: sub_hndlr_start
+ *
+ * Description: does blf subscriptions upon registration.
+ *
+ * Parameters: none.
+ *
+ * Returns: void
+ */
+void sub_hndlr_start()
+{
+ static const char fname[] = "sub_hndlr_start";
+ int i;
+ cc_uint32_t lineFeature = 0;
+ cc_uint32_t featureOptionMask = 0;
+ char speedDialNumber[MAX_LINE_NAME_SIZE] = {0};
+ char primaryLine[MAX_LINE_NAME_SIZE] = {0};
+ int transId;
+
+ CCAPP_DEBUG(DEB_F_PREFIX"entering\n",
+ DEB_F_PREFIX_ARGS(SIP_CC_PROV, fname));
+ /* let the system know that subscription handler is available. */
+ isAvailable = TRUE;
+
+ /* get primary DN */
+ config_get_line_string(CFGID_LINE_NAME, primaryLine, 1, sizeof(primaryLine));
+
+ /*
+ * for speeddial/BLF buttons, make presence subscriptions.
+ */
+ for (i = SPEEDDIAL_START_BUTTON_NUMBER; i <= MAX_REG_LINES; i++) {
+ // first line must always be a calling line.
+ config_get_line_value(CFGID_LINE_FEATURE, &lineFeature, sizeof(lineFeature), i);
+
+
+ CCAPP_DEBUG(DEB_F_PREFIX"inst=%d, lineFeature=%d\n",
+ DEB_F_PREFIX_ARGS(SIP_CC_PROV, fname),
+ i, lineFeature);
+ switch (lineFeature) {
+ case cfgLineFeatureSpeedDialBLF:
+ config_get_line_string(CFGID_LINE_SPEEDDIAL_NUMBER, speedDialNumber, i, sizeof(speedDialNumber));
+ if (speedDialNumber[0] == 0) {
+ break;
+ }
+ config_get_line_value(CFGID_LINE_FEATURE, &featureOptionMask, sizeof(featureOptionMask), i);
+
+ transId = get_new_trans_id();
+ transactionIds[i - 1] = transId;
+ CC_BLF_subscribe(transId,
+ INT_MAX,
+ primaryLine,
+ speedDialNumber,
+ i,
+ featureOptionMask );
+ break;
+ default:
+ break;
+ }
+
+ //Initializes native BLF handler
+ ccBLFHandlerInitialized();
+ }
+}
+
+static void ccBLFHandlerInitialized()
+{
+ if (!isBLFHandlerRunning) {
+ CC_BLF_init();
+ isBLFHandlerRunning = TRUE;
+ }
+}
+
+/*
+ * Function: sub_hndlr_stop
+ *
+ * Description: terminates blf subscriptions upon unregistration.
+ *
+ * Parameters: none.
+ *
+ * Returns: void
+ */
+void sub_hndlr_stop()
+{
+ static const char fname[] = "sub_hndlr_stop";
+ int i;
+
+ CCAPP_DEBUG(DEB_F_PREFIX"entering\n",
+ DEB_F_PREFIX_ARGS(SIP_CC_PROV, fname));
+ isAvailable = FALSE;
+ isBLFHandlerRunning = FALSE;
+
+ // should clean up blf susbcription list.
+ for (i = SPEEDDIAL_START_BUTTON_NUMBER; i <= MAX_REG_LINES; i++) {
+ //first, reset the transaction ids
+ transactionIds[i - 1] = 0;
+ //reset blf states.
+ blfStates[i - 1] = CC_SIP_BLF_UNKNOWN;
+ }
+ CC_BLF_unsubscribe_All();
+}
+
+
+/*
+ * Function: hideBLFButtonsDisplay
+ *
+ * Description: hides BLF states
+ *
+ * Parameters: none.
+ *
+ * Returns: void
+ */
+static void hideBLFButtonsDisplay()
+{
+ static const char fname[] = "hideBLFButtonsDisplay";
+ int i;
+ cc_uint32_t lineFeature = 0;
+
+ CCAPP_DEBUG(DEB_F_PREFIX"entering\n",
+ DEB_F_PREFIX_ARGS(SIP_CC_PROV, fname));
+ displayBLFState = FALSE;
+ for (i = SPEEDDIAL_START_BUTTON_NUMBER; i <= MAX_REG_LINES; i++) {
+ // first line must always be a calling line.
+ config_get_line_value(CFGID_LINE_FEATURE, &lineFeature, sizeof(lineFeature), i);
+
+ switch (lineFeature) {
+ case cfgLineFeatureSpeedDialBLF:
+ ccsnap_gen_blfFeatureEvent(CC_SIP_BLF_UNKNOWN, i);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+/*
+ * Function: unhideBLFButtonsDisplay
+ *
+ * Description: unhides BLF states.
+ *
+ * Parameters: none.
+ *
+ * Returns: void
+ */
+static void unhideBLFButtonsDisplay()
+{
+ static const char fname[] = "unhideBLFButtonsDisplay";
+ int i;
+ cc_uint32_t lineFeature = 0;
+ char speedDialNumber[MAX_LINE_NAME_SIZE] = {0};
+
+ CCAPP_DEBUG(DEB_F_PREFIX"entering\n",
+ DEB_F_PREFIX_ARGS(SIP_CC_PROV, fname));
+
+ displayBLFState = TRUE;
+
+ for (i = SPEEDDIAL_START_BUTTON_NUMBER; i <= MAX_REG_LINES; i++) {
+ // first line must always be a calling line.
+ config_get_line_value(CFGID_LINE_FEATURE, &lineFeature, sizeof(lineFeature), i);
+ config_get_line_string(CFGID_LINE_SPEEDDIAL_NUMBER, speedDialNumber, i, sizeof(speedDialNumber));
+
+ switch (lineFeature) {
+ case cfgLineFeatureSpeedDialBLF:
+ ccsnap_gen_blfFeatureEvent(blfStates[i - 1], i);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+/*
+ * Function: sub_hndlr_controlBLFButtons
+ *
+ * Description: hides/unhides BLF states.
+ *
+ * Parameters: none.
+ *
+ * Returns: void
+ */
+void sub_hndlr_controlBLFButtons(boolean state)
+{
+ static const char fname[] = "sub_hndlr_controlBLFButtons";
+
+ if (state == TRUE) {
+ CCAPP_DEBUG(DEB_F_PREFIX"going to hide\n",
+ DEB_F_PREFIX_ARGS(SIP_CC_PROV, fname));
+ hideBLFButtonsDisplay();
+ } else {
+ CCAPP_DEBUG(DEB_F_PREFIX"going to unhide\n",
+ DEB_F_PREFIX_ARGS(SIP_CC_PROV, fname));
+ unhideBLFButtonsDisplay();
+ }
+}
+
+/*
+ * Function: sub_hndlr_NotifyBLFStatus
+ *
+ * Description: notifies the app of BLF state.
+ *
+ * Parameters:
+ * requestId - requestId of the subscription
+ * status - BLF status
+ * appId - button number of the BLF feature key.
+ *
+ * Returns: void
+ */
+void sub_hndlr_NotifyBLFStatus(int requestId, cc_blf_state_t status, int appId)
+{
+ static const char fname[] = "sub_hndlr_NotifyBLFStatus";
+ cc_uint32_t lineFeature = 0;
+ char speedDialNumber[MAX_LINE_NAME_SIZE] = {0};
+
+
+ CCAPP_DEBUG(DEB_F_PREFIX"requestId=%d, status=%d, appId=%d\n",
+ DEB_F_PREFIX_ARGS(SIP_CC_PROV, fname),
+ requestId, status, appId);
+ if (appId == 0) {
+ // call list BLF.
+ } else {
+ config_get_line_value(CFGID_LINE_FEATURE, &lineFeature, sizeof(lineFeature), appId);
+ config_get_line_string(CFGID_LINE_SPEEDDIAL_NUMBER, speedDialNumber, appId, sizeof(speedDialNumber));
+
+ blfStates[appId - 1] = status;
+ if (displayBLFState == FALSE) {
+ return; // ignore the notify
+ }
+ if (lineFeature == cfgLineFeatureSpeedDialBLF) {
+ ccsnap_gen_blfFeatureEvent(status, appId);
+ }
+ }
+}
+
diff --git a/libs/sipcc/core/common/subscription_handler.h b/libs/sipcc/core/common/subscription_handler.h
new file mode 100755
index 0000000000..3bcf7317d2
--- /dev/null
+++ b/libs/sipcc/core/common/subscription_handler.h
@@ -0,0 +1,23 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef __SUB_HANDLER_H__
+#define __SUB_HANDLER_H__
+
+boolean sub_hndlr_isAlertingBLFState(int inst);
+
+boolean sub_hndlr_isInUseBLFState(int inst);
+
+boolean sub_hndlr_isAvailable();
+
+void sub_hndlr_start();
+
+void sub_hndlr_stop();
+
+void sub_hndlr_controlBLFButtons(boolean state);
+
+void sub_hndlr_NotifyBLFStatus(int requestId, int status, int appId);
+
+#endif
+
diff --git a/libs/sipcc/core/common/text_strings.c b/libs/sipcc/core/common/text_strings.c
new file mode 100755
index 0000000000..b8576c9c7d
--- /dev/null
+++ b/libs/sipcc/core/common/text_strings.c
@@ -0,0 +1,361 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include
+#include "text_strings.h"
+
+
+#define dcl_str(x,p) char str_##x[] = p
+#define use_str(x) str_##x
+
+
+/*
+ * Debug strings. No localization needed. Keep it separate.
+ */
+
+dcl_str(DEBUG_START, "SIPCC-START:\0");
+dcl_str(DEBUG_SEPARATOR_BAR, "===============\n");
+dcl_str(DEBUG_CONSOLE_PASSWORD, "CONSOLE-PWD:cisco");
+dcl_str(DEBUG_CONSOLE_KEYWORD_CONSOLE_STALL, "CONSOLE-STALL");
+dcl_str(DEBUG_CONSOLE_KEYWORD_MEMORYMAP, "CONSOLE-MEMORYMAP");
+dcl_str(DEBUG_CONSOLE_KEYWORD_MALLOCTABLE, "CONSOLE-MALLOCTABLE");
+dcl_str(DEBUG_CONSOLE_KEYWORD_MEMORYDUMP, "CONSOLE-DUMP");
+dcl_str(DEBUG_CONSOLE_KEYWORD_DNS, "CONSOLE-DNS");
+dcl_str(DEBUG_CONSOLE_KEYWORD_DSPSTATE, "CONSOLE-DSPSTATE");
+dcl_str(DEBUG_CONSOLE_USAGE_MEMORYDUMP, "CONSOLE-MEMORYDUMP: addr bytes [cnt blk [1/0 char output]]\n");
+dcl_str(DEBUG_CONSOLE_BREAK, "CONSOLE-BREAK\r\n");
+
+dcl_str(DEBUG_FUNCTION_ENTRY, "SIPCC-FUNC_ENTRY: LINE %d/%d: %-35s: %s <- %s\n");
+dcl_str(DEBUG_FUNCTION_ENTRY2, "SIPCC-FUNC_ENTRY: LINE %d/%d: %-35s: %s <- %s(%d)\n");
+dcl_str(DEBUG_SIP_ENTRY, "SIPCC-ENTRY: LINE %d/%d: %-35s: %s\n");
+dcl_str(DEBUG_SIP_URL_ERROR, "SIPCC-%s: Error: URL is not SIP.\n");
+dcl_str(DEBUG_LINE_NUMBER_INVALID, "SIPCC-LINE_NUM: %s: Error: Line number (%d) is invalid\n");
+dcl_str(DEBUG_SIP_SPI_SEND_ERROR, "SIPCC-SPI_SEND_ERR: %s: Error: sipSPISendErrorResponse(%d) failed.\n");
+dcl_str(DEBUG_SIP_SDP_CREATE_BUF_ERROR, "SIPCC-SDP_BUF: %s: Error: sipsdp_src_dest_create() returned null\n");
+dcl_str(DEBUG_SIP_PARSE_SDP_ERROR, "SIPCC-SDP_PARSE: %s: Error: sdp_parse()\n");
+dcl_str(DEBUG_SIP_FEATURE_UNSUPPORTED, "SIPCC-FEATURE: LINE %d/%d: %-35s: This feature is unsupported in the current state.\n");
+dcl_str(DEBUG_SIP_DEST_SDP, "SIPCC-SDP_DEST: LINE %d/%d: %-35s: Process SDP: Dest=<%s>:<%d>\n");
+dcl_str(DEBUG_SIP_MSG_SENDING_REQUEST, "SIPCC-MSG_SEND_REQ: %s: Sending %s...\n");
+dcl_str(DEBUG_SIP_MSG_SENDING_RESPONSE, "SIPCC-MSG_SEND_RESP: %s: Sending response %d...\n");
+dcl_str(DEBUG_SIP_MSG_RECV, "SIPCC-MSG_RECV: %s: Received SIP message %s.\n");
+dcl_str(DEBUG_SIP_STATE_UNCHANGED, "SIPCC-SIP_STATE: LINE %d/%d: %-35s: State unchanged -> %s\n");
+dcl_str(DEBUG_SIP_FUNCTIONCALL_FAILED, "SIPCC-FUNC_CALL: LINE %d/%d: %-35s: Error: %s returned error.\n");
+dcl_str(DEBUG_SIP_BUILDFLAG_ERROR, "SIPCC-BUILD_FLAG: %s: Error: Build flag is not successful. Will not send message.\n");
+dcl_str(DEBUG_GENERAL_FUNCTIONCALL_FAILED, "SIPCC-FUNC_CALL: %s: Error: %s returned error.\n");
+dcl_str(DEBUG_GENERAL_SYSTEMCALL_FAILED, "SIPCC-SYS_CALL: %s: Error: %s failed: errno = %d\n");
+dcl_str(DEBUG_GENERAL_FUNCTIONCALL_BADARGUMENT, "SIPCC-FUNC_CALL: %s: Error: invalid argument: %s\n");
+dcl_str(DEBUG_FUNCTIONNAME_SIPPMH_PARSE_FROM, "SIPCC-FUNC_NAME: sippmh_parse_from_or_to(FROM)");
+dcl_str(DEBUG_FUNCTIONNAME_SIPPMH_PARSE_TO, "SIPCC-FUNC_NAME: sippmh_parse_from_or_to(TO)");
+dcl_str(DEBUG_FUNCTIONNAME_SIP_SM_REQUEST_CHECK_AND_STORE, "SIPCC-SM_REQ: sip_sm_request_check_and_store()");
+dcl_str(DEBUG_SNTP_LI_ERROR, "SIPCC-SNTP: Leap indicator == 3\n");
+dcl_str(DEBUG_SNTP_MODE_ERROR, "SIPCC-SNTP: Mode is not server (4/5) in response\n");
+dcl_str(DEBUG_SNTP_STRATUM_ERROR, "SIPCC-SNTP: Invalid stratum > 15\n");
+dcl_str(DEBUG_SNTP_TIMESTAMP_ERROR, "SIPCC-SNTP: Server did not echo our transmit timestamp\n");
+dcl_str(DEBUG_SNTP_TIMESTAMP1, "SIPCC-SNTP: %-15s: 0x%08x %08x, ");
+dcl_str(DEBUG_SNTP_TIMESTAMP2, "SIPCC-SNTP: (%+03d:%02d) %s");
+dcl_str(DEBUG_SNTP_TIME_UPDATE, "SIPCC-SNTP: Updating date and time to:\n%s %lu %02lu:%02lu:%02lu "
+ "%04lu, %s, week %lu and day %lu. "
+ "Daylight saving is: %d\n\n");
+dcl_str(DEBUG_SNTP_TS_HEADER, "SIPCC-SNTP: Settings:\nMode : %lu\nTimezone "
+ ": %d\nServer Addr : %s\nTimeStruct : TZ/Offset: %d/%lu,"
+ " AutoAdjust: %d\nMo Day DoW WoM Time\n");
+dcl_str(DEBUG_SNTP_TS_PRINT, "SIPCC-SNTP: %3lu %3lu %3lu %3lu %4lu\n");
+dcl_str(DEBUG_SNTP_SOCKET_REOPEN, "SIPCC-SNTP: Re-opening listening port due to IP change\n");
+dcl_str(DEBUG_SNTP_DISABLED, "SIPCC-SNTP: Unicast w/server addr 0.0.0.0, SNTP disabled\n");
+dcl_str(DEBUG_SNTP_REQUEST, "SIPCC-SNTP: Sending NTP request packet [%s]\n");
+dcl_str(DEBUG_SNTP_RESPONSE, "SIPCC-SNTP: Receiving NTP response packet\n");
+dcl_str(DEBUG_SNTP_RETRANSMIT, "SIPCC-SNTP: Waiting %d msec to retransmit\n");
+dcl_str(DEBUG_SNTP_UNICAST_MODE, "SIPCC-SNTP: Unicast mode [%s]\n");
+dcl_str(DEBUG_SNTP_MULTICAST_MODE, "SIPCC-SNTP: Multicast/Directed broadcast mode [%s]\n");
+dcl_str(DEBUG_SNTP_ANYCAST_MODE, "SIPCC-SNTP: Anycast mode [%s]\n");
+dcl_str(DEBUG_SNTP_VALIDATION, "SIPCC-SNTP: Dropping unauthorized SNTP response: %s\n");
+dcl_str(DEBUG_SNTP_VALIDATION_PACKET, "SIPCC-SNTP: Semantic check failed for NTP packet\n");
+dcl_str(DEBUG_SNTP_WRONG_SERVER, "SIPCC-SNTP: Unauthorized server");
+dcl_str(DEBUG_SNTP_NO_REQUEST, "SIPCC-SNTP: No request sent");
+dcl_str(DEBUG_SNTP_ANYCAST_RESET, "SIPCC-SNTP: Reset to Unicast to server: %s\n");
+dcl_str(DEBUG_SOCKET_UDP_RTP, "SIPCC-SOC_TASK: UDP_RTP event received.\n");
+dcl_str(DEBUG_MAC_PRINT, "SIPCC-MAC_PRINT: %04x:%04x:%04x");
+dcl_str(DEBUG_IP_PRINT, "SIPCC-IP_PRINT: %u.%u.%u.%u");
+dcl_str(DEBUG_SYSBUF_UNAVAILABLE, "SIPCC-SYS_BUF: %s: Error: IRXLstGet() failed\n");
+dcl_str(DEBUG_MSG_BUFFER_TOO_BIG, "SIPCC-MSG_BUF: %s: Error: Args Check: message buffer length (%d) too big.\n");
+dcl_str(DEBUG_UNKNOWN_TIMER_BLOCK, "SIPCC-TIMER: %s: Error: Unknown timer block\n");
+dcl_str(DEBUG_CREDENTIALS_BAG_CORRUPTED, "SIPCC-CRED: %-35s: Error: credentials bags corrupted");
+dcl_str(DEBUG_INPUT_NULL, "SIPCC-INPUT: %s: Error: Input is null\n");
+dcl_str(DEBUG_INPUT_EMPTY, "SIPCC-INPUT: %s: Error: Input is empty\n");
+dcl_str(DEBUG_STRING_DUP_FAILED, "SIPCC-STR_DUP: %s: Unable to duplicate string.\n");
+dcl_str(DEBUG_PARSER_STRING_TOO_LARGE, "SIPCC-PARSE: Parse error: string too big (%d,%d)\n");
+dcl_str(DEBUG_PARSER_NULL_KEY_TABLE, "SIPCC-PARSE: Parse error: NULL key table passed into parser\n");
+dcl_str(DEBUG_PARSER_UNKNOWN_KEY, "SIPCC-PARSE: Parse error: Unknown key name: %s\n");
+dcl_str(DEBUG_PARSER_UNKNOWN_KEY_ENUM, "SIPCC-PARSE: Print error: Unknown key enum: %d\n");
+dcl_str(DEBUG_PARSER_INVALID_START_VAR, "SIPCC-PARSE: Parse error: Invalid start variable ch=0x%02x(%c)\n");
+dcl_str(DEBUG_PARSER_INVALID_VAR_CHAR, "SIPCC-PARSE: Parse error: Invalid variable ch=0x%02x(%c)\n");
+dcl_str(DEBUG_PARSER_MISSING_COLON, "SIPCC-PARSE: Parse error: Missing colon separator\n");
+dcl_str(DEBUG_PARSER_NO_VALUE, "SIPCC-PARSE: Parse error: no value for variable\n");
+dcl_str(DEBUG_PARSER_EARLY_EOL, "SIPCC-PARSE: Parse error: early EOL for value\n");
+dcl_str(DEBUG_PARSER_INVALID_VAR_NAME, "SIPCC-PARSE: Parse error: parse_var_name failed: %d\n");
+dcl_str(DEBUG_PARSER_INVALID_VAR_VALUE, "SIPCC-PARSE: Parse error: var: %s parse_var_value failed: %d\n");
+dcl_str(DEBUG_PARSER_UNKNOWN_VAR, "SIPCC-PARSE: Parse error: var: %s not found in table\n");
+dcl_str(DEBUG_PARSER_NAME_VALUE, "SIPCC-PARSE: Name: [%s] Value: [%s]\n");
+dcl_str(DEBUG_PARSER_UNKNOWN_NAME_VALUE, "SIPCC-PARSE: Parse error: Name: [%s] Value: [%s] rc:%d\n");
+dcl_str(DEBUG_PARSER_UNKNOWN_ERROR, "SIPCC-PARSE: Default error: Name: [%s] Value: [%s] rc:%d\n");
+dcl_str(DEBUG_PARSER_NUM_ERRORS, "SIPCC-PARSE: Parse error: %d Errors found\n");
+dcl_str(DEBUG_PARSER_SET_DEFAULT, "SIPCC-PARSE: Parser Info: Setting var: %s to default value: %s\n\n");
+dcl_str(DEBUG_SDP_ERROR_BODY_FIELD, "SIPCC-SDP: \n%s: Error in one of the SDP body fields \n");
+dcl_str(DEBUG_UDP_OPEN_FAIL, "SIPCC-UDP: %s: UdpOpen(R IP=%d, R Port=%d, L Port=%d) failed\n");
+dcl_str(DEBUG_UDP_PAYLOAD_TOO_LARGE, "SIPCC-UDP: %s: Error: payload size=<%d> > allowed size=<%d>\n");
+dcl_str(DEBUG_RTP_TRANSPORT, "SIPCC-RTP: %s: transport= %d\n");
+dcl_str(DEBUG_RTP_INVALID_VOIP_TYPE, "SIPCC-RTP: %s: Error: Unexpected voipCodec_t type: <%d>\n");
+dcl_str(DEBUG_RTP_INVALID_RTP_TYPE, "SIPCC-RTP: %s: Error: Unexpected rtp_ptype in SDP body: <%d>\n");
+dcl_str(DEBUG_MEMORY_ALLOC, "SIPCC-MEM: Malloc Addr:0x%lx, Size:%d\n");
+dcl_str(DEBUG_MEMORY_FREE, "SIPCC-MEM: Free Addr:0x%lx, Size:%d\n");
+dcl_str(DEBUG_MEMORY_MALLOC_ERROR, "SIPCC-MEM: 0x%lx:Malloc error for size %d\n");
+dcl_str(DEBUG_MEMORY_REALLOC_ERROR, "SIPCC-MEM: %s: Error: malloc_tagged() returned null.\n");
+dcl_str(DEBUG_MEMORY_OUT_OF_MEM, "SIPCC-MEM: %s: Error: malloc failed\n");
+dcl_str(DEBUG_MEMORY_ENTRY, "SIPCC-MEM: >> Used: %1d size: %6d addr:0x%08x\n");
+dcl_str(DEBUG_MEMORY_SUMMARY, "===== MEMORY MAP START =====\n"
+ "free blocks : %6d, free block space:%6d, largest free block: %6d\n"
+ "used blocks : %6d, used block space:%6d, largest used block: %6d\n"
+ "wasted block: %6d, str_lib space :%6d\n"
+ "used space excluding str_lib space :%6d\n \n"
+ "===== MEMORY MAP END =====\n");
+dcl_str(DEBUG_MEMORY_ADDRESS_HEADER, "SIPCC-MEM: 0x%08x: ");
+dcl_str(DEBUG_MEMORY_DUMP, "SIPCC-MEM: DUMP: 0x%08x - 0x%08x\n");
+dcl_str(DEBUG_DNS_GETHOSTBYNAME, "SIPCC-DNS: gethostbyname('%s',%08x,%d,%d)\n");
+dcl_str(DEBUG_PMH_INCORRECT_SYNTAX, "SIPCC-PMH: INCORRECT SYNTAX");
+dcl_str(DEBUG_PMH_INVALID_FIELD_VALUE, "SIPCC-PMH: INVALID FIELD VALUE");
+dcl_str(DEBUG_PMH_INVALID_SCHEME, "SIPCC-PMH: INVALID SCHEME");
+dcl_str(DEBUG_PMH_UNKNOWN_SCHEME, "SIPCC-PMH: UNKNOWN SCHEME");
+dcl_str(DEBUG_PMH_NOT_ENOUGH_PARAMETERS, "SIPCC-PMH: NOT ENOUGH PARAMETERS");
+dcl_str(DEBUG_REG_DISABLED, "SIPCC-REG: LINE %d/%d: %-35s: registration disabled\n");
+dcl_str(DEBUG_REG_PROXY_EXPIRES, "SIPCC-REG: LINE %d/%d: %-35s: Using proxy expires value\n");
+dcl_str(DEBUG_REG_SIP_DATE, "SIPCC-REG: LINE %d/%d: %-35s: SIP-date= %s\n");
+dcl_str(DEBUG_REG_SIP_RESP_CODE, "SIPCC-REG: LINE %d/%d: %-35s: Error: SIP response code\n");
+dcl_str(DEBUG_REG_SIP_RESP_FAILURE, "SIPCC-REG: LINE %d/%d: %-35s: SIP failure %d resp\n");
+dcl_str(DEBUG_REG_INVALID_LINE, "SIPCC-REG: %-35s: Line %d: Invalid line\n");
+dcl_str(CC_NO_MSG_BUFFER, "SIPCC-MSG_BUF: %s : no msg buffer available\n");
+dcl_str(CC_SEND_FAILURE, "SIPCC-MSG_SEND: %s : unable to send msg\n");
+dcl_str(GSM_UNDEFINED, "SIPCC-GSM: UNDEFINED");
+dcl_str(GSM_DBG_PTR, "SIPCC-GSM_DBG_PTR: %s %-4d: %-35s: %s= %p\n");
+dcl_str(GSM_FUNC_ENTER, "SIPCC-GSM_FUNC_ENT: %s %-4d: %-35s\n");
+dcl_str(GSM_DBG1, "SIPCC-GSM: %s %-4d: %-35s: %s\n");
+dcl_str(FSM_DBG_SM_DEFAULT_EVENT, "SIPCC-FSM: default - ignoring.\n");
+dcl_str(FSM_DBG_SM_FTR_ENTRY, "SIPCC-FSM: feature= %s, src= %s\n");
+dcl_str(FSM_DBG_FAC_ERR, "SIPCC-FSM_FAC_ERR: %-4d: %-35s:\n %s, rc= %s\n");
+dcl_str(FSM_DBG_FAC_FOUND, "SIPCC-FSM: %-4d: %-35s: facility found(%d)\n");
+dcl_str(FSM_DBG_IGNORE_FTR, "SIPCC-FSM: %s %-4d: %8d: ignoring feature= %s\n");
+dcl_str(FSM_DBG_IGNORE_SRC, "SIPCC-FSM: %s %-4d: %8d: ignoring src= %s\n");
+dcl_str(FSM_DBG_CHANGE_STATE, "SIPCC-FSM: %s %-4d: %8d: %s -> %s\n");
+dcl_str(FSM_DBG_SDP_BUILD_ERR, "SIPCC-FSM: Unable to build SDP. \n");
+dcl_str(FSMDEF_DBG_PTR, "SIPCC-FSM: DEF %-4d/%d: %-35s: dcb= %p\n");
+dcl_str(FSMDEF_DBG1, "SIPCC-FSM: DEF %-4d/%d: %-35s: %s\n");
+dcl_str(FSMDEF_DBG2, "SIPCC-FSM: DEF %-4d/%d: %-35s: %s %d\n");
+dcl_str(FSMDEF_DBG_SDP, "SIPCC-FSM: DEF %-4d/%d: %-35s: addr= %s, port= %d,\n media_type(s)=");
+dcl_str(FSMDEF_DBG_CLR_SPOOF_APPLD, "SIPCC-FSM: DEF %-4d/%d: %-35s: clearing spoof_ringout_applied.\n");
+dcl_str(FSMDEF_DBG_CLR_SPOOF_RQSTD, "SIPCC-FSM: DEF %-4d/%d: %-35s: clearing spoof_ringout_requested.\n");
+dcl_str(FSMDEF_DBG_INVALID_DCB, "SIPCC-FSM: DEF 0 : %-35s: invalid dcb\n");
+dcl_str(FSMDEF_DBG_FTR_REQ_ACT, "SIPCC-FSM: DEF %-4d/%d: feature requested %s but %s is active.\n");
+dcl_str(FSMDEF_DBG_TMR_CREATE_FAILED, "SIPCC-FSM: DEF %-4d/%d: %-35s: %s:\n cprCreateTimer failed.\n");
+dcl_str(FSMDEF_DBG_TMR_START_FAILED, "SIPCC-FSM: DEF %-4d/%d: %-35s: %s:\n cprStartTimer failed, errno= %d.\n");
+dcl_str(FSMDEF_DBG_TMR_CANCEL_FAILED, "SIPCC-FSM: DEF %-4d/%d: %-35s: %s:\n cprCancelTimer failed, errno= %d.\n");
+dcl_str(FSMXFR_DBG_XFR_INITIATED, "SIPCC-FSM: XFR %-4d/%d/%d: %8d: xfer initiated\n");
+dcl_str(FSMXFR_DBG_PTR, "SIPCC-FSM: XFR %-4d/%d/%d: %-35s: xcb= %p\n");
+dcl_str(FSMCNF_DBG_CNF_INITIATED, "SIPCC-FSM: CNF %-4d/%d/%d: %8d: conf initiated\n");
+dcl_str(FSMCNF_DBG_PTR, "SIPCC-FSM: CNF %-4d/%d/%d: %-35s: ncb= %p\n");
+dcl_str(FSMB2BCNF_DBG_CNF_INITIATED, "SIPCC-FSM: B2BCNF %-4d/%d/%d: %8d: b2bconf initiated\n");
+dcl_str(FSMB2BCNF_DBG_PTR, "SIPCC-FSM: B2BCNF %-4d/%d/%d: %-35s: ncb= %p\n");
+dcl_str(FSMSHR_DBG_BARGE_INITIATED, "SIPCC-FSM: SHR %-4d/%d/%d: %8d: Barge initiated\n");
+dcl_str(LSM_DBG_ENTRY, "SIPCC-LSM: %-4d/%d: %-35s\n");
+dcl_str(LSM_DBG_INT1, "SIPCC-LSM: %-4d/%d: %-35s: %s= %d\n");
+dcl_str(LSM_DBG_CC_ERROR, "SIPCC-LSM: %-4d/%d: %-35s: (%d:%p) failure\n");
+dcl_str(VCM_DEBUG_ENTRY, "SIPCC-VCM: %-4d: %-35s\n");
+dcl_str(SM_PROCESS_EVENT_ERROR, "SIPCC-SM: %s: Error: sip_sm_process_event() returned error processing %d\n");
+dcl_str(REG_SM_PROCESS_EVENT_ERROR, "SIPCC-SM: %s: Error: sip_reg_sm_process_event() returned error processing %d\n");
+dcl_str(DEBUG_END, "SIPCC-END: \0");
+
+/*
+ * Debug string table NOT subject to localization
+ */
+debug_string_table_entry debug_string_table [] = {
+ {0}, // DEBUG_START
+ {use_str(DEBUG_SEPARATOR_BAR)}, // DEBUG_SEPARATOR_BAR
+ {use_str(DEBUG_CONSOLE_PASSWORD)}, // DEBUG_CONSOLE_PASSWORD
+ {use_str(DEBUG_CONSOLE_KEYWORD_CONSOLE_STALL)}, // DEBUG_CONSOLE_KEYWORD_CONSOLE_STALL
+ {use_str(DEBUG_CONSOLE_KEYWORD_MEMORYMAP)}, // DEBUG_CONSOLE_KEYWORD_MEMORYMAP
+ {use_str(DEBUG_CONSOLE_KEYWORD_MALLOCTABLE)}, // DEBUG_CONSOLE_KEYWORD_MALLOCTABLE
+ {use_str(DEBUG_CONSOLE_KEYWORD_MEMORYDUMP)}, // DEBUG_CONSOLE_KEYWORD_MEMORYDUMP
+ {use_str(DEBUG_CONSOLE_KEYWORD_DNS)}, // DEBUG_CONSOLE_KEYWORD_DNS
+ {use_str(DEBUG_CONSOLE_KEYWORD_DSPSTATE)}, // DEBUG_CONSOLE_KEYWORD_DSPSTATE
+ {use_str(DEBUG_CONSOLE_USAGE_MEMORYDUMP)}, // DEBUG_CONSOLE_USAGE_MEMORYDUMP
+ {use_str(DEBUG_CONSOLE_BREAK)}, // DEBUG_CONSOLE_BREAK
+ {use_str(DEBUG_FUNCTION_ENTRY)}, // DEBUG_FUNCTION_ENTRY
+ {use_str(DEBUG_FUNCTION_ENTRY2)}, // DEBUG_FUNCTION_ENTRY2
+ {use_str(DEBUG_SIP_ENTRY)}, // DEBUG_SIP_ENTRY
+ {use_str(DEBUG_SIP_URL_ERROR)}, // DEBUG_SIP_URL_ERROR
+ {use_str(DEBUG_LINE_NUMBER_INVALID)}, // DEBUG_LINE_NUMBER_INVALID
+ {use_str(DEBUG_SIP_SPI_SEND_ERROR)}, // DEBUG_SIP_SPI_SEND_ERROR
+ {use_str(DEBUG_SIP_SDP_CREATE_BUF_ERROR)}, // DEBUG_SIP_SDP_CREATE_BUF_ERROR
+ {use_str(DEBUG_SIP_PARSE_SDP_ERROR)}, // DEBUG_SIP_PARSE_SDP_ERROR
+ {use_str(DEBUG_SIP_FEATURE_UNSUPPORTED)}, // DEBUG_SIP_FEATURE_UNSUPPORTED
+ {use_str(DEBUG_SIP_DEST_SDP)}, // DEBUG_SIP_DEST_SDP
+ {use_str(DEBUG_SIP_MSG_SENDING_REQUEST)}, // DEBUG_SIP_MSG_SENDING_REQUEST
+ {use_str(DEBUG_SIP_MSG_SENDING_RESPONSE)}, // DEBUG_SIP_MSG_SENDING_RESPONSE
+ {use_str(DEBUG_SIP_MSG_RECV)}, // DEBUG_SIP_MSG_RECV
+ {use_str(DEBUG_SIP_STATE_UNCHANGED)}, // DEBUG_SIP_STATE_UNCHANGED
+ {use_str(DEBUG_SIP_FUNCTIONCALL_FAILED)}, // DEBUG_SIP_FUNCTIONCALL_FAILED
+ {use_str(DEBUG_SIP_BUILDFLAG_ERROR)}, // DEBUG_SIP_BUILDFLAG_ERROR
+ {use_str(DEBUG_GENERAL_FUNCTIONCALL_FAILED)}, // DEBUG_GENERAL_FUNCTIONCALL_FAILED
+ {use_str(DEBUG_GENERAL_SYSTEMCALL_FAILED)}, // DEBUG_GENERAL_SYSTEMCALL_FAILED
+ {use_str(DEBUG_GENERAL_FUNCTIONCALL_BADARGUMENT)}, // DEBUG_GENERAL_FUNCTIONCALL_BADARGUMENT
+ {use_str(DEBUG_FUNCTIONNAME_SIPPMH_PARSE_FROM)},// DEBUG_FUNCTIONNAME_SIP_PARSE_FROM
+ {use_str(DEBUG_FUNCTIONNAME_SIPPMH_PARSE_TO)}, // DEBUG_FUNCTIONNAME_SIP_PARSE_TO
+ {use_str(DEBUG_FUNCTIONNAME_SIP_SM_REQUEST_CHECK_AND_STORE)}, // DEBUG_FUNCTIONNAME_SIP_SM_REQUEST_CHECK_AND_STORE
+ {use_str(DEBUG_SNTP_LI_ERROR)}, // DEBUG_SNTP_LI_ERROR
+ {use_str(DEBUG_SNTP_MODE_ERROR)}, // DEBUG_SNTP_MODE_ERROR
+ {use_str(DEBUG_SNTP_STRATUM_ERROR)}, // DEBUG_SNTP_STRATUM_ERROR
+ {use_str(DEBUG_SNTP_TIMESTAMP_ERROR)}, // DEBUG_SNTP_TIMESTAMP_ERROR
+ {use_str(DEBUG_SNTP_TIMESTAMP1)}, // DEBUG_SNTP_TIMESTAMP1
+ {use_str(DEBUG_SNTP_TIMESTAMP2)}, // DEBUG_SNTP_TIMESTAMP2
+ {use_str(DEBUG_SNTP_TIME_UPDATE)}, // DEBUG_SNTP_TIME_UPDATE
+ {use_str(DEBUG_SNTP_TS_HEADER)}, // DEBUG_SNTP_TS_HEADER
+ {use_str(DEBUG_SNTP_TS_PRINT)}, // DEBUG_SNTP_TS_PRINT
+ {use_str(DEBUG_SNTP_SOCKET_REOPEN)}, // DEBUG_SNTP_SOCKET_REOPEN
+ {use_str(DEBUG_SNTP_DISABLED)}, // DEBUG_SNTP_DISABLED
+ {use_str(DEBUG_SNTP_REQUEST)}, // DEBUG_SNTP_REQUEST
+ {use_str(DEBUG_SNTP_RESPONSE)}, // DEBUG_SNTP_RESPONSE
+ {use_str(DEBUG_SNTP_RETRANSMIT)}, // DEBUG_SNTP_RETRANSMIT
+ {use_str(DEBUG_SNTP_UNICAST_MODE)}, // DEBUG_SNTP_UNICAST_MODE
+ {use_str(DEBUG_SNTP_MULTICAST_MODE)}, // DEBUG_SNTP_MULTICAST_MODE
+ {use_str(DEBUG_SNTP_ANYCAST_MODE)}, // DEBUG_SNTP_ANYCAST_MODE
+ {use_str(DEBUG_SNTP_VALIDATION)}, // DEBUG_SNTP_VALIDATION
+ {use_str(DEBUG_SNTP_VALIDATION_PACKET)}, // DEBUG_SNTP_VALIDATION_PACKET
+ {use_str(DEBUG_SNTP_WRONG_SERVER)}, // DEBUG_SNTP_WRONG_SERVER
+ {use_str(DEBUG_SNTP_NO_REQUEST)}, // DEBUG_SNTP_NO_REQUEST
+ {use_str(DEBUG_SNTP_ANYCAST_RESET)}, // DEBUG_SNTP_ANYCAST_RESET
+ {use_str(DEBUG_SOCKET_UDP_RTP)}, // DEBUG_SOCKET_UDP_RTP
+ {use_str(DEBUG_MAC_PRINT)}, // DEBUG_MAC_PRINT
+ {use_str(DEBUG_IP_PRINT)}, // DEBUG_IP_PRINT
+ {use_str(DEBUG_SYSBUF_UNAVAILABLE)}, // DEBUG_SYSBUF_UNAVAILABLE
+ {use_str(DEBUG_MSG_BUFFER_TOO_BIG)}, // DEBUG_MSG_BUFFER_TOO_BIG
+ {use_str(DEBUG_UNKNOWN_TIMER_BLOCK)}, // DEBUG_UNKNOWN_TIMER_BLOCK
+ {use_str(DEBUG_CREDENTIALS_BAG_CORRUPTED)}, // DEBUG_CREDENTIALS_BAG_CORRUPTED
+ {use_str(DEBUG_INPUT_NULL)}, // DEBUG_INPUT_NULL
+ {use_str(DEBUG_INPUT_EMPTY)}, // DEBUG_INPUT_EMPTY
+ {use_str(DEBUG_STRING_DUP_FAILED)}, // DEBUG_STRING_DUP_FAILED
+ {use_str(DEBUG_PARSER_STRING_TOO_LARGE)}, // DEBUG_PARSER_STRING_TOO_LARGE
+ {use_str(DEBUG_PARSER_NULL_KEY_TABLE)}, // DEBUG_PARSER_NULL_KEY_TABLE
+ {use_str(DEBUG_PARSER_UNKNOWN_KEY)}, // DEBUG_PARSER_UNKNOWN_KEY
+ {use_str(DEBUG_PARSER_UNKNOWN_KEY_ENUM)}, // DEBUG_PARSER_UNKNOWN_KEY_ENUM
+ {use_str(DEBUG_PARSER_INVALID_START_VAR)}, // DEBUG_PARSER_INVALID_START_VAR
+ {use_str(DEBUG_PARSER_INVALID_VAR_CHAR)}, // DEBUG_PARSER_INVALID_VAR_CHAR
+ {use_str(DEBUG_PARSER_MISSING_COLON)}, // DEBUG_PARSER_MISSING_COLON
+ {use_str(DEBUG_PARSER_NO_VALUE)}, // DEBUG_PARSER_NO_VALUE
+ {use_str(DEBUG_PARSER_EARLY_EOL)}, // DEBUG_PARSER_EARLY_EOL
+ {use_str(DEBUG_PARSER_INVALID_VAR_NAME)}, // DEBUG_PARSER_INVALID_VAR_NAME
+ {use_str(DEBUG_PARSER_INVALID_VAR_VALUE)}, // DEBUG_PARSER_INVALID_VAR_VALUE
+ {use_str(DEBUG_PARSER_UNKNOWN_VAR)}, // DEBUG_PARSER_UNKNOWN_VAR
+ {use_str(DEBUG_PARSER_NAME_VALUE)}, // DEBUG_PARSER_NAME_VALUE
+ {use_str(DEBUG_PARSER_UNKNOWN_NAME_VALUE)}, // DEBUG_PARSER_UNKNOWN_NAME_VALUE
+ {use_str(DEBUG_PARSER_UNKNOWN_ERROR)}, // DEBUG_PARSER_UNKNOWN_ERROR
+ {use_str(DEBUG_PARSER_NUM_ERRORS)}, // DEBUG_PARSER_NUM_ERRORS
+ {use_str(DEBUG_PARSER_SET_DEFAULT)}, // DEBUG_PARSER_SET_DEFAULT
+ {use_str(DEBUG_SDP_ERROR_BODY_FIELD)}, // DEBUG_SDP_ERROR_BODY_FIELD
+ {use_str(DEBUG_UDP_OPEN_FAIL)}, // DEBUG_UDP_OPEN_FAIL
+ {use_str(DEBUG_UDP_PAYLOAD_TOO_LARGE)}, // DEBUG_UDP_PAYLOAD_TOO_LARGE
+ {use_str(DEBUG_RTP_TRANSPORT)}, // DEBUG_RTP_TRANSPORT
+ {use_str(DEBUG_RTP_INVALID_VOIP_TYPE)}, // DEBUG_RTP_INVALID_VOIP_TYPE
+ {use_str(DEBUG_RTP_INVALID_RTP_TYPE)}, // DEBUG_RTP_INVALID_RTP_TYPE
+ {use_str(DEBUG_MEMORY_ALLOC)}, // DEBUG_MEMORY_ALLOC
+ {use_str(DEBUG_MEMORY_FREE)}, // DEBUG_MEMORY_FREE
+ {use_str(DEBUG_MEMORY_MALLOC_ERROR)}, // DEBUG_MEMORY_MALLOC_ERROR
+ {use_str(DEBUG_MEMORY_REALLOC_ERROR)}, // DEBUG_MEMORY_REALLOC_ERROR
+ {use_str(DEBUG_MEMORY_OUT_OF_MEM)}, // DEBUG_MEMORY_OUT_OF_MEM
+ {use_str(DEBUG_MEMORY_ENTRY)}, // DEBUG_MEMORY_ENTRY
+ {use_str(DEBUG_MEMORY_SUMMARY)}, // DEBUG_MEMORY_SUMMARY
+ {use_str(DEBUG_MEMORY_ADDRESS_HEADER)}, // DEBUG_MEMORY_ADDRESS_HEADER
+ {use_str(DEBUG_MEMORY_DUMP)}, // DEBUG_MEMORY_DUMP
+ {use_str(DEBUG_DNS_GETHOSTBYNAME)}, // DEBUG_DNS_GETHOSTBYNAME
+ {use_str(DEBUG_PMH_INCORRECT_SYNTAX)}, // DEBUG_PMH_INCORRECT_SYNTAX
+ {use_str(DEBUG_PMH_INVALID_FIELD_VALUE)}, // DEBUG_PMH_INVALID_FIELD_VALUE
+ {use_str(DEBUG_PMH_INVALID_SCHEME)}, // DEBUG_PMH_INVALID_SCHEME
+ {use_str(DEBUG_PMH_UNKNOWN_SCHEME)}, // DEBUG_PMH_UNKNOWN_SCHEME
+ {use_str(DEBUG_PMH_NOT_ENOUGH_PARAMETERS)}, // DEBUG_PMH_NOT_ENOUGH_PARAMETERS
+ {use_str(DEBUG_REG_DISABLED)}, // DEBUG_REG_DISABLED
+ {use_str(DEBUG_REG_PROXY_EXPIRES)}, // DEBUG_REG_PROXY_EXPIRES
+ {use_str(DEBUG_REG_SIP_DATE)}, // DEBUG_REG_SIP_DATE
+ {use_str(DEBUG_REG_SIP_RESP_CODE)}, // DEBUG_REG_SIP_RESP_CODE
+ {use_str(DEBUG_REG_SIP_RESP_FAILURE)}, // DEBUG_REG_SIP_RESP_FAILURE
+ {use_str(DEBUG_REG_INVALID_LINE)}, // DEBUG_REG_INVALID_LINE
+ {use_str(CC_NO_MSG_BUFFER)}, // CC_NO_MSG_BUFFER^M
+ {use_str(CC_SEND_FAILURE)}, // CC_SEND_FAILURE^M
+ {use_str(GSM_UNDEFINED)}, // GSM_UNDEFINED
+ {use_str(GSM_DBG_PTR)}, // GSM_DBG_PTR
+ {use_str(GSM_FUNC_ENTER)}, // GSM_FUNC_ENTER
+ {use_str(GSM_DBG1)}, // GSM_DBG1
+ {use_str(FSM_DBG_SM_DEFAULT_EVENT)}, // FSM_DBG_SM_DEFAULT_EVENT
+ {use_str(FSM_DBG_SM_FTR_ENTRY)}, // FSM_DBG_SM_FTR_ENTRY
+ {use_str(FSM_DBG_FAC_ERR)}, // FSM_DBG_FAC_ERR
+ {use_str(FSM_DBG_FAC_FOUND)}, // FSM_DBG_FAC_FOUND
+ {use_str(FSM_DBG_IGNORE_FTR)}, // FSM_DBG_IGNORE_FTR
+ {use_str(FSM_DBG_IGNORE_SRC)}, // FSM_DBG_IGNORE_SRC
+ {use_str(FSM_DBG_CHANGE_STATE)}, // FSM_DBG_CHANGE_STATE
+ {use_str(FSM_DBG_SDP_BUILD_ERR)}, // FSM_DBG_SDP_BUILD_ERR
+ {use_str(FSMDEF_DBG_PTR)}, // FSMDEF_DBG_PTR
+ {use_str(FSMDEF_DBG1)}, // FSMDEF_DBG1
+ {use_str(FSMDEF_DBG2)}, // FSMDEF_DBG2
+ {use_str(FSMDEF_DBG_SDP)}, // FSMDEF_DBG_SDP
+ {use_str(FSMDEF_DBG_CLR_SPOOF_APPLD)}, // FSMDEF_DBG_CLEAR_SPOOF
+ {use_str(FSMDEF_DBG_CLR_SPOOF_RQSTD)}, // FSMDEF_DBG_CLEAR_SPOOF
+ {use_str(FSMDEF_DBG_INVALID_DCB)}, // FSMDEF_DBG_INVALID_DCB
+ {use_str(FSMDEF_DBG_FTR_REQ_ACT)}, // FSMDEF_DBG_FTR_REQ_ACT
+ {use_str(FSMDEF_DBG_TMR_CREATE_FAILED)}, // FSMDEF_DBG_TMR_CREATE_FAILED
+ {use_str(FSMDEF_DBG_TMR_START_FAILED)}, // FSMDEF_DBG_TMR_START_FAILED
+ {use_str(FSMDEF_DBG_TMR_CANCEL_FAILED)}, // FSMDEF_DBG_TMR_CANCEL_FAILED
+ {use_str(FSMXFR_DBG_XFR_INITIATED)}, // FSMXFR_DBG_XFR_INITIATED
+ {use_str(FSMXFR_DBG_PTR)}, // FSMXFR_DBG_PTR
+ {use_str(FSMCNF_DBG_CNF_INITIATED)}, // FSMCNF_DBG_CNF_INITIATED
+ {use_str(FSMCNF_DBG_PTR)}, // FSMCNF_DBG_PTR
+ {use_str(FSMB2BCNF_DBG_CNF_INITIATED)}, // FSMB2BCNF_DBG_CNF_INITIATED
+ {use_str(FSMB2BCNF_DBG_PTR)}, // FSMB2BCNF_DBG_PTR
+ {use_str(FSMSHR_DBG_BARGE_INITIATED)}, // FSMSHR_DBG_BARGE_INITIATED
+ {use_str(LSM_DBG_ENTRY)}, // LSM_DBG_ENTRY
+ {use_str(LSM_DBG_INT1)}, // LSM_DBG_INT1
+ {use_str(LSM_DBG_CC_ERROR)}, // LSM_DBG_CC_ERROR
+ {use_str(VCM_DEBUG_ENTRY)}, // VCM_DEBUG_ENTRY
+ {use_str(SM_PROCESS_EVENT_ERROR)}, // SM_PROCESS_EVENT_ERROR
+ {use_str(REG_SM_PROCESS_EVENT_ERROR)}, // REG_SM_PROCESS_EVENT_ERROR
+ {0},
+};
+
+
+
+//************************************************************************
+
+/*
+ * Phrase string table subject to localization
+ */
+tnp_phrase_index_str_table_entry tnp_phrase_index_str_table [] = {
+ {"\0"}, // LOCALE_START
+ {"\x80\x13"}, // IDLE_PROMPT sccp 119
+ {"Anonymous"}, // ANONYMOUS - used for messaging; keep English
+ {"\x80\x1e"}, // CALL_PROCEEDING_IN
+ {"\x80\x1e"}, // CALL_PROCEEDING_OUT
+ {"\x80\x16"}, // CALL_ALERTING sccp 122
+ {"\x80\x1b"}, // CALL_ALERTING_SECONDARY sccp 127
+ {"\x80\x16"}, // CALL_ALERTING_LOCAL
+ {"\x80\x18"}, // CALL_CONNECTED sccp 124
+ {"\x80\x03"}, // CALL_INITIATE_HOLD sccp 103 or phone 786?
+ {"\x80\x20"}, // PROMPT_DIAL sccp 132
+ {"\x80\x19"}, // LINE_BUSY sccp 125
+ {"\x80\x1b"}, // CALL_WAITING
+ {"\x80\x52"}, // TRANSFER_FAILED sccp 182
+ {"\x80\x26"}, // Cannot complete the b2b conf
+ {"\x80\x34"}, // UI_CONFERENCE
+ {"\x80\x38"}, // UI_UNKNOWN
+ {"\x80\x1f"}, // REMOTE_IN_USE
+ {"\x80\x55"}, // NUM_NOT_CONFIGURED
+ {"\x80\x17"}, // UI_FROM
+ {"\x80\x29"}, // INVALID_CONF_PARTICIPANT
+ {"\x80\x36"}, // UI_PRIVATE
+ {"\0"} // LOCALE_END
+};
diff --git a/libs/sipcc/core/common/text_strings.h b/libs/sipcc/core/common/text_strings.h
new file mode 100755
index 0000000000..0502a38e05
--- /dev/null
+++ b/libs/sipcc/core/common/text_strings.h
@@ -0,0 +1,302 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef TEXT_STRINGS_H
+#define TEXT_STRINGS_H
+
+#include "cpr_types.h"
+#include "phone_types.h"
+#include "string_lib.h"
+
+
+#define DEF_NOTIFY_PRI 20
+#define HR_NOTIFY_PRI 1
+
+/*
+ * Define hard coded Anonymous string to be used in From header
+ * when call id blocking is enabled. This is also used to
+ * compare to when anonymous call block is enabled. We can
+ * can not use the localized version of Anonymous for these
+ * actions.
+ */
+#define SIP_HEADER_ANONYMOUS_STR "Anonymous"
+
+/*
+ * Define special strings that are not localized to be used for
+ * comparing special display names whether the names are special
+ * and not to display the number associated with the name.
+ */
+#define CONFERENCE_STR "conference"
+#define CONFERENCE_STR_LEN (sizeof(CONFERENCE_STR)-1)
+#define CONFERENCE_LOCALE_CODE 964
+/*
+ * Constants for dictionary index
+ */
+
+// Hardcoding phrases that need to be dropped on floor for RT to 1
+
+#define STR_INDEX_GRP_CALL_PICKUP 47
+#define STR_INDEX_LST_CALL_PICKUP 49
+#define STR_INDEX_FEAT_UNAVAIL 148
+#define STR_INDEX_CNFR_FAIL_NOCODEC 1054
+#define STR_INDEX_REORDER 1055
+#define STR_INDEX_ANONYMOUS_SPACE 1056
+#define STR_INDEX_NO_FREE_LINES 1057
+#define STR_INDEX_REGISTRATION_REJECTED 1058
+#define STR_INDEX_REGISTERING 1
+#define STR_INDEX_WHISPER 1
+#define STR_INDEX_PROXY_UNAVAIL 1
+#define STR_INDEX_CALL_REDIRECTED 1
+#define STR_INDEX_TRANSFERRING 1
+#define STR_INDEX_SESSION_PROGRESS 1
+#define STR_INDEX_CALLING 1
+#define STR_INDEX_USE_LINE_OR_JOIN_TO_COMPLETE 1
+#define STR_INDEX_CONF_LOCAL_MIXED 1
+#define STR_INDEX_NO_CALL_FOR_PICKUP 195
+
+#define STR_INDEX_CALL_FORWARD 105
+#define STR_INDEX_CALL_PICKUP 117
+#define STR_INDEX_NO_LINE_FOR_PICKUP 198
+
+
+#define STR_INDEX_ERROR_PASS_LIMIT 149
+#define STR_INDEX_TRANS_COMPLETE 918
+#define STR_INDEX_END_CALL 877
+#define STR_INDEX_NO_BAND_WIDTH 1158
+
+#define STR_INDEX_RESP_TIMEOUT 1160
+
+#define CALL_BUBBLE_STR_MAX_LEN 32
+
+#define STATUS_LINE_MAX_LEN 128
+
+/*
+ * Escape codes definitions
+ */
+#define OLD_CUCM_DICTIONARY_ESCAPE_TAG '\x80'
+#define NEW_CUCM_DICTIONARY_ESCAPE_TAG '\x1E'
+#define CALL_CONTROL_PHRASE_OFFSET '\x64' // offset 100
+#define MAX_LOCALE_PHRASE_LEN 256
+#define MAX_LOCALE_STRING_LEN 1024
+
+/*
+ * Escaped index string codes for Call Mgr dictionary phrases
+ */
+#define INDEX_STR_KEY_NOT_ACTIVE (char *) "\x80\x2D"
+#define INDEX_STR_BARGE (char *) "\x80\x43"
+#define INDEX_STR_PRIVATE (char *) "\x80\x36"
+#define INDEX_STR_HOLD_REVERSION (char *) "\x1E\x23"
+#define INDEX_STR_MONITORING (char *) "\x1E\x27"
+#define INDEX_STR_COACHING (char *) "\x1E\x46"
+
+
+/*
+ * Index value for phrase strings subject to localization
+ */
+enum PHRASE_STRINGS_ENUM {
+ LOCALE_START,
+ IDLE_PROMPT,
+ ANONYMOUS, /* fsmdef.o */
+ CALL_PROCEEDING_IN,
+ CALL_PROCEEDING_OUT,
+ CALL_ALERTING,
+ CALL_ALERTING_SECONDARY,
+ CALL_ALERTING_LOCAL,
+ CALL_CONNECTED,
+ CALL_INITIATE_HOLD,
+ PROMPT_DIAL,
+ LINE_BUSY,
+ CALL_WAITING,
+ TRANSFER_FAILED,
+ CONF_CANNOT_COMPLETE,
+ UI_CONFERENCE,
+ UI_UNKNOWN,
+ REMOTE_IN_USE,
+ NUM_NOT_CONFIGURED,
+ UI_FROM,
+ INVALID_CONF_PARTICIPANT,
+ UI_PRIVATE,
+ LOCALE_END
+};
+
+/*
+ * Index value for Debug strings NOT subject to localization
+ */
+enum DEBUG_STRINGS_ENUM {
+ DEBUG_START,
+ DEBUG_SEPARATOR_BAR,
+ DEBUG_CONSOLE_PASSWORD,
+ DEBUG_CONSOLE_KEYWORD_CONSOLE_STALL,
+ DEBUG_CONSOLE_KEYWORD_MEMORYMAP,
+ DEBUG_CONSOLE_KEYWORD_MALLOCTABLE,
+ DEBUG_CONSOLE_KEYWORD_MEMORYDUMP,
+ DEBUG_CONSOLE_KEYWORD_DNS,
+ DEBUG_CONSOLE_KEYWORD_DSPSTATE,
+ DEBUG_CONSOLE_USAGE_MEMORYDUMP,
+ DEBUG_CONSOLE_BREAK,
+
+ DEBUG_FUNCTION_ENTRY,
+ DEBUG_FUNCTION_ENTRY2,
+ DEBUG_SIP_ENTRY,
+ DEBUG_SIP_URL_ERROR,
+ DEBUG_LINE_NUMBER_INVALID,
+ DEBUG_SIP_SPI_SEND_ERROR,
+ DEBUG_SIP_SDP_CREATE_BUF_ERROR,
+ DEBUG_SIP_PARSE_SDP_ERROR,
+ DEBUG_SIP_FEATURE_UNSUPPORTED,
+ DEBUG_SIP_DEST_SDP,
+ DEBUG_SIP_MSG_SENDING_REQUEST,
+ DEBUG_SIP_MSG_SENDING_RESPONSE,
+ DEBUG_SIP_MSG_RECV,
+ DEBUG_SIP_STATE_UNCHANGED,
+ DEBUG_SIP_FUNCTIONCALL_FAILED,
+ DEBUG_SIP_BUILDFLAG_ERROR,
+ DEBUG_GENERAL_FUNCTIONCALL_FAILED,
+ DEBUG_GENERAL_SYSTEMCALL_FAILED,
+ DEBUG_GENERAL_FUNCTIONCALL_BADARGUMENT,
+ DEBUG_FUNCTIONNAME_SIPPMH_PARSE_FROM,
+ DEBUG_FUNCTIONNAME_SIPPMH_PARSE_TO,
+ DEBUG_FUNCTIONNAME_SIP_SM_REQUEST_CHECK_AND_STORE,
+
+ DEBUG_SNTP_LI_ERROR,
+ DEBUG_SNTP_MODE_ERROR,
+ DEBUG_SNTP_STRATUM_ERROR,
+ DEBUG_SNTP_TIMESTAMP_ERROR,
+ DEBUG_SNTP_TIMESTAMP1,
+ DEBUG_SNTP_TIMESTAMP2,
+ DEBUG_SNTP_TIME_UPDATE,
+ DEBUG_SNTP_TS_HEADER,
+ DEBUG_SNTP_TS_PRINT,
+ DEBUG_SNTP_SOCKET_REOPEN,
+ DEBUG_SNTP_DISABLED,
+ DEBUG_SNTP_REQUEST,
+ DEBUG_SNTP_RESPONSE,
+ DEBUG_SNTP_RETRANSMIT,
+ DEBUG_SNTP_UNICAST_MODE,
+ DEBUG_SNTP_MULTICAST_MODE,
+ DEBUG_SNTP_ANYCAST_MODE,
+ DEBUG_SNTP_VALIDATION,
+ DEBUG_SNTP_VALIDATION_PACKET,
+ DEBUG_SNTP_WRONG_SERVER,
+ DEBUG_SNTP_NO_REQUEST,
+ DEBUG_SNTP_ANYCAST_RESET,
+ DEBUG_SOCKET_UDP_RTP,
+ DEBUG_MAC_PRINT,
+ DEBUG_IP_PRINT,
+ DEBUG_SYSBUF_UNAVAILABLE,
+ DEBUG_MSG_BUFFER_TOO_BIG,
+ DEBUG_UNKNOWN_TIMER_BLOCK,
+ DEBUG_CREDENTIALS_BAG_CORRUPTED,
+ DEBUG_INPUT_EMPTY,
+ DEBUG_INPUT_NULL,
+ DEBUG_STRING_DUP_FAILED,
+ DEBUG_PARSER_STRING_TOO_LARGE,
+ DEBUG_PARSER_NULL_KEY_TABLE,
+ DEBUG_PARSER_UNKNOWN_KEY,
+ DEBUG_PARSER_UNKNOWN_KEY_ENUM,
+ DEBUG_PARSER_INVALID_START_VAR,
+ DEBUG_PARSER_INVALID_VAR_CHAR,
+ DEBUG_PARSER_MISSING_COLON,
+ DEBUG_PARSER_NO_VALUE,
+ DEBUG_PARSER_EARLY_EOL,
+ DEBUG_PARSER_INVALID_VAR_NAME,
+ DEBUG_PARSER_INVALID_VAR_VALUE,
+ DEBUG_PARSER_UNKNOWN_VAR,
+ DEBUG_PARSER_NAME_VALUE,
+ DEBUG_PARSER_UNKNOWN_NAME_VALUE,
+ DEBUG_PARSER_UNKNOWN_ERROR,
+ DEBUG_PARSER_NUM_ERRORS,
+ DEBUG_PARSER_SET_DEFAULT,
+ DEBUG_SDP_ERROR_BODY_FIELD,
+ DEBUG_UDP_OPEN_FAIL,
+ DEBUG_UDP_PAYLOAD_TOO_LARGE,
+ DEBUG_TCP_PAYLOAD_TOO_LARGE = DEBUG_UDP_PAYLOAD_TOO_LARGE,
+ DEBUG_RTP_TRANSPORT,
+ DEBUG_RTP_INVALID_VOIP_TYPE,
+ DEBUG_RTP_INVALID_RTP_TYPE,
+ DEBUG_MEMORY_ALLOC,
+ DEBUG_MEMORY_FREE,
+ DEBUG_MEMORY_MALLOC_ERROR,
+ DEBUG_MEMORY_REALLOC_ERROR,
+ DEBUG_MEMORY_OUT_OF_MEM,
+ DEBUG_MEMORY_ENTRY,
+ DEBUG_MEMORY_SUMMARY,
+ DEBUG_MEMORY_ADDRESS_HEADER,
+ DEBUG_MEMORY_DUMP,
+ DEBUG_DNS_GETHOSTBYNAME,
+ DEBUG_PMH_INCORRECT_SYNTAX,
+ DEBUG_PMH_INVALID_FIELD_VALUE,
+ DEBUG_PMH_INVALID_SCHEME,
+ DEBUG_PMH_UNKNOWN_SCHEME,
+ DEBUG_PMH_NOT_ENOUGH_PARAMETERS,
+ DEBUG_REG_DISABLED,
+ DEBUG_REG_PROXY_EXPIRES,
+ DEBUG_REG_SIP_DATE,
+ DEBUG_REG_SIP_RESP_CODE,
+ DEBUG_REG_SIP_RESP_FAILURE,
+ DEBUG_REG_INVALID_LINE,
+ CC_NO_MSG_BUFFER,
+ CC_SEND_FAILURE,
+ GSM_UNDEFINED,
+ GSM_DBG_PTR,
+ GSM_FUNC_ENTER,
+ GSM_DBG1,
+ FSM_DBG_SM_DEFAULT_EVENT,
+ FSM_DBG_SM_FTR_ENTRY,
+ FSM_DBG_FAC_ERR,
+ FSM_DBG_FAC_FOUND,
+ FSM_DBG_IGNORE_FTR,
+ FSM_DBG_IGNORE_SRC,
+ FSM_DBG_CHANGE_STATE,
+ FSM_DBG_SDP_BUILD_ERR,
+ FSMDEF_DBG_PTR,
+ FSMDEF_DBG1,
+ FSMDEF_DBG2,
+ FSMDEF_DBG_SDP,
+ FSMDEF_DBG_CLR_SPOOF_APPLD,
+ FSMDEF_DBG_CLR_SPOOF_RQSTD,
+ FSMDEF_DBG_INVALID_DCB,
+ FSMDEF_DBG_FTR_REQ_ACT,
+ FSMDEF_DBG_TMR_CREATE_FAILED,
+ FSMDEF_DBG_TMR_START_FAILED,
+ FSMDEF_DBG_TMR_CANCEL_FAILED,
+ FSMXFR_DBG_XFR_INITIATED,
+ FSMXFR_DBG_PTR,
+ FSMCNF_DBG_CNF_INITIATED,
+ FSMCNF_DBG_PTR,
+ FSMB2BCNF_DBG_CNF_INITIATED,
+ FSMB2BCNF_DBG_PTR,
+ FSMSHR_DBG_BARGE_INITIATED,
+ LSM_DBG_ENTRY,
+ LSM_DBG_INT1,
+ LSM_DBG_CC_ERROR,
+ VCM_DEBUG_ENTRY,
+ SM_PROCESS_EVENT_ERROR,
+ REG_SM_PROCESS_EVENT_ERROR,
+ DEBUG_END
+};
+
+
+typedef struct {
+ const char *text;
+} debug_string_table_entry;
+
+extern debug_string_table_entry debug_string_table[];
+
+#define get_debug_string(index) ((char*)debug_string_table[(index)].text)
+
+
+
+typedef struct {
+ const char *index_str;
+} tnp_phrase_index_str_table_entry;
+
+
+extern tnp_phrase_index_str_table_entry tnp_phrase_index_str_table[];
+
+#define platform_get_phrase_index_str(index) ((char*)tnp_phrase_index_str_table[(index)].index_str)
+#define get_info_string(index) "NotImplemented"
+
+
+#endif
diff --git a/libs/sipcc/core/common/ui.c b/libs/sipcc/core/common/ui.c
new file mode 100755
index 0000000000..750a43539d
--- /dev/null
+++ b/libs/sipcc/core/common/ui.c
@@ -0,0 +1,1666 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/** @file tnp_ui.c
+ * API provided by Platform to the Call Control for User Interface activities
+ */
+
+#include "cpr.h"
+#include "cpr_in.h"
+#include "phone.h"
+#include "time2.h"
+#include "debug.h"
+#include "phone_debug.h"
+#include "dialplan.h"
+#include "ccapi.h"
+#include "cfgfile_utils.h"
+#include "prot_configmgr.h"
+#include "dns_utils.h"
+#include "uiapi.h"
+#include "lsm.h"
+#include "fsm.h"
+#include "CCProvider.h"
+#include "ccSession.h"
+#include "platform_api.h"
+#include "vcm.h"
+#include "ccapp_task.h"
+
+/*
+ * Note: Do not include "msprovider.h" here unless the dependencies on
+ * /vob/ip_phone/ip_g4/infra have been removed, as those dependencies
+ * break CSF builds.
+ */
+
+/*--------------------------------------------------------------------------
+ * Local definitions
+ *--------------------------------------------------------------------------
+ */
+#define CCAPP_F_PREFIX "CCAPP : %s : " // requires 1 arg: __FUNCTION__
+// Why don't we modify strlib_malloc to handle NULL?
+#define STRLIB_CREATE(str) (str)?strlib_malloc((str), strlen((str))):strlib_empty()
+// Define default display timeout and priority
+#define DEFAULT_DISPLAY_NOTIFY_TIMEOUT 0
+#define DEFAULT_DISPLAY_NOTIFY_PRIORITY 0
+
+
+/*--------------------------------------------------------------------------
+ * Global data
+ *--------------------------------------------------------------------------
+ */
+
+/*--------------------------------------------------------------------------
+ * External data references
+ * -------------------------------------------------------------------------
+ */
+
+
+/*--------------------------------------------------------------------------
+ * External function prototypes
+ *--------------------------------------------------------------------------
+ */
+
+extern int Basic_Get_Line_By_Name(char *name);
+extern char *Basic_is_phone_forwarded(line_t line);
+extern void dp_int_dial_immediate(line_t line, callid_t call_id,
+ boolean collect_more, char *digit_str,
+ char *g_call_id,
+ monitor_mode_t monitor_mode);
+extern void dp_int_init_dialing_data(line_t line, callid_t call_id);
+extern callid_t dp_get_dialing_call_id(void);
+extern void dp_int_update_key_string(line_t line, callid_t call_id,
+ char *digits);
+extern void platform_set_time(int32_t gmt_time);
+extern session_id_t createSessionId(line_t line, callid_t call);
+// XXX need to either make msprovider.h platform-independent and include that file instead,
+// or move ui_keypad_button out of this file (ccmedia.c, perhaps?)
+
+/*--------------------------------------------------------------------------
+ * Local scope function prototypes
+ *--------------------------------------------------------------------------
+ */
+
+/**
+ * wrapper to post Call State change to CCAPP
+ *
+ * @param event - new state change event
+ * @param nLine - line identifier for which call state change
+ * @param nCallID - call identifier
+ *
+ *
+ * @return none (Side effect: Call bubble changes accordingly)
+ *
+ */
+void
+ui_call_state (call_events event, line_t nLine, callid_t nCallID, cc_causes_t cause)
+{
+ session_update_t msg;
+
+ TNP_DEBUG(DEB_L_C_F_PREFIX"event=%d \n", DEB_L_C_F_PREFIX_ARGS(UI_API, nLine, nCallID, __FUNCTION__),
+ event);
+
+ if (nCallID == CC_NO_CALL_ID) {
+ /* no operation when no call ID */
+ return;
+ }
+
+ msg.sessionID = createSessionId(nLine, nCallID);
+ msg.eventID = CALL_STATE;
+ msg.update.ccSessionUpd.data.state_data.state = event;
+ msg.update.ccSessionUpd.data.state_data.line_id = nLine;
+ msg.update.ccSessionUpd.data.state_data.cause = cause;
+
+ if ( ccappTaskPostMsg(CCAPP_SESSION_UPDATE, &msg, sizeof(session_update_t), CCAPP_CCPROVIER) != CPR_SUCCESS ) {
+ CCAPP_ERROR(CCAPP_F_PREFIX"failed to send CALL_STATE(%d) msg \n", __FUNCTION__, event);
+ }
+}
+
+/**
+ * wrapper to post presentation for new call to CCAPP
+ * Function: ui_new_call
+ *
+ * @param nLine line identifier
+ * @param nCallID - call identifier
+ * @param call_attr - call attribute(normal, transfer consult, conf consult)
+ * @param call_instance_id - call instance identifier
+ *
+ * @return none
+ */
+void
+ui_new_call (call_events event, line_t nLine, callid_t nCallID,
+ int call_attr, uint16_t call_instance_id, boolean dialed_digits)
+{
+ session_update_t msg;
+
+ TNP_DEBUG(DEB_L_C_F_PREFIX"state=%d attr=%d call_instance=%d, dialed_digits=%s\n",
+ DEB_L_C_F_PREFIX_ARGS(UI_API, nLine, nCallID, __FUNCTION__), event, call_attr, call_instance_id, (dialed_digits)? "true" : "false");
+
+ if (nCallID == CC_NO_CALL_ID) {
+ /* no operation when no call ID */
+ return;
+ }
+
+ msg.sessionID= createSessionId(nLine, nCallID);
+
+ msg.eventID = CALL_NEWCALL;
+ msg.update.ccSessionUpd.data.state_data.state = event;
+ msg.update.ccSessionUpd.data.state_data.attr = call_attr;
+ msg.update.ccSessionUpd.data.state_data.inst = call_instance_id;
+ msg.update.ccSessionUpd.data.state_data.line_id = nLine;
+
+ if ( ccappTaskPostMsg(CCAPP_SESSION_UPDATE, &msg, sizeof(session_update_t), CCAPP_CCPROVIER) != CPR_SUCCESS ) {
+ CCAPP_ERROR(CCAPP_F_PREFIX"failed to send CALL_STATE(%d) msg \n", __FUNCTION__, event);
+ }
+
+ return;
+}
+
+/**
+ * set or change the attribute on the call and reflect the changes
+ * to call plane (such as change in softkeys or other visual aspects).
+ * used to change the call attribute back to normal from consult
+ *
+ * Posts the update to CCAPP
+ *
+ * @param line_id - line identifier
+ * @param call_id - call identifier
+ * @param attr - call attribute has to be one of call_attr_t
+ *
+ * @return none
+ */
+void
+ui_set_call_attr (line_t line_id, callid_t call_id, call_attr_t attr)
+{
+ session_update_t msg;
+
+ TNP_DEBUG(DEB_L_C_F_PREFIX"attr=%d\n", DEB_L_C_F_PREFIX_ARGS(UI_API, line_id, call_id, __FUNCTION__), attr);
+
+ if (call_id == CC_NO_CALL_ID) {
+ /* no operation when no call ID */
+ return;
+ }
+
+ msg.sessionID = createSessionId(line_id, call_id);
+ msg.eventID = CALL_ATTR;
+ msg.update.ccSessionUpd.data.state_data.attr = attr;
+
+ if ( ccappTaskPostMsg(CCAPP_SESSION_UPDATE, &msg, sizeof(session_update_t), CCAPP_CCPROVIER) != CPR_SUCCESS ) {
+ CCAPP_ERROR(CCAPP_F_PREFIX"failed to send CALL_ATTR(%d) msg \n", __FUNCTION__, attr);
+ }
+}
+
+/**
+ * Wrapper for ui_update_callref
+ *
+ * @param line - line for the session
+ * @param call_id - callid for the session
+ * @param callref - callref for the session
+ *
+ * @return none
+ */
+void
+ui_update_callref (line_t line, callid_t call_id, unsigned int callref)
+{
+ session_update_t msg;
+
+ TNP_DEBUG(DEB_L_C_F_PREFIX"callref = %d\n", DEB_L_C_F_PREFIX_ARGS(UI_API, line, call_id, __FUNCTION__), callref);
+
+ if ( callref == 0 ) return;
+
+ if (call_id == CC_NO_CALL_ID) {
+ /* no operation when no call ID */
+ return;
+ }
+
+ msg.sessionID = createSessionId(line, call_id);
+ msg.eventID = CALL_CALLREF;
+ msg.update.ccSessionUpd.data.callref = callref;
+
+ if ( ccappTaskPostMsg(CCAPP_SESSION_UPDATE, &msg, sizeof(session_update_t), CCAPP_CCPROVIER) != CPR_SUCCESS ) {
+ CCAPP_ERROR(CCAPP_F_PREFIX"failed to send CALL_REF() msg \n", __FUNCTION__);
+ }
+
+ return;
+}
+
+
+/**
+ * Wrapper for ui_update_gcid - global_call_id
+ *
+ * @param line - line for the session
+ * @param call_id - callid for the session
+ * @param gcid - Global CallId for the session
+ *
+ * @return none
+ */
+void
+ui_update_gcid (line_t line, callid_t call_id, char *gcid)
+{
+ session_update_t msg;
+
+ TNP_DEBUG(DEB_L_C_F_PREFIX"gcid = %s\n", DEB_L_C_F_PREFIX_ARGS(UI_API, line, call_id, __FUNCTION__), gcid);
+
+ if ( *gcid == '\0' ) return;
+
+ if (call_id == CC_NO_CALL_ID) {
+ /* no operation when no call ID */
+ return;
+ }
+
+ msg.sessionID = createSessionId(line, call_id);
+ msg.eventID = CALL_GCID;
+ sstrncpy(msg.update.ccSessionUpd.data.gcid, gcid, CC_MAX_GCID);
+
+ if ( ccappTaskPostMsg(CCAPP_SESSION_UPDATE, &msg, sizeof(session_update_t), CCAPP_CCPROVIER) != CPR_SUCCESS ) {
+ CCAPP_ERROR(CCAPP_F_PREFIX"failed to send CALL_GCID() msg \n", __FUNCTION__);
+ }
+
+ return;
+}
+
+/**
+ * Wrapper for ui_update_video_avail
+ * indicates video stream is avail for this session to UI
+ * @param line - line for the session
+ * @param call_id - callid for the session
+ *
+ * @return none
+ */
+void
+ui_update_video_avail (line_t line, callid_t call_id, int avail)
+{
+ session_update_t msg;
+
+ TNP_DEBUG(DEB_L_C_F_PREFIX, DEB_L_C_F_PREFIX_ARGS(UI_API, line, call_id, __FUNCTION__));
+
+ if (call_id == CC_NO_CALL_ID) {
+ /* no operation when no call ID */
+ return;
+ }
+
+ msg.sessionID = createSessionId(line, call_id);
+ msg.eventID = VIDEO_AVAIL;
+ msg.update.ccSessionUpd.data.action = avail;
+
+ if ( ccappTaskPostMsg(CCAPP_SESSION_UPDATE, &msg, sizeof(session_update_t), CCAPP_CCPROVIER) != CPR_SUCCESS ) {
+ CCAPP_ERROR(CCAPP_F_PREFIX"failed to send VIDEO_AVAIL() msg \n", __FUNCTION__);
+ }
+
+ return;
+}
+
+void ui_update_media_interface_change(line_t line, callid_t call_id, group_call_event_t event) {
+ session_update_t msg;
+
+ if (event != MEDIA_INTERFACE_UPDATE_BEGIN &&
+ event != MEDIA_INTERFACE_UPDATE_SUCCESSFUL &&
+ event != MEDIA_INTERFACE_UPDATE_FAIL) {
+ // un-related event. ignore.
+ return;
+ }
+
+ if (event != MEDIA_INTERFACE_UPDATE_BEGIN) {
+ /* we are sending final result */
+ g_dock_undock_event = MEDIA_INTERFACE_UPDATE_NOT_REQUIRED;
+ }
+
+ DEF_DEBUG(DEB_L_C_F_PREFIX "event=%s", DEB_L_C_F_PREFIX_ARGS(UI_API, line, call_id, __FUNCTION__),
+ event == MEDIA_INTERFACE_UPDATE_BEGIN ? "MEDIA_INTERFACE_UPDATE_BEGIN" :
+ event == MEDIA_INTERFACE_UPDATE_SUCCESSFUL ? "MEDIA_INTERFACE_UPDATE_SUCCESSFUL" :
+ event == MEDIA_INTERFACE_UPDATE_FAIL ? "MEDIA_INTERFACE_UPDATE_FAIL" : "unknown");
+ if (call_id == CC_NO_CALL_ID) {
+ /* no operation when no call ID */
+ return;
+ }
+ msg.sessionID = createSessionId(line, call_id);
+ msg.eventID = event;
+
+ if ( ccappTaskPostMsg(CCAPP_SESSION_UPDATE, &msg, sizeof(session_update_t), CCAPP_CCPROVIER) != CPR_SUCCESS ) {
+ CCAPP_ERROR(CCAPP_F_PREFIX"failed to send media update () msg \n", __FUNCTION__);
+ }
+}
+
+void
+ui_call_stop_ringer (line_t line, callid_t call_id)
+{
+ session_update_t msg;
+
+ TNP_DEBUG(DEB_L_C_F_PREFIX, DEB_L_C_F_PREFIX_ARGS(UI_API, line, call_id, __FUNCTION__));
+
+ if (call_id == CC_NO_CALL_ID) {
+ /* no operation when no call ID */
+ return;
+ }
+
+ msg.sessionID = createSessionId(line, call_id);
+ msg.eventID = RINGER_STATE;
+ msg.update.ccSessionUpd.data.ringer.start = FALSE;
+ msg.update.ccSessionUpd.data.ringer.mode = VCM_RING_OFF;
+
+ if ( ccappTaskPostMsg(CCAPP_SESSION_UPDATE, &msg, sizeof(session_update_t), CCAPP_CCPROVIER) != CPR_SUCCESS ) {
+ CCAPP_ERROR(CCAPP_F_PREFIX"failed to send RINGER_STATE() msg \n", __FUNCTION__);
+ }
+
+ return;
+}
+
+void
+ui_call_start_ringer (vcm_ring_mode_t ringMode, short once, line_t line, callid_t call_id)
+{
+ session_update_t msg;
+
+ TNP_DEBUG(DEB_L_C_F_PREFIX, DEB_L_C_F_PREFIX_ARGS(UI_API, line, call_id, __FUNCTION__));
+
+ if (call_id == CC_NO_CALL_ID) {
+ /* no operation when no call ID */
+ return;
+ }
+
+ msg.sessionID = createSessionId(line, call_id);
+ msg.eventID = RINGER_STATE;
+ msg.update.ccSessionUpd.data.ringer.start = TRUE;
+ msg.update.ccSessionUpd.data.ringer.mode = ringMode;
+ msg.update.ccSessionUpd.data.ringer.once = (cc_boolean) once;
+
+ if ( ccappTaskPostMsg(CCAPP_SESSION_UPDATE, &msg, sizeof(session_update_t), CCAPP_CCPROVIER) != CPR_SUCCESS ) {
+ CCAPP_ERROR(CCAPP_F_PREFIX"failed to send RINGER_STATE() msg \n", __FUNCTION__);
+ }
+
+ return;
+}
+
+/**
+ * Wrapper for ui_update_video_avail
+ * indicates video stream is avail for this session to UI
+ * @param line - line for the session
+ * @param call_id - callid for the session
+ *
+ * @return none
+ */
+void
+ui_update_video_offered (line_t line, callid_t call_id, int avail)
+{
+ session_update_t msg;
+
+ TNP_DEBUG(DEB_L_C_F_PREFIX, DEB_L_C_F_PREFIX_ARGS(UI_API, line, call_id, __FUNCTION__));
+
+ if (call_id == CC_NO_CALL_ID) {
+ /* no operation when no call ID */
+ return;
+ }
+
+ msg.sessionID = createSessionId(line, call_id);
+ msg.eventID = VIDEO_OFFERED;
+ msg.update.ccSessionUpd.data.action = avail;
+
+ if ( ccappTaskPostMsg(CCAPP_SESSION_UPDATE, &msg, sizeof(session_update_t), CCAPP_CCPROVIER) != CPR_SUCCESS ) {
+ CCAPP_ERROR(CCAPP_F_PREFIX"failed to send VIDEO_OFFERED() msg \n", __FUNCTION__);
+ }
+
+ return;
+}
+
+
+/**
+ * Wrapper for ui call info post to CCAPP
+ * call bubble with appropriate party information
+ *
+ * @param pCallingPartyNameStr/NumberStr - Calling party information
+ * @param displayCallingNumber
+ * @param pCalledPartyNameStr/NumberStr - called party information
+ * @param displayCalledNumber
+ * @param pOrigCalledNameStr/NumberStr
+ * @param pLastRedirectingNameStr/NumberStr
+ * @param call_type
+ * @param line - line identifier
+ * @param call_id - call identifier
+ * @param call_instance_id - call instance displayed in call bubble
+ * @param cc_security
+ *
+ * @return none
+ */
+void
+ui_call_info (string_t pCallingPartyNameStr,
+ string_t pCallingPartyNumberStr,
+ string_t pAltCallingPartyNumberStr,
+ boolean displayCallingNumber,
+ string_t pCalledPartyNameStr,
+ string_t pCalledPartyNumberStr,
+ boolean displayCalledNumber,
+ string_t pOrigCalledNameStr,
+ string_t pOrigCalledNumberStr,
+ string_t pLastRedirectingNameStr,
+ string_t pLastRedirectingNumberStr,
+ calltype_t call_type,
+ line_t line,
+ callid_t call_id,
+ uint16_t call_instance_id,
+ cc_security_e call_security,
+ cc_policy_e call_policy)
+{
+ session_update_t msg;
+ const char *uiCalledName;
+ const char *uiCalledNumber;
+ const char *uiCallingName;
+ const char *uiCallingNumber;
+ int inbound;
+ char lineName[MAX_LINE_NAME_SIZE];
+ char lineNumber[MAX_LINE_NAME_SIZE];
+
+
+ TNP_DEBUG(DEB_L_C_F_PREFIX"call instance=%d callednum=%s calledname=%s clngnum=%s clngname = %s\n",
+ DEB_L_C_F_PREFIX_ARGS(UI_API, line, call_id, __FUNCTION__), call_instance_id, pCalledPartyNumberStr,
+ pCalledPartyNameStr, pCallingPartyNumberStr, pCallingPartyNameStr);
+
+ TNP_DEBUG(DEB_F_PREFIX"calltype=%d displayClng=%d displayCld=%d\n", DEB_F_PREFIX_ARGS(UI_API, __FUNCTION__), call_type,
+ displayCallingNumber, displayCalledNumber);
+
+
+ inbound = (call_type == FSMDEF_CALL_TYPE_INCOMING) || (call_type == FSMDEF_CALL_TYPE_FORWARD);
+ uiCalledNumber = pCalledPartyNumberStr;
+ uiCalledName = pCalledPartyNameStr;
+ uiCallingNumber = pCallingPartyNumberStr;
+ uiCallingName = pCallingPartyNameStr;
+
+ config_get_line_string(CFGID_LINE_DISPLAYNAME, lineName, line, sizeof(lineName));
+ config_get_line_string(CFGID_LINE_NAME, lineNumber, line, sizeof(lineNumber));
+
+ if (inbound) {
+ uiCalledNumber = lineNumber;
+ uiCalledName = lineName;
+ } else {
+ uiCallingNumber = lineNumber;
+ uiCallingName = lineName;
+ }
+
+ if (call_id == CC_NO_CALL_ID) {
+ /* no operation when no call ID */
+ return;
+ }
+
+
+ msg.sessionID = createSessionId(line, call_id);
+ msg.eventID = CALL_INFORMATION;
+ msg.update.ccSessionUpd.data.call_info.clgName = uiCallingName?strlib_malloc(uiCallingName, strlen(uiCallingName)):strlib_empty();
+
+ if ( uiCallingNumber== NULL || (inbound && !displayCallingNumber)) {
+ msg.update.ccSessionUpd.data.call_info.clgNumber = strlib_empty();
+ } else {
+ msg.update.ccSessionUpd.data.call_info.clgNumber = strlib_malloc(uiCallingNumber, strlen(uiCallingNumber));
+ }
+
+ if ( pAltCallingPartyNumberStr == NULL || (inbound && !displayCallingNumber)) {
+ msg.update.ccSessionUpd.data.call_info.altClgNumber = strlib_empty();
+ } else {
+ msg.update.ccSessionUpd.data.call_info.altClgNumber = strlib_malloc(pAltCallingPartyNumberStr,strlen(pAltCallingPartyNumberStr));
+ }
+
+ msg.update.ccSessionUpd.data.call_info.cldName = uiCalledName?strlib_malloc(uiCalledName,strlen(uiCalledName)):strlib_empty();
+
+ if (uiCalledNumber == NULL || (!inbound && !displayCalledNumber)) {
+ msg.update.ccSessionUpd.data.call_info.cldNumber = strlib_empty();
+ } else {
+ msg.update.ccSessionUpd.data.call_info.cldNumber = strlib_malloc(uiCalledNumber,strlen(uiCalledNumber));
+ }
+ msg.update.ccSessionUpd.data.call_info.origCalledName = pOrigCalledNameStr?strlib_malloc(pOrigCalledNameStr, strlen(pOrigCalledNameStr)):strlib_empty();
+ msg.update.ccSessionUpd.data.call_info.origCalledNumber = pOrigCalledNumberStr?strlib_malloc(pOrigCalledNumberStr,strlen(pOrigCalledNumberStr)):strlib_empty();
+ msg.update.ccSessionUpd.data.call_info.lastRedirectingName = pLastRedirectingNameStr?strlib_malloc(pLastRedirectingNameStr,strlen(pLastRedirectingNameStr)):strlib_empty();
+ msg.update.ccSessionUpd.data.call_info.lastRedirectingNumber = pLastRedirectingNumberStr?strlib_malloc(pLastRedirectingNumberStr, strlen(pLastRedirectingNumberStr)):strlib_empty();
+ msg.update.ccSessionUpd.data.call_info.call_type = call_type;
+ msg.update.ccSessionUpd.data.call_info.instance_id = call_instance_id;
+ msg.update.ccSessionUpd.data.call_info.security = call_security;
+ msg.update.ccSessionUpd.data.call_info.policy = call_policy;
+
+ if ( ccappTaskPostMsg(CCAPP_SESSION_UPDATE, &msg, sizeof(session_update_t), CCAPP_CCPROVIER) != CPR_SUCCESS ) {
+ CCAPP_ERROR(CCAPP_F_PREFIX"failed to send CALL_INFO() msg \n", __FUNCTION__);
+ }
+
+ return;
+}
+
+/**
+ * Wrapper for ui cc capability post to CCAPP
+ *
+ * @param line - line identifier
+ * @param callID - call identifier
+ * @param capability - cc capability
+ *
+ * @return none
+ */
+void
+ui_cc_capability (line_t line, callid_t call_id, string_t recv_info_list)
+{
+ session_update_t msg;
+
+ TNP_DEBUG(DEB_L_C_F_PREFIX"recv_info_list:%s\n",
+ DEB_L_C_F_PREFIX_ARGS(UI_API, line, call_id, __FUNCTION__),
+ recv_info_list);
+
+ msg.sessionID = createSessionId(line, call_id);
+ msg.eventID = CALL_RECV_INFO_LIST;
+ msg.update.ccSessionUpd.data.recv_info_list = strlib_copy(recv_info_list);
+
+ if ( ccappTaskPostMsg(CCAPP_SESSION_UPDATE, &msg, sizeof(session_update_t), CCAPP_CCPROVIER) != CPR_SUCCESS ) {
+ CCAPP_ERROR(CCAPP_F_PREFIX"failed to send CALL_RECV_INFO_LIST msg \n", __FUNCTION__);
+ }
+}
+
+/**
+ * Wrapper for ui info received post to CCAPP
+ *
+ * @param line - line identifier
+ * @param callID - call identifier
+ * @param info_package - the Info-Package header of the Info Package
+ * @param content_type - the Content-Type header of the Info Package
+ * @param message_body - the message body of the Info Package
+ *
+ * @return none
+ */
+void
+ui_info_received (line_t line, callid_t call_id, const char *info_package,
+ const char *content_type, const char *message_body)
+{
+ session_rcvd_info_t msg;
+
+ TNP_DEBUG(DEB_L_C_F_PREFIX"info_package:%s content_type:%s message_body:%s\n",
+ DEB_L_C_F_PREFIX_ARGS(UI_API, line, call_id, __FUNCTION__),
+ info_package, content_type, message_body);
+
+ msg.sessionID = createSessionId(line, call_id);
+ msg.packageID = INFO_PKG_ID_GENERIC_RAW;
+ msg.info.generic_raw.info_package = info_package?strlib_malloc(info_package, strlen(info_package)):strlib_empty();
+ msg.info.generic_raw.content_type = content_type?strlib_malloc(content_type, strlen(content_type)):strlib_empty();
+ msg.info.generic_raw.message_body = message_body?strlib_malloc(message_body, strlen(message_body)):strlib_empty();
+
+ if ( ccappTaskPostMsg(CCAPP_RCVD_INFO, &msg, sizeof(session_rcvd_info_t), CCAPP_CCPROVIER) != CPR_SUCCESS ) {
+ CCAPP_ERROR(CCAPP_F_PREFIX"failed to send CALL_INFO_RECEIVED msg \n", __FUNCTION__);
+ }
+}
+
+
+/**
+ * An internal wrapper for ui call status post to CCAPP
+ *
+ * @param pString - status string
+ * @param line - line identifier
+ * @param callID - call identifier
+ * @param timeout - timeout for the status line
+ *
+ * @return none
+ */
+static void
+ui_set_call_status_display (string_t status, line_t line, callid_t callID, int timeout, char priority)
+{
+ session_update_t msg;
+
+ TNP_DEBUG(DEB_L_C_F_PREFIX"the stat string =%s, timeout= %d, priority=%d\n", DEB_L_C_F_PREFIX_ARGS(UI_API, line, callID, __FUNCTION__),
+ status,
+ timeout,
+ priority);
+
+ if (callID == CC_NO_CALL_ID) {
+ /* no operation when no call ID */
+ return;
+ }
+
+ msg.sessionID = createSessionId(line, callID);
+ msg.eventID = CALL_STATUS;
+ msg.update.ccSessionUpd.data.status.timeout = timeout;
+ msg.update.ccSessionUpd.data.status.priority = priority;
+ if ( status ) {
+ msg.update.ccSessionUpd.data.status.status = strlib_malloc(status, strlen(status));
+ } else {
+ msg.update.ccSessionUpd.data.status.status = strlib_empty();
+ }
+
+ if ( ccappTaskPostMsg(CCAPP_SESSION_UPDATE, &msg, sizeof(session_update_t), CCAPP_CCPROVIER) != CPR_SUCCESS ) {
+ CCAPP_ERROR(CCAPP_F_PREFIX"failed to send CALL_STATUS(%s) msg \n", __FUNCTION__, status);
+ }
+}
+
+
+/**
+ * Wrapper for ui call status post to CCAPP
+ *
+ * @param pString - status string
+ * @param line - line identifier
+ * @param callID - call identifier
+ * @param timeout - timeout for the status line
+ *
+ * @return none
+ */
+void
+ui_set_call_status (string_t status, line_t line, callid_t callID)
+{
+
+ TNP_DEBUG(DEB_L_C_F_PREFIX"the stat string =%s\n", DEB_L_C_F_PREFIX_ARGS(UI_API, line, callID, __FUNCTION__),
+ status);
+
+ if (callID == CC_NO_CALL_ID) {
+ /* no operation when no call ID */
+ return;
+ }
+
+ ui_set_call_status_display(status, line, callID, DEFAULT_DISPLAY_NOTIFY_TIMEOUT, DEFAULT_DISPLAY_NOTIFY_PRIORITY);
+}
+
+
+/**
+ * Wrapper for sending notification CCAPP
+ *
+ * @param promptString - notification string
+ * @param timeout - timeout of this notify
+ * @param notifyProgress- the type of notification
+ * TRUE - Progress, FALSE- Normal
+ * @param priority - priority of this notification
+ * Pri 1..5 Low .. High
+ *
+ * @return none
+ */
+void
+ui_set_notification (line_t line, callid_t call_id, char *promptString, int timeout,
+ boolean notifyProgress, char priority)
+{
+ feature_update_t msg;
+
+ TNP_DEBUG(DEB_F_PREFIX"line=%d callid=%d str=%s tout=%d notifyProgress=%d pri=%d\n", DEB_F_PREFIX_ARGS(UI_API, __FUNCTION__),
+ line, call_id, promptString, timeout, notifyProgress, priority);
+
+ if (line > 0 && call_id > 0) {
+ ui_set_call_status_display(promptString, line, call_id, timeout, priority);
+ return;
+ }
+ msg.sessionType = SESSIONTYPE_CALLCONTROL;
+ msg.featureID = DEVICE_NOTIFICATION;
+ msg.update.ccFeatUpd.data.notification.timeout = timeout;
+ msg.update.ccFeatUpd.data.notification.notifyProgress = notifyProgress;
+ msg.update.ccFeatUpd.data.notification.priority = priority;
+ if ( promptString != NULL ) {
+ msg.update.ccFeatUpd.data.notification.prompt = strlib_malloc(promptString, strlen(promptString));
+ } else {
+ msg.update.ccFeatUpd.data.notification.prompt = strlib_empty();
+ }
+
+ if ( ccappTaskPostMsg(CCAPP_FEATURE_UPDATE, &msg, sizeof(feature_update_t), CCAPP_CCPROVIER) != CPR_SUCCESS ) {
+ CCAPP_ERROR(CCAPP_F_PREFIX"failed to send DEVICE_NOTIFICATION(%s) msg \n", __FUNCTION__, promptString);
+ }
+}
+
+/**
+ * CCAPPPost to clear the previous notify of given priority
+ *
+ * @param priority - notification of the given pri
+ *
+ * @return none
+ */
+/* TBD: the API should have priority param */
+void
+ui_clear_notification ()
+{
+ TNP_DEBUG(DEB_F_PREFIX"called..\n", DEB_F_PREFIX_ARGS(UI_API, __FUNCTION__));
+
+ // A promptString of NULL shall act as a clear
+ ui_set_notification(CC_NO_LINE, CC_NO_CALL_ID, NULL, 0, FALSE, 1);
+}
+
+/**
+ *
+ * CCAPP Post to set the MWI lamp indication of the device
+ *
+ * @param 1 - on or else off
+ *
+ * @return none
+ */
+void
+ui_change_mwi_lamp (int status)
+{
+ feature_update_t msg;
+
+
+ TNP_DEBUG(DEB_F_PREFIX"status=%d \n", DEB_F_PREFIX_ARGS(UI_API, __FUNCTION__), status);
+
+ msg.sessionType = SESSIONTYPE_CALLCONTROL;
+ msg.featureID = DEVICE_FEATURE_MWILAMP;
+ msg.update.ccFeatUpd.data.state_data.state = status;
+
+ if ( ccappTaskPostMsg(CCAPP_FEATURE_UPDATE, &msg, sizeof(feature_update_t), CCAPP_CCPROVIER) != CPR_SUCCESS ) {
+ CCAPP_ERROR(CCAPP_F_PREFIX"failed to send DEVICE_FEATURE_MWILAMP(%d) msg \n", __FUNCTION__, status);
+ }
+}
+
+/**
+ *
+ * CCAPP post to set the MWI lamp indication for given line
+ *
+ * @param line - line identifier
+ * @param on - TRUE -> on, otherwise off
+ *
+ * @return none
+ */
+void
+ui_set_mwi (line_t line, boolean status, int type, int newCount, int oldCount, int hpNewCount, int hpOldCount)
+{
+ feature_update_t msg;
+
+ TNP_DEBUG(DEB_F_PREFIX"line=%d count=%d \n", DEB_F_PREFIX_ARGS(UI_API, __FUNCTION__), line, status);
+
+ msg.sessionType = SESSIONTYPE_CALLCONTROL;
+ msg.featureID = DEVICE_FEATURE_MWI;
+ msg.update.ccFeatUpd.data.mwi_status.line = line;
+ msg.update.ccFeatUpd.data.mwi_status.status = status;
+ msg.update.ccFeatUpd.data.mwi_status.type = type;
+ msg.update.ccFeatUpd.data.mwi_status.newCount = newCount;
+ msg.update.ccFeatUpd.data.mwi_status.oldCount = oldCount;
+ msg.update.ccFeatUpd.data.mwi_status.hpNewCount = hpNewCount;
+ msg.update.ccFeatUpd.data.mwi_status.hpOldCount = hpOldCount;
+
+ if ( ccappTaskPostMsg(CCAPP_FEATURE_UPDATE, &msg, sizeof(feature_update_t), CCAPP_CCPROVIER) != CPR_SUCCESS ) {
+ CCAPP_ERROR(CCAPP_F_PREFIX"failed to send DEVICE_FEATURE_MWI(%d,%d) msg \n", __FUNCTION__, line, status);
+ }
+}
+
+/*
+ * Function: ui_mnc_reached
+ *
+ * @param line - line number
+ * @param boolean - maximum number of calls reached on this line
+ *
+ * Description:
+ * post mnc_reached status to CCAPP
+ *
+ * @return none
+ *
+ */
+void ui_mnc_reached (line_t line, boolean mnc_reached)
+{
+ feature_update_t msg;
+
+ DEF_DEBUG(DEB_F_PREFIX"line %d: Max number of calls reached =%d \n",
+ DEB_F_PREFIX_ARGS(UI_API, __FUNCTION__),
+ line, mnc_reached);
+
+ msg.sessionType = SESSIONTYPE_CALLCONTROL;
+ msg.featureID = DEVICE_FEATURE_MNC_REACHED;
+ msg.update.ccFeatUpd.data.line_info.line = line;
+ msg.update.ccFeatUpd.data.line_info.info = mnc_reached;
+
+ if ( ccappTaskPostMsg(CCAPP_FEATURE_UPDATE, &msg, sizeof(feature_update_t), CCAPP_CCPROVIER) != CPR_SUCCESS ) {
+ CCAPP_ERROR(CCAPP_F_PREFIX"failed to send DEVICE_FEATURE_MNC_REACHED(%d,%d) msg \n", __FUNCTION__,
+ line, mnc_reached);
+ }
+
+}
+
+/**
+ *
+ * Check if MWI is active on a given line
+ *
+ * @param line - line identifier
+ *
+ * @return true if active; false otherwise.
+ */
+boolean
+ui_line_has_mwi_active (line_t line)
+{
+ session_mgmt_t msg;
+
+ TNP_DEBUG(DEB_F_PREFIX"line=%d\n", DEB_F_PREFIX_ARGS(UI_API, __FUNCTION__), line);
+
+ msg.func_id = SESSION_MGMT_LINE_HAS_MWI_ACTIVE;
+ msg.data.line_mwi_active.line = line;
+
+ ccappSyncSessionMgmt(&msg);
+
+ return msg.data.line_mwi_active.ret_val;
+}
+
+
+/**
+ * CCAPP msg post to Set linekey values
+ *
+ * @param line - line identifier
+ * @param SpeedDial - Speeddial string to be changed
+ * @param label - Feature lable to be changed
+ *
+ * @return none
+ */
+void
+ui_update_label_n_speeddial (line_t line, line_t button_no, string_t speed_dial, string_t label)
+{
+ feature_update_t msg;
+
+ TNP_DEBUG(DEB_F_PREFIX"line=%d speeddial=%s displayname=%s\n", DEB_F_PREFIX_ARGS(UI_API, __FUNCTION__), line,
+ speed_dial, label);
+
+ msg.sessionType = SESSIONTYPE_CALLCONTROL;
+ msg.featureID = DEVICE_LABEL_N_SPEED;
+ msg.update.ccFeatUpd.data.cfg_lbl_n_spd.line = line;
+ msg.update.ccFeatUpd.data.cfg_lbl_n_spd.button = (unsigned char) button_no;
+ msg.update.ccFeatUpd.data.cfg_lbl_n_spd.speed = strlib_malloc(speed_dial, sizeof(speed_dial));
+ msg.update.ccFeatUpd.data.cfg_lbl_n_spd.label = strlib_malloc(label, sizeof(label));
+
+ if ( ccappTaskPostMsg(CCAPP_FEATURE_UPDATE, &msg, sizeof(feature_update_t), CCAPP_CCPROVIER) != CPR_SUCCESS ) {
+ CCAPP_ERROR(CCAPP_F_PREFIX"failed to send DEVICE_LABEL_N_SPEED(%d) msg \n", __FUNCTION__, button_no);
+ }
+}
+
+/**
+ * Inform CCAPP of registration state of given line in Line Plane
+ *
+ * @param line - line identifier
+ * @param registered - whether the line was registered or not
+ *
+ * @return none
+ */
+void
+ui_set_sip_registration_state (line_t line, boolean registered)
+{
+ feature_update_t msg;
+ int value;
+
+ TNP_DEBUG(DEB_F_PREFIX"%s %d: %s\n", DEB_F_PREFIX_ARGS(UI_API, __FUNCTION__),
+ (line==CC_ALL_LINES) ? "ALL LINES":"LINE" ,line,
+ (registered)? "REGISTERED":"UN-REGISTERED");
+
+ msg.sessionType = SESSIONTYPE_CALLCONTROL;
+ msg.featureID = DEVICE_REG_STATE;
+ msg.update.ccFeatUpd.data.line_info.line = line;
+ msg.update.ccFeatUpd.data.line_info.info = registered ? CC_REGISTERED : CC_UNREGISTERED;
+ config_get_value(CFGID_PROXY_REGISTER, &value, sizeof(value));
+ if (value == 0) {
+ msg.update.ccFeatUpd.data.line_info.info = CC_REGISTERED;
+ }
+
+ if ( ccappTaskPostMsg(CCAPP_FEATURE_UPDATE, &msg, sizeof(feature_update_t), CCAPP_CCPROVIER) != CPR_SUCCESS ) {
+ CCAPP_ERROR(CCAPP_F_PREFIX"failed to send CALL_STATE(%d, %d) msg \n", __FUNCTION__, line, registered);
+ }
+}
+
+/**
+ * Inform CCAPP of registration state of given line in Line Plane
+ *
+ * @param registered - line registered true/false
+ *
+ * @return none
+ */
+void
+ui_update_registration_state_all_lines (boolean registered)
+{
+ DEF_DEBUG(DEB_F_PREFIX"***********ALL LINES %s****************\n",
+ DEB_F_PREFIX_ARGS(UI_API, __FUNCTION__),
+ (registered)? "REGISTERED":"UN-REGISTERED");
+
+ ui_set_sip_registration_state(CC_ALL_LINES, registered);
+
+}
+
+/**
+ * Inform the CCAPP that all registration attempts with
+ * all call controls have failed.
+ *
+ * @param none
+ *
+ * @return none
+ */
+void
+ui_reg_all_failed (void)
+{
+ feature_update_t msg;
+
+ TNP_DEBUG(DEB_F_PREFIX"***********Registration to all CUCMs failed.***********\n",
+ DEB_F_PREFIX_ARGS(UI_API, __FUNCTION__));
+
+ msg.sessionType = SESSIONTYPE_CALLCONTROL;
+ msg.featureID = CCAPP_REG_ALL_FAIL;
+ msg.update.ccFeatUpd.data.line_info.line = CC_ALL_LINES;
+ msg.update.ccFeatUpd.data.line_info.info = FALSE;
+
+ if ( ccappTaskPostMsg(CCAPP_REG_ALL_FAIL, &msg, sizeof(feature_update_t), CCAPP_CCPROVIER) != CPR_SUCCESS ) {
+ CCAPP_ERROR(CCAPP_F_PREFIX"failed to send CALL_STATE() msg \n", __FUNCTION__);
+ }
+}
+
+/**
+ *
+ * inform CCAPP about the status of the CCMs
+ *
+ * @param ccm_addr - IP address string
+ * @param status - status (notconnected, active, standby, notavail)
+ *
+ * @return none
+ */
+void
+ui_set_ccm_conn_status (char * ccm_addr, int status)
+{
+ feature_update_t msg;
+
+ DEF_DEBUG(DEB_F_PREFIX"***********CUCM %s %s***********\n",
+ DEB_F_PREFIX_ARGS(UI_API, __FUNCTION__), ccm_addr,
+ ((status == 0) ?"Not connected":((status == 1)?"STAND BY":
+ ((status == 2)?"ACTIVE":"UNKNOWN"))));
+
+ msg.sessionType = SESSIONTYPE_CALLCONTROL;
+ msg.featureID = DEVICE_CCM_CONN_STATUS;
+ msg.update.ccFeatUpd.data.ccm_conn.addr = ccm_addr?strlib_malloc(ccm_addr, strlen(ccm_addr)):strlib_empty();
+ msg.update.ccFeatUpd.data.ccm_conn.status = status;
+
+ if ( ccappTaskPostMsg(CCAPP_FEATURE_UPDATE, &msg, sizeof(feature_update_t), CCAPP_CCPROVIER) != CPR_SUCCESS ) {
+ CCAPP_ERROR(CCAPP_F_PREFIX"failed to send DEVICE_CCM_CONN_STATUS(%d) msg \n", __FUNCTION__, status);
+ }
+}
+
+/**
+ * Treat given line and callid as being put on hold by user.
+ *
+ * @param line - line identifier
+ * @param call_id - call identifier
+ *
+ * @return none
+ */
+void
+ui_set_local_hold (line_t line, callid_t call_id)
+{
+ /* THIS IS A NOP FOR TNP */
+ TNP_DEBUG(DEB_L_C_F_PREFIX"called\n", DEB_L_C_F_PREFIX_ARGS(UI_API, line, call_id, "ui_set_local_hold"));
+ return;
+}
+
+/**
+ * Sets the call forward status as a flashing arrow and status line
+ * accordingly.
+ *
+ * @param line - line identifier
+ * @param cfa - call forward all true/false
+ * @param cfa_number - string representing call forwarded to number
+ *
+ * @return none
+ */
+void
+ui_cfwd_status (line_t line, boolean cfa, char *cfa_number, boolean lcl_fwd)
+{
+ feature_update_t msg;
+
+ TNP_DEBUG(DEB_F_PREFIX"line=%d cfa=%d cfa_number=%s lcl_fwd=%d", DEB_F_PREFIX_ARGS(UI_API, __FUNCTION__),
+ line, cfa, cfa_number, lcl_fwd);
+
+ msg.sessionType = SESSIONTYPE_CALLCONTROL;
+ msg.featureID = DEVICE_FEATURE_CFWD;
+ msg.update.ccFeatUpd.data.cfwd.line = line;
+ msg.update.ccFeatUpd.data.cfwd.isFwd = cfa;
+ msg.update.ccFeatUpd.data.cfwd.isLocal = lcl_fwd;
+ msg.update.ccFeatUpd.data.cfwd.cfa_num = cfa_number?strlib_malloc(cfa_number, strlen(cfa_number)):strlib_empty();
+
+ if ( ccappTaskPostMsg(CCAPP_FEATURE_UPDATE, &msg, sizeof(feature_update_t), CCAPP_CCPROVIER) != CPR_SUCCESS ) {
+ CCAPP_ERROR(CCAPP_F_PREFIX"failed to send DEVICE_FEATURE_CFWD(%d) msg \n", __FUNCTION__, cfa);
+ }
+}
+
+/**
+ * Get the Idle prompt string.
+ *
+ * @return the idle prompt phrase from locale
+ */
+char *
+ui_get_idle_prompt_string (void)
+{
+ TNP_DEBUG(DEB_F_PREFIX"called\n", DEB_F_PREFIX_ARGS(UI_API, "ui_get_idle_prompt_string"));
+ return platform_get_phrase_index_str(IDLE_PROMPT);
+}
+
+/**
+ * Set the Appropriate Idle prompt string.
+ *
+ * @param pString - New Idle Prompt String
+ * @param prompt - The Idle Prompt To Be Modified
+ *
+ * @return the idle prompt phrase from locale
+ */
+void
+ui_set_idle_prompt_string (string_t pString, int prompt)
+{
+ TNP_DEBUG(DEB_F_PREFIX"Prompt=%d, Prompt string=%s NOP operation\n", DEB_F_PREFIX_ARGS(UI_API, __FUNCTION__), prompt, pString);
+}
+
+/**
+ * Updates placed call information for call history
+ *
+ * @param line - line identifier
+ * @param call_id - call identifier
+ * @param cldName - called name
+ * @param cldNumber - called number
+ *
+ * @return none
+ */
+void
+ui_update_placed_call_info (line_t line, callid_t call_id, string_t cldName,
+ string_t cldNumber)
+{
+ session_update_t msg;
+
+ TNP_DEBUG(DEB_L_C_F_PREFIX"calledName:calledNumber %s:%s\n",
+ DEB_L_C_F_PREFIX_ARGS(UI_API, line, call_id, __FUNCTION__), cldName, cldNumber);
+
+ if (call_id == CC_NO_CALL_ID) {
+ /* no operation when no call ID */
+ TNP_DEBUG(DEB_F_PREFIX"invalid callid\n", DEB_F_PREFIX_ARGS(UI_API, __FUNCTION__));
+ return;
+ }
+ msg.sessionID = createSessionId(line, call_id);
+ msg.eventID = CALL_PLACED_INFO;
+ msg.update.ccSessionUpd.data.plcd_info.cldName = strlib_empty();
+ msg.update.ccSessionUpd.data.plcd_info.cldNum = strlib_empty();
+
+ if ( cldName) {
+ msg.update.ccSessionUpd.data.plcd_info.cldName = strlib_update(
+ msg.update.ccSessionUpd.data.plcd_info.cldName, cldName);
+ }
+ if ( cldNumber) {
+ msg.update.ccSessionUpd.data.plcd_info.cldNum = strlib_update(
+ msg.update.ccSessionUpd.data.plcd_info.cldNum, cldNumber);
+ }
+
+ if ( ccappTaskPostMsg(CCAPP_SESSION_UPDATE, &msg, sizeof(session_update_t), CCAPP_CCPROVIER) != CPR_SUCCESS ) {
+ CCAPP_ERROR(CCAPP_F_PREFIX"failed to send CALL_PLACED_INFO(%s) msg \n", __FUNCTION__, cldNumber);
+ }
+}
+
+
+/**
+ * Description: remove last digit from input box
+ *
+ * @param line - line identifier
+ * @param call_id - call identifier
+ *
+ * @return none
+ */
+void
+ui_delete_last_digit (line_t line_id, callid_t call_id)
+{
+ session_update_t msg;
+
+ TNP_DEBUG(DEB_L_C_F_PREFIX"called\n", DEB_L_C_F_PREFIX_ARGS(UI_API, line_id, call_id, __FUNCTION__));
+
+ if (call_id == CC_NO_CALL_ID) {
+ /* no operation when no call ID */
+ return;
+ }
+
+ msg.sessionID = createSessionId(line_id, call_id);
+ msg.eventID = CALL_DELETE_LAST_DIGIT;
+
+ if ( ccappTaskPostMsg(CCAPP_SESSION_UPDATE, &msg, sizeof(session_update_t), CCAPP_CCPROVIER) != CPR_SUCCESS ) {
+ CCAPP_ERROR(CCAPP_F_PREFIX"failed to send CALL_DELETE_LAST_DIGIT() msg \n", __FUNCTION__);
+ }
+}
+
+/**
+ * Keep/Remove BackSpace key if presented
+ *
+ * @param line_id - line identifier
+ * @param call_id - call identifier
+ * @param enable - TRUE -> enable backspace softkey
+ *
+ * @return none
+ */
+void
+ui_control_featurekey_bksp (line_t line_id, callid_t call_id, boolean enable)
+{
+ session_update_t msg;
+
+ TNP_DEBUG(DEB_L_C_F_PREFIX"enable=%d\n", DEB_L_C_F_PREFIX_ARGS(UI_API, line_id, call_id, __FUNCTION__),
+ enable);
+
+ msg.sessionID = createSessionId(line_id, call_id);
+ msg.eventID = CALL_ENABLE_BKSP;
+ msg.update.ccSessionUpd.data.action = enable;
+ if ( ccappTaskPostMsg(CCAPP_SESSION_UPDATE, &msg, sizeof(session_update_t), CCAPP_CCPROVIER) != CPR_SUCCESS ) {
+ CCAPP_ERROR(CCAPP_F_PREFIX"failed to send CALL_ENABLE_BKSP(%d) msg \n", __FUNCTION__, enable);
+ }
+}
+
+
+/**
+ * Select(lock-down) the call specified.
+ * For tnp this visually places a check box on the bubble.
+ *
+ * @param line_id - line identifier
+ * @param call_id - call identifier
+ * @param selected - TRUE -> call is locked-down in signaling,
+ * mark as such on UI
+ *
+ * @return none
+ */
+void
+ui_call_selected (line_t line_id, callid_t call_id, int selected)
+{
+ session_update_t msg;
+
+ TNP_DEBUG(DEB_L_C_F_PREFIX"selected=%d\n",
+ DEB_L_C_F_PREFIX_ARGS(UI_API, line_id, call_id, __FUNCTION__), selected);
+
+ msg.sessionID = createSessionId(line_id, call_id);
+ msg.eventID = CALL_SELECTED;
+ msg.update.ccSessionUpd.data.action = selected;
+
+ if ( ccappTaskPostMsg(CCAPP_SESSION_UPDATE, &msg, sizeof(session_update_t), CCAPP_CCPROVIER) != CPR_SUCCESS ) {
+ CCAPP_ERROR(CCAPP_F_PREFIX"failed to send CALL_SELECTED(%d) msg \n", __FUNCTION__, selected);
+ }
+}
+
+/**
+ * Send the BLF state to the UI apps.
+ *
+ * @param[in] state - TRUE/FALSE
+ *
+ * @return none
+ */
+void ui_BLF_notification (int request_id, cc_blf_state_t blf_state, int app_id)
+{
+ feature_update_t msg;
+
+ TNP_DEBUG(DEB_F_PREFIX"state=%d app_id=%d\n", DEB_F_PREFIX_ARGS(UI_API, __FUNCTION__), blf_state, app_id);
+
+ msg.sessionType = SESSIONTYPE_CALLCONTROL;
+ msg.featureID = DEVICE_FEATURE_BLF;
+ msg.update.ccFeatUpd.data.blf_data.state = blf_state;
+ msg.update.ccFeatUpd.data.blf_data.request_id = request_id;
+ msg.update.ccFeatUpd.data.blf_data.app_id = app_id;
+
+ if ( ccappTaskPostMsg(CCAPP_FEATURE_UPDATE, &msg, sizeof(feature_update_t), CCAPP_CCPROVIER) != CPR_SUCCESS ) {
+ CCAPP_ERROR(CCAPP_F_PREFIX"failed to send DEVICE_FEATURE_BLF(state=%d, app_id=%d) msg \n",
+ __FUNCTION__, blf_state, app_id);
+ }
+}
+
+/**
+ *
+ * Change the softkey set to preservation key set (with just the EndCall key)
+ * From the platform perspective, this is strictly a softkey set change
+ * operation. There is no underlying state change in the call or its status.
+ * In other words, after this invocation, the clients can still issue
+ * ui_call_state() or any other call operation if they deem fit and
+ * the softkey set will adhere to that state.
+ *
+ * @param line_id - line identifier
+ * @param call_id - call identifier
+ *
+ * @return none
+ */
+void
+ui_call_in_preservation (line_t line_id, callid_t call_id)
+{
+ TNP_DEBUG(DEB_L_C_F_PREFIX"called\n", DEB_L_C_F_PREFIX_ARGS(UI_API, line_id, call_id, __FUNCTION__));
+
+ /* simply update the state . A Preservation event from
+ CUCM is just for the session */
+ ui_call_state (evCallPreservation , line_id, call_id, CC_CAUSE_NORMAL);
+}
+
+/**
+ * request ui to present a named softkey set for given call.
+ * The softkey set passed(set_name param) must be known to the platform.
+ * enable_mask is a set of bits (starting from LSB) one for each softkey.
+ * (so least significant bit represents left most softkey and so on).
+ * This function is typically used to mask certain softkeys in a given set.
+ * Use of this API as general purpose mechanism to present softkeys is
+ * discouraged because it breaks encapsulation. This API is introduced
+ * for the tough cases where adapter can not determine which keys to
+ * mask based on its state alone.
+ *
+ * @param line_id - line identifier
+ * @param call_id - call identifier
+ * @param set_name - name of the softkey set
+ * @param sk_mask_list - the softkey events that need to be masked
+ * @param len - length of the softkey list array
+ *
+ * @return none
+ */
+void
+ui_select_feature_key_set (line_t line_id, callid_t call_id, char *set_name,
+ int sk_mask_list[], int len)
+{
+ int i;
+ session_update_t msg;
+
+ TNP_DEBUG(DEB_L_C_F_PREFIX"called\n", DEB_L_C_F_PREFIX_ARGS(UI_API, line_id, call_id, __FUNCTION__));
+
+ if (call_id == CC_NO_CALL_ID) {
+ /* no operation when no call ID */
+ return;
+ }
+
+ if (len <= 0 || len > MAX_SOFT_KEYS) {
+ TNP_DEBUG(DEB_F_PREFIX"Incorrect softkey array length passed in : %d\n", DEB_F_PREFIX_ARGS(UI_API, __FUNCTION__), len);
+ return;
+ }
+
+ memset( &msg, 0, sizeof(session_update_t));
+
+ msg.sessionID = createSessionId(line_id, call_id);
+ msg.eventID = CALL_SELECT_FEATURE_SET;
+
+ if ( set_name == NULL ) {
+ // No point continuing here
+ return;
+ }
+
+ msg.update.ccSessionUpd.data.feat_set.featSet = set_name?strlib_malloc(set_name, sizeof(set_name)):strlib_empty();
+ for (i = 0; i < len; i++) {
+ msg.update.ccSessionUpd.data.feat_set.featMask[i] = sk_mask_list[i];
+ }
+
+ if ( ccappTaskPostMsg(CCAPP_SESSION_UPDATE, &msg, sizeof(session_update_t), CCAPP_CCPROVIER) != CPR_SUCCESS ) {
+ CCAPP_ERROR(CCAPP_F_PREFIX"failed to send CALL_SELECT_FEATURE_SET() msg \n", __FUNCTION__);
+ }
+}
+
+
+/* Test Interface Operations */
+
+/**
+ * Inject a simulated keypress into the Java Infrastructure
+ *
+ * @param uri - string
+ *
+ * @return none
+ */
+void
+ui_execute_uri (char *uri)
+{
+ session_mgmt_t msg;
+
+ TNP_DEBUG(DEB_F_PREFIX"uri=%s\n", DEB_F_PREFIX_ARGS(UI_API, __FUNCTION__), uri);
+
+ msg.func_id = SESSION_MGMT_EXECUTE_URI;
+ msg.data.uri.uri = STRLIB_CREATE(uri);
+
+ if ( ccappTaskPostMsg(CCAPP_SESSION_MGMT, &msg, sizeof(session_mgmt_t), CCAPP_CCPROVIER) != CPR_SUCCESS ) {
+ CCAPP_ERROR(DEB_F_PREFIX"failed to send EXECUTE_URI() msg\n", DEB_F_PREFIX_ARGS(PLAT_API, __FUNCTION__));
+ }
+}
+
+/* Log Message Interface Operations */
+
+/**
+ *
+ * Update Security (mainly lock) Icon on the call bubble.
+ * NOTE: Only used to indicate media security (ENCRYPTED or not).
+ * For updating the signaling security(shield icon), use uiCallInfo or
+ * uiUpdateCallInfo.
+ *
+ * @param line - line identifier
+ * @param call_id - call identifier
+ * @param call_security - follows the cc_security_e enum
+ *
+ * @return none
+ */
+void
+ui_update_call_security (line_t line, callid_t call_id,
+ cc_security_e call_security)
+{
+ session_update_t msg;
+
+ TNP_DEBUG(DEB_L_C_F_PREFIX"security=%d\n", DEB_L_C_F_PREFIX_ARGS(UI_API, line, call_id, __FUNCTION__),
+ call_security);
+
+ msg.sessionID = createSessionId(line, call_id);
+ msg.eventID = CALL_SECURITY;
+ msg.update.ccSessionUpd.data.security = call_security;
+
+ if ( ccappTaskPostMsg(CCAPP_SESSION_UPDATE, &msg, sizeof(session_update_t), CCAPP_CCPROVIER) != CPR_SUCCESS ) {
+ CCAPP_ERROR(CCAPP_F_PREFIX"failed to send CALL_SECURITY(%d) msg \n", __FUNCTION__, call_security);
+ }
+}
+
+/*
+ *Just for TNP currently.
+ */
+void
+ui_update_conf_invoked (line_t line, callid_t call_id,
+ boolean invoked)
+{
+ //Nothing to do here
+}
+
+
+/**
+ *
+ * Cancel the feature plane given by call_id.
+ *
+ * @param line - line identifier
+ * @param call_id - call identifier
+ * @param target_call_id - target call id
+ *
+ * @return none
+ */
+void
+ui_terminate_feature (line_t line, callid_t call_id,
+ callid_t target_call_id)
+{
+ session_update_t msg;
+
+ TNP_DEBUG(DEB_L_C_F_PREFIX"target_call_id=%d\n", DEB_L_C_F_PREFIX_ARGS(UI_API, line, call_id, __FUNCTION__),
+ target_call_id);
+
+ msg.sessionID = createSessionId(line, call_id);
+ msg.eventID = CALL_FEATURE_CANCEL;
+ if (target_call_id != CC_NO_CALL_ID) {
+ msg.update.ccSessionUpd.data.target_sess_id = createSessionId(line, target_call_id);
+ } else {
+ msg.update.ccSessionUpd.data.target_sess_id = 0;
+ }
+
+ if ( ccappTaskPostMsg(CCAPP_SESSION_UPDATE, &msg, sizeof(session_update_t), CCAPP_CCPROVIER) != CPR_SUCCESS ) {
+ CCAPP_ERROR(CCAPP_F_PREFIX"failed to send CALL_FEATURE_CANCEL(%d) msg \n", __FUNCTION__, target_call_id);
+ }
+}
+
+/* APIs required for CTI operations */
+
+/* NOP for TNP: the speaker mode is set by media manager. if call control
+ * need to set the mode explicitely use vcm_set_speaker_mode.
+ */
+void
+ui_set_speaker_mode (boolean mode)
+{
+ return;
+}
+
+void
+ui_cfwdall_req (unsigned int line)
+{
+ lsm_clear_cfwd_all_ccm(line);
+ return;
+}
+
+
+/***********************************************************/
+
+char *
+Basic_is_phone_forwarded (line_t line)
+{
+ TNP_DEBUG(DEB_F_PREFIX"called for line %d\n", DEB_F_PREFIX_ARGS(UI_API, "Basic_is_phone_forwarded"), line);
+ return ((char *) lsm_is_phone_forwarded(line));
+}
+
+void
+ui_sip_config_done (void)
+{
+}
+
+/**
+ * convert to numeric dtmf tone code that ms
+ * understands from ascii code
+ */
+static int map_digit(char k)
+{
+ switch(k) {
+ case '1':
+ return 1;
+ case '2':
+ return 2;
+ case '3':
+ return 3;
+ case '4':
+ return 4;
+ case '5':
+ return 5;
+ case '6':
+ return 6;
+ case '7':
+ return 7;
+ case '8':
+ return 8;
+ case '9':
+ return 9;
+ case '0':
+ return 0;
+ case '*':
+ return 10;
+ case'#':
+ return 11;
+ case 'A':
+ return 12;
+ case 'B':
+ return 13;
+ case 'C':
+ return 14;
+ case 'D':
+ return 15;
+ default:
+ return -1;
+ }
+}
+
+
+/**
+ * Emulate keypad button press
+ *
+ * @param digitstr - one or more digits to be pressed
+ * @param direction - either VCM_PLAY_TONE_TO_EAR or VCM_PLAY_TONE_TO_NET
+ * or VCM_PLAY_TONE_TO_ALL
+ *
+ * @return none
+ */
+void
+ui_keypad_button (char *digitstr, int direction)
+{
+ int digit;
+ unsigned int i;
+
+
+ for (i=0; iline, call_id, __FUNCTION__));
+
+ msg.sessionID = createSessionId(dcb->line, call_id);
+ msg.eventID = CALL_LOGDISP;
+ msg.update.ccSessionUpd.data.action = logdisp;
+
+ if ( ccappTaskPostMsg(CCAPP_SESSION_UPDATE, &msg, sizeof(session_update_t), CCAPP_CCPROVIER) != CPR_SUCCESS ) {
+ CCAPP_ERROR("%s: failed to send CALL_PRESERVATION_ACTIVE(%d) msg \n", __FUNCTION__, call_id);
+ }
+}
+
+/**
+ * Stub for ui_control_feature
+ *
+ * @param line_id - line identifier
+ * @param call_id - call identifier
+ * @param feature - name of the softkey set
+ * @param enable - enable/disable
+ *
+ * @return none
+ */
+void
+ui_control_feature (line_t line_id, callid_t call_id,
+ int feat_list[], int len, int enable)
+{
+ // do nothing.
+}
+
+/*
+ * Helper for the following four functions which all load up a
+ * session_update message and post it.
+ *
+ */
+static void post_message_helper(
+ group_call_event_t eventId,
+ call_events event,
+ line_t nLine,
+ callid_t nCallId,
+ uint16_t call_instance_id,
+ char *sdp,
+ cc_int32_t status)
+{
+ session_update_t msg;
+
+ if (nCallId == CC_NO_CALL_ID) {
+ /* no operation when no call ID */
+ return;
+ }
+
+ msg.sessionID = createSessionId(nLine, nCallId);
+
+ msg.eventID = eventId;
+ msg.update.ccSessionUpd.data.state_data.state = event;
+ msg.update.ccSessionUpd.data.state_data.inst = call_instance_id;
+ msg.update.ccSessionUpd.data.state_data.line_id = nLine;
+ msg.update.ccSessionUpd.data.state_data.sdp = sdp;
+ if (eventId == SET_LOCAL_DESC || eventId == SET_REMOTE_DESC) {
+ msg.update.ccSessionUpd.data.state_data.cause = status;
+ }
+
+ if ( ccappTaskPostMsg(CCAPP_SESSION_UPDATE, &msg, sizeof(session_update_t), CCAPP_CCPROVIER) != CPR_SUCCESS ) {
+ CCAPP_ERROR(CCAPP_F_PREFIX"failed to send CALL_STATE(%d) msg \n", __FUNCTION__, event);
+ }
+
+ return;
+}
+
+/**
+ * Send data from createOffer to the UI, can send success with SDP string
+ * or can send error
+ *
+ * @return none
+ */
+void ui_create_offer(call_events event, line_t nLine, callid_t nCallID,
+ uint16_t call_instance_id, char* sdp)
+{
+ TNP_DEBUG(DEB_L_C_F_PREFIX"state=%d attr=%d call_instance=%d\n",
+ DEB_L_C_F_PREFIX_ARGS(UI_API, nLine, nCallID, __FUNCTION__), event, call_instance_id);
+
+ post_message_helper(CREATE_OFFER, event, nLine, nCallID, call_instance_id, sdp, 0);
+
+ return;
+}
+
+/**
+ * Send data from createAnswer to the UI, can send success with SDP string
+ * or can send error
+ *
+ * @return none
+ */
+void ui_create_answer(call_events event, line_t nLine, callid_t nCallID,
+ uint16_t call_instance_id, char* sdp)
+{
+ TNP_DEBUG(DEB_L_C_F_PREFIX"state=%d call_instance=%d\n",
+ DEB_L_C_F_PREFIX_ARGS(UI_API, nLine, nCallID, __FUNCTION__), event, call_instance_id);
+
+ post_message_helper(CREATE_ANSWER, event, nLine, nCallID, call_instance_id, sdp, 0);
+
+ return;
+}
+
+/**
+ * Send data from setLocalDescription to the UI
+ *
+ * @return none
+ */
+
+void ui_set_local_description(call_events event, line_t nLine, callid_t nCallID,
+ uint16_t call_instance_id, char* sdp, cc_int32_t status)
+{
+ TNP_DEBUG(DEB_L_C_F_PREFIX"state=%d call_instance=%d\n",
+ DEB_L_C_F_PREFIX_ARGS(UI_API, nLine, nCallID, __FUNCTION__), event, call_instance_id);
+
+ post_message_helper(SET_LOCAL_DESC, event, nLine, nCallID, call_instance_id, sdp, status);
+
+ return;
+}
+
+/**
+ * Send data from setRemoteDescription to the UI
+ *
+ * @return none
+ */
+
+void ui_set_remote_description(call_events event, line_t nLine, callid_t nCallID,
+ uint16_t call_instance_id, char* sdp, cc_int32_t status)
+{
+ TNP_DEBUG(DEB_L_C_F_PREFIX"state=%d call_instance=%d\n",
+ DEB_L_C_F_PREFIX_ARGS(UI_API, nLine, nCallID, __FUNCTION__), event, call_instance_id);
+
+ post_message_helper(SET_REMOTE_DESC, event, nLine, nCallID, call_instance_id, sdp, status);
+
+ return;
+}
+
+
+/**
+ * Send Remote Stream data to the UI
+ *
+ * @return none
+ */
+
+void ui_on_remote_stream_added(call_events event, line_t nLine, callid_t nCallID, uint16_t call_instance_id, cc_media_remote_track_table_t media_track)
+{
+ session_update_t msg;
+ fsmdef_dcb_t *dcb = fsmdef_get_dcb_by_call_id(nCallID);
+
+ if (nCallID == CC_NO_CALL_ID || dcb == NULL) {
+ /* no operation when no call ID */
+ return;
+ }
+
+ TNP_DEBUG(DEB_L_C_F_PREFIX"state=%d call_instance=%d\n",
+ DEB_L_C_F_PREFIX_ARGS(UI_API, nLine, nCallID, __FUNCTION__), event, call_instance_id);
+
+
+ msg.sessionID = createSessionId(nLine, nCallID);
+
+ msg.eventID = REMOTE_STREAM_ADD;
+ msg.update.ccSessionUpd.data.state_data.state = event;
+ msg.update.ccSessionUpd.data.state_data.inst = call_instance_id;
+ msg.update.ccSessionUpd.data.state_data.line_id = nLine;
+ msg.update.ccSessionUpd.data.state_data.media_stream_track_id = media_track.track[0].media_stream_track_id;
+ msg.update.ccSessionUpd.data.state_data.media_stream_id = (unsigned int)media_track.media_stream_id;
+
+ if ( ccappTaskPostMsg(CCAPP_SESSION_UPDATE, &msg, sizeof(session_update_t), CCAPP_CCPROVIER) != CPR_SUCCESS ) {
+ CCAPP_ERROR(CCAPP_F_PREFIX"failed to send CALL_STATE(%d) msg \n", __FUNCTION__, event);
+ }
+
+ return;
+}
diff --git a/libs/sipcc/core/gsm/ccapi.c b/libs/sipcc/core/gsm/ccapi.c
new file mode 100755
index 0000000000..9f9a65800c
--- /dev/null
+++ b/libs/sipcc/core/gsm/ccapi.c
@@ -0,0 +1,1749 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "cpr_types.h"
+#include "cpr_stdio.h"
+#include "cpr_string.h"
+#include "cpr_memory.h"
+#include "cpr_stdlib.h"
+#include "ccapi.h"
+#include "ccsip_task.h"
+#include "debug.h"
+#include "phone_debug.h"
+#include "phntask.h"
+#include "phone.h"
+#include "text_strings.h"
+#include "string_lib.h"
+#include "gsm.h"
+#include "vcm.h"
+#include "sip_common_regmgr.h"
+#include "util_string.h"
+
+static const char *cc_src_names[] = {
+ "GSM",
+ "UI",
+ "SIP",
+ "MISC_APP",
+ "CCAPP"
+};
+
+#define CC_DEBUG_ENTRY(__FUNCTION__, src_id, dst_id, call_id, line, msg) \
+ DEF_DEBUG(DEB_L_C_F_PREFIX"%s -> %s: %-20s\n",\
+ DEB_L_C_F_PREFIX_ARGS(CC_API, line, call_id, __FUNCTION__),\
+ cc_src_name(src_id), cc_src_name(dst_id), msg)
+
+
+callid_t cc_get_new_call_id (void)
+{
+ static callid_t call_id = CC_NO_CALL_ID;
+
+ if (++call_id == 0) {
+ call_id = 1;
+ }
+
+ return call_id;
+}
+
+
+const char *
+cc_src_name (cc_srcs_t id)
+{
+ if ((id <= CC_SRC_MIN) || (id >= CC_SRC_MAX)) {
+ return get_debug_string(GSM_UNDEFINED);
+ }
+
+ return cc_src_names[id];
+}
+
+
+static void
+cc_print_msg (char *pData, int len)
+{
+ int ix;
+ int msg_id = *((int *) pData);
+
+ buginf("\n" CCA_F_PREFIX "cc_msg= %s, 0x=", __FUNCTION__,
+ cc_msg_name((cc_msgs_t) msg_id));
+ for (ix = 0; ix < len; ix++) {
+ if ((ix % 8 == 0) && ix) {
+ buginf(" ");
+ }
+ if (ix % 24 == 0) {
+ buginf("\n");
+ }
+ buginf("%02x ", *pData++);
+ }
+ buginf("\n");
+}
+
+
+/*
+ * Return a SysBuf and initialize
+ * Parameters supplied by application:
+ * - MinSize: size of buffer requested
+ */
+cprBuffer_t
+cc_get_msg_buf (int min_size)
+{
+ cprBuffer_t buf;
+
+ if (min_size > CPR_MAX_MSG_SIZE) {
+ /* Size requested exceeds maximum ethernet buffer */
+ GSM_ERR_MSG(get_debug_string(DEBUG_MSG_BUFFER_TOO_BIG),
+ __FUNCTION__, min_size);
+ return (cprBuffer_t)NULL;
+ }
+
+ buf = gsm_get_buffer((uint16_t) min_size);
+ if (!buf) {
+ GSM_ERR_MSG(get_debug_string(DEBUG_SYSBUF_UNAVAILABLE), __FUNCTION__);
+ return (cprBuffer_t)NULL;
+ }
+
+ /* Clean out the data region of the message */
+ memset(buf, 0, min_size);
+
+ CC_DEBUG(DEB_F_PREFIX "Msg id = 0x%0x\n", DEB_F_PREFIX_ARGS(CC_API, __FUNCTION__), buf);
+
+ return buf;
+}
+
+static cc_rcs_t
+cc_send_cmd_msg (uint32_t cmd, cprBuffer_t buf, uint16_t len, cc_srcs_t dst_id)
+{
+ cpr_status_e rc;
+
+ CC_DEBUG_MSG cc_print_msg((char *) buf, len);
+
+ switch (dst_id) {
+ case CC_SRC_GSM:
+ rc = gsm_send_msg(cmd, buf, len);
+ if (rc == CPR_FAILURE) {
+ cc_free_msg_data((cc_msg_t *) buf);
+ cpr_free(buf);
+ }
+ break;
+ case CC_SRC_SIP:
+ rc = SIPTaskSendMsg(cmd, buf, len, NULL);
+ if (rc == CPR_FAILURE) {
+ cc_free_msg_data((cc_msg_t *) buf);
+ cpr_free(buf);
+ }
+ break;
+ default:
+ rc = CPR_FAILURE;
+ break;
+ }
+
+ return (rc == CPR_SUCCESS) ? CC_RC_SUCCESS : CC_RC_ERROR;
+}
+
+static cc_rcs_t
+cc_send_msg (cprBuffer_t buf, uint16_t len, cc_srcs_t dst_id)
+{
+ cpr_status_e rc;
+
+ CC_DEBUG_MSG cc_print_msg((char *) buf, len);
+
+ switch (dst_id) {
+ case CC_SRC_GSM:
+ rc = gsm_send_msg(GSM_SIP, buf, len);
+ if (rc == CPR_FAILURE) {
+ cc_free_msg_data((cc_msg_t *) buf);
+ cpr_free(buf);
+ }
+ break;
+ case CC_SRC_SIP:
+ rc = SIPTaskSendMsg(SIP_GSM, buf, len, NULL);
+ if (rc == CPR_FAILURE) {
+ cc_free_msg_data((cc_msg_t *) buf);
+ cpr_free(buf);
+ }
+ break;
+ default:
+ rc = CPR_FAILURE;
+ break;
+ }
+
+ return (rc == CPR_SUCCESS) ? CC_RC_SUCCESS : CC_RC_ERROR;
+}
+
+
+/*
+ * ROUTINE: cc_initialize_msg_body_parts_info
+ *
+ * DESCRIPTION: Initializes the msg body part.
+ *
+ * PARAMETERS:
+ * msg_body - pointer to cc_msgbody_info_t to be initialized.
+ *
+ * RETURNS:
+ * None.
+ *
+ * NOTES: None
+ */
+void
+cc_initialize_msg_body_parts_info (cc_msgbody_info_t *msg_body)
+{
+ if (msg_body == NULL) {
+ return;
+ }
+ msg_body->num_parts = 0;
+ memset(&msg_body->parts[0], 0, sizeof(msg_body->parts));
+}
+
+/*
+ * ROUTINE: cc_mv_msg_body_parts
+ *
+ * DESCRIPTION: Move the body parts from source to destination.
+ *
+ * PARAMETERS:
+ * dst_msg - pointer to destination cc_msgbody_info_t
+ * src_msg - pointer to source cc_msgbody_info_t
+ *
+ * RETURNS:
+ * None
+ *
+ * NOTES: The function attempts to free the message bodies
+ * that might be in the destination to prevent
+ * memory leak from overridden the destination by
+ * moving the new message source.
+ *
+ * The dst_msg must be pointed to the initialized
+ * message block either with all zero or at least
+ * number of parts is set to zero to prevent
+ * freeing an invalid address.
+ */
+void
+cc_mv_msg_body_parts (cc_msgbody_info_t *dst_msg, cc_msgbody_info_t *src_msg)
+{
+ if (dst_msg == NULL) {
+ GSM_ERR_MSG(CCA_F_PREFIX "dst is NULL\n", __FUNCTION__);
+ return;
+ }
+
+ /* Free the msg. bodies that might be in the dest first */
+ cc_free_msg_body_parts(dst_msg);
+
+ if (src_msg != NULL) {
+ /* copy all of the parts */
+ *dst_msg = *src_msg;
+ src_msg->num_parts = 0;
+ }
+}
+
+/*
+ * ROUTINE: cc_free_msg_body_parts
+ *
+ * DESCRIPTION: Free elements in the msg body part structure.
+ *
+ * PARAMETERS:
+ * msg_body - pointer to cc_msgbody_info_t for freeing.
+ *
+ * RETURNS:
+ * None
+ *
+ * NOTES: None
+ */
+void
+cc_free_msg_body_parts (cc_msgbody_info_t *msg_body)
+{
+ cc_msgbody_t *part;
+
+ if ((msg_body == NULL) || (msg_body->num_parts == 0)) {
+ /* Nothing to be freed */
+ return;
+ }
+
+ /* Free all of the bodies and their contents */
+ part = &msg_body->parts[0];
+ for (; msg_body->num_parts; msg_body->num_parts--, part++) {
+ if (part->body != NULL) {
+ cpr_free(part->body);
+ part->body = NULL;
+ }
+ if (part->content_id != NULL) {
+ cpr_free(part->content_id);
+ part->content_id = NULL;
+ }
+ }
+}
+
+/*
+ * ROUTINE: cc_get_msg_body_info_ptr_from_feature_data
+ *
+ * DESCRIPTION: The function gets msg pointer from a cc_feature_data_t
+ * structure if there is one. The msg body
+ * info does not aways attach to all features
+ * i.e. only certain feature IDs have msg body
+ * in the feature data. The function returns
+ * pointer to the msg body if the feature has
+ * valid data and for those features that contain
+ * msg body.
+ *
+ * PARAMETERS:
+ * id - cc_feature_t.
+ * data - pointer to cc_feature_data_t of the feature data to
+ * whose embedded resources need to be freed.
+ *
+ * RETURNS:
+ * msg_body - pointer to msg_body_info_t if there is
+ * a msg.
+ *
+ * NOTES: None
+ */
+static cc_msgbody_info_t *
+cc_get_msg_body_info_ptr_from_feature_data (cc_features_t id,
+ cc_feature_data_t *data)
+{
+ cc_msgbody_info_t *msg_body = NULL;
+
+ if (data == NULL) {
+ return (NULL);
+ }
+
+ switch (id) {
+ case CC_FEATURE_HOLD:
+ msg_body = &data->hold.msg_body;
+ break;
+ case CC_FEATURE_RESUME:
+ case CC_FEATURE_MEDIA:
+ msg_body = &data->resume.msg_body;
+ break;
+ case CC_FEATURE_UPDATE:
+ msg_body = &data->update.msg_body;
+ break;
+ default:
+ /*
+ * Other ones do not have msg body info yet, add the handling here
+ * when adding feature that needs msg body info.
+ */
+ break;
+ }
+ return (msg_body);
+}
+
+/*
+ * ROUTINE: cc_cp_caller
+ *
+ * DESCRIPTION: Copy caller ID and other fields from source to destination.
+ *
+ * PARAMETERS:
+ * dst_caller - pointer to destination cc_caller_id_t
+ * src_caller - pointer to source cc_caller_id_t
+ *
+ * RETURNS:
+ * None
+ *
+ * Note: See also cc_mv_caller_id() cc_free_caller().
+ */
+static void
+cc_cp_caller (cc_caller_id_t *dst_caller, cc_caller_id_t *src_caller)
+{
+ if ((src_caller == NULL) || (dst_caller == NULL)) {
+ return;
+ }
+
+ dst_caller->calling_name = strlib_empty();
+ if (src_caller->calling_name != NULL) {
+ dst_caller->calling_name = strlib_update(dst_caller->calling_name,
+ src_caller->calling_name);
+ }
+
+ dst_caller->calling_number = strlib_empty();
+ if (src_caller->calling_number != NULL) {
+ dst_caller->calling_number = strlib_update(dst_caller->calling_number,
+ src_caller->calling_number);
+ }
+
+ dst_caller->alt_calling_number = strlib_empty();
+ if (src_caller->alt_calling_number != NULL) {
+ dst_caller->alt_calling_number = strlib_update(dst_caller->alt_calling_number,
+ src_caller->alt_calling_number);
+ }
+
+ dst_caller->called_name = strlib_empty();
+ if (src_caller->called_name != NULL) {
+ dst_caller->called_name = strlib_update(dst_caller->called_name,
+ src_caller->called_name);
+ }
+
+ dst_caller->called_number = strlib_empty();
+ if (src_caller->called_number != NULL) {
+ dst_caller->called_number = strlib_update(dst_caller->called_number,
+ src_caller->called_number);
+ }
+
+ dst_caller->orig_called_name = strlib_empty();
+ if (src_caller->orig_called_name != NULL) {
+ dst_caller->orig_called_name =
+ strlib_update(dst_caller->orig_called_name,
+ src_caller->orig_called_name);
+ }
+
+ dst_caller->orig_called_number = strlib_empty();
+ if (src_caller->orig_called_number != NULL) {
+ dst_caller->orig_called_number =
+ strlib_update(dst_caller->orig_called_number,
+ src_caller->orig_called_number);
+ }
+
+ dst_caller->last_redirect_name = strlib_empty();
+ if (src_caller->last_redirect_name != NULL) {
+ dst_caller->last_redirect_name =
+ strlib_update(dst_caller->last_redirect_name,
+ src_caller->last_redirect_name);
+ }
+
+ dst_caller->last_redirect_number = strlib_empty();
+ if (src_caller->last_redirect_number) {
+ dst_caller->last_redirect_number =
+ strlib_update(dst_caller->last_redirect_number,
+ src_caller->last_redirect_number);
+ }
+
+ dst_caller->orig_rpid_number = strlib_empty();
+ if (src_caller->orig_rpid_number != NULL) {
+ dst_caller->orig_rpid_number =
+ strlib_update(dst_caller->orig_rpid_number,
+ src_caller->orig_rpid_number);
+ }
+ dst_caller->display_calling_number = src_caller->display_calling_number;
+ dst_caller->display_called_number = src_caller->display_called_number;
+ dst_caller->call_type = src_caller->call_type;
+ dst_caller->call_instance_id = src_caller->call_instance_id;
+}
+
+/*
+ * ROUTINE: cc_mv_caller_id
+ *
+ * DESCRIPTION: Move caller ID fields from source to destination.
+ * The caller ID fields from the destination will be
+ * freed if necessary prior to the move. This allows
+ * caller to replace the older IDs with the new IDs
+ * without data duplication.
+ *
+ * PARAMETERS:
+ * dst_caller - pointer to destination cc_caller_id_t
+ * src_caller - pointer to source cc_caller_id_t
+ *
+ * RETURNS:
+ * None
+ *
+ * Note: See also cc_cp_caller() cc_free_caller().
+ */
+void
+cc_mv_caller_id (cc_caller_id_t *dst_caller, cc_caller_id_t *src_caller)
+{
+ if ((src_caller == NULL) || (dst_caller == NULL)) {
+ return;
+ }
+
+ /*
+ * Move the IDs from the source to the destination.
+ * After moved the IDs from the source to the destination then
+ * the source needs to be NULL.
+ */
+ if (src_caller->calling_name != NULL) {
+ if (dst_caller->calling_name != NULL) {
+ strlib_free(dst_caller->calling_name);
+ }
+ dst_caller->calling_name = src_caller->calling_name;
+ src_caller->calling_name = NULL;
+ }
+
+ if (src_caller->calling_number != NULL) {
+ if (dst_caller->calling_number != NULL) {
+ strlib_free(dst_caller->calling_number);
+ }
+ dst_caller->calling_number = src_caller->calling_number;
+ src_caller->calling_number = NULL;
+ }
+
+ if (src_caller->alt_calling_number != NULL) {
+ if (dst_caller->alt_calling_number != NULL) {
+ strlib_free(dst_caller->alt_calling_number);
+ }
+ dst_caller->alt_calling_number = src_caller->alt_calling_number;
+ src_caller->alt_calling_number = NULL;
+ }
+
+ if (src_caller->called_name != NULL) {
+ if (dst_caller->called_name != NULL) {
+ strlib_free(dst_caller->called_name);
+ }
+ dst_caller->called_name = src_caller->called_name;
+ src_caller->called_name = NULL;
+ }
+
+ if (src_caller->called_number != NULL) {
+ if (dst_caller->called_number != NULL) {
+ strlib_free(dst_caller->called_number);
+ }
+ dst_caller->called_number = src_caller->called_number;
+ src_caller->called_number = NULL;
+ }
+
+ if (src_caller->orig_called_name != NULL) {
+ if (dst_caller->orig_called_name != NULL) {
+ strlib_free(dst_caller->orig_called_name);
+ }
+ dst_caller->orig_called_name = src_caller->orig_called_name;
+ src_caller->orig_called_name = NULL;
+ }
+
+ if (src_caller->orig_called_number != NULL) {
+ if (dst_caller->orig_called_number != NULL) {
+ strlib_free(dst_caller->orig_called_number);
+ }
+ dst_caller->orig_called_number = src_caller->orig_called_number;
+ src_caller->orig_called_number = NULL;
+ }
+
+ if (src_caller->last_redirect_name != NULL) {
+ if (dst_caller->last_redirect_name != NULL) {
+ strlib_free(dst_caller->last_redirect_name);
+ }
+ dst_caller->last_redirect_name = src_caller->last_redirect_name;
+ src_caller->last_redirect_name = NULL;
+ }
+
+ if (src_caller->last_redirect_number != NULL) {
+ if (dst_caller->last_redirect_number != NULL) {
+ strlib_free(dst_caller->last_redirect_number);
+ }
+ dst_caller->last_redirect_number = src_caller->last_redirect_number;
+ src_caller->last_redirect_number = NULL;
+ }
+
+ if (src_caller->orig_rpid_number != NULL) {
+ if (dst_caller->orig_rpid_number != NULL) {
+ strlib_free(dst_caller->orig_rpid_number);
+ }
+ dst_caller->orig_rpid_number = src_caller->orig_rpid_number;
+ src_caller->orig_rpid_number = NULL;
+ }
+ dst_caller->display_calling_number = src_caller->display_calling_number;
+ dst_caller->display_called_number = src_caller->display_called_number;
+}
+
+/*
+ * ROUTINE: cc_free_caller_id
+ *
+ * DESCRIPTION: Free caller ID fields. The IDs that are not NULL IDs will be
+ * freed because others might have been moved already.
+ *
+ * PARAMETERS:
+ * caller - pointer to destination cc_caller_id_t
+ *
+ * RETURNS:
+ * None
+ *
+ * Note: See also cc_cp_caller() cc_mv_caller().
+ */
+static void
+cc_free_caller_id (cc_caller_id_t *caller)
+{
+ if (caller == NULL) {
+ return;
+ }
+
+ if (caller->calling_name != NULL) {
+ strlib_free(caller->calling_name);
+ }
+
+ if (caller->calling_number != NULL) {
+ strlib_free(caller->calling_number);
+ }
+
+ if (caller->alt_calling_number != NULL) {
+ strlib_free(caller->alt_calling_number);
+ }
+
+ if (caller->called_name != NULL) {
+ strlib_free(caller->called_name);
+ }
+
+ if (caller->called_number != NULL) {
+ strlib_free(caller->called_number);
+ }
+
+ if (caller->orig_called_name != NULL) {
+ strlib_free(caller->orig_called_name);
+ }
+
+ if (caller->orig_called_number != NULL) {
+ strlib_free(caller->orig_called_number);
+ }
+
+ if (caller->last_redirect_name != NULL) {
+ strlib_free(caller->last_redirect_name);
+ }
+
+ if (caller->last_redirect_number) {
+ strlib_free(caller->last_redirect_number);
+ }
+
+ if (caller->orig_rpid_number != NULL) {
+ strlib_free(caller->orig_rpid_number);
+ }
+}
+
+/*
+ * ROUTINE: cc_free_msg_data
+ *
+ * DESCRIPTION: Free resources embedded in CCAPI msg. data
+ * structure.
+ *
+ * PARAMETERS:
+ * data - pointer to cc_msg_t whose embedded resources
+ * need to be freed.
+ *
+ * RETURNS:
+ * None
+ */
+void
+cc_free_msg_data (cc_msg_t *msg)
+{
+ cc_msgbody_info_t *msg_body = NULL;
+ cc_caller_id_t *caller_id = NULL;
+
+ if (msg == NULL) {
+ return;
+ }
+ switch (msg->msg.setup.msg_id) {
+ case CC_MSG_SETUP:
+ msg_body = &msg->msg.setup.msg_body;
+ caller_id = &msg->msg.setup.caller_id;
+ strlib_free(msg->msg.setup.recv_info_list);
+ break;
+ case CC_MSG_SETUP_ACK:
+ msg_body = &msg->msg.setup_ack.msg_body;
+ caller_id = &msg->msg.setup_ack.caller_id;
+ break;
+ case CC_MSG_PROCEEDING:
+ caller_id = &msg->msg.proceeding.caller_id;
+ break;
+ case CC_MSG_ALERTING:
+ msg_body = &msg->msg.alerting.msg_body;
+ caller_id = &msg->msg.alerting.caller_id;
+ break;
+ case CC_MSG_CONNECTED:
+ msg_body = &msg->msg.connected.msg_body;
+ caller_id = &msg->msg.connected.caller_id;
+ strlib_free(msg->msg.connected.recv_info_list);
+ break;
+ case CC_MSG_CONNECTED_ACK:
+ msg_body = &msg->msg.connected_ack.msg_body;
+ caller_id = &msg->msg.connected_ack.caller_id;
+ break;
+ case CC_MSG_FEATURE:
+ if (msg->msg.feature.data_valid) {
+ msg_body = cc_get_msg_body_info_ptr_from_feature_data(
+ msg->msg.feature.feature_id,
+ &msg->msg.feature.data);
+
+ if (msg->msg.feature.feature_id == CC_FEATURE_CALLINFO) {
+ caller_id = &msg->msg.feature.data.call_info.caller_id;
+ }
+ }
+ break;
+ case CC_MSG_FEATURE_ACK:
+ if (msg->msg.feature_ack.data_valid) {
+ msg_body = cc_get_msg_body_info_ptr_from_feature_data(
+ msg->msg.feature_ack.feature_id,
+ &msg->msg.feature_ack.data);
+ }
+ break;
+ case CC_MSG_OPTIONS_ACK:
+ msg_body = &msg->msg.options_ack.msg_body;
+ break;
+ case CC_MSG_AUDIT_ACK:
+ msg_body = &msg->msg.audit_ack.msg_body;
+ break;
+ case CC_MSG_INFO:
+ strlib_free(msg->msg.info.message_body);
+ strlib_free(msg->msg.info.content_type);
+ strlib_free(msg->msg.info.info_package);
+ break;
+ default:
+ return;
+ }
+ cc_free_msg_body_parts(msg_body);
+ cc_free_caller_id(caller_id);
+}
+
+/*
+ * ROUTINE: cc_cp_msg_body_parts
+ *
+ * DESCRIPTION: Copy elements in the msg body part structure.
+ *
+ * PARAMETERS:
+ * dst_msg - pointer to destination cc_msgbody_info_t
+ * src_msg - pointer to source cc_msgbody_info_t
+ *
+ * RETURNS:
+ * CC_RC_ERROR
+ * CC_RC_SUCCESS
+ *
+ * NOTES: The function attempts to free the message bodies
+ * that might be in the destination to prevent
+ * memory leak from overridden the destination by
+ * moving the new message source.
+ *
+ * The dst_msg must be pointed to the initialized
+ * message block either with all zero or at least
+ * number of parts is set to zero to prevent
+ * freeing an invalid address.
+ */
+cc_rcs_t
+cc_cp_msg_body_parts (cc_msgbody_info_t *dst_msg, cc_msgbody_info_t *src_msg)
+{
+ uint32_t i, body_length;
+ cc_msgbody_t *src_part, *dst_part;
+ cc_rcs_t status;
+ int len;
+
+ if ((dst_msg == NULL) || (src_msg == NULL)) {
+ return CC_RC_ERROR;
+ }
+ /* Free the msg. bodies that might be in the dest first */
+ cc_free_msg_body_parts(dst_msg);
+
+ src_part = &src_msg->parts[0];
+ dst_part = &dst_msg->parts[0];
+
+ /* Copy all of the fields of all body parts */
+ status = CC_RC_SUCCESS;
+ for (i = 0; i < src_msg->num_parts; i++, src_part++, dst_part++) {
+ dst_part->content_type = src_part->content_type;
+ dst_part->content_disposition = src_part->content_disposition;
+
+ /* Copy body */
+ dst_part->body = NULL;
+ dst_part->body_length = 0;
+ if ((src_part->body != NULL) && (src_part->body_length > 0)) {
+ body_length = src_part->body_length;
+ dst_part->body = (char *) cpr_malloc(body_length);
+
+ if (dst_part->body == NULL) {
+ /* Unable to allocate memory for body */
+ status = CC_RC_ERROR;
+ break;
+ } else {
+ /*
+ * Copy body including NULL char but the length field
+ * does not include the extra NULL char.
+ */
+ memcpy(dst_part->body, src_part->body, body_length);
+ dst_part->body_length = src_part->body_length;
+ }
+ }
+
+ dst_part->content_id = NULL;
+ /* Copy content ID */
+ if (src_part->content_id != NULL) {
+ len = strlen(src_part->content_id) + 1;
+ dst_part->content_id = (char *) cpr_malloc(len);
+ if (dst_part->content_id != NULL) {
+ memcpy(dst_part->content_id, src_part->content_id, len);
+ } else {
+ /* Unable to allocate memory for content ID */
+ status = CC_RC_ERROR;
+ break;
+ }
+ }
+ }
+ dst_msg->num_parts = i; /* number of part copied */
+ dst_msg->content_type = src_msg->content_type;
+
+ if (status != CC_RC_SUCCESS) {
+ /*
+ * Unable to duplicate the body parts, free all of the allocated
+ * resources
+ */
+ cc_free_msg_body_parts(dst_msg);
+ }
+ return status;
+}
+
+void
+cc_int_setup (cc_srcs_t src_id, cc_srcs_t dst_id, callid_t call_id,
+ line_t line, cc_caller_id_t *caller_id,
+ cc_alerting_type alert_info, vcm_ring_mode_t alerting_ring,
+ vcm_tones_t alerting_tone, cc_redirect_t *redirect,
+ cc_call_info_t *call_info_p, boolean replaces,
+ string_t recv_info_list, cc_msgbody_info_t *msg_body)
+{
+ cc_setup_t *pmsg;
+
+ if (caller_id == NULL) {
+ // nobody checks, CC_RC_ERROR, so generate error message
+ GSM_ERR_MSG("%s: caller id is NULL\n", __FUNCTION__);
+ return;
+ }
+
+ CC_DEBUG(DEB_L_C_F_PREFIX " CGPD= %s, CGPN= %s,\n CDPD= %s, CDPN= %s\n",
+ DEB_L_C_F_PREFIX_ARGS(CC_API, line, call_id, __FUNCTION__),
+ caller_id->calling_name, caller_id->calling_number,
+ caller_id->called_name, caller_id->called_number);
+
+ pmsg = (cc_setup_t *) cc_get_msg_buf(sizeof(*pmsg));
+ if (!pmsg) {
+ // nobody checks, CC_RC_ERROR, so generate error message
+ GSM_ERR_MSG(get_debug_string(CC_NO_MSG_BUFFER), __FUNCTION__);
+ return;
+ }
+
+ pmsg->msg_id = CC_MSG_SETUP;
+ pmsg->src_id = src_id;
+ pmsg->call_id = call_id;
+ pmsg->line = line;
+ pmsg->alert_info = alert_info;
+ pmsg->alerting_ring = alerting_ring;
+ pmsg->alerting_tone = alerting_tone;
+ cc_cp_caller(&pmsg->caller_id, caller_id);
+
+ pmsg->call_info.type = CC_FEAT_NONE;
+ if (call_info_p) {
+ pmsg->call_info = *call_info_p;
+ }
+
+ pmsg->replaces = replaces;
+
+ if (redirect != NULL) {
+ pmsg->redirect = *redirect;
+ }
+
+ /* Info Package */
+ if (recv_info_list && (*recv_info_list != '\0')) {
+ pmsg->recv_info_list = strlib_copy(recv_info_list);
+ } else {
+ pmsg->recv_info_list = strlib_empty();
+ }
+
+ /* Move body parts if there are any */
+ pmsg->msg_body.num_parts = 0;
+ cc_mv_msg_body_parts(&pmsg->msg_body, msg_body);
+
+ CC_DEBUG_ENTRY(__FUNCTION__, src_id, dst_id, call_id, line, cc_msg_name(pmsg->msg_id));
+
+ if (cc_send_msg((cprBuffer_t) pmsg, sizeof(*pmsg), dst_id) != CC_RC_SUCCESS) {
+ // nobody checks the return code, so generate error message
+ GSM_ERR_MSG(get_debug_string(CC_SEND_FAILURE), __FUNCTION__);
+ }
+ return;
+}
+
+
+void
+cc_int_setup_ack (cc_srcs_t src_id, cc_srcs_t dst_id, callid_t call_id,
+ line_t line, cc_caller_id_t *caller_id,
+ cc_msgbody_info_t *msg_body)
+{
+ cc_setup_ack_t *pmsg;
+
+ pmsg = (cc_setup_ack_t *) cc_get_msg_buf(sizeof(*pmsg));
+ if (!pmsg) {
+ // nobody checks, CC_RC_ERROR, so generate error message
+ GSM_ERR_MSG(get_debug_string(CC_NO_MSG_BUFFER), __FUNCTION__);
+ return;
+ }
+
+ pmsg->msg_id = CC_MSG_SETUP_ACK;
+ pmsg->src_id = src_id;
+ pmsg->call_id = call_id;
+ pmsg->line = line;
+ if (caller_id != NULL) {
+ cc_cp_caller(&pmsg->caller_id, caller_id);
+ }
+ /* Move body parts if there are any */
+ pmsg->msg_body.num_parts = 0;
+ cc_mv_msg_body_parts(&pmsg->msg_body, msg_body);
+
+ CC_DEBUG_ENTRY(__FUNCTION__, src_id, dst_id, call_id, line, cc_msg_name(pmsg->msg_id));
+
+ if (cc_send_msg((cprBuffer_t) pmsg, sizeof(*pmsg), dst_id) != CC_RC_SUCCESS) {
+ // nobody checks the return code, so generate error message
+ GSM_ERR_MSG(get_debug_string(CC_SEND_FAILURE), __FUNCTION__);
+ }
+}
+
+
+void
+cc_int_proceeding (cc_srcs_t src_id, cc_srcs_t dst_id, callid_t call_id,
+ line_t line, cc_caller_id_t *caller_id)
+{
+ cc_proceeding_t *pmsg;
+
+ pmsg = (cc_proceeding_t *) cc_get_msg_buf(sizeof(*pmsg));
+ if (!pmsg) {
+ // nobody checks, CC_RC_ERROR, so generate error message
+ GSM_ERR_MSG(get_debug_string(CC_NO_MSG_BUFFER), __FUNCTION__);
+ return;
+ }
+
+ pmsg->msg_id = CC_MSG_PROCEEDING;
+ pmsg->src_id = src_id;
+ pmsg->call_id = call_id;
+ pmsg->line = line;
+ if (caller_id != NULL) {
+ cc_cp_caller(&pmsg->caller_id, caller_id);
+ }
+
+ CC_DEBUG_ENTRY(__FUNCTION__, src_id, dst_id, call_id, line, cc_msg_name(pmsg->msg_id));
+
+ if (cc_send_msg(pmsg, sizeof(*pmsg), dst_id) != CC_RC_SUCCESS) {
+ // nobody checks the return code, so generate error message
+ GSM_ERR_MSG(get_debug_string(CC_SEND_FAILURE), __FUNCTION__);
+ }
+ return;
+}
+
+
+void
+cc_int_alerting (cc_srcs_t src_id, cc_srcs_t dst_id, callid_t call_id,
+ line_t line, cc_caller_id_t *caller_id,
+ cc_msgbody_info_t *msg_body, boolean inband)
+{
+ cc_alerting_t *pmsg;
+
+
+ pmsg = (cc_alerting_t *) cc_get_msg_buf(sizeof(*pmsg));
+ if (!pmsg) {
+ // nobody checks, CC_RC_ERROR, so generate error message
+ GSM_ERR_MSG(get_debug_string(CC_NO_MSG_BUFFER), __FUNCTION__);
+ return;
+ }
+
+ pmsg->msg_id = CC_MSG_ALERTING;
+ pmsg->src_id = src_id;
+ pmsg->call_id = call_id;
+ pmsg->line = line;
+ if (caller_id != NULL) {
+ cc_cp_caller(&pmsg->caller_id, caller_id);
+ }
+ /* Move body parts if there are any */
+ pmsg->msg_body.num_parts = 0;
+ cc_mv_msg_body_parts(&pmsg->msg_body, msg_body);
+
+ pmsg->inband = inband;
+
+ CC_DEBUG_ENTRY(__FUNCTION__, src_id, dst_id, call_id, line, cc_msg_name(pmsg->msg_id));
+ CC_DEBUG(DEB_L_C_F_PREFIX " inband= %d\n",
+ DEB_L_C_F_PREFIX_ARGS(CC_API, line, call_id, __FUNCTION__), inband);
+
+ if (cc_send_msg((cprBuffer_t) pmsg, sizeof(*pmsg), dst_id) != CC_RC_SUCCESS) {
+ // nobody checks the return code, so generate error message
+ GSM_ERR_MSG(get_debug_string(CC_SEND_FAILURE), __FUNCTION__);
+ }
+ return;
+}
+
+
+void
+cc_int_connected (cc_srcs_t src_id, cc_srcs_t dst_id, callid_t call_id,
+ line_t line, cc_caller_id_t *caller_id,
+ string_t recv_info_list, cc_msgbody_info_t *msg_body)
+{
+ cc_connected_t *pmsg;
+
+ pmsg = (cc_connected_t *) cc_get_msg_buf(sizeof(*pmsg));
+ if (!pmsg) {
+ // nobody checks, CC_RC_ERROR, so generate error message
+ GSM_ERR_MSG(get_debug_string(CC_NO_MSG_BUFFER), __FUNCTION__);
+ return;
+ }
+
+ pmsg->msg_id = CC_MSG_CONNECTED;
+ pmsg->src_id = src_id;
+ pmsg->call_id = call_id;
+ pmsg->line = line;
+ if (caller_id != NULL) {
+ cc_cp_caller(&pmsg->caller_id, caller_id);
+ }
+
+ /* Info Package */
+ if (recv_info_list && (*recv_info_list != '\0')) {
+ pmsg->recv_info_list = strlib_copy(recv_info_list);
+ } else {
+ pmsg->recv_info_list = strlib_empty();
+ }
+
+ /* Move body parts if there are any */
+ pmsg->msg_body.num_parts = 0;
+ cc_mv_msg_body_parts(&pmsg->msg_body, msg_body);
+
+ CC_DEBUG_ENTRY(__FUNCTION__, src_id, dst_id, call_id, line, cc_msg_name(pmsg->msg_id));
+
+ if (cc_send_msg((cprBuffer_t) pmsg, sizeof(*pmsg), dst_id) != CC_RC_SUCCESS) {
+ // nobody checks the return code, so generate error message
+ GSM_ERR_MSG(get_debug_string(CC_SEND_FAILURE), __FUNCTION__);
+ }
+ return;
+}
+
+
+void
+cc_int_connected_ack (cc_srcs_t src_id, cc_srcs_t dst_id, callid_t call_id,
+ line_t line, cc_caller_id_t *caller_id,
+ cc_msgbody_info_t *msg_body)
+{
+ cc_connected_ack_t *pmsg;
+
+ pmsg = (cc_connected_ack_t *) cc_get_msg_buf(sizeof(*pmsg));
+ if (!pmsg) {
+ // nobody checks, CC_RC_ERROR, so generate error message
+ GSM_ERR_MSG(get_debug_string(CC_NO_MSG_BUFFER), __FUNCTION__);
+ return;
+ }
+
+ pmsg->msg_id = CC_MSG_CONNECTED_ACK;
+ pmsg->src_id = src_id;
+ pmsg->call_id = call_id;
+ pmsg->line = line;
+ if (caller_id != NULL) {
+ cc_cp_caller(&pmsg->caller_id, caller_id);
+ }
+ /* Move body parts if there are any */
+ pmsg->msg_body.num_parts = 0;
+ cc_mv_msg_body_parts(&pmsg->msg_body, msg_body);
+
+ CC_DEBUG_ENTRY(__FUNCTION__, src_id, dst_id, call_id, line, cc_msg_name(pmsg->msg_id));
+
+ if (cc_send_msg((cprBuffer_t) pmsg, sizeof(*pmsg), dst_id) != CC_RC_SUCCESS) {
+ // nobody checks the return code, so generate error message
+ GSM_ERR_MSG(get_debug_string(CC_SEND_FAILURE), __FUNCTION__);
+ }
+ return;
+}
+
+
+void
+cc_int_release (cc_srcs_t src_id, cc_srcs_t dst_id, callid_t call_id,
+ line_t line, cc_causes_t cause, const char *dialstring,
+ cc_kfact_t *kfactor)
+{
+ cc_release_t *pmsg;
+
+ if (dialstring == NULL) {
+ CC_DEBUG(DEB_L_C_F_PREFIX " cause= %s\n",
+ DEB_L_C_F_PREFIX_ARGS(CC_API, line, call_id, __FUNCTION__), cc_cause_name(cause));
+ } else {
+ CC_DEBUG(DEB_L_C_F_PREFIX " cause= %s, dialstring= %s\n",
+ DEB_L_C_F_PREFIX_ARGS(CC_API, line, call_id, __FUNCTION__), cc_cause_name(cause), dialstring);
+ }
+
+ pmsg = (cc_release_t *) cc_get_msg_buf(sizeof(*pmsg));
+ if (!pmsg) {
+ // nobody checks, CC_RC_ERROR, so generate error message
+ GSM_ERR_MSG(get_debug_string(CC_NO_MSG_BUFFER), __FUNCTION__);
+ return;
+ }
+
+ pmsg->msg_id = CC_MSG_RELEASE;
+ pmsg->src_id = src_id;
+ pmsg->call_id = call_id;
+ pmsg->line = line;
+ pmsg->cause = cause;
+
+ if (dialstring) {
+ sstrncpy(pmsg->dialstring, dialstring, CC_MAX_DIALSTRING_LEN);
+ }
+ if (kfactor != NULL) {
+ sstrncpy(pmsg->kfactor.rxstats, kfactor->rxstats, CC_KFACTOR_STAT_LEN);
+ sstrncpy(pmsg->kfactor.txstats, kfactor->txstats, CC_KFACTOR_STAT_LEN);
+ }
+
+ CC_DEBUG_ENTRY(__FUNCTION__, src_id, dst_id, call_id, line, cc_msg_name(pmsg->msg_id));
+
+ if (cc_send_msg((cprBuffer_t) pmsg, sizeof(*pmsg), dst_id) != CC_RC_SUCCESS) {
+ // nobody checks the return code, so generate error message
+ GSM_ERR_MSG(get_debug_string(CC_SEND_FAILURE), __FUNCTION__);
+ }
+ return;
+}
+
+
+void
+cc_int_release_complete (cc_srcs_t src_id, cc_srcs_t dst_id,
+ callid_t call_id, line_t line, cc_causes_t cause,
+ cc_kfact_t *kfactor)
+{
+ cc_release_complete_t *pmsg;
+
+
+ pmsg = (cc_release_complete_t *) cc_get_msg_buf(sizeof(*pmsg));
+ if (!pmsg) {
+ // nobody checks, CC_RC_ERROR, so generate error message
+ GSM_ERR_MSG(get_debug_string(CC_NO_MSG_BUFFER), __FUNCTION__);
+ return;
+ }
+
+ pmsg->msg_id = CC_MSG_RELEASE_COMPLETE;
+ pmsg->src_id = src_id;
+ pmsg->call_id = call_id;
+ pmsg->line = line;
+ pmsg->cause = cause;
+ if (kfactor != NULL) {
+ sstrncpy(pmsg->kfactor.rxstats, kfactor->rxstats, CC_KFACTOR_STAT_LEN);
+ sstrncpy(pmsg->kfactor.txstats, kfactor->txstats, CC_KFACTOR_STAT_LEN);
+ }
+
+ CC_DEBUG_ENTRY(__FUNCTION__, src_id, dst_id, call_id, line, cc_msg_name(pmsg->msg_id));
+ CC_DEBUG(DEB_L_C_F_PREFIX " cause= %s\n",
+ DEB_L_C_F_PREFIX_ARGS(CC_API, line, call_id, __FUNCTION__), cc_cause_name(cause));
+
+ if (cc_send_msg((cprBuffer_t) pmsg, sizeof(*pmsg), dst_id) != CC_RC_SUCCESS) {
+ // nobody checks the return code, so generate error message
+ GSM_ERR_MSG(get_debug_string(CC_SEND_FAILURE), __FUNCTION__);
+ }
+ return;
+}
+
+
+void
+cc_int_feature2 (cc_msgs_t msg_id, cc_srcs_t src_id, cc_srcs_t dst_id,
+ callid_t call_id, line_t line, cc_features_t feature_id,
+ cc_feature_data_t *data)
+{
+ cc_feature_t *pmsg;
+ cc_msgbody_info_t *msg_body;
+
+ pmsg = (cc_feature_t *) cc_get_msg_buf(sizeof(*pmsg));
+ if (!pmsg) {
+ // nobody checks, CC_RC_ERROR, so generate error message
+ GSM_ERR_MSG("%s: no buffer available for feat=%s\n", __FUNCTION__,
+ cc_feature_name(feature_id));
+ return;
+ }
+
+ pmsg->msg_id = msg_id;
+ pmsg->src_id = src_id;
+ pmsg->call_id = call_id;
+ pmsg->line = line;
+ pmsg->feature_id = feature_id;
+ pmsg->data_valid = (data == NULL) ? (FALSE) : (TRUE);
+
+ if (pmsg->data_valid == TRUE) {
+ pmsg->data = *data;
+ /*
+ * For call Info feature, need to copy the caller ID
+ */
+ if (feature_id == CC_FEATURE_CALLINFO) {
+ /* Copy the caller ID */
+ cc_cp_caller(&pmsg->data.call_info.caller_id,
+ &data->call_info.caller_id);
+ }
+ /*
+ * Clear the msg body from the source now since the msg. bodies
+ * has been transferred to to the CCAPI msg.
+ */
+ msg_body = cc_get_msg_body_info_ptr_from_feature_data(feature_id, data);
+ cc_initialize_msg_body_parts_info(msg_body);
+ }
+
+ if ((feature_id == CC_FEATURE_XFER) ||
+ (feature_id == CC_FEATURE_BLIND_XFER)) {
+ if (data != NULL) {
+ CC_DEBUG(DEB_L_C_F_PREFIX
+ "method= %d, call_id= %d, cause= %s dialstring= %s\n",
+ DEB_L_C_F_PREFIX_ARGS(CC_API, line, call_id, __FUNCTION__),
+ data->xfer.method, data->xfer.target_call_id,
+ cc_cause_name(data->xfer.cause), data->xfer.dialstring);
+ }
+ }
+ CC_DEBUG_ENTRY(__FUNCTION__, src_id, dst_id, call_id, line, cc_feature_name(feature_id));
+ CC_DEBUG(DEB_L_C_F_PREFIX "feature= %s, data= %p\n",
+ DEB_L_C_F_PREFIX_ARGS(CC_API, line, call_id, __FUNCTION__), cc_feature_name(feature_id), data);
+ if (cc_send_msg((cprBuffer_t) pmsg, sizeof(*pmsg), dst_id) != CC_RC_SUCCESS) {
+ // nobody checks the return code, so generate error message
+ GSM_ERR_MSG("%s: unable to send msg for feat=%s\n", __FUNCTION__,
+ cc_feature_name(feature_id));
+ }
+ return;
+}
+
+/*
+ * Helper function for the next six functions that populates and sends
+ * a feature message
+ *
+ */
+static void send_message_helper(
+ cc_msgs_t msg_id,
+ cc_srcs_t src_id,
+ cc_srcs_t dst_id,
+ callid_t call_id,
+ line_t line,
+ cc_features_t feature_id,
+ cc_feature_data_t *data,
+ string_t sdp,
+ cc_jsep_action_t action)
+{
+ cc_feature_t *pmsg;
+ cc_msgbody_info_t *msg_body;
+
+ pmsg = (cc_feature_t *) cc_get_msg_buf(sizeof(*pmsg));
+ if (!pmsg) {
+ GSM_ERR_MSG("%s: no buffer available for feat=%s\n", __FUNCTION__,
+ cc_feature_name(feature_id));
+ return;
+ }
+
+ pmsg->msg_id = msg_id;
+ pmsg->src_id = src_id;
+ pmsg->call_id = call_id;
+ pmsg->line = line;
+ pmsg->feature_id = feature_id;
+ pmsg->data_valid = (data == NULL) ? (FALSE) : (TRUE);
+
+ if (msg_id == CC_MSG_SETLOCALDESC || msg_id == CC_MSG_SETREMOTEDESC) {
+ pmsg->action = action;
+ }
+
+ if (msg_id == CC_MSG_CREATEANSWER || msg_id == CC_MSG_SETLOCALDESC || msg_id == CC_MSG_SETREMOTEDESC) {
+ sstrncpy(pmsg->sdp, sdp, sizeof(pmsg->sdp));
+ }
+
+ if (pmsg->data_valid == TRUE) {
+ pmsg->data = *data;
+ /*
+ * For call Info feature, need to copy the caller ID
+ */
+ if (feature_id == CC_FEATURE_CALLINFO) {
+ /* Copy the caller ID */
+ cc_cp_caller(&pmsg->data.call_info.caller_id,
+ &data->call_info.caller_id);
+ }
+ /*
+ * Clear the msg body from the source now since the msg. bodies
+ * has been transferred to to the CCAPI msg.
+ */
+ msg_body = cc_get_msg_body_info_ptr_from_feature_data(feature_id, data);
+ cc_initialize_msg_body_parts_info(msg_body);
+ }
+
+ CC_DEBUG_ENTRY(__FUNCTION__, src_id, dst_id, call_id, line, cc_feature_name(feature_id));
+ CC_DEBUG(DEB_L_C_F_PREFIX "feature= %s, data= %p\n",
+ DEB_L_C_F_PREFIX_ARGS(CC_API, line, call_id, __FUNCTION__), cc_feature_name(feature_id), data);
+ if (cc_send_msg((cprBuffer_t) pmsg, sizeof(*pmsg), dst_id) != CC_RC_SUCCESS) {
+ // nobody checks the return code, so generate error message
+ GSM_ERR_MSG("%s: unable to send msg for feat=%s\n", __FUNCTION__,
+ cc_feature_name(feature_id));
+ }
+
+ return;
+}
+
+void
+cc_createoffer (cc_srcs_t src_id, cc_srcs_t dst_id, callid_t call_id,
+ line_t line, cc_features_t feature_id, cc_feature_data_t *data)
+{
+ send_message_helper(CC_MSG_CREATEOFFER, src_id, dst_id, call_id, line,
+ feature_id, data, NULL, 0);
+
+ return;
+}
+
+
+void
+cc_createanswer (cc_srcs_t src_id, cc_srcs_t dst_id, callid_t call_id,
+ line_t line, cc_features_t feature_id, string_t sdp, cc_feature_data_t *data)
+{
+ send_message_helper(CC_MSG_CREATEANSWER, src_id, dst_id, call_id, line,
+ feature_id, data, sdp, 0);
+
+ return;
+}
+
+
+void cc_setlocaldesc (cc_srcs_t src_id, cc_srcs_t dst_id, callid_t call_id, line_t line,
+ cc_features_t feature_id, cc_jsep_action_t action, string_t sdp, cc_feature_data_t *data)
+{
+ send_message_helper(CC_MSG_SETLOCALDESC, src_id, dst_id, call_id, line,
+ feature_id, data, sdp, action);
+
+ return;
+}
+
+void cc_setremotedesc (cc_srcs_t src_id, cc_srcs_t dst_id, callid_t call_id, line_t line,
+ cc_features_t feature_id, cc_jsep_action_t action, string_t sdp, cc_feature_data_t *data)
+{
+ send_message_helper(CC_MSG_SETREMOTEDESC, src_id, dst_id, call_id, line,
+ feature_id, data, sdp, action);
+
+ return;
+}
+
+void cc_localdesc (cc_srcs_t src_id, cc_srcs_t dst_id, callid_t call_id, line_t line,
+ cc_features_t feature_id, cc_feature_data_t *data)
+{
+ send_message_helper(CC_MSG_LOCALDESC, src_id, dst_id, call_id, line,
+ feature_id, data, NULL, 0);
+
+ return;
+}
+
+void cc_remotedesc (cc_srcs_t src_id, cc_srcs_t dst_id, callid_t call_id, line_t line,
+ cc_features_t feature_id, cc_feature_data_t *data)
+{
+ send_message_helper(CC_MSG_REMOTEDESC, src_id, dst_id, call_id, line,
+ feature_id, data, NULL, 0);
+
+ return;
+}
+
+
+void
+cc_int_feature_ack (cc_srcs_t src_id, cc_srcs_t dst_id, callid_t call_id,
+ line_t line, cc_features_t feature_id,
+ cc_feature_data_t *data, cc_causes_t cause)
+{
+ cc_feature_ack_t *pmsg;
+ cc_msgbody_info_t *msg_body;
+
+ pmsg = (cc_feature_ack_t *) cc_get_msg_buf(sizeof(*pmsg));
+ if (!pmsg) {
+ // nobody checks, CC_RC_ERROR, so generate error message
+ GSM_ERR_MSG(get_debug_string(CC_NO_MSG_BUFFER), __FUNCTION__);
+ return;
+ }
+
+ pmsg->msg_id = CC_MSG_FEATURE_ACK;
+ pmsg->src_id = src_id;
+ pmsg->call_id = call_id;
+ pmsg->line = line;
+ pmsg->feature_id = feature_id;
+ pmsg->data_valid = (data == NULL) ? (FALSE) : (TRUE);
+
+ if (pmsg->data_valid == TRUE) {
+ pmsg->data = *data;
+ /*
+ * Clear the msg body from the source now since the msg. bodies
+ * has been transferred to to the CCAPI msg.
+ */
+ msg_body = cc_get_msg_body_info_ptr_from_feature_data(feature_id, data);
+ cc_initialize_msg_body_parts_info(msg_body);
+ }
+ pmsg->cause = cause;
+
+ if ((feature_id == CC_FEATURE_XFER) ||
+ (feature_id == CC_FEATURE_BLIND_XFER)) {
+ if (data != NULL) {
+ CC_DEBUG(DEB_L_C_F_PREFIX
+ "method= %d, call_id= %d, cause= %s dialstring= %s\n",
+ DEB_L_C_F_PREFIX_ARGS(CC_API, line, call_id, __FUNCTION__),
+ data->xfer.method, data->xfer.target_call_id,
+ cc_cause_name(data->xfer.cause), data->xfer.dialstring);
+ }
+ }
+
+ CC_DEBUG_ENTRY(__FUNCTION__, src_id, dst_id, call_id, line, cc_msg_name(pmsg->msg_id));
+ CC_DEBUG(DEB_L_C_F_PREFIX "feature= %s, data= %p, cause= %s\n",
+ DEB_L_C_F_PREFIX_ARGS(CC_API, line, call_id, __FUNCTION__), cc_feature_name(feature_id), data,
+ cc_cause_name(cause));
+
+ if (cc_send_msg((cprBuffer_t) pmsg, sizeof(*pmsg), dst_id) != CC_RC_SUCCESS) {
+ // nobody checks the return code, so generate error message
+ GSM_ERR_MSG(get_debug_string(CC_SEND_FAILURE), __FUNCTION__);
+ }
+ return;
+}
+
+
+void
+cc_int_offhook (cc_srcs_t src_id, cc_srcs_t dst_id, callid_t prim_call_id,
+ cc_hold_resume_reason_e consult_reason, callid_t call_id,
+ line_t line, char *global_call_id, monitor_mode_t monitor_mode,
+ cfwdall_mode_t cfwdall_mode)
+{
+ cc_offhook_t *pmsg;
+
+ pmsg = (cc_offhook_t *) cc_get_msg_buf(sizeof(*pmsg));
+ if (!pmsg) {
+ // nobody checks, CC_RC_ERROR, so generate error message
+ GSM_ERR_MSG(get_debug_string(CC_NO_MSG_BUFFER), __FUNCTION__);
+ return;
+ }
+
+ pmsg->msg_id = CC_MSG_OFFHOOK;
+ pmsg->src_id = src_id;
+ pmsg->call_id = call_id;
+ pmsg->line = line;
+ if (global_call_id != NULL) {
+ sstrncpy(pmsg->global_call_id, global_call_id, CC_GCID_LEN);
+ }
+ pmsg->prim_call_id = prim_call_id;
+ pmsg->hold_resume_reason = consult_reason;
+ pmsg->monitor_mode = monitor_mode;
+ pmsg->cfwdall_mode = cfwdall_mode;
+
+ CC_DEBUG_ENTRY(__FUNCTION__, src_id, dst_id, call_id, line, cc_msg_name(pmsg->msg_id));
+
+ if (cc_send_msg((cprBuffer_t) pmsg, sizeof(*pmsg), dst_id) != CC_RC_SUCCESS) {
+ // nobody checks the return code, so generate error message
+ GSM_ERR_MSG(get_debug_string(CC_SEND_FAILURE), __FUNCTION__);
+ }
+ return;
+}
+
+
+void
+cc_int_line (cc_srcs_t src_id, cc_srcs_t dst_id, callid_t call_id, line_t line)
+{
+ cc_line_t *pmsg;
+
+ pmsg = (cc_line_t *) cc_get_msg_buf(sizeof(*pmsg));
+ if (!pmsg) {
+ // nobody checks, CC_RC_ERROR, so generate error message
+ GSM_ERR_MSG(get_debug_string(CC_NO_MSG_BUFFER), __FUNCTION__);
+ return;
+ }
+
+ pmsg->msg_id = CC_MSG_LINE;
+ pmsg->src_id = src_id;
+ pmsg->call_id = call_id;
+ pmsg->line = line;
+
+ CC_DEBUG_ENTRY(__FUNCTION__, src_id, dst_id, call_id, line, cc_msg_name(pmsg->msg_id));
+
+ if (cc_send_msg((cprBuffer_t) pmsg, sizeof(*pmsg), dst_id) != CC_RC_SUCCESS) {
+ // nobody checks the return code, so generate error message
+ GSM_ERR_MSG(get_debug_string(CC_SEND_FAILURE), __FUNCTION__);
+ }
+ return;
+}
+
+
+void
+cc_int_onhook (cc_srcs_t src_id, cc_srcs_t dst_id, callid_t prim_call_id,
+ cc_hold_resume_reason_e consult_reason, callid_t call_id,
+ line_t line, boolean softkey, cc_onhook_reason_e active_list)
+{
+ cc_onhook_t *pmsg;
+
+ pmsg = (cc_onhook_t *) cc_get_msg_buf(sizeof(*pmsg));
+ if (!pmsg) {
+ // nobody checks, CC_RC_ERROR, so generate error message
+ GSM_ERR_MSG(get_debug_string(CC_NO_MSG_BUFFER), __FUNCTION__);
+ return;
+ }
+
+ pmsg->msg_id = CC_MSG_ONHOOK;
+ pmsg->src_id = src_id;
+ pmsg->call_id = call_id;
+ pmsg->line = line;
+ pmsg->softkey = softkey;
+ pmsg->prim_call_id = prim_call_id;
+ pmsg->hold_resume_reason = consult_reason;
+ pmsg->active_list = active_list;
+
+ CC_DEBUG_ENTRY(__FUNCTION__, src_id, dst_id, call_id, line, cc_msg_name(pmsg->msg_id));
+
+ if (cc_send_msg((cprBuffer_t) pmsg, sizeof(*pmsg), dst_id) != CC_RC_SUCCESS) {
+ // nobody checks the return code, so generate error message
+ GSM_ERR_MSG(get_debug_string(CC_SEND_FAILURE), __FUNCTION__);
+ }
+ return;
+}
+
+
+void
+cc_int_digit_begin (cc_srcs_t src_id, cc_srcs_t dst_id, callid_t call_id,
+ line_t line, int digit)
+{
+ cc_digit_begin_t *pmsg;
+
+ pmsg = (cc_digit_begin_t *) cc_get_msg_buf(sizeof(*pmsg));
+ if (!pmsg) {
+ // nobody checks, CC_RC_ERROR, so generate error message
+ GSM_ERR_MSG(get_debug_string(CC_NO_MSG_BUFFER), __FUNCTION__);
+ return;
+ }
+
+ pmsg->msg_id = CC_MSG_DIGIT_BEGIN;
+ pmsg->src_id = src_id;
+ pmsg->call_id = call_id;
+ pmsg->digit = digit;
+
+ CC_DEBUG_ENTRY(__FUNCTION__, src_id, dst_id, call_id, line, cc_msg_name(pmsg->msg_id));
+
+ if (cc_send_msg((cprBuffer_t) pmsg, sizeof(*pmsg), dst_id) != CC_RC_SUCCESS) {
+ // nobody checks the return code, so generate error message
+ GSM_ERR_MSG(get_debug_string(CC_SEND_FAILURE), __FUNCTION__);
+ }
+ return;
+}
+
+
+void
+cc_int_dialstring (cc_srcs_t src_id, cc_srcs_t dst_id, callid_t call_id,
+ line_t line, const char *dialstring, const char *g_call_id,
+ monitor_mode_t monitor_mode)
+{
+ cc_dialstring_t *pmsg;
+
+ if (dialstring == NULL) {
+ // nobody checks, CC_RC_ERROR, so generate error message
+ GSM_ERR_MSG("%s: no dialstring\n", __FUNCTION__);
+ return;
+ }
+
+ CC_DEBUG(DEB_L_C_F_PREFIX "dialstring= %s\n",
+ DEB_L_C_F_PREFIX_ARGS(CC_API, line, call_id, __FUNCTION__),dialstring);
+
+ pmsg = (cc_dialstring_t *) cc_get_msg_buf(sizeof(*pmsg));
+ if (!pmsg) {
+ // nobody checks, CC_RC_ERROR, so generate error message
+ GSM_ERR_MSG(get_debug_string(CC_NO_MSG_BUFFER), __FUNCTION__);
+ return;
+ }
+
+ pmsg->msg_id = CC_MSG_DIALSTRING;
+ pmsg->src_id = src_id;
+ pmsg->call_id = call_id;
+ pmsg->line = line;
+ sstrncpy(pmsg->dialstring, dialstring, CC_MAX_DIALSTRING_LEN);
+ sstrncpy(pmsg->g_call_id, g_call_id, CC_GCID_LEN);
+ pmsg->monitor_mode = monitor_mode;
+
+ CC_DEBUG_ENTRY(__FUNCTION__, src_id, dst_id, call_id, line, cc_msg_name(pmsg->msg_id));
+
+ if (cc_send_msg((cprBuffer_t) pmsg, sizeof(*pmsg), dst_id) != CC_RC_SUCCESS) {
+ // nobody checks the return code, so generate error message
+ GSM_ERR_MSG(get_debug_string(CC_SEND_FAILURE), __FUNCTION__);
+ }
+ return;
+}
+
+
+void
+cc_int_mwi (cc_srcs_t src_id, cc_srcs_t dst_id, callid_t call_id, line_t line,
+ boolean on, int type, int newCount, int oldCount, int hpNewCount, int hpOldCount)
+{
+ cc_mwi_t *pmsg;
+
+ pmsg = (cc_mwi_t *) cc_get_msg_buf(sizeof(*pmsg));
+ if (!pmsg) {
+ // nobody checks, CC_RC_ERROR, so generate error message
+ GSM_ERR_MSG(get_debug_string(CC_NO_MSG_BUFFER), __FUNCTION__);
+ return;
+ }
+
+ pmsg->msg_id = CC_MSG_MWI;
+ pmsg->src_id = src_id;
+ pmsg->call_id = call_id;
+ pmsg->line = line;
+ pmsg->msgSummary.on = on;
+ pmsg->msgSummary.type = type;
+ pmsg->msgSummary.newCount = newCount;
+ pmsg->msgSummary.oldCount = oldCount;
+ pmsg->msgSummary.hpNewCount = hpNewCount;
+ pmsg->msgSummary.hpOldCount = hpOldCount;
+
+ CC_DEBUG_ENTRY(__FUNCTION__, src_id, dst_id, call_id, line, cc_msg_name(pmsg->msg_id));
+ CC_DEBUG(DEB_L_C_F_PREFIX " mwi status= %d\n new count= %d old count= %d",
+ DEB_L_C_F_PREFIX_ARGS(CC_API, line, call_id, __FUNCTION__), on, newCount, oldCount);
+
+ if (cc_send_msg((cprBuffer_t) pmsg, sizeof(*pmsg), dst_id) != CC_RC_SUCCESS) {
+ // nobody checks the return code, so generate error message
+ GSM_ERR_MSG(get_debug_string(CC_SEND_FAILURE), __FUNCTION__);
+ }
+ return;
+}
+
+void
+cc_int_options_sdp_req (cc_srcs_t src_id, cc_srcs_t dst_id, callid_t call_id,
+ line_t line, void *pMessage)
+{
+ cc_options_sdp_req_t *pmsg;
+
+ pmsg = (cc_options_sdp_req_t *) cc_get_msg_buf(sizeof(*pmsg));
+ if (!pmsg) {
+ // nobody checks, CC_RC_ERROR, so generate error message
+ GSM_ERR_MSG(get_debug_string(CC_NO_MSG_BUFFER), __FUNCTION__);
+ return;
+ }
+
+ pmsg->msg_id = CC_MSG_OPTIONS;
+ pmsg->src_id = src_id;
+ pmsg->call_id = call_id;
+ pmsg->line = line;
+ pmsg->pMessage = pMessage;
+
+ CC_DEBUG_ENTRY(__FUNCTION__, src_id, dst_id, call_id, line, cc_msg_name(pmsg->msg_id));
+ CC_DEBUG(DEB_L_C_F_PREFIX " message ptr=%p\n",
+ DEB_L_C_F_PREFIX_ARGS(CC_API, line, call_id, __FUNCTION__), pMessage);
+
+ if (cc_send_msg((cprBuffer_t) pmsg, sizeof(*pmsg), dst_id) != CC_RC_SUCCESS) {
+ // nobody checks the return code, so generate error message
+ GSM_ERR_MSG(get_debug_string(CC_SEND_FAILURE), __FUNCTION__);
+ }
+ return;
+}
+
+void
+cc_int_options_sdp_ack (cc_srcs_t src_id, cc_srcs_t dst_id, callid_t call_id,
+ line_t line, void *pMessage, cc_msgbody_info_t *msg_body)
+{
+ cc_options_sdp_ack_t *pmsg;
+
+ pmsg = (cc_options_sdp_ack_t *) cc_get_msg_buf(sizeof(*pmsg));
+ if (!pmsg) {
+ // nobody checks, CC_RC_ERROR, so generate error message
+ GSM_ERR_MSG(get_debug_string(CC_NO_MSG_BUFFER), __FUNCTION__);
+ return;
+ }
+
+ pmsg->msg_id = CC_MSG_OPTIONS_ACK;
+ pmsg->src_id = src_id;
+ pmsg->call_id = call_id;
+ pmsg->line = line;
+ pmsg->pMessage = pMessage;
+ /* Move body parts if there are any */
+ pmsg->msg_body.num_parts = 0;
+ cc_mv_msg_body_parts(&pmsg->msg_body, msg_body);
+
+ CC_DEBUG_ENTRY(__FUNCTION__, src_id, dst_id, call_id, line, cc_msg_name(pmsg->msg_id));
+ CC_DEBUG(DEB_L_C_F_PREFIX " message ptr=%p\n",
+ DEB_L_C_F_PREFIX_ARGS(CC_API, line, call_id, __FUNCTION__), pMessage);
+
+ if (cc_send_msg((cprBuffer_t) pmsg, sizeof(*pmsg), dst_id) != CC_RC_SUCCESS) {
+ // nobody checks the return code, so generate error message
+ GSM_ERR_MSG(get_debug_string(CC_SEND_FAILURE), __FUNCTION__);
+ }
+ return;
+}
+
+void
+cc_int_audit_sdp_req (cc_srcs_t src_id, cc_srcs_t dst_id, callid_t call_id,
+ line_t line, boolean apply_ringout)
+{
+ cc_audit_sdp_req_t *pmsg;
+
+ pmsg = (cc_audit_sdp_req_t *) cc_get_msg_buf(sizeof(*pmsg));
+ if (!pmsg) {
+ // nobody checks, CC_RC_ERROR, so generate error message
+ GSM_ERR_MSG(get_debug_string(CC_NO_MSG_BUFFER), __FUNCTION__);
+ return;
+ }
+
+ pmsg->msg_id = CC_MSG_AUDIT;
+ pmsg->src_id = src_id;
+ pmsg->call_id = call_id;
+ pmsg->line = line;
+ pmsg->apply_ringout = apply_ringout;
+
+ CC_DEBUG_ENTRY(__FUNCTION__, src_id, dst_id, call_id, line, cc_msg_name(pmsg->msg_id));
+ CC_DEBUG(DEB_L_C_F_PREFIX "\n", DEB_L_C_F_PREFIX_ARGS(CC_API, line, call_id, __FUNCTION__));
+
+ if (cc_send_msg((cprBuffer_t) pmsg, sizeof(*pmsg), dst_id) != CC_RC_SUCCESS) {
+ // nobody checks the return code, so generate error message
+ GSM_ERR_MSG(get_debug_string(CC_SEND_FAILURE), __FUNCTION__);
+ }
+ return;
+}
+
+void
+cc_int_audit_sdp_ack (cc_srcs_t src_id, cc_srcs_t dst_id, callid_t call_id,
+ line_t line, cc_msgbody_info_t *msg_body)
+{
+ cc_audit_sdp_ack_t *pmsg;
+
+ pmsg = (cc_audit_sdp_ack_t *) cc_get_msg_buf(sizeof(*pmsg));
+ if (!pmsg) {
+ // nobody checks, CC_RC_ERROR, so generate error message
+ GSM_ERR_MSG(get_debug_string(CC_NO_MSG_BUFFER), __FUNCTION__);
+ return;
+ }
+
+ pmsg->msg_id = CC_MSG_AUDIT_ACK;
+ pmsg->src_id = src_id;
+ pmsg->call_id = call_id;
+ pmsg->line = line;
+ /* Move body parts if there are any */
+ pmsg->msg_body.num_parts = 0;
+ cc_mv_msg_body_parts(&pmsg->msg_body, msg_body);
+
+ CC_DEBUG_ENTRY(__FUNCTION__, src_id, dst_id, call_id, line, cc_msg_name(pmsg->msg_id));
+
+ if (cc_send_msg((cprBuffer_t) pmsg, sizeof(*pmsg), dst_id) != CC_RC_SUCCESS) {
+ // nobody checks the return code, so generate error message
+ GSM_ERR_MSG(get_debug_string(CC_SEND_FAILURE), __FUNCTION__);
+ }
+ return;
+}
+
+void
+cc_int_fail_fallback (cc_srcs_t src_id, cc_srcs_t dst_id, int rsp_type,
+ cc_regmgr_rsp_e rsp_id, boolean waited)
+{
+ cc_regmgr_t *pmsg;
+
+
+ pmsg = (cc_regmgr_t *) cc_get_msg_buf(sizeof(*pmsg));
+ if (!pmsg) {
+ // nobody checks, CC_RC_ERROR, so generate error message
+ GSM_ERR_MSG(get_debug_string(CC_NO_MSG_BUFFER), __FUNCTION__);
+ return;
+ }
+
+ pmsg->msg_id = CC_MSG_FAILOVER_FALLBACK;
+ pmsg->src_id = src_id;
+ pmsg->rsp_type = rsp_type;
+ pmsg->rsp_id = rsp_id;
+ pmsg->wait_flag = waited;
+
+ CC_DEBUG_ENTRY(__FUNCTION__, src_id, dst_id, 0, 0, cc_msg_name(pmsg->msg_id));
+ CC_DEBUG(DEB_F_PREFIX "rsp_type= %s rsp_id= %s waited = %d\n",
+ DEB_F_PREFIX_ARGS(CC_API, __FUNCTION__),
+ rsp_type == RSP_START ? "RSP_START" : "RSP_COMPLETE",
+ rsp_id == CC_REG_FAILOVER_RSP ? "REG_FAILOVER_RSP" : "REG_FALLBACK_RSP",
+ waited);
+
+ if (cc_send_cmd_msg(REG_MGR_STATE_CHANGE, (cprBuffer_t) pmsg,
+ sizeof(*pmsg), dst_id) != CC_RC_SUCCESS) {
+ // nobody checks the return code, so generate error message
+ GSM_ERR_MSG(get_debug_string(CC_SEND_FAILURE), __FUNCTION__);
+ }
+ return;
+}
+
+void
+cc_int_info (cc_srcs_t src_id, cc_srcs_t dst_id, callid_t call_id,
+ line_t line, string_t info_package, string_t content_type,
+ string_t message_body)
+{
+ cc_info_t *pmsg;
+
+
+ pmsg = (cc_info_t *) cc_get_msg_buf(sizeof(*pmsg));
+ if (!pmsg) {
+ // nobody checks, CC_RC_ERROR, so generate error message
+ GSM_ERR_MSG(get_debug_string(CC_NO_MSG_BUFFER), __FUNCTION__);
+ return;
+ }
+
+ pmsg->msg_id = CC_MSG_INFO;
+ pmsg->call_id = call_id;
+ pmsg->line = line;
+ pmsg->info_package = strlib_copy(info_package);
+ pmsg->content_type = strlib_copy(content_type);
+ pmsg->message_body = strlib_copy(message_body);
+
+ CC_DEBUG_ENTRY(__FUNCTION__, src_id, dst_id, call_id, line, cc_msg_name(pmsg->msg_id));
+
+ if (cc_send_msg((cprBuffer_t) pmsg, sizeof(*pmsg), dst_id) != CC_RC_SUCCESS) {
+ // nobody checks the return code, so generate error message
+ GSM_ERR_MSG(get_debug_string(CC_SEND_FAILURE), __FUNCTION__);
+ }
+ return;
+}
+
+void
+cc_init (void)
+{
+ /* Placeholder function for any initialization tasks */
+}
+
diff --git a/libs/sipcc/core/gsm/ccapi_strings.c b/libs/sipcc/core/gsm/ccapi_strings.c
new file mode 100644
index 0000000000..23e6da7d59
--- /dev/null
+++ b/libs/sipcc/core/gsm/ccapi_strings.c
@@ -0,0 +1,60 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "cpr_types.h"
+#define __CC_FEATURE_STRINGS__ // this is required to include feature strings.
+#define __CC_MESSAGES_STRINGS__ // this is required to include message strings.
+#define __CC_CAUSE_STRINGS__ // this is required to include cause strings.
+#include "text_strings.h"
+#include "ccapi.h"
+
+/**
+ * This function will be invoked by debug print functions.
+ *
+ * @param id - feature id
+ *
+ * @return feature name string.
+ */
+const char *cc_feature_name (cc_features_t id)
+{
+ if ((id <= CC_FEATURE_MIN) || (id >= CC_FEATURE_MAX)) {
+ return get_debug_string(GSM_UNDEFINED);
+ }
+
+ return cc_feature_names[id - CC_FEATURE_NONE];
+}
+
+
+/**
+ * This function will be invoked by debug print functions.
+ *
+ * @param id - cc msg id
+ *
+ * @return cc msg name string.
+ */
+const char *cc_msg_name (cc_msgs_t id)
+{
+ if ((id <= CC_MSG_MIN) || (id >= CC_MSG_MAX)) {
+ return get_debug_string(GSM_UNDEFINED);
+ }
+
+ return cc_msg_names[id];
+}
+
+/**
+ * This function will be invoked by debug print functions.
+ *
+ * @param id - cc cause id
+ *
+ * @return cc cause name string.
+ */
+const char *cc_cause_name (cc_causes_t id)
+{
+ if ((id <= CC_CAUSE_MIN) || (id >= CC_CAUSE_MAX)) {
+ return get_debug_string(GSM_UNDEFINED);
+ }
+
+ return cc_cause_names[id - CC_CAUSE_OK];
+}
+
diff --git a/libs/sipcc/core/gsm/dcsm.c b/libs/sipcc/core/gsm/dcsm.c
new file mode 100755
index 0000000000..0484ef2d3a
--- /dev/null
+++ b/libs/sipcc/core/gsm/dcsm.c
@@ -0,0 +1,723 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "cpr_types.h"
+#include "cpr_stdlib.h"
+#include "cpr_stdio.h"
+#include "cpr_string.h"
+#include "cpr_errno.h"
+#include "phone.h"
+#include "phntask.h"
+#include "lsm.h"
+#include "ccapi.h"
+#include "phone_debug.h"
+#include "fim.h"
+#include "sdp.h"
+#include "debug.h"
+#include "gsm_sdp.h"
+#include "uiapi.h"
+#include "gsm.h"
+#include "prot_configmgr.h"
+#include "singly_link_list.h"
+
+typedef enum dcsm_state {
+ DCSM_S_MIN = -1,
+ DCSM_S_READY,
+ DCSM_S_WAITING,
+ DCSM_S_MAX
+} dcsm_state_e;
+
+#define DCSM_MAX_CALL_IDS (LSM_MAX_CALLS)
+
+static struct dcsm_icb_t {
+ callid_t call_ids[DCSM_MAX_CALL_IDS];
+ line_t line;
+ int gsm_state;
+ sll_handle_t s_msg_list;
+
+ dcsm_state_e state;
+} dcsm_cb;
+
+static const char *dcsm_state_names[] = {
+ "DCSM_READY",
+ "DCSM_WAITING"
+};
+
+extern cc_int32_t g_dcsmDebug;
+
+static sm_rcs_t dcsm_wait_ev_feature_handling(void *event, int event_id);
+static sm_rcs_t dcsm_wait_ev_offhook_handling(void *event, int event_id);
+static sm_rcs_t dcsm_wait_ev_dialstring_handling(void *event, int event_id);
+
+typedef sm_rcs_t (*pdcsm_sm_evt_handler)(void *event, int event_id);
+
+typedef struct _dcsm_table_t {
+ int min_state;
+ int max_state;
+ int min_event;
+ int max_event;
+ pdcsm_sm_evt_handler *table;
+} dcsm_table_t;
+
+
+static pdcsm_sm_evt_handler dcsm_function_table[DCSM_S_MAX][CC_MSG_MAX] =
+{
+/* DCSM_S_READY ------------------------------------------------------------ */
+ {
+ /* DCSM_E_SETUP */ NULL,
+ /* DCSM_E_SETUP_ACK */ NULL,
+ /* DCSM_E_PROCEEDING */ NULL,
+ /* DCSM_E_ALERTING */ NULL,
+ /* DCSM_E_CONNECTED */ NULL,
+ /* DCSM_E_CONNECTED_ACK */ NULL,
+ /* DCSM_E_RELEASE */ NULL,
+ /* DCSM_E_RELEASE_COMPLETE */ NULL,
+ /* DCSM_E_FEATURE */ NULL,
+ /* DCSM_E_FEATURE_ACK */ NULL,
+ /* DCSM_E_OFFHOOK */ NULL,
+ /* DCSM_E_ONHOOK */ NULL,
+ /* DCSM_E_LINE */ NULL,
+ /* DCSM_E_DIGIT_BEGIN */ NULL,
+ /* DCSM_E_DIGIT_END */ NULL,
+ /* DCSM_E_DIALSTRING */ NULL,
+ /* DCSM_E_MWI */ NULL,
+ /* DCSM_E_SESSION_AUDIT */ NULL
+ },
+
+/* DCSM_S_WAITING----------------------------------------------------- */
+ {
+ /* DCSM_E_SETUP */ NULL,
+ /* DCSM_E_SETUP_ACK */ NULL,
+ /* DCSM_E_PROCEEDING */ NULL,
+ /* DCSM_E_ALERTING */ NULL,
+ /* DCSM_E_CONNECTED */ NULL,
+ /* DCSM_E_CONNECTED_ACK */ NULL,
+ /* DCSM_E_RELEASE */ NULL,
+ /* DCSM_E_RELEASE_COMPLETE */ NULL,
+ /* DCSM_E_FEATURE */ dcsm_wait_ev_feature_handling,
+ /* DCSM_E_FEATURE_ACK */ NULL,
+ /* DCSM_E_OFFHOOK */ dcsm_wait_ev_offhook_handling,
+ /* DCSM_E_ONHOOK */ NULL,
+ /* DCSM_E_LINE */ NULL,
+ /* DCSM_E_DIGIT_BEGIN */ NULL,
+ /* DCSM_E_DIGIT_END */ NULL,
+ /* DCSM_E_DIALSTRING */ dcsm_wait_ev_dialstring_handling,
+ /* DCSM_E_MWI */ NULL,
+ /* DCSM_E_SESSION_AUDIT */ NULL
+ },
+};
+
+static dcsm_table_t dcsm_sm_table;
+static dcsm_table_t *pdcsm_sm_table = &dcsm_sm_table;
+
+/*
+ * Adds event to the dcsm queue.
+ *
+ * @param event - Call control event to add
+ *
+ * @return TRUE if the event is added.
+
+ *
+ */
+static boolean
+dcsm_add_event_to_queue (void *event)
+{
+ (void) sll_append(dcsm_cb.s_msg_list, event);
+
+ return TRUE;
+}
+
+/*
+ * Get a event from the queue.
+ *
+ * @param none
+ *
+ * @return pointer to the event.
+
+ *
+ */
+static void *
+dcsm_get_first_event_from_queue (void)
+{
+ void *msg_ptr = NULL;
+
+ msg_ptr = sll_next(dcsm_cb.s_msg_list, NULL);
+
+ sll_remove(dcsm_cb.s_msg_list, msg_ptr);
+
+ return(msg_ptr);
+}
+
+/*
+ * Get dcsm state name.
+ *
+ * @param int - state id
+ *
+ * @return ponter to the state name either
+ * DCSM_READY or DCSM_WAITING.
+ *
+ */
+const char *dcsm_get_state_name (int state)
+{
+ if ((state <= DCSM_S_MIN) ||
+ (state >= DCSM_S_MAX)) {
+ return (get_debug_string(GSM_UNDEFINED));
+ }
+
+ return dcsm_state_names[state];
+}
+
+/**
+ * Feed the event to FIM state machine a direct function call
+ * to process message retrieved from the queue.
+ *
+ * @param void * - pointer to the message to be processed
+ *
+ * @return none.
+ */
+static void dcsm_process_event_to_gsm (void *msg_ptr)
+{
+ if (fim_process_event(msg_ptr, FALSE) == TRUE) {
+
+ fim_free_event(msg_ptr);
+
+ /* Release buffer too */
+ cpr_free(msg_ptr);
+ }
+}
+
+
+/**
+ * Process ready state events.
+ *
+ * @param none
+ *
+ * @return none.
+ */
+
+static void dcsm_do_ready_state_job (void)
+{
+ static const char fname[] = "dcsm_do_ready_state_job";
+ void *msg_ptr;
+ int event_id;
+ cc_feature_t *feat_msg = NULL;
+ callid_t call_id = CC_NO_CALL_ID;
+
+ if (dcsm_cb.state != DCSM_S_READY) {
+ DEF_DEBUG(DEB_F_PREFIX": not in ready state.\n",
+ DEB_F_PREFIX_ARGS("DCSM", fname));
+ return;
+ }
+
+ msg_ptr = dcsm_get_first_event_from_queue();
+
+ /* Check if there is any msg available */
+ if (msg_ptr != NULL) {
+ event_id = (int)(((cc_setup_t *)msg_ptr)->msg_id);
+ if (event_id == CC_MSG_FEATURE) {
+ feat_msg = (cc_feature_t *) msg_ptr;
+ if (feat_msg != NULL) {
+ call_id = feat_msg->call_id;
+ }
+ }
+
+ DEF_DEBUG(DEB_F_PREFIX"%d: event (%s%s)\n",
+ DEB_F_PREFIX_ARGS("DCSM", fname), call_id,
+ cc_msg_name((cc_msgs_t)(event_id)),
+ feat_msg ? cc_feature_name(feat_msg->feature_id):" ");
+ dcsm_process_event_to_gsm(msg_ptr);
+ }
+}
+
+/**
+ * Function process events based on the state of DCSM.
+ *
+ * @param none
+ *
+ * @return none.
+ */
+void dcsm_process_jobs (void)
+{
+ dcsm_do_ready_state_job();
+}
+
+/**
+ * Adds call_id to the list of call_id's which made DCSM to move
+ * to waiting state.
+ *
+ * @param callid_t - call id that has to be added to the list
+ *
+ * @return none.
+ */
+static void dcsm_add_call_id_to_list (callid_t call_id)
+{
+ static const char fname[] = "dcsm_add_call_id_to_list";
+ int i, loc = -1;
+
+ for (i=0; i< DCSM_MAX_CALL_IDS; i++) {
+ if (dcsm_cb.call_ids[i] == CC_NO_CALL_ID) {
+ loc = i;
+ } else if (dcsm_cb.call_ids[i] == call_id) {
+ //Call_id already present so do not try to add again
+ return;
+ }
+ }
+
+ if (loc == -1) {
+
+ /* Should never happen as there is a space to store call_id
+ * for each calls
+ */
+ DCSM_ERROR(DCSM_F_PREFIX"DCSM No space to store call_id.\n",
+ DEB_F_PREFIX_ARGS("DCSM", fname));
+ return;
+ }
+
+ dcsm_cb.call_ids[loc] = call_id;
+}
+
+/**
+ * Remove call_id from the list and see if the call_ids list is null.
+ *
+ * @param callid_t - call id that to be removed from the list.
+ *
+ * @return TRUE - if the call_ids list is empty.
+ * FALSE - call_ids list is not empty.
+ */
+static boolean dcsm_remove_check_for_empty_list (callid_t call_id)
+{
+ int i;
+ boolean call_id_present = FALSE;
+
+ for (i=0; i< DCSM_MAX_CALL_IDS; i++) {
+ if (dcsm_cb.call_ids[i] == call_id) {
+ dcsm_cb.call_ids[i] = CC_NO_CALL_ID;
+
+ /* Found out that other call_id exist by setting
+ * call_id_preset, so return true, don't have to
+ * continue
+ */
+ if (call_id_present == TRUE) {
+ return FALSE;
+ }
+
+ } else if (dcsm_cb.call_ids[i] != CC_NO_CALL_ID) {
+ call_id_present = TRUE;
+ }
+ }
+
+ if (call_id_present == TRUE) {
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+
+/*
+ * The function responsible for setting gsm state machine.
+ *
+ * @param callid_t - call id of the call
+ * state - current GSM state
+ *
+ * @return void
+ *
+ */
+void
+dcsm_update_gsm_state (fsm_fcb_t *fcb, callid_t call_id, int state)
+{
+ int last_state;
+ static const char fname[] = "dcsm_update_gsm_state";
+ fsmdef_dcb_t *dcb;
+
+ if (fcb->fsm_type != FSM_TYPE_DEF) {
+ DEF_DEBUG(DEB_F_PREFIX"%d: Not handling for %s\n",
+ DEB_F_PREFIX_ARGS("DCSM", fname), call_id,
+ fsm_type_name(fcb->fsm_type));
+ return;
+ }
+
+ last_state = dcsm_cb.state;
+
+ switch (state) {
+ case FSMDEF_S_RELEASING:
+ dcb = fsmdef_get_dcb_by_call_id(call_id);
+ if (dcb && dcb->send_release == FALSE) {
+ /* This call is already released from SIP persepctive. so no need to wait */
+ break;
+ }
+ case FSMDEF_S_CONNECTING:
+ case FSMDEF_S_HOLD_PENDING:
+ case FSMDEF_S_RESUME_PENDING:
+ dcsm_add_call_id_to_list(call_id);
+
+ dcsm_cb.state = DCSM_S_WAITING;
+ break;
+ case FSMDEF_S_MIN:
+ case FSMDEF_S_IDLE:
+ case FSMDEF_S_COLLECT_INFO:
+ case FSMDEF_S_CALL_SENT:
+ case FSMDEF_S_OUTGOING_PROCEEDING:
+ case FSMDEF_S_KPML_COLLECT_INFO:
+ case FSMDEF_S_OUTGOING_ALERTING:
+ case FSMDEF_S_INCOMING_ALERTING:
+ case FSMDEF_S_JOINING:
+ case FSMDEF_S_CONNECTED:
+ case FSMDEF_S_CONNECTED_MEDIA_PEND:
+ case FSMDEF_S_HOLDING:
+ case FSMDEF_S_PRESERVED:
+ case FSMDEF_S_MAX:
+ /* If there are no other call_id then move it to
+ * ready state else, it will remain in waiting
+ * state
+ */
+ if (dcsm_remove_check_for_empty_list(call_id) == TRUE) {
+ dcsm_cb.state = DCSM_S_READY;
+ /* Check if there are any pending events in the queue
+ * if so send a DCSM_EV_READY to the GSM so dcsm will
+ * get a chance to execute.
+ */
+ if (sll_count(dcsm_cb.s_msg_list) > 0 ) {
+ if (gsm_send_msg(DCSM_EV_READY, NULL, 0) == CPR_FAILURE) {
+ DCSM_ERROR(DCSM_F_PREFIX"send DCSM_EV_READY ERROR.\n",
+ DEB_F_PREFIX_ARGS(DCSM, fname));
+ }
+ }
+ }
+
+ break;
+ default:
+ break;
+ }
+
+ DEF_DEBUG(DEB_F_PREFIX"%d : %s --> %s\n",
+ DEB_F_PREFIX_ARGS("DCSM", fname), call_id,
+ dcsm_get_state_name(last_state),
+ dcsm_get_state_name(dcsm_cb.state));
+ return;
+}
+
+/**
+ *
+ * Feature passed through when state machine is in waiting state
+ *
+ * @param sm_event_t
+ *
+ * @return sm_rcs_t
+ *
+ * @pre (none)
+ */
+static sm_rcs_t
+dcsm_wait_ev_offhook_handling (void *event, int event_id)
+{
+ static const char fname[] = "dcsm_wait_ev_offhook_handling";
+
+ DEF_DEBUG(DEB_F_PREFIX": offhook\n",
+ DEB_F_PREFIX_ARGS("DCSM", fname));
+
+ dcsm_add_event_to_queue(event);
+ return (SM_RC_END);
+}
+/**
+ *
+ * Feature passed through when state machine is in waiting state
+ *
+ * @param sm_event_t
+ *
+ * @return sm_rcs_t
+ *
+ * @pre (none)
+ */
+static sm_rcs_t
+dcsm_wait_ev_feature_handling (void *event, int event_id)
+{
+ static const char fname[] = "dcsm_wait_ev_feature_handling";
+ cc_feature_t *feat_msg = (cc_feature_t *) event;
+ sm_rcs_t rc = SM_RC_END;
+ cc_features_t ftr_id = CC_FEATURE_UNDEFINED;
+ callid_t call_id = CC_NO_CALL_ID;
+
+ if (feat_msg != NULL) {
+ ftr_id = feat_msg->feature_id;
+ call_id = feat_msg->call_id;
+ }
+
+ DEF_DEBUG(DEB_F_PREFIX"%d: id= %s%s\n",
+ DEB_F_PREFIX_ARGS("DCSM", fname), call_id,
+ cc_msg_name((cc_msgs_t)(event_id)),
+ feat_msg ? cc_feature_name(feat_msg->feature_id):" ");
+
+ switch (ftr_id) {
+ case CC_FEATURE_ANSWER:
+ case CC_FEATURE_NEW_CALL:
+ case CC_FEATURE_REDIAL:
+ case CC_FEATURE_RESUME:
+ case CC_FEATURE_JOIN:
+ dcsm_add_event_to_queue(event);
+ DEF_DEBUG(DEB_F_PREFIX"%d: Event queued\n",
+ DEB_F_PREFIX_ARGS("DCSM", fname), call_id);
+ rc = SM_RC_END;
+ break;
+ default:
+ DEF_DEBUG(DEB_F_PREFIX"%d: Feature msg not handled\n",
+ DEB_F_PREFIX_ARGS("DCSM", fname), call_id);
+
+ rc = SM_RC_CONT;
+ break;
+ }
+
+
+ return (rc);
+
+}
+
+/**
+ *
+ * Feature passed through when state machine is in waiting state
+ *
+ * @param sm_event_t
+ *
+ * @return sm_rcs_t
+ *
+ * @pre (none)
+ */
+static sm_rcs_t
+dcsm_wait_ev_dialstring_handling (void *event, int event_id)
+{
+ static const char fname[] = "dcsm_wait_ev_dialstring_handling";
+
+ DEF_DEBUG(DEB_F_PREFIX": dialstring\n",
+ DEB_F_PREFIX_ARGS("DCSM", fname));
+
+ dcsm_add_event_to_queue(event);
+ return (SM_RC_END);
+}
+
+/**
+ *
+ * Feature passed through when state machine is in waiting state
+ *
+ * @param sm_event_t
+ *
+ * @return sm_rcs_t
+ *
+ * @pre (none)
+ */
+sm_rcs_t
+dcsm_process_event (void *event, int event_id)
+{
+ static const char fname[] = "dcsm_process_event";
+ callid_t call_id;
+ int state_id;
+ sm_rcs_t rc = SM_RC_CONT;
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event;
+ cc_feature_t *feat_msg = NULL;
+ pdcsm_sm_evt_handler hdlr; /* cached handler in order to compute its addr once */
+
+ call_id = fcb->call_id;
+
+ if (event_id == CC_MSG_FEATURE) {
+ feat_msg = (cc_feature_t *) event;
+
+ if (feat_msg != NULL){
+ call_id = feat_msg->call_id;
+ }
+ }
+
+ DEF_DEBUG(DEB_F_PREFIX"DCSM %-4d:(%s:%s%s)\n",
+ DEB_F_PREFIX_ARGS("DCSM", fname), call_id,
+ dcsm_get_state_name(dcsm_cb.state),
+ cc_msg_name((cc_msgs_t)(event_id)),
+ feat_msg ? cc_feature_name(feat_msg->feature_id):" ");
+
+ state_id = dcsm_cb.state; // Get current state;
+
+ /*
+ * validate the state and event
+ * and that there is a valid function for this state-event pair.
+ */
+ if ((state_id > pdcsm_sm_table->min_state) &&
+ (state_id < pdcsm_sm_table->max_state) &&
+ (event_id > pdcsm_sm_table->min_event) &&
+ (event_id < pdcsm_sm_table->max_event)) {
+
+ if ((hdlr = pdcsm_sm_table->table[pdcsm_sm_table->max_event * state_id +
+ event_id]) != NULL) {
+ DEF_DEBUG(DEB_F_PREFIX"%-4d: dcsm entry: (%s)\n",
+ DEB_F_PREFIX_ARGS("DCSM", fname), call_id,
+ cc_msg_name((cc_msgs_t)(event_id)));
+
+ rc = hdlr(event, event_id);
+ }
+
+ }
+
+ return (rc);
+
+}
+
+/*
+ * Function responsible for searching the list.
+ *
+ * @param cac_data_t *key_p - pointer to the key.
+ * @param cac_data_t *cac_data - cac data.
+ *
+ * @return void
+ *
+ */
+static sll_match_e
+dcsm_match_event (void *key_p, void *msg_data)
+{
+ return SLL_MATCH_FOUND;
+}
+
+/**
+ *
+ * Show function for DCSM
+ *
+ * @param argc - number of parameter passed
+ * argv - argument passed
+ *
+ * @return 0 - if function successful
+ */
+cc_int32_t
+dcsm_show_cmd (cc_int32_t argc, const char *argv[])
+{
+ void *msg_ptr;
+ int i;
+ cc_setup_t *msg;
+ cc_msgs_t msg_id;
+ line_t line;
+ callid_t call_id;
+ cc_feature_t *feat_msg = NULL;
+
+
+ /*
+ * check if need help
+ */
+ if ((argc == 2) && (argv[1][0] == '?')) {
+ debugif_printf("%s", "show dcsm\n");
+ return (0);
+ }
+
+
+ if (dcsm_cb.s_msg_list == NULL) {
+ return(0);
+ }
+
+ debugif_printf("%s", "\n-------------------------- DCSM Data --------------------------");
+ debugif_printf("\nDCSM State = %s",dcsm_get_state_name(dcsm_cb.state));
+ debugif_printf("%s", "\nDCSM waiting calls \n");
+
+ for (i=0; i< DCSM_MAX_CALL_IDS; i++) {
+ if (dcsm_cb.call_ids[i] != CC_NO_CALL_ID) {
+ debugif_printf("%d ", dcsm_cb.call_ids[i]);
+ }
+ }
+ debugif_printf("%s", "\n");
+
+ debugif_printf("%s", "\nDCSM waiting events \n");
+ i = 0;
+ msg_ptr = sll_next(dcsm_cb.s_msg_list, NULL);
+ while (msg_ptr) {
+ msg_ptr = sll_next(dcsm_cb.s_msg_list, msg_ptr);
+
+ if (msg_ptr) {
+ msg = (cc_setup_t *) msg_ptr;
+ msg_id = msg->msg_id;
+ call_id = msg->call_id;
+ line = msg->line;
+ if ((int)msg_id == CC_MSG_FEATURE) {
+ feat_msg = (cc_feature_t *) msg_ptr;
+ }
+
+ debugif_printf("Event %d (%d/%d): (%s%s)\n",
+ i++, line, call_id, cc_msg_name(msg_id),
+ feat_msg ? cc_feature_name(feat_msg->feature_id):" ");
+ }
+ }
+ debugif_printf("%s", "\n-------------------------- DCSM Data Done-----------------------");
+
+ return (0);
+}
+
+
+/**
+ *
+ * Initialize dcsm state machine.
+ *
+ * @param none
+ *
+ * @return none
+ *
+ * @pre none
+ */
+void
+dcsm_init (void)
+{
+ static const char fname[] = "dcsm_init";
+ int i;
+
+ /*
+ * Initialize the state/event table.
+ */
+ dcsm_sm_table.min_state = DCSM_S_MIN;
+ dcsm_sm_table.max_state = DCSM_S_MAX;
+ dcsm_sm_table.min_event = CC_MSG_MIN;
+ dcsm_sm_table.max_event = CC_MSG_MAX;
+ dcsm_sm_table.table = (&(dcsm_function_table[0][0]));
+
+ dcsm_cb.state = DCSM_S_READY;
+
+ for (i=0; i< DCSM_MAX_CALL_IDS; i++) {
+ dcsm_cb.call_ids[i] = CC_NO_CALL_ID;
+ }
+
+ /* allocate and initialize cac list */
+ dcsm_cb.s_msg_list = sll_create((sll_match_e(*)(void *, void *))
+ dcsm_match_event);
+
+ if (dcsm_cb.s_msg_list == NULL) {
+ DCSM_ERROR(DCSM_F_PREFIX"DCSM CB creation failed.\n",
+ DEB_F_PREFIX_ARGS("DCSM", fname));
+
+ }
+
+}
+
+/**
+ *
+ * Shut down routine for dcsm state machine.
+ *
+ * @param none
+ *
+ * @return none
+ *
+ * @pre none
+ */
+void
+dcsm_shutdown (void)
+{
+ void *msg_ptr;
+
+ if (dcsm_cb.s_msg_list == NULL) {
+ return;
+ }
+
+ msg_ptr = sll_next(dcsm_cb.s_msg_list, NULL);
+ while (msg_ptr) {
+ msg_ptr = sll_next(dcsm_cb.s_msg_list, msg_ptr);
+
+ if (msg_ptr) {
+ fim_free_event(msg_ptr);
+
+ /* Release buffer too */
+ cpr_free(msg_ptr);
+ }
+ }
+
+ sll_destroy(dcsm_cb.s_msg_list);
+ dcsm_cb.s_msg_list = NULL;
+}
+
diff --git a/libs/sipcc/core/gsm/fim.c b/libs/sipcc/core/gsm/fim.c
new file mode 100755
index 0000000000..4a176ed0eb
--- /dev/null
+++ b/libs/sipcc/core/gsm/fim.c
@@ -0,0 +1,761 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+//#include "mozilla/Assertions.h"
+#include "cpr_types.h"
+#include "cpr_stdlib.h"
+#include "cpr_stdio.h"
+#include "phone.h"
+#include "fim.h"
+#include "lsm.h"
+#include "fsm.h"
+#include "sm.h"
+#include "ccapi.h"
+#include "debug.h"
+#include "phone_debug.h"
+#include "util_string.h"
+#include "sdp.h"
+#include "gsm_sdp.h"
+#include "ccsip_sdp.h"
+#include "platform_api.h"
+
+extern void set_next_sess_video_pref(int pref);
+extern sm_rcs_t dcsm_process_event(void *event, int event_id);
+
+#define FIM_MAX_CHNS (LSM_MAX_CALLS)
+#define FIM_MAX_SCBS (FSM_TYPE_MAX)
+#define FIM_MAX_ICBS (FSM_TYPE_MAX * FIM_MAX_CHNS)
+
+static fim_scb_t *fim_scbs;
+static fim_icb_t *fim_icbs;
+
+
+static void
+fim_mwi (cc_mwi_t *msg)
+{
+ cc_action_data_t data;
+
+ data.mwi.on = msg->msgSummary.on;
+ data.mwi.type = msg->msgSummary.type;
+ data.mwi.newCount = msg->msgSummary.newCount;
+ data.mwi.oldCount = msg->msgSummary.oldCount;
+ data.mwi.hpNewCount = msg->msgSummary.hpNewCount;
+ data.mwi.hpOldCount = msg->msgSummary.hpOldCount;
+
+ (void)cc_call_action(msg->call_id, msg->line, CC_ACTION_MWI, &data);
+}
+
+
+static void
+fim_init_call_chns (void)
+{
+ int chn;
+ fsm_types_t type;
+ fim_icb_t *icb = NULL;
+ static const char fname[] = "fim_init_call_chns";
+
+ fim_scbs = (fim_scb_t *) cpr_calloc(FIM_MAX_SCBS, sizeof(fim_scb_t));
+ if (fim_scbs == NULL) {
+ GSM_DEBUG_ERROR(GSM_F_PREFIX"Failed to allocate FIM SCBs.\n", fname);
+ return;
+ }
+
+ fim_icbs = (fim_icb_t *) cpr_calloc(FIM_MAX_ICBS, sizeof(fim_icb_t));
+ if (fim_icbs == NULL) {
+ GSM_DEBUG_ERROR(GSM_F_PREFIX"Failed to allocate FIM ICBs.\n", fname);
+ cpr_free(fim_scbs);
+ fim_scbs = NULL;
+ return;
+ }
+
+ /*
+ * Initialize the icbs (fim control blocks).
+ */
+ icb = fim_icbs;
+ for (chn = 0; chn < FIM_MAX_CHNS; chn++) {
+ for (type = FSM_TYPE_HEAD; type < FSM_TYPE_MAX; type++, icb++) {
+ icb->call_id = CC_NO_CALL_ID;
+ icb->scb = &(fim_scbs[type]);
+ icb->cb = NULL;
+
+ /*
+ * Set the next_chn pointers if this is the head of the chain,
+ * Set non-head icbs and the last head to NULL.
+ */
+ if ((type == FSM_TYPE_HEAD) && (chn < (FIM_MAX_CHNS - 1))) {
+ icb->next_chn = icb + FSM_TYPE_MAX;
+ } else {
+ icb->next_chn = NULL;
+ }
+
+ /*
+ * Set the next_icb pointers if this icb is not the last
+ * one on the chain.
+ */
+ if (type < (FSM_TYPE_MAX - 1)) {
+ icb->next_icb = icb + 1;
+ } else {
+ icb->next_icb = NULL;
+ }
+ } /* for (jscb = FSM_TYPE_HEAD; i < FSM_TYPE_MAX; i++) { */
+ } /* for (ichn = 0; ichn < FIM_MAX_CHNS; ichn++) { */
+
+ /*
+ * Initialize the scbs (state machine control blocks).
+ */
+ icb = fim_icbs;
+ for (type = FSM_TYPE_HEAD; type < FSM_TYPE_MAX; type++, icb++) {
+ icb->scb->type = type;
+ fsm_init_scb(icb, CC_NO_CALL_ID);
+ }
+}
+
+static void
+fim_free_call_chn (fim_icb_t *call_chn, line_t line, boolean update_call_cnt)
+{
+ static const char fname[] = "fim_free_call_chn";
+ fim_icb_t *icb = call_chn;
+
+ FIM_DEBUG(get_debug_string(GSM_DBG_PTR), "FIM", call_chn->call_id, fname,
+ "call_chn", call_chn);
+
+ /*
+ * Go through the chain and free each icb.
+ */
+ for (icb = call_chn; icb != NULL; icb = icb->next_icb) {
+ if (icb->scb->free_cb != NULL) {
+ icb->scb->free_cb(icb, icb->call_id);
+ }
+ icb->call_id = CC_NO_CALL_ID;
+ icb->cb = NULL;
+ }
+ if (update_call_cnt == TRUE) {
+ lsm_decrement_call_chn_cnt(line);
+ }
+ else {
+ FIM_DEBUG(get_debug_string(GSM_DBG_PTR), "lsm not decremented", call_chn->call_id, fname,
+ "call_chn", call_chn);
+ }
+}
+
+
+static fim_icb_t *
+fim_get_call_chn_by_call_id (callid_t call_id)
+{
+ static const char fname[] = "fim_get_call_chn_by_call_id";
+ fim_icb_t *call_chn = NULL;
+ fim_icb_t *icb = NULL;
+
+ for (icb = fim_icbs; icb != NULL; icb = icb->next_chn) {
+ if (icb->call_id == call_id) {
+ call_chn = icb;
+ break;
+ }
+ }
+
+ FIM_DEBUG(get_debug_string(GSM_DBG_PTR), "FIM", call_id, fname, "chn",
+ call_chn);
+
+ return call_chn;
+}
+
+static fim_icb_t *
+fim_get_new_call_chn (callid_t call_id)
+{
+ static const char fname[] = "fim_get_new_call_chn";
+ fim_icb_t *call_chn = NULL;
+ fim_icb_t *icb = NULL;
+
+ /*
+ * Verify that this call_id is not already used.
+ */
+ call_chn = fim_get_call_chn_by_call_id(call_id);
+ if (call_chn != NULL) {
+ FIM_DEBUG(get_debug_string(GSM_DBG1), "FIM", call_id, fname,
+ "call_id in use");
+
+ return NULL;
+ }
+
+ /*
+ * Construct a new call chain.
+ */
+ call_chn = fim_get_call_chn_by_call_id(CC_NO_CALL_ID);
+ if (call_chn == NULL) {
+ /*
+ * No more free call_chns are available.
+ */
+ FIM_DEBUG(get_debug_string(GSM_DBG1), "FIM", call_id, fname,
+ "no free call_chns");
+
+ return NULL;
+ }
+
+ call_chn->call_id = call_id;
+ call_chn->ui_locked = FALSE;
+
+ /*
+ * Set the control blocks for the icbs.
+ */
+ for (icb = call_chn; icb != NULL; icb = icb->next_icb) {
+ FIM_DEBUG(get_debug_string(GSM_DBG1), "FIM", call_id, fname,
+ fsm_type_name(icb->scb->type));
+
+ if (icb->scb->get_cb) {
+ icb->scb->get_cb(icb, call_id);
+ icb->call_id = call_id;
+ icb->ui_locked = FALSE;
+ }
+ }
+
+ FIM_DEBUG(get_debug_string(GSM_DBG_PTR), "FIM", call_chn->call_id, fname,
+ "call_chn", call_chn);
+
+ return call_chn;
+}
+
+void
+fim_free_event (void *data)
+{
+ cc_msg_t *msg = (cc_msg_t *) data;
+
+ /* Free CCAPI msg. data that are not consumed */
+ cc_free_msg_data(msg);
+}
+
+static void
+fim_process_options_msg (void *data)
+{
+ static const char fname[] = "fim_process_options_msg";
+ cc_sdp_t *local_sdp_p = NULL;
+ cc_causes_t cause = CC_CAUSE_MIN;
+ cc_msgbody_info_t msg_body;
+ cc_options_sdp_req_t *options_msg = (cc_options_sdp_req_t *) data;
+
+ gsmsdp_create_options_sdp(&local_sdp_p);
+
+ cause = gsmsdp_encode_sdp(local_sdp_p, &msg_body);
+ if (cause != CC_CAUSE_OK) {
+ FIM_DEBUG(get_debug_string(GSM_DBG1), "FIM", options_msg->call_id,
+ fname, "Unable to build SDP\n");
+ } else {
+ cc_int_options_sdp_ack(CC_SRC_GSM, CC_SRC_SIP,
+ options_msg->call_id,
+ options_msg->line,
+ options_msg->pMessage, &msg_body);
+ }
+ sipsdp_src_dest_free(CCSIP_SRC_SDP_BIT, &local_sdp_p);
+}
+
+void
+fim_lock_ui (callid_t call_id)
+{
+ fim_icb_t *call_chn = fim_get_call_chn_by_call_id(call_id);
+
+ if (call_chn == NULL) {
+ FIM_DEBUG(DEB_F_PREFIX"unknown call id\n", DEB_F_PREFIX_ARGS(FIM, "fim_lock_ui"));
+ return;
+ }
+ call_chn->ui_locked = TRUE;
+}
+
+void
+fim_unlock_ui (callid_t call_id)
+{
+ fim_icb_t *call_chn = fim_get_call_chn_by_call_id(call_id);
+
+ if (call_chn == NULL) {
+ FIM_DEBUG(DEB_F_PREFIX"unknown call id\n", DEB_F_PREFIX_ARGS(FIM, "fim_unlock_ui"));
+ return;
+ }
+ call_chn->ui_locked = FALSE;
+}
+
+static boolean
+fsm_event_filtered_by_ui_lock (int event_id, cc_features_t feature_id)
+{
+ /*
+ * If UI has been locked by GSM due to pending states, we want
+ * to filter the events that come in from the UI. We will still
+ * allow all GSM and SIP stack originated events through to the
+ * GSM sm.
+ */
+ if (event_id == CC_MSG_ONHOOK) {
+ return FALSE;
+ }
+
+ if ((event_id == CC_MSG_FEATURE) &&
+ (feature_id == CC_FEATURE_END_CALL ||
+ feature_id == CC_FEATURE_REQ_PEND_TIMER_EXP ||
+ feature_id == CC_FEATURE_RESUME ||
+ feature_id == CC_FEATURE_HOLD)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ *
+ * Check if the feature event is generic feature
+ *
+ * @param cc_features_t feature_id
+ *
+ * @return TRUE if the feature is generic or else FALSE
+ *
+ * @pre None
+ */
+boolean fim_is_app_generic_features (cc_features_t feat_id)
+{
+ return(FALSE);
+}
+
+/**
+ *
+ * Check if the message is the feature event that may requires a new
+ * call chain.
+ *
+ * @param msg - pointer to cc_setup_t.
+ *
+ * @return TRUE if the feature that may requires a new call chain.
+ *
+ * @pre (msg != NULL)
+ */
+static boolean
+fim_check_feature_event (cc_setup_t *msg)
+{
+
+ if ((((cc_feature_t *)msg)->feature_id == CC_FEATURE_SELECT) ||
+ (((cc_feature_t *)msg)->feature_id == CC_FEATURE_DIRTRXFR) ||
+ (((cc_feature_t *)msg)->feature_id == CC_FEATURE_B2BCONF) ||
+ (((cc_feature_t *)msg)->feature_id == CC_FEATURE_CFWD_ALL)) {
+ return (TRUE);
+ }
+ return (FALSE);
+}
+
+/*
+ * fim_feature_need_outgoing_call_context
+ *
+ * Description:
+ * This function determines whther a new feature invokation needs
+ * an early outgoing call context created in the FIM main module or not.
+ *
+ * Parameters:
+ msg - pointer to the cc_setup_t.
+ *
+ * Returns:
+ * TRUE - the feature requires outgoing call context to be created.
+ * FALSE - the feature does not requries outgoing call context to
+ * be created during initial FIM displacthing.
+ */
+static boolean
+fim_feature_need_outgoing_call_context (cc_setup_t *msg)
+{
+ if (((cc_feature_t *)msg)->feature_id == CC_FEATURE_NOTIFY) {
+ /*
+ * these features do not need outgoing context to be created early
+ */
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+/**
+ *
+ * Process events received for GSM
+ *
+ * @param void event data
+ * cac_passed indicate if the event passed cac request.
+ * Usually set to true once the cac response is
+ * received so that it won't do another request.
+ *
+ * @return true if message memory has to be released by caller
+ * false if the message memory is not to be released by
+ * caller.
+ *
+ * @pre (data not_eq NULL)
+ * @pre (CC_MSG_MIN < msg->msg_id msg_id;
+ callid_t call_id = msg->call_id;
+ line_t line = msg->line;
+ int event_id = msg_id;
+ sm_event_t event;
+ fim_icb_t *call_chn = NULL;
+ fim_icb_t *icb = NULL;
+ boolean done = FALSE;
+ sm_rcs_t rc = SM_RC_ERROR;
+ fim_cb_hdr_t *cb_hdr = NULL;
+ fsm_fcb_t *fcb = NULL;
+ cc_feature_t *feat_msg = (cc_feature_t *) data;
+ cc_feature_data_t * feat_data = &(feat_msg->data);
+ boolean update_call_cnt = TRUE;
+ uint32_t no_of_session = 1;
+ callid_t bw_call_id;
+
+ FIM_DEBUG(DEB_L_C_F_PREFIX"Msg name = %s\n", DEB_L_C_F_PREFIX_ARGS(FIM, line, call_id, fname),
+ cc_msg_name(msg_id));
+
+ /*
+ * Validate the incoming event.
+ */
+ if ((event_id <= CC_MSG_MIN) || (event_id >= CC_MSG_MAX)) {
+ cc_call_state(call_id, line, CC_STATE_UNKNOWN, NULL);
+ return(TRUE);
+ }
+
+ /* Make sure to process the device events
+ */
+
+ if (dcsm_process_event(data, event_id) == SM_RC_END) {
+ /* Keep the message in the dcsm state handler */
+ return(FALSE);
+ }
+
+ /*
+ * Grab non-call control events and hand them off to other functions that
+ * are not implemented by the fsms.
+ */
+ if (msg_id == CC_MSG_MWI) {
+ fim_mwi((cc_mwi_t *) msg);
+ }
+
+ if (event_id == CC_MSG_OPTIONS) {
+ fim_process_options_msg(data);
+ return(TRUE);
+ }
+
+
+ if (platWlanISActive() && cac_passed == FALSE) {
+ /* The WLAN will request for bandwidth only for the events received from
+ * UI or other external entity. For internal events there is allocated bandwidth
+ * and do not need to request again.
+ */
+
+ if ((msg->src_id != CC_SRC_GSM) &&
+ ((event_id == CC_MSG_SETUP) ||
+ (event_id == CC_MSG_OFFHOOK) ||
+ (event_id == CC_MSG_DIALSTRING) ||
+ (event_id == CC_MSG_LINE) ||
+ ((event_id == CC_MSG_FEATURE) &&
+ ((((cc_feature_t *) msg)->feature_id == CC_FEATURE_NEW_CALL))))) {
+
+ bw_call_id = call_id;
+
+ if ((event_id == CC_MSG_SETUP) &&
+ ((((cc_setup_t *)msg)->call_info.type == CC_FEAT_MONITOR))) {
+ no_of_session = 2;
+ bw_call_id = msg->call_info.data.join.join_call_id;
+ }
+
+ if (fsm_cac_call_bandwidth_req (bw_call_id, no_of_session, msg) != CC_CAUSE_OK) {
+ return(TRUE);
+ }
+ /* Do not release the msg once it returns from the call
+ */
+ return(FALSE);
+ }
+ }
+
+ if ((event_id == CC_MSG_FEATURE) && ((call_id == CC_NO_CALL_ID) ||
+ fim_is_app_generic_features(((cc_feature_t *) msg)->feature_id))) {
+ if (((cc_feature_t *)msg)->feature_id == CC_FEATURE_BLF_ALERT_TONE) {
+ (void)cc_call_action(0, 0, CC_ACTION_PLAY_BLF_ALERTING_TONE, NULL);
+ } else if (((cc_feature_t *)msg)->feature_id == CC_FEATURE_UPD_MEDIA_CAP) {
+ fsmdef_update_media_cap_feature_event(feat_msg);
+ }
+ return(TRUE);
+ }
+
+ /*
+ * Throw away any messages with call_id < 1 (which means they are invalid).
+ *
+ * The GSM will send messages back to itself with a call_id < 1 because
+ * it uses the NULL_DCB. The fsmxfr will use a NULL_DCB that has invalid
+ * data in it, but the DCB points to a valid DCB. This way, the fsmxfr does
+ * not have to keep checking for the NULL.
+ */
+ if (call_id < 1) {
+ return(TRUE);
+ }
+
+
+ /*
+ * Get the call chain associated with this call_id.
+ */
+ call_chn = fim_get_call_chn_by_call_id(call_id);
+
+ if (call_chn == NULL) {
+ /*
+ * No call chain, so get a new call chain,
+ * but only if the event is a call establishment event.
+ */
+ if ((event_id == CC_MSG_SETUP) ||
+ (event_id == CC_MSG_OFFHOOK) ||
+ (event_id == CC_MSG_DIALSTRING) ||
+ (event_id == CC_MSG_LINE) ||
+ (event_id == CC_MSG_CREATEOFFER) ||
+ (event_id == CC_MSG_CREATEANSWER) ||
+ (event_id == CC_MSG_SETLOCALDESC) ||
+ (event_id == CC_MSG_SETREMOTEDESC) ||
+ (event_id == CC_MSG_SETPEERCONNECTION) ||
+ (event_id == CC_MSG_ADDSTREAM) ||
+ (event_id == CC_MSG_REMOVESTREAM) ||
+ (event_id == CC_MSG_ADDCANDIDATE) ||
+ ((event_id == CC_MSG_FEATURE) &&
+ ((((cc_feature_t *) msg)->feature_id == CC_FEATURE_NEW_CALL)))) {
+ call_chn = fim_get_new_call_chn(call_id);
+
+ /*
+ * Make sure we got a new call chain.
+ */
+ if (call_chn == NULL) {
+ FIM_DEBUG(get_debug_string(GSM_DBG1), "FIM", call_id, fname,
+ "no call_chn");
+
+ fsm_display_no_free_lines();
+
+ cc_call_state(call_id, line, CC_STATE_UNKNOWN, NULL);
+ return(TRUE);
+ }
+
+ } else if ((event_id == CC_MSG_FEATURE) &&
+ (fim_check_feature_event(msg))) {
+
+ call_chn = fim_get_new_call_chn(call_id);
+
+ /*
+ * Make sure we got a new call chain.
+ */
+ if (call_chn == NULL) {
+ FIM_DEBUG(get_debug_string(GSM_DBG1), "FIM", call_id, fname,
+ "no call_chn");
+
+ fsm_display_no_free_lines();
+
+ cc_call_state(call_id, line, CC_STATE_UNKNOWN, NULL);
+ return(TRUE);
+ }
+
+ if (fim_feature_need_outgoing_call_context(msg)) {
+ /* Get new outgoing call context using DEF state m/c fsm */
+ if (fsm_get_new_outgoing_call_context(call_id, line,
+ fsm_get_fcb_by_call_id_and_type(call_id, FSM_TYPE_DEF),
+ FALSE) != CC_CAUSE_OK) {
+ cc_call_state(call_id, line, CC_STATE_UNKNOWN, NULL);
+ return(TRUE);
+ }
+ }
+
+ } else {
+ FIM_DEBUG(get_debug_string(GSM_DBG1), "FIM", call_id, fname,
+ "not a call establishment event\n");
+ if( feat_msg->feature_id == CC_FEATURE_UPD_SESSION_MEDIA_CAP) {
+ FIM_DEBUG(DEB_L_C_F_PREFIX"set_next_sess_video_pref = %d\n",
+ DEB_L_C_F_PREFIX_ARGS(FIM, line, call_id, fname),
+ feat_data->caps.support_direction);
+ set_next_sess_video_pref(feat_data->caps.support_direction);
+ }
+ return(TRUE);
+ }
+ if (event_id != CC_MSG_SETUP) {
+ /*
+ * Increment the call chain cnt for this line
+ * For incoming calls, we don't know the line number
+ * when SETUP msg is received, so it's an exception, it'll be
+ * added in fsmdef_idle_setup
+ */
+ lsm_increment_call_chn_cnt(line);
+ }
+ } /* if (call_chn == NULL) */
+
+
+ /*
+ * Pass the event to the call chain unless UI lock has been enabled.
+ */
+ if (call_chn->ui_locked && ((cc_feature_t *) msg)->src_id == CC_SRC_UI) {
+ if (fsm_event_filtered_by_ui_lock(event_id,
+ ((cc_feature_t *)msg)->feature_id)) {
+ FIM_DEBUG(DEB_L_C_F_PREFIX" %s filtered by UI lock\n",
+ DEB_L_C_F_PREFIX_ARGS(FIM, line, call_id, fname),
+ cc_feature_name(((cc_feature_t *)msg)->feature_id));
+ return(TRUE);
+ }
+ }
+
+ /*
+ * Skip the head.
+ */
+ icb = call_chn->next_icb;
+ PR_ASSERT(icb);
+ while (icb && !done) {
+ /*
+ * Set the required event data so the entity can process the event.
+ */
+ cb_hdr = (fim_cb_hdr_t *) (icb->cb);
+
+ PR_ASSERT(cb_hdr);
+ if (!cb_hdr) {
+ done = TRUE;
+ break;
+ }
+
+ event.data = cb_hdr;
+ event.state = cb_hdr->state;
+ event.event = event_id;
+ event.msg = data;
+
+ fcb = (fsm_fcb_t *) icb->cb;
+
+ /*
+ * For example, if we receive INVITE and CANCEL messages back to back,
+ * we may be decrementing the call count of wrong line because SIP stack did
+ * not get the correct value for line yet.
+ * so set the line value to correct value from DCB.
+ * For RIU calls, there will be no DCB. However, line value cames from SIP stack
+ * correctly.
+ */
+
+ if ((fcb->fsm_type == FSM_TYPE_DEF) && (event_id == CC_MSG_RELEASE)) {
+ if (fcb->dcb != NULL) {
+ line = fcb->dcb->line;
+ }
+ }
+
+ /*
+ * This update_call_cnt is only used when RC_CLEANUP is returned.
+ */
+ update_call_cnt = TRUE; // by default, always update call count
+ if (fcb->dcb != NULL) {
+ update_call_cnt = (fcb->dcb->call_not_counted_in_mnc_bt) ? FALSE: TRUE;
+ }
+
+ FIM_DEBUG(DEB_L_C_F_PREFIX" %s(%s:%s)\n",
+ DEB_L_C_F_PREFIX_ARGS(FIM, line, call_id, fname), fsm_type_name(icb->scb->type),
+ fsm_state_name(fcb->fsm_type, event.state),
+ cc_msg_name((cc_msgs_t) (event.event)));
+
+ rc = sm_process_event(icb->scb->sm, &event);
+
+
+ switch (rc) {
+ case SM_RC_CONT:
+ case SM_RC_DEF_CONT:
+ icb = icb->next_icb;
+ break;
+
+ case SM_RC_END:
+ done = TRUE;
+ break;
+
+ case SM_RC_ERROR:
+ FIM_DEBUG(DEB_L_C_F_PREFIX" fsm sm error(%d:%d)\n",
+ DEB_L_C_F_PREFIX_ARGS(FIM, line, call_id, fname), event.state, event.event);
+ done = TRUE;
+ cc_call_state(call_id, line, CC_STATE_UNKNOWN, NULL);
+ break;
+
+ case SM_RC_CLEANUP:
+ done = TRUE;
+ cc_call_state(call_id, line, CC_STATE_UNKNOWN, NULL);
+ break;
+
+ default:
+ done = TRUE;
+ cc_call_state(call_id, line, CC_STATE_UNKNOWN, NULL);
+ break;
+ } /* switch (rc) */
+
+ if ((rc == SM_RC_END) && (fcb->fsm_type == FSM_TYPE_DEF) &&
+ (event_id == CC_MSG_FEATURE))
+ {
+ if ( ((cc_feature_t *) msg)->feature_id == CC_FEATURE_CFWD_ALL){
+ lsm_decrement_call_chn_cnt(line);
+ }
+ }
+
+ if (icb == NULL) {
+ done = TRUE;
+ FIM_DEBUG("icb is null and get here!");
+ }
+
+ } /* while (done != TRUE) { */
+
+ if (rc == SM_RC_CLEANUP) {
+ fim_free_call_chn(call_chn, line, update_call_cnt);
+
+ }
+
+ return(TRUE);
+}
+
+
+cc_int32_t
+fim_show_cmd (cc_int32_t argc, const char *argv[])
+{
+ fim_icb_t *icb = NULL;
+ fim_scb_t *scb = NULL;
+ int i = 0;
+
+ /*
+ * Check if need help.
+ */
+ if ((argc == 2) && (argv[1][0] == '?')) {
+ debugif_printf("%s", "show fim\n");
+ }
+
+ /*
+ * Print the icbs.
+ */
+ debugif_printf("%s", "\n---------------------------------- FIM icbs -----------------------------------");
+ debugif_printf("%s", "\ni call_id type icb next_chn next_icb cb scb");
+ debugif_printf("%s", "\n-------------------------------------------------------------------------------\n");
+
+ FSM_FOR_ALL_CBS(icb, fim_icbs, FIM_MAX_ICBS) {
+ debugif_printf("%-3d %-7d %-6s 0x%8p 0x%8p 0x%8p 0x%8p 0x%8p\n",
+ i++, icb->call_id, fsm_type_name(icb->scb->type),
+ icb, icb->next_chn, icb->next_icb, icb->cb, icb->scb);
+ }
+
+ /*
+ * Print the scbs.
+ */
+ i = 0;
+ debugif_printf
+ ("%s", "\n------------------------ FIM scbs ------------------------");
+ debugif_printf("%s", "\ni type scb sm get_cb free_cb");
+ debugif_printf
+ ("%s", "\n----------------------------------------------------------\n");
+
+ FSM_FOR_ALL_CBS(scb, fim_scbs, FIM_MAX_SCBS) {
+ debugif_printf("%-2d %-6s 0x%8p 0x%8p 0x%8p 0x%8p\n",
+ i++, fsm_type_name(scb->type), scb,
+ scb->sm, scb->get_cb, scb->free_cb);
+ }
+
+ return (0);
+}
+
+
+void
+fim_init (void)
+{
+
+ fim_init_call_chns();
+}
+
+void
+fim_shutdown (void)
+{
+ cpr_free(fim_scbs);
+ cpr_free(fim_icbs);
+ fim_scbs = NULL;
+ fim_icbs = NULL;
+}
diff --git a/libs/sipcc/core/gsm/fsm.c b/libs/sipcc/core/gsm/fsm.c
new file mode 100755
index 0000000000..c5f676a9ba
--- /dev/null
+++ b/libs/sipcc/core/gsm/fsm.c
@@ -0,0 +1,1385 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "cpr_types.h"
+#include "cpr_stdlib.h"
+#include "cpr_stdio.h"
+#include "fsm.h"
+#include "fim.h"
+#include "lsm.h"
+#include "sm.h"
+#include "gsm.h" /* for GSM_ERR_MSG */
+#include "ccapi.h"
+#include "phone_debug.h"
+#include "debug.h"
+#include "text_strings.h"
+#include "sip_interface_regmgr.h"
+#include "resource_manager.h"
+#include "platform_api.h"
+
+#define FSM_MAX_FCBS (LSM_MAX_CALLS * (FSM_TYPE_MAX - 1))
+#define FSM_S_IDLE 0
+
+extern sm_table_t *pfsmcnf_sm_table;
+extern sm_table_t *pfsmb2bcnf_sm_table;
+extern sm_table_t *pfsmxfr_sm_table;
+extern sm_table_t *pfsmdef_sm_table;
+
+static fsm_fcb_t *fsm_fcbs;
+static fsmdef_dcb_t fsm_dcb;
+extern uint16_t g_numofselected_calls;
+extern void dcsm_update_gsm_state(fsm_fcb_t *fcb, callid_t call_id, int state);
+
+
+static const char *fsm_type_names[] = {
+ "HEAD",
+ "CNF",
+ "B2BCNF",
+ "XFR",
+ "DEF"
+};
+
+static resource_manager_t *ci_map_p[MAX_REG_LINES + 1];
+static resource_manager_t *shown_calls_ci_map_p[MAX_REG_LINES + 1];
+
+const char *
+fsm_type_name (fsm_types_t type)
+{
+ if ((type <= FSM_TYPE_MIN) || (type >= FSM_TYPE_MAX)) {
+ return (get_debug_string(GSM_UNDEFINED));
+ }
+
+ return (fsm_type_names[type]);
+}
+
+
+const char *
+fsm_state_name (fsm_types_t type, int id)
+{
+ switch (type) {
+ case FSM_TYPE_DEF:
+ return (fsmdef_state_name(id));
+
+ case FSM_TYPE_XFR:
+ return (fsmxfr_state_name(id));
+
+ case FSM_TYPE_CNF:
+ return (fsmcnf_state_name(id));
+
+ case FSM_TYPE_B2BCNF:
+ return (fsmb2bcnf_state_name(id));
+
+ case FSM_TYPE_NONE:
+ return ("IDLE");
+
+ default:
+ return (get_debug_string(GSM_UNDEFINED));
+ }
+}
+
+
+void
+fsm_sm_ftr (cc_features_t ftr_id, cc_srcs_t src_id)
+{
+ FSM_DEBUG_SM(get_debug_string(FSM_DBG_SM_FTR_ENTRY),
+ cc_feature_name(ftr_id), cc_src_name(src_id));
+}
+
+
+void
+fsm_sm_ignore_ftr (fsm_fcb_t *fcb, int fname, cc_features_t ftr_id)
+{
+ FSM_DEBUG_SM(get_debug_string(FSM_DBG_IGNORE_FTR),
+ fsm_type_name(fcb->fsm_type), fcb->call_id, fname,
+ cc_feature_name(ftr_id));
+}
+
+
+void
+fsm_sm_ignore_src (fsm_fcb_t *fcb, int fname, cc_srcs_t src_id)
+{
+ FSM_DEBUG_SM(get_debug_string(FSM_DBG_IGNORE_SRC),
+ fsm_type_name(fcb->fsm_type), fcb->call_id, fname,
+ cc_src_name(src_id));
+}
+
+
+void
+fsm_init_fcb (fsm_fcb_t *fcb, callid_t call_id, fsmdef_dcb_t *dcb,
+ fsm_types_t type)
+{
+ fcb->call_id = call_id;
+
+ fcb->state = FSM_S_IDLE;
+ fcb->old_state = FSM_S_IDLE;
+
+ fcb->fsm_type = type;
+
+ fcb->dcb = dcb;
+
+ fcb->xcb = NULL;
+
+ fcb->ccb = NULL;
+
+ fcb->b2bccb = NULL;
+}
+
+
+/*
+ * ROUTINE: fsm_get_fcb_by_call_id_and_type
+ *
+ * DESCRIPTION: return the fcb referenced by the given call_id and type
+ *
+ * PARAMETERS: fsm_id
+ *
+ * RETURNS: fcb
+ * !NULL: fcb found
+ * NULL: fcb not found
+ *
+ * NOTES:
+ */
+fsm_fcb_t *
+fsm_get_fcb_by_call_id_and_type (callid_t call_id, fsm_types_t type)
+{
+ static const char fname[] = "fsm_get_fcb_by_call_id_and_type";
+ fsm_fcb_t *fcb;
+ fsm_fcb_t *fcb_found = NULL;
+
+ FSM_FOR_ALL_CBS(fcb, fsm_fcbs, FSM_MAX_FCBS) {
+ if ((fcb->call_id == call_id) && (fcb->fsm_type == type)) {
+ fcb_found = fcb;
+ break;
+ }
+ }
+
+ FSM_DEBUG_SM(get_debug_string(GSM_DBG_PTR), "FSM", call_id,
+ fname, "fcb", fcb_found);
+
+ return (fcb_found);
+}
+
+/*
+ * DESCRIPTION: return the fcb referenced by the given call_id and type
+ *
+ * PARAMETERS: fsm_id
+ *
+ * @return void
+ * !NULL: fcb found
+ * NULL: fcb not found
+ *
+ */
+void
+fsm_get_fcb_by_selected_or_connected_call_fcb (callid_t call_id, fsm_fcb_t **con_fcb_found,
+ fsm_fcb_t **sel_fcb_found)
+{
+ static const char fname[] = "fsm_get_fcb_by_selected_or_connected_call_fcb";
+ fsm_fcb_t *fcb;
+
+ *con_fcb_found = NULL;
+ *sel_fcb_found = NULL;
+
+ FSM_FOR_ALL_CBS(fcb, fsm_fcbs, FSM_MAX_FCBS) {
+
+ if (fcb->call_id == call_id) {
+ /* Do not count current call_id */
+ continue;
+ }
+ if (fcb->fsm_type == FSM_TYPE_DEF &&
+ (fcb->state == FSMDEF_S_CONNECTED ||
+ fcb->state == FSMDEF_S_CONNECTED_MEDIA_PEND ||
+ fcb->state == FSMDEF_S_OUTGOING_ALERTING)) {
+ *con_fcb_found = fcb;
+ } else if (fcb->fsm_type == FSM_TYPE_DEF && fcb->dcb->selected) {
+ *sel_fcb_found = fcb;
+ break;
+ }
+ }
+
+ FSM_DEBUG_SM(get_debug_string(GSM_DBG_PTR), "FSM", call_id,
+ fname, "fcb", con_fcb_found);
+
+}
+
+/*
+ * ROUTINE: fsm_get_fcb_by_call_id
+ *
+ * DESCRIPTION: return the fcb referenced by the given call_id
+ *
+ * PARAMETERS: fsm_id
+ *
+ * RETURNS: fcb
+ * !NULL: fcb found
+ * NULL: fcb not found
+ *
+ * NOTES:
+ */
+fsm_fcb_t *
+fsm_get_fcb_by_call_id (callid_t call_id)
+{
+ static const char fname[] = "fsm_get_fcb_by_call_id";
+ fsm_fcb_t *fcb;
+ fsm_fcb_t *fcb_found = NULL;
+
+ FSM_FOR_ALL_CBS(fcb, fsm_fcbs, FSM_MAX_FCBS) {
+ if (fcb->call_id == call_id) {
+ fcb_found = fcb;
+ break;
+ }
+ }
+
+ FSM_DEBUG_SM(get_debug_string(GSM_DBG_PTR), "FSM", call_id,
+ fname, "fcb", fcb_found);
+
+ return (fcb_found);
+}
+
+
+/*
+ * ROUTINE: fsm_get_new_fcb
+ *
+ * DESCRIPTION: return a new fcb initialized with the given data
+ *
+ * PARAMETERS:
+ * call_id: call_id
+ * type: feature type
+ *
+ * RETURNS:
+ * fcb: the new fcb
+ */
+fsm_fcb_t *
+fsm_get_new_fcb (callid_t call_id, fsm_types_t fsm_type)
+{
+ static const char fname[] = "fsm_get_new_fcb";
+ fsm_fcb_t *fcb;
+
+ /*
+ * Get free fcb by using CC_NO_CALL_ID as the call_id because a free fcb
+ * will have a call_id of CC_NO_CALL_ID.
+ */
+ fcb = fsm_get_fcb_by_call_id(CC_NO_CALL_ID);
+ if (fcb != NULL) {
+ fsm_init_fcb(fcb, call_id, FSMDEF_NO_DCB, fsm_type);
+ }
+
+ FSM_DEBUG_SM(get_debug_string(GSM_DBG_PTR), "FSM", call_id,
+ fname, "fcb", fcb);
+
+ return (fcb);
+}
+
+
+fsmdef_dcb_t *
+fsm_get_dcb (callid_t call_id)
+{
+ fsmdef_dcb_t *dcb;
+
+ dcb = fsmdef_get_dcb_by_call_id(call_id);
+
+ /*
+ * Return the fsm default dcb if a dcb was not found.
+ */
+ if (dcb == NULL) {
+ dcb = &fsm_dcb;
+ }
+
+ return (dcb);
+}
+
+
+void
+fsm_get_fcb (fim_icb_t *icb, callid_t call_id)
+{
+ icb->cb = fsm_get_new_fcb(call_id, icb->scb->type);
+}
+
+
+void
+fsm_init_scb (fim_icb_t *icb, callid_t call_id)
+{
+ icb->scb->get_cb = &fsm_get_fcb;
+
+ switch (icb->scb->type) {
+
+ case FSM_TYPE_B2BCNF:
+ icb->scb->sm = pfsmb2bcnf_sm_table;
+ icb->scb->free_cb = fsmb2bcnf_free_cb;
+
+ break;
+
+ case FSM_TYPE_CNF:
+ icb->scb->sm = pfsmcnf_sm_table;
+ icb->scb->free_cb = fsmcnf_free_cb;
+
+ break;
+ case FSM_TYPE_XFR:
+ icb->scb->sm = pfsmxfr_sm_table;
+ icb->scb->free_cb = fsmxfr_free_cb;
+
+ break;
+
+ case FSM_TYPE_DEF:
+ icb->scb->sm = pfsmdef_sm_table;
+ icb->scb->free_cb = fsmdef_free_cb;
+
+ break;
+
+ case FSM_TYPE_HEAD:
+ default:
+ icb->scb->get_cb = NULL;
+ icb->scb->free_cb = NULL;
+ icb->scb->sm = NULL;
+ }
+
+}
+
+
+void
+fsm_change_state (fsm_fcb_t *fcb, int fname, int new_state)
+{
+
+ DEF_DEBUG(DEB_L_C_F_PREFIX"%s: %s -> %s\n",
+ DEB_L_C_F_PREFIX_ARGS(FSM, ((fcb->dcb == NULL)? CC_NO_LINE: fcb->dcb->line),
+ fcb->call_id, "fsm_change_state"),
+ fsm_type_name(fcb->fsm_type),
+ fsm_state_name(fcb->fsm_type, fcb->state),
+ fsm_state_name(fcb->fsm_type, new_state));
+
+ fcb->old_state = fcb->state;
+ fcb->state = new_state;
+ NOTIFY_STATE_CHANGE(fcb, fcb->call_id, new_state);
+
+}
+
+
+void
+fsm_release (fsm_fcb_t *fcb, int fname, cc_causes_t cause)
+{
+ fsm_change_state(fcb, fname, FSM_S_IDLE);
+
+ /* Cleanup any pending cac request for that call */
+ fsm_cac_call_release_cleanup(fcb->call_id);
+
+ fsm_init_fcb(fcb, CC_NO_CALL_ID, FSMDEF_NO_DCB, FSM_TYPE_NONE);
+}
+
+
+cc_int32_t
+fsm_show_cmd (cc_int32_t argc, const char *argv[])
+{
+ fsm_fcb_t *fcb;
+ int i = 0;
+ void *cb = NULL;
+
+ PR_ASSERT(i == 0);
+
+ /*
+ * check if need help
+ */
+ if ((argc == 2) && (argv[1][0] == '?')) {
+ debugif_printf("%s", "show fsm\n");
+ return 0;
+ }
+
+ /*
+ * Print the fcbs
+ */
+ debugif_printf("%s", "\n----------------------------- FSM fcbs -------------------------------");
+ debugif_printf("%s", "\ni call_id fcb type state dcb cb ");
+ debugif_printf("%s", "\n----------------------------------------------------------------------\n");
+
+ FSM_FOR_ALL_CBS(fcb, fsm_fcbs, FSM_MAX_FCBS) {
+ switch (fcb->fsm_type) {
+ case FSM_TYPE_CNF:
+ cb = fcb->ccb;
+ break;
+
+ case FSM_TYPE_B2BCNF:
+ cb = fcb->ccb;
+ break;
+
+ case FSM_TYPE_XFR:
+ cb = fcb->xcb;
+ break;
+
+ case FSM_TYPE_DEF:
+ cb = fcb->dcb;
+ break;
+
+ default:
+ cb = NULL;
+ }
+
+ debugif_printf("%-3d %-7d 0x%8p %-9s %-9s 0x%8p 0x%8p\n",
+ i++, fcb->call_id, fcb, fsm_type_name(fcb->fsm_type),
+ fsm_state_name(fcb->fsm_type, fcb->state),
+ fcb->dcb, cb);
+ }
+
+ return (0);
+}
+
+
+void
+fsm_init (void)
+{
+ fsm_fcb_t *fcb;
+
+ fsmdef_init_dcb(&fsm_dcb, 0, FSMDEF_CALL_TYPE_NONE, NULL, LSM_NO_LINE,
+ NULL);
+
+ fsmdef_init();
+ fsmb2bcnf_init();
+ fsmcnf_init();
+ fsmxfr_init();
+
+ fsm_cac_init();
+
+ /*
+ * Initialize the fcbs.
+ */
+ fsm_fcbs = (fsm_fcb_t *) cpr_calloc(FSM_MAX_FCBS, sizeof(fsm_fcb_t));
+ if (fsm_fcbs == NULL) {
+ GSM_ERR_MSG(GSM_F_PREFIX"Failed to allcoate FSM FCBs.\n", "fsm_init");
+ return;
+ }
+
+ FSM_FOR_ALL_CBS(fcb, fsm_fcbs, FSM_MAX_FCBS) {
+ fsm_init_fcb(fcb, CC_NO_CALL_ID, FSMDEF_NO_DCB, FSM_TYPE_NONE);
+ }
+
+ /*
+ * Init call instance id map.
+ */
+ fsmutil_init_ci_map();
+}
+
+void
+fsm_shutdown (void)
+{
+ fsmdef_shutdown();
+
+ fsmb2bcnf_shutdown();
+
+ fsmcnf_shutdown();
+ fsmxfr_shutdown();
+
+ fsm_cac_shutdown();
+
+ cpr_free(fsm_fcbs);
+ fsm_fcbs = NULL;
+
+ /*
+ * Free call instance id map.
+ */
+ fsmutil_free_ci_map();
+}
+
+/*
+ * ROUTINE: fsm_set_fcb_dcbs
+ *
+ * DESCRIPTION: Set the dcbs for the fsms. The fsm call chain is setup before
+ * the dcb is known, so this function is called after the dcb
+ * is known to set the dcb in the fcbs.
+ *
+ * PARAMETERS:
+ * dcb
+ *
+ * RETURNS: NONE
+ *
+ * NOTES:
+ */
+cc_causes_t
+fsm_set_fcb_dcbs (fsmdef_dcb_t *dcb)
+{
+ callid_t call_id = dcb->call_id;
+ fsm_fcb_t *fcb;
+ fsm_types_t i;
+
+ for (i = FSM_TYPE_CNF; i < FSM_TYPE_MAX; i++) {
+ fcb = fsm_get_fcb_by_call_id_and_type(call_id, i);
+ if (fcb == NULL) {
+ return CC_CAUSE_ERROR;
+ }
+ fcb->dcb = dcb;
+ }
+
+ return CC_CAUSE_OK;
+}
+
+
+/*
+ * ROUTINE: fsm_get_new_outgoing_call_context
+ *
+ * DESCRIPTION: get a new outgoing call context
+ *
+ * PARAMETERS:
+ * fcb
+ * call_id
+ * line
+ *
+ * RETURNS: rc
+ * FSM_SUCCESS: context successfully created
+ * FSM_SUCCESS: context unsuccessfully created
+ *
+ * NOTES:
+ */
+cc_causes_t
+fsm_get_new_outgoing_call_context (callid_t call_id, line_t line,
+ fsm_fcb_t *fcb, boolean expline)
+{
+ static const char fname[] = "fsm_get_new_outgoing_call_context";
+ fsmdef_dcb_t *dcb;
+ cc_causes_t cause = CC_CAUSE_OK;
+ cc_causes_t lsm_rc;
+
+ /*
+ * Get a dcb to handle the call.
+ */
+ dcb = fsmdef_get_new_dcb(call_id);
+ if (dcb == NULL) {
+ return CC_CAUSE_NO_RESOURCE;
+ }
+
+ /*
+ * Get a free facility associated with this line.
+ */
+ lsm_rc = lsm_get_facility_by_line(call_id, line, expline, dcb);
+ if (lsm_rc != CC_CAUSE_OK) {
+ FSM_DEBUG_SM(get_debug_string(FSM_DBG_FAC_ERR), call_id, fname,
+ "lsm_get_facility_by_line failed", cc_cause_name(lsm_rc));
+ }
+
+ /*
+ * If no line was returned, then init the dcb with an invalid line to
+ * indicate that no line was returned.
+ */
+ if (lsm_rc != CC_CAUSE_OK) {
+ line = LSM_NO_LINE;
+ }
+ fsmdef_init_dcb(dcb, call_id, FSMDEF_CALL_TYPE_OUTGOING, NULL, line, fcb);
+
+ cause = fsm_set_fcb_dcbs(dcb);
+ if (cause == CC_CAUSE_OK) {
+ cause = lsm_rc;
+ }
+
+ FSM_DEBUG_SM(get_debug_string(FSM_DBG_FAC_FOUND), call_id, fname,
+ dcb->line);
+
+ return cause;
+}
+
+
+/*
+ * ROUTINE: fsm_get_new_incoming_call_context
+ *
+ * DESCRIPTION: get a new incoming call context
+ *
+ * PARAMETERS:
+ * fcb
+ * call_id
+ *
+ * RETURNS: rc
+ * FSM_SUCCESS: context successfully created
+ * FSM_SUCCESS: context unsuccessfully created
+ *
+ * NOTES:
+ */
+cc_causes_t
+fsm_get_new_incoming_call_context (callid_t call_id, fsm_fcb_t *fcb,
+ const char *called_number, boolean expline)
+{
+ static const char fname[] = "fsm_get_new_incoming_call_context";
+ fsmdef_dcb_t *dcb;
+ line_t free_line;
+ cc_causes_t cause;
+ cc_causes_t lsm_rc;
+
+
+ /*
+ * Get a dcb to handle the call.
+ */
+ dcb = fsmdef_get_new_dcb(call_id);
+ if (dcb == NULL) {
+ return CC_CAUSE_NO_RESOURCE;
+ }
+
+ /*
+ * Get a free facility associated with this called_number.
+ */
+ if ((lsm_rc = lsm_get_facility_by_called_number(call_id, called_number,
+ &free_line, expline, dcb))
+ != CC_CAUSE_OK) {
+ /*
+ * Set a default free line (This should really be changed
+ * to a special invalid value and GSM modified to recognize it.)
+ * The dcb is needed in order for GSM to clean up the call correctly.
+ */
+ free_line = 1;
+ FSM_DEBUG_SM(get_debug_string(FSM_DBG_FAC_ERR), call_id, fname,
+ "lsm_get_facility_by_called_number",
+ cc_cause_name(lsm_rc));
+ }
+
+ fsmdef_init_dcb(dcb, call_id, FSMDEF_CALL_TYPE_INCOMING, called_number,
+ free_line, fcb);
+
+ cause = fsm_set_fcb_dcbs(dcb);
+ if (cause == CC_CAUSE_OK) {
+ cause = lsm_rc;
+ }
+
+ FSM_DEBUG_SM(get_debug_string(FSM_DBG_FAC_FOUND), call_id, fname,
+ dcb->line);
+
+ return cause;
+}
+
+/*
+ * fsmutil_is_cnf_leg
+ *
+ * Description:
+ *
+ * Returns TRUE if conferencing is active for the call_id
+ *
+ *
+ * Parameters:
+ *
+ * call_id - ccapi call identifier associated with the call.
+ * fsmxcb_ccbs - pointer to all conf ccbs
+ * max_ccbs - Max number of ccbs to check
+ *
+ * Returns TRUE if the conferencing is active for the call_id
+ */
+int
+fsmutil_is_cnf_leg (callid_t call_id, fsmcnf_ccb_t *fsmcnf_ccbs,
+ unsigned short max_ccbs)
+{
+ fsmcnf_ccb_t *ccb;
+
+ FSM_FOR_ALL_CBS(ccb, fsmcnf_ccbs, max_ccbs) {
+ if ((ccb->cnf_call_id == call_id) || (ccb->cns_call_id == call_id)) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*
+ * fsmutil_is_xfr_leg
+ *
+ * Description:
+ *
+ * Returns transfer mode if the specified leg identified by call_id is
+ * participating in a xfer
+ *
+ * Parameters:
+ *
+ * call_id - ccapi call identifier associated with the call.
+ * fsmxfr_xcbs - pointer to all xfr ccbs
+ * max_xcbs - Max number of ccbs to check
+ *
+ * Returns: fsmxfr_modes_t
+ */
+int
+fsmutil_is_xfr_leg (callid_t call_id, fsmxfr_xcb_t *fsmxfr_xcbs,
+ unsigned short max_xcbs)
+{
+ fsmxfr_xcb_t *xcb;
+
+ FSM_FOR_ALL_CBS(xcb, fsmxfr_xcbs, max_xcbs) {
+ if ((xcb->xfr_call_id == call_id) || (xcb->cns_call_id == call_id)) {
+ return xcb->mode;
+ }
+ }
+ return FSMXFR_MODE_MIN;
+}
+
+void
+fsm_display_no_free_lines (void)
+{
+ char tmp_str[STATUS_LINE_MAX_LEN];
+
+ if ((platGetPhraseText(STR_INDEX_NO_FREE_LINES,
+ (char *)tmp_str,
+ (STATUS_LINE_MAX_LEN - 1))) == CPR_SUCCESS) {
+ lsm_ui_display_notify(tmp_str, NO_FREE_LINES_TIMEOUT);
+ }
+}
+
+/*
+ * Function: fsm_display_use_line_or_join_to_complete
+ *
+ * Description:
+ * The function is used to put up the status line
+ * "Use Line or Join to Complete"
+ *
+ * @param None
+ *
+ * @return None
+ */
+void
+fsm_display_use_line_or_join_to_complete (void)
+{
+ char tmp_str[STATUS_LINE_MAX_LEN];
+
+ if ((platGetPhraseText(STR_INDEX_USE_LINE_OR_JOIN_TO_COMPLETE,
+ (char *)tmp_str,
+ (STATUS_LINE_MAX_LEN - 1))) == CPR_SUCCESS) {
+ lsm_ui_display_notify(tmp_str, NO_FREE_LINES_TIMEOUT);
+ }
+}
+
+void
+fsm_display_feature_unavailable (void)
+{
+ char tmp_str[STATUS_LINE_MAX_LEN];
+
+ if ((platGetPhraseText(STR_INDEX_FEAT_UNAVAIL,
+ (char *)tmp_str,
+ (STATUS_LINE_MAX_LEN - 1))) == CPR_SUCCESS) {
+ lsm_ui_display_notify(tmp_str, NO_FREE_LINES_TIMEOUT);
+ }
+}
+
+void
+fsm_set_call_status_feature_unavailable (callid_t call_id, line_t line)
+{
+ char tmp_str[STATUS_LINE_MAX_LEN];
+
+ if ((platGetPhraseText(STR_INDEX_FEAT_UNAVAIL,
+ (char *)tmp_str,
+ (STATUS_LINE_MAX_LEN - 1))) == CPR_SUCCESS) {
+ ui_set_call_status(tmp_str, line, lsm_get_ui_id(call_id));
+ }
+}
+
+/**
+ *
+ * Get total number of selected calls.
+ *
+ * @param void
+ *
+ * @return uint16_t
+ *
+ * @pre (none)
+ */
+uint16_t fsmutil_get_num_selected_calls (void)
+{
+ return(g_numofselected_calls);
+}
+
+/**
+ * This function will hide/unhide ringingin calls.
+ *
+ * @param[in] hide - indicates whether calls should be hidden or unhidden
+ *
+ * @return none
+ */
+void fsm_display_control_ringin_calls (boolean hide)
+{
+ fsm_fcb_t *fcb;
+
+ FSM_FOR_ALL_CBS(fcb, fsm_fcbs, FSM_MAX_FCBS) {
+ if ((fcb->state == FSMDEF_S_INCOMING_ALERTING) &&
+ (lsm_is_it_priority_call(fcb->call_id) == FALSE)) { /* priority call should not be hidden */
+ lsm_display_control_ringin_call (fcb->call_id, fcb->dcb->line, hide);
+ if (hide == TRUE) {
+ fsmutil_clear_shown_calls_ci_element(fcb->dcb->caller_id.call_instance_id, fcb->dcb->line);
+ } else {
+ fsmutil_set_shown_calls_ci_element(fcb->dcb->caller_id.call_instance_id, fcb->dcb->line);
+ }
+ }
+ }
+}
+
+/*
+ * fsmutil_init_groupid
+ *
+ * Description:
+ *
+ * Assign the group id to the default control block.
+ *
+ * Parameters:
+ * dcb - default control block
+ * call_id - ccapi call identifier associated with the call
+ * call_type - incoming or outgoing call
+ *
+ * Returns: None. groupid will be assigned in the dcb.
+ */
+void
+fsmutil_init_groupid (fsmdef_dcb_t *dcb, callid_t call_id,
+ fsmdef_call_types_t call_type)
+{
+ fsmcnf_ccb_t *ccb = NULL;
+
+ /* if this was a consult leg of a conference then there will be
+ * a ccb on the primary leg
+ */
+ dcb->group_id = CC_NO_GROUP_ID;
+ if (call_type != FSMDEF_CALL_TYPE_NONE) {
+ ccb = fsmcnf_get_ccb_by_call_id(call_id);
+ if (ccb) {
+ /* consult leg of a conference */
+ fsmdef_dcb_t *other_dcb = NULL;
+
+ other_dcb =
+ fsmdef_get_dcb_by_call_id(fsmcnf_get_other_call_id(ccb, call_id));
+ if (other_dcb) {
+ dcb->group_id = other_dcb->group_id;
+ }
+ } else {
+ /* either a primary or some other leg; not part of any conference */
+
+ dcb->group_id = dcb->call_id;
+ }
+ }
+ return;
+}
+
+/**
+ *
+ * Find out if the call pointed by call_id is a consult call
+ * of a conference, transfer.
+ *
+ * @param line line related to that call
+ * @param call_id call_id
+ *
+ * @return call attributes
+ *
+ * @pre none
+ */
+int
+fsmutil_get_call_attr (fsmdef_dcb_t *dcb,
+ line_t line, callid_t call_id)
+{
+ int call_attr;
+
+ if (fsmutil_is_cnf_consult_call(call_id) == TRUE) {
+ call_attr = LOCAL_CONF_CONSULT;
+ } else if (fsmutil_is_b2bcnf_consult_call(call_id) == TRUE) {
+ call_attr = CONF_CONSULT;
+ } else if (fsmutil_is_xfr_consult_call(call_id) == TRUE) {
+ call_attr = XFR_CONSULT;
+ } else {
+ if (dcb == NULL) {
+ return(NORMAL_CALL);
+ }
+
+ switch (dcb->active_feature) {
+ case CC_FEATURE_CFWD_ALL:
+ call_attr = CC_ATTR_CFWD_ALL;
+ break;
+ default:
+ call_attr = NORMAL_CALL;
+ break;
+ }
+ }
+ return call_attr;
+}
+
+/*
+ * fsmutil_is_cnf_consult_leg
+ *
+ * Description:
+ * Returns TRUE if the specified call_id is for a call that is
+ * the consultative call of a conference.
+ *
+ * Parameters:
+ * call_id - ccapi call identifier associated with the call.
+ * fsmxcb_ccbs - pointer to all conf ccbs
+ * max_ccbs - Max number of ccbs to check
+ *
+ * Returns: TRUE if consultative call; otherwise, FALSE.
+ */
+int
+fsmutil_is_cnf_consult_leg (callid_t call_id, fsmcnf_ccb_t *fsmcnf_ccbs,
+ uint16_t max_ccbs)
+{
+ fsmcnf_ccb_t *ccb;
+
+ FSM_FOR_ALL_CBS(ccb, fsmcnf_ccbs, max_ccbs) {
+ if (ccb->cns_call_id == call_id) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+/*
+ * fsmutil_is_xfr_consult_leg
+ *
+ * Description:
+ * Returns TRUE if the specified call_id is for a call that is
+ * the consultative call of a transfer only when that consult
+ * was an initiated transfer.
+ *
+ * Parameters:
+ * call_id - ccapi call identifier associated with the call.
+ * fsmxfr_xcbs - pointer to all xfr ccbs
+ * max_xcbs - Max number of ccbs to check
+ *
+ * Returns: TRUE if consultative call; otherwise, FALSE.
+ */
+int
+fsmutil_is_xfr_consult_leg (callid_t call_id, fsmxfr_xcb_t *fsmxfr_xcbs,
+ uint16_t max_xcbs)
+{
+ fsmxfr_xcb_t *xcb;
+
+ FSM_FOR_ALL_CBS(xcb, fsmxfr_xcbs, max_xcbs) {
+ if ((xcb->mode == FSMXFR_MODE_TRANSFEROR) &&
+ (xcb->cns_call_id == call_id)) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*
+ * fsmutil_clear_feature_invocation_state
+ *
+ * Description:
+ * This function clears the feature invocation state of the feature id
+ * supplied. This function is used by the code that would receive the
+ * feature ack (from SIP stack).
+ *
+ * Note: Code responsible for invoking features and receiving feature acks
+ * must call this function to clear the feature invocation state.
+ *
+ * Parameters:
+ * fsmdef_dcb_t *dcb - dcb associated with the call
+ * cc_features_t feature_id - feature id in question
+ *
+ * Returns: None
+ */
+static void
+fsmutil_clear_feature_invocation_state (fsmdef_dcb_t *dcb,
+ cc_features_t feature_id)
+{
+ if ((feature_id < CC_FEATURE_NONE) || (feature_id >= CC_FEATURE_MAX)) {
+ /* Log Error */
+ GSM_ERR_MSG(GSM_L_C_F_PREFIX"Invalid feature id -> %d\n", dcb->line, dcb->call_id, "fsmutil_clear_feature_invocation_state", feature_id);
+ return;
+ }
+
+ rm_clear_element((resource_manager_t *) dcb->feature_invocation_state,
+ (int16_t) feature_id);
+}
+
+/*
+ * fsmutil_process_feature_ack
+ *
+ * Description:
+ * This function implements the generic feature ack processing.
+ * Feature invocation state is Cleared when feature ack is received.
+ *
+ * Parameters:
+ * fsmdef_dcb_t *dcb - dcb associated with the call
+ * cc_features_t feature_id - feature id in question
+ *
+ * Returns: None
+ */
+void
+fsmutil_process_feature_ack (fsmdef_dcb_t *dcb, cc_features_t feature_id)
+{
+ /* clear the feature invocation state (was set when invoked) */
+ fsmutil_clear_feature_invocation_state(dcb, feature_id);
+}
+
+/*
+ * fsmutil_clear_all_feature_invocation_state
+ *
+ * Description:
+ * This function clears the feature invocation state of ALL features.
+ *
+ * This function may be used by the code that would initialize/reset
+ * the state machine.
+ *
+ * Parameters:
+ * fsmdef_dcb_t *dcb - dcb associated with the call
+ *
+ * Returns: None
+ */
+void
+fsmutil_clear_all_feature_invocation_state (fsmdef_dcb_t *dcb)
+{
+ rm_clear_all_elements((resource_manager_t *) dcb->feature_invocation_state);
+}
+
+/*
+ * fsmutil_init_feature_invocation_state
+ *
+ * Description:
+ * Utility function to allocate and init a feature invocation state table.
+ *
+ * Parameters:
+ * dcb - dcb whose feature invocation state table is being created
+ *
+ * Returns:
+ * none
+ */
+void
+fsmutil_init_feature_invocation_state (fsmdef_dcb_t *dcb)
+{
+ static const char fname[] = "fsmutil_init_feature_invocation_state";
+
+ dcb->feature_invocation_state = rm_create(CC_FEATURE_MAX);
+
+ if (!dcb->feature_invocation_state) {
+ GSM_ERR_MSG(GSM_L_C_F_PREFIX"failed to allocate feature invocation state table\n", dcb->line, dcb->call_id,
+ fname);
+ }
+}
+
+
+/*
+ * fsmutil_free_feature_invocation_state
+ *
+ * Description:
+ * Utility function to free the feature invocation state table of the
+ * specified dcb.
+ *
+ * Parameters:
+ * None
+ *
+ * Returns:
+ * None
+ */
+void
+fsmutil_free_feature_invocation_state (fsmdef_dcb_t *dcb)
+{
+ rm_destroy((resource_manager_t *) dcb->feature_invocation_state);
+ dcb->feature_invocation_state = NULL;
+}
+
+/*
+ * fsmutil_free_all_ci_id
+ *
+ * Description:
+ * This function clears the entire call instance map.
+ *
+ * Parameters:
+ * None
+ *
+ * Returns:
+ * None
+ */
+void
+fsmutil_free_all_ci_id (void)
+{
+ uint16_t line;
+
+ for (line = 1; line <= MAX_REG_LINES; line++) {
+ rm_clear_all_elements((resource_manager_t *) ci_map_p[line]);
+ }
+}
+
+/*
+ * fsmutil_free_ci_id
+ *
+ * Description:
+ * This function clears a specified call instance id from
+ * the call instance map.
+ *
+ * Note that call instance ids are one based. The resource manager
+ * used to implement the call instance map is zero based so we have
+ * to adjust the call instance id when using the resource manager API.
+ *
+ * Parameters:
+ * id - the call instance id to be freed
+ * line - line from where to free the call instance id
+ *
+ * Returns:
+ * None
+ */
+void
+fsmutil_free_ci_id (uint16_t id, line_t line)
+{
+ static const char fname[] = "fsmutil_free_ci_id";
+
+ if (id < 1 || id > MAX_CALLS) {
+ GSM_ERR_MSG(GSM_F_PREFIX"specified id %d is invalid\n", fname, id);
+ return;
+ }
+
+ if (line < 1 || line > MAX_REG_LINES) {
+ GSM_ERR_MSG(GSM_F_PREFIX"specified line %d is invalid\n", fname, line);
+ return;
+ }
+
+ rm_clear_element((resource_manager_t *) ci_map_p[line], (int16_t) --id);
+}
+
+#ifdef LOCAL_UI_CALLINSTANCE_ID
+/*This routine is not needed now as the local assignment
+ *of call instance id is no longer supported.
+ */
+/*
+ * fsmutil_get_ci_id
+ *
+ * Description:
+ * This function locates the next available call instance id in
+ * the call instance map. This function is utilized when operating in
+ * the peer to peer mode to assign call instance ids for inbound
+ * and outbound calls.
+ *
+ * Note that call instance ids are one based. The resource manager
+ * used to implement the call instance map is zero based so we have
+ * to adjust the call instance id when using the resource manager API.
+ *
+ * Parameters:
+ * line - line from where to retrieve the call instance id
+ *
+ * Returns:
+ * uint16_t - Non-zero call instance id. 0 if no call instance ids
+ * are available.
+ */
+uint16_t
+fsmutil_get_ci_id (line_t line)
+{
+ static const char fname[] = "fsmutil_get_ci_id";
+ int16_t id;
+ uint16_t return_id = 0;
+
+ if (line < 1 || line > MAX_REG_LINES) {
+ GSM_ERR_MSG("specified line %d is invalid\n", fname, line);
+ return 0;
+ }
+
+ id = rm_get_free_element(ci_map_p[line]);
+ if (id >= 0) {
+ return_id = ++id;
+ }
+ return (return_id);
+}
+#endif
+
+/*
+ * fsmutil_set_ci_id
+ *
+ * Description:
+ * This function marks a specified call instance id as being in
+ * use in the call instance map. This function is used when in
+ * CCM mode to store the call instance id specified by the CCM
+ * for inbound and outbound calls.
+ *
+ * Note that call instance ids are one based. The resource manager
+ * used to implement the call instance map is zero based so we have
+ * to adjust the call instance id when using the resource manager API.
+ * Parameters:
+ *
+ * Parameters:
+ * id - The call instance id to set.
+ * line - Line being used for the call.
+ *
+ * Returns:
+ * None
+ */
+void
+fsmutil_set_ci_id (uint16_t id, line_t line)
+{
+ static const char fname[] = "fsmutil_set_ci_id";
+
+ if (id < 1 || id > MAX_CALLS) {
+ GSM_ERR_MSG(GSM_F_PREFIX"specified id %d is invalid\n", fname, id);
+ return;
+ }
+
+ if (line < 1 || line > MAX_REG_LINES) {
+ GSM_ERR_MSG(GSM_F_PREFIX"specified line %d is invalid\n", fname, line);
+ return;
+ }
+
+ rm_set_element(ci_map_p[line], (int16_t) --id);
+}
+
+/*
+ * fsmutil_init_ci_map
+ *
+ * Description:
+ * Utility function to allocate and init the call instance id map.
+ *
+ * Parameters:
+ * None
+ *
+ * Returns:
+ * None
+ */
+void
+fsmutil_init_ci_map (void)
+{
+ static const char fname[] = "fsmutil_init_ci_map";
+ uint16_t line;
+
+ for (line = 1; line <= MAX_REG_LINES; line++) {
+ ci_map_p[line] = rm_create(MAX_CALLS);
+
+ if (!ci_map_p[line]) {
+ GSM_ERR_MSG(GSM_F_PREFIX"failed to allocate call instance id map for line %d",
+ fname, line);
+ }
+ }
+}
+
+/**
+ * This function will allocate and initialize the shown_calls_call_instnace map.
+ *
+ * @return none
+ */
+void fsmutil_init_shown_calls_ci_map (void)
+{
+ static const char fname[] = "fsmutil_init_shown_calls_ci_map";
+ uint16_t line;
+
+ for (line = 1; line <= MAX_REG_LINES; line++) {
+ shown_calls_ci_map_p[line] = rm_create(MAX_CALLS);
+
+ if (!shown_calls_ci_map_p[line]) {
+ GSM_ERR_MSG(GSM_F_PREFIX"failed to allocate shown calls call instance id map for line %d",
+ fname, line);
+ }
+ }
+}
+
+/**
+ * This function will set the shown_calls_call_instnace map to zeros.
+ *
+ * @return none
+ */
+void fsmutil_free_all_shown_calls_ci_map (void)
+{
+ uint16_t line;
+
+ for (line = 1; line <= MAX_REG_LINES; line++) {
+ rm_clear_all_elements((resource_manager_t *) shown_calls_ci_map_p[line]);
+ }
+}
+
+/**
+ * This function marks a given call to be hidden.
+ *
+ * @param[in] id - call instance id of the call to be hidden.
+ * @param[in] line - the line being used for the call.
+ *
+ * @return none
+ */
+void fsmutil_clear_shown_calls_ci_element (uint16_t id, line_t line)
+{
+ static const char fname[] = "fsmutil_clear_shown_calls_ci_element";
+
+ if (id < 1 || id > MAX_CALLS) {
+ GSM_ERR_MSG(GSM_F_PREFIX"specified id %d is invalid\n", fname, id);
+ return;
+ }
+
+ if (line < 1 || line > MAX_REG_LINES) {
+ GSM_ERR_MSG(GSM_F_PREFIX"specified line %d is invalid\n", fname, line);
+ return;
+ }
+
+ rm_clear_element((resource_manager_t *) shown_calls_ci_map_p[line], (int16_t)(id - 1));
+}
+
+/**
+ * This function marks a given call to be shown.
+ *
+ * @param[in] id - call instance id of the call to be shown.
+ * @param[in] line - the line being used for the call.
+ *
+ * @return none
+ */
+void fsmutil_set_shown_calls_ci_element (uint16_t id, line_t line)
+{
+ static const char fname[] = "fsmutil_set_shown_calls_ci_element";
+
+ if (id < 1 || id > MAX_CALLS) {
+ GSM_ERR_MSG(GSM_F_PREFIX"specified id %d is invalid\n", fname, id);
+ return;
+ }
+
+ if (line < 1 || line > MAX_REG_LINES) {
+ GSM_ERR_MSG(GSM_F_PREFIX"specified line %d is invalid\n", fname, line);
+ return;
+ }
+
+ rm_set_element(shown_calls_ci_map_p[line], (int16_t)(id - 1));
+}
+
+/**
+ * This function checks if a given call is to be shown.
+ *
+ * @param[in] id - call instance id of the call.
+ * @param[in] line - the line being used for the call.
+ *
+ * @return none
+ */
+boolean fsmutil_is_shown_calls_ci_element_set (uint16_t id, line_t line)
+{
+ static const char fname[] = "fsmutil_is_shown_calls_ci_element_set";
+
+ if (id < 1 || id > MAX_CALLS) {
+ GSM_ERR_MSG(GSM_F_PREFIX"specified id %d is invalid\n", fname, id);
+ return FALSE;
+ }
+
+ if (line < 1 || line > MAX_REG_LINES) {
+ GSM_ERR_MSG(GSM_F_PREFIX"specified line %d is invalid\n", fname, line);
+ return FALSE;
+ }
+
+ if (rm_is_element_set(shown_calls_ci_map_p[line], (int16_t)(id - 1))) {
+ return (TRUE);
+ }
+
+ return (FALSE);
+}
+
+/*
+ * fsmutil_free_ci_map
+ *
+ * Description:
+ * Utility function to free the call instance id map.
+ *
+ * Parameters:
+ * None
+ *
+ * Returns:
+ * None
+ */
+void
+fsmutil_free_ci_map (void)
+{
+ uint16_t line;
+
+ for (line = 1; line <= MAX_REG_LINES; line++) {
+ rm_destroy((resource_manager_t *) ci_map_p[line]);
+ ci_map_p[line] = NULL;
+ }
+}
+
+/*
+ * fsmutil_show_ci_map
+ *
+ * Description:
+ * Utility function to display the current state of the call
+ * instance map.
+ *
+ * Parameters:
+ * None
+ *
+ * Returns:
+ * None
+ */
+void
+fsmutil_show_ci_map (void)
+{
+ uint16_t line;
+
+ for (line = 1; line <= MAX_REG_LINES; line++) {
+ rm_show(ci_map_p[line]);
+ }
+}
diff --git a/libs/sipcc/core/gsm/fsmb2bcnf.c b/libs/sipcc/core/gsm/fsmb2bcnf.c
new file mode 100755
index 0000000000..aa8423ab28
--- /dev/null
+++ b/libs/sipcc/core/gsm/fsmb2bcnf.c
@@ -0,0 +1,1285 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "cpr_types.h"
+#include "cpr_stdlib.h"
+#include "cpr_stdio.h"
+#include "cpr_string.h"
+#include "fsm.h"
+#include "fim.h"
+#include "lsm.h"
+#include "sm.h"
+#include "ccapi.h"
+#include "phone_debug.h"
+#include "text_strings.h"
+#include "debug.h"
+#include "config.h"
+#include "uiapi.h"
+#include "phntask.h"
+#include "regmgrapi.h"
+#include "subapi.h"
+#include "rcc_int_types.h"
+
+static fsmcnf_ccb_t *fsmb2bcnf_ccbs;
+
+typedef enum {
+ FSMB2BCNF_S_MIN = -1,
+ FSMB2BCNF_S_IDLE,
+ FSMB2BCNF_S_ACTIVE,
+ FSMB2BCNF_S_MAX
+} fsmb2bcnf_states_t;
+
+static const char *fsmb2bcnf_state_names[] = {
+ "IDLE",
+ "ACTIVE"
+};
+
+
+static sm_rcs_t fsmb2bcnf_ev_idle_feature(sm_event_t *event);
+static sm_rcs_t fsmb2bcnf_ev_active_release(sm_event_t *event);
+static sm_rcs_t fsmb2bcnf_ev_active_release_complete(sm_event_t *event);
+static sm_rcs_t fsmb2bcnf_ev_active_feature(sm_event_t *event);
+static sm_rcs_t fsmb2bcnf_ev_active_feature_ack(sm_event_t *event);
+static sm_rcs_t fsmb2bcnf_ev_active_onhook(sm_event_t *event);
+
+static sm_function_t fsmb2bcnf_function_table[FSMB2BCNF_S_MAX][CC_MSG_MAX] =
+{
+/* FSMB2BCNF_S_IDLE ------------------------------------------------------------ */
+ {
+ /* FSMB2BCNF_E_SETUP */ NULL,
+ /* FSMB2BCNF_E_SETUP_ACK */ NULL,
+ /* FSMB2BCNF_E_PROCEEDING */ NULL,
+ /* FSMB2BCNF_E_ALERTING */ NULL,
+ /* FSMB2BCNF_E_CONNECTED */ NULL,
+ /* FSMB2BCNF_E_CONNECTED_ACK */ NULL,
+ /* FSMB2BCNF_E_RELEASE */ NULL,
+ /* FSMB2BCNF_E_RELEASE_COMPLETE */ NULL,
+ /* FSMB2BCNF_E_FEATURE */ fsmb2bcnf_ev_idle_feature,
+ /* FSMB2BCNF_E_FEATURE_ACK */ NULL,
+ /* FSMB2BCNF_E_OFFHOOK */ NULL,
+ /* FSMB2BCNF_E_ONHOOK */ NULL,
+ /* FSMB2BCNF_E_LINE */ NULL,
+ /* FSMB2BCNF_E_DIGIT_BEGIN */ NULL,
+ /* FSMB2BCNF_E_DIGIT */ NULL,
+ /* FSMB2BCNF_E_DIALSTRING */ NULL,
+ /* FSMB2BCNF_E_MWI */ NULL,
+ /* FSMB2BCNF_E_SESSION_AUDIT */ NULL
+ },
+
+/* FSMB2BCNF_S_ACTIVE --------------------------------------------------- */
+ {
+ /* FSMB2BCNF_E_SETUP */ NULL,
+ /* FSMB2BCNF_E_SETUP_ACK */ NULL,
+ /* FSMB2BCNF_E_PROCEEDING */ NULL,
+ /* FSMB2BCNF_E_ALERTING */ fsmb2bcnf_ev_active_feature,
+ /* FSMB2BCNF_E_CONNECTED */ NULL,
+ /* FSMB2BCNF_E_CONNECTED_ACK */ NULL,
+ /* FSMB2BCNF_E_RELEASE */ fsmb2bcnf_ev_active_release,
+ /* FSMB2BCNF_E_RELEASE_COMPLETE */ fsmb2bcnf_ev_active_release_complete,
+ /* FSMB2BCNF_E_FEATURE */ fsmb2bcnf_ev_active_feature,
+ /* FSMB2BCNF_E_FEATURE_ACK */ fsmb2bcnf_ev_active_feature_ack,
+ /* FSMB2BCNF_E_OFFHOOK */ NULL,
+ /* FSMB2BCNF_E_ONHOOK */ fsmb2bcnf_ev_active_onhook,
+ /* FSMB2BCNF_E_LINE */ NULL,
+ /* FSMB2BCNF_E_DIGIT_BEGIN */ NULL,
+ /* FSMB2BCNF_E_DIGIT */ NULL,
+ /* FSMB2BCNF_E_DIALSTRING */ NULL,
+ /* FSMB2BCNF_E_MWI */ NULL,
+ /* FSMB2BCNF_E_SESSION_AUDIT */ NULL
+ }
+};
+
+static sm_table_t g_fsmb2bcnf_sm_table;
+sm_table_t *pfsmb2bcnf_sm_table = &g_fsmb2bcnf_sm_table;
+
+const char *
+fsmb2bcnf_state_name (int state)
+{
+ if ((state <= FSMB2BCNF_S_MIN) || (state >= FSMB2BCNF_S_MAX)) {
+ return (get_debug_string(GSM_UNDEFINED));
+ }
+
+ return (fsmb2bcnf_state_names[state]);
+}
+
+
+static int
+fsmb2bcnf_get_new_b2bcnf_id (void)
+{
+ static int b2bcnf_id = FSM_NO_ID;
+
+ if (++b2bcnf_id < FSM_NO_ID) {
+ b2bcnf_id = 1;
+ }
+
+ return (b2bcnf_id);
+}
+
+
+static void
+fsmb2bcnf_init_ccb (fsmcnf_ccb_t *ccb)
+{
+ if (ccb != NULL) {
+ ccb->cnf_id = FSM_NO_ID;
+ ccb->cnf_call_id = CC_NO_CALL_ID;
+ ccb->cns_call_id = CC_NO_CALL_ID;
+ ccb->cnf_line = CC_NO_LINE;
+ ccb->cns_line = CC_NO_LINE;
+ ccb->bridged = FALSE;
+ ccb->active = FALSE;
+ ccb->cnf_ftr_ack = FALSE;
+ ccb->cnf_orig = CC_SRC_MIN;
+ }
+}
+
+/**
+ *
+ * Get active trasnfer state machine information (in active state).
+ *
+ * @param none
+ *
+ * @return fsm_fcb_t if there is a active trasnfer pending
+ * else NULL
+ *
+ * @pre (none)
+ */
+
+fsm_fcb_t *fsmb2bcnf_get_active_cnf(void)
+{
+ fsm_fcb_t *fcb;
+ fsmcnf_ccb_t *b2bccb;
+
+ FSM_FOR_ALL_CBS(b2bccb, fsmb2bcnf_ccbs, FSMCNF_MAX_CCBS) {
+ fcb = fsm_get_fcb_by_call_id_and_type(b2bccb->cnf_call_id,
+ FSM_TYPE_B2BCNF);
+ if (fcb && fcb->state == FSMB2BCNF_S_ACTIVE) {
+ return(fcb);
+ }
+ }
+
+ return(NULL);
+}
+
+static fsmcnf_ccb_t *
+fsmb2bcnf_get_ccb_by_b2bcnf_id (int b2bcnf_id)
+{
+ fsmcnf_ccb_t *ccb;
+ fsmcnf_ccb_t *ccb_found = NULL;
+
+ FSM_FOR_ALL_CBS(ccb, fsmb2bcnf_ccbs, FSMCNF_MAX_CCBS) {
+ if (ccb->cnf_id == b2bcnf_id) {
+ ccb_found = ccb;
+
+ break;
+ }
+ }
+
+ return (ccb_found);
+}
+
+
+/*
+ * Function: fsmb2bcnf_get_new_b2bcnf_context
+ *
+ * Parameters:
+ * b2bcnf_call_id: call_id for the call initiating the conference
+ *
+ * Description: This function creates a new conference context by:
+ * - getting a free ccb
+ * - creating new b2bcnf_id and cns_call_id
+ *
+ * Returns: ccb
+ *
+ */
+static fsmcnf_ccb_t *
+fsmb2bcnf_get_new_b2bcnf_context (callid_t b2bcnf_call_id, line_t line)
+{
+ const char fname[] = "fsmb2bcnf_get_new_b2bcnf_context";
+ fsmcnf_ccb_t *ccb;
+
+ ccb = fsmb2bcnf_get_ccb_by_b2bcnf_id(FSM_NO_ID);
+ if (ccb != NULL) {
+ ccb->cnf_id = fsmb2bcnf_get_new_b2bcnf_id();
+ ccb->cnf_call_id = b2bcnf_call_id;
+ ccb->cnf_line = line;
+ ccb->cns_line = line;
+ ccb->cns_call_id = cc_get_new_call_id();
+
+ FSM_DEBUG_SM(get_debug_string(FSMB2BCNF_DBG_PTR), ccb->cnf_id,
+ ccb->cnf_call_id, ccb->cns_call_id, fname, ccb);
+ } else {
+
+ GSM_DEBUG_ERROR(GSM_F_PREFIX"Failed to get new b2bccb.\n", fname);
+ }
+
+ return (ccb);
+}
+
+
+static fsmcnf_ccb_t *
+fsmb2bcnf_get_ccb_by_call_id (callid_t call_id)
+{
+ fsmcnf_ccb_t *ccb;
+ fsmcnf_ccb_t *ccb_found = NULL;
+
+ FSM_FOR_ALL_CBS(ccb, fsmb2bcnf_ccbs, FSMCNF_MAX_CCBS) {
+ if ((ccb->cnf_call_id == call_id) || (ccb->cns_call_id == call_id)) {
+ ccb_found = ccb;
+
+ break;
+ }
+ }
+
+ return (ccb_found);
+}
+
+
+static void
+fsmb2bcnf_update_b2bcnf_context (fsmcnf_ccb_t *ccb, callid_t old_call_id,
+ callid_t new_call_id)
+{
+ const char fname[] = "fsmb2bcnf_update_b2bcnf_context";
+
+ if (ccb != NULL) {
+ if (old_call_id == ccb->cnf_call_id) {
+ ccb->cnf_call_id = new_call_id;
+ } else if (old_call_id == ccb->cns_call_id) {
+ ccb->cns_call_id = new_call_id;
+ }
+
+ FSM_DEBUG_SM(get_debug_string(FSMB2BCNF_DBG_PTR), ccb->cnf_id,
+ ccb->cnf_call_id, ccb->cns_call_id, fname, ccb);
+ }
+}
+
+/*
+ * Function to get line number of other call associated in
+ * transfer.
+ *
+ * @param xcb and call_id.
+ *
+ * @return void
+ *
+ */
+line_t
+fsmb2bcnf_get_other_line (fsmcnf_ccb_t *ccb, callid_t call_id)
+{
+ line_t other_line = CC_NO_LINE;
+
+ if (ccb != NULL) {
+ if (ccb->cnf_call_id == call_id) {
+ other_line = ccb->cns_line;
+ } else if (ccb->cns_call_id == call_id) {
+ other_line = ccb->cnf_line;
+ }
+ }
+
+ return (other_line);
+}
+
+static callid_t
+fsmb2bcnf_get_other_call_id (fsmcnf_ccb_t *ccb, callid_t call_id)
+{
+ callid_t other_call_id = CC_NO_CALL_ID;
+
+ if (ccb != NULL) {
+ if (ccb->cnf_call_id == call_id) {
+ other_call_id = ccb->cns_call_id;
+ } else if (ccb->cns_call_id == call_id) {
+ other_call_id = ccb->cnf_call_id;
+ }
+ }
+
+ return (other_call_id);
+}
+
+/*
+ * Function: fsmb2bcnf_remove_fcb
+ *
+ * Parameters:
+ * b2bcnf_id: b2bcnf_id for the conference
+ * call_id: call_id that identifies the fcb to be removed
+ *
+ * Description: This function will remove the fcb identified by the given
+ * call_id from the ccb. And the function will free the ccb
+ * if both fcbs have been removed.
+ *
+ * Returns: none
+ *
+ * Note: This is a helper function for fsmb2bcnf_cleanup. It allows fsmb2bcnf_cleanup
+ * to cleanup one fcb (one call involved in the conference) independent
+ * of the other involved fcb.
+ */
+static void
+fsmb2bcnf_remove_fcb (fsm_fcb_t *fcb, callid_t call_id)
+{
+ fsmcnf_ccb_t *ccb = fcb->b2bccb;
+
+ if (ccb != NULL) {
+ fsmb2bcnf_update_b2bcnf_context(ccb, call_id, CC_NO_CALL_ID);
+
+ /*
+ * Free the ccb if both fcb references have been removed.
+ */
+ if ((ccb->cnf_call_id == CC_NO_CALL_ID) &&
+ (ccb->cns_call_id == CC_NO_CALL_ID)) {
+ fsmb2bcnf_init_ccb(ccb);
+ }
+ }
+}
+
+
+static void
+fsmb2bcnf_cleanup (fsm_fcb_t *fcb, int fname, boolean both)
+{
+ fsm_fcb_t *other_fcb = NULL;
+ callid_t call_id = fcb->call_id;
+ callid_t other_call_id = CC_NO_CALL_ID;
+ line_t other_line;
+
+ other_call_id = fsmb2bcnf_get_other_call_id(fcb->b2bccb, call_id);
+ other_line = fsmb2bcnf_get_other_line(fcb->b2bccb, call_id);
+
+ if (other_call_id != CC_NO_CALL_ID) {
+ other_fcb = fsm_get_fcb_by_call_id_and_type(other_call_id,
+ FSM_TYPE_B2BCNF);
+ }
+
+ if (fcb->b2bccb && (call_id == fcb->b2bccb->cnf_call_id)) {
+
+ if (other_call_id != CC_NO_CALL_ID) {
+ /*
+ * Not clearing consulation call, so change consultation
+ * call attribute to display connected softkey set.
+ * Do not change softkey set if it is a transfer o
+ */
+ cc_call_attribute(other_call_id, other_line, NORMAL_CALL);
+ }
+
+ }
+ /*
+ * Check if the user wanted to cleanup the whole ccb.
+ * If so, then we will grab the other fcb first and call this function
+ * again with this other fcb. The whole ccb will be freed after this block
+ * of code because both call_ids will be -1, which tells
+ * fsmb2bcnf_remove_fcb to free the ccb.
+ */
+ if (both) {
+ if (other_call_id != CC_NO_CALL_ID) {
+ if (other_fcb != NULL) {
+ fsmb2bcnf_cleanup(other_fcb, fname, FALSE);
+ }
+ }
+ }
+ /*
+ * Remove the reference to this fcb from the ccb.
+ */
+ fsmb2bcnf_remove_fcb(fcb, fcb->call_id);
+
+ /*
+ * Move this fcb to the IDLE state
+ */
+ fsm_change_state(fcb, fname, FSMB2BCNF_S_IDLE);
+
+ /*
+ * Reset the data for this fcb. The fcb is still included in a call
+ * so set the call_id and dcb values accordingly.
+ */
+ fsm_init_fcb(fcb, fcb->call_id, fcb->dcb, FSM_TYPE_B2BCNF);
+}
+
+
+void
+fsmb2bcnf_free_cb (fim_icb_t *icb, callid_t call_id)
+{
+ fsm_fcb_t *fcb = NULL;
+
+ if (call_id != CC_NO_CALL_ID) {
+ fcb = fsm_get_fcb_by_call_id_and_type(call_id, FSM_TYPE_B2BCNF);
+
+ if (fcb != NULL) {
+ fsmb2bcnf_cleanup(fcb, __LINE__, FALSE);
+ fsm_init_fcb(fcb, CC_NO_CALL_ID, FSMDEF_NO_DCB, FSM_TYPE_NONE);
+ }
+ }
+}
+
+
+/*
+ * fsmb2bcnf_check_if_ok_to_setup_conf
+ *
+ * Description:
+ * Checks if the requested call is ok to setup conference.
+ *
+ * Parameters:
+ * call_id
+ *
+ * Returns: TRUE - if the call is ok to setup conference
+ * FALSE - other cases
+ */
+boolean
+fsmb2bcnf_check_if_ok_to_setup_conf (callid_t call_id)
+{
+ fsmdef_dcb_t *dcb;
+
+ if (call_id == CC_NO_CALL_ID) {
+ return (FALSE);
+ }
+
+ dcb = fsm_get_dcb(call_id);
+
+ if(dcb && dcb->policy == CC_POLICY_CHAPERONE
+ && dcb->is_conf_call == TRUE){
+ return (FALSE);
+ }
+
+ return (TRUE);
+}
+
+
+/*
+ * fsmb2bcnf_b2bcnf_invoke
+ *
+ * Description:
+ * This function implements the conference feature invocation.
+ * If the feature is already invoked and waiting for the
+ * feature ack back from the SIP stack then no action taken.
+ * Otherwise, the conf feature is invoked and state is SET.
+ *
+ * Parameters:
+ * fsmdef_dcb_t *dcb - dcb associated with this call
+ *
+ * Returns: None
+ */
+static void
+fsmb2bcnf_cnf_invoke (callid_t call_id, callid_t target_call_id,
+ line_t line, fsmcnf_ccb_t *ccb)
+{
+ sipspi_msg_t subscribe_msg;
+ ccsip_event_data_t *evt_data;
+
+ /*
+ * post SIPSPI_EV_CC_SUBSCRIBE to SIP stack
+ */
+ evt_data = (ccsip_event_data_t *)
+ cpr_malloc(sizeof(ccsip_event_data_t));
+ if (evt_data == NULL) {
+ return;
+ }
+ memset(evt_data, 0, sizeof(ccsip_event_data_t));
+ evt_data->type = EVENT_DATA_REMOTECC_REQUEST;
+ evt_data->u.remotecc_data.line = 0;
+ evt_data->u.remotecc_data.rcc_request_type = RCC_SOFTKEY_EVT;
+ evt_data->u.remotecc_data.rcc_int.rcc_softkey_event_msg.softkeyevent = RCC_SOFTKEY_CONFERENCE;
+ evt_data->u.remotecc_data.consult_gsm_id = target_call_id;
+ evt_data->u.remotecc_data.gsm_id = call_id;
+
+ memset(&subscribe_msg, 0, sizeof(sipspi_msg_t));
+ subscribe_msg.msg.subscribe.eventPackage = CC_SUBSCRIPTIONS_REMOTECC;
+ subscribe_msg.msg.subscribe.sub_id = CCSIP_SUBS_INVALID_SUB_ID;
+ subscribe_msg.msg.subscribe.auto_resubscribe = TRUE;
+ subscribe_msg.msg.subscribe.request_id = (long)ccb;
+ subscribe_msg.msg.subscribe.duration = 60;
+ subscribe_msg.msg.subscribe.subsNotCallbackTask = CC_SRC_GSM;
+ subscribe_msg.msg.subscribe.subsResCallbackMsgID = SUB_MSG_B2BCNF_SUBSCRIBE_RESP;
+ subscribe_msg.msg.subscribe.subsNotIndCallbackMsgID = SUB_MSG_B2BCNF_NOTIFY;
+ subscribe_msg.msg.subscribe.subsTermCallbackMsgID = SUB_MSG_B2BCNF_TERMINATE;
+ subscribe_msg.msg.subscribe.norefersub = FALSE;
+ subscribe_msg.msg.subscribe.eventData = evt_data;
+ subscribe_msg.msg.subscribe.dn_line = line;
+
+ (void)sub_int_subscribe(&subscribe_msg);
+}
+
+/**
+ *
+ * Cancel b2b conference feature by sending cancel event to SIP stack.
+ * This routine is used in roundtable phone.
+ *
+ * @param line, call_id, target_call_id, cause (implicit or explicit)
+ *
+ * @return void
+ *
+ * @pre (none)
+ */
+void
+fsmb2bcnf_feature_cancel (fsmcnf_ccb_t *ccb, line_t line, callid_t call_id,
+ callid_t target_call_id,
+ cc_rcc_skey_evt_type_e cause)
+{
+ cc_feature_data_t data;
+ fsm_fcb_t *fcb_def;
+
+ fcb_def = fsm_get_fcb_by_call_id_and_type(call_id, FSM_TYPE_DEF);
+
+ if ((cause == CC_SK_EVT_TYPE_EXPLI) &&
+ (fcb_def != NULL) && ((fcb_def->dcb->selected == FALSE) &&
+ ((fcb_def->state == FSMDEF_S_OUTGOING_ALERTING) ||
+ ((fcb_def->state == FSMDEF_S_CONNECTED) &&
+ (fcb_def->dcb->spoof_ringout_requested == TRUE) &&
+ (fcb_def->dcb->spoof_ringout_applied == TRUE))))) {
+
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, call_id,
+ line, CC_FEATURE_END_CALL, NULL);
+ }
+
+ fcb_def = fsm_get_fcb_by_call_id_and_type(target_call_id, FSM_TYPE_DEF);
+
+ if ((cause == CC_SK_EVT_TYPE_EXPLI) &&
+ (fcb_def != NULL) && ((fcb_def->dcb->selected == FALSE) &&
+ ((fcb_def->state == FSMDEF_S_OUTGOING_ALERTING) ||
+ ((fcb_def->state == FSMDEF_S_CONNECTED) &&
+ (fcb_def->dcb->spoof_ringout_requested == TRUE) &&
+ (fcb_def->dcb->spoof_ringout_applied == TRUE))))) {
+
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, target_call_id,
+ line, CC_FEATURE_END_CALL, NULL);
+ }
+
+ data.cancel.target_call_id = target_call_id;
+ data.cancel.call_id = call_id;
+ data.cancel.cause = cause;
+
+ cc_int_feature(CC_SRC_GSM, CC_SRC_SIP, call_id,
+ line, CC_FEATURE_CANCEL, &data);
+}
+
+/*******************************************************************
+ * event functions
+ */
+
+
+static sm_rcs_t
+fsmb2bcnf_ev_idle_feature (sm_event_t *event)
+{
+ const char *fname = "fsmb2bcnf_ev_idle_feature";
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ cc_feature_t *msg = (cc_feature_t *) event->msg;
+ callid_t call_id = msg->call_id;
+ line_t line = msg->line;
+ cc_srcs_t src_id = msg->src_id;
+ cc_features_t ftr_id = msg->feature_id;
+ cc_feature_data_t *ftr_data = &(msg->data);
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ callid_t cns_call_id;
+ sm_rcs_t sm_rc = SM_RC_CONT;
+ fsmcnf_ccb_t *ccb;
+ int free_lines;
+ cc_feature_data_t data;
+ fsm_fcb_t *other_fcb, *cns_fcb;
+ fsm_fcb_t *fcb_def;
+ callid_t other_call_id;
+ line_t newcall_line = 0;
+
+ fsm_sm_ftr(ftr_id, src_id);
+
+ switch (src_id) {
+ case CC_SRC_RCC:
+ case CC_SRC_UI:
+ switch (ftr_id) {
+ case CC_FEATURE_B2BCONF:
+ /* Connect the existing call to active trasnfer state
+ * machine. If the UI generates the event with target
+ * call_id in the data then terminate the existing consulatative
+ * call and link that to another call.
+ */
+ if (ftr_data && msg->data_valid &&
+ (ftr_data->b2bconf.target_call_id != CC_NO_CALL_ID)
+ && (cns_fcb = fsm_get_fcb_by_call_id_and_type(ftr_data->b2bconf.target_call_id,
+ FSM_TYPE_B2BCNF)) != NULL) {
+ /*
+ * Get a new ccb and new b2bcnf id - This is the handle that will
+ * identify the b2bcnf.
+ */
+ ccb = fsmb2bcnf_get_new_b2bcnf_context(call_id, line);
+
+ if (ccb==NULL || ccb->cnf_id == FSM_NO_ID) {
+ return(SM_RC_END);
+ }
+
+ /* Conference origination id, required later. This indicates conf is
+ * because of UI or because of CTI
+ */
+ ccb->cnf_orig = src_id;
+
+ ccb->cns_call_id = ftr_data->b2bconf.target_call_id;
+ fcb->b2bccb = ccb;
+ cns_fcb->b2bccb = ccb;
+
+ /* Find line information for target call.
+ */
+ fcb_def = fsm_get_fcb_by_call_id_and_type(call_id, FSM_TYPE_DEF);
+ if (fcb_def != NULL && fcb_def->dcb) {
+
+ ccb->cns_line = fcb_def->dcb->line;
+
+ } else {
+
+ return(SM_RC_END);
+ }
+
+ fsm_change_state(fcb, __LINE__, FSMB2BCNF_S_ACTIVE);
+
+ fsm_change_state(cns_fcb, __LINE__, FSMB2BCNF_S_ACTIVE);
+
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, ccb->cns_call_id,
+ ccb->cns_line, CC_FEATURE_B2BCONF, NULL);
+ return(SM_RC_END);
+
+ }
+
+
+ /*
+ * This call is the conference and we are initiating a local
+ * conference. So:
+ * 1. Make sure we have a free line to open a new call plane to
+ * collect digits (and place call) for the consultation call,
+ * 2. Create a new conference context,
+ * 3. Place this call on hold,
+ * 4. Send a newcall feature back to the GSM so that the
+ * consultation call can be initiated.
+ */
+
+ /*
+ * Check for any other active features which may block
+ * the conference.
+ */
+
+ /*
+ * The call must be in the connected state to initiate a conference
+ */
+ fcb_def = fsm_get_fcb_by_call_id_and_type(call_id, FSM_TYPE_DEF);
+ if ((fcb_def != NULL) && (fcb_def->state != FSMDEF_S_CONNECTED)) {
+ break;
+ }
+
+ /*
+ * Make sure we have a free line to start the consultation call.
+ */
+ //CSCsz38962 don't use expline for b2bcnf call
+ //free_lines = lsm_get_instances_available_cnt(line, TRUE);
+ free_lines = lsm_get_instances_available_cnt(line, FALSE);
+ if (free_lines <= 0) {
+ /*
+ * No free lines - let the user know and end this request.
+ */
+ fsm_display_no_free_lines();
+
+ break;
+ }
+
+ newcall_line = lsm_get_newcall_line(line);
+ if (newcall_line == NO_LINES_AVAILABLE) {
+ /*
+ * Error Pass Limit- let the user know and end this request.
+ */
+ lsm_ui_display_notify_str_index(STR_INDEX_ERROR_PASS_LIMIT);
+
+ break;
+ }
+
+ /*
+ * Get a new ccb and new b2bcnf id - This is the handle that will
+ * identify the b2bcnf.
+ */
+ ccb = fsmb2bcnf_get_new_b2bcnf_context(call_id, line);
+
+ if (ccb==NULL || ccb->cnf_id == FSM_NO_ID) {
+ break;
+ }
+
+ ccb->cnf_orig = src_id;
+ fcb->b2bccb = ccb;
+ ccb->cns_line = newcall_line;
+
+ /*
+ * This call needs to go on hold so we can start the consultation
+ * call. Indicate feature indication should be send by setting
+ * call info type to hold and feature reason to conference.
+ */
+ memset(&data, 0, sizeof(data));
+ data.hold.call_info.type = CC_FEAT_HOLD;
+ data.hold.call_info.data.hold_resume_reason = CC_REASON_CONF;
+ data.hold.msg_body.num_parts = 0;
+ data.hold.call_info.data.call_info_feat_data.protect = TRUE;
+
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, dcb->call_id, dcb->line,
+ CC_FEATURE_HOLD, &data);
+
+ /*
+ * Initiate the consultation call.
+ */
+ data.newcall.cause = CC_CAUSE_CONF;
+ cns_call_id = ccb->cns_call_id;
+ sstrncpy(data.newcall.global_call_id,
+ ftr_data->b2bconf.global_call_id, CC_GCID_LEN);
+ data.newcall.prim_call_id = ccb->cnf_call_id;
+ data.newcall.hold_resume_reason = CC_REASON_CONF;
+
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, cns_call_id, newcall_line,
+ CC_FEATURE_NEW_CALL, &data);
+
+ FSM_DEBUG_SM(get_debug_string(FSMB2BCNF_DBG_CNF_INITIATED),
+ ccb->cnf_id, call_id, cns_call_id, __LINE__);
+
+ fsm_change_state(fcb, __LINE__, FSMB2BCNF_S_ACTIVE);
+
+ sm_rc = SM_RC_END;
+ break;
+
+ default:
+ fsm_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ sm_rc = SM_RC_DEF_CONT;
+ break;
+ } /* switch (ftr_id) */
+ break;
+
+ case CC_SRC_GSM:
+ switch (ftr_id) {
+ case CC_FEATURE_NOTIFY:
+
+ /* Since this message is specifically for conference, msg is
+ * consumed here and not forwarded
+ */
+ if ((msg->data.notify.subscription == CC_SUBSCRIPTIONS_REMOTECC)
+ && (msg->data.notify.data.rcc.feature == CC_FEATURE_B2BCONF)) {
+ sm_rc = SM_RC_END;
+ }
+ break;
+ case CC_FEATURE_NEW_CALL:
+ /*
+ * If this is the consultation call involved in a conference,
+ * then set the rest of the data required to make the conference
+ * happen. The data is the b2bcnf_id in the fcb. The data is set now
+ * because we did not have the fcb when the conference was
+ * initiated. The fcb is created when a new_call event is
+ * received by the FIM, not when a conference event is received.
+ *
+ * Or this could be the call that originated the conference and
+ * the person he was talking to (the conference target) has
+ * decided to conference the trasnferor to another party.
+ */
+
+ /*
+ * Ignore this event if this call is not involved in a conference.
+ */
+ ccb = fsmb2bcnf_get_ccb_by_call_id(call_id);
+ if (ccb == NULL) {
+ break;
+ }
+ fcb->b2bccb = ccb;
+
+ /*
+ * Determine what state this b2bcnf should be in (b2bcnfing or b2bcnfed).
+ * If the cnfrn key has only been hit once, then this call will
+ * be in the cnfing state. If it has been hit the second time,
+ * then this call should go to the cnfed state. The latter
+ * case only happens when the calls are conferenced and one
+ * of the remote ends has decided to transfer one leg of the cnf.
+ * And it just so happens that the other call involved in the cnf
+ * should match this call, so we can just use it's state to
+ * assign the state to this call.
+ */
+ other_call_id = fsmb2bcnf_get_other_call_id(ccb, call_id);
+ other_fcb = fsm_get_fcb_by_call_id_and_type(other_call_id,
+ FSM_TYPE_B2BCNF);
+
+ if (other_fcb == NULL) {
+ GSM_DEBUG_ERROR(GSM_F_PREFIX"FCP not found \n", fname);
+ } else {
+ fsm_change_state(fcb, __LINE__, other_fcb->state);
+ }
+ break;
+
+ default:
+ fsm_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ sm_rc = SM_RC_DEF_CONT;
+ break;
+ } /* switch (ftr_id) */
+ break;
+
+ default:
+ fsm_sm_ignore_src(fcb, __LINE__, src_id);
+ sm_rc = SM_RC_DEF_CONT;
+ break;
+ } /* switch (src_id) */
+
+ return (sm_rc);
+}
+
+
+static sm_rcs_t
+fsmb2bcnf_ev_active_release (sm_event_t *event)
+{
+
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmcnf_ccb_t *ccb = fcb->b2bccb;
+
+ /* For round table phone wait for NOTIFY response, so do not
+ * clear the conf state machine
+ */
+ if (ccb->active == FALSE) {
+ fsmb2bcnf_feature_cancel(ccb, ccb->cnf_line, ccb->cnf_call_id,
+ ccb->cns_call_id, CC_SK_EVT_TYPE_IMPLI);
+ fsmb2bcnf_cleanup((fsm_fcb_t *) event->data, __LINE__, TRUE);
+ }
+
+ return (SM_RC_CONT);
+}
+
+static sm_rcs_t
+fsmb2bcnf_ev_active_release_complete (sm_event_t *event)
+{
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmcnf_ccb_t *ccb = fcb->b2bccb;
+
+ if (ccb->active == FALSE) {
+
+
+ fsmb2bcnf_cleanup((fsm_fcb_t *) event->data, __LINE__, TRUE);
+ }
+
+ return (SM_RC_CONT);
+}
+
+static sm_rcs_t
+fsmb2bcnf_ev_active_feature (sm_event_t *event)
+{
+ static const char fname[] = "fsmb2bcnf_ev_active_feature";
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ cc_feature_t *msg = (cc_feature_t *) event->msg;
+ callid_t call_id = msg->call_id;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ fsmcnf_ccb_t *ccb = fcb->b2bccb;
+ cc_srcs_t src_id = msg->src_id;
+ cc_features_t ftr_id = msg->feature_id;
+ cc_feature_data_t *feat_data = &(msg->data);
+ sm_rcs_t sm_rc = SM_RC_CONT;
+ callid_t other_call_id;
+ fsmdef_dcb_t *other_dcb;
+ fsm_fcb_t *other_fcb;
+ cc_action_data_t action_data;
+ fsm_fcb_t *cnf_fcb = NULL;
+
+ fsm_sm_ftr(ftr_id, src_id);
+
+ memset(&action_data, 0, sizeof(cc_action_data_t));
+
+ switch (src_id) {
+ case CC_SRC_UI:
+ case CC_SRC_RCC:
+ case CC_SRC_GSM:
+ switch (ftr_id) {
+ case CC_FEATURE_CANCEL:
+ sm_rc = SM_RC_END;
+ fsmb2bcnf_feature_cancel(ccb, ccb->cnf_line, ccb->cnf_call_id,
+ ccb->cns_call_id,
+ CC_SK_EVT_TYPE_EXPLI);
+ fsmb2bcnf_cleanup(fcb, __LINE__, TRUE);
+ break;
+
+ case CC_FEATURE_HOLD:
+ /* Do not send out protect parameter for CTI generated conference
+ * and send protect=true for swap or hold call
+ */
+ if ((msg->data_valid) &&
+ (feat_data->hold.call_info.data.hold_resume_reason == CC_REASON_SWAP ||
+ feat_data->hold.call_info.data.hold_resume_reason == CC_REASON_CONF ||
+ feat_data->hold.call_info.data.hold_resume_reason == CC_REASON_INTERNAL))
+ {
+ feat_data->hold.call_info.data.call_info_feat_data.protect = TRUE;
+ } else if ((msg->data_valid) &&
+ (feat_data->hold.call_info.data.hold_resume_reason == CC_REASON_RCC)) {
+ //Do nothing remote-cc will terminate the feature layer.
+
+ } else {
+ DEF_DEBUG(DEB_F_PREFIX"Invoke hold call_id = %d t_call_id=%d\n",
+ DEB_F_PREFIX_ARGS(GSM, fname), ccb->cnf_call_id, ccb->cns_call_id);
+ //Actual hold to this call, so break the feature layer.
+ ui_terminate_feature(ccb->cnf_line, ccb->cnf_call_id, ccb->cns_call_id);
+ fsmb2bcnf_feature_cancel(ccb, ccb->cnf_line, ccb->cnf_call_id,
+ ccb->cns_call_id, CC_SK_EVT_TYPE_IMPLI);
+ fsmb2bcnf_cleanup(fcb, __LINE__, TRUE);
+ }
+ fsm_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ break;
+
+ case CC_FEATURE_B2BCONF:
+ /* Connect the existing call to active trasnfer state
+ * machine. If the UI generates the event with target
+ * call_id in the data then terminate the existing consulatative
+ * call and link that to another call.
+ */
+ DEF_DEBUG(DEB_F_PREFIX"ACTIVE CNF call_id = %d, t_id = %d, cns_id=%d\n",
+ DEB_F_PREFIX_ARGS(GSM, fname), ccb->cnf_call_id,
+ feat_data->b2bconf.target_call_id, ccb->cns_call_id);
+
+ if (feat_data && msg->data_valid &&
+ (feat_data->b2bconf.target_call_id != CC_NO_CALL_ID)) {
+ /* End existing consult call and then link another
+ * call with the trasfer. This is the case where User can
+ * select active call instead of consultative call
+ */
+ cnf_fcb = fsm_get_fcb_by_call_id_and_type(ccb->cns_call_id,
+ FSM_TYPE_DEF);
+
+ /* If the call_id is different then active call has been picked
+ */
+
+ if (ccb->cns_call_id != feat_data->b2bconf.target_call_id) {
+
+ cnf_fcb = fsm_get_fcb_by_call_id_and_type(ccb->cns_call_id,
+ FSM_TYPE_B2BCNF);
+
+ if (cnf_fcb != NULL) {
+ DEF_DEBUG(DEB_F_PREFIX"INVOKE ACTIVE CNF call_id = %d, t_id=%d\n",
+ DEB_F_PREFIX_ARGS(GSM, fname), ccb->cnf_call_id,
+ feat_data->b2bconf.target_call_id);
+
+ cnf_fcb->b2bccb = ccb;
+ fsm_change_state(cnf_fcb, __LINE__, FSMB2BCNF_S_ACTIVE);
+
+
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, ccb->cns_call_id,
+ ccb->cnf_line, CC_FEATURE_B2BCONF, NULL);
+ }
+
+ return(SM_RC_END);
+ }
+ }
+ /*
+ * This is the second conference event for a local
+ * attended conference with consultation.
+ *
+ * The user is attempting to complete the conference, so
+ * resume the other leg of the conference call.
+ */
+ ccb->active = TRUE;
+
+ if (dcb) {
+ dcb->active_feature = CC_FEATURE_B2BCONF;
+ }
+
+ other_call_id = fsmb2bcnf_get_other_call_id(ccb, call_id);
+ other_dcb = fsm_get_dcb(other_call_id);
+
+ //Update confinvoked value through JPlatUi method.
+ ui_update_conf_invoked(other_dcb->line, other_call_id, TRUE);
+
+ fsmb2bcnf_cnf_invoke(fsmb2bcnf_get_other_call_id(ccb, call_id),
+ call_id, other_dcb->line, ccb);
+
+ other_fcb = fsm_get_fcb_by_call_id_and_type(other_call_id,
+ FSM_TYPE_B2BCNF);
+
+ fsm_change_state(other_fcb, __LINE__, FSMB2BCNF_S_ACTIVE);
+
+ fsm_change_state(fcb, __LINE__, FSMB2BCNF_S_ACTIVE);
+
+ sm_rc = SM_RC_END;
+
+ break;
+
+ case CC_FEATURE_END_CALL:
+ /* Release ccbs related to conference and allow event to pass through
+ * fsmdef
+ */
+ fsmb2bcnf_feature_cancel(ccb, ccb->cnf_line, ccb->cnf_call_id,
+ ccb->cns_call_id, CC_SK_EVT_TYPE_IMPLI);
+ fsmb2bcnf_cleanup(fcb, __LINE__, TRUE);
+
+ break;
+
+
+ case CC_FEATURE_RESUME:
+ /* to achieve SCCP phone behaviour, if the 1st call is resumed
+ * then conference should be terminated.
+ */
+ if (ccb->cnf_orig == CC_SRC_RCC) {
+ if (ccb->cnf_call_id == call_id) {
+ fsmb2bcnf_feature_cancel(ccb, ccb->cnf_line, ccb->cnf_call_id,
+ ccb->cns_call_id, CC_SK_EVT_TYPE_IMPLI);
+ fsmb2bcnf_cleanup(fcb, __LINE__, TRUE);
+ cc_call_state(dcb->call_id, dcb->line, CC_STATE_CONNECTED,
+ ((cc_state_data_t *) (&(dcb->caller_id))));
+ }
+ }
+ break;
+
+ case CC_FEATURE_NOTIFY:
+
+ if ((msg->data.notify.subscription == CC_SUBSCRIPTIONS_REMOTECC)
+ && (msg->data.notify.data.rcc.feature == CC_FEATURE_B2BCONF)) {
+
+ if (msg->data.notify.cause_code != RCC_SUCCESS) {
+ fsmb2bcnf_feature_cancel(fcb->b2bccb, fcb->b2bccb->cnf_line,
+ fcb->b2bccb->cnf_call_id,
+ fcb->b2bccb->cns_call_id, CC_SK_EVT_TYPE_IMPLI);
+ }
+ /*
+ * Conference key press has been accepted, so now terminate the
+ * conference data structures. This call is now same as any other
+ * regular call. All the future events are handled by fsmdef.
+ */
+ fsmb2bcnf_cleanup(fcb, __LINE__, TRUE);
+ sm_rc = SM_RC_END;
+ }
+ break;
+
+ default:
+ fsm_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ break;
+ } /* switch (ftr_id) */
+ break;
+
+ case CC_SRC_SIP:
+ switch (ftr_id) {
+ case CC_FEATURE_CALL_PRESERVATION:
+ DEF_DEBUG(DEB_F_PREFIX"Invoke hold call_id = %d t_call_id=%d\n",
+ DEB_F_PREFIX_ARGS(GSM, fname), ccb->cnf_call_id, ccb->cns_call_id);
+ //Actual hold to this call, so break the feature layer.
+ ui_terminate_feature(ccb->cnf_line, ccb->cnf_call_id, ccb->cns_call_id);
+ fsmb2bcnf_feature_cancel(ccb, ccb->cnf_line, ccb->cnf_call_id,
+ ccb->cns_call_id, CC_SK_EVT_TYPE_IMPLI);
+ fsmb2bcnf_cleanup(fcb, __LINE__, TRUE);
+ break;
+
+ default:
+ fsm_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ break;
+ } /* switch (ftr_id) */
+ break;
+
+ default:
+ fsm_sm_ignore_src(fcb, __LINE__, src_id);
+ break;
+ } /* switch (src_id) */
+
+ return (sm_rc);
+}
+
+static sm_rcs_t
+fsmb2bcnf_ev_active_feature_ack (sm_event_t *event)
+{
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ cc_feature_ack_t *msg = (cc_feature_ack_t *) event->msg;
+ callid_t call_id = msg->call_id;
+ cc_srcs_t src_id = msg->src_id;
+ cc_features_t ftr_id = msg->feature_id;
+ sm_rcs_t sm_rc = SM_RC_CONT;
+ cc_action_data_t data;
+ callid_t other_call_id;
+ callid_t other_ui_id;
+
+ fsm_sm_ftr(ftr_id, src_id);
+
+ memset(&data, 0, sizeof(cc_action_data_t));
+
+ switch (src_id) {
+ case CC_SRC_GSM:
+ case CC_SRC_SIP:
+ switch (ftr_id) {
+ case CC_FEATURE_B2BCONF:
+ /* Handle 2nd conference key press completion NOTIFY */
+ if (msg->cause == CC_CAUSE_ERROR) {
+ other_call_id =
+ fsmb2bcnf_get_other_call_id(fcb->b2bccb, call_id);
+
+ other_ui_id = lsm_get_ui_id(other_call_id);
+ ui_set_call_status(platform_get_phrase_index_str(CONF_CANNOT_COMPLETE),
+ msg->line, other_ui_id);
+ fsmb2bcnf_feature_cancel(fcb->b2bccb, fcb->b2bccb->cnf_line, fcb->b2bccb->cnf_call_id,
+ fcb->b2bccb->cns_call_id, CC_SK_EVT_TYPE_IMPLI);
+ fsmb2bcnf_cleanup(fcb, __LINE__, TRUE);
+ break;
+ }
+
+ sm_rc = SM_RC_END;
+ break;
+
+ case CC_FEATURE_NOTIFY:
+
+ if ((msg->data.notify.subscription == CC_SUBSCRIPTIONS_REMOTECC) &&
+ (msg->data.notify.data.rcc.feature == CC_FEATURE_B2BCONF)) {
+
+ /*
+ * Conference key press has been accepted, so now terminate the
+ * conference data structures. This call is now same as any other
+ * regular call. All the future events are handled by fsmdef.
+ */
+ fsmb2bcnf_cleanup(fcb, __LINE__, TRUE);
+ sm_rc = SM_RC_END;
+ }
+
+ break;
+
+ default:
+ fsm_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ break;
+ } /* switch (ftr_id) */
+ break;
+
+ default:
+ fsm_sm_ignore_src(fcb, __LINE__, src_id);
+ break;
+ } /* switch (src_id) */
+
+ return (sm_rc);
+}
+
+void
+fsmb2bcnf_get_sub_call_id_from_ccb(fsmcnf_ccb_t *ccb, callid_t *cnf_call_id,
+ callid_t *cns_call_id)
+{
+ static const char fname[] = "fsmb2bcnf_get_sub_call_id_from_ccb";
+
+ DEF_DEBUG(DEB_F_PREFIX"call_id = %d t_call_id=%d\n",
+ DEB_F_PREFIX_ARGS(GSM, fname), ccb->cnf_call_id, ccb->cns_call_id);
+
+ *cnf_call_id = ccb->cnf_call_id;
+ *cns_call_id = ccb->cns_call_id;
+}
+
+static sm_rcs_t
+fsmb2bcnf_ev_active_onhook (sm_event_t *event)
+{
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmcnf_ccb_t *ccb = fcb->b2bccb;
+ cc_onhook_t *msg = (cc_onhook_t *) event->msg;
+
+ /* For RT phone active call list can be invoked during
+ * conf and that genertes onhook event for existing
+ * consult call. Conf state machine is not terminated
+ */
+ if (msg->active_list == CC_REASON_ACTIVECALL_LIST) {
+
+ ccb->cns_line = CC_NO_LINE;
+ ccb->cns_call_id = CC_NO_CALL_ID;
+
+ } else {
+ fsmb2bcnf_feature_cancel(ccb, ccb->cnf_line, ccb->cnf_call_id,
+ ccb->cns_call_id, CC_SK_EVT_TYPE_IMPLI);
+ fsmb2bcnf_cleanup((fsm_fcb_t *) event->data, __LINE__, TRUE);
+ }
+
+ return (SM_RC_CONT);
+}
+
+cc_int32_t
+fsmb2bcnf_show_cmd (cc_int32_t argc, const char *argv[])
+{
+ fsmcnf_ccb_t *ccb;
+ int i = 0;
+
+ PR_ASSERT( i == 0 );
+ /*
+ * check if need help
+ */
+ if ((argc == 2) && (argv[1][0] == '?')) {
+ debugif_printf("%s", "show fsmb2bcnf\n");
+ return (0);
+ }
+
+ debugif_printf("%s", "\n-------------------------- FSMB2BCNF ccbs --------------------------");
+ debugif_printf("%s", "\ni b2bcnf_id ccb cnf_call_id cns_call_id active bridged");
+ debugif_printf("%s", "\n--------------------------------------------------------------------"
+ "\n");
+
+ FSM_FOR_ALL_CBS(ccb, fsmb2bcnf_ccbs, FSMCNF_MAX_CCBS) {
+ debugif_printf("%-2d %-6d 0x%08p %-11d %-11d %-6d %-7d\n",
+ i++, ccb->cnf_id, ccb, ccb->cnf_call_id,
+ ccb->cns_call_id, ccb->active, ccb->bridged);
+ }
+
+ return (0);
+}
+
+
+void
+fsmb2bcnf_init (void)
+{
+ fsmcnf_ccb_t *ccb;
+ static const char *fname = "fsmb2bcnf_init";
+
+
+ /*
+ * Initialize the ccbs.
+ */
+ fsmb2bcnf_ccbs = (fsmcnf_ccb_t *)
+ cpr_malloc(sizeof(fsmcnf_ccb_t) * FSMCNF_MAX_CCBS);
+
+ if (fsmb2bcnf_ccbs == NULL) {
+ GSM_DEBUG_ERROR(GSM_F_PREFIX"Failed to allocate memory \
+ forb2bcnf ccbs.\n", fname);
+ return;
+ }
+
+ FSM_FOR_ALL_CBS(ccb, fsmb2bcnf_ccbs, FSMCNF_MAX_CCBS) {
+ fsmb2bcnf_init_ccb(ccb);
+ }
+
+ /*
+ * Initialize the state/event table.
+ */
+ g_fsmb2bcnf_sm_table.min_state = FSMB2BCNF_S_MIN;
+ g_fsmb2bcnf_sm_table.max_state = FSMB2BCNF_S_MAX;
+ g_fsmb2bcnf_sm_table.min_event = CC_MSG_MIN;
+ g_fsmb2bcnf_sm_table.max_event = CC_MSG_MAX;
+ g_fsmb2bcnf_sm_table.table = (&(fsmb2bcnf_function_table[0][0]));
+}
+
+
+callid_t
+fsmb2bcnf_get_primary_call_id (callid_t call_id)
+{
+ fsmcnf_ccb_t *ccb;
+
+ ccb = fsmb2bcnf_get_ccb_by_call_id(call_id);
+
+ if (ccb && (ccb->cns_call_id == call_id)) {
+ return (fsmb2bcnf_get_other_call_id(ccb, call_id));
+ } else {
+ return (CC_NO_CALL_ID);
+ }
+}
+
+callid_t
+fsmb2bcnf_get_consult_call_id (callid_t call_id)
+{
+ fsmcnf_ccb_t *ccb;
+
+ ccb = fsmb2bcnf_get_ccb_by_call_id(call_id);
+
+ if (ccb && ccb->cnf_call_id == call_id) {
+ return (fsmb2bcnf_get_other_call_id(ccb, call_id));
+ } else {
+ return (CC_NO_CALL_ID);
+ }
+}
+
+int
+fsmutil_is_b2bcnf_consult_call (callid_t call_id)
+{
+ return fsmutil_is_cnf_consult_leg(call_id, fsmb2bcnf_ccbs, FSMCNF_MAX_CCBS);
+}
+
+boolean
+fsmb2bcnf_is_rcc_orig_b2bcnf (callid_t call_id)
+{
+ fsmcnf_ccb_t *ccb;
+
+ ccb = fsmb2bcnf_get_ccb_by_call_id(call_id);
+ if (ccb && ccb->cnf_orig == CC_SRC_RCC) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+void
+fsmb2bcnf_shutdown (void)
+{
+ cpr_free(fsmb2bcnf_ccbs);
+ fsmb2bcnf_ccbs = NULL;
+}
diff --git a/libs/sipcc/core/gsm/fsmcac.c b/libs/sipcc/core/gsm/fsmcac.c
new file mode 100755
index 0000000000..21c32ef81c
--- /dev/null
+++ b/libs/sipcc/core/gsm/fsmcac.c
@@ -0,0 +1,707 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "cpr_types.h"
+#include "cpr_stdlib.h"
+#include "cpr_stdio.h"
+#include "phntask.h"
+#include "fsm.h"
+#include "fim.h"
+#include "lsm.h"
+#include "sm.h"
+#include "gsm.h"
+#include "ccapi.h"
+#include "phone_debug.h"
+#include "debug.h"
+#include "text_strings.h"
+#include "sip_interface_regmgr.h"
+#include "resource_manager.h"
+#include "singly_link_list.h"
+#include "platform_api.h"
+
+#define CAC_FAILURE_TIMEOUT 5
+cc_int32_t g_cacDebug = 0;
+
+/* CAC key */
+typedef struct {
+ callid_t call_id;
+} cac_key_t;
+
+
+typedef enum {
+ FSM_CAC_IDLE = 0,
+ FSM_CAC_REQ_PENDING = 1,
+ FSM_CAC_REQ_RESP = 2
+} fsm_cac_state_e;
+
+/* CAC structure to hold the data
+ */
+typedef struct cac_data_t {
+ void *msg_ptr;
+ callid_t call_id;
+ void *cac_fail_timer;
+ fsm_cac_state_e cac_state;
+ uint32_t sessions;
+} cac_data_t;
+
+static sll_handle_t s_cac_list = NULL;
+
+
+
+/*
+ * Function responsible for searching the list waiting for
+ * bandwidth allocation.
+ *
+ * @param cac_data_t *key_p - pointer to the key.
+ * @param cac_data_t *cac_data - cac data.
+ *
+ * @return void
+ *
+ */
+static sll_match_e
+fsm_cac_match_call_id (cac_data_t *key_p, cac_data_t *cac_data)
+{
+ if (cac_data->call_id == key_p->call_id) {
+
+ return SLL_MATCH_FOUND;
+ }
+
+ return SLL_MATCH_NOT_FOUND;
+
+}
+
+/*
+ * Function responsible to create new data information
+ * for cac.
+ *
+ * @param none.
+ *
+ * @return cac_data_t *
+ *
+ */
+static cac_data_t *
+fsm_get_new_cac_data (void)
+{
+ static const char *fname="fsm_get_new_cac_data";
+ cac_data_t *cac_mem;
+
+ cac_mem = (cac_data_t *) cpr_malloc(sizeof(cac_data_t));
+
+ if (cac_mem == NULL) {
+ CAC_ERROR(CAC_F_PREFIX"No memory for CAC data.\n",
+ DEB_F_PREFIX_ARGS("CAC", fname));
+ return (NULL);
+ }
+
+ memset(cac_mem, 0, sizeof(cac_data_t));
+ return (cac_mem);
+}
+
+/**
+ *
+ * Release all cac related data. This includes timer, cac_data
+ * and message buffers
+ *
+ * @param cac_data cac data structure
+ *
+ * @return none.
+ *
+ * @pre (cac_data not_eq NULL)
+ */
+
+static void
+fsm_clear_cac_data (cac_data_t *cac_data)
+{
+
+ if (cac_data->cac_fail_timer) {
+ (void) cprCancelTimer(cac_data->cac_fail_timer);
+
+ (void) cprDestroyTimer(cac_data->cac_fail_timer);
+ }
+
+ (void) sll_remove(s_cac_list, cac_data);
+
+ fim_free_event(cac_data->msg_ptr);
+
+ /* Release buffer too */
+ cpr_free(cac_data->msg_ptr);
+
+ cpr_free(cac_data);
+
+}
+
+/**
+ *
+ * Notifies the SIP stack and UI that CAC has failed.
+ *
+ * @param cac_data cac data structure
+ *
+ * @return none.
+ *
+ * @pre (cac_data not_eq NULL)
+ */
+
+static void fsm_cac_notify_failure (cac_data_t *cac_data)
+{
+ const char fname[] = "fsm_cac_notify_failure";
+ cc_setup_t *msg = (cc_setup_t *) cac_data->msg_ptr;
+ cc_msgs_t msg_id = msg->msg_id;
+ callid_t call_id = msg->call_id;
+ line_t line = msg->line;
+ int event_id = msg_id;
+ cc_srcs_t src_id = msg->src_id;
+
+ /* Notify UI about the failure */
+ lsm_ui_display_notify_str_index(STR_INDEX_NO_BAND_WIDTH);
+
+ /* Send response from network side regarding the failure */
+ if (event_id == CC_MSG_SETUP &&
+ src_id == CC_SRC_SIP) {
+ DEF_DEBUG(DEB_F_PREFIX"Send CAC failure to SIP %d.\n",
+ DEB_F_PREFIX_ARGS("CAC", fname), cac_data->call_id);
+ cc_int_release(CC_SRC_GSM, CC_SRC_SIP, call_id, line,
+ CC_CAUSE_CONGESTION, NULL, NULL);
+ } else {
+ /* If the cac failed, GSM is not spinning yet, so just send the
+ * information to UI in this case. Other case, where GSM receives event
+ * will send the information from GSM.
+ * If the UI is not cleaned up, session infomation is not cleared.
+ */
+ ui_call_state(evOnHook, line, call_id, CC_CAUSE_CONGESTION);
+ }
+
+}
+
+/**
+ *
+ * Initialize the cac timer. This timer is responsible for cleanup if the
+ * cac response is not received from lower layer.
+ *
+ * @param cac_data cac data structure
+ * timeout specify the time out in sec
+ *
+ * @return true if the timer is created scuccessfully.
+ * false if the timer is not created.
+ *
+ * @pre (cac_data not_eq NULL)
+ */
+
+static boolean
+fsm_init_cac_failure_timer(cac_data_t *cac_data, uint32_t timeout)
+{
+ const char fname[] = "fsm_init_cac_failure_timer";
+
+ CAC_DEBUG(DEB_F_PREFIX"cac_data call_id=%x\n",
+ DEB_F_PREFIX_ARGS("CAC", fname),
+ cac_data->call_id);
+
+ cac_data->cac_fail_timer =
+ cprCreateTimer("CAC failure timer", GSM_CAC_FAILURE_TIMER, TIMER_EXPIRATION,
+ gsm_msg_queue);
+
+ if (cac_data->cac_fail_timer == NULL) {
+ CAC_ERROR(CAC_F_PREFIX"CAC Timer allocation failed.\n",
+ DEB_F_PREFIX_ARGS("CAC", fname));
+ return(FALSE);
+ }
+
+ (void) cprStartTimer(cac_data->cac_fail_timer, timeout * 1000,
+ (void *)(long)cac_data->call_id);
+
+ return(TRUE);
+}
+
+/**
+ *
+ * Serches through cac link list and returns cac_data
+ * based on call_id. This search is a singly link list search.
+ *
+ * @param call_id call_id of the call
+ *
+ * @return cac_data if found in the list
+ * NULL if there is no cac_data
+ *
+ * @pre (call_id not_eq CC_NO_CALL_ID)
+ */
+
+static cac_data_t *
+fsm_cac_get_data_by_call_id (callid_t call_id)
+{
+ const char fname[] = "fsm_cac_get_data_by_call_id";
+ cac_data_t *cac_data;
+
+ cac_data = (cac_data_t *) sll_next(s_cac_list, NULL);
+
+ while (cac_data != NULL) {
+
+ if (cac_data->call_id == call_id) {
+ CAC_DEBUG(DEB_F_PREFIX"cac_data found call_id=%x\n",
+ DEB_F_PREFIX_ARGS("CAC", fname),
+ cac_data->call_id);
+ return(cac_data);
+ }
+
+ cac_data = (cac_data_t *) sll_next(s_cac_list, cac_data);
+
+ }
+
+ CAC_DEBUG(DEB_F_PREFIX"cac_data NOT found.\n",
+ DEB_F_PREFIX_ARGS("CAC", fname));
+ return(NULL);
+}
+
+/**
+ *
+ * Initialize cac module by enabling debugs and creating a cac list.
+ *
+ * @param void
+ *
+ * @return void
+ *
+ * @pre (NULL)
+ */
+void fsm_cac_init (void)
+{
+ const char fname[] = "fsm_cac_init";
+
+
+ /* allocate and initialize cac list */
+ s_cac_list = sll_create((sll_match_e(*)(void *, void *))
+ fsm_cac_match_call_id);
+
+ if (s_cac_list == NULL) {
+ CAC_ERROR(CAC_F_PREFIX"CAC list creation failed.\n",
+ DEB_F_PREFIX_ARGS("CAC", fname));
+
+ }
+}
+
+/**
+ *
+ * clears all the entries in the cac list
+ *
+ * @param void
+ *
+ * @return void
+ *
+ * @pre (NULL)
+ */
+void fsm_cac_clear_list (void)
+{
+ const char fname[] = "fsm_cac_clear_list";
+ cac_data_t *cac_data;
+ cac_data_t *prev_cac_data;
+
+ DEF_DEBUG(DEB_F_PREFIX"Clear all pending CAC dat.\n",
+ DEB_F_PREFIX_ARGS("CAC", fname));
+
+ cac_data = (cac_data_t *) sll_next(s_cac_list, NULL);
+
+ while (cac_data != NULL) {
+
+ prev_cac_data = cac_data;
+ cac_data = (cac_data_t *) sll_next(s_cac_list, cac_data);
+
+ fsm_cac_notify_failure(prev_cac_data);
+ fsm_clear_cac_data(prev_cac_data);
+ }
+
+}
+
+/**
+ *
+ * Shutdown cac module, clears all the pending cac requests
+ *
+ * @param void
+ *
+ * @return void
+ *
+ * @pre (NULL)
+ */
+void fsm_cac_shutdown (void)
+{
+
+ fsm_cac_clear_list();
+
+ sll_destroy(s_cac_list);
+
+ s_cac_list = NULL;
+}
+
+/**
+ *
+ * Check if there are pending CAC requests
+ *
+ * @param none
+ *
+ * @return cac_data returns first pending request.
+ *
+ * @pre (NULL)
+ */
+static cac_data_t *
+fsm_cac_check_if_pending_req (void)
+{
+ cac_data_t *cac_data;
+
+ cac_data = (cac_data_t *) sll_next(s_cac_list, NULL);
+
+ while (cac_data != NULL) {
+
+ if (cac_data->cac_state == FSM_CAC_REQ_PENDING ||
+ cac_data->cac_state == FSM_CAC_IDLE) {
+
+ return(cac_data);
+ }
+
+ cac_data = (cac_data_t *) sll_next(s_cac_list, cac_data);
+
+ }
+
+ return(NULL);
+}
+
+/**
+ *
+ * Check if there are pending CAC requests
+ *
+ * @param none
+ *
+ * @return cac_data returns first pending request.
+ *
+ * @pre (NULL)
+ */
+static cc_causes_t
+fsm_cac_process_bw_allocation (cac_data_t *cac_data)
+{
+ const char fname[] = "fsm_cac_process_bw_allocation";
+
+ if (lsm_allocate_call_bandwidth(cac_data->call_id, cac_data->sessions) ==
+ CC_CAUSE_CONGESTION) {
+
+ DEF_DEBUG(DEB_F_PREFIX"CAC Allocation failed.\n",
+ DEB_F_PREFIX_ARGS("CAC", fname));
+
+ fsm_cac_notify_failure(cac_data);
+
+ fsm_clear_cac_data(cac_data);
+
+ return(CC_CAUSE_CONGESTION);
+ }
+
+ cac_data->cac_state = FSM_CAC_REQ_PENDING;
+
+ return(CC_CAUSE_OK);
+}
+
+/**
+ *
+ * Check if there are pending CAC requests
+ *
+ * @param call_id request a cac for this call_id
+ * sessions number of sessions in the request
+ * msg ccapi msg, that is held to process
+ * till cac response is received.
+ *
+ * @return CC_CAUSE_BW_OK if the bandwidth is received.
+ * CC_CAUSE_Ok Call returned successfully, not sure about BW yet
+ * CC_CAUSE_ERROR: Call returned with failure.
+ *
+ * @pre (NULL)
+ */
+cc_causes_t
+fsm_cac_call_bandwidth_req (callid_t call_id, uint32_t sessions,
+ void *msg)
+{
+ const char fname[] = "fsm_cac_call_bandwidth_req";
+ cac_data_t *cac_data, *cac_pend_data;
+
+ /* If wlan not connected return OK */
+ cac_data = fsm_get_new_cac_data();
+
+ if (cac_data == NULL) {
+
+ return(CC_CAUSE_CONGESTION);
+ }
+
+ cac_data->msg_ptr = msg;
+ cac_data->call_id = call_id;
+ cac_data->cac_state = FSM_CAC_IDLE;
+ cac_data->sessions = sessions;
+
+ fsm_init_cac_failure_timer(cac_data, CAC_FAILURE_TIMEOUT);
+
+ /* Make sure there is no pending requests before submitting
+ * another one
+ */
+ if ((cac_pend_data = fsm_cac_check_if_pending_req()) == NULL) {
+
+ /*
+ * Make sure sufficient bandwidth available to make a outgoing call. This
+ * should be done before allocating other resources.
+ */
+ DEF_DEBUG(DEB_F_PREFIX"CAC request for %d sessions %d.\n",
+ DEB_F_PREFIX_ARGS("CAC", fname), call_id, sessions);
+
+ if (fsm_cac_process_bw_allocation(cac_data) == CC_CAUSE_CONGESTION) {
+
+ return(CC_CAUSE_CONGESTION);
+ }
+
+ cac_data->cac_state = FSM_CAC_REQ_PENDING;
+
+ } else if (cac_pend_data->cac_state == FSM_CAC_IDLE) {
+
+ if (fsm_cac_process_bw_allocation(cac_pend_data) ==
+ CC_CAUSE_CONGESTION) {
+
+ /* Clear all remaining data */
+ fsm_cac_clear_list();
+
+ return(CC_CAUSE_CONGESTION);
+ }
+
+ }
+
+ (void) sll_append(s_cac_list, cac_data);
+
+ return(CC_CAUSE_OK);
+
+}
+
+/**
+ *
+ * This is called by gsm to cleanup the cac data. If there are any
+ * pending CAC requests and far end cancels the call, the pending
+ * request has to be canceled.
+ *
+ * @param call_id - call_id of the request
+ *
+ * @return none.
+ *
+ * @pre (NULL)
+ */
+void fsm_cac_call_release_cleanup (callid_t call_id)
+{
+ cac_data_t *cac_data;
+
+ cac_data = fsm_cac_get_data_by_call_id(call_id);
+
+ if (cac_data) {
+
+ sll_remove(s_cac_list, cac_data);
+
+ fsm_clear_cac_data(cac_data);
+ }
+
+}
+
+
+/**
+ *
+ * Called when the bandwidth response with available bw is received. This
+ * also process held ccapi messages through fim event chain
+ *
+ * @param none
+ *
+ * @return CC_CAUSE_NO_RESOURCE No bandwidth
+ * CC_CAUSE_OK if ok
+ *
+ *
+ * @pre (NULL)
+ */
+
+cc_causes_t
+fsm_cac_process_bw_avail_resp (void)
+{
+ const char fname[] = "fsm_cac_process_bw_avail_resp";
+ cac_data_t *cac_data = NULL;
+ cac_data_t *next_cac_data = NULL;
+
+
+ cac_data = (cac_data_t *) sll_next(s_cac_list, NULL);
+
+ if (cac_data != NULL) {
+
+ switch (cac_data->cac_state) {
+ default:
+ case FSM_CAC_IDLE:
+ DEF_DEBUG(DEB_F_PREFIX"No Pending CAC request.\n",
+ DEB_F_PREFIX_ARGS("CAC", fname));
+ /*
+ * Make sure sufficient bandwidth available to make a outgoing call. This
+ * should be done before allocating other resources.
+ */
+ if (fsm_cac_process_bw_allocation(cac_data) == CC_CAUSE_CONGESTION) {
+
+ sll_remove(s_cac_list, cac_data);
+
+ return(CC_CAUSE_NO_RESOURCE);
+ }
+
+
+ break;
+ case FSM_CAC_REQ_PENDING:
+
+ next_cac_data = (cac_data_t *) sll_next(s_cac_list, cac_data);
+ sll_remove(s_cac_list, cac_data);
+
+ /* Request for the next bandwidth */
+ DEF_DEBUG(DEB_F_PREFIX"Process pending responses %d.\n",
+ DEB_F_PREFIX_ARGS("CAC", fname), cac_data->call_id);
+
+ /* Let GSM process completed request */
+ fim_process_event(cac_data->msg_ptr, TRUE);
+
+ fsm_clear_cac_data(cac_data);
+
+ if (next_cac_data != NULL) {
+ /*
+ * Make sure sufficient bandwidth available to make a outgoing call. This
+ * should be done before allocating other resources.
+ */
+ DEF_DEBUG(DEB_F_PREFIX"Requesting next allocation %d.\n",
+ DEB_F_PREFIX_ARGS("CAC", fname), next_cac_data->call_id);
+
+ if (fsm_cac_process_bw_allocation(next_cac_data) ==
+ CC_CAUSE_CONGESTION) {
+
+ /* If the next data was in idle state and the request fialed
+ * then clean up the remaining list
+ */
+ if (next_cac_data->cac_state == FSM_CAC_IDLE) {
+ /* Clear all remaining data */
+ fsm_cac_clear_list();
+ } else {
+
+ sll_remove(s_cac_list, next_cac_data);
+ }
+
+ return(CC_CAUSE_NO_RESOURCE);
+ }
+
+ }
+
+ break;
+ }
+
+ }
+
+ return(CC_CAUSE_NO_RESOURCE);
+
+}
+
+/**
+ *
+ * Called when the bandwidth response with failed bw is received. This
+ * also process held ccapi messages through fim event chain
+ *
+ * @param none
+ *
+ * @return CC_CAUSE_NO_RESOURCE No bandwidth
+ * CC_CAUSE_OK if ok
+ *
+ *
+ * @pre (NULL)
+ */
+cc_causes_t
+fsm_cac_process_bw_failed_resp (void)
+{
+ const char fname[] = "fsm_cac_process_bw_avail_resp";
+ cac_data_t *cac_data = NULL;
+ cac_data_t *next_cac_data = NULL;
+
+
+ cac_data = (cac_data_t *) sll_next(s_cac_list, NULL);
+
+ if (cac_data != NULL) {
+
+ switch (cac_data->cac_state) {
+ default:
+ case FSM_CAC_IDLE:
+ DEF_DEBUG(DEB_F_PREFIX"No Pending request.\n",
+ DEB_F_PREFIX_ARGS("CAC", fname));
+ /*
+ * Make sure sufficient bandwidth available to make a outgoing call. This
+ * should be done before allocating other resources.
+ */
+ if (fsm_cac_process_bw_allocation(cac_data) == CC_CAUSE_CONGESTION) {
+
+ sll_remove(s_cac_list, cac_data);
+
+ return(CC_CAUSE_NO_RESOURCE);
+ }
+
+ break;
+ case FSM_CAC_REQ_PENDING:
+
+ next_cac_data = (cac_data_t *) sll_next(s_cac_list, cac_data);
+
+ sll_remove(s_cac_list, cac_data);
+
+ /* Request for the next bandwidth */
+ DEF_DEBUG(DEB_F_PREFIX"Process pending responses even after failure.\n",
+ DEB_F_PREFIX_ARGS("CAC", fname));
+
+ /* Let GSM process completed request */
+ fsm_cac_notify_failure(cac_data);
+
+ fsm_clear_cac_data(cac_data);
+
+ if (next_cac_data != NULL) {
+
+ /*
+ * Make sure sufficient bandwidth available to make a outgoing call. This
+ * should be done before allocating other resources.
+ */
+ if (fsm_cac_process_bw_allocation(next_cac_data) == CC_CAUSE_CONGESTION) {
+
+ /* If the next data was in idle state and the request fialed
+ * then clean up the remaining list
+ */
+ if (next_cac_data->cac_state == FSM_CAC_IDLE) {
+ /* Clear all remaining data */
+ fsm_cac_clear_list();
+ } else {
+
+ sll_remove(s_cac_list, next_cac_data);
+ }
+
+ return(CC_CAUSE_NO_RESOURCE);
+ }
+
+ }
+
+ break;
+ }
+
+ }
+
+ return(CC_CAUSE_NO_RESOURCE);
+}
+
+/**
+ *
+ * Process time-out event. This cause cac data to send failure notifications.
+ *
+ * @param void *tmr_data - timer data
+ *
+ * @return none
+ *
+ *
+ * @pre (NULL)
+ */
+void
+fsm_cac_process_bw_fail_timer (void *tmr_data)
+{
+ const char fname[] = "fsm_cac_process_bw_fail_timer";
+
+ DEF_DEBUG(DEB_F_PREFIX"CAC request timedout %d.\n",
+ DEB_F_PREFIX_ARGS("CAC", fname), (callid_t)(long)tmr_data);
+
+ /* Time-out causes same set of processing as bw failure
+ */
+ fsm_cac_process_bw_failed_resp();
+
+}
+
diff --git a/libs/sipcc/core/gsm/fsmcnf.c b/libs/sipcc/core/gsm/fsmcnf.c
new file mode 100755
index 0000000000..3f27e30eb1
--- /dev/null
+++ b/libs/sipcc/core/gsm/fsmcnf.c
@@ -0,0 +1,1750 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "cpr_types.h"
+#include "cpr_stdlib.h"
+#include "cpr_string.h"
+#include "cpr_stdio.h"
+#include "fsm.h"
+#include "fim.h"
+#include "lsm.h"
+#include "sm.h"
+#include "ccapi.h"
+#include "phone_debug.h"
+#include "text_strings.h"
+#include "config.h"
+#include "debug.h"
+#include "gsm_sdp.h"
+#include "regmgrapi.h"
+#include "platform_api.h"
+
+static fsmcnf_ccb_t *fsmcnf_ccbs;
+
+static int softkey_mask_list[MAX_SOFT_KEYS];
+
+#define FSMCNF_CONNECTED_SET "CONNECTED"
+
+typedef enum {
+ FSMCNF_S_MIN = -1,
+ FSMCNF_S_IDLE,
+ FSMCNF_S_CNFING,
+ FSMCNF_S_CNFED,
+ FSMCNF_S_MAX
+} fsmcnf_states_t;
+
+static const char *fsmcnf_state_names[] = {
+ "IDLE",
+ "CNFING",
+ "CNFED"
+};
+
+
+static sm_rcs_t fsmcnf_ev_idle_setup(sm_event_t *event);
+static sm_rcs_t fsmcnf_ev_idle_feature(sm_event_t *event);
+static sm_rcs_t fsmcnf_ev_cnfing_release(sm_event_t *event);
+static sm_rcs_t fsmcnf_ev_cnfing_feature(sm_event_t *event);
+static sm_rcs_t fsmcnf_ev_cnfing_onhook(sm_event_t *event);
+static sm_rcs_t fsmcnf_ev_cnfed_release(sm_event_t *event);
+static sm_rcs_t fsmcnf_ev_cnfed_feature(sm_event_t *event);
+static sm_rcs_t fsmcnf_ev_cnfed_feature_ack(sm_event_t *event);
+static sm_rcs_t fsmcnf_ev_cnfed_onhook(sm_event_t *event);
+
+static sm_function_t fsmcnf_function_table[FSMCNF_S_MAX][CC_MSG_MAX] =
+{
+/* FSMCNF_S_IDLE ------------------------------------------------------------ */
+ {
+ /* FSMCNF_E_SETUP */ fsmcnf_ev_idle_setup,
+ /* FSMCNF_E_SETUP_ACK */ NULL,
+ /* FSMCNF_E_PROCEEDING */ NULL,
+ /* FSMCNF_E_ALERTING */ NULL,
+ /* FSMCNF_E_CONNECTED */ NULL,
+ /* FSMCNF_E_CONNECTED_ACK */ NULL,
+ /* FSMCNF_E_RELEASE */ NULL,
+ /* FSMCNF_E_RELEASE_COMPLETE */ NULL,
+ /* FSMCNF_E_FEATURE */ fsmcnf_ev_idle_feature,
+ /* FSMCNF_E_FEATURE_ACK */ NULL,
+ /* FSMCNF_E_OFFHOOK */ NULL,
+ /* FSMCNF_E_ONHOOK */ NULL,
+ /* FSMCNF_E_LINE */ NULL,
+ /* FSMCNF_E_DIGIT_BEGIN */ NULL,
+ /* FSMCNF_E_DIGIT */ NULL,
+ /* FSMCNF_E_DIALSTRING */ NULL,
+ /* FSMCNF_E_MWI */ NULL,
+ /* FSMCNF_E_SESSION_AUDIT */ NULL
+ },
+
+/* FSMCNF_S_CNFING --------------------------------------------------- */
+ {
+ /* FSMCNF_E_SETUP */ NULL,
+ /* FSMCNF_E_SETUP_ACK */ NULL,
+ /* FSMCNF_E_PROCEEDING */ NULL,
+ /* FSMCNF_E_ALERTING */ NULL,
+ /* FSMCNF_E_CONNECTED */ NULL,
+ /* FSMCNF_E_CONNECTED_ACK */ NULL,
+ /* FSMCNF_E_RELEASE */ fsmcnf_ev_cnfing_release,
+ /* FSMCNF_E_RELEASE_COMPLETE */ NULL,
+ /* FSMCNF_E_FEATURE */ fsmcnf_ev_cnfing_feature,
+ /* FSMCNF_E_FEATURE_ACK */ NULL,
+ /* FSMCNF_E_OFFHOOK */ NULL,
+ /* FSMCNF_E_ONHOOK */ fsmcnf_ev_cnfing_onhook,
+ /* FSMCNF_E_LINE */ NULL,
+ /* FSMCNF_E_DIGIT_BEGIN */ NULL,
+ /* FSMCNF_E_DIGIT */ NULL,
+ /* FSMCNF_E_DIALSTRING */ NULL,
+ /* FSMCNF_E_MWI */ NULL,
+ /* FSMCNF_E_SESSION_AUDIT */ NULL
+ },
+
+/* FSMCNF_S_CNFED ---------------------------------------------------- */
+ {
+ /* FSMCNF_E_SETUP */ NULL,
+ /* FSMCNF_E_SETUP_ACK */ NULL,
+ /* FSMCNF_E_PROCEEDING */ NULL,
+ /* FSMCNF_E_ALERTING */ NULL,
+ /* FSMCNF_E_CONNECTED */ NULL,
+ /* FSMCNF_E_CONNECTED_ACK */ NULL,
+ /* FSMCNF_E_RELEASE */ fsmcnf_ev_cnfed_release,
+ /* FSMCNF_E_RELEASE_COMPLETE */ NULL,
+ /* FSMCNF_E_FEATURE */ fsmcnf_ev_cnfed_feature,
+ /* FSMCNF_E_FEATURE_ACK */ fsmcnf_ev_cnfed_feature_ack,
+ /* FSMCNF_E_OFFHOOK */ NULL,
+ /* FSMCNF_E_ONHOOK */ fsmcnf_ev_cnfed_onhook,
+ /* FSMCNF_E_LINE */ NULL,
+ /* FSMCNF_E_DIGIT_BEGIN */ NULL,
+ /* FSMCNF_E_DIGIT */ NULL,
+ /* FSMCNF_E_DIALSTRING */ NULL,
+ /* FSMCNF_E_MWI */ NULL,
+ /* FSMCNF_E_SESSION_AUDIT */ NULL
+ }
+};
+
+static sm_table_t fsmcnf_sm_table;
+sm_table_t *pfsmcnf_sm_table = &fsmcnf_sm_table;
+
+
+const char *
+fsmcnf_state_name (int state)
+{
+ if ((state <= FSMCNF_S_MIN) || (state >= FSMCNF_S_MAX)) {
+ return (get_debug_string(GSM_UNDEFINED));
+ }
+
+ return (fsmcnf_state_names[state]);
+}
+
+
+static int
+fsmcnf_get_new_cnf_id (void)
+{
+ static int cnf_id = 0;
+
+ if (++cnf_id < 0) {
+ cnf_id = 1;
+ }
+
+ return (cnf_id);
+}
+
+
+static void
+fsmcnf_init_ccb (fsmcnf_ccb_t *ccb)
+{
+ if (ccb != NULL) {
+ ccb->cnf_id = FSM_NO_ID;
+ ccb->cnf_call_id = CC_NO_CALL_ID;
+ ccb->cns_call_id = CC_NO_CALL_ID;
+ ccb->cnf_line = CC_NO_LINE;
+ ccb->cns_line = CC_NO_LINE;
+ ccb->bridged = FALSE;
+ ccb->active = FALSE;
+ ccb->flags = 0;
+ ccb->cnf_ftr_ack = FALSE;
+ }
+}
+
+
+static fsmcnf_ccb_t *
+fsmcnf_get_ccb_by_cnf_id (int cnf_id)
+{
+ fsmcnf_ccb_t *ccb;
+ fsmcnf_ccb_t *ccb_found = NULL;
+
+ FSM_FOR_ALL_CBS(ccb, fsmcnf_ccbs, FSMCNF_MAX_CCBS) {
+ if (ccb->cnf_id == cnf_id) {
+ ccb_found = ccb;
+
+ break;
+ }
+ }
+
+ return (ccb_found);
+}
+
+
+/*
+ * Function: fsmcnf_get_new_cnf_context
+ *
+ * Parameters:
+ * cnf_call_id: call_id for the call initiating the conference
+ *
+ * Description: This function creates a new conference context by:
+ * - getting a free ccb
+ * - creating new cnf_id and cns_call_id
+ *
+ * Returns: ccb
+ *
+ */
+static fsmcnf_ccb_t *
+fsmcnf_get_new_cnf_context (callid_t cnf_call_id)
+{
+ static const char fname[] = "fsmcnf_get_new_cnf_context";
+ fsmcnf_ccb_t *ccb;
+
+ ccb = fsmcnf_get_ccb_by_cnf_id(FSM_NO_ID);
+ if (ccb != NULL) {
+ ccb->cnf_id = fsmcnf_get_new_cnf_id();
+ ccb->cnf_call_id = cnf_call_id;
+ ccb->cns_call_id = cc_get_new_call_id();
+
+ FSM_DEBUG_SM(get_debug_string(FSMCNF_DBG_PTR), ccb->cnf_id,
+ ccb->cnf_call_id, ccb->cns_call_id, fname, ccb);
+ } else {
+ GSM_DEBUG_ERROR(GSM_F_PREFIX"Failed to get new ccb.\n", fname);
+ }
+
+ return (ccb);
+}
+
+
+fsmcnf_ccb_t *
+fsmcnf_get_ccb_by_call_id (callid_t call_id)
+{
+ fsmcnf_ccb_t *ccb;
+ fsmcnf_ccb_t *ccb_found = NULL;
+
+ FSM_FOR_ALL_CBS(ccb, fsmcnf_ccbs, FSMCNF_MAX_CCBS) {
+ if ((ccb->cnf_call_id == call_id) || (ccb->cns_call_id == call_id)) {
+ ccb_found = ccb;
+
+ break;
+ }
+ }
+
+ return (ccb_found);
+}
+
+
+static void
+fsmcnf_update_cnf_context (fsmcnf_ccb_t *ccb, callid_t old_call_id,
+ callid_t new_call_id)
+{
+ static const char fname[] = "fsmcnf_update_cnf_context";
+
+ if (ccb != NULL) {
+ if (old_call_id == ccb->cnf_call_id) {
+ ccb->cnf_call_id = new_call_id;
+ } else if (old_call_id == ccb->cns_call_id) {
+ ccb->cns_call_id = new_call_id;
+ }
+
+ FSM_DEBUG_SM(get_debug_string(FSMCNF_DBG_PTR), ccb->cnf_id,
+ ccb->cnf_call_id, ccb->cns_call_id, fname, ccb);
+ }
+}
+
+
+callid_t
+fsmcnf_get_other_call_id (fsmcnf_ccb_t *ccb, callid_t call_id)
+{
+ callid_t other_call_id = CC_NO_CALL_ID;
+
+ if (ccb != NULL) {
+ if (ccb->cnf_call_id == call_id) {
+ other_call_id = ccb->cns_call_id;
+ } else if (ccb->cns_call_id == call_id) {
+ other_call_id = ccb->cnf_call_id;
+ }
+ }
+
+ return (other_call_id);
+}
+
+static void
+fsmcnf_cnf_xfer (fsmcnf_ccb_t *ccb)
+{
+ fsmdef_dcb_t *dcb;
+ cc_feature_data_t ftr_data;
+
+ dcb = fsm_get_dcb(ccb->cnf_call_id);
+
+ /*
+ * Pretending attended transfer
+ */
+ ftr_data.xfer.cause = CC_CAUSE_XFER_CNF;
+ ftr_data.xfer.target_call_id = ccb->cns_call_id;
+ cc_int_feature(CC_SRC_UI, CC_SRC_GSM, dcb->call_id,
+ dcb->line, CC_FEATURE_XFER, &(ftr_data));
+}
+
+
+/*
+ * Function: fsmcnf_remove_fcb
+ *
+ * Parameters:
+ * cnf_id: cnf_id for the conference
+ * call_id: call_id that identifies the fcb to be removed
+ *
+ * Description: This function will remove the fcb identified by the given
+ * call_id from the ccb. And the function will free the ccb
+ * if both fcbs have been removed.
+ *
+ * Returns: none
+ *
+ * Note: This is a helper function for fsmcnf_cleanup. It allows fsmcnf_cleanup
+ * to cleanup one fcb (one call involved in the conference) independent
+ * of the other involved fcb.
+ */
+static void
+fsmcnf_remove_fcb (fsm_fcb_t *fcb, callid_t call_id)
+{
+ fsmcnf_ccb_t *ccb = fcb->ccb;
+
+ if (ccb != NULL) {
+ fsmcnf_update_cnf_context(ccb, call_id, CC_NO_CALL_ID);
+
+ /*
+ * Free the ccb if both fcb references have been removed.
+ */
+ if ((ccb->cnf_call_id == CC_NO_CALL_ID) &&
+ (ccb->cns_call_id == CC_NO_CALL_ID)) {
+ fsmcnf_init_ccb(ccb);
+ }
+ }
+}
+
+
+static void
+fsmcnf_cleanup (fsm_fcb_t *fcb, int fname, boolean both)
+{
+ fsmcnf_ccb_t *ccb;
+ fsm_fcb_t *other_fcb, *fcb_def;
+ callid_t call_id = fcb->call_id;
+ callid_t other_call_id = CC_NO_CALL_ID;
+
+ /* stop the channel mixing if we are currently doing it */
+ ccb = fsmcnf_get_ccb_by_call_id(call_id);
+ other_call_id = fsmcnf_get_other_call_id(fcb->ccb, call_id);
+ /* Set session to be primary */
+ fcb_def = fsm_get_fcb_by_call_id_and_type(call_id, FSM_TYPE_DEF);
+
+ if (fcb->ccb && (call_id == fcb->ccb->cnf_call_id)) {
+
+ if (other_call_id != CC_NO_CALL_ID) {
+ /*
+ * Not clearing consulation call, so change consultation
+ * call attribute to display connected softkey set.
+ * Do not change softkey set if it is a transfer o
+ */
+ if (ccb == NULL) {
+ GSM_DEBUG_ERROR(GSM_F_PREFIX"Failed to get CCB.\n", fname);
+ } else {
+ cc_call_attribute(other_call_id, ccb->cnf_line, NORMAL_CALL);
+ }
+ }
+
+ }
+
+ if (fcb_def && fcb_def->dcb) {
+ fcb_def->dcb->session = PRIMARY;
+ }
+ /*
+ * Check if the user wanted to cleanup the whole ccb.
+ * If so, then we will grab the other fcb first and call this function
+ * again with this other fcb. The whole ccb will be freed after this block
+ * of code because both call_ids will be -1, which tells
+ * fsmcnf_remove_fcb to free the ccb.
+ */
+ if (both) {
+ other_call_id = fsmcnf_get_other_call_id(fcb->ccb, call_id);
+ if (other_call_id != CC_NO_CALL_ID) {
+ other_fcb = fsm_get_fcb_by_call_id_and_type(other_call_id,
+ FSM_TYPE_CNF);
+ if (other_fcb != NULL) {
+ fsmcnf_cleanup(other_fcb, fname, FALSE);
+ }
+ }
+ }
+
+ /*
+ * Remove the reference to this fcb from the ccb.
+ */
+ fsmcnf_remove_fcb(fcb, fcb->call_id);
+
+ /*
+ * Move this fcb to the IDLE state
+ */
+ fsm_change_state(fcb, fname, FSMCNF_S_IDLE);
+
+ /*
+ * Reset the data for this fcb. The fcb is still included in a call
+ * so set the call_id and dcb values accordingly.
+ */
+ fsm_init_fcb(fcb, fcb->call_id, fcb->dcb, FSM_TYPE_CNF);
+}
+
+
+void
+fsmcnf_free_cb (fim_icb_t *icb, callid_t call_id)
+{
+ fsm_fcb_t *fcb = NULL;
+
+ if (call_id != CC_NO_CALL_ID) {
+ fcb = fsm_get_fcb_by_call_id_and_type(call_id, FSM_TYPE_CNF);
+
+ if (fcb != NULL) {
+ fsmcnf_cleanup(fcb, __LINE__, FALSE);
+ fsm_init_fcb(fcb, CC_NO_CALL_ID, FSMDEF_NO_DCB, FSM_TYPE_NONE);
+ }
+ }
+}
+
+
+/**
+ *
+ * Cancel conference feature by sending cancel event to SIP stack.
+ * This routine is used in roundtable phone.
+ *
+ * Copied and pasted from fsmb2bcnf_feature_cancel().
+ * See also fsmxfr_feature_cancel().
+ *
+ * @param line, call_id, target_call_id, cause (implicit or explicit)
+ *
+ * @return void
+ *
+ * @pre (none)
+ */
+void
+fsmcnf_feature_cancel (fsmcnf_ccb_t *ccb, line_t line, callid_t call_id,
+ callid_t target_call_id)
+{
+ cc_feature_data_t data;
+ fsm_fcb_t *fcb_def;
+
+ fcb_def = fsm_get_fcb_by_call_id_and_type(call_id, FSM_TYPE_DEF);
+
+ // 'cause' will always be CC_SK_EVT_TYPE_EXPLI for now since it's only
+ // called by fsmcnf_ev_cnfing_feature in the case of CC_FEAURE_CANCEL.
+ // Thus 'cause' is ignored (for now) until the whole SM is refactored.
+ if (/*(cause == CC_SK_EVT_TYPE_EXPLI) && */
+ (fcb_def != NULL) && ((fcb_def->dcb->selected == FALSE) &&
+ ((fcb_def->state == FSMDEF_S_OUTGOING_ALERTING) ||
+ ((fcb_def->state == FSMDEF_S_CONNECTED) &&
+ (fcb_def->dcb->spoof_ringout_requested == TRUE) &&
+ (fcb_def->dcb->spoof_ringout_applied == TRUE))))) {
+
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, call_id,
+ line, CC_FEATURE_END_CALL, NULL);
+ }
+
+ fcb_def = fsm_get_fcb_by_call_id_and_type(target_call_id, FSM_TYPE_DEF);
+
+ if (/* (cause == CC_SK_EVT_TYPE_EXPLI) && */
+ (fcb_def != NULL) && ((fcb_def->dcb->selected == FALSE) &&
+ ((fcb_def->state == FSMDEF_S_OUTGOING_ALERTING) ||
+ ((fcb_def->state == FSMDEF_S_CONNECTED) &&
+ (fcb_def->dcb->spoof_ringout_requested == TRUE) &&
+ (fcb_def->dcb->spoof_ringout_applied == TRUE))))) {
+
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, target_call_id,
+ line, CC_FEATURE_END_CALL, NULL);
+ }
+
+ data.cancel.target_call_id = target_call_id;
+ data.cancel.call_id = call_id;
+ data.cancel.cause = CC_SK_EVT_TYPE_EXPLI;
+
+ cc_int_feature(CC_SRC_GSM, CC_SRC_SIP, call_id,
+ line, CC_FEATURE_CANCEL, &data);
+}
+
+/*******************************************************************
+ * event functions
+ */
+
+
+static sm_rcs_t
+fsmcnf_ev_idle_setup (sm_event_t *event)
+{
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ cc_setup_t *msg = (cc_setup_t *) event->msg;
+ callid_t call_id = msg->call_id;
+ fsmcnf_ccb_t *ccb;
+
+ if (!msg->replaces) {
+ return (SM_RC_DEF_CONT);
+ }
+
+ /*
+ * Check to see if this new setup call is a new call that replaces
+ * one of the conferenced call i.e. the this new call replacing the
+ * existing leg of a conferenced by XFER feature from SIP. The
+ * call id of this setup should match call id of a conference.
+ */
+ ccb = fsmcnf_get_ccb_by_call_id(call_id);
+ if (ccb == NULL) {
+ return (SM_RC_DEF_CONT);
+ }
+
+ /* This new call is part of a conference */
+ fcb->ccb = ccb; /* attach ccb to the new call chain */
+ fsm_change_state(fcb, __LINE__, FSMCNF_S_CNFING);
+
+ return (SM_RC_CONT);
+}
+
+
+static sm_rcs_t
+fsmcnf_ev_idle_feature (sm_event_t *event)
+{
+ static const char *fname = "fsmcnf_ev_idle_feature";
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ cc_feature_t *msg = (cc_feature_t *) event->msg;
+ callid_t call_id = msg->call_id;
+ line_t line = msg->line;
+ cc_srcs_t src_id = msg->src_id;
+ cc_features_t ftr_id = msg->feature_id;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ callid_t cns_call_id;
+ sm_rcs_t sm_rc = SM_RC_CONT;
+ fsmcnf_ccb_t *ccb;
+ int free_lines;
+ cc_feature_data_t data;
+ cc_action_data_t action_data;
+ fsmdef_dcb_t *other_dcb;
+ fsm_fcb_t *other_fcb;
+ fsm_fcb_t *fcb_def, *join_fcb_cnf;
+ cc_feature_data_t ftr_data = msg->data;
+ cc_feature_data_t *feat_data = &(msg->data);
+ fsm_fcb_t *cns_fcb;
+ callid_t other_call_id;
+ fsmxfr_xcb_t *xcb;
+ cc_causes_t cause;
+
+ memset(&data, 0, sizeof(cc_feature_data_t));
+
+ fsm_sm_ftr(ftr_id, src_id);
+
+ switch (src_id) {
+ case CC_SRC_UI:
+ switch (ftr_id) {
+ case CC_FEATURE_CONF:
+
+ /* Connect the existing call to active conference state
+ * machine. If the UI generates the event with target
+ * call_id in the data then terminate the existing consulatative
+ * call and link that to another call.
+ */
+ if (feat_data && msg->data_valid &&
+ (feat_data->cnf.target_call_id != CC_NO_CALL_ID)
+ && (cns_fcb = fsm_get_fcb_by_call_id_and_type(feat_data->cnf.target_call_id,
+ FSM_TYPE_CNF)) != NULL) {
+ /*
+ * Get a new ccb and new b2bcnf id - This is the handle that will
+ * identify the b2bcnf.
+ */
+ ccb = fsmcnf_get_new_cnf_context(feat_data->cnf.target_call_id);
+
+ if (ccb == NULL || ccb->cnf_id == FSM_NO_ID) {
+ return(SM_RC_END);
+ }
+
+ ccb->cns_call_id = call_id;
+ fcb->ccb = ccb;
+ cns_fcb->ccb = ccb;
+ ccb->cnf_line = line;
+ ccb->cns_line = line;
+
+ fsm_change_state(fcb, __LINE__, FSMCNF_S_CNFING);
+
+ fsm_change_state(cns_fcb, __LINE__, FSMCNF_S_CNFING);
+
+ cc_int_feature(CC_SRC_UI, CC_SRC_GSM, ccb->cns_call_id,
+ cns_fcb->dcb->line, CC_FEATURE_CONF, NULL);
+ return(SM_RC_END);
+
+ }
+
+ /*
+ * This call is the conference and we are initiating a local
+ * conference. So:
+ * 1. Make sure we have a free line to open a new call plane to
+ * collect digits (and place call) for the consultation call,
+ * 2. Create a new conference context,
+ * 3. Place this call on hold,
+ * 4. Send a newcall feature back to the GSM so that the
+ * consultation call can be initiated.
+ */
+
+ /*
+ * Check for any other active features which may block
+ * the conference.
+ */
+
+ /*
+ * The call must be in the connected state to initiate a conference.
+ */
+ fcb_def = fsm_get_fcb_by_call_id_and_type(call_id, FSM_TYPE_DEF);
+ if ((fcb_def != NULL) && (fcb_def->state != FSMDEF_S_CONNECTED)) {
+ break;
+ }
+
+ /*
+ * Make sure we have a free line to start the consultation call.
+ */
+ //CSCsz38962 don't use expline for local conf call
+ //free_lines = lsm_get_instances_available_cnt(line, TRUE);
+ free_lines = lsm_get_instances_available_cnt(line, FALSE);
+ if (free_lines <= 0) {
+ /*
+ * No free lines - let the user know and end this request.
+ */
+ fsm_display_no_free_lines();
+
+ break;
+ }
+
+ /*
+ * Get a new ccb and new cnf id - This is the handle that will
+ * identify the cnf.
+ */
+ ccb = fsmcnf_get_new_cnf_context(call_id);
+ if (ccb == NULL || ccb->cnf_id == 0) {
+ break;
+ }
+ fcb->ccb = ccb;
+ ccb->cnf_line = line;
+ ccb->cns_line = line;
+
+ /*
+ * This call needs to go on hold so we can start the consultation
+ * call. Indicate feature indication should be send by setting
+ * call info type to hold and feature reason to conference.
+ */
+ data.hold.call_info.type = CC_FEAT_HOLD;
+ data.hold.call_info.data.hold_resume_reason = CC_REASON_CONF;
+ data.hold.msg_body.num_parts = 0;
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, dcb->call_id, dcb->line,
+ CC_FEATURE_HOLD, &data);
+
+ /*
+ * Initiate the consultation call.
+ */
+ data.newcall.cause = CC_CAUSE_CONF;
+ cns_call_id = ccb->cns_call_id;
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, cns_call_id, line,
+ CC_FEATURE_NEW_CALL, &data);
+
+ FSM_DEBUG_SM(get_debug_string(FSMCNF_DBG_CNF_INITIATED),
+ ccb->cnf_id, call_id, cns_call_id, __LINE__);
+
+ fsm_change_state(fcb, __LINE__, FSMCNF_S_CNFING);
+
+ sm_rc = SM_RC_END;
+
+ break;
+
+ case CC_FEATURE_JOIN:
+ /*
+ * The call must be in the connected state to initiate a conference
+ */
+ fcb_def = fsm_get_fcb_by_call_id_and_type(call_id, FSM_TYPE_DEF);
+ if ((fcb_def != NULL) && (fcb_def->state != FSMDEF_S_CONNECTED)) {
+ break;
+ }
+
+ /*
+ * Make sure that we have another active call on this line.
+ */
+ other_dcb = fsmdef_get_other_dcb_by_line(call_id, dcb->line);
+ if (other_dcb == NULL) {
+ break;
+ }
+
+ /* get other calls FCB */
+ other_fcb = fsm_get_fcb_by_call_id_and_type(other_dcb->call_id,
+ FSM_TYPE_DEF);
+ if (other_fcb == NULL) {
+ break;
+ }
+
+ if (other_fcb->state == FSMDEF_S_HOLDING) {
+ /*
+ * Get a new ccb and new cnf id - This is the handle that will
+ * identify the cnf.
+ */
+ ccb = fsmcnf_get_new_cnf_context(call_id);
+ if (ccb == NULL) {
+ break;
+ }
+ fcb->ccb = ccb;
+ fsm_change_state(fcb, __LINE__, FSMCNF_S_CNFED);
+
+
+ other_fcb = fsm_get_fcb_by_call_id_and_type(other_dcb->call_id,
+ FSM_TYPE_CNF);
+ if (other_fcb == NULL) {
+ fsmcnf_cleanup(fcb, __LINE__, TRUE);
+ break;
+ }
+ other_fcb->ccb = ccb;
+ fsm_change_state(other_fcb, __LINE__, FSMCNF_S_CNFED);
+
+ ccb->cnf_call_id = dcb->call_id;
+ ccb->cns_call_id = other_dcb->call_id;
+ ccb->bridged = TRUE;
+
+ /* Build SDP for sending out */
+ cause = gsmsdp_encode_sdp_and_update_version(other_dcb,
+ &data.resume.msg_body);
+ if (cause != CC_CAUSE_OK) {
+ FSM_DEBUG_SM(get_debug_string(FSM_DBG_SDP_BUILD_ERR));
+ sm_rc = SM_RC_END;
+ break;
+ }
+ data.resume.cause = CC_CAUSE_CONF;
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, other_dcb->call_id,
+ other_dcb->line, CC_FEATURE_RESUME, &data);
+
+ /*
+ * Update the UI for this call.
+ */
+ action_data.update_ui.action = CC_UPDATE_CONF_ACTIVE;
+ (void)cc_call_action(other_dcb->call_id, other_dcb->line,
+ CC_ACTION_UPDATE_UI, &action_data);
+ } else {
+ fsm_display_feature_unavailable();
+ }
+
+ break;
+
+ default:
+ fsm_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ sm_rc = SM_RC_DEF_CONT;
+
+ break;
+ } /* switch (ftr_id) */
+
+ break;
+
+ case CC_SRC_GSM:
+ switch (ftr_id) {
+ case CC_FEATURE_NEW_CALL:
+
+ /*
+ * If this is the consultation call involved in a conference,
+ * then set the rest of the data required to make the conference
+ * happen. The data is the cnf_id in the fcb. The data is set now
+ * because we did not have the fcb when the conference was
+ * initiated. The fcb is created when a new_call event is
+ * received by the FIM, not when a conference event is received.
+ *
+ * Or this could be the call that originated the conference and
+ * the person he was talking to (the conference target) has
+ * decided to conference the trasnferor to another party.
+ */
+
+ /*
+ * Ignore this event if this call is not involved in a conference.
+ */
+ ccb = fsmcnf_get_ccb_by_call_id(call_id);
+ if (ccb == NULL) {
+ break;
+ }
+ fcb->ccb = ccb;
+
+ /*
+ * Determine what state this cnf should be in (cnfing or cnfed).
+ * If the cnfrn key has only been hit once, then this call will
+ * be in the cnfing state. If it has been hit the second time,
+ * then this call should go to the cnfed state. The latter
+ * case only happens when the calls are conferenced and one
+ * of the remote ends has decided to transfer one leg of the cnf.
+ * And it just so happens that the other call involved in the cnf
+ * should match this call, so we can just use it's state to
+ * assign the state to this call.
+ */
+ other_call_id = fsmcnf_get_other_call_id(ccb, call_id);
+ other_fcb = fsm_get_fcb_by_call_id_and_type(other_call_id,
+ FSM_TYPE_CNF);
+
+ if(other_fcb == NULL) {
+ GSM_DEBUG_ERROR(GSM_F_PREFIX"Failed to get FCB.\n", fname);
+ } else {
+ fsm_change_state(fcb, __LINE__, other_fcb->state);
+ }
+
+ break;
+
+ case CC_FEATURE_JOIN:
+ if (fsm_is_joining_call(ftr_data)) {
+ /*
+ * The join target call must be in the
+ * connected state to initiate a conference.
+ */
+ fcb_def = fsm_get_fcb_by_call_id_and_type(call_id,
+ FSM_TYPE_DEF);
+ if ((fcb_def == NULL) ||
+ ((fcb_def->state != FSMDEF_S_CONNECTED) &&
+ (fcb_def->state != FSMDEF_S_RESUME_PENDING))) {
+ FSM_DEBUG_SM(DEB_L_C_F_PREFIX"Join target \
+ call is not at connected state\n",
+ DEB_L_C_F_PREFIX_ARGS(FSM, line, call_id, fname));
+ break;
+ }
+
+ /* Get the joining call fcb */
+ join_fcb_cnf = fsm_get_fcb_by_call_id_and_type(
+ ftr_data.newcall.join.join_call_id,
+ FSM_TYPE_CNF);
+
+ /* Create a conference context for the join target call */
+ ccb = fsmcnf_get_new_cnf_context(call_id);
+ if (ccb == NULL || join_fcb_cnf == NULL) {
+ FSM_DEBUG_SM(DEB_L_C_F_PREFIX"Could not \
+ find the conference context\n",
+ DEB_L_C_F_PREFIX_ARGS(FSM, line, call_id, fname));
+ break;
+ }
+
+ fcb->ccb = ccb;
+ join_fcb_cnf->ccb = ccb;
+ ccb->cnf_call_id = fcb_def->dcb->call_id;
+ /* Joining call is the consultative call of the conference */
+ ccb->cns_call_id = join_fcb_cnf->dcb->call_id;
+
+ join_fcb_cnf->dcb->group_id = fcb_def->dcb->group_id;
+ fsm_change_state(fcb, __LINE__, FSMCNF_S_CNFED);
+ fsm_change_state(join_fcb_cnf, __LINE__, FSMCNF_S_CNFED);
+
+ softkey_mask_list[0] = skConfrn;
+ ui_select_feature_key_set(line, call_id,
+ FSMCNF_CONNECTED_SET,
+ softkey_mask_list, 1);
+
+ ccb->flags |= JOINED;
+
+ ccb->bridged = FALSE;
+ }
+ break;
+
+ default:
+ fsm_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ sm_rc = SM_RC_DEF_CONT;
+
+ break;
+ } /* switch (ftr_id) */
+
+ break;
+
+ case CC_SRC_SIP:
+ switch (ftr_id) {
+ case CC_FEATURE_NOTIFY:
+ if ((msg->data_valid == TRUE) &&
+ (msg->data.notify.subscription == CC_SUBSCRIPTIONS_XFER) &&
+ (msg->data.notify.method == CC_XFER_METHOD_REFER)) {
+ xcb = fsmxfr_get_xcb_by_call_id(call_id);
+ if ((xcb != NULL) && (call_id == xcb->cns_call_id)) {
+ /*
+ * One leg of the conference has decided to transfer us.
+ * We need to
+ * 1. remove the transferred call from the conference
+ * context and associate the new call
+ * with the context,
+ * 2. cleanup this transferred fcb.
+ */
+ ccb = fsmcnf_get_ccb_by_call_id(xcb->xfr_call_id);
+ if (ccb == NULL) {
+ break;
+ }
+
+ other_fcb =
+ fsm_get_fcb_by_call_id_and_type(xcb->xfr_call_id,
+ FSM_TYPE_CNF);
+ if (other_fcb == NULL) {
+ break;
+ }
+
+ fcb->ccb = ccb;
+
+ fsmcnf_update_cnf_context(ccb, xcb->xfr_call_id,
+ xcb->cns_call_id);
+
+ fsmcnf_cleanup(other_fcb, __LINE__, FALSE);
+
+ other_call_id = fsmcnf_get_other_call_id(ccb, call_id);
+ other_fcb = fsm_get_fcb_by_call_id_and_type(other_call_id,
+ FSM_TYPE_CNF);
+
+ fsm_change_state(fcb, __LINE__, other_fcb->state);
+
+ if (other_fcb->state == FSMCNF_S_CNFED) {
+ ccb->bridged = TRUE;
+
+ /*
+ * Resume the other leg of the conference that was
+ * not transferred.
+ */
+ other_dcb = fsm_get_dcb(other_call_id);
+
+ /* Build SDP for sending out */
+ cause = gsmsdp_encode_sdp_and_update_version(other_dcb,
+ &data.resume.msg_body);
+ if (cause != CC_CAUSE_OK) {
+ GSM_DEBUG_ERROR(get_debug_string(FSM_DBG_SDP_BUILD_ERR));
+ fsmcnf_cleanup(fcb, __LINE__, TRUE);
+ sm_rc = SM_RC_END;
+ break;
+ }
+ data.resume.cause = CC_CAUSE_CONF;
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM,
+ other_dcb->call_id, other_dcb->line,
+ CC_FEATURE_RESUME, &data);
+ }
+
+ /*
+ * Update the UI for the just transferred leg.
+ */
+ action_data.update_ui.action = CC_UPDATE_CONF_ACTIVE;
+ (void)cc_call_action(fcb->call_id, dcb->line,
+ CC_ACTION_UPDATE_UI, &action_data);
+ }
+ }
+
+ break;
+
+ default:
+ fsm_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ sm_rc = SM_RC_DEF_CONT;
+
+ break;
+ } /* switch (ftr_id) */
+
+ break;
+
+ default:
+ fsm_sm_ignore_src(fcb, __LINE__, src_id);
+ sm_rc = SM_RC_DEF_CONT;
+
+ break;
+ } /* switch (src_id) */
+
+ return (sm_rc);
+}
+
+
+static void
+fsmcnf_update_release (sm_event_t *event)
+{
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ callid_t other_call_id;
+ cc_action_data_t action_data;
+ fsm_fcb_t *other_fcb;
+
+ /*
+ * Update the UI for the other call.
+ */
+ other_call_id = fsmcnf_get_other_call_id(fcb->ccb, fcb->call_id);
+ if (other_call_id != CC_NO_CALL_ID) {
+ action_data.update_ui.action = CC_UPDATE_CONF_RELEASE;
+ (void)cc_call_action(other_call_id, fcb->dcb->line, CC_ACTION_UPDATE_UI,
+ &action_data);
+
+ /* Far end released its original call. Set the attribute of
+ * other call so it can display connected softkey set.
+ *
+ * Check only for the consultation leg since only that leg
+ * will need its attribute reset - the other leg does not
+ * have an atribute set.
+ */
+ if (fcb->ccb && (fcb->call_id == fcb->ccb->cnf_call_id)) {
+ other_fcb = fsm_get_fcb_by_call_id_and_type(other_call_id,
+ FSM_TYPE_CNF);
+ if (other_fcb != NULL) {
+ fsm_fcb_t *b2bcnf_fcb, *xfr_fcb;
+ b2bcnf_fcb = fsm_get_fcb_by_call_id_and_type(other_call_id,
+ FSM_TYPE_B2BCNF);
+ xfr_fcb = fsm_get_fcb_by_call_id_and_type(other_call_id,
+ FSM_TYPE_XFR);
+ if ((b2bcnf_fcb != NULL && b2bcnf_fcb->b2bccb == NULL) &&
+ (xfr_fcb != NULL && xfr_fcb->xcb == NULL)) {
+ cc_call_attribute(other_call_id, other_fcb->dcb->line, NORMAL_CALL);
+ }
+ }
+ }
+ }
+
+ fsmcnf_cleanup(fcb, __LINE__, TRUE);
+}
+
+
+static sm_rcs_t
+fsmcnf_ev_cnfing_release (sm_event_t *event)
+{
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ cc_release_t *msg = (cc_release_t *) event->msg;
+ callid_t call_id = msg->call_id;
+ fsmcnf_ccb_t *ccb = fcb->ccb;
+ fsmxfr_xcb_t *xcb;
+ fsm_fcb_t *other_fcb;
+
+ xcb = fsmxfr_get_xcb_by_call_id(call_id);
+ if (xcb != NULL) {
+ /*
+ * One leg of the conference has decided to transfer us.
+ * We need to
+ * 1. remove this call from the conference context and
+ * associate the new (transferred) call with the context,
+ * 2. cleanup this fcb.
+ */
+ fsmcnf_update_cnf_context(ccb, call_id, xcb->cns_call_id);
+
+ fsmcnf_cleanup(fcb, __LINE__, FALSE);
+
+ other_fcb = fsm_get_fcb_by_call_id_and_type(xcb->cns_call_id,
+ FSM_TYPE_CNF);
+
+ if (other_fcb != NULL) {
+ other_fcb->ccb = ccb;
+ fsm_change_state(other_fcb, __LINE__, FSMCNF_S_CNFING);
+ }
+
+ return (SM_RC_CONT);
+ }
+
+ fsmcnf_update_release(event);
+
+ return (SM_RC_CONT);
+}
+
+
+static sm_rcs_t
+fsmcnf_ev_cnfing_feature (sm_event_t *event)
+{
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ cc_feature_t *msg = (cc_feature_t *) event->msg;
+ callid_t call_id = msg->call_id;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ fsmcnf_ccb_t *ccb = fcb->ccb;
+ cc_srcs_t src_id = msg->src_id;
+ cc_features_t ftr_id = msg->feature_id;
+ static const char fname[] = "fsmcnf_ev_cnfing_feature";
+ cc_feature_data_t *feat_data = &(msg->data);
+ sm_rcs_t sm_rc = SM_RC_CONT;
+ callid_t other_call_id;
+ fsmdef_dcb_t *other_dcb;
+ fsm_fcb_t *other_fcb;
+ cc_action_data_t action_data;
+ cc_feature_data_t data;
+ cc_causes_t cause;
+
+ fsm_sm_ftr(ftr_id, src_id);
+
+ switch (src_id) {
+ case CC_SRC_UI:
+ switch (ftr_id) {
+ case CC_FEATURE_CANCEL:
+ sm_rc = SM_RC_END;
+ fsmcnf_feature_cancel(ccb, ccb->cnf_line, ccb->cnf_call_id,
+ ccb->cns_call_id /*,
+ CC_SK_EVT_TYPE_EXPLI */);
+ fsmcnf_cleanup(fcb, __LINE__, TRUE);
+ break;
+
+ case CC_FEATURE_ANSWER:
+ other_call_id = fsmcnf_get_other_call_id(ccb, call_id);
+ if (other_call_id == CC_NO_CALL_ID) {
+ fsm_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ return (sm_rc);
+ }
+ other_dcb = fsm_get_dcb(other_call_id);
+ if (other_dcb == NULL) {
+ fsm_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ return (sm_rc);
+ }
+ /*
+ * The answer to the a setup with replaced we have received.
+ * The setup with replaced is automatically answered
+ * by xfer state machine as UI source (simulate user pressing
+ * the answer key).
+ *
+ * Set the group ID to the new call so that the voice can be
+ * mixed with the new call.
+ */
+ dcb->group_id = other_dcb->group_id;
+ fsm_change_state(fcb, __LINE__, FSMCNF_S_CNFED);
+ return (sm_rc);
+
+ default:
+ break;
+ }
+ /* Fall through */
+
+ case CC_SRC_GSM:
+ switch (ftr_id) {
+ case CC_FEATURE_CONF:
+ /*
+ * This is the second conference event for a local
+ * attended conference with consultation.
+ *
+ * The user is attempting to complete the conference, so
+ * resume the other leg of the conference call.
+ */
+ ccb->bridged = TRUE;
+ ccb->active = TRUE;
+ ccb->flags |= LCL_CNF;
+
+ other_call_id = fsmcnf_get_other_call_id(ccb, call_id);
+ other_dcb = fsm_get_dcb(other_call_id);
+
+ /*
+ * Since we are resuming the other leg, allocate the src_sdp
+ * because src_sdp was freed and set to null when this other-leg
+ * was put on hold.
+ */
+ gsmsdp_update_local_sdp_media_capability(other_dcb, TRUE, FALSE);
+
+ /* Build SDP for sending out */
+ cause = gsmsdp_encode_sdp_and_update_version(other_dcb,
+ &data.resume.msg_body);
+ if (cause != CC_CAUSE_OK) {
+ GSM_DEBUG_ERROR(get_debug_string(FSM_DBG_SDP_BUILD_ERR));
+ sm_rc = SM_RC_END;
+ break;
+ }
+ data.resume.cause = CC_CAUSE_CONF;
+
+ other_fcb = fsm_get_fcb_by_call_id_and_type(other_call_id,
+ FSM_TYPE_DEF);
+ if (other_fcb && other_fcb->state == FSMDEF_S_HOLDING) {
+
+ other_dcb->session = LOCAL_CONF;
+
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, other_dcb->call_id,
+ other_dcb->line, CC_FEATURE_RESUME, &data);
+
+ } else {
+ /* Other call must be on hold */
+
+ dcb->session = LOCAL_CONF;
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, call_id,
+ ccb->cnf_line, CC_FEATURE_RESUME, &data);
+
+
+ }
+
+ /*
+ * Update the UI for this call.
+ */
+ action_data.update_ui.action = CC_UPDATE_CONF_ACTIVE;
+ (void)cc_call_action(dcb->call_id, dcb->line, CC_ACTION_UPDATE_UI,
+ &action_data);
+
+ other_fcb = fsm_get_fcb_by_call_id_and_type(other_call_id,
+ FSM_TYPE_CNF);
+ fsm_change_state(other_fcb, __LINE__, FSMCNF_S_CNFED);
+ fsm_change_state(fcb, __LINE__, FSMCNF_S_CNFED);
+
+ sm_rc = SM_RC_END;
+
+ break;
+
+ case CC_FEATURE_END_CALL:
+ fsmcnf_update_release(event);
+
+ break;
+
+ case CC_FEATURE_HOLD:
+ if ((msg->data_valid) &&
+ (feat_data->hold.call_info.data.hold_resume_reason != CC_REASON_SWAP &&
+ feat_data->hold.call_info.data.hold_resume_reason != CC_REASON_CONF &&
+ feat_data->hold.call_info.data.hold_resume_reason != CC_REASON_INTERNAL)) {
+ sm_rc = SM_RC_END;
+ DEF_DEBUG(DEB_F_PREFIX"Invoke hold call_id = %d t_call_id=%d\n",
+ DEB_F_PREFIX_ARGS(GSM, fname), ccb->cnf_call_id, ccb->cns_call_id);
+ //Actual hold to this call, so break the feature layer.
+ ui_terminate_feature(dcb->line, ccb->cnf_call_id, ccb->cns_call_id);
+
+ fsmcnf_feature_cancel(ccb, ccb->cnf_line, ccb->cnf_call_id,
+ ccb->cns_call_id /*,
+ CC_SK_EVT_TYPE_EXPLI */);
+ fsmcnf_cleanup(fcb, __LINE__, TRUE);
+ }
+ break;
+
+ default:
+ fsm_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+
+ break;
+ } /* switch (ftr_id) */
+
+ break;
+
+ case CC_SRC_SIP:
+ switch (ftr_id) {
+ default:
+ fsm_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+
+ break;
+ } /* switch (ftr_id) */
+
+ break;
+
+ default:
+ fsm_sm_ignore_src(fcb, __LINE__, src_id);
+
+ break;
+ } /* switch (src_id) */
+
+ return (sm_rc);
+}
+
+
+static sm_rcs_t
+fsmcnf_ev_cnfing_onhook (sm_event_t *event)
+{
+ fsmcnf_update_release(event);
+
+ return (SM_RC_CONT);
+}
+
+
+static sm_rcs_t
+fsmcnf_ev_cnfed_release (sm_event_t *event)
+{
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ cc_release_t *msg = (cc_release_t *) event->msg;
+ callid_t call_id = msg->call_id;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ fsmcnf_ccb_t *ccb = fcb->ccb;
+ callid_t other_call_id;
+ fsmdef_dcb_t *other_dcb;
+ cc_feature_data_t data;
+ cc_action_data_t action_data;
+ fsmxfr_xcb_t *xcb;
+ fsm_fcb_t *other_fcb;
+ cc_causes_t cause;
+
+ /* Conference is not active any more, clear that flag
+ */
+ ccb->active = FALSE;
+
+ if( ccb->flags & JOINED ){
+ other_call_id = fsmcnf_get_other_call_id(ccb, call_id);
+ if(other_call_id != CC_NO_CALL_ID ){
+ fsm_fcb_t *b2bcnf_fcb, *xfr_fcb;
+ b2bcnf_fcb = fsm_get_fcb_by_call_id_and_type(other_call_id,
+ FSM_TYPE_B2BCNF);
+ xfr_fcb = fsm_get_fcb_by_call_id_and_type(other_call_id,
+ FSM_TYPE_XFR);
+ if ((b2bcnf_fcb != NULL && b2bcnf_fcb->b2bccb == NULL) &&
+ (xfr_fcb != NULL && xfr_fcb->xcb == NULL)) {
+ cc_call_attribute(other_call_id, dcb->line, NORMAL_CALL);
+ }
+ }
+ }
+ xcb = fsmxfr_get_xcb_by_call_id(call_id);
+ if ((xcb != NULL) && (!(ccb->flags & JOINED))) {
+ /*
+ * One leg of the conference has decided to transfer us.
+ * We need to:
+ * 1. remove this call from the conference context and
+ * associate the new (transferred) call with the context,
+ * 2. Resume the other leg of the conference that was not transferred.
+ * More than likely this leg was put on hold when the transfer
+ * was intitated if this was a REFER transfer.
+ * 3.
+ */
+ fsmcnf_update_cnf_context(ccb, call_id, xcb->cns_call_id);
+
+ fsmcnf_cleanup(fcb, __LINE__, FALSE);
+
+ /* NOTE:
+ * Normally, we would reset the ccb->bridged flag to indicate
+ * that the bridge is not active. We do not want to do that in
+ * this case because we want the conference to bridge as soon as
+ * the target we are transferred to answers.
+ */
+
+ ccb->bridged = TRUE;
+
+ /*
+ * Resume the other leg of the conference that was not transferred.
+ */
+ other_call_id = fsmcnf_get_other_call_id(ccb, xcb->cns_call_id);
+ other_dcb = fsm_get_dcb(other_call_id);
+
+ /* Build SDP for sending out */
+ cause = gsmsdp_encode_sdp_and_update_version(other_dcb,
+ &data.resume.msg_body);
+ if (cause != CC_CAUSE_OK) {
+ GSM_DEBUG_ERROR(get_debug_string(FSM_DBG_SDP_BUILD_ERR));
+ return (SM_RC_END);
+ }
+ data.resume.cause = CC_CAUSE_CONF;
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, other_dcb->call_id,
+ other_dcb->line, CC_FEATURE_RESUME, &data);
+
+ /*
+ * Update the UI for the just transferred leg.
+ */
+ other_fcb = fsm_get_fcb_by_call_id_and_type(xcb->cns_call_id,
+ FSM_TYPE_CNF);
+
+ if (other_fcb != NULL) {
+ other_fcb->ccb = ccb;
+
+ fsm_change_state(other_fcb, __LINE__, FSMCNF_S_CNFED);
+
+ action_data.update_ui.action = CC_UPDATE_CONF_ACTIVE;
+ cc_call_action(other_fcb->call_id, dcb->line, CC_ACTION_UPDATE_UI,
+ &action_data);
+ return (SM_RC_CONT);
+ }
+ }
+
+ fsmcnf_update_release(event);
+
+ return (SM_RC_CONT);
+}
+
+
+static void
+fsmcnf_other_feature (fsm_fcb_t *fcb, cc_features_t ftr_id)
+{
+ callid_t other_call_id;
+
+ other_call_id = fsmcnf_get_other_call_id(fcb->ccb, fcb->call_id);
+ if (other_call_id != CC_NO_CALL_ID) {
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, other_call_id,
+ fcb->dcb->line, ftr_id, NULL);
+ }
+}
+
+
+static sm_rcs_t
+fsmcnf_ev_cnfed_feature (sm_event_t *event)
+{
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ cc_feature_t *msg = (cc_feature_t *) event->msg;
+ callid_t call_id = msg->call_id;
+ cc_srcs_t src_id = msg->src_id;
+ cc_features_t ftr_id = msg->feature_id;
+ sm_rcs_t sm_rc = SM_RC_CONT;
+ fsmcnf_ccb_t *ccb = fcb->ccb;
+ fsmxfr_xcb_t *xcb;
+ int join = 1;
+
+ fsm_sm_ftr(ftr_id, src_id);
+
+ switch (src_id) {
+ case CC_SRC_UI:
+ case CC_SRC_GSM:
+ switch (ftr_id) {
+ case CC_FEATURE_CANCEL:
+ sm_rc = SM_RC_END;
+ fsmcnf_cleanup(fcb, __LINE__, TRUE);
+ break;
+
+ case CC_FEATURE_END_CALL:
+ if ((ccb->flags & JOINED) && (ccb->bridged == FALSE)) {
+ /* Something went wrong during the barge/monitor call setup, clean up */
+ fsmcnf_cleanup(fcb, __LINE__, TRUE);
+ return (sm_rc);
+ }
+ /*
+ * If bridge of conference call ends the call, other 2
+ * users should still be able to talk to each other.
+ * So we simulate attended transfer when bridge tries
+ * to end the call.
+ */
+ config_get_value(CFGID_CNF_JOIN_ENABLE, &join, sizeof(join));
+ if (((ccb->bridged == TRUE) && (join) && !(ccb->flags & JOINED)) ||
+ ((ccb->bridged == TRUE) && (ccb->flags & XFER))) {
+
+ fsmcnf_cnf_xfer(ccb);
+ sm_rc = SM_RC_END;
+ } else {
+ /*
+ * The user is attempting to clear the call, therefore
+ * we need to also clear the other leg of this
+ * conference if it is active.
+ */
+ fsmcnf_other_feature(fcb, ftr_id);
+ }
+
+ fsmcnf_cleanup(fcb, __LINE__, TRUE);
+ break;
+
+ case CC_FEATURE_HOLD:
+ /* Don't process the Hold if we are still waiting
+ * on an ack from a previous Resume.
+ */
+ if ((ccb->cnf_ftr_ack) && (src_id == CC_SRC_UI)) {
+ return (SM_RC_END);
+ }
+
+ /*
+ * The user is attempting to hold the call, therefore we need
+ * to also hold the other leg of this conference. Only update
+ * the other leg if the conference is bridged and not involved
+ * in a transfer.
+ */
+ if (ccb->bridged == TRUE) {
+
+ if ((ccb->flags & XFER) && (src_id == CC_SRC_GSM)) {
+ fsmcnf_cleanup(fcb, __LINE__, TRUE);
+ return (sm_rc);
+ }
+ xcb = fsmxfr_get_xcb_by_call_id(call_id);
+ if ((xcb == NULL) || (!(ccb->flags & XFER))) {
+ fsmcnf_other_feature(fcb, ftr_id);
+ ccb->cnf_ftr_ack = TRUE;
+ ccb->bridged = FALSE;
+ }
+ }
+ break;
+
+ case CC_FEATURE_RESUME:
+ /* Don't process the Resume if we are still waiting
+ * on an ack from a previous Hold.
+ */
+ if ((ccb->cnf_ftr_ack) && (src_id == CC_SRC_UI)) {
+ return (SM_RC_END);
+ }
+
+ /*
+ * The user is attempting to resume the call, therefore we need
+ * to also resume the other leg of this conference. Only do this
+ * if the conference is not bridged.
+ */
+ if (ccb->bridged == FALSE) {
+ fsmcnf_other_feature(fcb, ftr_id);
+ ccb->cnf_ftr_ack = TRUE;
+ ccb->bridged = TRUE;
+ }
+ break;
+
+ default:
+ fsm_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ break;
+ } /* switch (ftr_id) */
+ break;
+
+ case CC_SRC_SIP:
+ switch (ftr_id) {
+ case CC_FEATURE_CALLINFO:
+ if ((ccb->flags & JOINED) &&
+ (call_id == ccb->cns_call_id)) {
+ /*
+ * Call is already joined into, eat this call
+ * info event that came for the virtual bubble
+ */
+ return (SM_RC_END);
+ }
+ fsm_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ break;
+
+ case CC_FEATURE_XFER:
+ if (msg->data_valid == FALSE) {
+ fsm_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ break;
+ }
+
+ switch (msg->data.xfer.method) {
+ case CC_XFER_METHOD_BYE:
+ fsm_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ break;
+
+ case CC_XFER_METHOD_REFER:
+ if ((msg->data.xfer.cause == CC_CAUSE_XFER_REMOTE) &&
+ (msg->data.xfer.target_call_id != CC_NO_CALL_ID)) {
+ /*
+ * This operation is replacing this call leg with the
+ * new leg. This call is a target of a transfer.
+ * Replace the call id of this call with the new
+ * replacing call id.
+ */
+ fsmcnf_update_cnf_context(ccb, call_id,
+ msg->data.xfer.target_call_id);
+ /* Drop this call from conferenced */
+ fsmcnf_cleanup(fcb, __LINE__, FALSE);
+ } else {
+ fsm_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ }
+ break;
+
+ default:
+ fsm_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ break;
+ }
+ break;
+
+ default:
+ fsm_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ break;
+ }
+ break;
+
+ default:
+ fsm_sm_ignore_src(fcb, __LINE__, src_id);
+ break;
+ } /* switch (src_id) */
+
+ return (sm_rc);
+}
+
+
+static sm_rcs_t
+fsmcnf_ev_cnfed_feature_ack (sm_event_t *event)
+{
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ cc_feature_ack_t *msg = (cc_feature_ack_t *) event->msg;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ fsmcnf_ccb_t *ccb = fcb->ccb;
+ cc_srcs_t src_id = msg->src_id;
+ cc_features_t ftr_id = msg->feature_id;
+ sm_rcs_t sm_rc = SM_RC_CONT;
+ cc_feature_data_t ftr_data;
+ cc_causes_t cause;
+ char tmp_str[STATUS_LINE_MAX_LEN];
+
+ fsm_sm_ftr(ftr_id, src_id);
+
+ switch (src_id) {
+ case CC_SRC_SIP:
+ switch (ftr_id) {
+ case CC_FEATURE_HOLD:
+ /*
+ * HOLD request is pending. Let this event drop through
+ * to the default sm for handling.
+ */
+ if (msg->cause == CC_CAUSE_REQUEST_PENDING) {
+ fsm_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ } else {
+ ccb->cnf_ftr_ack = FALSE;
+ }
+ break;
+
+ case CC_FEATURE_RESUME:
+ /*
+ * Resume request is pending. Let this event drop through
+ * to the default sm for handling.
+ */
+ if (msg->cause == CC_CAUSE_REQUEST_PENDING) {
+ fsm_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ break;
+ }
+
+ ccb->cnf_ftr_ack = FALSE;
+
+ /*
+ * Check the status of the cause code
+ */
+ if (msg->cause != CC_CAUSE_NORMAL) {
+ if ((platGetPhraseText(STR_INDEX_CNFR_FAIL_NOCODEC,
+ (char *) tmp_str,
+ STATUS_LINE_MAX_LEN - 1)) == CPR_SUCCESS) {
+ lsm_ui_display_notify(tmp_str, NO_FREE_LINES_TIMEOUT);
+ }
+
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, ccb->cns_call_id,
+ fcb->dcb->line, CC_FEATURE_END_CALL, NULL);
+
+ dcb = fsmdef_get_dcb_by_call_id(ccb->cnf_call_id);
+ if (dcb != NULL) {
+ /* Build SDP for sending out */
+ cause = gsmsdp_encode_sdp_and_update_version(dcb,
+ &ftr_data.resume.msg_body);
+ if (cause != CC_CAUSE_OK) {
+ GSM_DEBUG_ERROR(get_debug_string(FSM_DBG_SDP_BUILD_ERR));
+ return (SM_RC_END);
+ }
+ ftr_data.resume.cause = CC_CAUSE_OK;
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, dcb->call_id,
+ dcb->line, CC_FEATURE_RESUME, &ftr_data);
+ }
+
+ fsmcnf_cleanup(fcb, __LINE__, TRUE);
+ }
+
+ break;
+
+ default:
+ fsm_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+
+ break;
+ } /* switch (ftr_id) */
+
+ break;
+
+ default:
+ fsm_sm_ignore_src(fcb, __LINE__, src_id);
+
+ break;
+ } /* switch (src_id) */
+
+ return (sm_rc);
+}
+
+
+static sm_rcs_t
+fsmcnf_ev_cnfed_onhook (sm_event_t *event)
+{
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ sm_rcs_t sm_rc = SM_RC_CONT;
+ fsmcnf_ccb_t *ccb = fcb->ccb;
+ int join = 1;
+ fsmdef_dcb_t *other_dcb;
+ boolean conf_id_valid = FALSE;
+
+ /* If call_id of the ONHOOK received is of cnf_call_id,
+ * flag to dcb of cns_call_id to know of the event,
+ * and vice versa. We do not want to process more than
+ * one onhook for calls in a conf call. Note that this is
+ * needed because when in Speaker mode, onhook event is
+ * sent to each call_id in active state.
+ */
+ if (fcb->call_id == ccb->cnf_call_id) {
+ other_dcb = fsm_get_dcb(ccb->cns_call_id);
+ } else {
+ other_dcb = fsm_get_dcb(ccb->cnf_call_id);
+ }
+ other_dcb->onhook_received = TRUE;
+
+ // CSCtc04202, when conf_id_valid is FALSE,which mean at least one call is dropped
+ // Need release the whole conference session.
+ conf_id_valid = fsmcnd_conf_call_id_valid(ccb);
+ config_get_value(CFGID_CNF_JOIN_ENABLE, &join, sizeof(join));
+ if (((ccb->bridged == TRUE) && (join) && !(ccb->flags & JOINED) && (conf_id_valid)) ||
+ ((ccb->bridged == TRUE) && (ccb->flags & XFER) && (conf_id_valid))) {
+ /*
+ * If bridge of conference call ends the call other 2
+ * users should still be able to talk to each other
+ * So we simulate attended transfer when bridge tries
+ * to end the call
+ */
+ fsmcnf_cnf_xfer(ccb);
+ sm_rc = SM_RC_END;
+ } else {
+ /*
+ * The user is attempting to clear the call, therefore
+ * we need to also clear the other leg of this
+ * conference if it is active.
+ */
+ fsmcnf_other_feature(fcb, CC_FEATURE_END_CALL);
+ }
+
+ fsmcnf_cleanup(fcb, __LINE__, TRUE);
+ return (sm_rc);
+}
+
+
+cc_int32_t
+fsmcnf_show_cmd (cc_int32_t argc, const char *argv[])
+{
+ fsmcnf_ccb_t *ccb;
+ int i = 0;
+
+ PR_ASSERT(i == 0);
+ /*
+ * check if need help
+ */
+ if ((argc == 2) && (argv[1][0] == '?')) {
+ debugif_printf("%s", "show fsmcnf\n");
+ return (0);
+ }
+
+ debugif_printf("%s", "\n-------------------------- FSMCNF ccbs --------------------------");
+ debugif_printf("%s", "\ni cnf_id ccb cnf_call_id cns_call_id active bridged");
+ debugif_printf("%s", "\n-----------------------------------------------------------------"
+ "\n");
+
+ FSM_FOR_ALL_CBS(ccb, fsmcnf_ccbs, FSMCNF_MAX_CCBS) {
+ debugif_printf("%-2d %-6d 0x%8p %-11d %-11d %-6d %-7d\n",
+ i++, ccb->cnf_id, ccb, ccb->cnf_call_id,
+ ccb->cns_call_id, ccb->active, ccb->bridged);
+ }
+
+ return (0);
+}
+
+
+void
+fsmcnf_init (void)
+{
+ fsmcnf_ccb_t *ccb;
+ static const char *fname = "fsmcnf_init";
+
+
+ /*
+ * Initialize the ccbs.
+ */
+ fsmcnf_ccbs = (fsmcnf_ccb_t *)
+ cpr_calloc(FSMCNF_MAX_CCBS, sizeof(fsmcnf_ccb_t));
+
+ if (fsmcnf_ccbs == NULL) {
+ GSM_DEBUG_ERROR(GSM_F_PREFIX"Failed to allocate memory for " \
+ "cnf ccbs.\n", fname);
+ return;
+ }
+
+ FSM_FOR_ALL_CBS(ccb, fsmcnf_ccbs, FSMCNF_MAX_CCBS) {
+ fsmcnf_init_ccb(ccb);
+ }
+
+ /*
+ * Initialize the state/event table.
+ */
+ fsmcnf_sm_table.min_state = FSMCNF_S_MIN;
+ fsmcnf_sm_table.max_state = FSMCNF_S_MAX;
+ fsmcnf_sm_table.min_event = CC_MSG_MIN;
+ fsmcnf_sm_table.max_event = CC_MSG_MAX;
+ fsmcnf_sm_table.table = (&(fsmcnf_function_table[0][0]));
+}
+
+int
+cc_is_cnf_call (callid_t call_id)
+{
+ if (call_id == CC_NO_CALL_ID) {
+ return FALSE;
+ }
+ return fsmutil_is_cnf_leg(call_id, fsmcnf_ccbs, FSMCNF_MAX_CCBS);
+}
+
+void
+fsmcnf_shutdown (void)
+{
+ cpr_free(fsmcnf_ccbs);
+ fsmcnf_ccbs = NULL;
+}
+
+int
+fsmutil_is_cnf_consult_call (callid_t call_id)
+{
+ return fsmutil_is_cnf_consult_leg(call_id, fsmcnf_ccbs, FSMCNF_MAX_CCBS);
+}
+
+boolean
+fsmcnd_conf_call_id_valid(fsmcnf_ccb_t *ccb){
+
+ static const char fname[] = "fsmcnd_conf_call_id_valid";
+ if( ccb != NULL){
+ FSM_DEBUG_SM(get_debug_string(FSMCNF_DBG_PTR), ccb->cnf_id,
+ ccb->cnf_call_id, ccb->cns_call_id, fname, ccb);
+ if((ccb->cnf_call_id != CC_NO_CALL_ID) && (ccb->cns_call_id != CC_NO_CALL_ID) ){
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
diff --git a/libs/sipcc/core/gsm/fsmdef.c b/libs/sipcc/core/gsm/fsmdef.c
new file mode 100755
index 0000000000..2c35f3dadb
--- /dev/null
+++ b/libs/sipcc/core/gsm/fsmdef.c
@@ -0,0 +1,8668 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include
+#include "CCProvider.h"
+#include "cpr_types.h"
+#include "cpr_stdlib.h"
+#include "cpr_stdio.h"
+#include "cpr_string.h"
+#include "cpr_rand.h"
+#include "cpr_timers.h"
+#include "cpr_errno.h"
+#include "phone.h"
+#include "lsm.h"
+#include "fsm.h"
+#include "sm.h"
+#include "ccapi.h"
+#include "ccsip_cc.h"
+#include "phone_debug.h"
+#include "fim.h"
+#include "config.h"
+#include "sdp.h"
+#include "ccsip_sdp.h" // Temporary include
+#include "rtp_defs.h"
+#include "debug.h"
+#include "gsm_sdp.h"
+#include "vcm.h"
+#include "uiapi.h"
+#include "gsm.h"
+#include "phntask.h"
+#include "prot_configmgr.h"
+#include "sip_interface_regmgr.h"
+#include "dialplanint.h"
+#include "subapi.h"
+#include "text_strings.h"
+#include "platform_api.h"
+#include "peer_connection_types.h"
+//#include "prlog.h"
+#include "sessionHash.h"
+
+extern void update_kpmlconfig(int kpmlVal);
+extern boolean g_disable_mass_reg_debug_print;
+void escalateDeescalate();
+
+#define FSMDEF_NO_NUMBER (NULL)
+#define DIGIT_POUND ('#')
+#define FSMDEF_MAX_DCBS (LSM_MAX_CALLS)
+#define FSMDEF_CC_CALLER_ID ((cc_state_data_t *)(&(dcb->caller_id)))
+#define RINGBACK_DELAY 90
+
+// Minimum and maximum hold reversion timer in seconds
+#define MIN_HOLD_REVERSION_INTERVAL_TIMER 10
+#define MAX_HOLD_REVERSION_INTERVAL_TIMER 1200
+
+fsmdef_dcb_t *fsmdef_dcbs;
+
+static const char *fsmdef_state_names[] = {
+ "IDLE",
+ "COLLECTING_INFO",
+ "CALL_SENT",
+ "OUTGOING_PROCEEDING",
+ "KPML_COLLECTING_INFO",
+ "OUTGOING_ALERTING",
+ "INCOMING_ALERTING",
+ "CONNECTING",
+ "JOINING",
+ "CONNECTED",
+ "CONNECTED MEDIA PEND",
+ "RELEASING",
+ "HOLD_PENDING",
+ "HOLDING",
+ "RESUME_PENDING",
+ "PRESERVED"
+};
+
+
+static sm_rcs_t fsmdef_ev_createoffer(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_createanswer(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_setlocaldesc(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_setremotedesc(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_setpeerconnection(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_localdesc(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_remotedesc(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_addstream(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_removestream(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_addcandidate(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_default(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_default_feature_ack(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_idle_setup(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_idle_feature(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_idle_offhook(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_idle_dialstring(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_onhook(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_collectinginfo_release(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_collectinginfo_feature(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_offhook(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_digit_begin(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_dialstring(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_proceeding(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_callsent_release(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_callsent_feature(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_out_alerting(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_inalerting_feature(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_inalerting_offhook(sm_event_t *event);
+static sm_rcs_t fsmdef_handle_inalerting_offhook_answer(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_connected(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_connected_line(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_connected_ack(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_connecting_feature(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_connected_feature(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_connected_media_pend_feature(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_connected_media_pend_feature_ack(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_release(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_release_complete(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_releasing_release(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_releasing_feature(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_releasing_onhook(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_hold_pending_feature(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_hold_pending_feature_ack(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_holding_release(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_holding_feature(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_holding_feature_ack(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_holding_onhook(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_holding_offhook(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_session_audit(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_resume_pending_feature(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_resume_pending_feature_ack(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_preserved_feature(sm_event_t *event);
+static void fsmdef_ev_join(cc_feature_data_t *data);
+
+static sm_rcs_t fsmdef_cfwd_clear_ccm(fsm_fcb_t *fcb);
+static sm_rcs_t fsmdef_process_dialstring_for_callfwd(sm_event_t *event);
+static sm_rcs_t fsmdef_process_cfwd_softkey_event(sm_event_t *event);
+static sm_rcs_t fsmdef_cfwd_clear_ccm(fsm_fcb_t *fcb);
+static sm_rcs_t fsmdef_ev_joining_connected_ack(sm_event_t *event);
+static sm_rcs_t fsmdef_ev_joining_offhook(sm_event_t *event);
+
+static void fsmdef_b2bjoin_invoke(fsmdef_dcb_t *dcb,
+ cc_feature_data_t *join_data);
+static void fsmdef_select_invoke(fsmdef_dcb_t *dcb,
+ cc_feature_data_t *select_data);
+static void fsmdef_handle_join_pending(fsmdef_dcb_t *dcb);
+static void fsmdef_append_dialstring_to_feature_uri(fsmdef_dcb_t *dcb,
+ const char *dialstring);
+static boolean fsmdef_is_feature_uri_configured(cc_features_t ftr_id);
+static void fsmdef_set_call_info_cc_call_state(fsmdef_dcb_t *dcb,
+ cc_states_t state,
+ cc_causes_t cause);
+static boolean fsmdef_extract_join_target(sm_event_t *event);
+static void fsmdef_ev_notify_feature(cc_feature_t *msg, fsmdef_dcb_t *dcb);
+static void fsmdef_notify_hook_event(fsm_fcb_t *fcb, cc_msgs_t msg,
+ char *global_call_id,
+ callid_t prim_call_id,
+ cc_hold_resume_reason_e consult_reason,
+ monitor_mode_t monitor_mode,
+ cfwdall_mode_t cfwdall_mode);
+static void fsmdef_update_callinfo_security_status(fsmdef_dcb_t *dcb,
+ cc_feature_data_call_info_t *call_info);
+static void fsmdef_update_calltype (fsm_fcb_t *fcb, cc_feature_t *msg);
+
+
+/*
+ * TODO Update events for correct JSEP transitions
+ * Instead of providing events for all states
+ */
+static sm_function_t fsmdef_function_table[FSMDEF_S_MAX][CC_MSG_MAX] =
+{
+/* FSMDEF_S_IDLE ------------------------------------------------------------ */
+ {
+ /* CC_MSG_SETUP */ fsmdef_ev_idle_setup, // New incoming
+ /* CC_MSG_SETUP_ACK */ fsmdef_ev_default,
+ /* CC_MSG_PROCEEDING */ fsmdef_ev_default,
+ /* CC_MSG_ALERTING */ fsmdef_ev_default,
+ /* CC_MSG_CONNECTED */ fsmdef_ev_default,
+ /* CC_MSG_CONNECTED_ACK */ fsmdef_ev_default,
+ /* CC_MSG_RELEASE */ fsmdef_ev_default,
+ /* CC_MSG_RELEASE_COMPLETE */ fsmdef_ev_release_complete,
+ /* CC_MSG_FEATURE */ fsmdef_ev_idle_feature,
+ /* CC_MSG_FEATURE_ACK */ fsmdef_ev_default_feature_ack,
+ /* CC_MSG_OFFHOOK */ fsmdef_ev_idle_offhook,
+ /* CC_MSG_ONHOOK */ fsmdef_ev_default,
+ /* CC_MSG_LINE */ fsmdef_ev_idle_offhook,
+ /* CC_MSG_DIGIT_BEGIN */ fsmdef_ev_default,
+ /* CC_MSG_DIGIT_END */ fsmdef_ev_default,
+ /* CC_MSG_DIALSTRING */ fsmdef_ev_idle_dialstring, // new outgoing
+ /* CC_MSG_MWI */ fsmdef_ev_default,
+ /* CC_MSG_SESSION_AUDIT */ fsmdef_ev_session_audit,
+ /* CC_MSG_CREATEOFFER */ fsmdef_ev_createoffer,
+ /* CC_MSG_CREATEANSWER */ fsmdef_ev_createanswer,
+ /* CC_MSG_SETLOCALDESC */ fsmdef_ev_setlocaldesc,
+ /* CC_MSG_SETREMOTEDESC */ fsmdef_ev_setremotedesc,
+ /* CC_MSG_LOCALDESC */ fsmdef_ev_localdesc,
+ /* CC_MSG_REMOTEDESC */ fsmdef_ev_remotedesc,
+ /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_setpeerconnection,
+ /* CC_MSG_ADDSTREAM */ fsmdef_ev_addstream,
+ /* CC_MSG_REMOVESTREAM */ fsmdef_ev_removestream,
+ /* CC_MSG_ADDCANDIDATE */ fsmdef_ev_addcandidate
+ },
+
+/* FSMDEF_S_COLLECT_INFO ---------------------------------------------------- */
+ {
+ /* CC_MSG_SETUP */ fsmdef_ev_default,
+ /* CC_MSG_SETUP_ACK */ fsmdef_ev_default,
+ /* CC_MSG_PROCEEDING */ fsmdef_ev_default,
+ /* CC_MSG_ALERTING */ fsmdef_ev_default,
+ /* CC_MSG_CONNECTED */ fsmdef_ev_default,
+ /* CC_MSG_CONNECTED_ACK */ fsmdef_ev_default,
+ /* CC_MSG_RELEASE */ fsmdef_ev_collectinginfo_release,
+ /* CC_MSG_RELEASE_COMPLETE */ fsmdef_ev_default,
+ /* CC_MSG_FEATURE */ fsmdef_ev_collectinginfo_feature,
+ /* CC_MSG_FEATURE_ACK */ fsmdef_ev_default_feature_ack,
+ /* CC_MSG_OFFHOOK */ fsmdef_ev_default,
+ /* CC_MSG_ONHOOK */ fsmdef_ev_onhook,
+ /* CC_MSG_LINE */ fsmdef_ev_default,
+ /* CC_MSG_DIGIT_BEGIN */ fsmdef_ev_digit_begin,
+ /* CC_MSG_DIGIT_END */ fsmdef_ev_default,
+ /* CC_MSG_DIALSTRING */ fsmdef_ev_dialstring,
+ /* CC_MSG_MWI */ fsmdef_ev_default,
+ /* CC_MSG_SESSION_AUDIT */ fsmdef_ev_session_audit,
+ /* CC_MSG_CREATEOFFER */ fsmdef_ev_createoffer,
+ /* CC_MSG_CREATEANSWER */ fsmdef_ev_createanswer,
+ /* CC_MSG_SETLOCALDESC */ fsmdef_ev_setlocaldesc,
+ /* CC_MSG_SETREMOTEDESC */ fsmdef_ev_setremotedesc,
+ /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_setpeerconnection,
+ /* CC_MSG_ADDSTREAM */ fsmdef_ev_addstream,
+ /* CC_MSG_REMOVESTREAM */ fsmdef_ev_removestream,
+ /* CC_MSG_ADDCANDIDATE */ fsmdef_ev_addcandidate
+ },
+
+/* FSMDEF_S_CALL_SENT ------------------------------------------------------- */
+ {
+ /* CC_MSG_SETUP */ fsmdef_ev_default,
+ /* CC_MSG_SETUP_ACK */ fsmdef_ev_default,
+ /* CC_MSG_PROCEEDING */ fsmdef_ev_proceeding,
+ /* CC_MSG_ALERTING */ fsmdef_ev_out_alerting,
+ /* CC_MSG_CONNECTED */ fsmdef_ev_connected,
+ /* CC_MSG_CONNECTED_ACK */ fsmdef_ev_default,
+ /* CC_MSG_RELEASE */ fsmdef_ev_callsent_release,
+ /* CC_MSG_RELEASE_COMPLETE */ fsmdef_ev_default,
+ /* CC_MSG_FEATURE */ fsmdef_ev_callsent_feature,
+ /* CC_MSG_FEATURE_ACK */ fsmdef_ev_default_feature_ack,
+ /* CC_MSG_OFFHOOK */ fsmdef_ev_offhook,
+ /* CC_MSG_ONHOOK */ fsmdef_ev_onhook,
+ /* CC_MSG_LINE */ fsmdef_ev_default,
+ /* CC_MSG_DIGIT_BEGIN */ fsmdef_ev_default,
+ /* CC_MSG_DIGIT_END */ fsmdef_ev_default,
+ /* CC_MSG_DIALSTRING */ fsmdef_ev_default,
+ /* CC_MSG_MWI */ fsmdef_ev_default,
+ /* CC_MSG_SESSION_AUDIT */ fsmdef_ev_session_audit,
+ /* CC_MSG_CREATEOFFER */ fsmdef_ev_createoffer,
+ /* CC_MSG_CREATEANSWER */ fsmdef_ev_createanswer,
+ /* CC_MSG_SETLOCALDESC */ fsmdef_ev_setlocaldesc,
+ /* CC_MSG_SETREMOTEDESC */ fsmdef_ev_setremotedesc,
+ /* CC_MSG_LOCALDESC */ fsmdef_ev_localdesc,
+ /* CC_MSG_REMOTEDESC */ fsmdef_ev_remotedesc,
+ /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_setpeerconnection,
+ /* CC_MSG_ADDSTREAM */ fsmdef_ev_addstream,
+ /* CC_MSG_REMOVESTREAM */ fsmdef_ev_removestream,
+ /* CC_MSG_ADDCANDIDATE */ fsmdef_ev_addcandidate
+ },
+
+/* FSMDEF_S_OUTGOING_PROCEEDING --------------------------------------------- */
+ {
+ /* CC_MSG_SETUP */ fsmdef_ev_default,
+ /* CC_MSG_SETUP_ACK */ fsmdef_ev_default,
+ /* CC_MSG_PROCEEDING */ fsmdef_ev_default,
+ /* CC_MSG_ALERTING */ fsmdef_ev_out_alerting,
+ /* CC_MSG_CONNECTED */ fsmdef_ev_connected,
+ /* CC_MSG_CONNECTED_ACK */ fsmdef_ev_default,
+ /* CC_MSG_RELEASE */ fsmdef_ev_callsent_release,
+ /* CC_MSG_RELEASE_COMPLETE */ fsmdef_ev_default,
+ /* CC_MSG_FEATURE */ fsmdef_ev_callsent_feature,
+ /* CC_MSG_FEATURE_ACK */ fsmdef_ev_default_feature_ack,
+ /* CC_MSG_OFFHOOK */ fsmdef_ev_offhook,
+ /* CC_MSG_ONHOOK */ fsmdef_ev_onhook,
+ /* CC_MSG_LINE */ fsmdef_ev_default,
+ /* CC_MSG_DIGIT_BEGIN */ fsmdef_ev_default,
+ /* CC_MSG_DIGIT_END */ fsmdef_ev_default,
+ /* CC_MSG_DIALSTRING */ fsmdef_ev_default,
+ /* CC_MSG_MWI */ fsmdef_ev_default,
+ /* CC_MSG_SESSION_AUDIT */ fsmdef_ev_session_audit,
+ /* CC_MSG_CREATEOFFER */ fsmdef_ev_createoffer,
+ /* CC_MSG_CREATEANSWER */ fsmdef_ev_createanswer,
+ /* CC_MSG_SETLOCALDESC */ fsmdef_ev_setlocaldesc,
+ /* CC_MSG_SETREMOTEDESC */ fsmdef_ev_setremotedesc,
+ /* CC_MSG_LOCALDESC */ fsmdef_ev_localdesc,
+ /* CC_MSG_REMOTEDESC */ fsmdef_ev_remotedesc,
+ /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_setpeerconnection,
+ /* CC_MSG_ADDSTREAM */ fsmdef_ev_addstream,
+ /* CC_MSG_REMOVESTREAM */ fsmdef_ev_removestream,
+ /* CC_MSG_ADDCANDIDATE */ fsmdef_ev_addcandidate
+ },
+
+/* FSMDEF_S_KPML_COLLECT_INFO ----------------------------------------------- */
+ {
+ /* CC_MSG_SETUP */ fsmdef_ev_default,
+ /* CC_MSG_SETUP_ACK */ fsmdef_ev_default,
+ /* CC_MSG_PROCEEDING */ fsmdef_ev_default,
+ /* CC_MSG_ALERTING */ fsmdef_ev_out_alerting,
+ /* CC_MSG_CONNECTED */ fsmdef_ev_connected,
+ /* CC_MSG_CONNECTED_ACK */ fsmdef_ev_default,
+ /* CC_MSG_RELEASE */ fsmdef_ev_callsent_release,
+ /* CC_MSG_RELEASE_COMPLETE */ fsmdef_ev_default,
+ /* CC_MSG_FEATURE */ fsmdef_ev_collectinginfo_feature,
+ /* CC_MSG_FEATURE_ACK */ fsmdef_ev_default_feature_ack,
+ /* CC_MSG_OFFHOOK */ fsmdef_ev_default,
+ /* CC_MSG_ONHOOK */ fsmdef_ev_onhook,
+ /* CC_MSG_LINE */ fsmdef_ev_default,
+ /* CC_MSG_DIGIT_BEGIN */ fsmdef_ev_digit_begin,
+ /* CC_MSG_DIGIT_END */ fsmdef_ev_default,
+ /* CC_MSG_DIALSTRING */ fsmdef_ev_default,
+ /* CC_MSG_MWI */ fsmdef_ev_default,
+ /* CC_MSG_SESSION_AUDIT */ fsmdef_ev_session_audit,
+ /* CC_MSG_CREATEOFFER */ fsmdef_ev_createoffer,
+ /* CC_MSG_CREATEANSWER */ fsmdef_ev_createanswer,
+ /* CC_MSG_SETLOCALDESC */ fsmdef_ev_setlocaldesc,
+ /* CC_MSG_SETREMOTEDESC */ fsmdef_ev_setremotedesc,
+ /* CC_MSG_LOCALDESC */ fsmdef_ev_localdesc,
+ /* CC_MSG_REMOTEDESC */ fsmdef_ev_remotedesc,
+ /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_setpeerconnection,
+ /* CC_MSG_ADDSTREAM */ fsmdef_ev_addstream,
+ /* CC_MSG_REMOVESTREAM */ fsmdef_ev_removestream,
+ /* CC_MSG_ADDCANDIDATE */ fsmdef_ev_addcandidate
+ },
+
+/* FSMDEF_S_OUTGOING_ALERTING ----------------------------------------------- */
+ {
+ /* CC_MSG_SETUP */ fsmdef_ev_default,
+ /* CC_MSG_SETUP_ACK */ fsmdef_ev_default,
+ /* CC_MSG_PROCEEDING */ fsmdef_ev_default,
+ /* CC_MSG_ALERTING */ fsmdef_ev_out_alerting,
+ /* CC_MSG_CONNECTED */ fsmdef_ev_connected,
+ /* CC_MSG_CONNECTED_ACK */ fsmdef_ev_default,
+ /* CC_MSG_RELEASE */ fsmdef_ev_callsent_release,
+ /* CC_MSG_RELEASE_COMPLETE */ fsmdef_ev_default,
+ /* CC_MSG_FEATURE */ fsmdef_ev_callsent_feature,
+ /* CC_MSG_FEATURE_ACK */ fsmdef_ev_default_feature_ack,
+ /* CC_MSG_OFFHOOK */ fsmdef_ev_offhook,
+ /* CC_MSG_ONHOOK */ fsmdef_ev_onhook,
+ /* CC_MSG_LINE */ fsmdef_ev_default,
+ /* CC_MSG_DIGIT_BEGIN */ fsmdef_ev_default,
+ /* CC_MSG_DIGIT_END */ fsmdef_ev_default,
+ /* CC_MSG_DIALSTRING */ fsmdef_ev_default,
+ /* CC_MSG_MWI */ fsmdef_ev_default,
+ /* CC_MSG_SESSION_AUDIT */ fsmdef_ev_session_audit,
+ /* CC_MSG_CREATEOFFER */ fsmdef_ev_createoffer,
+ /* CC_MSG_CREATEANSWER */ fsmdef_ev_createanswer,
+ /* CC_MSG_SETLOCALDESC */ fsmdef_ev_setlocaldesc,
+ /* CC_MSG_SETREMOTEDESC */ fsmdef_ev_setremotedesc,
+ /* CC_MSG_LOCALDESC */ fsmdef_ev_localdesc,
+ /* CC_MSG_REMOTEDESC */ fsmdef_ev_remotedesc,
+ /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_setpeerconnection,
+ /* CC_MSG_ADDSTREAM */ fsmdef_ev_addstream,
+ /* CC_MSG_REMOVESTREAM */ fsmdef_ev_removestream,
+ /* CC_MSG_ADDCANDIDATE */ fsmdef_ev_addcandidate
+ },
+
+/* FSMDEF_S_INCOMING_ALERTING ----------------------------------------------- */
+ {
+ /* CC_MSG_SETUP */ fsmdef_ev_default,
+ /* CC_MSG_SETUP_ACK */ fsmdef_ev_default,
+ /* CC_MSG_PROCEEDING */ fsmdef_ev_default,
+ /* CC_MSG_ALERTING */ fsmdef_ev_default,
+ /* CC_MSG_CONNECTED */ fsmdef_ev_default,
+ /* CC_MSG_CONNECTED_ACK */ fsmdef_ev_default,
+ /* CC_MSG_RELEASE */ fsmdef_ev_release,
+ /* CC_MSG_RELEASE_COMPLETE */ fsmdef_ev_default,
+ /* CC_MSG_FEATURE */ fsmdef_ev_inalerting_feature,
+ /* CC_MSG_FEATURE_ACK */ fsmdef_ev_default_feature_ack,
+ /* CC_MSG_OFFHOOK */ fsmdef_ev_inalerting_offhook,
+ /* CC_MSG_ONHOOK */ fsmdef_ev_onhook,
+ /* CC_MSG_LINE */ fsmdef_ev_inalerting_offhook,
+ /* CC_MSG_DIGIT_BEGIN */ fsmdef_ev_default,
+ /* CC_MSG_DIGIT_END */ fsmdef_ev_default,
+ /* CC_MSG_DIALSTRING */ fsmdef_ev_default,
+ /* CC_MSG_MWI */ fsmdef_ev_default,
+ /* CC_MSG_SESSION_AUDIT */ fsmdef_ev_session_audit,
+ /* CC_MSG_CREATEOFFER */ fsmdef_ev_createoffer,
+ /* CC_MSG_CREATEANSWER */ fsmdef_ev_createanswer,
+ /* CC_MSG_SETLOCALDESC */ fsmdef_ev_setlocaldesc,
+ /* CC_MSG_SETREMOTEDESC */ fsmdef_ev_setremotedesc,
+ /* CC_MSG_LOCALDESC */ fsmdef_ev_localdesc,
+ /* CC_MSG_REMOTEDESC */ fsmdef_ev_remotedesc,
+ /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_setpeerconnection,
+ /* CC_MSG_ADDSTREAM */ fsmdef_ev_addstream,
+ /* CC_MSG_REMOVESTREAM */ fsmdef_ev_removestream,
+ /* CC_MSG_ADDCANDIDATE */ fsmdef_ev_addcandidate
+ },
+
+/* FSMDEF_S_CONNECTING ------------------------------------------------------ */
+ {
+ /* CC_MSG_SETUP */ fsmdef_ev_default,
+ /* CC_MSG_SETUP_ACK */ fsmdef_ev_default,
+ /* CC_MSG_PROCEEDING */ fsmdef_ev_default,
+ /* CC_MSG_ALERTING */ fsmdef_ev_default,
+ /* CC_MSG_CONNECTED */ fsmdef_ev_default,
+ /* CC_MSG_CONNECTED_ACK */ fsmdef_ev_connected_ack,
+ /* CC_MSG_RELEASE */ fsmdef_ev_release,
+ /* CC_MSG_RELEASE_COMPLETE */ fsmdef_ev_default,
+ /* CC_MSG_FEATURE */ fsmdef_ev_connecting_feature,
+ /* CC_MSG_FEATURE_ACK */ fsmdef_ev_default_feature_ack,
+ /* CC_MSG_OFFHOOK */ fsmdef_ev_offhook,
+ /* CC_MSG_ONHOOK */ fsmdef_ev_onhook,
+ /* CC_MSG_LINE */ fsmdef_ev_connected_line,
+ /* CC_MSG_DIGIT_BEGIN */ fsmdef_ev_default,
+ /* CC_MSG_DIGIT_END */ fsmdef_ev_default,
+ /* CC_MSG_DIALSTRING */ fsmdef_ev_default,
+ /* CC_MSG_MWI */ fsmdef_ev_default,
+ /* CC_MSG_SESSION_AUDIT */ fsmdef_ev_session_audit,
+ /* CC_MSG_CREATEOFFER */ fsmdef_ev_createoffer,
+ /* CC_MSG_CREATEANSWER */ fsmdef_ev_createanswer,
+ /* CC_MSG_SETLOCALDESC */ fsmdef_ev_setlocaldesc,
+ /* CC_MSG_SETREMOTEDESC */ fsmdef_ev_setremotedesc,
+ /* CC_MSG_LOCALDESC */ fsmdef_ev_localdesc,
+ /* CC_MSG_REMOTEDESC */ fsmdef_ev_remotedesc,
+ /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_setpeerconnection,
+ /* CC_MSG_ADDSTREAM */ fsmdef_ev_addstream,
+ /* CC_MSG_REMOVESTREAM */ fsmdef_ev_removestream,
+ /* CC_MSG_ADDCANDIDATE */ fsmdef_ev_addcandidate
+ },
+
+/* FSMDEF_S_JOINING --------------------------------------------------------- */
+ {
+ /* CC_MSG_SETUP */ fsmdef_ev_default,
+ /* CC_MSG_SETUP_ACK */ fsmdef_ev_default,
+ /* CC_MSG_PROCEEDING */ fsmdef_ev_default,
+ /* CC_MSG_ALERTING */ fsmdef_ev_default,
+ /* CC_MSG_CONNECTED */ fsmdef_ev_default,
+ /* CC_MSG_CONNECTED_ACK */ fsmdef_ev_joining_connected_ack,
+ /* CC_MSG_RELEASE */ fsmdef_ev_release,
+ /* CC_MSG_RELEASE_COMPLETE */ fsmdef_ev_default,
+ /* CC_MSG_FEATURE */ fsmdef_ev_connecting_feature,
+ /* CC_MSG_FEATURE_ACK */ fsmdef_ev_default_feature_ack,
+ /* CC_MSG_OFFHOOK */ fsmdef_ev_joining_offhook,
+ /* CC_MSG_ONHOOK */ fsmdef_ev_onhook,
+ /* CC_MSG_LINE */ fsmdef_ev_connected_line,
+ /* CC_MSG_DIGIT_BEGIN */ fsmdef_ev_default,
+ /* CC_MSG_DIGIT_END */ fsmdef_ev_default,
+ /* CC_MSG_DIALSTRING */ fsmdef_ev_default,
+ /* CC_MSG_MWI */ fsmdef_ev_default,
+ /* CC_MSG_SESSION_AUDIT */ fsmdef_ev_session_audit,
+ /* CC_MSG_CREATEOFFER */ fsmdef_ev_createoffer,
+ /* CC_MSG_CREATEANSWER */ fsmdef_ev_createanswer,
+ /* CC_MSG_SETLOCALDESC */ fsmdef_ev_setlocaldesc,
+ /* CC_MSG_SETREMOTEDESC */ fsmdef_ev_setremotedesc,
+ /* CC_MSG_LOCALDESC */ fsmdef_ev_localdesc,
+ /* CC_MSG_REMOTEDESC */ fsmdef_ev_remotedesc,
+ /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_setpeerconnection,
+ /* CC_MSG_ADDSTREAM */ fsmdef_ev_addstream,
+ /* CC_MSG_REMOVESTREAM */ fsmdef_ev_removestream,
+ /* CC_MSG_ADDCANDIDATE */ fsmdef_ev_addcandidate
+ },
+
+/* FSMDEF_S_CONNECTED ------------------------------------------------------- */
+ {
+ /* CC_MSG_SETUP */ fsmdef_ev_default,
+ /* CC_MSG_SETUP_ACK */ fsmdef_ev_default,
+ /* CC_MSG_PROCEEDING */ fsmdef_ev_default,
+ /* CC_MSG_ALERTING */ fsmdef_ev_default,
+ /* CC_MSG_CONNECTED */ fsmdef_ev_default,
+ /* CC_MSG_CONNECTED_ACK */ fsmdef_ev_default,
+ /* CC_MSG_RELEASE */ fsmdef_ev_release,
+ /* CC_MSG_RELEASE_COMPLETE */ fsmdef_ev_default,
+ /* CC_MSG_FEATURE */ fsmdef_ev_connected_feature,
+ /* CC_MSG_FEATURE_ACK */ fsmdef_ev_default_feature_ack,
+ /* CC_MSG_OFFHOOK */ fsmdef_ev_offhook,
+ /* CC_MSG_ONHOOK */ fsmdef_ev_onhook,
+ /* CC_MSG_LINE */ fsmdef_ev_connected_line,
+ /* CC_MSG_DIGIT_BEGIN */ fsmdef_ev_default,
+ /* CC_MSG_DIGIT_END */ fsmdef_ev_default,
+ /* CC_MSG_DIALSTRING */ fsmdef_ev_default,
+ /* CC_MSG_MWI */ fsmdef_ev_default,
+ /* CC_MSG_SESSION_AUDIT */ fsmdef_ev_session_audit,
+ /* CC_MSG_CREATEOFFER */ fsmdef_ev_createoffer,
+ /* CC_MSG_CREATEANSWER */ fsmdef_ev_createanswer,
+ /* CC_MSG_SETLOCALDESC */ fsmdef_ev_setlocaldesc,
+ /* CC_MSG_SETREMOTEDESC */ fsmdef_ev_setremotedesc,
+ /* CC_MSG_LOCALDESC */ fsmdef_ev_localdesc,
+ /* CC_MSG_REMOTEDESC */ fsmdef_ev_remotedesc,
+ /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_setpeerconnection,
+ /* CC_MSG_ADDSTREAM */ fsmdef_ev_addstream,
+ /* CC_MSG_REMOVESTREAM */ fsmdef_ev_removestream,
+ /* CC_MSG_ADDCANDIDATE */ fsmdef_ev_addcandidate
+ },
+
+/* FSMDEF_S_CONNECTED_MEDIA_PEND ------------------------------------------- */
+ {
+ /* CC_MSG_SETUP */ fsmdef_ev_default,
+ /* CC_MSG_SETUP_ACK */ fsmdef_ev_default,
+ /* CC_MSG_PROCEEDING */ fsmdef_ev_default,
+ /* CC_MSG_ALERTING */ fsmdef_ev_default,
+ /* CC_MSG_CONNECTED */ fsmdef_ev_default,
+ /* CC_MSG_CONNECTED_ACK */ fsmdef_ev_default,
+ /* CC_MSG_RELEASE */ fsmdef_ev_release,
+ /* CC_MSG_RELEASE_COMPLETE */ fsmdef_ev_default,
+ /* CC_MSG_FEATURE */ fsmdef_ev_connected_media_pend_feature,
+ /* CC_MSG_FEATURE_ACK */ fsmdef_ev_connected_media_pend_feature_ack,
+ /* CC_MSG_OFFHOOK */ fsmdef_ev_offhook,
+ /* CC_MSG_ONHOOK */ fsmdef_ev_onhook,
+ /* CC_MSG_LINE */ fsmdef_ev_connected_line,
+ /* CC_MSG_DIGIT_BEGIN */ fsmdef_ev_default,
+ /* CC_MSG_DIGIT_END */ fsmdef_ev_default,
+ /* CC_MSG_DIALSTRING */ fsmdef_ev_default,
+ /* CC_MSG_MWI */ fsmdef_ev_default,
+ /* CC_MSG_SESSION_AUDIT */ fsmdef_ev_session_audit,
+ /* CC_MSG_CREATEOFFER */ fsmdef_ev_createoffer,
+ /* CC_MSG_CREATEANSWER */ fsmdef_ev_createanswer,
+ /* CC_MSG_SETLOCALDESC */ fsmdef_ev_setlocaldesc,
+ /* CC_MSG_SETREMOTEDESC */ fsmdef_ev_setremotedesc,
+ /* CC_MSG_LOCALDESC */ fsmdef_ev_localdesc,
+ /* CC_MSG_REMOTEDESC */ fsmdef_ev_remotedesc,
+ /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_setpeerconnection,
+ /* CC_MSG_ADDSTREAM */ fsmdef_ev_addstream,
+ /* CC_MSG_REMOVESTREAM */ fsmdef_ev_removestream,
+ /* CC_MSG_ADDCANDIDATE */ fsmdef_ev_addcandidate
+ },
+
+/* FSMDEF_S_RELEASING ------------------------------------------------------- */
+ {
+ /* CC_MSG_SETUP */ fsmdef_ev_default,
+ /* CC_MSG_SETUP_ACK */ fsmdef_ev_default,
+ /* CC_MSG_PROCEEDING */ fsmdef_ev_default,
+ /* CC_MSG_ALERTING */ fsmdef_ev_default,
+ /* CC_MSG_CONNECTED */ fsmdef_ev_default,
+ /* CC_MSG_CONNECTED_ACK */ fsmdef_ev_default,
+ /* CC_MSG_RELEASE */ fsmdef_ev_releasing_release,
+ /* CC_MSG_RELEASE_COMPLETE */ fsmdef_ev_release_complete,
+ /* CC_MSG_FEATURE */ fsmdef_ev_releasing_feature,
+ /* CC_MSG_FEATURE_ACK */ fsmdef_ev_default_feature_ack,
+ /* CC_MSG_OFFHOOK */ fsmdef_ev_default,
+ /* CC_MSG_ONHOOK */ fsmdef_ev_releasing_onhook,
+ /* CC_MSG_LINE */ fsmdef_ev_connected_line,
+ /* CC_MSG_DIGIT_BEGIN */ fsmdef_ev_default,
+ /* CC_MSG_DIGIT_END */ fsmdef_ev_default,
+ /* CC_MSG_DIALSTRING */ fsmdef_ev_default,
+ /* CC_MSG_MWI */ fsmdef_ev_default,
+ /* CC_MSG_SESSION_AUDIT */ fsmdef_ev_session_audit,
+ /* CC_MSG_CREATEOFFER */ fsmdef_ev_createoffer,
+ /* CC_MSG_CREATEANSWER */ fsmdef_ev_createanswer,
+ /* CC_MSG_SETLOCALDESC */ fsmdef_ev_setlocaldesc,
+ /* CC_MSG_SETREMOTEDESC */ fsmdef_ev_setremotedesc,
+ /* CC_MSG_LOCALDESC */ fsmdef_ev_localdesc,
+ /* CC_MSG_REMOTEDESC */ fsmdef_ev_remotedesc,
+ /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_setpeerconnection,
+ /* CC_MSG_ADDSTREAM */ fsmdef_ev_addstream,
+ /* CC_MSG_REMOVESTREAM */ fsmdef_ev_removestream,
+ /* CC_MSG_ADDCANDIDATE */ fsmdef_ev_addcandidate
+ },
+
+/* FSMDEF_S_HOLD_PENDING ---------------------------------------------------- */
+ {
+ /* CC_MSG_SETUP */ fsmdef_ev_default,
+ /* CC_MSG_SETUP_ACK */ fsmdef_ev_default,
+ /* CC_MSG_PROCEEDING */ fsmdef_ev_default,
+ /* CC_MSG_ALERTING */ fsmdef_ev_default,
+ /* CC_MSG_CONNECTED */ fsmdef_ev_default,
+ /* CC_MSG_CONNECTED_ACK */ fsmdef_ev_default,
+ /* CC_MSG_RELEASE */ fsmdef_ev_holding_release,
+ /* CC_MSG_RELEASE_COMPLETE */ fsmdef_ev_default,
+ /* CC_MSG_FEATURE */ fsmdef_ev_hold_pending_feature,
+ /* CC_MSG_FEATURE_ACK */ fsmdef_ev_hold_pending_feature_ack,
+ /* CC_MSG_OFFHOOK */ fsmdef_ev_default,
+ /* CC_MSG_ONHOOK */ fsmdef_ev_onhook,
+ /* CC_MSG_LINE */ fsmdef_ev_default,
+ /* CC_MSG_DIGIT_BEGIN */ fsmdef_ev_default,
+ /* CC_MSG_DIGIT_END */ fsmdef_ev_default,
+ /* CC_MSG_DIALSTRING */ fsmdef_ev_default,
+ /* CC_MSG_MWI */ fsmdef_ev_default,
+ /* CC_MSG_SESSION_AUDIT */ fsmdef_ev_session_audit,
+ /* CC_MSG_CREATEOFFER */ fsmdef_ev_createoffer,
+ /* CC_MSG_CREATEANSWER */ fsmdef_ev_createanswer,
+ /* CC_MSG_SETLOCALDESC */ fsmdef_ev_setlocaldesc,
+ /* CC_MSG_SETREMOTEDESC */ fsmdef_ev_setremotedesc,
+ /* CC_MSG_LOCALDESC */ fsmdef_ev_localdesc,
+ /* CC_MSG_REMOTEDESC */ fsmdef_ev_remotedesc,
+ /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_setpeerconnection,
+ /* CC_MSG_ADDSTREAM */ fsmdef_ev_addstream,
+ /* CC_MSG_REMOVESTREAM */ fsmdef_ev_removestream,
+ /* CC_MSG_ADDCANDIDATE */ fsmdef_ev_addcandidate
+ },
+
+/* FSMDEF_S_HOLDING --------------------------------------------------------- */
+ {
+ /* CC_MSG_SETUP */ fsmdef_ev_default,
+ /* CC_MSG_SETUP_ACK */ fsmdef_ev_default,
+ /* CC_MSG_PROCEEDING */ fsmdef_ev_default,
+ /* CC_MSG_ALERTING */ fsmdef_ev_default,
+ /* CC_MSG_CONNECTED */ fsmdef_ev_default,
+ /* CC_MSG_CONNECTED_ACK */ fsmdef_ev_default,
+ /* CC_MSG_RELEASE */ fsmdef_ev_holding_release,
+ /* CC_MSG_RELEASE_COMPLETE */ fsmdef_ev_default,
+ /* CC_MSG_FEATURE */ fsmdef_ev_holding_feature,
+ /* CC_MSG_FEATURE_ACK */ fsmdef_ev_holding_feature_ack,
+ /* CC_MSG_OFFHOOK */ fsmdef_ev_holding_offhook,
+ /* CC_MSG_ONHOOK */ fsmdef_ev_holding_onhook,
+ /* CC_MSG_LINE */ fsmdef_ev_default,
+ /* CC_MSG_DIGIT_BEGIN */ fsmdef_ev_default,
+ /* CC_MSG_DIGIT_END */ fsmdef_ev_default,
+ /* CC_MSG_DIALSTRING */ fsmdef_ev_default,
+ /* CC_MSG_MWI */ fsmdef_ev_default,
+ /* CC_MSG_SESSION_AUDIT */ fsmdef_ev_session_audit,
+ /* CC_MSG_CREATEOFFER */ fsmdef_ev_createoffer,
+ /* CC_MSG_CREATEANSWER */ fsmdef_ev_createanswer,
+ /* CC_MSG_SETLOCALDESC */ fsmdef_ev_setlocaldesc,
+ /* CC_MSG_SETREMOTEDESC */ fsmdef_ev_setremotedesc,
+ /* CC_MSG_LOCALDESC */ fsmdef_ev_localdesc,
+ /* CC_MSG_REMOTEDESC */ fsmdef_ev_remotedesc,
+ /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_setpeerconnection,
+ /* CC_MSG_ADDSTREAM */ fsmdef_ev_addstream,
+ /* CC_MSG_REMOVESTREAM */ fsmdef_ev_removestream,
+ /* CC_MSG_ADDCANDIDATE */ fsmdef_ev_addcandidate
+ },
+
+/* FSMDEF_S_RESUME_PENDING -------------------------------------------------- */
+ {
+ /* CC_MSG_SETUP */ fsmdef_ev_default,
+ /* CC_MSG_SETUP_ACK */ fsmdef_ev_default,
+ /* CC_MSG_PROCEEDING */ fsmdef_ev_default,
+ /* CC_MSG_ALERTING */ fsmdef_ev_default,
+ /* CC_MSG_CONNECTED */ fsmdef_ev_default,
+ /* CC_MSG_CONNECTED_ACK */ fsmdef_ev_default,
+ /* CC_MSG_RELEASE */ fsmdef_ev_release,
+ /* CC_MSG_RELEASE_COMPLETE */ fsmdef_ev_default,
+ /* CC_MSG_FEATURE */ fsmdef_ev_resume_pending_feature,
+ /* CC_MSG_FEATURE_ACK */ fsmdef_ev_resume_pending_feature_ack,
+ /* CC_MSG_OFFHOOK */ fsmdef_ev_default,
+ /* CC_MSG_ONHOOK */ fsmdef_ev_onhook,
+ /* CC_MSG_LINE */ fsmdef_ev_default,
+ /* CC_MSG_DIGIT_BEGIN */ fsmdef_ev_default,
+ /* CC_MSG_DIGIT_END */ fsmdef_ev_default,
+ /* CC_MSG_DIALSTRING */ fsmdef_ev_default,
+ /* CC_MSG_MWI */ fsmdef_ev_default,
+ /* CC_MSG_SESSION_AUDIT */ fsmdef_ev_session_audit,
+ /* CC_MSG_CREATEOFFER */ fsmdef_ev_createoffer,
+ /* CC_MSG_CREATEANSWER */ fsmdef_ev_createanswer,
+ /* CC_MSG_SETLOCALDESC */ fsmdef_ev_setlocaldesc,
+ /* CC_MSG_SETREMOTEDESC */ fsmdef_ev_setremotedesc,
+ /* CC_MSG_LOCALDESC */ fsmdef_ev_localdesc,
+ /* CC_MSG_REMOTEDESC */ fsmdef_ev_remotedesc,
+ /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_setpeerconnection,
+ /* CC_MSG_ADDSTREAM */ fsmdef_ev_addstream,
+ /* CC_MSG_REMOVESTREAM */ fsmdef_ev_removestream,
+ /* CC_MSG_ADDCANDIDATE */ fsmdef_ev_addcandidate
+ },
+
+/* FSMDEF_S_PRESERVED ------------------------------------------------------ */
+ {
+ /* CC_MSG_SETUP */ fsmdef_ev_default,
+ /* CC_MSG_SETUP_ACK */ fsmdef_ev_default,
+ /* CC_MSG_PROCEEDING */ fsmdef_ev_default,
+ /* CC_MSG_ALERTING */ fsmdef_ev_default,
+ /* CC_MSG_CONNECTED */ fsmdef_ev_default,
+ /* CC_MSG_CONNECTED_ACK */ fsmdef_ev_default,
+ /* CC_MSG_RELEASE */ fsmdef_ev_release,
+ /* CC_MSG_RELEASE_COMPLETE */ fsmdef_ev_default,
+ /* CC_MSG_FEATURE */ fsmdef_ev_preserved_feature,
+ /* CC_MSG_FEATURE_ACK */ fsmdef_ev_default,
+ /* CC_MSG_OFFHOOK */ fsmdef_ev_default,
+ /* CC_MSG_ONHOOK */ fsmdef_ev_onhook,
+ /* CC_MSG_LINE */ fsmdef_ev_default,
+ /* CC_MSG_DIGIT_BEGIN */ fsmdef_ev_default,
+ /* CC_MSG_DIGIT_END */ fsmdef_ev_default,
+ /* CC_MSG_DIALSTRING */ fsmdef_ev_default,
+ /* CC_MSG_MWI */ fsmdef_ev_default,
+ /* CC_MSG_SESSION_AUDIT */ fsmdef_ev_session_audit,
+ /* CC_MSG_CREATEOFFER */ fsmdef_ev_createoffer,
+ /* CC_MSG_CREATEANSWER */ fsmdef_ev_createanswer,
+ /* CC_MSG_SETLOCALDESC */ fsmdef_ev_setlocaldesc,
+ /* CC_MSG_SETREMOTEDESC */ fsmdef_ev_setremotedesc,
+ /* CC_MSG_LOCALDESC */ fsmdef_ev_localdesc,
+ /* CC_MSG_REMOTEDESC */ fsmdef_ev_remotedesc,
+ /* CC_MSG_SETPEERCONNECTION */fsmdef_ev_setpeerconnection,
+ /* CC_MSG_ADDSTREAM */ fsmdef_ev_addstream,
+ /* CC_MSG_REMOVESTREAM */ fsmdef_ev_removestream,
+ /* CC_MSG_ADDCANDIDATE */ fsmdef_ev_addcandidate
+ }
+};
+
+static sm_table_t fsmdef_sm_table;
+sm_table_t *pfsmdef_sm_table = &fsmdef_sm_table;
+
+/*--------------------------------------------------------------------------
+ * Global data
+ *--------------------------------------------------------------------------
+ */
+uint16_t g_numofselected_calls = 0;
+boolean g_b2bjoin_pending = FALSE;
+callid_t g_b2bjoin_callid = CC_NO_CALL_ID;
+
+static sdp_direction_e s_default_video_dir = SDP_DIRECTION_SENDRECV;
+static sdp_direction_e s_session_video_dir = SDP_MAX_QOS_DIRECTIONS;
+
+
+void set_default_video_pref(int pref) {
+ s_default_video_dir = pref;
+}
+
+void set_next_sess_video_pref(int pref) {
+ s_session_video_dir = pref;
+}
+
+const char *
+fsmdef_state_name (int state)
+{
+ if ((state <= FSMDEF_S_MIN) || (state >= FSMDEF_S_MAX)) {
+ return (get_debug_string(GSM_UNDEFINED));
+ }
+
+ return (fsmdef_state_names[state]);
+}
+
+/*
+ * fsmdef_get_dcb_by_call_id
+ *
+ * return the dcb referenced by the given call_id
+ */
+fsmdef_dcb_t *
+fsmdef_get_dcb_by_call_id (callid_t call_id)
+{
+ static const char fname[] = "fsmdef_get_dcb_by_call_id";
+ fsmdef_dcb_t *dcb;
+ fsmdef_dcb_t *dcb_found = NULL;
+
+ FSM_FOR_ALL_CBS(dcb, fsmdef_dcbs, FSMDEF_MAX_DCBS) {
+ if (dcb->call_id == call_id) {
+ dcb_found = dcb;
+ break;
+ }
+ }
+
+ if (dcb_found) {
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG_PTR),
+ dcb->call_id, dcb->line, fname, dcb_found);
+ }
+
+ return (dcb_found);
+}
+
+
+/*
+ * fsmdef_check_if_chaperone_call_exist
+ *
+ * return the dcb referenced by the given call_id
+ */
+boolean
+fsmdef_check_if_chaperone_call_exist (void)
+{
+ static const char fname[] = "fsmdef_check_if_chaperone_call_exist";
+ fsmdef_dcb_t *dcb;
+ boolean result = FALSE;
+
+ FSM_FOR_ALL_CBS(dcb, fsmdef_dcbs, FSMDEF_MAX_DCBS) {
+ if(dcb->policy == CC_POLICY_CHAPERONE){
+ result = TRUE;
+ break;
+ }
+ }
+
+ if (result) {
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG_PTR),
+ dcb->call_id, dcb->line, fname, dcb);
+ }
+
+ return result;
+}
+
+
+void fsmdef_get_rtp_stat (fsmdef_dcb_t *dcb , cc_kfact_t *kfactor)
+{
+ static const char fname[] ="fsmdef_get_rtp_stat";
+
+ int call_stats_flag;
+ fsmdef_media_t *media;
+ media = gsmsdp_find_audio_media(dcb);
+
+ if (!media) {
+ GSM_ERR_MSG(GSM_F_PREFIX"dcb media pointer invalid\n", fname);
+ return;
+ }
+
+ memset(kfactor, 0, sizeof(cc_kfact_t));
+ config_get_value(CFGID_CALL_STATS, &call_stats_flag, sizeof(call_stats_flag));
+
+ if (call_stats_flag) {
+ vcmGetRtpStats(media->cap_index, dcb->group_id,
+ media->refid,
+ lsm_get_ms_ui_call_handle(dcb->line, dcb->call_id, CC_NO_CALL_ID), &(kfactor->rxstats[0]), &(kfactor->txstats[0]));
+ }
+}
+
+/**
+ * The function sets or clears the local hold status to the given media or
+ * for all of the media.
+ *
+ * @param[in]dcb - pointer to fsmdef_dcb_t.
+ * @param[in]media - specify which media to use. The value of
+ * NULL indicates for all media.
+ * @param[in]set - set local hold or clear local hold.
+ *
+ * @return none
+ *
+ * @pre (dcb not_eq NULL)
+ */
+static void
+fsmdef_update_media_hold_status (fsmdef_dcb_t *dcb, fsmdef_media_t *media,
+ boolean set)
+{
+ fsmdef_media_t *start_media, *end_media;
+
+ if (media == NULL) {
+ /* NULL value of the given media indicates for all media */
+ start_media = GSMSDP_FIRST_MEDIA_ENTRY(dcb);
+ end_media = NULL; /* NULL means till the end of the list */
+ } else {
+ /* given media, uses the provided media */
+ start_media = media;
+ end_media = media;
+ }
+
+ GSMSDP_FOR_MEDIA_LIST(media, start_media, end_media, dcb) {
+ if (GSMSDP_MEDIA_ENABLED(media)) {
+ if (set) {
+ FSM_SET_FLAGS(media->hold, FSM_HOLD_LCL);
+ } else {
+ FSM_RESET_FLAGS(media->hold, FSM_HOLD_LCL);
+ }
+ }
+ }
+}
+
+/**
+ * The function checks to see whether all media streams are
+ * in locally held or not.
+ *
+ * @param[in]dcb - pointer to fsmdef_dcb_t.
+ *
+ * @return TRUE - all media streams are in local hold.
+ * FALSE - not all media streams are in local hold.
+ *
+ * @pre (dcb not_eq NULL)
+ */
+static boolean
+fsmdef_all_media_are_local_hold (fsmdef_dcb_t *dcb)
+{
+ fsmdef_media_t *media;
+ /*
+ * Check the local hold status of each media to see if the
+ * media is already locally held or not.
+ */
+ GSMSDP_FOR_ALL_MEDIA(media, dcb) {
+ if (!GSMSDP_MEDIA_ENABLED(media)) {
+ continue;
+ }
+ if (!FSM_CHK_FLAGS(media->hold, FSM_HOLD_LCL)) {
+ /* found one media that is not on hold */
+ return (FALSE);
+ }
+ }
+ /* all media streams are local held */
+ return (TRUE);
+}
+
+/**
+ * The function gets the numbmer of media in local hold.
+ *
+ * @param[in]dcb - pointer to fsmdef_dcb_t.
+ *
+ * @return uint16_t for the number of media in local hold.
+ *
+ * @pre (dcb not_eq NULL)
+ */
+static unsigned int
+fsmdef_num_media_in_local_hold (fsmdef_dcb_t *dcb)
+{
+ fsmdef_media_t *media;
+ unsigned int num_local_hold = 0;
+
+ /* Check the local hold status of the media(s) */
+ GSMSDP_FOR_ALL_MEDIA(media, dcb) {
+ if (!GSMSDP_MEDIA_ENABLED(media)) {
+ continue;
+ }
+ if (FSM_CHK_FLAGS(media->hold, FSM_HOLD_LCL)) {
+ num_local_hold++;
+ }
+ }
+ return (num_local_hold);
+}
+
+/**
+ * The function is a convenient function to set each local hold in
+ * SDP for each media if it is marked as locally held.
+ *
+ * @param[in]dcb - pointer to fsmdef_dcb_t.
+ *
+ * @return None
+ *
+ * @pre (dcb not_eq NULL)
+ */
+static void
+fsmdef_set_per_media_local_hold_sdp (fsmdef_dcb_t *dcb)
+{
+ fsmdef_media_t *media;
+
+ GSMSDP_FOR_ALL_MEDIA(media, dcb) {
+ if (!GSMSDP_MEDIA_ENABLED(media)) {
+ continue;
+ }
+ if (FSM_CHK_FLAGS(media->hold, FSM_HOLD_LCL)) {
+ /* set local hold to this media entry */
+ gsmsdp_set_local_hold_sdp(dcb, media);
+ }
+ }
+}
+
+void
+fsmdef_init_dcb (fsmdef_dcb_t *dcb, callid_t call_id,
+ fsmdef_call_types_t call_type,
+ string_t called_number, line_t line, fsm_fcb_t *fcb)
+{
+ string_t calling_name;
+ int blocking;
+ char name[MAX_LINE_NAME_SIZE];
+
+ dcb->call_id = call_id;
+ dcb->line = line;
+
+ dcb->spoof_ringout_requested = FALSE;
+ dcb->spoof_ringout_applied = FALSE;
+
+ dcb->log_disp = CC_CALL_LOG_DISP_UNKNWN;
+
+ fsmutil_init_groupid(dcb, call_id, call_type);
+
+ /*
+ * Fill in as much of the caller_id data as possible.
+ * Different data is available based on the call_type.
+ */
+ switch (call_type) {
+ case FSMDEF_CALL_TYPE_OUTGOING:
+ config_get_value(CFGID_CALLERID_BLOCKING, &blocking, sizeof(blocking));
+ if (line != 0) {
+ sip_config_get_display_name(line, name, sizeof(name));
+ }
+ if (blocking & 1 || line == 0) {
+ calling_name = SIP_HEADER_ANONYMOUS_STR;
+ } else {
+ calling_name = name;
+ }
+ dcb->caller_id.calling_name = strlib_update(dcb->caller_id.calling_name,
+ calling_name);
+ dcb->caller_id.calling_number =
+ strlib_update(dcb->caller_id.calling_number, name);
+
+ /*
+ * called_xxx data will be set when the fsmdef receives the dialstring.
+ */
+ dcb->caller_id.called_name = strlib_empty();
+ dcb->caller_id.called_number = strlib_empty();
+ dcb->caller_id.orig_rpid_number = strlib_empty();
+
+ dcb->inbound = FALSE;
+
+ break;
+
+ case FSMDEF_CALL_TYPE_INCOMING:
+ case FSMDEF_CALL_TYPE_FORWARD:
+ /*
+ * calling_xxx data will be set when the fsmdef receives the setup.
+ */
+ dcb->caller_id.calling_name = strlib_empty();
+ dcb->caller_id.calling_number = strlib_empty();
+
+ dcb->caller_id.last_redirect_name = strlib_empty();
+ dcb->caller_id.last_redirect_number = strlib_empty();
+ dcb->caller_id.orig_called_name = strlib_empty();
+ dcb->caller_id.orig_called_number = strlib_empty();
+ dcb->caller_id.orig_rpid_number = strlib_empty();
+
+ sip_config_get_display_name(line, name, sizeof(name));
+ dcb->caller_id.called_name =
+ strlib_update(dcb->caller_id.called_name, name);
+ dcb->caller_id.called_number =
+ strlib_update(dcb->caller_id.called_number, called_number);
+
+ dcb->inbound = TRUE;
+
+ break;
+
+ case FSMDEF_CALL_TYPE_NONE:
+ dcb->caller_id.calling_name = strlib_empty();
+ dcb->caller_id.calling_number = strlib_empty();
+ dcb->caller_id.called_name = strlib_empty();
+ dcb->caller_id.called_number = strlib_empty();
+ dcb->caller_id.alt_calling_number = strlib_empty();
+ dcb->caller_id.last_redirect_name = strlib_empty();
+ dcb->caller_id.last_redirect_number = strlib_empty();
+ dcb->caller_id.orig_called_name = strlib_empty();
+ dcb->caller_id.orig_called_number = strlib_empty();
+ dcb->caller_id.orig_rpid_number = strlib_empty();
+ dcb->inbound = FALSE;
+
+ break;
+ default:
+ break;
+ } /* switch (call_type) { */
+
+ dcb->caller_id.display_calling_number = TRUE;
+ dcb->caller_id.display_called_number = TRUE;
+
+ /* Initially, assume ui update is required for a new call. */
+ dcb->ui_update_required = TRUE;
+ dcb->placed_call_update_required = TRUE;
+
+ dcb->is_conf_call = FALSE; /*Initially, set to conf call false*/
+
+ dcb->digit_cnt = 0;
+
+ dcb->call_type = call_type;
+ dcb->orientation = CC_ORIENTATION_NONE;
+
+ dcb->caller_id.call_instance_id = 0;
+
+ dcb->msgs_sent = FSMDEF_MSG_NONE;
+ dcb->msgs_rcvd = FSMDEF_MSG_NONE;
+
+ dcb->send_release = FALSE;
+
+ dcb->inband = FALSE;
+ dcb->inband_received = FALSE;
+ dcb->outofband = 0;
+
+ dcb->remote_sdp_present = FALSE;
+ dcb->remote_sdp_in_ack = FALSE;
+
+ dcb->sdp = NULL;
+ dcb->src_sdp_version = 0;
+
+ dcb->dial_mode = DIAL_MODE_NUMERIC;
+
+ dcb->hold_reason = CC_REASON_NONE;
+
+ dcb->pd_updated = FALSE;
+
+ dcb->alerting_tone = VCM_NO_TONE;
+ dcb->tone_direction = VCM_PLAY_TONE_TO_EAR;
+
+ dcb->alert_info = ALERTING_NONE;
+
+ dcb->dialplan_tone = FALSE;
+
+ dcb->active_tone = VCM_NO_TONE;
+
+ dcb->monrec_tone_action = FSMDEF_MRTONE_NO_ACTION;
+ dcb->monitor_tone_direction = VCM_PLAY_TONE_TO_EAR;
+ dcb->recorder_tone_direction = VCM_PLAY_TONE_TO_EAR;
+
+ dcb->play_tone_action = FSMDEF_PLAYTONE_NO_ACTION;
+
+ dcb->fcb = fcb;
+
+ dcb->early_error_release = FALSE;
+
+ dcb->active_feature = CC_FEATURE_NONE;
+
+ /* Release transient timers if any have been allocated */
+ if (dcb->err_onhook_tmr) {
+ (void) cprDestroyTimer(dcb->err_onhook_tmr);
+ dcb->err_onhook_tmr = NULL;
+ }
+ if (dcb->req_pending_tmr) {
+ (void) cprDestroyTimer(dcb->req_pending_tmr);
+ dcb->req_pending_tmr = NULL;
+ }
+
+ FSM_SET_SECURITY_STATUS(dcb, CC_SECURITY_UNKNOWN);
+ FSM_SET_POLICY(dcb, CC_POLICY_UNKNOWN);
+ dcb->session = PRIMARY;
+
+ dcb->dsp_out_of_resources = FALSE;
+
+ if (dcb->selected) {
+ g_numofselected_calls--;
+ }
+
+ dcb->selected = FALSE;
+
+ dcb->select_pending = FALSE;
+ dcb->call_not_counted_in_mnc_bt = FALSE;
+ if (g_disable_mass_reg_debug_print == FALSE) {
+ FSM_DEBUG_SM(DEB_L_C_F_PREFIX"call_not_counted_in_mnc_bt = FALSE\n",
+ DEB_L_C_F_PREFIX_ARGS(FSM, line, call_id, "fsmdef_init_dcb"));
+ }
+
+ /* clear all bit flags */
+ dcb->flags = 0;
+ dcb->onhook_received = FALSE;
+
+ dcb->cur_video_avail = SDP_DIRECTION_INACTIVE;
+
+ if ( s_session_video_dir != SDP_MAX_QOS_DIRECTIONS &&
+ call_type == FSMDEF_CALL_TYPE_OUTGOING ) {
+ dcb->video_pref = s_session_video_dir;
+ s_session_video_dir = SDP_MAX_QOS_DIRECTIONS;
+ } else {
+ dcb->video_pref = s_default_video_dir;
+ }
+
+ gsmsdp_init_media_list(dcb);
+
+ dcb->join_call_id = CC_NO_CALL_ID;
+ dcb->callref = 0;
+
+ dcb->ice_ufrag = NULL;
+ dcb->ice_pwd = NULL;
+ dcb->ice_default_candidate_addr[0] = '\0';
+
+ dcb->digest_alg[0] = '\0';
+ dcb->digest[0] = '\0';
+}
+
+
+static void
+fsmdef_free_dcb (fsmdef_dcb_t *dcb)
+{
+ if (dcb == NULL) {
+ return;
+ }
+
+ strlib_free(dcb->caller_id.calling_name);
+ strlib_free(dcb->caller_id.calling_number);
+ strlib_free(dcb->caller_id.alt_calling_number);
+ strlib_free(dcb->caller_id.called_name);
+ strlib_free(dcb->caller_id.called_number);
+
+ strlib_free(dcb->caller_id.last_redirect_name);
+ strlib_free(dcb->caller_id.last_redirect_number);
+ strlib_free(dcb->caller_id.orig_called_name);
+ strlib_free(dcb->caller_id.orig_called_number);
+ strlib_free(dcb->caller_id.orig_rpid_number);
+
+ /* Cancel any existing error onhook timer */
+ if (dcb->err_onhook_tmr) {
+ (void) cprCancelTimer(dcb->err_onhook_tmr);
+ (void) cprDestroyTimer(dcb->err_onhook_tmr);
+ dcb->err_onhook_tmr = NULL;
+ }
+
+ /* Cancel any existing request pending timer */
+ if (dcb->req_pending_tmr) {
+ (void) cprCancelTimer(dcb->req_pending_tmr);
+ (void) cprDestroyTimer(dcb->req_pending_tmr);
+ dcb->req_pending_tmr = NULL;
+ }
+
+ /* Cancel any existing ringback delay timer */
+ if (dcb->ringback_delay_tmr) {
+ (void) cprCancelTimer(dcb->ringback_delay_tmr);
+ }
+
+ // Free the call instance id
+ if (dcb->caller_id.call_instance_id != 0) {
+ fsmutil_free_ci_id(dcb->caller_id.call_instance_id, dcb->line);
+ }
+
+ /* clean media list */
+ gsmsdp_clean_media_list(dcb);
+
+ gsmsdp_free(dcb);
+
+ fsmdef_init_dcb(dcb, CC_NO_CALL_ID, FSMDEF_CALL_TYPE_NONE, NULL,
+ LSM_NO_LINE, NULL);
+
+ /*
+ * Cache random numbers for SRTP keys
+ */
+ gsmsdp_cache_crypto_keys();
+
+}
+
+void
+fsmdef_free_cb (fim_icb_t *icb, callid_t call_id)
+{
+ fsm_fcb_t *fcb = NULL;
+ fsmdef_dcb_t *dcb = NULL;
+
+ if (call_id != CC_NO_CALL_ID) {
+ dcb = fsmdef_get_dcb_by_call_id(call_id);
+ if (dcb != NULL) {
+ fcb = dcb->fcb;
+ fsmdef_init_dcb(dcb, CC_NO_CALL_ID, FSMDEF_CALL_TYPE_NONE,
+ NULL, LSM_NO_LINE, NULL);
+ /* fsmdef_init_dcb(...,NULL) will always set the fcb ptr to NULL,
+ so if fsmdef_free_cb were called on that we'd have fcb==NULL here */
+ if (fcb != NULL) {
+ fsm_init_fcb(fcb, CC_NO_CALL_ID, FSMDEF_NO_DCB, FSM_TYPE_NONE);
+ }
+ } else {
+
+ fcb = fsm_get_fcb_by_call_id_and_type(call_id, FSM_TYPE_DEF);
+ if (fcb != NULL) {
+ fsm_init_fcb(fcb, CC_NO_CALL_ID, FSMDEF_NO_DCB, FSM_TYPE_NONE);
+ }
+ }
+ }
+}
+
+
+/*
+ * ROUTINE: fsmdef_get_new_dcb
+ *
+ * DESCRIPTION: return a new dcb initialized with the given data
+ *
+ * PARAMETERS:
+ * call_id: call_id
+ *
+ * RETURNS:
+ * dcb: the new dcb
+ *
+ * NOTES: None
+ */
+fsmdef_dcb_t *
+fsmdef_get_new_dcb (callid_t call_id)
+{
+ static const char fname[] = "fsmdef_get_new_dcb";
+ fsmdef_dcb_t *dcb = NULL;
+
+ /*
+ * Get a free dcb.
+ */
+ if ((dcb = fsmdef_get_dcb_by_call_id(CC_NO_CALL_ID)) == NULL) {
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG1), call_id, 0, fname,
+ "no dcbs available");
+
+ return (NULL);
+ }
+
+ dcb->call_id = call_id;
+
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG_PTR),
+ dcb->call_id, dcb->line, fname, dcb);
+
+ return (dcb);
+}
+
+
+/**
+ *
+ * Returns dcb related to connected call.
+ *
+ * @param none
+ *
+ * @return dcb of connected call.
+ *
+ * @pre none
+ */
+
+fsmdef_dcb_t *
+fsmdef_get_connected_call (void)
+{
+ fsmdef_dcb_t *dcb;
+ fsm_fcb_t *fcb;
+
+ FSM_FOR_ALL_CBS(dcb, fsmdef_dcbs, FSMDEF_MAX_DCBS) {
+ if (dcb->call_id != CC_NO_CALL_ID) {
+ fcb = dcb->fcb;
+ if ((fcb != NULL) && (fcb->state == FSMDEF_S_RESUME_PENDING ||
+ fcb->state == FSMDEF_S_CONNECTED ||
+ fcb->state == FSMDEF_S_CONNECTED_MEDIA_PEND)) {
+
+ return (dcb);
+ }
+ }
+ }
+
+ return (NULL);
+}
+
+/**
+ *
+ * Returns dcb related to alerting out call.
+ *
+ * @param none
+ *
+ * @return dcb of outgoing alerting call.
+ *
+ * @pre none
+ */
+static fsmdef_dcb_t *
+fsmdef_get_alertingout_call (void)
+{
+ fsmdef_dcb_t *dcb;
+ fsm_fcb_t *fcb;
+
+ FSM_FOR_ALL_CBS(dcb, fsmdef_dcbs, FSMDEF_MAX_DCBS) {
+ if (dcb->call_id != CC_NO_CALL_ID) {
+ fcb = dcb->fcb;
+ if ((fcb != NULL) && (fcb->state == FSMDEF_S_OUTGOING_ALERTING)) {
+ return (dcb);
+ }
+ }
+ }
+
+ return (NULL);
+}
+
+/*
+ * fsmdef_get_active_call_cnt
+ *
+ * Return the count of active calls aside from the
+ * callid passed in.
+ */
+int
+fsmdef_get_active_call_cnt (callid_t callId)
+{
+ fsmdef_dcb_t *dcb;
+ int cnt = 0;
+
+ FSM_FOR_ALL_CBS(dcb, fsmdef_dcbs, FSMDEF_MAX_DCBS) {
+ if ((dcb->call_id != CC_NO_CALL_ID) && (dcb->call_id != callId)) {
+ cnt++;
+ }
+ }
+
+ return (cnt);
+}
+
+
+/*
+ * return the dcbs and count of calls that are ringing and
+ * are in error state not including the given call_id
+ *
+ * @param pointer to dcbs array
+ * @param call_id that should be ignored from search
+ *
+ * @return int number of ringing or error state calls
+ *
+ * @pre none
+*/
+static int
+fsmdef_get_ringing_n_error_call_dcbs (fsmdef_dcb_t **dcbs, callid_t ignore_call_id)
+{
+ fsmdef_dcb_t *dcb;
+ int cnt = 0;
+
+ FSM_FOR_ALL_CBS(dcb, fsmdef_dcbs, FSMDEF_MAX_DCBS) {
+ if (dcb->spoof_ringout_applied ||
+ ((dcb->call_id != CC_NO_CALL_ID) &&
+ (dcb->call_id != ignore_call_id) &&
+ (dcb->fcb && ((dcb->fcb->state <= FSMDEF_S_CONNECTING) ||
+ (dcb->fcb->state == FSMDEF_S_RELEASING))))) {
+ dcbs[cnt++] = dcb;
+ }
+ }
+
+ return (cnt);
+}
+
+
+int
+fsmdef_get_dcbs_in_held_state (fsmdef_dcb_t **dcbs, callid_t ignore_call_id)
+{
+ fsmdef_dcb_t *dcb;
+ int cnt = 0;
+
+ FSM_FOR_ALL_CBS(dcb, fsmdef_dcbs, FSMDEF_MAX_DCBS) {
+ if ((dcb->call_id != CC_NO_CALL_ID) &&
+ (dcb->call_id != ignore_call_id) &&
+ (dcb->fcb && (dcb->fcb->state == FSMDEF_S_HOLDING ||
+ dcb->fcb->state == FSMDEF_S_HOLD_PENDING))) {
+ dcbs[cnt++] = dcb;
+ }
+ }
+
+ return (cnt);
+}
+
+void fsmdef_call_cc_state_dialing (fsmdef_dcb_t *dcb, boolean suppress)
+{
+ cc_state_data_dialing_t data;
+
+ if ( dcb->caller_id.called_number[0] == '\0' ) {
+ data.play_dt = TRUE;
+ } else {
+ data.play_dt = FALSE;
+ }
+
+ data.suppress_stutter = suppress;
+
+ cc_call_state(dcb->call_id, dcb->line, CC_STATE_DIALING,
+ (cc_state_data_t *)(&data));
+}
+
+/*
+ * fsmdef_get_other_dcb_by_line
+ *
+ * return the dcb of the call that is active on a given line,
+ * not including the given call_id
+ */
+fsmdef_dcb_t *
+fsmdef_get_other_dcb_by_line (callid_t call_id, line_t line)
+{
+ fsmdef_dcb_t *dcb;
+ fsmdef_dcb_t *dcb_found = NULL;
+
+ FSM_FOR_ALL_CBS(dcb, fsmdef_dcbs, FSMDEF_MAX_DCBS) {
+ if ((dcb->call_id != CC_NO_CALL_ID) &&
+ (dcb->line == line) && (dcb->call_id != call_id)) {
+ dcb_found = dcb;
+ }
+ }
+
+ return (dcb_found);
+}
+
+/*
+ * fsmdef_are_there_selected_calls_onotherline
+ *
+ * @param line - line number
+ *
+ * loop thru the dcbs and check if there are selected calls
+ * on a line other than this one
+ *
+ * @return TRUE, there are
+ * FALSE there are not
+ */
+boolean fsmdef_are_there_selected_calls_onotherline (line_t line)
+{
+ fsmdef_dcb_t *dcb;
+
+ FSM_FOR_ALL_CBS(dcb, fsmdef_dcbs, FSMDEF_MAX_DCBS) {
+ if (dcb->selected) {
+ if (dcb->line != line) {
+ return (TRUE);
+ }
+ }
+ }
+ return (FALSE);
+}
+
+/*
+ * fsmdef_are_join_calls_on_same_line
+ *
+ * @param line - line number
+ *
+ * loop thru the dcbs and check if the line passed is the
+ * same as where the initial join started
+ *
+ * @return TRUE, they are on the same line
+ * FALSE not on the same line
+ */
+boolean fsmdef_are_join_calls_on_same_line (line_t line)
+{
+ fsmdef_dcb_t *dcb;
+
+ FSM_FOR_ALL_CBS(dcb, fsmdef_dcbs, FSMDEF_MAX_DCBS) {
+ if (dcb->call_id == g_b2bjoin_callid) {
+ if (dcb->line != line) {
+ return (FALSE);
+ } else {
+ return (TRUE);
+ }
+ }
+ }
+ return (FALSE);
+}
+
+/**
+ *
+ * Handles media capability update feature event from platform when
+ * media stream capability changes.
+ *
+ * @param[in]msg - pointer to the cc_feature_t.
+ *
+ * @return None.
+ *
+ * @pre (msg not_eq NULL)
+ */
+void
+fsmdef_update_media_cap_feature_event (cc_feature_t *msg)
+{
+ static const char fname[] = "fsmdef_update_media_cap_feature_event";
+ fsmdef_dcb_t *dcb;
+ fsm_fcb_t *fcb;
+
+ FSM_DEBUG_SM(DEB_L_C_F_PREFIX"\n", DEB_L_C_F_PREFIX_ARGS(FSM, msg->line, msg->call_id, fname));
+
+ /*
+ * Find the connected call to send the media capability update
+ * event to. There can be more than one call chains in
+ * connected state for an example, a call that participates in
+ * local conference, barged, monitored. All calls that
+ * are active are sent the update event. Each call leg will handle
+ * the event.
+ *
+ */
+ FSM_FOR_ALL_CBS(dcb, fsmdef_dcbs, FSMDEF_MAX_DCBS) {
+ if (dcb->call_id != CC_NO_CALL_ID) {
+ fcb = dcb->fcb;
+ if ((fcb != NULL) && (fcb->state == FSMDEF_S_RESUME_PENDING ||
+ fcb->state == FSMDEF_S_CONNECTED)) {
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, dcb->call_id,
+ dcb->line, CC_FEATURE_UPD_MEDIA_CAP, NULL);
+
+ }
+ }
+ }
+}
+
+/**
+ *
+ * Function to find and hold any connected call.
+ *
+ * @param call_id call id of the call
+ * @param wait flag to indicate if the caller has to wait ton invoke the event
+ * @param src_id source id of the caller where to post hold or endcall event.
+ *
+ * @return none
+ *
+ * @pre (wait == FALSE)
+ */
+
+static void
+fsmdef_find_and_hold_connected_call (callid_t call_id, boolean *wait,
+ cc_srcs_t src_id)
+{
+ fsmdef_dcb_t *con_dcb;
+ fsmcnf_ccb_t *ccb;
+ fsmcnf_ccb_t *con_ccb;
+ fsmxfr_xcb_t *xcb;
+ cc_feature_data_t data;
+ callid_t other_call_id;
+ callid_t other_call_id2;
+
+ *wait = FALSE;
+
+ /*
+ * Place the connected call, if there is one, on hold,
+ * but there are some restrictions to ignore the hold request:
+ * 1. the connected call must be different than the one requesting the hold,
+ * 2. the connected call is involved with this call in a conference and
+ * the conference is active.
+ * NOTE: for case 2, why do we not send a hold for each of the calls
+ * involved in the conference? Because, the fsmcnf will generate the
+ * second hold for the other leg of the conference when it receives
+ * this hold.
+ * 3. the connected call is in a conference with another call that is
+ * involved with a transfer. This is the case when two calls are in a
+ * conference and a bridge decides to transfer one leg of the bridge
+ * using REFER. I.E., cnf between A-B and A-C. B initiates transfer to D.
+ * B holds A-B, sends REFER to A, A holds A-B, initiates A-D, D answers,
+ * A hangs up A-B and connects conference. So, when A initiates A-D,
+ * we do not want to hold the active bridge between A-C.
+ */
+ con_dcb = fsmdef_get_connected_call();
+ if ((con_dcb != NULL) && ((con_dcb->call_id != call_id) ||
+ (con_dcb->spoof_ringout_applied == FALSE))) {
+ ccb = fsmcnf_get_ccb_by_call_id(call_id);
+ con_ccb = fsmcnf_get_ccb_by_call_id(con_dcb->call_id);
+
+
+ if ((ccb == NULL) || (con_ccb == NULL) ||
+ ((ccb == con_ccb) && (ccb->active != TRUE)) || (ccb != con_ccb)) {
+ other_call_id = fsmcnf_get_other_call_id(con_ccb, con_dcb->call_id);
+ xcb = fsmxfr_get_xcb_by_call_id(other_call_id);
+
+ other_call_id2 = fsmxfr_get_other_call_id(xcb, other_call_id);
+
+ if (call_id != other_call_id2) {
+ *wait = TRUE;
+
+ data.hold.call_info.type = CC_FEAT_HOLD;
+ data.hold.call_info.data.hold_resume_reason =
+ CC_REASON_INTERNAL;
+ data.hold.msg_body.num_parts = 0;
+ data.hold.call_info.data.call_info_feat_data.swap = FALSE;
+ data.hold.call_info.data.call_info_feat_data.protect = FALSE;
+ cc_int_feature(src_id, CC_SRC_GSM, con_dcb->call_id,
+ con_dcb->line, CC_FEATURE_HOLD, &data);
+ }
+ }
+ }
+}
+
+/*
+ * Function post a event to end the call which are in ringing
+ * reorder or busy and connecting state. This would indicate call function to
+ * wait on the existing event.
+ *
+ * @param call_id that should be ignored from search
+ * @param pointer to boolean to indicate if the caller has to wait
+ *
+ * @return none
+ *
+ * @pre none
+*/
+static void
+fsmdef_find_and_handle_ring_connecting_releasing_calls (callid_t call_id, boolean *wait)
+{
+ int i;
+ int act_dcb_cnt;
+ fsmdef_dcb_t *act_dcb;
+ fsmdef_dcb_t *act_dcbs[LSM_MAX_CALLS];
+ cc_feature_data_t data;
+
+ *wait = FALSE;
+
+ data.endcall.cause = CC_CAUSE_NORMAL;
+ data.endcall.dialstring[0] = '\0';
+
+ act_dcb_cnt = fsmdef_get_ringing_n_error_call_dcbs(act_dcbs, call_id);
+ for (i = 0; i < act_dcb_cnt; i++) {
+ act_dcb = act_dcbs[i];
+ /*
+ * Clear all the outgoing ringing lines (if there are any).
+ */
+ if (act_dcb->call_type == FSMDEF_CALL_TYPE_OUTGOING ||
+ act_dcb->spoof_ringout_applied) {
+ *wait = TRUE;
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, act_dcb->call_id,
+ act_dcb->line, CC_FEATURE_END_CALL, &data);
+
+ }
+ else if (act_dcb->fcb->state == FSMDEF_S_CONNECTING) {
+ /* If the call is in connecting state, then wait till SIP
+ * response to get the call in connected state.
+ * The call can be put on hold only when call is connected.
+ */
+ *wait = TRUE;
+ }
+ }
+}
+
+void
+fsmdef_end_call (fsmdef_dcb_t *dcb, cc_causes_t cause)
+{
+ cc_feature_data_t data;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+ data.endcall.cause = cause;
+ data.endcall.dialstring[0] = '\0';
+
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, dcb->call_id, dcb->line,
+ CC_FEATURE_END_CALL, &data);
+}
+
+/*
+ * fsmdef_clear_preserved_calls
+ *
+ * Release any calls in the preserved state
+ */
+static void
+fsmdef_clear_preserved_calls (boolean *wait)
+{
+ fsmdef_dcb_t *dcb;
+
+ *wait = FALSE;
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ FSM_FOR_ALL_CBS(dcb, fsmdef_dcbs, FSMDEF_MAX_DCBS) {
+ if ((dcb->call_id != CC_NO_CALL_ID) &&
+ (dcb->fcb->state == FSMDEF_S_PRESERVED)) {
+ *wait = TRUE;
+ fsmdef_end_call(dcb, CC_CAUSE_NORMAL);
+ }
+ }
+}
+
+/**
+ *
+ * Checks to see if actions are required for existing calls before the new
+ * call can be activated.
+ *
+ * 1. Place the currently active connected call on hold.
+ * 2. Clear any ringing calls.
+ * 3. Release any call in the preserved state.
+ *
+ * @param is_newcall To indicate if this is a new call
+ * @param src_id source of the caller
+ * @param call_id call-id
+ * @param line line number
+ * @param feature feature which is waiting on hodling call.
+ * @param feature data
+ *
+ * @return TRUE if actions require delay before the new call may begin
+ * FALSE if no actions are required an the new call may begin
+ *
+ * @pre (wait, wait2, wait3 all FALSE)
+ */
+static boolean
+fsmdef_wait_to_start_new_call (boolean is_newcall, cc_srcs_t src_id, callid_t call_id,
+ line_t line, cc_features_t feature,
+ cc_feature_data_t *data)
+{
+ boolean wait = FALSE;
+ boolean wait2 = FALSE;
+ boolean wait3 = FALSE;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ fsmdef_find_and_hold_connected_call(call_id, &wait, src_id);
+
+ fsmdef_find_and_handle_ring_connecting_releasing_calls(call_id, &wait2);
+
+ fsmdef_clear_preserved_calls(&wait3);
+
+ /*
+ * Requeue the message because we need to wait for call actions to complete
+ */
+ if ((wait) || (wait2) || (wait3)) {
+ cc_int_feature(src_id, CC_SRC_GSM, call_id, line, feature, data);
+ }
+
+ return (wait | wait2 | wait3);
+}
+
+static cc_causes_t
+fsmdef_get_cause (boolean data_valid, cc_feature_data_t *data)
+{
+ cc_causes_t cause;
+
+ if (data_valid) {
+ cause = data->endcall.cause;
+ } else {
+ cause = CC_CAUSE_NORMAL;
+ }
+
+ return (cause);
+}
+
+
+/**
+ * common function to release a call given cause code
+ * i.e onhooks the given call.
+ *
+ * @param[in] fcb The pointer to the fsm_fcb_t structure of this
+ * call chain.
+ * @param[in] cause release cause code.
+ *
+ * @param[in] send_release When set to TRUE the function sends release
+ * and waits for release complete.
+ * When set to FALSE the function cleans up
+ * dcb and release fcb.
+ *
+ * @pre (fcb not_eq NULL)
+ *
+ * @return sm_rcs_t indicates whether the execution of
+ * next statmachine to end (SM_RC_END) or clean up
+ * (SM_RC_CLEANUP)
+ *
+ * @Usage Note: The function uses send_release flag to
+ * as an indicator for sending release out or not.
+ * If release is sent, the function transitions fsmdef's
+ * state to FSMDEF_S_RELEASING and
+ * return the SM_RC_END to waite for release complete.
+ *
+ * Otherwise, it cleans up dcb and releases fcb and
+ * return SM_RC_CLEANUP to the caller.
+ *
+ * If the SM_RC_CLEANUP is returned, the caller should
+ * terminate any access or perform any operation
+ * afterward.
+ */
+sm_rcs_t
+fsmdef_release (fsm_fcb_t *fcb, cc_causes_t cause, boolean send_release)
+{
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ cc_state_data_t state_data;
+ cc_kfact_t kfactor;
+ fsmdef_media_t *media;
+ char tmp_str[STATUS_LINE_MAX_LEN];
+
+ if (!dcb) {
+ /* Already been released */
+ return SM_RC_CLEANUP;
+ }
+
+ FSM_DEBUG_SM(DEB_L_C_F_PREFIX"Entered. cause= %s\n",
+ DEB_L_C_F_PREFIX_ARGS(FSM, dcb->line, dcb->call_id, __FUNCTION__), cc_cause_name(cause));
+
+ if (g_dock_undock_event != MEDIA_INTERFACE_UPDATE_NOT_REQUIRED) {
+ ui_update_media_interface_change(dcb->line, dcb->call_id, MEDIA_INTERFACE_UPDATE_FAIL);
+ }
+ memset(&kfactor, 0, sizeof(cc_kfact_t));
+ /* Cancel any existing autoanswer timer */
+ (void) cprCancelTimer(dcb->autoAnswerTimer);
+
+
+ /*
+ * Let Dialog Manager know that there is ONHOOK event
+ */
+ fsmdef_notify_hook_event(fcb, CC_MSG_ONHOOK, NULL, CC_NO_CALL_ID,
+ CC_REASON_NONE, CC_MONITOR_NONE,CFWDALL_NONE);
+
+ media = gsmsdp_find_audio_media(dcb);
+ if ((media) && (media->direction != SDP_DIRECTION_INACTIVE)) {
+ fsmdef_get_rtp_stat(dcb, &kfactor);
+ }
+
+ if ( cause == CC_SIP_CAUSE_ANSWERED_ELSEWHERE ) {
+ ui_log_disposition(dcb->call_id, CC_CALL_LOG_DISP_IGNORE );
+ }
+
+ if ( cause == CC_CAUSE_RESP_TIMEOUT) {
+ if ((platGetPhraseText(STR_INDEX_RESP_TIMEOUT,
+ (char *) tmp_str,
+ STATUS_LINE_MAX_LEN - 1)) == CPR_SUCCESS) {
+ lsm_ui_display_status(tmp_str, dcb->line, dcb->call_id);
+ }
+ }
+
+ if (send_release) {
+ cc_int_release(CC_SRC_GSM, CC_SRC_SIP, dcb->call_id, dcb->line,
+ cause, NULL, &kfactor);
+ /*
+ * Wait around for the release_complete.
+ */
+ fsm_change_state(fcb, __LINE__, FSMDEF_S_RELEASING);
+
+ /*
+ * Only move the UI if we changed the UI's state when the call was
+ * received.
+ */
+ if ((dcb->line != LSM_NO_LINE) || (cause != CC_CAUSE_BUSY)) {
+ state_data.onhook.caller_id = dcb->caller_id;
+ state_data.onhook.local = FALSE;
+ state_data.onhook.cause = CC_CAUSE_NORMAL;
+ cc_call_state(dcb->call_id, dcb->line, CC_STATE_ONHOOK,
+ &state_data);
+ }
+ return (SM_RC_END);
+ } else {
+ /*
+ * Only move the UI if we changed the UI's state when the call was
+ * initiated.
+ */
+ if ((dcb->line != LSM_NO_LINE) || (cause != CC_CAUSE_BUSY)) {
+ state_data.onhook.caller_id = dcb->caller_id;
+ state_data.onhook.local = FALSE;
+ state_data.onhook.cause = CC_CAUSE_NORMAL;
+ cc_call_state(dcb->call_id, dcb->line, CC_STATE_ONHOOK,
+ &state_data);
+ }
+
+ /*
+ * Only send a release complete to the remote end if they are waiting
+ * for it. This is the case when we have sent a proceeding or we
+ * have received a release.
+ */
+ if (FSM_CHK_FLAGS(dcb->msgs_sent, FSMDEF_MSG_PROCEEDING) ||
+ FSM_CHK_FLAGS(dcb->msgs_rcvd, FSMDEF_MSG_RELEASE)) {
+ cc_int_release_complete(CC_SRC_GSM, CC_SRC_SIP, dcb->call_id,
+ dcb->line, cause, &kfactor);
+ }
+
+ fsm_change_state(fcb, __LINE__, FSMDEF_S_IDLE);
+ fsmdef_free_dcb(dcb);
+ fsm_release(fcb, __LINE__, cause);
+ /*
+ * fsmdef has been released, indiate cleanup FSM chain.
+ */
+ return (SM_RC_CLEANUP);
+ }
+}
+
+/*
+ * fsmdef_convert_esc_plus
+ *
+ * replaces an escaped "+" (%2B) with a real "+"
+ */
+static void
+fsmdef_convert_esc_plus (const char *src_number)
+{
+ int i, len;
+ char *number;
+
+ len = strlen(src_number) - 2;
+ number = (char *) src_number;
+ number[0] = '+';
+ for (i = 1; i < len; i++) {
+ number[i] = number[i + 2];
+ }
+ number[i] = '\0';
+}
+
+static boolean
+fsmdef_compare_caller_id_string (string_t dest, string_t src)
+{
+ if ((dest == NULL) && (src == NULL)) {
+ /*
+ * Strings are same.
+ */
+ return (FALSE);
+ }
+
+ if ((dest == NULL) || (src == NULL)) {
+ /*
+ * Strings differ.
+ */
+ return (TRUE);
+ }
+
+ if (strncmp(dest, src, FSMDEF_MAX_CALLER_ID_LEN) != 0) {
+ /*
+ * Strings differ.
+ */
+ return (TRUE);
+ }
+
+ /*
+ * Strings are same.
+ */
+ return (FALSE);
+}
+
+static boolean
+fsmdef_compare_caller_id (cc_caller_id_t *dest_caller_id,
+ cc_caller_id_t *src_caller_id)
+{
+ if (fsmdef_compare_caller_id_string(dest_caller_id->calling_name,
+ src_caller_id->calling_name)) {
+ return (TRUE);
+ }
+
+ if (fsmdef_compare_caller_id_string(dest_caller_id->calling_number,
+ src_caller_id->calling_number)) {
+ return (TRUE);
+ }
+
+ if (fsmdef_compare_caller_id_string(dest_caller_id->called_name,
+ src_caller_id->called_name)) {
+ return (TRUE);
+ }
+
+ if (fsmdef_compare_caller_id_string(dest_caller_id->called_number,
+ src_caller_id->called_number)) {
+ return (TRUE);
+ }
+
+ if (fsmdef_compare_caller_id_string(dest_caller_id->orig_called_name,
+ src_caller_id->orig_called_name)) {
+ return (TRUE);
+ }
+
+ if (fsmdef_compare_caller_id_string(dest_caller_id->orig_called_number,
+ src_caller_id->orig_called_number)) {
+ return (TRUE);
+ }
+
+ if (fsmdef_compare_caller_id_string(dest_caller_id->last_redirect_name,
+ src_caller_id->last_redirect_name)) {
+ return (TRUE);
+ }
+
+ if (fsmdef_compare_caller_id_string(dest_caller_id->last_redirect_number,
+ src_caller_id->last_redirect_number)) {
+ return (TRUE);
+ }
+
+ if (fsmdef_compare_caller_id_string(dest_caller_id->orig_rpid_number,
+ src_caller_id->orig_rpid_number)) {
+ return (TRUE);
+ }
+
+ if (dest_caller_id->display_calling_number != src_caller_id->display_calling_number ||
+ dest_caller_id->display_called_number != src_caller_id->display_called_number ||
+ dest_caller_id->call_type != src_caller_id->call_type ||
+ dest_caller_id->call_instance_id != src_caller_id->call_instance_id) {
+ return (TRUE);
+ }
+
+ return (FALSE);
+}
+
+static void
+fsmdef_mv_caller_id (fsmdef_dcb_t *dcb, cc_caller_id_t *caller_id)
+{
+ /*
+ * Move the caller ID from the source to the storage in dcb if there
+ * is a change in what is already stored in the dcb.
+ */
+ if (fsmdef_compare_caller_id(&dcb->caller_id, caller_id)) {
+ cc_mv_caller_id(&dcb->caller_id, caller_id);
+ dcb->ui_update_required = TRUE;
+ }
+}
+
+static void
+fsmdef_update_callinfo (fsm_fcb_t *fcb, cc_feature_t *msg)
+{
+ static const char fname[] = "fsmdef_update_callinfo";
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ cc_feature_data_t *feat_data = &(msg->data);
+ cc_action_data_t action_data;
+ cc_caller_id_t *caller_id;
+
+ if (msg->data_valid == FALSE) {
+ /* No data to use for update. Just ignore the event. */
+ return;
+ }
+
+ if ((feat_data->call_info.feature_flag & CC_UI_STATE) &&
+ (feat_data->call_info.ui_state == CC_UI_STATE_RINGOUT)) {
+
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG1),
+ dcb->call_id, dcb->line, fname,
+ "setting spoof_ringout_requested");
+
+ dcb->spoof_ringout_requested = TRUE;
+ } else {
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG_CLR_SPOOF_RQSTD),
+ dcb->call_id, dcb->line, fname);
+
+ dcb->spoof_ringout_requested = FALSE;
+ }
+
+ caller_id = &feat_data->call_info.caller_id;
+
+ if (feat_data->call_info.feature_flag & CC_CALLER_ID) {
+ fsmdef_mv_caller_id(dcb, caller_id);
+ }
+
+ /*
+ * If CCM provides a call instance id and it does not match
+ * the current call instance id, free the current call instance
+ * id and set the call instance id to the newly provided value.
+ */
+ if (feat_data->call_info.feature_flag & CC_CALL_INSTANCE &&
+ feat_data->call_info.caller_id.call_instance_id != dcb->caller_id.call_instance_id) {
+ if (dcb->caller_id.call_instance_id != 0) {
+ fsmutil_free_ci_id(dcb->caller_id.call_instance_id, dcb->line);
+ }
+ dcb->caller_id.call_instance_id =
+ feat_data->call_info.caller_id.call_instance_id;
+ fsmutil_set_ci_id(dcb->caller_id.call_instance_id, dcb->line);
+ dcb->ui_update_required = TRUE;
+ }
+
+ /*
+ * Update security status
+ */
+ fsmdef_update_callinfo_security_status(dcb, &feat_data->call_info);
+
+ /*
+ * Update call policy
+ */
+ if (feat_data->call_info.feature_flag & CC_POLICY) {
+ if (dcb->policy != feat_data->call_info.policy) {
+ dcb->policy = feat_data->call_info.policy;
+ dcb->ui_update_required = TRUE;
+ }
+ }
+
+ /*
+ * Save orientation so that UI call update can be done at
+ * any time that UI needs to be updated.
+ */
+ if (feat_data->call_info.feature_flag & CC_ORIENTATION) {
+ if (dcb->orientation != feat_data->call_info.orientation) {
+ dcb->orientation = feat_data->call_info.orientation;
+ dcb->ui_update_required = TRUE;
+ }
+ }
+
+ /*
+ * This call info. event may be as part of media effecting
+ * signaling event (such as INVITE, re-INVITE, 180 etc.)
+ * which will be followed by actual media effected event. It is
+ * indicated by SIP stack to improve media cutting through as soonest.
+ * If SIP indicates that UI can be delayed then do not update call
+ * information now. The UI will be updated as part of media
+ * manipulation event that will follow.
+ * (Note: call info event is sent separately from the SIP signaling
+ * event currently and it is sent before SIP signaling event).
+ */
+ if (feat_data->call_info.feature_flag & CC_DELAY_UI_UPDATE) {
+ /* Delay UI update */
+ } else {
+ /*
+ * Only perform a UI update if something changed.
+ */
+ if (dcb->ui_update_required == TRUE
+ || dcb->spoof_ringout_requested == TRUE) {
+
+ action_data.update_ui.action = CC_UPDATE_CALLER_INFO;
+ action_data.update_ui.data.caller_info = feat_data->call_info;
+
+ (void)cc_call_action(dcb->call_id, dcb->line, CC_ACTION_UPDATE_UI,
+ &action_data);
+
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG1), dcb->call_id,
+ dcb->line, fname, "UI update");
+ } else {
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG1),
+ dcb->call_id, dcb->line, fname, "No UI update");
+ }
+ }
+ /* update callref */
+ if ( dcb->callref == 0 ) {
+ dcb->callref = feat_data->call_info.callref;
+ ui_update_callref(dcb->line, dcb->call_id, feat_data->call_info.callref);
+ }
+ /* update gcid */
+ if (feat_data->call_info.global_call_id[0] != '\0') {
+ ui_update_gcid(dcb->line, dcb->call_id, feat_data->call_info.global_call_id);
+ /*
+ * store the gcid lcb, this is used to prevent short ringing
+ * in scenarios where a call is routed to the calling phone.
+ */
+ lsm_update_gcid(dcb->call_id, feat_data->call_info.global_call_id);
+ }
+}
+
+/**
+ * Function: fsmdef_set_feature_timer
+ *
+ * Description: This function is called to set (start) timer for a
+ * given timer. The context of the timer is set so that upon
+ * expiration the corresponding context (dcb) can be obtained.
+ *
+ * Parameters:
+ * dcb - pointer to the fsmdef_dcb_t. The caller must ensure
+ * dcb is not NULL.
+ * timer - pointer to cprTimer_t. The caller must ensure that
+ * timer is not NULL.
+ * duration - the time duration for the timer to be set.
+ *
+ * Returns:
+ * N/A.
+ */
+static void
+fsmdef_set_feature_timer (fsmdef_dcb_t *dcb, cprTimer_t *timer,
+ uint32_t duration)
+{
+ static const char fname[] = "fsmdef_set_feature_timer";
+
+ if (cprCancelTimer(*timer) != CPR_SUCCESS) {
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG_TMR_CANCEL_FAILED),
+ dcb->call_id, dcb->line, fname, "Feature", cpr_errno);
+
+ return;
+ }
+
+ if (cprStartTimer(*timer, duration, (void *)(long)dcb->call_id) == CPR_FAILURE) {
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG_TMR_START_FAILED),
+ dcb->call_id, dcb->line, fname, "Feature", cpr_errno);
+ }
+}
+
+static void
+fsmdef_set_req_pending_timer (fsmdef_dcb_t *dcb)
+{
+ static const char fname[] = "fsmdef_set_req_pending_timer";
+ uint32_t msec;
+
+ if (dcb == NULL) {
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG_INVALID_DCB), fname);
+ return;
+ }
+
+ if (!dcb->req_pending_tmr) {
+ dcb->req_pending_tmr = cprCreateTimer("Request Pending",
+ GSM_REQ_PENDING_TIMER,
+ TIMER_EXPIRATION,
+ gsm_msg_queue);
+
+ if (dcb->req_pending_tmr == NULL) {
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG_TMR_CREATE_FAILED),
+ dcb->call_id, dcb->line, fname, "Request Pending");
+
+ return;
+ }
+ }
+
+ if (dcb->inbound) {
+ // We did not initiate this call, so set timer between 0 and 2000ms
+ msec = abs(cpr_rand()) % 2000;
+ } else {
+ // We initiated this call, so set the timer between 2100 and 4000ms
+ msec = abs(cpr_rand()) % 1900 + 2100;
+ }
+
+ FSM_DEBUG_SM(DEB_L_C_F_PREFIX"Starting req pending timer for %d ms.\n",
+ DEB_L_C_F_PREFIX_ARGS(FSM, dcb->line, dcb->call_id, fname), msec);
+
+ fsmdef_set_feature_timer(dcb, &dcb->req_pending_tmr, msec);
+}
+
+static void
+fsmdef_set_ringback_delay_timer (fsmdef_dcb_t *dcb)
+{
+ static const char fname[] = "fsmdef_set_ringback_delay_timer";
+
+ if (dcb == NULL) {
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG_INVALID_DCB), fname);
+ return;
+ }
+
+ FSM_DEBUG_SM(DEB_L_C_F_PREFIX"Starting Ringback Delay timer"
+ " for %d ms.\n",
+ DEB_L_C_F_PREFIX_ARGS(FSM, dcb->line, dcb->call_id, fname), RINGBACK_DELAY);
+
+ fsmdef_set_feature_timer(dcb, &dcb->ringback_delay_tmr, RINGBACK_DELAY);
+}
+
+/*******************************************************************
+ * event functions
+ */
+static sm_rcs_t
+fsmdef_ev_default (sm_event_t *event)
+{
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+
+ FSM_DEBUG_SM(get_debug_string(FSM_DBG_SM_DEFAULT_EVENT));
+ if (fcb->dcb) {
+ cc_call_state(fcb->dcb->call_id, fcb->dcb->line, CC_STATE_UNKNOWN,
+ NULL);
+ }
+ return (SM_RC_END);
+}
+
+/*
+ * Default event handler for feature_ack event
+ */
+static sm_rcs_t
+fsmdef_ev_default_feature_ack (sm_event_t *event)
+{
+ static const char fname[] = "fsmdef_ev_default_feature_ack";
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ cc_feature_ack_t *msg = (cc_feature_ack_t *) event->msg;
+ cc_features_t ftr_id = msg->feature_id;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, "fsmdef_ev_default_feature_ack"));
+
+ if (ftr_id == CC_FEATURE_SELECT) {
+ /* Reeceived the response for select, so turn the flag off */
+ dcb->select_pending = FALSE;
+ if (dcb->selected) {
+ dcb->selected = FALSE;
+ g_numofselected_calls--;
+ FSM_DEBUG_SM(DEB_L_C_F_PREFIX"call is unselected and number of selected \
+ calls on the phone is %d\n",
+ DEB_L_C_F_PREFIX_ARGS(FSM, dcb->line, msg->call_id, fname),
+ g_numofselected_calls);
+
+ } else {
+ dcb->selected = TRUE;
+ if ((g_b2bjoin_pending == FALSE) &&
+ (dcb->active_feature == CC_FEATURE_B2B_JOIN)) {
+ g_b2bjoin_pending = TRUE;
+ g_b2bjoin_callid = dcb->call_id;
+ }
+ g_numofselected_calls++;
+ FSM_DEBUG_SM(DEB_L_C_F_PREFIX"call is selected and number of selected \
+ calls on the phone is %d\n",
+ DEB_L_C_F_PREFIX_ARGS(FSM, dcb->line, dcb->call_id, fname),
+ g_numofselected_calls);
+ }
+ ui_call_selected(dcb->line, lsm_get_ui_id(dcb->call_id), (dcb->selected)?CC_DIALOG_LOCKED:CC_DIALOG_UNLOCKED);
+
+ } else if (dcb->active_feature != ftr_id) {
+ // check if we are getting feature_ack for the active feature
+ FSM_DEBUG_SM(DEB_L_C_F_PREFIX"feature_ack rcvd for %s but %s is active\n",
+ DEB_L_C_F_PREFIX_ARGS(FSM, dcb->line, dcb->call_id, fname),
+ cc_feature_name(ftr_id), cc_feature_name(dcb->active_feature));
+
+ }
+
+ // reset active feature
+ dcb->active_feature = CC_FEATURE_NONE;
+
+ return (SM_RC_END);
+}
+
+
+static void
+fsmdef_sm_ignore_ftr (fsm_fcb_t *fcb, int fname, cc_features_t ftr_id)
+{
+ fsm_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ if (fcb->dcb) {
+ cc_call_state(fcb->dcb->call_id, fcb->dcb->line, CC_STATE_UNKNOWN,
+ NULL);
+ }
+}
+
+static void
+fsmdef_sm_ignore_src (fsm_fcb_t *fcb, int fname, cc_srcs_t src_id)
+{
+ fsm_sm_ignore_src(fcb, __LINE__, src_id);
+
+ if (fcb->dcb) {
+ cc_call_state(fcb->dcb->call_id, fcb->dcb->line, CC_STATE_UNKNOWN,
+ NULL);
+ }
+}
+
+/*
+ * fsmdef_error_onhook_timeout
+ *
+ * Timer is started immediately after the call error. This function is called
+ * when there is a timeout event generated by the timer .
+ *
+ * @param[in] data The gsm ID (callid_t) of the call onhook timeout
+ * has occured.
+ *
+ * @return N/A
+ */
+void
+fsmdef_error_onhook_timeout (void *data)
+{
+ static const char fname[] = "fsmdef_error_onhook_timeout";
+ fsmdef_dcb_t *dcb;
+ callid_t call_id;
+
+ call_id = (callid_t)(long)data;
+ if (call_id == CC_NO_CALL_ID) {
+ /* Invalid call id */
+ GSM_ERR_MSG(get_debug_string(FSMDEF_DBG1), 0, 0, fname, "invalid data");
+ return;
+ }
+
+ /* Retrieve dcb from call id */
+ dcb = fsmdef_get_dcb_by_call_id(call_id);
+ if (dcb == NULL) {
+ GSM_ERR_MSG(get_debug_string(FSMDEF_DBG_INVALID_DCB), fname);
+
+ return;
+ }
+
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG1),
+ dcb->call_id, dcb->line, fname, "timeout");
+
+ cc_int_onhook(CC_SRC_GSM, CC_SRC_GSM, CC_NO_CALL_ID, CC_REASON_NONE,
+ dcb->call_id, dcb->line, FALSE, FALSE);
+}
+
+/**
+ * Function: fsmdef_feature_timer_timeout
+ *
+ * Description: This function is called when receives time out
+ * notification. The function then converts the timer event
+ * into the CCAPI event suitable for GSM's call state machine.
+ *
+ * Parameters:
+ * feature_id - corresponding feature ID of the timer event.
+ * data - the opaque data for the caller which is actually
+ * is the GSM's call id.
+ *
+ * Returns:
+ * NULL or
+ * pointer to the cc_feature_t.
+ */
+void *
+fsmdef_feature_timer_timeout (cc_features_t feature_id, void *data)
+{
+ static const char fname[] = "fsmdef_feature_timer_timeout";
+ cc_feature_t *pmsg;
+ callid_t call_id;
+ fsmdef_dcb_t *dcb;
+
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG1), 0, 0, fname, "timeout");
+
+ call_id = (callid_t)(long)data;
+ if (call_id == CC_NO_CALL_ID) {
+ /* Invalid call id */
+ GSM_ERR_MSG(get_debug_string(FSMDEF_DBG1), 0, 0, fname, "invalid data");
+ return NULL;
+ }
+
+ dcb = fsmdef_get_dcb_by_call_id(call_id);
+ if (dcb == NULL) {
+ /* The corresponding dcb for the call ID is not found */
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG_INVALID_DCB), fname);
+ return (NULL);
+ }
+
+ if (dcb->inband_received && feature_id == CC_FEATURE_RINGBACK_DELAY_TIMER_EXP) {
+ /* Double check if inbound ringback indication is received*/
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG1), 0, 0, fname, "inband received!");
+ return (NULL);
+ }
+
+ pmsg = (cc_feature_t *) gsm_get_buffer(sizeof(*pmsg));
+ if (!pmsg) {
+ GSM_ERR_MSG(get_debug_string(FSMDEF_DBG1),
+ call_id, dcb->line, fname,
+ "failed to allocate feature timer message");
+ return NULL;
+ }
+
+ memset(pmsg, 0, sizeof(*pmsg));
+
+ pmsg->msg_id = CC_MSG_FEATURE;
+ pmsg->src_id = CC_SRC_GSM;
+ pmsg->call_id = call_id;
+ pmsg->line = dcb->line;
+ pmsg->feature_id = feature_id;
+ pmsg->data_valid = FALSE;
+
+ return (void *) pmsg;
+}
+
+/**
+ *
+ * Function handles idle setup request received from the network
+ *
+ * @sm_eent_t event
+ *
+ * @return SM_RC_END
+ *
+ * @pre (called_number and called_number not NULL)
+ * @pre (event->data not_eq NULL)
+ * @pre (event->msg not_eq NULL)
+ */
+static sm_rcs_t
+fsmdef_ev_idle_setup (sm_event_t *event)
+{
+ static const char fname[] = "fsmdef_ev_idle_setup";
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ cc_setup_t *msg = (cc_setup_t *) event->msg;
+ callid_t call_id = msg->call_id;
+ int temp;
+ string_t called_number = msg->caller_id.called_number;
+ string_t calling_number = msg->caller_id.calling_number;
+ fsmdef_dcb_t *dcb;
+ cc_causes_t cause;
+ fsmxfr_xcb_t *xcb;
+ fsm_fcb_t *other_fcb;
+ callid_t other_call_id;
+ boolean alerting = TRUE;
+ boolean replaces = msg->replaces;
+ int other_active_calls;
+ boolean transfer_target = FALSE;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ /*
+ * Make sure we have a valid called_number.
+ */
+ if ((called_number == NULL) || (called_number[0] == '\0')) {
+ return (SM_RC_CLEANUP);
+ }
+
+ /*
+ * Check the called/calling number for the E.164 escaped "+"
+ * and convert it to a real "+" if present.
+ */
+ if (cpr_strncasecmp(called_number, "%2B", 3) == 0) {
+ fsmdef_convert_esc_plus(called_number);
+ }
+ if (cpr_strncasecmp(calling_number, "%2B", 3) == 0) {
+ fsmdef_convert_esc_plus(calling_number);
+ }
+
+ FSM_DEBUG_SM(DEB_L_C_F_PREFIX"called_number= %s calling_number= %s\n",
+ DEB_L_C_F_PREFIX_ARGS(FSM, msg->line, msg->call_id, fname),
+ msg->caller_id.called_number, msg->caller_id.calling_number);
+
+ //idle = lsm_is_phone_idle();
+
+ xcb = fsmxfr_get_xcb_by_call_id(call_id);
+ if (xcb && replaces) {
+ transfer_target = TRUE;
+ }
+
+ /*
+ * Get a new incoming call context.
+ * if we the target of a transfer, request that the line
+ * availability be increased by one to account for the third
+ * instance of a line to become available to allow completion
+ * of transfer.
+ */
+ cause = fsm_get_new_incoming_call_context(call_id, fcb, called_number,
+ transfer_target);
+ dcb = fcb->dcb;
+ if ((msg->call_info.type != CC_FEAT_MONITOR) &&
+ (replaces != TRUE)) {
+ if (lsm_is_line_available(dcb->line, TRUE) == FALSE) {
+ /* increment it to compensate for decrementing while ending the call. */
+ lsm_increment_call_chn_cnt(dcb->line);
+ fsmdef_end_call(dcb, CC_CAUSE_BUSY);
+ return (SM_RC_END);
+ }
+ lsm_increment_call_chn_cnt(dcb->line);
+ }
+ else {
+ /*
+ * join calls (barged, M & R) are not counted by CUCM. so we should not count either
+ */
+ dcb->call_not_counted_in_mnc_bt = TRUE;
+ dcb->join_call_id = msg->call_info.data.join.join_call_id;
+ }
+ /*
+ * Set default orientation for the incoming setup as "from" to
+ * avoid updating UI when call info is received in "ACK" which
+ * shoule be "from" for typicall incoming call.
+ */
+ dcb->orientation = CC_ORIENTATION_FROM;
+
+ switch (cause) {
+ case CC_CAUSE_OK:
+ break;
+
+ case CC_CAUSE_NO_RESOURCE:
+ cc_call_state(fcb->dcb->call_id, fcb->dcb->line, CC_STATE_UNKNOWN,
+ NULL);
+ return (SM_RC_CLEANUP);
+
+ default:
+ fsmdef_end_call(dcb, cause);
+ return (SM_RC_END);
+ }
+
+ /*
+ * Check for Anonymous call blocking. If low bit is set,
+ * then do not allow call. Note that we must allow both upper and lowercase
+ * ANON strings, hence the use of strcasestr
+ */
+ config_get_value(CFGID_ANONYMOUS_CALL_BLOCK, &temp, sizeof(temp));
+ if (temp & 1) {
+ /*
+ * We compare the calling name to the hardcoded Anonymous string we use in
+ * our SIP headers. This handles the case where calling name was pulled from
+ * the From header and was set to Anonymous. We also compare the calling name
+ * to the localized string index for Private which is what the calling name will
+ * be set to if an RPID header was received.
+ */
+ char tmp_str[STATUS_LINE_MAX_LEN];
+ sstrncpy(tmp_str, platform_get_phrase_index_str(UI_PRIVATE), sizeof(tmp_str));
+ if (strcasestr(msg->caller_id.calling_name, SIP_HEADER_ANONYMOUS_STR) ||
+ strcasestr(msg->caller_id.calling_name, tmp_str)) {
+ fsmdef_end_call(dcb, CC_CAUSE_ANONYMOUS);
+ return (SM_RC_END);
+ }
+ }
+
+ /*
+ * Check if Call Waiting is disabled.
+ * If call-waiting is disabled and there is another call active
+ * then the GSM will return busy.
+ * unless this is a barge/monitor target call
+ *
+ */
+ config_get_line_value(CFGID_LINE_CALL_WAITING, &temp, sizeof(temp),
+ dcb->line);
+ other_active_calls = fsmdef_get_active_call_cnt(call_id);
+
+ if ((msg->call_info.type != CC_FEAT_MONITOR)) {
+ if ((!(temp & 1)) && (other_active_calls > 0) &&
+ (!((xcb != NULL) && (xcb->mode == FSMXFR_MODE_TARGET)))) {
+
+ fsmdef_end_call(dcb, CC_CAUSE_BUSY);
+
+ return (SM_RC_END);
+ }
+ }
+
+ /*
+ * If this is a call to replace another call,
+ * check that we have a call to replace
+ */
+ other_call_id = fsmxfr_get_other_call_id(xcb, call_id);
+ if (replaces) {
+ if ((xcb == NULL) || (other_call_id == CC_NO_CALL_ID)) {
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG1),
+ dcb->call_id, dcb->line, "",
+ "No call to replace");
+
+ fsmdef_end_call(dcb, CC_CAUSE_NO_REPLACE_CALL);
+ return (SM_RC_END);
+ }
+ }
+
+
+ /*
+ * The called name and number will not be obtained from
+ * the setup. Remove it before getting from the setup message.
+ */
+ if (msg->caller_id.called_name != NULL) {
+ strlib_free(msg->caller_id.called_name);
+ msg->caller_id.called_name = NULL;
+ }
+ if (msg->caller_id.called_number != NULL) {
+ strlib_free(msg->caller_id.called_number);
+ msg->caller_id.called_number = NULL;
+ }
+ /* Get the caller ID from the setup message */
+ fsmdef_mv_caller_id(dcb, &msg->caller_id);
+
+ if (msg->caller_id.call_type == CC_CALL_FORWARDED) {
+
+ dcb->call_type = FSMDEF_CALL_TYPE_FORWARD;
+ }
+
+ /*
+ * If a call instance id is provided, use it in the dcb. We will
+ * check to see that the call instance id provided differs from
+ * what is currently stored in the dcb before assigning it.
+ */
+ if (msg->call_info.type == CC_FEAT_CALLINFO) {
+ cc_feature_data_call_info_t *data;
+
+ data = &msg->call_info.data.call_info_feat_data;
+ if (data->feature_flag & CC_CALL_INSTANCE) {
+ if (data->caller_id.call_instance_id != 0 &&
+ data->caller_id.call_instance_id !=
+ dcb->caller_id.call_instance_id) {
+ if (dcb->caller_id.call_instance_id != 0) {
+ fsmutil_free_ci_id(dcb->caller_id.call_instance_id,
+ dcb->line);
+ }
+ dcb->caller_id.call_instance_id =
+ data->caller_id.call_instance_id;
+ fsmutil_set_ci_id(dcb->caller_id.call_instance_id, dcb->line);
+ }
+ }
+
+ if (data->feature_flag & CC_SECURITY) {
+ FSM_SET_SECURITY_STATUS(dcb, data->security);
+ }
+
+ if (data->feature_flag & CC_POLICY) {
+ FSM_SET_POLICY(dcb, data->policy);
+ }
+ }
+ dcb->alert_info = msg->alert_info;
+ dcb->alerting_ring = msg->alerting_ring;
+ dcb->alerting_tone = msg->alerting_tone;
+
+ /*
+ * This is an incoming call, so we know we will need to send a
+ * RELEASE when we clear the call.
+ */
+ dcb->send_release = TRUE;
+
+ cause = gsmsdp_negotiate_offer_sdp(fcb, &msg->msg_body, TRUE);
+ if (cause != CC_CAUSE_OK) {
+ return (fsmdef_release(fcb, cause, dcb->send_release));
+ }
+
+ if (transfer_target) {
+ /*
+ * Send a proceeding event to the transfer call.
+ *
+ * The proceeding event will end the other call
+ * and answer the current call.
+ *
+ */
+ cc_int_proceeding(CC_SRC_GSM, CC_SRC_GSM, dcb->call_id,
+ dcb->line, &(dcb->caller_id));
+ }
+
+ cc_int_setup_ack(CC_SRC_GSM, CC_SRC_SIP, dcb->call_id, dcb->line,
+ &(dcb->caller_id), NULL);
+
+ FSM_SET_FLAGS(dcb->msgs_sent, FSMDEF_MSG_SETUP_ACK);
+
+
+
+ cc_int_proceeding(CC_SRC_GSM, CC_SRC_SIP, dcb->call_id, dcb->line,
+ &(dcb->caller_id));
+
+ FSM_SET_FLAGS(dcb->msgs_sent, FSMDEF_MSG_PROCEEDING);
+
+
+ alerting = fsmdef_extract_join_target(event);
+
+ /*
+ * This might be the transfer call from the transferee to the target.
+ * In such a case we want this new call to match the state of the call
+ * that it is replacing.
+ */
+ if (xcb != NULL) {
+ other_fcb = fsm_get_fcb_by_call_id_and_type(other_call_id,
+ FSM_TYPE_DEF);
+ if (other_fcb && (other_fcb->old_state == FSMDEF_S_CONNECTED ||
+ other_fcb->old_state == FSMDEF_S_CONNECTED_MEDIA_PEND ||
+ other_fcb->old_state == FSMDEF_S_RESUME_PENDING ||
+ other_fcb->state == FSMDEF_S_CONNECTED ||
+ other_fcb->state == FSMDEF_S_CONNECTED_MEDIA_PEND ||
+ other_fcb->state == FSMDEF_S_RESUME_PENDING)) {
+ alerting = FALSE;
+ }
+ }
+
+
+ if (alerting == TRUE) {
+ /*
+ * set the call priority in lcb. This is used by ringer logic.
+ */
+ if ((msg->call_info.type == CC_FEAT_CALLINFO) &&
+ (msg->call_info.data.call_info_feat_data.priority == CC_CALL_PRIORITY_URGENT)) {
+ lsm_set_lcb_call_priority(call_id);
+ }
+ if ((msg->call_info.type == CC_FEAT_CALLINFO) &&
+ (msg->call_info.data.call_info_feat_data.dusting == TRUE)) {
+ lsm_set_lcb_dusting_call(call_id);
+ }
+
+ cc_call_state(dcb->call_id, dcb->line, CC_STATE_ALERTING,
+ FSMDEF_CC_CALLER_ID);
+ /*
+ * Currently we do not send SDP in the 180 response.
+ */
+ cc_int_alerting(CC_SRC_GSM, CC_SRC_SIP, dcb->call_id, dcb->line,
+ &(dcb->caller_id), NULL, FALSE);
+
+ /* update callref */
+ if ( dcb->callref == 0 ) {
+ dcb->callref = msg->call_info.data.call_info_feat_data.callref;
+ ui_update_callref(dcb->line, dcb->call_id, msg->call_info.data.call_info_feat_data.callref);
+ }
+ /* update gcid */
+ ui_update_gcid(dcb->line, dcb->call_id, msg->call_info.data.call_info_feat_data.global_call_id);
+ /*
+ * store the gcid lcb, this is used to prevent short ringing
+ * in scenarios where a call is routed to the calling phone.
+ */
+ lsm_update_gcid(dcb->call_id, msg->call_info.data.call_info_feat_data.global_call_id);
+ }
+
+ ui_cc_capability(dcb->line, lsm_get_ui_id(dcb->call_id), msg->recv_info_list);
+
+ FSM_SET_FLAGS(dcb->msgs_sent, FSMDEF_MSG_ALERTING);
+
+ fsm_change_state(fcb, __LINE__, FSMDEF_S_INCOMING_ALERTING);
+
+ return (SM_RC_END);
+}
+
+
+sm_rcs_t
+fsmdef_dialstring (fsm_fcb_t *fcb, const char *dialstring,
+ cc_redirect_t *redirect, boolean replace,
+ cc_call_info_t *call_info)
+{
+ static const char fname[] = "fsmdef_dialstring";
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ cc_causes_t cause;
+ cc_msgbody_info_t msg_body;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ if (dialstring) {
+ if (strlen(dialstring) > MAX_SIP_URL_LENGTH) {
+ FSM_DEBUG_SM(DEB_F_PREFIX"Dial string too long\n", DEB_F_PREFIX_ARGS(FSM, fname));
+ /* Force clean up call without sending release */
+ return (fsmdef_release(fcb, CC_CAUSE_INVALID_NUMBER, FALSE));
+ }
+ }
+
+ /*
+ * If there is active feature which is waiting for digit collection
+ * then use service URI preceded with dialed number.
+ */
+ switch (dcb->active_feature) {
+
+ case CC_FEATURE_CFWD_ALL:
+ fsmdef_append_dialstring_to_feature_uri(dcb, dialstring);
+ break;
+
+ default:
+ if (dialstring) {
+ dcb->caller_id.called_number =
+ strlib_update(dcb->caller_id.called_number, dialstring);
+ }
+ break;
+ }
+
+ cause = gsmsdp_create_local_sdp(dcb, FALSE, TRUE, TRUE, TRUE, TRUE);
+ if (cause != CC_CAUSE_OK) {
+ FSM_DEBUG_SM(get_debug_string(FSM_DBG_SDP_BUILD_ERR));
+ /* Force clean up call without sending release */
+ return (fsmdef_release(fcb, cause, FALSE));
+ }
+
+ /* Build SDP for sending out */
+ cause = gsmsdp_encode_sdp_and_update_version(dcb, &msg_body);
+ if (cause != CC_CAUSE_OK) {
+ FSM_DEBUG_SM(get_debug_string(FSM_DBG_SDP_BUILD_ERR));
+ /* Force clean up call without sending release */
+ return (fsmdef_release(fcb, cause, FALSE));
+ }
+
+ /*
+ * Since we are sending setup to UI we will also have to send
+ * release to it to for sip stack to clean up the call
+ */
+ dcb->send_release = TRUE;
+
+ /*
+ * lsm_parse_displaystr will free present called number and return
+ * pointer to parsed called number
+ */
+ dcb->caller_id.called_number =
+ lsm_parse_displaystr(dcb->caller_id.called_number);
+
+ /* set default orientation for outgoing call */
+ dcb->orientation = CC_ORIENTATION_TO;
+ dcb->inbound = FALSE;
+
+ /*
+ * Invoke cc_call_state with modified caller_id for features such as
+ * pickups
+ */
+ fsmdef_set_call_info_cc_call_state(dcb, CC_STATE_DIALING_COMPLETED, CC_CAUSE_MIN);
+
+ FSM_SET_FLAGS(dcb->msgs_sent, FSMDEF_MSG_SETUP);
+
+ fsmdef_set_call_info_cc_call_state(dcb, CC_STATE_CALL_SENT, CC_CAUSE_MIN);
+
+ /*
+ * Send setup or INVITE out after finishing all UI activities and media
+ * preparation. This is done as the final step in order to minimize
+ * UI activities/media activities to run concurrently while processing
+ * the response from the network. On the platform that uses Java VM to
+ * support UI and media, the time to process the UI and media activities
+ * may take longer than the network response time to the INVITE (such as
+ * voice mail case) and JNI calls may be blocked while invoking the
+ * UI or media calls in the LSM.
+ */
+ cc_int_setup(CC_SRC_GSM, CC_SRC_SIP, dcb->call_id, dcb->line,
+ &(dcb->caller_id), dcb->alert_info, VCM_INSIDE_RING,
+ VCM_INSIDE_DIAL_TONE, redirect, call_info, replace, NULL, &msg_body);
+ fsm_change_state(fcb, __LINE__, FSMDEF_S_CALL_SENT);
+
+ return (SM_RC_END);
+}
+
+
+static sm_rcs_t
+fsmdef_ev_dialstring (sm_event_t *event)
+{
+ sm_rcs_t sm_rc;
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ // handle dialstring event if from callfwdall
+ if (fsmdef_process_dialstring_for_callfwd(event) == SM_RC_END) {
+ // release the call started to collect callfwd info
+ dcb->send_release = FALSE;
+ return (fsmdef_release(fcb, CC_CAUSE_NORMAL, dcb->send_release));
+ }
+
+ sm_rc = fsmdef_dialstring(fcb, ((cc_dialstring_t *)event->msg)->dialstring,
+ NULL, FALSE, NULL);
+
+ return (sm_rc);
+}
+
+
+/**
+ * fsmdef_ev_createoffer
+ *
+ * Generates Offer SDP
+ *
+ */
+static sm_rcs_t
+fsmdef_ev_createoffer (sm_event_t *event) {
+ // sm_rcs_t sm_rc;
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ cc_causes_t cause = CC_CAUSE_NORMAL;
+ cc_msgbody_info_t msg_body;
+ cc_feature_t *msg = (cc_feature_t *) event->msg;
+ line_t line = msg->line;
+ callid_t call_id = msg->call_id;
+ // cc_causes_t lsm_rc;
+ int sdpmode = 0;
+ char *ufrag = NULL;
+ char *ice_pwd = NULL;
+ short vcm_res;
+ session_data_t *sess_data_p = NULL;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
+ if (!sdpmode) {
+ /* Force clean up call without sending release */
+ return (fsmdef_release(fcb, cause, FALSE));
+ }
+
+ if (dcb == NULL) {
+ FSM_DEBUG_SM(DEB_F_PREFIX"dcb is NULL.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+ return SM_RC_CLEANUP;
+ }
+
+ if (msg->data.session.has_constraints) {
+ sess_data_p = (session_data_t *)findhash(msg->data.session.sessionid);
+ if (sess_data_p) {
+ gsmsdp_process_cap_constraints(dcb, sess_data_p->cc_constraints);
+
+ if (0 > delhash(msg->data.session.sessionid)) {
+ FSM_DEBUG_SM (DEB_F_PREFIX"failed to delete hash sessid=0x%08x\n",
+ DEB_F_PREFIX_ARGS(SIP_CC_PROV, __FUNCTION__), msg->data.session.sessionid);
+ }
+ cpr_free(sess_data_p);
+ }
+ }
+
+ vcmGetIceParams(dcb->peerconnection, &ufrag, &ice_pwd);
+ if (!ufrag || !ice_pwd) {
+ ui_create_offer(evCreateOfferError, line, call_id, dcb->caller_id.call_instance_id, NULL);
+ return (fsmdef_release(fcb, cause, FALSE));
+ }
+
+ dcb->ice_ufrag = (char *)cpr_malloc(strlen(ufrag) + 1);
+ if (!dcb->ice_ufrag)
+ return SM_RC_END;
+
+ sstrncpy(dcb->ice_ufrag, ufrag, strlen(ufrag) + 1);
+ free(ufrag);
+
+
+ dcb->ice_pwd = (char *)cpr_malloc(strlen(ice_pwd) + 1);
+ if (!dcb->ice_pwd)
+ return SM_RC_END;
+
+ sstrncpy(dcb->ice_pwd, ice_pwd, strlen(ice_pwd) + 1);
+ free(ice_pwd);
+
+ vcm_res = vcmGetDtlsIdentity(dcb->peerconnection,
+ dcb->digest_alg, FSMDEF_MAX_DIGEST_ALG_LEN,
+ dcb->digest, FSMDEF_MAX_DIGEST_LEN);
+
+ if (vcm_res) {
+ FSM_DEBUG_SM(DEB_F_PREFIX"vcmGetDtlsIdentity returned an error\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+ return SM_RC_END;
+ }
+
+ cause = gsmsdp_create_local_sdp(dcb, FALSE, TRUE, TRUE, TRUE, TRUE);
+ if (cause != CC_CAUSE_OK) {
+ ui_create_offer(evCreateOfferError, line, call_id, dcb->caller_id.call_instance_id, NULL);
+ FSM_DEBUG_SM(get_debug_string(FSM_DBG_SDP_BUILD_ERR));
+ return (fsmdef_release(fcb, cause, FALSE));
+ }
+
+ cause = gsmsdp_encode_sdp_and_update_version(dcb, &msg_body);
+ if (cause != CC_CAUSE_OK) {
+ ui_create_offer(evCreateOfferError, line, call_id, dcb->caller_id.call_instance_id, NULL);
+ FSM_DEBUG_SM(get_debug_string(FSM_DBG_SDP_BUILD_ERR));
+ return (fsmdef_release(fcb, cause, FALSE));
+ }
+
+ /* Pass offer SDP back to UI */
+ ui_create_offer(evCreateOffer, line, call_id, dcb->caller_id.call_instance_id, msg_body.parts[0].body);
+
+ return (SM_RC_END);
+}
+
+
+/**
+ * fsmdef_ev_createanswer
+ *
+ * Generates Answer SDP
+ *
+ */
+static sm_rcs_t
+fsmdef_ev_createanswer (sm_event_t *event) {
+ // sm_rcs_t sm_rc;
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ cc_feature_t *msg = (cc_feature_t *) event->msg;
+ cc_causes_t cause = CC_CAUSE_NORMAL;
+ cc_msgbody_info_t msg_body;
+ line_t line = msg->line;
+ callid_t call_id = msg->call_id;
+ // line_t free_line;
+ int sdpmode = 0;
+ // const char *called_number = "1234";
+ // cc_causes_t lsm_rc;
+ // cc_msgbody_t *part;
+ // uint32_t body_length;
+ char *ufrag = NULL;
+ char *ice_pwd = NULL;
+ short vcm_res;
+ session_data_t *sess_data_p;
+ boolean has_audio;
+ boolean has_video;
+ boolean has_data;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
+ if (!sdpmode) {
+ return (fsmdef_release(fcb, cause, FALSE));
+ }
+
+ if (dcb == NULL) {
+ FSM_DEBUG_SM(DEB_F_PREFIX"dcb is NULL.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+ return SM_RC_CLEANUP;
+ }
+
+ if (msg->data.session.has_constraints) {
+ sess_data_p = (session_data_t *)findhash(msg->data.session.sessionid);
+ if (sess_data_p) {
+ gsmsdp_process_cap_constraints(dcb, sess_data_p->cc_constraints);
+
+ if (0 > delhash(msg->data.session.sessionid)) {
+ FSM_DEBUG_SM (DEB_F_PREFIX"failed to delete hash sessid=0x%08x\n",
+ DEB_F_PREFIX_ARGS(SIP_CC_PROV, __FUNCTION__), msg->data.session.sessionid);
+ }
+ cpr_free(sess_data_p);
+ }
+ }
+
+ vcmGetIceParams(dcb->peerconnection, &ufrag, &ice_pwd);
+ if (!ufrag || !ice_pwd) {
+ ui_create_offer(evCreateAnswerError, line, call_id, dcb->caller_id.call_instance_id, NULL);
+ return (fsmdef_release(fcb, cause, FALSE));
+ }
+
+ dcb->ice_ufrag = (char *)cpr_malloc(strlen(ufrag) + 1);
+ if (!dcb->ice_ufrag)
+ return SM_RC_END;
+
+ sstrncpy(dcb->ice_ufrag, ufrag, strlen(ufrag) + 1);
+ free(ufrag);
+
+
+ dcb->ice_pwd = (char *)cpr_malloc(strlen(ice_pwd) + 1);
+ if (!dcb->ice_pwd)
+ return SM_RC_END;
+
+ sstrncpy(dcb->ice_pwd, ice_pwd, strlen(ice_pwd) + 1);
+ free(ice_pwd);
+
+ vcm_res = vcmGetDtlsIdentity(dcb->peerconnection,
+ dcb->digest_alg, FSMDEF_MAX_DIGEST_ALG_LEN,
+ dcb->digest, FSMDEF_MAX_DIGEST_LEN);
+
+ if (vcm_res) {
+ FSM_DEBUG_SM(DEB_F_PREFIX"vcmGetDtlsIdentity returned an error\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+ return SM_RC_END;
+ }
+
+ /*
+ * Determine what media types are offered, used to create matching local SDP
+ * for negotiation.
+ */
+ gsmsdp_get_offered_media_types(fcb, dcb->sdp, &has_audio, &has_video, &has_data);
+
+ /*
+ * The sdp member of the dcb has local and remote sdp
+ * this next function fills in the local part
+ */
+ cause = gsmsdp_create_local_sdp(dcb, FALSE, has_audio, has_video, has_data, FALSE);
+ if (cause != CC_CAUSE_OK) {
+ ui_create_answer(evCreateAnswerError, line, call_id, dcb->caller_id.call_instance_id, NULL);
+ FSM_DEBUG_SM(get_debug_string(FSM_DBG_SDP_BUILD_ERR));
+ // Force clean up call without sending release
+ return (fsmdef_release(fcb, cause, FALSE));
+ }
+
+ /* TODO(ekr@rtfm.com): The second true is because we are acting as if we are
+ processing an offer. The first, however, is for an initial offer and we may
+ want to set that conditionally. */
+ cause = gsmsdp_negotiate_media_lines(fcb, dcb->sdp, TRUE, TRUE, FALSE, TRUE);
+
+ if (cause != CC_CAUSE_OK) {
+ ui_create_answer(evCreateAnswerError, line, call_id, dcb->caller_id.call_instance_id, NULL);
+ return (fsmdef_release(fcb, cause, FALSE));
+ }
+
+ cause = gsmsdp_encode_sdp_and_update_version(dcb, &msg_body);
+ if (cause != CC_CAUSE_OK) {
+ ui_create_answer(evCreateAnswerError, line, call_id, dcb->caller_id.call_instance_id, NULL);
+ FSM_DEBUG_SM(get_debug_string(FSM_DBG_SDP_BUILD_ERR));
+ return (fsmdef_release(fcb, cause, FALSE));
+ }
+
+ /* Pass SDP back to UI */
+ ui_create_answer(evCreateAnswer, line, call_id, dcb->caller_id.call_instance_id, msg_body.parts[0].body);
+
+ return (SM_RC_END);
+}
+
+
+/**
+ * SetLocalDescription
+ *
+ */
+static sm_rcs_t
+fsmdef_ev_setlocaldesc(sm_event_t *event) {
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ cc_feature_t *msg = (cc_feature_t *) event->msg;
+ cc_causes_t cause = CC_CAUSE_NORMAL;
+ cc_msgbody_info_t msg_body;
+ int action = msg->action;
+ // string_t sdp = msg->sdp;
+ int sdpmode = 0;
+ callid_t call_id = msg->call_id;
+ line_t line = msg->line;
+ // cc_causes_t lsm_rc;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
+ if (!sdpmode) {
+ ui_set_local_description(evSetLocalDescError, line, call_id, dcb->caller_id.call_instance_id, NULL, PC_SETLOCALDESCERROR);
+ return (SM_RC_END);
+ }
+
+ if (dcb == NULL) {
+ FSM_DEBUG_SM(DEB_F_PREFIX"dcb is NULL.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+ return SM_RC_CLEANUP;
+ }
+
+ if (JSEP_OFFER == action) {
+ cause = gsmsdp_encode_sdp(dcb->sdp, &msg_body);
+ if (cause != CC_CAUSE_OK) {
+ FSM_DEBUG_SM(get_debug_string(FSM_DBG_SDP_BUILD_ERR));
+ ui_set_local_description(evSetLocalDescError, line, call_id, dcb->caller_id.call_instance_id, NULL, PC_SETLOCALDESCERROR);
+ return (SM_RC_END);
+ }
+
+ /* compare and fail if different:
+ * anant: Why? The JS should be able to modify the SDP. Commenting out for now (same for answer)
+ if (strcmp(msg_body.parts[0].body, msg->sdp) != 0) {
+ ui_set_local_description(evSetLocalDescError, line, call_id, dcb->caller_id.call_instance_id, NULL, PC_SDPCHANGED);
+ return (SM_RC_END);
+ }
+ */
+
+ fsm_change_state(fcb, __LINE__, FSMDEF_S_CALL_SENT);
+
+ } else if (JSEP_ANSWER == action) {
+
+ /* compare SDP generated from CreateAnswer */
+ cause = gsmsdp_encode_sdp(dcb->sdp, &msg_body);
+ if (cause != CC_CAUSE_OK) {
+ FSM_DEBUG_SM(get_debug_string(FSM_DBG_SDP_BUILD_ERR));
+ ui_set_local_description(evSetLocalDescError, line, call_id, dcb->caller_id.call_instance_id, NULL, PC_SETLOCALDESCERROR);
+ return (SM_RC_END);
+ }
+
+ /* compare and fail if different
+ if (strcmp(msg_body.parts[0].body, msg->sdp) != 0) {
+ ui_set_local_description(evSetLocalDescError, line, call_id, dcb->caller_id.call_instance_id, NULL, PC_SDPCHANGED);
+ return (SM_RC_END);
+ }*/
+
+ FSM_SET_FLAGS(dcb->msgs_sent, FSMDEF_MSG_CONNECTED);
+
+
+ cc_call_state(dcb->call_id, dcb->line, CC_STATE_ANSWERED,
+ FSMDEF_CC_CALLER_ID);
+
+ fsm_change_state(fcb, __LINE__, FSMDEF_S_CONNECTING);
+
+ /*
+ * Now that we have negotiated the media, time to set up ICE.
+ * There also needs to be an ICE check in negotiate_media_lines.
+ */
+ cause = gsmsdp_install_peer_ice_attributes(fcb);
+ if (cause != CC_CAUSE_OK) {
+ ui_set_local_description(evSetLocalDescError, line, call_id, dcb->caller_id.call_instance_id, NULL, PC_SDPCHANGED);
+ return (SM_RC_END);
+ }
+
+ /* taken from fsmdef_ev_connected_ack start rx and tx */
+ cc_call_state(dcb->call_id, dcb->line, CC_STATE_CONNECTED,
+ FSMDEF_CC_CALLER_ID);
+ /*
+ * If DSP is not able to start rx/tx channels, release the call
+ */
+ if (dcb->dsp_out_of_resources == TRUE) {
+ cc_call_state(fcb->dcb->call_id, fcb->dcb->line, CC_STATE_UNKNOWN, NULL);
+ return (SM_RC_END);
+ }
+
+ /* we may want to use the functionality in the following method
+ * to handle media capability changes, needs discussion
+ * fsmdef_transition_to_connected(fcb);
+ */
+ fsm_change_state(fcb, __LINE__, FSMDEF_S_CONNECTED);
+
+ }
+
+ ui_set_local_description(evSetLocalDesc, line, call_id, dcb->caller_id.call_instance_id, NULL, PC_OK);
+
+ return (SM_RC_END);
+}
+
+
+/**
+ * SetRemoteDescription
+ *
+ */
+static sm_rcs_t
+fsmdef_ev_setremotedesc(sm_event_t *event) {
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ cc_feature_t *msg = (cc_feature_t *) event->msg;
+ cc_causes_t cause = CC_CAUSE_NORMAL;
+ int action = msg->action;
+ int sdpmode = 0;
+ callid_t call_id = msg->call_id;
+ line_t line = msg->line;
+ // cc_causes_t lsm_rc;
+ cc_msgbody_t *part;
+ uint32_t body_length;
+ cc_msgbody_info_t msg_body;
+ boolean has_audio;
+ boolean has_video;
+ boolean has_data;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
+ if (!sdpmode) {
+ ui_set_remote_description(evSetRemoteDescError, line, call_id,
+ dcb->caller_id.call_instance_id, NULL, PC_SETREMOTEDESCERROR);
+ return (SM_RC_END);
+ }
+
+ if (dcb == NULL) {
+ FSM_DEBUG_SM(DEB_F_PREFIX"dcb is NULL.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+ return SM_RC_CLEANUP;
+ }
+
+ cc_initialize_msg_body_parts_info(&msg_body);
+
+ msg_body.num_parts = 1;
+ msg_body.content_type = cc_content_type_SDP;
+ part = &msg_body.parts[0];
+ body_length = strlen(msg->sdp);
+ part->body = msg->sdp;
+ part->body_length = body_length;
+ part->content_type = cc_content_type_SDP;
+ part->content_disposition.required_handling = FALSE;
+ part->content_disposition.disposition = cc_disposition_session;
+ part->content_id = NULL;
+
+ if (JSEP_OFFER == action) {
+
+ cause = gsmsdp_process_offer_sdp(fcb, &msg_body, TRUE);
+ if (cause != CC_CAUSE_OK) {
+ ui_set_remote_description(evSetRemoteDescError, line, call_id,
+ dcb->caller_id.call_instance_id, NULL, PC_SETREMOTEDESCERROR);
+ return (SM_RC_END);
+ }
+
+ /*
+ * Determine what media types are offered, used to create matching local SDP
+ * for negotiation.
+ */
+ gsmsdp_get_offered_media_types(fcb, dcb->sdp, &has_audio, &has_video, &has_data);
+
+ /*
+ * The sdp member of the dcb has local and remote sdp
+ * this next function fills in the local part
+ */
+ cause = gsmsdp_create_local_sdp(dcb, TRUE, has_audio, has_video, has_data, FALSE);
+ if (cause != CC_CAUSE_OK) {
+ ui_set_remote_description(evSetRemoteDescError, line, call_id, dcb->caller_id.call_instance_id,
+ NULL, PC_SETREMOTEDESCERROR);
+ FSM_DEBUG_SM(get_debug_string(FSM_DBG_SDP_BUILD_ERR));
+ // Force clean up call without sending release
+ return (fsmdef_release(fcb, cause, FALSE));
+ }
+
+ cause = gsmsdp_negotiate_media_lines(fcb, dcb->sdp, TRUE, TRUE, TRUE, FALSE);
+ if (cause != CC_CAUSE_OK) {
+ ui_set_remote_description(evSetRemoteDescError, line, call_id, dcb->caller_id.call_instance_id,
+ NULL, PC_SETREMOTEDESCERROR);
+ return (fsmdef_release(fcb, cause, FALSE));
+ }
+
+ gsmsdp_clean_media_list(dcb);
+
+ fsm_change_state(fcb, __LINE__, FSMDEF_S_INCOMING_ALERTING);
+
+ } else if (JSEP_ANSWER == action) {
+
+ cause = gsmsdp_negotiate_answer_sdp(fcb, &msg_body);
+ if (cause != CC_CAUSE_OK) {
+ ui_set_remote_description(evSetRemoteDescError, line, call_id, dcb->caller_id.call_instance_id,
+ NULL, PC_SETREMOTEDESCERROR);
+ return (SM_RC_END);
+ }
+
+ /*
+ * Now that we have negotiated the media, time to set up ICE.
+ * There also needs to be an ICE check in negotiate_media_lines.
+ */
+ cause = gsmsdp_install_peer_ice_attributes(fcb);
+ if (cause != CC_CAUSE_OK) {
+ ui_set_remote_description(evSetRemoteDescError, line, call_id, dcb->caller_id.call_instance_id,
+ NULL, PC_SETREMOTEDESCERROR);
+ return (SM_RC_END);
+ }
+
+ cc_call_state(dcb->call_id, dcb->line, CC_STATE_CONNECTED, FSMDEF_CC_CALLER_ID);
+
+ /* we may want to use the functionality in the following method
+ * to handle media capability changes, needs discussion
+ * fsmdef_transition_to_connected(fcb);
+ * fsmdef_transition_to_connected(fcb);
+ */
+
+ fsm_change_state(fcb, __LINE__, FSMDEF_S_CONNECTED);
+ }
+
+ ui_set_remote_description(evSetRemoteDesc, line, call_id, dcb->caller_id.call_instance_id, NULL, PC_OK);
+
+ return (SM_RC_END);
+}
+
+
+static sm_rcs_t
+fsmdef_ev_localdesc(sm_event_t *event) {
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ // cc_causes_t cause = CC_CAUSE_NORMAL;
+ int sdpmode = 0;
+ // cc_causes_t lsm_rc;
+ // cc_msgbody_t *part;
+ // uint32_t body_length;
+ // cc_msgbody_info_t msg_body;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
+ if (!sdpmode) {
+ return (SM_RC_END);
+ }
+
+ if (dcb == NULL) {
+ FSM_DEBUG_SM(DEB_F_PREFIX"dcb is NULL.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+ return SM_RC_CLEANUP;
+ }
+
+
+ return (SM_RC_END);
+}
+
+static sm_rcs_t
+fsmdef_ev_remotedesc(sm_event_t *event) {
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ // cc_causes_t cause = CC_CAUSE_NORMAL;
+ int sdpmode = 0;
+ // cc_causes_t lsm_rc;
+ // cc_msgbody_t *part;
+ // uint32_t body_length;
+ // cc_msgbody_info_t msg_body;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
+ if (!sdpmode) {
+
+ return (SM_RC_END);
+ }
+
+ if (dcb == NULL) {
+ FSM_DEBUG_SM(DEB_F_PREFIX"dcb is NULL.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+ return SM_RC_CLEANUP;
+ }
+
+ return (SM_RC_END);
+}
+
+
+static sm_rcs_t
+fsmdef_ev_setpeerconnection(sm_event_t *event) {
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ // cc_causes_t cause = CC_CAUSE_NORMAL;
+ cc_feature_t *msg = (cc_feature_t *) event->msg;
+ callid_t call_id = msg->call_id;
+ int sdpmode = 0;
+ line_t line = msg->line;
+ cc_causes_t lsm_rc;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+ config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
+ if (!sdpmode) {
+ return (SM_RC_END);
+ }
+
+ if (!msg)
+ return SM_RC_END;
+
+ if (!msg->data_valid)
+ return SM_RC_END;
+
+ if (dcb == NULL) {
+ dcb = fsmdef_get_new_dcb(call_id);
+ if (dcb == NULL) {
+ return SM_RC_ERROR;
+ }
+
+ lsm_rc = lsm_get_facility_by_line(call_id, line, FALSE, dcb);
+ if (lsm_rc != CC_CAUSE_OK) {
+ FSM_DEBUG_SM(DEB_F_PREFIX"lsm_get_facility_by_line failed.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+ return SM_RC_END;
+ }
+
+ fsmdef_init_dcb(dcb, call_id, FSMDEF_CALL_TYPE_NONE, NULL, line, fcb);
+
+ fsm_set_fcb_dcbs(dcb);
+ }
+
+ PR_ASSERT(strlen(msg->data.pc.pc_handle) < PC_HANDLE_SIZE);
+ sstrncpy(dcb->peerconnection, msg->data.pc.pc_handle, sizeof(dcb->peerconnection));
+ dcb->peerconnection_set = TRUE;
+
+ return (SM_RC_END);
+}
+
+
+static sm_rcs_t
+fsmdef_ev_addstream(sm_event_t *event) {
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ // cc_causes_t cause = CC_CAUSE_NORMAL;
+ cc_feature_t *msg = (cc_feature_t *) event->msg;
+ int sdpmode = 0;
+ // cc_causes_t lsm_rc;
+ // cc_msgbody_t *part;
+ // uint32_t body_length;
+ // cc_msgbody_info_t msg_body;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
+ if (sdpmode == FALSE) {
+ return (SM_RC_END);
+ }
+
+ if (dcb == NULL) {
+ FSM_DEBUG_SM(DEB_F_PREFIX"dcb is NULL.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+ return SM_RC_CLEANUP;
+ }
+
+ /*
+ * This is temporary code to allow configuration of the two
+ * default streams. When multiple streams > 2 are supported this
+ * will be re-implemented.
+ */
+ if (msg->data.track.media_type == VIDEO) {
+ dcb->media_cap_tbl->cap[CC_VIDEO_1].enabled = TRUE;
+ dcb->media_cap_tbl->cap[CC_VIDEO_1].support_direction = SDP_DIRECTION_SENDRECV;
+ dcb->media_cap_tbl->cap[CC_VIDEO_1].pc_stream = msg->data.track.stream_id;
+ dcb->media_cap_tbl->cap[CC_VIDEO_1].pc_track = msg->data.track.track_id;
+ } else if (msg->data.track.media_type == AUDIO) {
+ dcb->media_cap_tbl->cap[CC_AUDIO_1].enabled = TRUE;
+ dcb->media_cap_tbl->cap[CC_AUDIO_1].support_direction = SDP_DIRECTION_SENDRECV;
+ dcb->media_cap_tbl->cap[CC_AUDIO_1].pc_stream = msg->data.track.stream_id;
+ dcb->media_cap_tbl->cap[CC_AUDIO_1].pc_track = msg->data.track.track_id;
+ } else {
+ return (SM_RC_END);
+ }
+
+ return (SM_RC_END);
+}
+
+static sm_rcs_t
+fsmdef_ev_removestream(sm_event_t *event) {
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ // cc_causes_t cause = CC_CAUSE_NORMAL;
+ cc_feature_t *msg = (cc_feature_t *) event->msg;
+ int sdpmode = 0;
+ // cc_causes_t lsm_rc;
+ // cc_msgbody_t *part;
+ // uint32_t body_length;
+ // cc_msgbody_info_t msg_body;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
+ if (sdpmode == FALSE) {
+
+ return (SM_RC_END);
+ }
+
+ if (dcb == NULL) {
+ FSM_DEBUG_SM(DEB_F_PREFIX"dcb is NULL.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+ return SM_RC_CLEANUP;
+ }
+
+ /*
+ * This is temporary code to allow configuration of the two
+ * default streams. When multiple streams > 2 are supported this
+ * will be re-implemented.
+ */
+ if (msg->data.track.media_type == AUDIO) {
+ dcb->media_cap_tbl->cap[CC_AUDIO_1].enabled = TRUE;
+ dcb->media_cap_tbl->cap[CC_AUDIO_1].support_direction = SDP_DIRECTION_RECVONLY;
+ dcb->video_pref = SDP_DIRECTION_SENDRECV;
+ } else if (msg->data.track.media_type == VIDEO) {
+ dcb->media_cap_tbl->cap[CC_VIDEO_1].enabled = TRUE;
+ dcb->media_cap_tbl->cap[CC_VIDEO_1].support_direction = SDP_DIRECTION_RECVONLY;
+ } else {
+ return (SM_RC_END);
+ }
+
+ return (SM_RC_END);
+}
+
+static sm_rcs_t
+fsmdef_ev_addcandidate(sm_event_t *event) {
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ // cc_causes_t cause = CC_CAUSE_NORMAL;
+ cc_feature_t *msg = (cc_feature_t *) event->msg;
+ int sdpmode = 0;
+ short vcm_res;
+ // uint16_t level;
+
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
+ if (sdpmode == FALSE) {
+
+ return (SM_RC_END);
+ }
+
+ if (dcb == NULL) {
+ FSM_DEBUG_SM(DEB_F_PREFIX"dcb is NULL.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+ return SM_RC_CLEANUP;
+ }
+
+
+ /* Perform level lookup based on mid value */
+ /* comment until mid is properly updated
+ cause = gsmsdp_find_level_from_mid(dcb, (const char *)msg->data.candidate.mid, &level);
+ */
+
+ vcm_res = vcmSetIceCandidate(dcb->peerconnection, (char *)msg->data.candidate.candidate, msg->data.candidate.level);
+ if(vcm_res) {
+ FSM_DEBUG_SM(DEB_F_PREFIX"failure setting ice candidate.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+ }
+
+
+ return (SM_RC_END);
+}
+
+static void
+fsmdef_check_active_feature (fsmdef_dcb_t *dcb, cc_features_t ftr_id)
+{
+ if ((dcb) && (dcb->active_feature != ftr_id)) {
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG_FTR_REQ_ACT),
+ dcb->call_id, dcb->line,
+ cc_feature_name(ftr_id),
+ cc_feature_name(dcb->active_feature));
+ lsm_ui_display_notify(INDEX_STR_KEY_NOT_ACTIVE, NO_FREE_LINES_TIMEOUT);
+ }
+}
+
+static sm_rcs_t
+fsmdef_ev_idle_feature (sm_event_t *event)
+{
+ static const char fname[] = "fsmdef_ev_idle_feature";
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ cc_feature_t *msg = (cc_feature_t *) event->msg;
+ cc_srcs_t src_id = msg->src_id;
+ cc_features_t ftr_id = msg->feature_id;
+ cc_feature_data_t *data = &(msg->data);
+ line_t line = msg->line;
+ cc_causes_t cause = CC_CAUSE_NORMAL;
+ callid_t call_id = fcb->call_id;
+ boolean expline;
+ sm_rcs_t sm_rc = SM_RC_END;
+ fsmcnf_ccb_t *ccb;
+ fsmxfr_xcb_t *xcb;
+ char *global_call_id = NULL;
+
+ fsm_sm_ftr(ftr_id, src_id);
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ switch (src_id) {
+ case CC_SRC_UI:
+ case CC_SRC_GSM:
+ switch (ftr_id) {
+ case CC_FEATURE_UPD_SESSION_MEDIA_CAP:
+ if (dcb) {
+ dcb->video_pref = data->caps.support_direction;
+ }
+ break;
+ case CC_FEATURE_CFWD_ALL:
+ if (fsmdef_is_feature_uri_configured(ftr_id) == FALSE) {
+ fsm_display_feature_unavailable();
+ fsmdef_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ break;
+ }
+
+ // handle cfwd event for ccm and non-ccm cases
+ // process feature event only if no other active feature
+ if ((dcb->active_feature == CC_FEATURE_NONE) &&
+ (fsmdef_get_connected_call() == NULL)) {
+ dcb->active_feature = ftr_id;
+ (void) fsmdef_process_cfwd_softkey_event(event);
+ } else {
+ fsmdef_check_active_feature(dcb, ftr_id);
+ fsmdef_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ }
+ break;
+ case CC_FEATURE_NEW_CALL:
+
+ /* fetch the global_call_id from feature data */
+ global_call_id = data->newcall.global_call_id;
+
+ /*
+ * Set the expanded parameter. This parameter is used when
+ * requesting a free line. A transfer can request that the line
+ * availability be increased by one to account for the third
+ * instance of a line to become available for transfers.
+ */
+ if (data != NULL) {
+ ccb = fsmcnf_get_ccb_by_call_id(call_id);
+ xcb = fsmxfr_get_xcb_by_call_id(call_id);
+ if ((ccb != NULL) || (xcb != NULL)) {
+ expline = TRUE;
+ } else {
+ expline = FALSE;
+ }
+ } else {
+ expline = FALSE;
+ }
+
+ /*
+ * Get a new outgoing call context if we have not already
+ * grabbed one.
+ */
+ if (fcb->dcb == NULL) {
+ cause = fsm_get_new_outgoing_call_context(call_id, line, fcb,
+ expline);
+ switch (cause) {
+ case CC_CAUSE_OK:
+ break;
+
+ case CC_CAUSE_NO_RESOURCE:
+ GSM_ERR_MSG("%s No Resource! Return SM_RC_CLEANUP.", fname);
+ return (SM_RC_CLEANUP);
+
+ default:
+ /*
+ * No free lines.
+ */
+ fsm_display_no_free_lines();
+
+ /*
+ * Send an endcall message. This behaviour is different
+ * than an offhook or line event because the new_call
+ * feature may have been generated by a transfer (as the
+ * consultation call) and will need this end_call message
+ * so that it can cleanup the transfer. The offhook can
+ * only come from the UI so it can just be cleaned up here
+ * without regard for a transfer.
+ */
+ fsmdef_end_call(fcb->dcb, cause);
+
+ return (SM_RC_END);
+ }
+
+ dcb = fcb->dcb;
+ /*
+ * Let Dialog Manager know that there is OFFHOOK event
+ */
+ fsmdef_notify_hook_event(fcb, CC_MSG_OFFHOOK, global_call_id,
+ data->newcall.prim_call_id,
+ data->newcall.hold_resume_reason,
+ CC_MONITOR_NONE,CFWDALL_NONE);
+ }
+
+
+ /*
+ * The user is attempting to start a new call on a specific line:
+ * 1. need to place the connected call (if there is one) on hold,
+ * 2. clear any outgoing ringing calls,
+ * 3. initiate this call.
+ */
+ if (fsmdef_wait_to_start_new_call(TRUE, CC_SRC_GSM, call_id, line,
+ ftr_id, data)) {
+ return (SM_RC_END);
+ }
+
+ //lsm_set_active_call_id(call_id);
+
+ cc_call_state(dcb->call_id, dcb->line, CC_STATE_OFFHOOK,
+ FSMDEF_CC_CALLER_ID);
+
+ if ( data->newcall.cause == CC_CAUSE_CONF ||
+ data->newcall.cause == CC_CAUSE_XFER_LOCAL ) {
+ /* suppress stutter dial tone for conf and transfer features */
+ fsmdef_call_cc_state_dialing(dcb, TRUE);
+ } else {
+ fsmdef_call_cc_state_dialing(dcb, FALSE);
+ }
+
+ switch (data->newcall.cause) {
+ case CC_CAUSE_XFER_REMOTE:
+ /*
+ * This newcall feature is really the consultation part of
+ * a local transfer that has been transferred by the
+ * consultation call, so proceed as though this is a
+ * dialstring call since we already have the called_number.
+ */
+ if (data->newcall.redirect.redirects[0].number[0] != '\0') {
+ sm_rc = fsmdef_dialstring(fcb, data->newcall.dialstring,
+ &(data->newcall.redirect), FALSE,
+ NULL);
+
+ } else if (data->newcall.redirect.redirects[0].redirect_reason
+ == CC_REDIRECT_REASON_DEFLECTION) {
+ /*
+ * CC_REDIRECT_REASON_DEFLECTION shows that transferee is
+ * going to initiate a new call for replacing the call leg
+ * between transferor and target.
+ */
+
+ memset(data->newcall.redirect.redirects[0].number, 0,
+ sizeof(CC_MAX_DIALSTRING_LEN));
+ sm_rc = fsmdef_dialstring(fcb, data->newcall.dialstring,
+ &(data->newcall.redirect), FALSE,
+ NULL);
+
+ } else {
+ sm_rc =
+ fsmdef_dialstring(fcb, data->newcall.dialstring, NULL,
+ FALSE, NULL);
+ }
+
+ return (sm_rc);
+
+ case CC_CAUSE_REDIRECT:
+ sm_rc = fsmdef_dialstring(fcb, data->newcall.dialstring,
+ &(data->newcall.redirect), FALSE,
+ NULL);
+ return (sm_rc);
+
+ case CC_CAUSE_XFER_BY_REMOTE:
+
+ /* CC_REDIRECT_REASON_DEFLECTION shows that transferee is
+ * going to initiate a new call for replacing the call leg
+ * between transferor and target.
+ */
+
+ memset(data->newcall.redirect.redirects[0].number, 0,
+ sizeof(CC_MAX_DIALSTRING_LEN));
+ sm_rc = fsmdef_dialstring(fcb, data->newcall.dialstring,
+ &(data->newcall.redirect), FALSE,
+ NULL);
+ return (sm_rc);
+
+ default:
+ fsm_change_state(fcb, __LINE__, FSMDEF_S_COLLECT_INFO);
+
+ return (SM_RC_END);
+ }
+
+ case CC_FEATURE_END_CALL:
+ cause = fsmdef_get_cause(msg->data_valid, data);
+
+ /*
+ * There has to be a dcb to process this event.
+ */
+ if (fcb->dcb == NULL) {
+ // commented out following line due to klocwork error
+ // call is dereferencing fcb->dcb when it is NULL (sorry, can't do that!)
+ // cc_call_state(fcb->dcb->call_id, fcb->dcb->line, CC_STATE_UNKNOWN, NULL);
+ return (SM_RC_CLEANUP);
+ }
+
+ if (dcb->call_type == FSMDEF_CALL_TYPE_INCOMING ||
+ dcb->call_type == FSMDEF_CALL_TYPE_FORWARD) {
+ dcb->send_release = TRUE;
+ }
+
+ return (fsmdef_release(fcb, cause, dcb->send_release));
+
+ default:
+ fsmdef_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+
+ break;
+ }
+ break;
+
+ default:
+ fsmdef_sm_ignore_src(fcb, __LINE__, src_id);
+
+ } /* switch (src_id) { */
+
+ return (sm_rc);
+}
+
+sm_rcs_t
+fsmdef_offhook (fsm_fcb_t *fcb, cc_msgs_t msg_id, callid_t call_id,
+ line_t line, const char *dial_string,
+ sm_event_t *event, char *global_call_id,
+ callid_t prim_call_id, cc_hold_resume_reason_e consult_reason,
+ monitor_mode_t monitor_mode)
+{
+ boolean wait = FALSE;
+ boolean wait2 = FALSE;
+ boolean wait3 = FALSE;
+ cc_causes_t cause;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ /*
+ * Get a new outgoing call context if we have not already
+ * grabbed one.
+ */
+ if (fcb->dcb == NULL) {
+ cause = fsm_get_new_outgoing_call_context(call_id, line, fcb, FALSE);
+ switch (cause) {
+ case CC_CAUSE_OK:
+ break;
+
+ default:
+ /*
+ * No free lines
+ */
+ fsm_display_no_free_lines();
+
+ if (fsmdef_get_connected_call() != NULL) {
+ lsm_speaker_mode(ON);
+ } else {
+ lsm_speaker_mode(OFF);
+ }
+ return (SM_RC_CLEANUP);
+ }
+
+ /*
+ * Let Dialog Manager know that there is OFFHOOK event
+ */
+ fsmdef_notify_hook_event(fcb, CC_MSG_OFFHOOK, global_call_id,
+ prim_call_id, consult_reason, monitor_mode,CFWDALL_NONE);
+ }
+
+
+ /*
+ * The user is attempting to start a new call on a specific line:
+ * 1. need to place the connected call (if there is one) on hold,
+ * 2. clear any outgoing ringing calls, or calls are in reorder/busy state
+ * 3. initiate this call.
+ */
+ fsmdef_find_and_hold_connected_call(call_id, &wait, CC_SRC_GSM);
+
+ fsmdef_find_and_handle_ring_connecting_releasing_calls(call_id, &wait2);
+
+ fsmdef_clear_preserved_calls(&wait3);
+
+ /*
+ * Requeue the message if we need to wait for the connected line to
+ * hold
+ */
+ if ((wait == TRUE) || (wait2 == TRUE) || (wait3 == TRUE)) {
+ switch (msg_id) {
+ case CC_MSG_OFFHOOK:
+ cc_int_offhook(CC_SRC_GSM, CC_SRC_GSM, prim_call_id, consult_reason,
+ call_id, line, global_call_id, monitor_mode,CFWDALL_NONE);
+ break;
+
+ case CC_MSG_LINE:
+ cc_int_line(CC_SRC_GSM, CC_SRC_GSM, call_id, line);
+ break;
+
+ case CC_MSG_DIALSTRING:
+ cc_int_dialstring(CC_SRC_GSM, CC_SRC_GSM, call_id, line,
+ dial_string, global_call_id, monitor_mode);
+ break;
+
+ case CC_MSG_FEATURE:
+ if (dial_string != NULL) {
+ cc_int_dialstring(CC_SRC_GSM, CC_SRC_GSM, call_id, line,
+ dial_string, global_call_id, monitor_mode);
+ break;
+ }
+
+ /*FALLTHROUGH*/
+ default:
+ cc_call_state(fcb->dcb->call_id, fcb->dcb->line, CC_STATE_UNKNOWN,
+ NULL);
+ return (SM_RC_CLEANUP);
+ }
+
+ return (SM_RC_END);
+ }
+
+ //lsm_set_active_call_id(call_id);
+
+ return (SM_RC_SUCCESS);
+}
+
+
+static sm_rcs_t
+fsmdef_ev_idle_offhook (sm_event_t *event)
+{
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ cc_offhook_t *msg = (cc_offhook_t *) event->msg;
+ fsmdef_dcb_t *dcb;
+ sm_rcs_t sm_rc;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ sm_rc = fsmdef_offhook(fcb, msg->msg_id, msg->call_id, msg->line, NULL,
+ event, msg->global_call_id, msg->prim_call_id,
+ msg->hold_resume_reason, msg->monitor_mode);
+
+ if (sm_rc != SM_RC_SUCCESS) {
+ return (sm_rc);
+ }
+
+ dcb = fcb->dcb;
+
+ cc_call_state(dcb->call_id, dcb->line, CC_STATE_OFFHOOK,
+ FSMDEF_CC_CALLER_ID);
+
+ fsmdef_call_cc_state_dialing(dcb, FALSE);
+
+ fsm_change_state(fcb, __LINE__, FSMDEF_S_COLLECT_INFO);
+
+ return (SM_RC_END);
+}
+
+
+static sm_rcs_t
+fsmdef_ev_idle_dialstring (sm_event_t *event)
+{
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ cc_dialstring_t *msg = (cc_dialstring_t *) event->msg;
+ fsmdef_dcb_t *dcb;
+ cc_action_data_t data;
+ sm_rcs_t sm_rc;
+ cc_call_info_t call_info;
+ cc_call_info_t *call_info_p = NULL;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ sm_rc = fsmdef_offhook(fcb, msg->msg_id, msg->call_id, msg->line,
+ msg->dialstring, event, msg->g_call_id,
+ CC_NO_CALL_ID, CC_REASON_NONE, msg->monitor_mode);
+
+ if (sm_rc != SM_RC_SUCCESS) {
+ return (sm_rc);
+ }
+
+ dcb = fcb->dcb;
+
+ if (msg->dialstring) {
+ lsm_set_lcb_dialed_str_flag(dcb->call_id);
+ }
+ cc_call_state(dcb->call_id, dcb->line, CC_STATE_OFFHOOK,
+ FSMDEF_CC_CALLER_ID);
+
+ data.tone.tone = VCM_INSIDE_DIAL_TONE;
+ (void)cc_call_action(dcb->call_id, dcb->line, CC_ACTION_STOP_TONE, &data);
+
+ dcb->send_release = TRUE;
+
+ /* Set call_info with global call_id, sent in the Initcallreq,
+ * If this call is not because Initcallreq, then don't set call_info
+ * Also, if this is a monitor call, add the mode to the call_info
+ */
+ if (msg->g_call_id != NULL) {
+
+ call_info.type = CC_FEAT_INIT_CALL;
+ call_info.data.initcall.monitor_mode = msg->monitor_mode;
+ sstrncpy(call_info.data.initcall.gcid, msg->g_call_id, CC_GCID_LEN);
+
+ call_info_p = &call_info;
+ }
+
+ if ( strncmp(CISCO_BLFPICKUP_STRING, msg->dialstring, strlen(CISCO_BLFPICKUP_STRING)) == 0 ) {
+ dcb->log_disp = CC_CALL_LOG_DISP_RCVD;
+ }
+
+ sm_rc = fsmdef_dialstring(fcb, msg->dialstring, NULL, FALSE, call_info_p);
+
+ return (sm_rc);
+}
+
+static sm_rcs_t
+fsmdef_ev_session_audit (sm_event_t *event)
+{
+ static const char fname[] = "fsmdef_ev_session_audit";
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ cc_audit_sdp_req_t *audit_msg = (cc_audit_sdp_req_t *) event->msg;
+ cc_msgbody_info_t msg_body;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ if (gsmsdp_encode_sdp_and_update_version(dcb, &msg_body) != CC_CAUSE_OK) {
+ /*
+ * Failed to encode our local sdp. Send ack to SIP stack with
+ * no message body. SIP stack will include previously send
+ * SDP in response to session audit request.
+ */
+ FSM_DEBUG_SM(get_debug_string(FSM_DBG_SDP_BUILD_ERR));
+
+ cc_int_audit_sdp_ack(CC_SRC_GSM, CC_SRC_SIP, audit_msg->call_id,
+ audit_msg->line, NULL);
+ } else {
+ cc_int_audit_sdp_ack(CC_SRC_GSM, CC_SRC_SIP, audit_msg->call_id,
+ audit_msg->line, &msg_body);
+ }
+
+ /*
+ * If we are currently performing a spoofed ringout and the current session audit
+ * does not indicate that we should continue to do so, go back to connected state.
+ * But only change to connected state if not locally held.
+ */
+ if (dcb->spoof_ringout_applied &&
+ !dcb->spoof_ringout_requested) {
+
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG_CLR_SPOOF_APPLD),
+ dcb->call_id, dcb->line, fname);
+
+ if ((fcb->state != FSMDEF_S_HOLDING) &&
+ (fcb->state != FSMDEF_S_HOLD_PENDING)) {
+ /*
+ * If is at least one media entry that is not in loally held
+ * then go to connected state.
+ */
+ dcb->spoof_ringout_applied = FALSE;
+ cc_call_state(dcb->call_id, dcb->line, CC_STATE_CONNECTED,
+ FSMDEF_CC_CALLER_ID);
+ }
+ }
+
+ return (SM_RC_SUCCESS);
+}
+
+static sm_rcs_t
+fsmdef_ev_collectinginfo_release (sm_event_t *event)
+{
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ fsmdef_set_call_info_cc_call_state(dcb, CC_STATE_CALL_FAILED, CC_CAUSE_INVALID_NUMBER);
+
+ // Start onhook timer
+ if ( dcb->err_onhook_tmr) {
+ (void) cprDestroyTimer(dcb->err_onhook_tmr);
+ }
+ dcb->err_onhook_tmr = cprCreateTimer("Error Onhook",
+ GSM_ERROR_ONHOOK_TIMER,
+ TIMER_EXPIRATION,
+ gsm_msg_queue);
+ if (dcb->err_onhook_tmr == NULL) {
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG_TMR_CREATE_FAILED),
+ dcb->call_id, dcb->line, "", "Error Onhook");
+
+ return (SM_RC_CLEANUP);
+ }
+
+ if (cprStartTimer(dcb->err_onhook_tmr,
+ FSMDEF_ERR_ONHOOK_TMR_SECS * 1000,
+ (void *)(long)dcb->call_id) == CPR_FAILURE) {
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG_TMR_START_FAILED),
+ dcb->call_id, dcb->line, "",
+ "Error Onhook", cpr_errno);
+ return (SM_RC_CLEANUP);
+ }
+
+ return (SM_RC_END);
+}
+
+
+static sm_rcs_t
+fsmdef_ev_collectinginfo_feature (sm_event_t *event)
+{
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ cc_feature_t *msg = (cc_feature_t *) event->msg;
+ cc_srcs_t src_id = msg->src_id;
+ cc_features_t ftr_id = msg->feature_id;
+ cc_action_data_t data;
+ sm_rcs_t sm_rc = SM_RC_END;
+ cc_causes_t cause;
+ cc_feature_data_t *feature_data = &(msg->data);
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ fsm_sm_ftr(ftr_id, src_id);
+
+ switch (msg->feature_id) {
+ case CC_FEATURE_UPD_SESSION_MEDIA_CAP:
+ dcb->video_pref = feature_data->caps.support_direction;
+ break;
+ case CC_FEATURE_END_CALL:
+ cause = fsmdef_get_cause(msg->data_valid, &(msg->data));
+ if (fcb->state == FSMDEF_S_KPML_COLLECT_INFO) {
+ /* Clean up and send release */
+ return (fsmdef_release(fcb, cause, TRUE));
+ }
+ else {
+ /* Clean up without sending release */
+ return (fsmdef_release(fcb, cause, FALSE));
+ }
+
+ case CC_FEATURE_NUMBER:
+ case CC_FEATURE_URL:
+ dcb->dial_mode = ((msg->feature_id == CC_FEATURE_NUMBER) ?
+ (DIAL_MODE_NUMERIC) : (DIAL_MODE_URL));
+
+ data.dial_mode.mode = dcb->dial_mode;
+ data.dial_mode.digit_cnt = dcb->digit_cnt;
+ (void)cc_call_action(dcb->call_id, dcb->line, CC_ACTION_DIAL_MODE,
+ &data);
+
+ break;
+
+ case CC_FEATURE_CALLINFO:
+ fsmdef_update_callinfo(fcb, msg);
+ /*
+ * lsm_set_lcb_prevent_ringing() will check if there is a RINGIN call
+ * with the same GCID. If so, it will set a flag to prevent ringing.
+ */
+ lsm_set_lcb_prevent_ringing(dcb->call_id);
+ break;
+
+ case CC_FEATURE_SELECT:
+ fsmdef_select_invoke(dcb, feature_data);
+ return (SM_RC_END);
+
+ case CC_FEATURE_CFWD_ALL:
+ if (fsmdef_is_feature_uri_configured(msg->feature_id) == FALSE) {
+ fsm_set_call_status_feature_unavailable(dcb->call_id, dcb->line);
+
+ fsmdef_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ break;
+ }
+
+ // handle cfwd event for ccm and non-ccm cases
+ // process feature event only if no other active feature
+ if (dcb->active_feature == CC_FEATURE_NONE) {
+ dcb->active_feature = ftr_id;
+ (void) fsmdef_process_cfwd_softkey_event(event);
+ } else {
+ fsmdef_check_active_feature(dcb, ftr_id);
+ fsmdef_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ }
+ break;
+
+ default:
+ dcb->active_feature = CC_FEATURE_NONE;
+ fsmdef_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+
+ break;
+ }
+
+ return (sm_rc);
+}
+
+/*
+ * Function: fsmdef_ev_digit_begin
+ *
+ * Parameters: event
+ *
+ * Description: This function is called each time a digit is
+ * received from the platform code. Currently, the platform code
+ * parses the dialplan. This function simply turns the
+ * dialtone off every time a digit is received and
+ * displays the appropriate keyset. (Eventually, this
+ * interface should be changed and GSM should have
+ * better knowledge of the dialplan.)
+ *
+ * Returns: SM_RC_END
+ */
+static sm_rcs_t
+fsmdef_ev_digit_begin (sm_event_t *event)
+{
+ static const char fname[] = "fsmdef_ev_digit_begin";
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ cc_digit_begin_t *msg = (cc_digit_begin_t *) event->msg;
+ char digit;
+ cc_action_data_t data;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ digit = lsm_digit2ch(msg->digit);
+
+ FSM_DEBUG_SM(DEB_L_C_F_PREFIX"Digit Received= %c: stopping dial tone..\n",
+ DEB_L_C_F_PREFIX_ARGS(FSM, msg->line, msg->call_id, fname), digit);
+ data.tone.tone = VCM_INSIDE_DIAL_TONE;
+ (void)cc_call_action(dcb->call_id, dcb->line, CC_ACTION_STOP_TONE, &data);
+
+ /*
+ * Increment digit_cnt so that the proper keyset will be
+ * displayed.
+ */
+ if (dcb->digit_cnt < CC_MAX_DIALSTRING_LEN) {
+ dcb->digit_cnt++;
+ }
+
+ return (SM_RC_END);
+}
+
+
+static sm_rcs_t
+fsmdef_ev_proceeding (sm_event_t *event)
+{
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+
+ fcb->dcb->send_release = TRUE;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+#ifdef SAPP_SAPP_GSM
+ if ((event->msg != NULL) &&
+ (((cc_proceeding_t *)(event->msg))->caller_id.called_name != NULL)) {
+ dcb->caller_id.called_name =
+ strlib_update(dcb->caller_id.called_name,
+ ((cc_proceeding_t *) (event->msg))->caller_id.
+ called_name);
+ }
+#endif
+
+ cc_call_state(dcb->call_id, dcb->line, CC_STATE_FAR_END_PROCEEDING,
+ FSMDEF_CC_CALLER_ID);
+
+
+ fsm_change_state(fcb, __LINE__, FSMDEF_S_OUTGOING_PROCEEDING);
+
+ return (SM_RC_END);
+}
+
+static sm_rcs_t
+fsmdef_ev_out_alerting (sm_event_t *event)
+{
+ static const char fname[] = "fsmdef_ev_out_alerting";
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ cc_alerting_t *msg = (cc_alerting_t *) event->msg;
+ cc_causes_t cause = CC_CAUSE_ERROR;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ dcb->send_release = TRUE;
+
+ dcb->inband = FALSE;
+ if (msg->inband) {
+ dcb->inband = TRUE;
+
+ cause = gsmsdp_negotiate_answer_sdp(fcb, &msg->msg_body);
+ if (cause != CC_CAUSE_OK) {
+ cc_call_state(fcb->dcb->call_id, fcb->dcb->line, CC_STATE_UNKNOWN,
+ NULL);
+ return (fsmdef_release(fcb, cause, dcb->send_release));
+ }
+
+ /*
+ * Record fact that we have successfully negotiated media that may be
+ * used for inband ringback.
+ */
+ dcb->inband_received = TRUE;
+ FSM_DEBUG_SM(DEB_F_PREFIX"inband_received, cancel timer.\n", DEB_F_PREFIX_ARGS(FSM, fname));
+
+ /*
+ * If ringback delay timer has been started, cancel it now.
+ */
+ if (cprCancelTimer(dcb->ringback_delay_tmr) != CPR_SUCCESS) {
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG_TMR_CANCEL_FAILED),
+ dcb->call_id, dcb->line, fname, "Ringback Delay",
+ cpr_errno);
+ }
+ } else {
+ /*
+ * Not inband alerting case. Set ringback delay timer so that local
+ * ringback will eventually be played. We delay the ringback for
+ * a short time to handle the case where the messages key was pressed.
+ * This is because VM server can respond very quickly with RTP, 183,
+ * and 200 and we do not want local ringback tone to interfere with
+ * the playing of the VM prompt.
+ */
+ if (!cprIsTimerRunning(dcb->ringback_delay_tmr)) {
+ fsmdef_set_ringback_delay_timer(dcb);
+ }
+ }
+
+ cc_call_state(dcb->call_id, dcb->line, CC_STATE_FAR_END_ALERTING,
+ FSMDEF_CC_CALLER_ID);
+
+ /*
+ * If DSP is not able to start rx/tx channels, release the call
+ */
+ if (dcb->dsp_out_of_resources == TRUE) {
+ (void)fsmdef_release(fcb, CC_CAUSE_NO_MEDIA, dcb->send_release);
+ cc_call_state(fcb->dcb->call_id, fcb->dcb->line, CC_STATE_UNKNOWN,
+ NULL);
+ return (SM_RC_END);
+ }
+// fsmdef_update_pd(dcb, FSMDEF_CALL_TYPE_OUTGOING);
+
+ fsm_change_state(fcb, __LINE__, FSMDEF_S_OUTGOING_ALERTING);
+
+ return (SM_RC_END);
+}
+
+static sm_rcs_t
+fsmdef_ev_callsent_release (sm_event_t *event)
+{
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ cc_release_t *msg = (cc_release_t *) event->msg;
+ cc_causes_t cause = msg->cause;
+ cc_srcs_t src_id = msg->src_id;
+ sm_rcs_t sm_rc = SM_RC_END;
+ char tmp_str[STATUS_LINE_MAX_LEN];
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ /* if UI_STATE of BUSY in 183 Call-Info is causing the release,
+ do not modify dcb->send_release */
+ if (cause != CC_CAUSE_UI_STATE_BUSY) {
+ dcb->send_release = FALSE;
+ } else {
+ // CSCti63677
+ if ((fcb->state == FSMDEF_S_OUTGOING_ALERTING) &&
+ (dcb->inband_received == TRUE) &&
+ (dcb->placed_call_update_required)) {
+
+ lsm_update_placed_callinfo(dcb);
+ dcb->placed_call_update_required = FALSE;
+ }
+ }
+
+ FSM_SET_FLAGS(dcb->msgs_rcvd, FSMDEF_MSG_RELEASE);
+
+ /* For 500 response from the CCM, disconnect the call and clear the UI.
+ * There are several cases in which CCM sends down 500 response code to
+ * clear the call and UI. Some of the cases are CFWDALL, early conference
+ * and CTI transfer of ringing call
+ *
+ * Non-auto pickups do receive 480 response, it is OK release the call.
+ */
+ if ((cause == CC_CAUSE_REMOTE_SERVER_ERROR) ||
+ (((strncmp(dcb->caller_id.called_number, CISCO_BLFPICKUP_STRING,
+ (sizeof(CISCO_BLFPICKUP_STRING) - 1)) == 0)) &&
+ ((cause == CC_TEMP_NOT_AVAILABLE) || (cause == CC_CAUSE_CONGESTION) ))) {
+ if (cause == CC_CAUSE_CONGESTION) {
+ if (platGetPhraseText(STR_INDEX_NO_CALL_FOR_PICKUP, (char *)tmp_str, STATUS_LINE_MAX_LEN - 1) == CPR_SUCCESS)
+ {
+ ui_set_notification(CC_NO_LINE, CC_NO_CALL_ID, tmp_str, 2, FALSE, DEF_NOTIFY_PRI);
+ }
+ }
+ cause = CC_CAUSE_OK;
+ }
+
+ switch (cause) {
+ case CC_CAUSE_ERROR:
+ case CC_CAUSE_NOT_FOUND:
+ case CC_CAUSE_BUSY:
+ case CC_CAUSE_CONGESTION:
+ case CC_CAUSE_INVALID_NUMBER:
+ case CC_CAUSE_PAYLOAD_MISMATCH:
+ case CC_CAUSE_REMOTE_SERVER_ERROR:
+ case CC_TEMP_NOT_AVAILABLE:
+ case CC_CAUSE_UI_STATE_BUSY:
+ case CC_CAUSE_NO_USER_ANS:
+
+ fsmdef_set_call_info_cc_call_state(dcb, CC_STATE_CALL_FAILED, cause);
+
+ if (cause != CC_CAUSE_UI_STATE_BUSY) {
+ cc_int_release_complete(CC_SRC_GSM, CC_SRC_SIP, dcb->call_id,
+ dcb->line, cause, NULL);
+ }
+ /* see if the SIP stack has aborted this call early for some reason
+ * If SIP brought this down, we are still offhook on the UI, so
+ * when we get the release_complete from the 200 for the BYE, we
+ * need to ignore it, so that reorder can be played AND when the user
+ * hangs up, then the UI will be driven to a clean state.
+ */
+ if (src_id == CC_SRC_SIP) {
+ dcb->early_error_release = TRUE;
+ }
+
+ if ( dcb->err_onhook_tmr) {
+ (void) cprDestroyTimer(dcb->err_onhook_tmr);
+ }
+ dcb->err_onhook_tmr = cprCreateTimer("Error Onhook",
+ GSM_ERROR_ONHOOK_TIMER,
+ TIMER_EXPIRATION,
+ gsm_msg_queue);
+ if (dcb->err_onhook_tmr == NULL) {
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG_TMR_CREATE_FAILED),
+ dcb->call_id, dcb->line, "", "Error Onhook");
+ return (SM_RC_CLEANUP);
+ }
+
+ if (cprStartTimer(dcb->err_onhook_tmr,
+ FSMDEF_ERR_ONHOOK_TMR_SECS * 1000,
+ (void *)(long)dcb->call_id) == CPR_FAILURE) {
+
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG_TMR_START_FAILED),
+ dcb->call_id, dcb->line, "",
+ "Error Onhook", cpr_errno);
+
+ return (SM_RC_CLEANUP);
+ }
+
+ break;
+
+ default:
+ sm_rc = fsmdef_release(fcb, cause, dcb->send_release);
+ if (sm_rc == SM_RC_CLEANUP) {
+ /*
+ * FSM release indicates clean up, do not continue
+ * on since fcb and dcb have been freed or re-initialized.
+ */
+ return (sm_rc);
+ }
+ } /* switch (cause) */
+
+ /*UI_STATE of BUSY in 183 is causing the release, so
+ *don't change state. This is needed to support
+ *callback feature. Since the callee is busy, we need
+ *update call UI status to "Busy" from "Ringout" to
+ *reflect this change.
+ */
+ if (cause != CC_CAUSE_UI_STATE_BUSY) {
+ fsm_change_state(fcb, __LINE__, FSMDEF_S_RELEASING);
+ } else {
+ cc_action_data_t action_data;
+ action_data.update_ui.action = CC_UPDATE_SET_CALL_STATUS;
+ action_data.update_ui.data.set_call_status_parms.phrase_str_p = platform_get_phrase_index_str(LINE_BUSY);
+ action_data.update_ui.data.set_call_status_parms.timeout = 0;
+ action_data.update_ui.data.set_call_status_parms.call_id = dcb->call_id;
+ action_data.update_ui.data.set_call_status_parms.line = dcb->line;
+ /*Update UI status to "Busy".*/
+ (void)cc_call_action(dcb->call_id, dcb->line, CC_ACTION_UPDATE_UI,
+ &action_data);
+ }
+
+ return (sm_rc);
+}
+
+
+static sm_rcs_t
+fsmdef_ev_callsent_feature (sm_event_t *event)
+{
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ cc_feature_t *msg = (cc_feature_t *) event->msg;
+ cc_srcs_t src_id = msg->src_id;
+ cc_features_t ftr_id = msg->feature_id;
+ callid_t call_id = msg->call_id;
+ line_t line = msg->line;
+ cc_causes_t cause;
+ cc_feature_data_redirect_t *data = &(msg->data.redirect);
+ cc_action_data_t action_data;
+ cc_feature_data_t *select_data = &(msg->data);
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ fsm_sm_ftr(ftr_id, src_id);
+
+ switch (ftr_id) {
+ case CC_FEATURE_UPD_SESSION_MEDIA_CAP:
+ dcb->video_pref = select_data->caps.support_direction;
+ break;
+ case CC_FEATURE_NOTIFY:
+ if (src_id == CC_SRC_SIP) {
+ fsmdef_ev_notify_feature(msg, dcb);
+ } else {
+ fsmdef_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ }
+
+ break;
+
+ case CC_FEATURE_END_CALL:
+ /**
+ * In case of earlier attandence, there might a waiting call.
+ */
+ lsm_remove_lcb_prevent_ringing(dcb->call_id);
+ /*
+ * Since user press the end call, no need to wait to play the busy tone.
+ * So, clear the early_error_release and clean the fcb/dcb.
+ */
+ dcb->early_error_release = FALSE;
+ cause = fsmdef_get_cause(msg->data_valid, &(msg->data));
+
+ return (fsmdef_release(fcb, cause, dcb->send_release));
+
+ case CC_FEATURE_REDIRECT:
+ /*
+ * The outgoing call has been redirected, so we need to:
+ * 1. ACK the redirect request,
+ * 2. release the current call,
+ * 3. start a new call to the redirect number.
+ */
+ cc_int_feature_ack(CC_SRC_GSM, CC_SRC_SIP, call_id, line,
+ CC_FEATURE_REDIRECT, NULL, CC_CAUSE_REDIRECT);
+ /*
+ * May need to update an xcb if this call is involved in a transfer.
+ */
+ //xcb = fsmxfr_get_xcb_by_call_id(call_id);
+ // fsmxfr_update_xfr_context(xcb, call_id, redirect_call_id);
+ dcb->caller_id.called_number =
+ strlib_update(dcb->caller_id.called_number, data->redirect_number);
+
+ cc_call_state(dcb->call_id, dcb->line, CC_STATE_DIALING_COMPLETED,
+ FSMDEF_CC_CALLER_ID);
+
+ break;
+
+
+ case CC_FEATURE_CALLINFO:
+ fsmdef_update_calltype(fcb, msg);
+ fsmdef_update_callinfo(fcb, msg);
+ /*
+ * lsm_set_lcb_prevent_ringing() will check if there is a RINGIN call
+ * with the same GCID. If so, it will set a flag to prevent ringing.
+ */
+ lsm_set_lcb_prevent_ringing(dcb->call_id);
+ break;
+
+ case CC_FEATURE_UPDATE:
+ /* Simply reply with a 200OK to a received UPDATE */
+ cc_int_feature_ack(CC_SRC_GSM, CC_SRC_SIP, call_id, line,
+ CC_FEATURE_UPDATE, NULL, CC_CAUSE_OK);
+ break;
+
+ case CC_FEATURE_RINGBACK_DELAY_TIMER_EXP:
+ if (!dcb->inband_received) {
+ /*
+ * Ringback delay timer expired and we have not received
+ * a response from the far end indicating that they are
+ * playing inband ringback. Start local ringback tone now.
+ */
+ action_data.tone.tone = VCM_ALERTING_TONE;
+ (void)cc_call_action(call_id, line, CC_ACTION_PLAY_TONE,
+ &action_data);
+ }
+ break;
+
+
+ case CC_FEATURE_SELECT:
+ fsmdef_select_invoke(dcb, select_data);
+ return (SM_RC_END);
+
+
+ case CC_FEATURE_SUBSCRIBE:
+ /* KPML subscription received so collect digits for KPML */
+ fsm_change_state(fcb, __LINE__, FSMDEF_S_KPML_COLLECT_INFO);
+ break;
+
+ case CC_FEATURE_CFWD_ALL:
+ fsm_set_call_status_feature_unavailable(call_id, line);
+
+ fsmdef_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ break;
+
+ default:
+ fsmdef_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ break;
+ } /* switch (ftr_id) { */
+
+ return (SM_RC_END);
+}
+
+
+static sm_rcs_t
+fsmdef_release_call (fsm_fcb_t *fcb, cc_feature_t *msg)
+{
+ cc_feature_data_t *data = &(msg->data);
+ cc_state_data_t state_data;
+ cc_causes_t cause;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ cause = fsmdef_get_cause(msg->data_valid, data);
+
+ /*
+ * Do things a little different depending on the value of the
+ * release cause.
+ */
+ switch (cause) {
+ case CC_CAUSE_XFER_LOCAL:
+ /*
+ * Send release and then wait for the release_complete.
+ */
+ cc_int_release(CC_SRC_GSM, CC_SRC_SIP, dcb->call_id,
+ dcb->line, data->endcall.cause,
+ data->endcall.dialstring, NULL);
+
+ fsm_change_state(fcb, __LINE__, FSMDEF_S_RELEASING);
+
+ state_data.onhook.caller_id = dcb->caller_id;
+ state_data.onhook.local = TRUE;
+ state_data.onhook.cause = CC_CAUSE_NORMAL;
+ cc_call_state(dcb->call_id, dcb->line, CC_STATE_ONHOOK, &state_data);
+
+ break;
+
+ case CC_CAUSE_XFER_REMOTE:
+ /*
+ * No need to send release because the remote end initiated
+ * the transfer.
+ */
+ dcb->send_release = FALSE;
+ return (fsmdef_release(fcb, cause, dcb->send_release));
+
+ case CC_CAUSE_XFER_CNF:
+ case CC_CAUSE_REPLACE:
+ /*
+ * We are the target of a transfer and this is the consultation
+ * call that is being replaced, so we just need to onhook this call
+ * but leave the signaling up until the stack notifies the FSM that
+ * the transfer is accepted - and then we will release the call.
+ * Same has to happen when bridge of conference ends the call. We are
+ * initiating transfer in this case so we want signaling to remain
+ * up while UI should be cleared up.
+ */
+ state_data.onhook.caller_id = dcb->caller_id;
+ state_data.onhook.local = TRUE;
+ state_data.onhook.cause = CC_CAUSE_NORMAL;
+ cc_call_state(dcb->call_id, dcb->line, CC_STATE_ONHOOK, &state_data);
+
+ fsm_change_state(fcb, __LINE__, FSMDEF_S_HOLDING);
+
+ break;
+
+ default:
+ return (fsmdef_release(fcb, cause, dcb->send_release));
+ }
+
+ return (SM_RC_END);
+}
+
+
+static sm_rcs_t
+fsmdef_ev_inalerting_feature (sm_event_t *event)
+{
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ cc_feature_t *msg = (cc_feature_t *) event->msg;
+ cc_srcs_t src_id = msg->src_id;
+ cc_features_t ftr_id = msg->feature_id;
+ callid_t call_id = msg->call_id;
+ line_t line = msg->line;
+ cc_feature_data_t *data = &(msg->data);
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ fsm_sm_ftr(ftr_id, src_id);
+
+ switch (src_id) {
+ case CC_SRC_UI:
+ case CC_SRC_GSM:
+ switch (ftr_id) {
+ case CC_FEATURE_UPD_SESSION_MEDIA_CAP:
+ dcb->video_pref = data->caps.support_direction;
+ /* force an update to media cap */
+ dcb->media_cap_tbl->id--;
+ gsmsdp_update_local_sdp_media_capability(dcb, FALSE, FALSE);
+ break;
+
+ case CC_FEATURE_END_CALL:
+ return (fsmdef_release_call(fcb, msg));
+
+ case CC_FEATURE_ANSWER:
+ /*
+ * The user wants to answer this call, so...
+ * 1. need to place the connected call (if there is one) on hold,
+ * 2. clear all the outgoing ringing lines,
+ * 3. answer this call.
+ */
+ if (fsmdef_wait_to_start_new_call(TRUE, CC_SRC_GSM, dcb->call_id, dcb->line,
+ CC_FEATURE_ANSWER, NULL)) {
+
+ /*
+ * Inform the LSM that the answering of this call has
+ * been delayed while waiting for other calls to clear.
+ */
+ (void)cc_call_action(dcb->call_id, dcb->line,
+ CC_ACTION_ANSWER_PENDING, NULL);
+
+ return (SM_RC_END);
+ }
+
+ return (fsmdef_handle_inalerting_offhook_answer(event));
+
+ default:
+ fsmdef_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+
+ break;
+ } /* switch (ftr_id) { */
+
+ break;
+
+ case CC_SRC_SIP:
+ switch (ftr_id) {
+ case CC_FEATURE_CALLINFO:
+ fsmdef_update_callinfo(fcb, msg);
+ break;
+
+ case CC_FEATURE_UPDATE:
+ /* Simply reply with a 200 OK to a received UPDATE */
+ cc_int_feature_ack(CC_SRC_GSM, CC_SRC_SIP, call_id, line,
+ CC_FEATURE_UPDATE, NULL, CC_CAUSE_OK);
+ break;
+
+ default:
+ fsmdef_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+
+ break;
+ } /* switch (ftr_id) { */
+
+ break;
+
+ default:
+ fsmdef_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+
+ break;
+ } /* switch (src_id) { */
+
+ return (SM_RC_END);
+}
+
+
+/*
+ * This function contains the common code for fsmdef_ev_inalerting_offhook()
+ * and the ANSWER event handling in the fsmdef_ev_inalerting_feature().
+ */
+static sm_rcs_t
+fsmdef_handle_inalerting_offhook_answer (sm_event_t *event)
+{
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ cc_causes_t cause;
+ cc_msgbody_info_t msg_body;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ /* Build our response SDP to include in the connected */
+ cause = gsmsdp_encode_sdp_and_update_version(dcb, &msg_body);
+ if (cause != CC_CAUSE_OK) {
+ FSM_DEBUG_SM(get_debug_string(FSM_DBG_SDP_BUILD_ERR));
+ return (fsmdef_release(fcb, cause, dcb->send_release));
+ }
+
+ /* For CCM, call_type indicate if the call is forwarded or not
+ * for forwarded call display will be shown as "Forward", only
+ * during ringing state. Once the call is connected then the call
+ * is shown as normal incoming call "From". so change call type now
+ * Do this only if Retain Forward Information is disabled or not configured.
+ * If configured/enabled then leave the call type as Forward.
+ */
+
+ if (dcb->call_type == FSMDEF_CALL_TYPE_FORWARD) {
+ if (!fsmdef_check_retain_fwd_info_state()) {
+ dcb->call_type = FSMDEF_CALL_TYPE_INCOMING;
+ /*
+ * Force us to update the UI so that any possible callinfo received
+ * prior to the call is answered takes effect.
+ */
+ dcb->ui_update_required = TRUE;
+ }
+ }
+
+ /* Cancel any existing autoanswer timer */
+ (void)cprCancelTimer(dcb->autoAnswerTimer);
+
+ cc_int_connected(CC_SRC_GSM, CC_SRC_SIP, dcb->call_id, dcb->line,
+ &(dcb->caller_id), NULL, &msg_body);
+
+ FSM_SET_FLAGS(dcb->msgs_sent, FSMDEF_MSG_CONNECTED);
+
+ cc_call_state(dcb->call_id, dcb->line, CC_STATE_ANSWERED,
+ FSMDEF_CC_CALLER_ID);
+
+ fsm_change_state(fcb, __LINE__, FSMDEF_S_CONNECTING);
+
+ return (SM_RC_END);
+}
+
+
+static sm_rcs_t
+fsmdef_ev_inalerting_offhook (sm_event_t *event)
+{
+ return (fsmdef_handle_inalerting_offhook_answer(event));
+}
+
+
+static sm_rcs_t
+fsmdef_ev_connecting_feature (sm_event_t *event)
+{
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ cc_feature_t *msg = (cc_feature_t *) event->msg;
+ cc_srcs_t src_id = msg->src_id;
+ cc_features_t ftr_id = msg->feature_id;
+ cc_causes_t cause;
+ cc_feature_data_t *data = &(msg->data);
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ fsm_sm_ftr(ftr_id, src_id);
+
+ switch (src_id) {
+ case CC_SRC_UI:
+ switch (ftr_id) {
+ case CC_FEATURE_UPD_SESSION_MEDIA_CAP:
+ dcb->video_pref = data->caps.support_direction;
+ break;
+ case CC_FEATURE_END_CALL:
+ cause = fsmdef_get_cause(msg->data_valid, &(msg->data));
+
+ return (fsmdef_release(fcb, cause, dcb->send_release));
+
+ default:
+ fsmdef_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+
+ break;
+ }
+
+ break;
+
+ case CC_SRC_SIP:
+ switch (ftr_id) {
+ case CC_FEATURE_CALLINFO:
+ fsmdef_update_callinfo(fcb, msg);
+ break;
+
+ case CC_FEATURE_CALL_PRESERVATION:
+ return (fsmdef_release(fcb, CC_CAUSE_NORMAL, dcb->send_release));
+
+ case CC_FEATURE_NOTIFY:
+ fsmdef_ev_notify_feature(msg, dcb);
+ break;
+
+ default:
+ fsmdef_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+
+ break;
+ }
+
+ break;
+
+ case CC_SRC_GSM:
+ switch (ftr_id) {
+ case CC_FEATURE_END_CALL:
+ cause = fsmdef_get_cause(msg->data_valid, &(msg->data));
+
+ return (fsmdef_release(fcb, cause, dcb->send_release));
+
+ default:
+ fsmdef_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+
+ break;
+ }
+
+ break;
+
+ default:
+ fsmdef_sm_ignore_src(fcb, __LINE__, src_id);
+
+ break;
+ }
+
+ return (SM_RC_END);
+}
+
+/**
+ *
+ * Function to handle transition to FSMDEF_S_CONNECTED. It checks
+ * whether there is any media capability that needs to be updated
+ * or not. If there is not then it transition to FSMDEF_S_CONNECTED
+ * otherwise it transitions to the FSMDEF_S_CONNECTED_MEDIA_PEND state
+ * and sends out the media update request.
+ *
+ * @param[in] fcb - The pointer to the fsm_fcb_t structure of this
+ * call.
+ *
+ * @return SM_RC_END or SM_RC_CLEANUP
+ *
+ * @pre (fcb not_eq NULL)
+ */
+static sm_rcs_t
+fsmdef_transition_to_connected (fsm_fcb_t *fcb)
+{
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ cc_feature_data_t feature_data;
+ sm_rcs_t sm_rc = SM_RC_END;
+ cc_causes_t cause;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ if (dcb->req_pending_tmr) {
+ /* cancel any request pending timer, just in case */
+ (void) cprCancelTimer(dcb->req_pending_tmr);
+ }
+
+ /*
+ * Update the media capability without effecting the existing media line.
+ */
+ if (!gsmsdp_update_local_sdp_media_capability(dcb, FALSE, FALSE)) {
+ /* not thing is changed, transition to connected state */
+ fsm_change_state(fcb, __LINE__, FSMDEF_S_CONNECTED);
+ return (sm_rc);
+ }
+
+
+ feature_data.resume.call_info.type = CC_FEAT_NONE;
+ feature_data.resume.call_info.data.hold_resume_reason = CC_REASON_NONE;
+ feature_data.resume.msg_body.num_parts = 0;
+ feature_data.resume.call_info.data.call_info_feat_data.swap = FALSE;
+ feature_data.resume.call_info.data.call_info_feat_data.protect = FALSE;
+ /* Encode SDP */
+ cause = gsmsdp_encode_sdp_and_update_version(dcb,
+ &feature_data.resume.msg_body);
+ if (cause != CC_CAUSE_OK) {
+ FSM_DEBUG_SM(get_debug_string(FSM_DBG_SDP_BUILD_ERR));
+ return(fsmdef_release(fcb, cause, dcb->send_release));
+ }
+
+ fsmdef_get_rtp_stat(dcb, &(feature_data.resume.kfactor));
+
+ /* Send feature request to SIP */
+ cc_int_feature(CC_SRC_GSM, CC_SRC_SIP, dcb->call_id, dcb->line,
+ CC_FEATURE_MEDIA, &feature_data);
+
+
+ if (g_dock_undock_event == MEDIA_INTERFACE_UPDATE_STARTED) {
+ g_dock_undock_event = MEDIA_INTERFACE_UPDATE_IN_PROCESS;
+ ui_update_media_interface_change(dcb->line, dcb->call_id, MEDIA_INTERFACE_UPDATE_BEGIN);
+ } else if (g_dock_undock_event == MEDIA_INTERFACE_UPDATE_IN_PROCESS) {
+ DEF_DEBUG(DEB_F_PREFIX" MEDIA_INTERFACE_UPDATE is already in process. "
+ " Ignore another update event.\n", DEB_F_PREFIX_ARGS(FSM, "fsmdef_transition_to_connected"));
+ }
+ fsm_change_state(fcb, __LINE__, FSMDEF_S_CONNECTED_MEDIA_PEND);
+ return (sm_rc);
+}
+
+static sm_rcs_t
+fsmdef_ev_connected (sm_event_t *event)
+{
+ static const char fname[] = "fsmdef_ev_connected";
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ cc_connected_t *msg = (cc_connected_t *) event->msg;
+ cc_causes_t cause;
+ sm_rcs_t sm_rc;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ dcb->send_release = TRUE;
+
+ cause = gsmsdp_negotiate_answer_sdp(fcb, &msg->msg_body);
+ if (cause != CC_CAUSE_OK) {
+
+ cc_call_state(fcb->dcb->call_id, fcb->dcb->line, CC_STATE_UNKNOWN,
+ NULL);
+ return (fsmdef_release(fcb, cause, dcb->send_release));
+ }
+
+ // Reset dcb->active_feature flag
+ dcb->active_feature = CC_FEATURE_NONE;
+
+ /* Reset spoof ring out in case t was set before going to connected state. */
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG_CLR_SPOOF_APPLD),
+ dcb->call_id, dcb->line, fname);
+
+ dcb->spoof_ringout_applied = FALSE;
+
+ /*
+ * Cancel ringback delay timer
+ */
+ if (cprCancelTimer(dcb->ringback_delay_tmr) != CPR_SUCCESS) {
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG_TMR_CANCEL_FAILED),
+ dcb->call_id, dcb->line, fname, "Ringback Delay",
+ cpr_errno);
+ }
+
+ cc_call_state(dcb->call_id, dcb->line, CC_STATE_CONNECTED,
+ FSMDEF_CC_CALLER_ID);
+
+ if ( dcb->log_disp != CC_CALL_LOG_DISP_UNKNWN ) {
+ ui_log_disposition(dcb->call_id, dcb->log_disp );
+ }
+
+
+ ui_cc_capability(dcb->line, lsm_get_ui_id(dcb->call_id), msg->recv_info_list);
+
+ /*
+ * If DSP is not able to start rx/tx channels, release the call
+ */
+ if (dcb->dsp_out_of_resources == TRUE) {
+ (void)fsmdef_release(fcb, CC_CAUSE_NO_MEDIA, dcb->send_release);
+ cc_call_state(fcb->dcb->call_id, fcb->dcb->line, CC_STATE_UNKNOWN,
+ NULL);
+ return (SM_RC_END);
+ }
+ cc_int_connected_ack(CC_SRC_GSM, CC_SRC_SIP, dcb->call_id, dcb->line,
+ &(dcb->caller_id), NULL);
+
+ FSM_SET_FLAGS(dcb->msgs_sent, FSMDEF_MSG_CONNECTED_ACK);
+
+// fsmdef_update_pd(dcb, FSMDEF_CALL_TYPE_OUTGOING);
+
+ /*
+ * Handle media capability changes if there is before transition to
+ * connected state.
+ */
+ sm_rc = fsmdef_transition_to_connected(fcb);
+ fsmutil_set_shown_calls_ci_element(dcb->caller_id.call_instance_id, dcb->line);
+
+ return (sm_rc);
+}
+
+
+static sm_rcs_t
+fsmdef_ev_connected_ack (sm_event_t *event)
+{
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ cc_connected_ack_t *msg = (cc_connected_ack_t *) event->msg;
+ cc_causes_t cause;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ /*
+ * Check the remote SDP. The far end may not have included the SDP in an
+ * earlier message, which means that the SDP must be in this message.
+ */
+ if (dcb->remote_sdp_in_ack == TRUE) {
+ cause = gsmsdp_negotiate_answer_sdp(fcb, &msg->msg_body);
+ if (cause != CC_CAUSE_OK) {
+ return (fsmdef_release(fcb, cause, dcb->send_release));
+ }
+ }
+
+ cc_call_state(dcb->call_id, dcb->line, CC_STATE_CONNECTED,
+ FSMDEF_CC_CALLER_ID);
+ /*
+ * If DSP is not able to start rx/tx channels, release the call
+ */
+ if (dcb->dsp_out_of_resources == TRUE) {
+ (void)fsmdef_release(fcb, CC_CAUSE_NO_MEDIA, dcb->send_release);
+ cc_call_state(fcb->dcb->call_id, fcb->dcb->line, CC_STATE_UNKNOWN,
+ NULL);
+ return (SM_RC_END);
+ }
+
+// fsmdef_update_pd(dcb, FSMDEF_CALL_TYPE_INCOMING);
+
+ /*
+ * Handle media capability changes if there is before transition to
+ * connected state.
+ */
+ return (fsmdef_transition_to_connected(fcb));
+}
+
+/**
+ * The function handles local hold event but not sending any hold request
+ * out to the remote end. The local SDP is updated by the way.
+ *
+ * @param[in]fcb - pointer to fsm_fcb_t
+ *
+ * @return SM_RC_END or failrue.
+ *
+ * @pre (fcb not_eq NULL)
+ */
+static sm_rcs_t
+fsm_hold_local_only (fsm_fcb_t *fcb)
+{
+ static const char fname[] = "fsm_hold_local_only";
+ cc_state_data_t state_data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ /*
+ * Check local hold status, and allow request if the media is not
+ * locally held.
+ */
+ if (fsmdef_all_media_are_local_hold(dcb)) {
+ /*
+ * a new hold request is not allowed. Ignore the request
+ * but we should still ack the request.
+ */
+ cc_int_feature_ack(CC_SRC_GSM, CC_SRC_GSM, dcb->call_id,
+ dcb->line, CC_FEATURE_HOLD, NULL, CC_CAUSE_NORMAL);
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG1), dcb->call_id, dcb->line,
+ fname, "already hold");
+
+ return (SM_RC_END);
+ }
+
+ state_data.hold.caller_id = dcb->caller_id;
+ state_data.hold.local = TRUE;
+
+ /*
+ * Update the SDP so that offer indicates hold. Reinitialize the local
+ * sdp media to include all available codecs. We do this because our local
+ * list has been shortened to the one negotiated codec.
+ */
+ (void)gsmsdp_update_local_sdp_media_capability(dcb, TRUE, TRUE);
+
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG_CLR_SPOOF_APPLD),
+ dcb->call_id, dcb->line, fname);
+
+ dcb->spoof_ringout_applied = FALSE;
+
+ cc_call_state(dcb->call_id, dcb->line, CC_STATE_HOLD, &state_data);
+
+ /* set all the media to local hold */
+ fsmdef_update_media_hold_status(dcb, NULL, TRUE);
+
+ fsm_change_state(fcb, __LINE__, FSMDEF_S_HOLDING);
+
+ sipsdp_src_dest_free(CCSIP_DEST_SDP_BIT | CCSIP_SRC_SDP_BIT,
+ &dcb->sdp);
+
+ return (SM_RC_END);
+}
+
+/**
+ * The function handles local hold event. The function also supports
+ * re-sending hold request out such as during a glare condition.
+ *
+ * @param[in]fcb - pointer to fsm_fcb_t
+ * @param[in]data_p - pointer to the cc_feature_data_t of the
+ * hold feature.
+ * @param[in]resend - TRUE indicates to resend hold request.
+ *
+ * @return SM_RC_END or failrue.
+ *
+ * @pre (fcb not_eq NULL)
+ * @pre (data_p not_eq NULL)
+ */
+static sm_rcs_t
+fsm_hold_local (fsm_fcb_t *fcb, cc_feature_data_t *data_p,
+ boolean resend)
+{
+ static const char fname[] = "fsm_hold_local";
+ cc_state_data_t state_data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ cc_causes_t cause;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ /*
+ * Check local hold status, and allow request if the media is not
+ * locally held or the caller indicates that to resend the hold
+ * request (such as in glare resolution).
+ */
+ if (!resend && fsmdef_all_media_are_local_hold(dcb)) {
+ /*
+ * a new hold request is not allowed. Ignore the request
+ * but we should still ack the request.
+ */
+ cc_int_feature_ack(CC_SRC_GSM, CC_SRC_GSM, dcb->call_id,
+ dcb->line, CC_FEATURE_HOLD, NULL,
+ CC_CAUSE_NORMAL);
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG1), dcb->call_id, dcb->line,
+ fname, "already hold");
+ return (SM_RC_END);
+ }
+
+ state_data.hold.caller_id = dcb->caller_id;
+ state_data.hold.local = TRUE;
+ state_data.hold.reason = data_p->hold.call_info.data.hold_resume_reason;
+
+ /* Store hold reason in case we need to resend the hold request due to
+ * request pending response.
+ */
+ dcb->hold_reason = data_p->hold.call_info.data.hold_resume_reason;
+
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG_CLR_SPOOF_APPLD),
+ dcb->call_id, dcb->line, fname);
+
+ dcb->spoof_ringout_applied = FALSE;
+
+ fsmdef_get_rtp_stat(dcb, &(data_p->hold.kfactor));
+
+ /* put the call on hold before building the SDP as DSP
+ * will then be able to give us a full set of codecs
+ * CUCM doesn't like to see a change in codecs on the fly
+ * ( i.e. without going to inactive state ) */
+ cc_call_state(dcb->call_id, dcb->line, CC_STATE_HOLD, &state_data);
+
+ /*
+ * Update the SDP so that offer indicates hold. Reinitialize the local
+ * sdp to include all available codecs. We do this because our
+ * local list has been shortened to the one negotiated codec.
+ */
+ (void)gsmsdp_update_local_sdp_media_capability(dcb, TRUE, TRUE);
+
+ /*
+ * Do not expect any msg. body from local hold but free them
+ * just in case before build new SDP body to send out.
+ */
+ cc_free_msg_body_parts(&data_p->hold.msg_body);
+
+ /* Build SDP for sending out */
+ cause = gsmsdp_encode_sdp_and_update_version(dcb, &data_p->hold.msg_body);
+ if (cause != CC_CAUSE_OK) {
+ FSM_DEBUG_SM(get_debug_string(FSM_DBG_SDP_BUILD_ERR));
+ return (fsmdef_release(fcb, cause, dcb->send_release));
+ }
+
+ /* set all the media to local hold */
+ fsmdef_update_media_hold_status(dcb, NULL, TRUE);
+
+ cc_int_feature(CC_SRC_GSM, CC_SRC_SIP, dcb->call_id, dcb->line,
+ CC_FEATURE_HOLD, data_p);
+
+ fsm_change_state(fcb, __LINE__, FSMDEF_S_HOLDING);
+
+ sipsdp_src_dest_free(CCSIP_DEST_SDP_BIT | CCSIP_SRC_SDP_BIT,
+ &dcb->sdp);
+
+ return (SM_RC_END);
+}
+
+/**
+ * Handles hold feature in connected media update pending state.
+ *
+ * @param[in] fcb The pointer to the fsm_fcb_t structure of this
+ * call chain.
+ * @param[in] data_p pointer to the cc_feature_data_t.
+ *
+ * @return sm_rsc_t indicates whether the execution of
+ * next statmachine to end or to clean up.
+ */
+static sm_rcs_t
+fsm_connected_media_pend_local_hold (fsm_fcb_t *fcb, cc_feature_data_t *data_p)
+{
+ static const char fname[] = "fsm_hold_local_connected_media_pend";
+ fsmdef_dcb_t *dcb = fcb->dcb;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ /*
+ * Check local hold status, and allow request if the media is not
+ * locally held.
+ */
+ if (fsmdef_all_media_are_local_hold(dcb)) {
+ /*
+ * a new hold request is not allowed. Ignore the request
+ * but we should still ack the request.
+ */
+ cc_int_feature_ack(CC_SRC_GSM, CC_SRC_GSM, dcb->call_id,
+ dcb->line, CC_FEATURE_HOLD, NULL,
+ CC_CAUSE_NORMAL);
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG1), dcb->call_id, dcb->line,
+ fname, "already hold");
+ return (SM_RC_END);
+ }
+
+ if (dcb->req_pending_tmr &&
+ cprIsTimerRunning(dcb->req_pending_tmr)) {
+ /*
+ * Request timer is running, that means we are waiting
+ * to re-send media update again due to previously glare.
+ * Since the previous offer has not been accepted, we can
+ * simply just send hold instead when glare resolution timer
+ * expires.
+ */
+
+ /* store the reason to resend when glare timer expires */
+ dcb->hold_reason = data_p->hold.call_info.data.hold_resume_reason;
+ /*
+ * reset feature hold pending flag in case that there are
+ * multiple hold feature received while waiting for
+ * glare resolution to resolve.
+ */
+ FSM_RESET_FLAGS(dcb->flags, FSMDEF_F_HOLD_REQ_PENDING);
+ fsm_change_state(fcb, __LINE__, FSMDEF_S_HOLD_PENDING);
+ return (SM_RC_END);
+ }
+
+ /*
+ * We have sent media capability update out but have not received
+ * any response yet. The glare condition may occur but we can only
+ * assume that the media update was sent out at this point.
+ * We can not send out any more request until the result is
+ * known. We can not do any thing now but simply remember
+ * to re-send media with the hold feature pending when
+ * the result is known.
+ */
+ FSM_SET_FLAGS(dcb->flags, FSMDEF_F_HOLD_REQ_PENDING);
+ return (SM_RC_END);
+}
+
+/**
+ * common function to handles media feature from remote end.
+ *
+ * @param[in] fcb The pointer to the fsm_fcb_t structure of this
+ * call chain.
+ * @param[in] msg The pointer to cc_feature_t.
+ *
+ * @return sm_rsc_t indicates whether the execution of
+ * next statmachine to end or to clean up.
+ */
+static sm_rcs_t
+fsmdef_remote_media (fsm_fcb_t *fcb, cc_feature_t *msg)
+{
+ static const char fname[] = "fsmdef_remote_media";
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ cc_feature_data_t *data = &(msg->data);
+ cc_feature_data_t feature_data;
+ cc_causes_t cause;
+ boolean send_ack = TRUE;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ memset(&feature_data, 0 , sizeof(cc_feature_data_t));
+ /*
+ * Determine what type of RESUME/MEDIA this is:
+ * 1. third-party control is just trying to change the media -
+ * midcall-invite with no SDP, so we need to wait for the SDP
+ * in the SIP ACK before we can truly resume the media.
+ * 2. remote end wants to resume a held call or just a media
+ * changes.
+ *
+ * We can distinguish between the two because case 1 will not
+ * have any data and case 2 will have data.
+ */
+ if (msg->data_valid == FALSE) {
+ /*
+ * Case 1.
+ *
+ * negotiate offer without SDP will reset all local media entries
+ * to have all codecs included. This is to re-advertise the
+ * capabilities again.
+ */
+ (void) gsmsdp_negotiate_offer_sdp(fcb, NULL, FALSE);
+
+ /*
+ * Update the media direction based on whether each media
+ * stream is locally held or not before sending out the
+ * offer SDP.
+ */
+ fsmdef_set_per_media_local_hold_sdp(dcb);
+ (void)cc_call_action(dcb->call_id, dcb->line, CC_ACTION_STOP_MEDIA,
+ NULL);
+ (void)cc_call_action(dcb->call_id, dcb->line, CC_ACTION_START_RCV,
+ NULL);
+ } else {
+ /*
+ * SIP may send MEDIA feature when answer SDP is received in
+ * ACK. The secnario is found when remote resumes and the
+ * resume INVITE is a delayed media INVITE. We sent an offer in
+ * the 200 OK and gets the answer back in the ACK. In this
+ * case, SIP will send MEDIA feature to GSM. We need to check
+ * whether we are waiting for an answer in ACK or not and
+ * use the corresponding offer/answer SDP negotiation function.
+ */
+ if (dcb->remote_sdp_in_ack) {
+ cause = gsmsdp_negotiate_answer_sdp(fcb,
+ &data->resume.msg_body);
+ if (cause != CC_CAUSE_OK) {
+ /*
+ * There is some thing wrong the answer SDP for some
+ * reason, can not go on.
+ */
+ FSM_DEBUG_SM(get_debug_string(FSM_DBG_SDP_BUILD_ERR));
+ return (fsmdef_release(fcb, cause, dcb->send_release));
+ }
+
+ /*
+ * This is the answer to our previous offer, no need to
+ * to ack to SIP this one.
+ */
+ send_ack = FALSE;
+ } else {
+ /* This is a new offer */
+
+ /*
+ * get k factor to be included in the feature ack. Getting
+ * the k factor needs to be done before maniputate media
+ * stream by the LSM.
+ */
+ fsmdef_media_t *media = gsmsdp_find_audio_media(dcb);
+ if ((media) && (media->direction != SDP_DIRECTION_INACTIVE)) {
+ fsmdef_get_rtp_stat(dcb, &(feature_data.resume.kfactor));
+ }
+
+ cause = gsmsdp_negotiate_offer_sdp(fcb,
+ &data->resume.msg_body, FALSE);
+ if (cause != CC_CAUSE_OK) {
+ /*
+ * Received a sdp that cannot be accepted.
+ * It should just reject the new sdp offer rather than
+ * tearing down the call.
+ */
+ cc_int_feature_ack(CC_SRC_GSM, CC_SRC_SIP, dcb->call_id,
+ dcb->line, msg->feature_id, NULL, cause);
+ return (SM_RC_END);
+ }
+ /*
+ * Update the media based on local hold.
+ */
+ fsmdef_set_per_media_local_hold_sdp(dcb);
+ }
+
+ /*
+ * If spoof ringout is not being requested and we are currently
+ * playing spoof ringout, transition the LSM from the far end alerting
+ * to the connected state.
+ */
+ if ((!dcb->spoof_ringout_requested) && (dcb->spoof_ringout_applied)) {
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG_CLR_SPOOF_APPLD),
+ dcb->call_id, dcb->line, fname);
+
+ dcb->spoof_ringout_applied = FALSE;
+ cc_call_state(dcb->call_id, dcb->line, CC_STATE_CONNECTED,
+ FSMDEF_CC_CALLER_ID);
+ } else {
+ (void)cc_call_action(dcb->call_id, dcb->line, CC_ACTION_MEDIA,
+ NULL);
+ }
+ }
+
+ if (send_ack) {
+ /* Build SDP from our current SDP */
+ cause = gsmsdp_encode_sdp_and_update_version(dcb, &feature_data.resume.msg_body);
+ if (cause != CC_CAUSE_OK) {
+ FSM_DEBUG_SM(get_debug_string(FSM_DBG_SDP_BUILD_ERR));
+ return (fsmdef_release(fcb, cause, dcb->send_release));
+ }
+ cc_int_feature_ack(CC_SRC_GSM, CC_SRC_SIP, dcb->call_id,
+ dcb->line, msg->feature_id, &feature_data,
+ CC_CAUSE_NORMAL);
+ }
+ return (SM_RC_END);
+}
+
+/**
+ *
+ * Function to handles connected state feature events. Function handles
+ * feature events generated by GSM, UI and SIP stack.
+ *
+ * @param sm_event_t event
+ *
+ * @return SM_RC_END or SM_RC_CLEANUP
+ *
+ * @pre (fcb->dcb not_eq NULL)
+ * @pre (event->data not_eq NULL)
+ * @pre (event->msg not_eq NULL)
+ */
+static sm_rcs_t
+fsmdef_ev_connected_feature (sm_event_t *event)
+{
+ static const char fname[] = "fsmdef_ev_connected_feature";
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ cc_feature_t *msg = (cc_feature_t *) event->msg;
+ cc_srcs_t src_id = msg->src_id;
+ cc_features_t ftr_id = msg->feature_id;
+ cc_feature_data_t *data = &(msg->data);
+ sm_rcs_t sm_rc;
+ cc_feature_data_t feature_data;
+ cc_action_data_t action_data;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ fsm_sm_ftr(ftr_id, src_id);
+
+ switch (src_id) {
+ case CC_SRC_UI:
+ case CC_SRC_GSM:
+ switch (msg->feature_id) {
+ case CC_FEATURE_HOLD:
+ /* If the line number is 0xFF, then this request
+ * came from GSM during a Transfer. We want to
+ * put the call on local hold only. We do not want
+ * to send a cc_feature to the SIP stack because
+ * that will cause an Invite Hold to go via SIP.
+ * We don't want to put the other end on hold, just
+ * ourselves.
+ */
+ if (msg->line == 0xFF) {
+ sm_rc = fsm_hold_local_only(fcb);
+ } else {
+ if (msg->data_valid) {
+ sm_rc = fsm_hold_local(fcb, data, FALSE);
+ } else {
+ feature_data.hold.call_info.type = CC_FEAT_HOLD;
+ feature_data.hold.call_info.data.hold_resume_reason =
+ CC_REASON_NONE;
+ feature_data.hold.msg_body.num_parts = 0;
+ feature_data.hold.call_info.data.call_info_feat_data.swap = FALSE;
+ feature_data.hold.call_info.data.call_info_feat_data.protect = FALSE;
+ sm_rc = fsm_hold_local(fcb, &feature_data, FALSE);
+ }
+
+ }
+ fsmdef_handle_join_pending(dcb);
+ return (sm_rc);
+
+ case CC_FEATURE_END_CALL:
+ sm_rc = fsmdef_release_call(fcb, msg);
+
+ fsmdef_handle_join_pending(dcb);
+ return (sm_rc);
+
+ case CC_FEATURE_JOIN:
+ /*
+ * Send offhook to the new call that triggers the
+ * completion of the setup of the join in call
+ */
+ fsmdef_ev_join(data);
+ break;
+
+ case CC_FEATURE_SELECT:
+ if (msg->data_valid == FALSE) {
+ fsmdef_select_invoke(dcb, NULL);
+ } else {
+ fsmdef_select_invoke(dcb, data);
+ }
+ return (SM_RC_END);
+
+ case CC_FEATURE_B2B_JOIN:
+ if (msg->data_valid == FALSE) {
+ fsmdef_b2bjoin_invoke(dcb, NULL);
+ } else {
+ fsmdef_b2bjoin_invoke(dcb, data);
+ }
+ return (SM_RC_END);
+
+ case CC_FEATURE_DIRTRXFR:
+ case CC_FEATURE_UNDEFINED:
+ fsm_display_feature_unavailable();
+
+ fsmdef_handle_join_pending(dcb);
+ return (SM_RC_END);
+
+ case CC_FEATURE_UPD_SESSION_MEDIA_CAP:
+ dcb->video_pref = data->caps.support_direction;
+ // Force an re-INVITE by mismatching the id
+ dcb->media_cap_tbl->id--;
+ /* FALL THRU */
+ case CC_FEATURE_UPD_MEDIA_CAP:
+ /*
+ * Media capability update request, check to see if
+ * there is any change in media capability and transition
+ * the pending state or stay in the connected state.
+ */
+ sm_rc = fsmdef_transition_to_connected(fcb);
+ return (sm_rc);
+
+ case CC_FEATURE_REQ_PEND_TIMER_EXP:
+ fsmdef_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ break;
+
+ default:
+ fsmdef_handle_join_pending(dcb);
+ fsmdef_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+
+ break;
+ } /* switch (msg->feature_id) */
+
+ break;
+
+ case CC_SRC_SIP:
+ switch (msg->feature_id) {
+
+ case CC_FEATURE_MEDIA:
+ /*
+ * remote send media update which can be resume or
+ * or just media changes.
+ */
+ sm_rc = fsmdef_remote_media(fcb, msg);
+ return (sm_rc);
+
+ case CC_FEATURE_CALLINFO:
+ fsmdef_update_callinfo(fcb, msg);
+ break;
+
+ case CC_FEATURE_CALL_PRESERVATION:
+ action_data.update_ui.action = CC_UPDATE_CALL_PRESERVATION;
+ (void)cc_call_action(dcb->call_id, dcb->line, CC_ACTION_UPDATE_UI,
+ &action_data);
+ fsm_change_state(fcb, __LINE__, FSMDEF_S_PRESERVED);
+ break;
+ case CC_FEATURE_NOTIFY:
+ fsmdef_ev_notify_feature(msg, dcb);
+ break;
+
+ case CC_FEATURE_UPDATE:
+ /*
+ * We only get an UPDATE feature event if we receive a medialess UPDATE.
+ * This type of event only conveys UI updates that are processed with
+ * a call info event. We do perform one check to see if we are currently
+ * spoofing ringout. If we are and the spoof ringout requested flag
+ * has been cleared, we tell the LSM to go connected.
+ */
+ if ((!dcb->spoof_ringout_requested) && (dcb->spoof_ringout_applied)) {
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG_CLR_SPOOF_APPLD),
+ dcb->call_id, dcb->line, fname);
+
+ dcb->spoof_ringout_applied = FALSE;
+ cc_call_state(dcb->call_id, dcb->line, CC_STATE_CONNECTED,
+ FSMDEF_CC_CALLER_ID);
+ }
+
+ /*
+ * For chaperone call, we will update call state here, to update
+ * the related key's status.
+ */
+ if(dcb->policy == CC_POLICY_CHAPERONE){
+ cc_call_state(dcb->call_id, dcb->line, CC_STATE_CONNECTED,
+ FSMDEF_CC_CALLER_ID);
+ }
+ break;
+
+ case CC_FEATURE_FAST_PIC_UPD:
+
+ vcmMediaControl(CREATE_CALL_HANDLE(dcb->line, dcb->call_id), VCM_MEDIA_CONTROL_PICTURE_FAST_UPDATE);
+
+ break;
+
+ default:
+ fsmdef_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ break;
+ } /* switch (msg->feature_id) */
+ break;
+
+ default:
+ fsmdef_sm_ignore_src(fcb, __LINE__, src_id);
+ break;
+ } /* switch (src_id) */
+
+ return (SM_RC_END);
+}
+
+/**
+ *
+ * Function to handles connected state media update pending feature.
+ *
+ * @param sm_event_t event
+ *
+ * @return SM_RC_END or SM_RC_CLEANUP
+ *
+ * @pre (fcb->dcb not_eq NULL)
+ * @pre (event->data not_eq NULL)
+ * @pre (event->msg not_eq NULL)
+ */
+static sm_rcs_t
+fsmdef_ev_connected_media_pend_feature (sm_event_t *event)
+{
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ cc_feature_t *msg = (cc_feature_t *) event->msg;
+ cc_srcs_t src_id = msg->src_id;
+ cc_features_t ftr_id = msg->feature_id;
+ cc_feature_data_t *data = &(msg->data);
+ sm_rcs_t sm_rc = SM_RC_END;
+ cc_feature_data_t feature_data;
+ cc_causes_t cause;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ fsm_sm_ftr(ftr_id, src_id);
+
+ switch (src_id) {
+ case CC_SRC_UI:
+ case CC_SRC_GSM:
+ switch (msg->feature_id) {
+ case CC_FEATURE_HOLD:
+ /* If the line number is 0xFF, then this request
+ * came from GSM during a Transfer. We want to
+ * put the call on local hold only. We do not want
+ * to send a cc_feature to the SIP stack because
+ * that will cause an Invite Hold to go via SIP.
+ * We don't want to put the other end on hold, just
+ * ourselves.
+ */
+ if (msg->line == 0xFF) {
+ sm_rc = fsm_hold_local_only(fcb);
+ } else {
+ if (msg->data_valid) {
+ sm_rc = fsm_connected_media_pend_local_hold(fcb, data);
+ } else {
+ feature_data.hold.call_info.type = CC_FEAT_HOLD;
+ feature_data.hold.call_info.data.hold_resume_reason =
+ CC_REASON_NONE;
+ feature_data.hold.msg_body.num_parts = 0;
+ feature_data.hold.call_info.data.call_info_feat_data.swap = FALSE;
+ feature_data.hold.call_info.data.call_info_feat_data.protect = FALSE;
+ sm_rc = fsm_connected_media_pend_local_hold(fcb,
+ &feature_data);
+ }
+ }
+ fsmdef_handle_join_pending(dcb);
+ return (sm_rc);
+
+ case CC_FEATURE_UPD_SESSION_MEDIA_CAP:
+ dcb->video_pref = data->caps.support_direction;
+ /* FALL THRU */
+ case CC_FEATURE_UPD_MEDIA_CAP:
+ /* We are already in the media update state */
+ fsmdef_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ return (SM_RC_END);
+
+ case CC_FEATURE_REQ_PEND_TIMER_EXP:
+ /*
+ * Glare resolution timer expires.
+ */
+ if (FSM_CHK_FLAGS(dcb->flags, FSMDEF_F_HOLD_REQ_PENDING)) {
+ /* There is a hold feature pending, send out hold instead */
+ feature_data.hold.call_info.type = CC_FEAT_HOLD;
+ feature_data.hold.call_info.data.hold_resume_reason =
+ dcb->hold_reason;
+ feature_data.hold.msg_body.num_parts = 0;
+ feature_data.hold.call_info.data.call_info_feat_data.swap = FALSE;
+ feature_data.hold.call_info.data.call_info_feat_data.protect = FALSE;
+ FSM_RESET_FLAGS(dcb->flags, FSMDEF_F_HOLD_REQ_PENDING);
+ return (fsm_hold_local(fcb, &feature_data, FALSE));
+ }
+
+ /*
+ * Check the possible media capbility changes.
+ */
+ (void)gsmsdp_update_local_sdp_media_capability(dcb, FALSE, FALSE);
+ feature_data.resume.call_info.type = CC_FEAT_NONE;
+ feature_data.resume.call_info.data.hold_resume_reason =
+ CC_REASON_NONE;
+ feature_data.resume.msg_body.num_parts = 0;
+ feature_data.resume.call_info.data.call_info_feat_data.swap = FALSE;
+ feature_data.resume.call_info.data.call_info_feat_data.protect = FALSE;
+ /* Encode SDP */
+ cause = gsmsdp_encode_sdp_and_update_version(dcb,
+ &feature_data.resume.msg_body);
+
+ if (cause != CC_CAUSE_OK) {
+ FSM_DEBUG_SM(get_debug_string(FSM_DBG_SDP_BUILD_ERR));
+ return(fsmdef_release(fcb, cause, dcb->send_release));
+ }
+
+ /* Send feature request to SIP */
+ cc_int_feature(CC_SRC_GSM, CC_SRC_SIP, dcb->call_id, dcb->line,
+ CC_FEATURE_MEDIA, &feature_data);
+ return (SM_RC_END);
+
+ default:
+ /*
+ * The rest of the feature handles the same way as the
+ * connected feature handling.
+ */
+ break;
+ } /* switch (msg->feature_id) */
+ break;
+
+ default:
+ /*
+ * The rest of the feature handles the same way as the
+ * connected feature handling.
+ */
+ break;
+ }
+
+ /*
+ * Unhandled features are handled by the normal connected feature
+ */
+ return (fsmdef_ev_connected_feature(event));
+}
+
+/**
+ *
+ * Function to handles connected media update pending state feature ack
+ * events.
+ *
+ * @param sm_event_t event
+ *
+ * @return SM_RC_END or SM_RC_CLEANUP
+ *
+ * @pre (fcb->dcb not_eq NULL)
+ * @pre (event->data not_eq NULL)
+ * @pre (event->msg not_eq NULL)
+ */
+static sm_rcs_t
+fsmdef_ev_connected_media_pend_feature_ack (sm_event_t *event)
+{
+ static const char fname[] = "fsmdef_ev_connected_media_pend_feature_ack";
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ cc_feature_ack_t *msg = (cc_feature_ack_t *) event->msg;
+ cc_features_t ftr_id = msg->feature_id;
+ cc_srcs_t src_id = msg->src_id;
+ cc_feature_data_t feature_data;
+ sm_rcs_t sm_rc = SM_RC_END;
+ cc_msgbody_info_t *msg_body;
+ cc_causes_t cause;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ fsm_sm_ftr(ftr_id, src_id);
+ switch (src_id) {
+ case CC_SRC_SIP:
+ switch (ftr_id) {
+ case CC_FEATURE_MEDIA:
+ /* Media update feature ack from SIP */
+
+ if (msg->cause == CC_CAUSE_REQUEST_PENDING) {
+ /*
+ * The glare condition occurs from the previously sent
+ * media update. Starts a request pending timer so that
+ * we retry.
+ */
+ fsmdef_set_req_pending_timer(dcb);
+ if (FSM_CHK_FLAGS(dcb->flags, FSMDEF_F_HOLD_REQ_PENDING)) {
+ /*
+ * Feature hold is pending, abort the media capability
+ * update and retry with hold instead.
+ */
+ FSM_RESET_FLAGS(dcb->flags, FSMDEF_F_HOLD_REQ_PENDING);
+ fsm_change_state(fcb, __LINE__, FSMDEF_S_HOLD_PENDING);
+ }
+ return (SM_RC_END);
+ }
+
+ /* Check for error code reported */
+ if ((msg->cause != CC_CAUSE_NORMAL) &&
+ (msg->cause != CC_CAUSE_OK)) {
+ /* Unable to send media request */
+ GSM_ERR_MSG(get_debug_string(FSMDEF_DBG2),
+ dcb->call_id, dcb->line, fname,
+ " Media request failed, cause= ", msg->cause);
+ cc_call_state(dcb->call_id, dcb->line, CC_STATE_UNKNOWN, NULL);
+ return(fsmdef_release(fcb, CC_CAUSE_ERROR, dcb->send_release));
+ }
+
+ msg_body = &msg->data.resume.msg_body;
+ cause = gsmsdp_negotiate_answer_sdp(fcb, msg_body);
+ if (cause != CC_CAUSE_OK) {
+ return (fsmdef_release(fcb, cause, dcb->send_release));
+ }
+
+ /*
+ * Check to see if we have a feature request pending
+ */
+ if (FSM_CHK_FLAGS(dcb->flags, FSMDEF_F_HOLD_REQ_PENDING)) {
+ /* There is a hold feature pending, send out hold instead */
+ feature_data.hold.call_info.type = CC_FEAT_HOLD;
+ feature_data.hold.call_info.data.hold_resume_reason =
+ dcb->hold_reason;
+ feature_data.hold.msg_body.num_parts = 0;
+ feature_data.hold.call_info.data.call_info_feat_data.swap = FALSE;
+ feature_data.hold.call_info.data.call_info_feat_data.protect = FALSE;
+ FSM_RESET_FLAGS(dcb->flags, FSMDEF_F_HOLD_REQ_PENDING);
+ sm_rc = fsm_hold_local(fcb, &feature_data, FALSE);
+ } else {
+ /*
+ * If spoof ringout is not being requested and we are
+ * currently playing spoof ringout, transition the LSM from
+ * the far end alerting to the connected state.
+ */
+ if ((!dcb->spoof_ringout_requested) &&
+ (dcb->spoof_ringout_applied)) {
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG_CLR_SPOOF_APPLD),
+ dcb->call_id, dcb->line, fname);
+
+ dcb->spoof_ringout_applied = FALSE;
+ cc_call_state(dcb->call_id, dcb->line, CC_STATE_CONNECTED,
+ FSMDEF_CC_CALLER_ID);
+ } else {
+ (void)cc_call_action(dcb->call_id, dcb->line,
+ CC_ACTION_MEDIA, NULL);
+ }
+
+ /*
+ * Check any media capability changes that might occurs
+ * while we were in the middle of the previous transaction.
+ */
+ sm_rc = fsmdef_transition_to_connected(fcb);
+ if (g_dock_undock_event != MEDIA_INTERFACE_UPDATE_NOT_REQUIRED) {
+ if (is_gsmsdp_media_ip_updated_to_latest(dcb) == TRUE) {
+ ui_update_media_interface_change(dcb->line, dcb->call_id, MEDIA_INTERFACE_UPDATE_SUCCESSFUL);
+ } else {
+ DEF_DEBUG("We must have received another MEDIA_INTERFACE_UPDATE events "
+ " while current MEDIA_INTERFACE_UPDATE event is in procoess. Sending re-invite again");
+ escalateDeescalate();
+ }
+ }
+ }
+ return (sm_rc);
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ /* call default feature ack handler to take common/default actions*/
+ (void) fsmdef_ev_default_feature_ack(event);
+ return (SM_RC_END);
+}
+
+static sm_rcs_t
+fsmdef_ev_offhook (sm_event_t *event)
+{
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ cc_action_data_t data;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ /*
+ * User has gone offhook while using the speaker.
+ */
+ data.speaker.on = FALSE;
+ (void)cc_call_action(dcb->call_id, dcb->line, CC_ACTION_SPEAKER, &data);
+
+ //lsm_set_active_call_id(dcb->call_id);
+
+ return (SM_RC_END);
+}
+
+
+static sm_rcs_t
+fsmdef_ev_connected_line (sm_event_t *event)
+{
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ cc_call_state(dcb->call_id, dcb->line, CC_STATE_CONNECTED,
+ FSMDEF_CC_CALLER_ID);
+
+ /*
+ * Handle media capability changes if there is before transition to
+ * connected state.
+ */
+ return (fsmdef_transition_to_connected(fcb));
+}
+
+
+static sm_rcs_t
+fsmdef_ev_onhook (sm_event_t *event)
+{
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ sm_rcs_t sm_rc;
+ cc_action_data_t data;
+ int sdpmode = 0;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ /* currently this flag is only set by conference case. It signals
+ * that onhook has been received, do not process it anymore.
+ */
+ if (dcb->onhook_received) {
+ dcb->onhook_received = FALSE;
+ return SM_RC_END;
+ }
+
+ config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
+
+ if (sdpmode) {
+ if(dcb->ice_ufrag)
+ cpr_free(dcb->ice_ufrag);
+
+ if(dcb->ice_pwd)
+ cpr_free(dcb->ice_pwd);
+ }
+
+ /*
+ * If the user presses the ENDCALL softkey for an
+ * incoming call set the release cause to Busy.
+ */
+ if (fcb->state == FSMDEF_S_INCOMING_ALERTING) {
+ sm_rc = fsmdef_release(fcb, CC_CAUSE_BUSY, dcb->send_release);
+ } else {
+ dcb->early_error_release = FALSE;
+ sm_rc = fsmdef_release(fcb, CC_CAUSE_NORMAL, dcb->send_release);
+ }
+
+ if (sm_rc == SM_RC_CLEANUP) {
+ /* This dcb has been cleaned up, do nothing more */
+ return (sm_rc);
+ } else if (fcb->state == FSMDEF_S_HOLDING ||
+ fcb->state == FSMDEF_S_HOLD_PENDING) {
+ data.ringer.on = TRUE;
+ (void)cc_call_action(dcb->call_id, dcb->line, CC_ACTION_RINGER, &data);
+ sm_rc = SM_RC_END;
+ } else {
+ sm_rc = SM_RC_END;
+ }
+
+ return (sm_rc);
+}
+
+
+static sm_rcs_t
+fsmdef_ev_release (sm_event_t *event)
+{
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ cc_release_t *msg = (cc_release_t *) event->msg;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ dcb->send_release = FALSE;
+
+ FSM_SET_FLAGS(dcb->msgs_rcvd, FSMDEF_MSG_RELEASE);
+
+ if (msg->cause == CC_CAUSE_REMOTE_DISCONN_REQ_PLAYTONE) {
+
+ fsmdef_set_call_info_cc_call_state(dcb, CC_STATE_CALL_FAILED, CC_CAUSE_REMOTE_DISCONN_REQ_PLAYTONE);
+
+ /* what to return for return code */
+ return(SM_RC_SUCCESS);
+ } else {
+ return (fsmdef_release(fcb, msg->cause, dcb->send_release));
+ }
+}
+
+
+static sm_rcs_t
+fsmdef_ev_releasing_release (sm_event_t *event)
+{
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ cc_release_t *msg = (cc_release_t *) event->msg;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ /* see if the SIP stack has aborted this call early for some reason
+ * If SIP brought this down, we are still offhook on the UI. We
+ * need to ignore it, so that reorder can be played AND when the user
+ * hangs up, then the UI will be driven to a clean state.
+ */
+ if (fcb->dcb->early_error_release == FALSE) {
+
+ cc_int_release_complete(CC_SRC_GSM, CC_SRC_SIP, dcb->call_id, dcb->line,
+ msg->cause, NULL);
+
+ fsm_change_state(fcb, __LINE__, FSMDEF_S_IDLE);
+
+ fsmdef_free_dcb(dcb);
+
+ FSM_SET_FLAGS(dcb->msgs_rcvd, FSMDEF_MSG_RELEASE);
+
+ fsm_release(fcb, __LINE__, msg->cause);
+
+ return (SM_RC_CLEANUP);
+ } else {
+ FSM_DEBUG_SM(get_debug_string(FSM_DBG_SM_DEFAULT_EVENT));
+ return (SM_RC_END);
+ }
+}
+
+
+static sm_rcs_t
+fsmdef_ev_releasing_feature (sm_event_t *event)
+{
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ cc_feature_t *msg = (cc_feature_t *) event->msg;
+ cc_srcs_t src_id = msg->src_id;
+ cc_features_t ftr_id = msg->feature_id;
+ cc_causes_t cause;
+ sm_rcs_t sm_rc = SM_RC_END;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ fsm_sm_ftr(ftr_id, src_id);
+
+ switch (ftr_id) {
+ case CC_FEATURE_END_CALL:
+ cause = fsmdef_get_cause(msg->data_valid, &(msg->data));
+
+ /* Clean up call chain, no release sent */
+ return (fsmdef_release(fcb, cause, FALSE));
+
+ default:
+ fsmdef_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ break;
+ }
+
+ return (sm_rc);
+}
+
+
+static sm_rcs_t
+fsmdef_ev_releasing_onhook (sm_event_t *event)
+{
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ /* Clean up call chain, no release sent */
+ return (fsmdef_release(fcb, CC_CAUSE_NORMAL, FALSE));
+}
+
+
+static sm_rcs_t
+fsmdef_ev_release_complete (sm_event_t *event)
+{
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ if (fcb->dcb == NULL) {
+ return (SM_RC_CLEANUP);
+ }
+ /* see if the SIP stack has aborted this call early for some reason
+ * If SIP brought this down, we are still offhook on the UI. We
+ * need to ignore it, so that reorder can be played AND when the user
+ * hangs up, then the UI will be driven to a clean state.
+ */
+ if (fcb->dcb->early_error_release == FALSE) {
+
+ fsm_change_state(fcb, __LINE__, FSMDEF_S_IDLE);
+
+ fsmdef_free_dcb(fcb->dcb);
+
+ fsm_release(fcb, __LINE__,
+ ((cc_release_complete_t *) (event->msg))->cause);
+
+ return (SM_RC_CLEANUP);
+
+ } else {
+ FSM_DEBUG_SM(get_debug_string(FSM_DBG_SM_DEFAULT_EVENT));
+ return (SM_RC_END);
+ }
+}
+
+static sm_rcs_t
+fsmdef_ev_hold_pending_feature (sm_event_t *event)
+{
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ fsmcnf_ccb_t *ccb = NULL;
+ cc_feature_t *msg = (cc_feature_t *) event->msg;
+ cc_srcs_t src_id = msg->src_id;
+ cc_features_t ftr_id = msg->feature_id;
+ callid_t call_id = msg->call_id;
+ line_t line = msg->line;
+ cc_feature_data_t *data = &(msg->data);
+ cc_feature_data_t feature_data;
+ sm_rcs_t sm_rc;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ fsm_sm_ftr(ftr_id, src_id);
+
+ switch (src_id) {
+ case (CC_SRC_UI):
+ case (CC_SRC_GSM):
+ switch (ftr_id) {
+
+ case CC_FEATURE_UPD_SESSION_MEDIA_CAP:
+ dcb->video_pref = data->caps.support_direction;
+ break;
+
+ case CC_FEATURE_RESUME:
+ /*
+ * We will not be able to resume this call since we are in the
+ * hold pending state but we can place any other active call
+ * on hold. Find the connected call (if there is one) and place
+ * it on hold but not call if it is involved in a conference.
+ */
+ if (msg->data.resume.cause != CC_CAUSE_CONF) {
+ if (fsmdef_wait_to_start_new_call(TRUE, src_id, call_id, line,
+ CC_FEATURE_RESUME, NULL)) {
+ ccb = fsmcnf_get_ccb_by_call_id(call_id);
+ if (ccb != NULL) {
+ ccb->cnf_ftr_ack = FALSE;
+ }
+ }
+ }
+ return (SM_RC_END);
+
+ case CC_FEATURE_REQ_PEND_TIMER_EXP:
+ feature_data.hold.call_info.type = CC_FEAT_HOLD;
+ feature_data.hold.call_info.data.hold_resume_reason =
+ dcb->hold_reason;
+ feature_data.hold.msg_body.num_parts = 0;
+ feature_data.hold.call_info.data.call_info_feat_data.swap = FALSE;
+ feature_data.hold.call_info.data.call_info_feat_data.protect = FALSE;
+ sm_rc = fsm_hold_local(fcb, &feature_data, TRUE);
+ return sm_rc;
+
+ case CC_FEATURE_END_CALL:
+ sm_rc = fsmdef_release_call(fcb, msg);
+ return (sm_rc);
+
+ default:
+ fsmdef_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+
+ break;
+ } /* switch (ftr_id) */
+
+ break;
+
+ case (CC_SRC_SIP):
+ switch (ftr_id) {
+ case CC_FEATURE_MEDIA:
+ return (fsmdef_remote_media(fcb, msg));
+
+ case CC_FEATURE_CALLINFO:
+ fsmdef_update_callinfo(fcb, msg);
+ break;
+
+ case CC_FEATURE_CALL_PRESERVATION:
+ return (fsmdef_release(fcb, CC_CAUSE_NORMAL, dcb->send_release));
+
+ case CC_FEATURE_NOTIFY:
+ fsmdef_ev_notify_feature(msg, dcb);
+ break;
+
+ default:
+ fsmdef_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ break;
+ } /* switch (ftr_id) */
+
+ break;
+
+ default:
+ fsmdef_sm_ignore_src(fcb, __LINE__, src_id);
+
+ break;
+ } /* switch (src_id) */
+
+ return (SM_RC_END);
+}
+
+/**
+ * feature ack event handler in hold pending state.
+ *
+ * @param[in] event Pointer to sm_event_t structure for feature ack event.
+ *
+ * @return Value of type sm_rcs_t to state machine
+ *
+ * @pre (event not_eqs NULL) and
+ * (event->data not_eqs NULL) and
+ * ((fsm_fcb_t *)(event->data)->dcb not_eqs NULL)
+ */
+static sm_rcs_t
+fsmdef_ev_hold_pending_feature_ack (sm_event_t *event)
+{
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ cc_feature_ack_t *msg = (cc_feature_ack_t *) event->msg;
+ cc_srcs_t src_id = msg->src_id;
+ cc_features_t ftr_id = msg->feature_id;
+ cc_causes_t cause;
+ cc_msgbody_info_t *msg_body;
+ cc_feature_data_t feature_data;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ fsm_sm_ftr(ftr_id, src_id);
+
+ switch (src_id) {
+ case (CC_SRC_SIP):
+ switch (ftr_id) {
+ case CC_FEATURE_RESUME:
+ /*
+ * This is feature ack for resume. We received resume
+ * feature ack because the hold request was received while
+ * we are waiting to resume i.e. was in the
+ * resume pending state and resume request has been sent out.
+ *
+ * If the resume ack indicates glare, then ignore sending the
+ * resume and transition to holding (we were in hold and
+ * unable to send RESUME). Otherwise send hold out right away
+ * if there is no other error.
+ */
+ fsm_sm_ftr(ftr_id, src_id);
+ if (msg->cause == CC_CAUSE_REQUEST_PENDING) {
+ /*
+ * The glare condition occurs from the previously sent
+ * resume transition to holding.
+ */
+ (void)fsm_hold_local_only(fcb);
+ break;
+ }
+
+ /* call default feature ack handler to take common/default actions*/
+ (void) fsmdef_ev_default_feature_ack(event);
+
+ if ((msg->cause != CC_CAUSE_NORMAL) &&
+ (msg->cause != CC_CAUSE_OK)) {
+ cc_call_state(dcb->call_id, dcb->line,
+ CC_STATE_UNKNOWN, NULL);
+ return(fsmdef_release(fcb, CC_CAUSE_ERROR, dcb->send_release));
+ }
+
+ if (msg->data_valid != TRUE) {
+ cc_call_state(dcb->call_id, dcb->line,
+ CC_STATE_UNKNOWN, NULL);
+ return(fsmdef_release(fcb, CC_CAUSE_ERROR, dcb->send_release));
+ }
+
+ msg_body = &msg->data.resume.msg_body;
+ cause = gsmsdp_negotiate_answer_sdp(fcb, msg_body);
+ if (cause != CC_CAUSE_OK) {
+ return(fsmdef_release(fcb, cause, dcb->send_release));
+ }
+
+ /*
+ * HOLD can be sent now.
+ */
+ feature_data.hold.call_info.type = CC_FEAT_HOLD;
+ feature_data.hold.call_info.data.hold_resume_reason =
+ dcb->hold_reason;
+ feature_data.hold.msg_body.num_parts = 0;
+ feature_data.hold.call_info.data.call_info_feat_data.swap = FALSE;
+ feature_data.hold.call_info.data.call_info_feat_data.protect = FALSE;
+ fsm_hold_local(fcb, &feature_data, FALSE);
+ break;
+
+ default:
+ fsmdef_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ break;
+ }
+ break;
+
+ default:
+ fsmdef_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ break;
+ }
+
+ return (SM_RC_END);
+}
+
+
+static sm_rcs_t
+fsmdef_ev_holding_release (sm_event_t *event)
+{
+ cc_release_t *msg = (cc_release_t *) event->msg;
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ if (msg->cause != CC_CAUSE_XFER_LOCAL) {
+ fcb->dcb->send_release = FALSE;
+ }
+
+ FSM_SET_FLAGS(dcb->msgs_rcvd, FSMDEF_MSG_RELEASE);
+
+ return (fsmdef_release(fcb, msg->cause, fcb->dcb->send_release));
+}
+
+static sm_rcs_t
+fsmdef_ev_holding_onhook (sm_event_t *event)
+{
+ cc_onhook_t *msg = (cc_onhook_t *) event->msg;
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ if (!(msg->softkey)) {
+ /* Meaning Hangup, ignore, a held call can't be hung up */
+ FSM_DEBUG_SM(get_debug_string(FSM_DBG_SM_DEFAULT_EVENT));
+ return (SM_RC_END);
+ }
+
+ /*
+ * Meaning EndCall softkey is sent, take down
+ * the call, this happens during failover.
+ */
+ FSM_SET_FLAGS(dcb->msgs_rcvd, FSMDEF_MSG_RELEASE);
+
+ return (fsmdef_release(fcb, CC_CAUSE_NORMAL, dcb->send_release));
+}
+
+/**
+ *
+ * fsmdef_reversion_timeout - Triggers LSM for doing Reversion alerts.
+ *
+ * @param fsmdef_dcb_t dcb for this call
+ *
+ * @return none
+ *
+ * @pre (dcb not_eq NULL)
+ */
+
+void fsmdef_reversion_timeout(callid_t call_id)
+{
+
+ int ret = CPR_SUCCESS;
+
+ fsmdef_dcb_t *dcb = fsmdef_get_dcb_by_call_id(call_id) ;
+
+ if ( (dcb == NULL ) || (dcb->fcb == NULL)) {
+ return;
+ }
+
+ // check that we are in HOLDING state before proceeding
+ if ((dcb->fcb->state != FSMDEF_S_HOLDING) &&
+ (dcb->fcb->state != FSMDEF_S_HOLD_PENDING)) {
+ return;
+ }
+
+ if (dcb->reversionInterval > 0) {
+ ret = cprStartTimer(dcb->revertTimer, dcb->reversionInterval * 1000, (void*)(long)call_id);
+ }
+
+ if ( ret == CPR_FAILURE ) {
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG_TMR_START_FAILED),
+ dcb->call_id, dcb->line, "", "Reversion", cpr_errno);
+ return;
+ }
+
+ cc_call_state(dcb->call_id, dcb->line, CC_STATE_HOLD_REVERT, NULL);
+
+}
+
+
+/**
+ *
+ * fsmdef_resume - Performs Resume Operation.
+ *
+ * @param sm_event_t event
+ *
+ * @return sm_rcs_t SM_RC_END - indicating the event has been consumed
+ *
+ * @pre (event not_eq NULL)
+ */
+
+static void
+fsmdef_resume (sm_event_t *event)
+{
+
+ static const char fname[] = "fsmdef_resume";
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ fsmcnf_ccb_t *ccb = NULL;
+ cc_feature_t *msg = (cc_feature_t *) event->msg;
+ cc_feature_data_t *data = &(msg->data);
+ cc_srcs_t src_id = msg->src_id;
+ callid_t call_id = msg->call_id;
+ line_t line = msg->line;
+ cc_feature_data_t feature_data;
+ cc_causes_t cause;
+ boolean req_pending_tmr_running = FALSE;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ /*
+ * Ignore the request if local hold is not active.
+ */
+ if (fsmdef_num_media_in_local_hold(dcb) == 0) {
+ /*
+ * No media in local held, should not happen here.
+ */
+ cc_int_feature_ack(CC_SRC_GSM, CC_SRC_GSM, dcb->call_id,
+ dcb->line, CC_FEATURE_RESUME, NULL,
+ CC_CAUSE_NORMAL);
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG1), call_id, dcb->line,
+ fname, "resume media not in hold state\n");
+ return;
+ }
+
+ (void) cprCancelTimer(dcb->revertTimer);
+ dcb->reversionInterval = -1;
+ /*
+ * Make sure the connected call (if there is one) goes on hold,
+ * but do not hold the connected call if it is involved in a
+ * conference.
+ */
+ if (msg->data.resume.cause != CC_CAUSE_CONF) {
+ if (fsmdef_wait_to_start_new_call(TRUE, src_id, call_id, line,
+ CC_FEATURE_RESUME, (msg->data_valid ?
+ data : NULL))) {
+
+ ccb = fsmcnf_get_ccb_by_call_id(call_id);
+ if (ccb != NULL) {
+ ccb->cnf_ftr_ack = FALSE;
+ }
+ return ;
+ }
+ }
+
+ /* Clear all media holding status */
+ fsmdef_update_media_hold_status(dcb, NULL, FALSE);
+
+ if (dcb->req_pending_tmr && cprIsTimerRunning(dcb->req_pending_tmr)) {
+ req_pending_tmr_running = TRUE;
+ }
+
+ if (!req_pending_tmr_running) {
+ /*
+ * Reinitialize the local sdp to include all available codecs.
+ * We do this because it is possible that our local list
+ * may have been shortened to the one negotiated codec. This is
+ * the case when we receive an incoming call, we negotiate a
+ * single codec, copy it into the local sdp and send it back
+ * in the connected msg.
+ */
+ (void)gsmsdp_update_local_sdp_media_capability(dcb, TRUE, FALSE);
+
+ if (msg->data_valid) {
+ feature_data.resume.call_info = data->resume.call_info;
+ } else {
+ feature_data.resume.call_info.type = CC_FEAT_RESUME;
+ feature_data.resume.call_info.data.hold_resume_reason =
+ CC_REASON_NONE;
+ feature_data.resume.msg_body.num_parts = 0;
+ feature_data.resume.call_info.data.call_info_feat_data.swap = FALSE;
+ feature_data.resume.call_info.data.call_info_feat_data.protect = FALSE;
+ }
+ /* Encode SDP */
+ cause = gsmsdp_encode_sdp_and_update_version(dcb,
+ &feature_data.resume.msg_body);
+ if (cause != CC_CAUSE_OK) {
+ FSM_DEBUG_SM(get_debug_string(FSM_DBG_SDP_BUILD_ERR));
+ (void)fsmdef_release(fcb, cause, dcb->send_release);
+ return ;
+ }
+ }
+
+ /*
+ * If spoof ringout is currently requested, transition to the
+ * far end alerting state instead of the connected state.
+ */
+ if (dcb->spoof_ringout_requested) {
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG1),
+ dcb->call_id, dcb->line, fname,
+ "setting spoof_ringout_applied");
+
+ dcb->spoof_ringout_applied = TRUE;
+ cc_call_state(dcb->call_id, dcb->line,
+ CC_STATE_FAR_END_ALERTING, FSMDEF_CC_CALLER_ID);
+ } else {
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG_CLR_SPOOF_APPLD),
+ dcb->call_id, dcb->line, fname);
+
+ dcb->spoof_ringout_applied = FALSE;
+ /* Start receiving but not transmit, before sending resume */
+ (void)cc_call_action(dcb->call_id, dcb->line, CC_ACTION_START_RCV,
+ NULL);
+ }
+
+ if (!req_pending_tmr_running) {
+ cc_int_feature(CC_SRC_GSM, CC_SRC_SIP, dcb->call_id, dcb->line,
+ CC_FEATURE_RESUME, &feature_data);
+ }
+
+ /*
+ * We lock the UI until we learn the result of the resume request
+ */
+ fim_lock_ui(call_id);
+
+ /* Wait for feature ack */
+ fsm_change_state(fcb, __LINE__, FSMDEF_S_RESUME_PENDING);
+
+ return ;
+
+}
+
+/**
+ *
+ * fsmdef_ev_holding_offhook - Handles offhook in for holding state.
+ *
+ * @param sm_event_t event
+ *
+ * @return sm_rcs_t SM_RC_END - indicating the event has been consumed
+ *
+ * @pre (event not_eq NULL)
+ */
+
+static sm_rcs_t
+fsmdef_ev_holding_offhook (sm_event_t *event)
+{
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ if (cprIsTimerRunning(dcb->revertTimer)) {
+ // Off hook resume calls only if HR is active else ignore this event
+ fsmdef_resume(event);
+ }
+
+ return SM_RC_END;
+
+}
+
+static sm_rcs_t
+fsmdef_ev_holding_feature (sm_event_t *event)
+{
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ cc_feature_t *msg = (cc_feature_t *) event->msg;
+ cc_srcs_t src_id = msg->src_id;
+ cc_features_t ftr_id = msg->feature_id;
+ cc_feature_data_t *data = &(msg->data);
+ cc_feature_data_t feature_data;
+ sm_rcs_t sm_rc;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ fsm_sm_ftr(ftr_id, src_id);
+
+ switch (src_id) {
+ case (CC_SRC_UI):
+ case (CC_SRC_GSM):
+ switch (ftr_id) {
+
+ case CC_FEATURE_UPD_SESSION_MEDIA_CAP:
+ dcb->video_pref = data->caps.support_direction;
+ break;
+
+ case CC_FEATURE_HOLD:
+ if (msg->data_valid) {
+ sm_rc = fsm_hold_local(fcb, data, FALSE);
+ } else {
+ feature_data.hold.call_info.type = CC_FEAT_HOLD;
+ feature_data.hold.call_info.data.hold_resume_reason =
+ CC_REASON_NONE;
+ feature_data.hold.msg_body.num_parts = 0;
+ feature_data.hold.call_info.data.call_info_feat_data.swap = FALSE;
+ feature_data.hold.call_info.data.call_info_feat_data.protect = FALSE;
+ sm_rc = fsm_hold_local(fcb, &feature_data, FALSE);
+ }
+ fsmdef_handle_join_pending(dcb);
+ return (sm_rc);
+
+ case CC_FEATURE_HOLD_REVERSION:
+ // Stop the timer for alert interval
+ (void) cprCancelTimer(dcb->revertTimer);
+ dcb->reversionInterval = -1;
+
+ // Do not revert if alertInterval is negative
+ if ( data->hold_reversion.alertInterval < 0 )
+ return SM_RC_END;
+ // interval timer of 0 implies continue to revert
+ // Clamp the interval to be in MIN/MAX_HOLD_REVERSION_INTERVAL_TIMER
+ if ( data->hold_reversion.alertInterval > 0 &&
+ data->hold_reversion.alertInterval < MIN_HOLD_REVERSION_INTERVAL_TIMER )
+ data->hold_reversion.alertInterval = MIN_HOLD_REVERSION_INTERVAL_TIMER;
+
+ if ( data->hold_reversion.alertInterval > MAX_HOLD_REVERSION_INTERVAL_TIMER )
+ data->hold_reversion.alertInterval = MAX_HOLD_REVERSION_INTERVAL_TIMER;
+
+ dcb->reversionInterval = data->hold_reversion.alertInterval ;
+
+ fsmdef_reversion_timeout(fcb->dcb->call_id);
+
+ fsmdef_handle_join_pending(dcb);
+ return SM_RC_END;
+
+ case CC_FEATURE_RESUME:
+ fsmdef_resume(event);
+ break;
+
+ case CC_FEATURE_END_CALL:
+ sm_rc = fsmdef_release_call(fcb, msg);
+ (void) cprCancelTimer(dcb->revertTimer);
+ dcb->reversionInterval = -1;
+ fsmdef_handle_join_pending(dcb);
+ return (sm_rc);
+
+ case CC_FEATURE_SELECT:
+ if (msg->data_valid == FALSE) {
+ fsmdef_select_invoke(dcb, NULL);
+ } else {
+ fsmdef_select_invoke(dcb, data);
+ }
+ return (SM_RC_END);
+
+ case CC_FEATURE_B2B_JOIN:
+ if (msg->data_valid == FALSE) {
+ fsmdef_b2bjoin_invoke(dcb, NULL);
+ } else {
+ fsmdef_b2bjoin_invoke(dcb, data);
+ }
+ return (SM_RC_END);
+
+ case CC_FEATURE_DIRTRXFR:
+ case CC_FEATURE_UNDEFINED:
+ fsm_display_feature_unavailable();
+
+ fsmdef_handle_join_pending(dcb);
+ return (SM_RC_END);
+
+ case CC_FEATURE_REQ_PEND_TIMER_EXP:
+ /* Ignore the request pending timer when in holding state */
+ default:
+ fsmdef_handle_join_pending(dcb);
+ fsmdef_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+
+ break;
+ } /* switch (ftr_id) */
+
+ break;
+
+ case (CC_SRC_SIP):
+ switch (ftr_id) {
+ case CC_FEATURE_MEDIA:
+ return (fsmdef_remote_media(fcb, msg));
+
+ case CC_FEATURE_CALLINFO:
+ fsmdef_update_callinfo(fcb, msg);
+ break;
+
+ case CC_FEATURE_CALL_PRESERVATION:
+ (void) cprCancelTimer(dcb->revertTimer);
+ dcb->reversionInterval = -1;
+ return (fsmdef_release(fcb, CC_CAUSE_NORMAL, dcb->send_release));
+
+ case CC_FEATURE_NOTIFY:
+ fsmdef_ev_notify_feature(msg, dcb);
+ break;
+
+ default:
+ fsmdef_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+
+ break;
+ } /* switch (ftr_id) */
+
+ break;
+
+ default:
+ fsmdef_sm_ignore_src(fcb, __LINE__, src_id);
+
+ break;
+ } /* switch (src_id) */
+
+ return (SM_RC_END);
+}
+
+
+static sm_rcs_t
+fsmdef_ev_holding_feature_ack (sm_event_t *event)
+{
+ static const char fname[] = "fsmdef_ev_holding_feature_ack";
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ cc_feature_ack_t *msg = (cc_feature_ack_t *) event->msg;
+ cc_srcs_t src_id = msg->src_id;
+ cc_features_t ftr_id = msg->feature_id;
+ cc_causes_t cause = msg->cause;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ switch (src_id) {
+ case (CC_SRC_SIP):
+ switch (ftr_id) {
+ case CC_FEATURE_HOLD:
+ if (cause == CC_CAUSE_REQUEST_PENDING) {
+ /*
+ * If this is feature ack for hold and request is pending,
+ * set a request pending timer so that we retry the hold
+ * feature request.
+ */
+ fsmdef_set_req_pending_timer(dcb);
+ fsm_change_state(fcb, __LINE__, FSMDEF_S_HOLD_PENDING);
+ return (SM_RC_END);
+ }
+
+ /* Check for error code reported */
+ if ((cause != CC_CAUSE_NORMAL) &&
+ (cause != CC_CAUSE_OK)) {
+ /* Unable to send hold request */
+ GSM_ERR_MSG(get_debug_string(FSMDEF_DBG2),
+ dcb->call_id, dcb->line, fname,
+ "HOLD request failed, cause= ", cause);
+ cc_call_state(dcb->call_id, dcb->line, CC_STATE_UNKNOWN, NULL);
+ return(fsmdef_release(fcb, CC_CAUSE_ERROR, dcb->send_release));
+ }
+ // update video_avail as we are not negotiating the answer below
+ dcb->cur_video_avail = SDP_DIRECTION_INACTIVE;
+ lsm_update_video_avail(dcb->line, dcb->call_id, dcb->cur_video_avail);
+ break;
+
+ default:
+ fsm_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ break;
+ }
+ break;
+
+ default:
+ fsm_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ break;
+ }
+
+ /* call default feature ack handler to take common/default actions */
+ (void) fsmdef_ev_default_feature_ack(event);
+
+ return (SM_RC_END);
+}
+
+static sm_rcs_t
+fsmdef_ev_resume_pending_feature (sm_event_t *event)
+{
+ static const char fname[] = "fsmdef_ev_resume_pending_feature";
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ cc_feature_t *msg = (cc_feature_t *) event->msg;
+ cc_srcs_t src_id = msg->src_id;
+ cc_features_t ftr_id = msg->feature_id;
+ callid_t call_id = msg->call_id;
+ cc_feature_data_t *data = &(msg->data);
+ cc_feature_data_t feature_data;
+ sm_rcs_t sm_rc;
+ cc_causes_t cause;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ fsm_sm_ftr(ftr_id, src_id);
+
+ switch (src_id) {
+ case (CC_SRC_UI):
+ switch (ftr_id) {
+ case CC_FEATURE_UPD_SESSION_MEDIA_CAP:
+ dcb->video_pref = data->caps.support_direction;
+ break;
+
+ case CC_FEATURE_END_CALL:
+ fim_unlock_ui(call_id);
+ sm_rc = fsmdef_release_call(fcb, msg);
+ return (sm_rc);
+
+ case CC_FEATURE_HOLD:
+ /*
+ * The UI should be locked but the hold event from UI here
+ * can be the result of other call chain wants to put this
+ * other call that may be in conected state or in resume
+ * pending state on hold. One example, the user want to
+ * resume a call that is on hold, that call chain will look
+ * for any other call in connected state or call in resume
+ * pending (about to be connected) and puts this call on hold.
+ *
+ * There are 2 choices here. If we are in this state and has
+ * not sent a resume out to the network, then simply
+ * transition to holding state. If resume has already
+ * been sent and we are here waiting for resume pending ack,
+ * then we can not send out hold immediately. In the later
+ * case, go to hold pending state and wait for resume
+ * feature ack to send hold out.
+ *
+ * In either case, UI can be unlocked since we are now
+ * about to hold again.
+ */
+ fim_unlock_ui(dcb->call_id);
+ if (dcb->req_pending_tmr &&
+ cprIsTimerRunning(dcb->req_pending_tmr)) {
+ /*
+ * Request timer is running, that means we are waiting
+ * to send resume or we already have sent one out
+ * but it resulted in glare condition and that we are waiting
+ * to resent it again. In this, just go back to hold state.
+ */
+ (void) cprCancelTimer(dcb->req_pending_tmr);
+
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG1),
+ dcb->call_id, dcb->line, fname,
+ "Received Hold while waiting to send resume\n");
+
+ /* Go back to holding without sending any thing out */
+ (void)fsm_hold_local_only(fcb);
+ } else {
+ /*
+ * We have sent resume to the network and wait for
+ * for the feature ack. The glare condition can
+ * occur but we can only assume that resume was sent out
+ * at this point. We can not send out any more request
+ * until the result is known.
+ */
+ if (msg->data_valid) {
+ dcb->hold_reason =
+ data->hold.call_info.data.hold_resume_reason;
+ } else {
+ dcb->hold_reason = CC_REASON_NONE;
+ }
+ // since we are going to hold stop the media now
+ // else the next new call or resume will result in 2 sets of media ports open
+ (void)cc_call_action(dcb->call_id, dcb->line, CC_ACTION_STOP_MEDIA,
+ NULL);
+ fsm_change_state(fcb, __LINE__, FSMDEF_S_HOLD_PENDING);
+ }
+ break;
+
+ default:
+ fsmdef_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ break;
+ }
+ break;
+
+ case (CC_SRC_GSM):
+ switch (ftr_id) {
+
+ case CC_FEATURE_HOLD:
+ sm_rc = fsm_hold_local_only(fcb);
+ fim_unlock_ui(call_id);
+ return (sm_rc);
+
+ case CC_FEATURE_END_CALL:
+ fim_unlock_ui(call_id);
+ sm_rc = fsmdef_release_call(fcb, msg);
+ return (sm_rc);
+
+ case CC_FEATURE_REQ_PEND_TIMER_EXP:
+
+ /*
+ * Reinitialize the local sdp to include all available codecs.
+ * We do this because it is possible that our local list
+ * may have been shortened to the one negotiated codec. This is
+ * the case when we receive an incoming call, we negotiate a
+ * single codec, copy it into the local sdp and send it back
+ * in the connected msg.
+ */
+ (void)gsmsdp_update_local_sdp_media_capability(dcb, TRUE, FALSE);
+
+ feature_data.resume.call_info.type = CC_FEAT_RESUME;
+ feature_data.resume.call_info.data.hold_resume_reason =
+ CC_REASON_NONE;
+ feature_data.resume.msg_body.num_parts = 0;
+ feature_data.resume.call_info.data.call_info_feat_data.swap = FALSE;
+ feature_data.resume.call_info.data.call_info_feat_data.protect = FALSE;
+ /* Encode SDP */
+ cause = gsmsdp_encode_sdp_and_update_version(dcb, &feature_data.resume.msg_body);
+ if (cause != CC_CAUSE_OK) {
+ FSM_DEBUG_SM(get_debug_string(FSM_DBG_SDP_BUILD_ERR));
+ return (fsmdef_release(fcb, cause, dcb->send_release));
+ }
+
+ /*
+ * We lock the UI until we learn the result of the resume request.
+ */
+ fim_lock_ui(call_id);
+
+ cc_int_feature(CC_SRC_GSM, CC_SRC_SIP, dcb->call_id, dcb->line,
+ CC_FEATURE_RESUME, &feature_data);
+ break;
+
+ default:
+ fsmdef_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ break;
+ } /* switch (ftr_id) */
+
+ break;
+
+ case (CC_SRC_SIP):
+ switch (ftr_id) {
+ case CC_FEATURE_MEDIA:
+ return (fsmdef_remote_media(fcb, msg));
+
+ case CC_FEATURE_CALLINFO:
+ fsmdef_update_callinfo(fcb, msg);
+ break;
+
+ case CC_FEATURE_CALL_PRESERVATION:
+ fim_unlock_ui(call_id);
+ return (fsmdef_release(fcb, CC_CAUSE_NORMAL, dcb->send_release));
+
+ case CC_FEATURE_NOTIFY:
+ fsmdef_ev_notify_feature(msg, dcb);
+ break;
+
+ case CC_FEATURE_UPDATE:
+ /*
+ * We only get an UPDATE feature event if we receive a medialess UPDATE.
+ * This type of event only conveys UI updates that are processed with
+ * a call info event. We do perform one check to see if we are currently
+ * spoofing ringout. If we are and the spoof ringout requested flag
+ * has been cleared, we tell the LSM to go connected which halts the
+ * spoofed ringout.
+ */
+ if ((!dcb->spoof_ringout_requested) && (dcb->spoof_ringout_applied)) {
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG_CLR_SPOOF_APPLD),
+ dcb->call_id, dcb->line, fname);
+
+ dcb->spoof_ringout_applied = FALSE;
+ cc_call_state(dcb->call_id, dcb->line, CC_STATE_CONNECTED,
+ FSMDEF_CC_CALLER_ID);
+ }
+ break;
+
+ default:
+ fsmdef_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ break;
+ } /* switch (ftr_id) */
+
+ break;
+
+ default:
+ fsmdef_sm_ignore_src(fcb, __LINE__, src_id);
+ break;
+ } /* switch (src_id) */
+
+ return (SM_RC_END);
+}
+
+/**
+ * feature ack event handler in resume pending state.
+ *
+ * @param[in] event Pointer to sm_event_t structure for feature ack event.
+ *
+ * @return Value of type sm_rcs_t to state machine
+ *
+ * @pre (event not_eqs NULL) and
+ * (event->data not_eqs NULL) and
+ * ((fsm_fcb_t *)(event->data)->dcb not_eqs NULL)
+ */
+static sm_rcs_t
+fsmdef_ev_resume_pending_feature_ack (sm_event_t *event)
+{
+ static const char fname[] = "fsmdef_ev_resume_pending_feature_ack";
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ cc_feature_ack_t *msg = (cc_feature_ack_t *) event->msg;
+ cc_srcs_t src_id = msg->src_id;
+ cc_features_t ftr_id = msg->feature_id;
+ cc_causes_t cause;
+ cc_msgbody_info_t *msg_body;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ fsm_sm_ftr(ftr_id, src_id);
+
+ switch (src_id) {
+ case (CC_SRC_SIP):
+ switch (ftr_id) {
+ case CC_FEATURE_HOLD:
+ /*
+ * This can occur because SIP stack has not sent HOLD out yet
+ * but the user has pressed resume since we already moved
+ * to HOLD state as soon as the user pressed HOLD. Ignore the
+ * HOLD feature ACK except if it indicates error. If we get
+ * REQUEST_PENDING, we'll just move to connected state.
+ */
+ if (msg->cause == CC_CAUSE_REQUEST_PENDING) {
+ cc_call_state(dcb->call_id, dcb->line, CC_STATE_CONNECTED,
+ FSMDEF_CC_CALLER_ID);
+ fsm_change_state(fcb, __LINE__, FSMDEF_S_CONNECTED);
+ return (SM_RC_END);
+ }
+ if ((msg->cause != CC_CAUSE_NORMAL) &&
+ (msg->cause != CC_CAUSE_OK)) {
+ cc_call_state(dcb->call_id, dcb->line,
+ CC_STATE_UNKNOWN, NULL);
+ return(fsmdef_release(fcb, CC_CAUSE_ERROR, dcb->send_release));
+ }
+ fsmdef_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ break;
+
+ case CC_FEATURE_RESUME:
+ /*
+ * If this is feature ack for resume and request is pending,
+ * set a request pending timer so that we retry the resume
+ * feature request. Otherwise, unlock the UI and continue
+ * processing.
+ */
+ fsm_sm_ftr(ftr_id, src_id);
+ if ( msg->cause == CC_CAUSE_REQUEST_PENDING ) {
+ fsmdef_set_req_pending_timer(dcb);
+ return (SM_RC_END);
+ } else {
+ fim_unlock_ui(dcb->call_id);
+ }
+ /* call default feature ack handler to take common/default actions*/
+ (void) fsmdef_ev_default_feature_ack(event);
+
+ if ((msg->cause == CC_CAUSE_SERV_ERR_UNAVAIL) &&
+ (dcb->hold_reason == CC_REASON_MONITOR_UPDATE)) {
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG1),
+ dcb->call_id, dcb->line, fname,
+ "msg->cause == CC_CAUSE_SERV_ERR_UNAVAIL, unable to monitor update\n");
+ return (fsmdef_transition_to_connected(fcb));
+ }
+
+ if ((msg->cause != CC_CAUSE_NORMAL) &&
+ (msg->cause != CC_CAUSE_OK)) {
+ cc_call_state(dcb->call_id, dcb->line,
+ CC_STATE_UNKNOWN, NULL);
+ return(fsmdef_release(fcb, CC_CAUSE_ERROR, dcb->send_release));
+ }
+
+ if (msg->data_valid != TRUE) {
+ cc_call_state(dcb->call_id, dcb->line,
+ CC_STATE_UNKNOWN, NULL);
+ return(fsmdef_release(fcb, CC_CAUSE_ERROR, dcb->send_release));
+ }
+
+ msg_body = &msg->data.resume.msg_body;
+ cause = gsmsdp_negotiate_answer_sdp(fcb, msg_body);
+ if (cause != CC_CAUSE_OK) {
+ return (fsmdef_release(fcb, cause, dcb->send_release));
+ }
+ if (!dcb->spoof_ringout_applied) {
+ cc_call_state(dcb->call_id, dcb->line, CC_STATE_CONNECTED,
+ FSMDEF_CC_CALLER_ID);
+ }
+ /*
+ * Handle media capability changes if there is before transition
+ * to connected state to catch any changes during resume
+ * transaction.
+ */
+ return (fsmdef_transition_to_connected(fcb));
+
+ default:
+ fsmdef_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ break;
+ }
+ break;
+
+ default:
+ fsmdef_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ break;
+ }
+
+ /* call default feature ack handler to take common/default actions */
+ (void) fsmdef_ev_default_feature_ack(event);
+
+ return (SM_RC_END);
+}
+
+static sm_rcs_t
+fsmdef_ev_preserved_feature (sm_event_t *event)
+{
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ cc_feature_t *msg = (cc_feature_t *) event->msg;
+ cc_srcs_t src_id = msg->src_id;
+ cc_features_t ftr_id = msg->feature_id;
+ sm_rcs_t sm_rc;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ fsm_sm_ftr(ftr_id, src_id);
+
+ switch (src_id) {
+ case CC_SRC_UI:
+ case CC_SRC_GSM:
+ switch (msg->feature_id) {
+
+ case CC_FEATURE_END_CALL:
+ sm_rc = fsmdef_release_call(fcb, msg);
+ return (sm_rc);
+
+ default:
+ fsmdef_sm_ignore_src(fcb, __LINE__, src_id);
+ break;
+ }
+
+ break;
+
+ case CC_SRC_SIP:
+ switch (msg->feature_id) {
+ case CC_FEATURE_HOLD:
+ case CC_FEATURE_RESUME:
+ sm_rc = fsmdef_release_call(fcb, msg);
+ return (sm_rc);
+
+ case CC_FEATURE_MEDIA:
+ sm_rc = fsmdef_remote_media(fcb, msg);
+ return (sm_rc);
+
+ case CC_FEATURE_CALLINFO:
+ fsmdef_update_callinfo(fcb, msg);
+ break;
+
+ default:
+ fsmdef_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ break;
+ } /* switch (msg->feature_id) */
+
+ break;
+
+ default:
+ fsmdef_sm_ignore_src(fcb, __LINE__, src_id);
+ break;
+ } /* switch (src_id) */
+
+ return (SM_RC_END);
+}
+
+cc_int32_t
+fsmdef_show_cmd (cc_int32_t argc, const char *argv[])
+{
+ fsmdef_dcb_t *dcb;
+ fsm_fcb_t *fcb;
+ int i = 0;
+ callid_t call_id;
+ unsigned long strtoul_result;
+ char *strtoul_end;
+
+ PR_ASSERT( i == 0 );
+ /*
+ * Check if need help.
+ */
+ if ((argc == 2) && (argv[1][0] == '?')) {
+ debugif_printf("%s", "show fsmdef [all|rel]\n");
+ } else if ((argc == 1) || (strcmp(argv[1], "all") == 0)) {
+ debugif_printf("%s", "\n-------- FSMDEF dcbs --------");
+ debugif_printf("%s", "\ni call_id dcb line");
+ debugif_printf("%s", "\n-----------------------------\n");
+
+ /*
+ * Print info for all dcbs.
+ */
+ FSM_FOR_ALL_CBS(dcb, fsmdef_dcbs, FSMDEF_MAX_DCBS) {
+ debugif_printf("%-2d %-7d 0x%8p %-4d\n",
+ i++, dcb->call_id, dcb, dcb->line);
+ }
+ } else if (strcmp(argv[1], "rel") == 0) {
+ errno = 0;
+ strtoul_result = strtoul(argv[2], &strtoul_end, 10);
+
+ if (errno || argv[2] == strtoul_end || strtoul_result > USHRT_MAX) {
+ debugif_printf("%s parse error of call_id %s", __FUNCTION__, argv[2]);
+ return 0;
+ }
+
+ call_id = (callid_t) strtoul_result;
+
+ debugif_printf("\nDEF %-4d/%d: releasing\n", call_id, 0);
+
+ fcb = fsm_get_fcb_by_call_id_and_type(call_id, FSM_TYPE_DEF);
+ if (fcb == NULL) {
+ return (0);
+ }
+
+ (void)fsmdef_release(fcb, CC_CAUSE_NORMAL, fcb->dcb->send_release);
+ }
+ return (0);
+}
+
+/**
+ *
+ * This function is called to determine if the phone
+ * is in a state where autoAnswer is supported. Even
+ * if the feature is enabled on the line being called,
+ * the phone may be in a state that does not allow it.
+ *
+ * @param autoAnswerAlt to indicate what states auto answer enabled.
+ * @param myCallId call_id
+ *
+ * @return TRUE or FALSE
+ *
+ */
+static int
+fsmdef_check_auto_answer_allowed (int autoAnswerAlt, callid_t myCallId)
+{
+ fsmdef_dcb_t *dcb;
+
+ FSM_FOR_ALL_CBS(dcb, fsmdef_dcbs, FSMDEF_MAX_DCBS) {
+ if (dcb->call_id != myCallId && dcb->fcb != NULL) {
+ /*
+ * autoAnswer is disabled if there is an incoming or an
+ * outgoing call that has not reached the connected state
+ * regardless of the value of autoAnswerAlt.
+ */
+ if ((dcb->fcb->state == FSMDEF_S_COLLECT_INFO) ||
+ (dcb->fcb->state == FSMDEF_S_CALL_SENT) ||
+ (dcb->fcb->state == FSMDEF_S_OUTGOING_PROCEEDING) ||
+ (dcb->fcb->state == FSMDEF_S_KPML_COLLECT_INFO) ||
+ (dcb->fcb->state == FSMDEF_S_CONNECTING) ||
+ (dcb->fcb->state == FSMDEF_S_JOINING)) {
+ return (FALSE);
+ }
+
+ /*
+ * If autoAnswerAlt is 1, then autoAnswer is also
+ * disabled if there is a connected call or a call
+ * on hold.
+ */
+ if (autoAnswerAlt == 1) {
+ if ((dcb->fcb->state == FSMDEF_S_CONNECTED) ||
+ (dcb->fcb->state == FSMDEF_S_PRESERVED) ||
+ (dcb->fcb->state == FSMDEF_S_RESUME_PENDING) ||
+ (dcb->fcb->state == FSMDEF_S_CONNECTED_MEDIA_PEND) ||
+ (dcb->fcb->state == FSMDEF_S_HOLDING) ||
+ (dcb->fcb->state == FSMDEF_S_OUTGOING_ALERTING) ||
+ (dcb->fcb->state == FSMDEF_S_INCOMING_ALERTING) ||
+ (dcb->fcb->state == FSMDEF_S_HOLD_PENDING)) {
+
+ return (FALSE);
+ }
+ } else if (autoAnswerAlt == 0) {
+ if ((dcb->fcb->state == FSMDEF_S_CONNECTED) ||
+ (dcb->fcb->state == FSMDEF_S_PRESERVED) ||
+ (dcb->fcb->state == FSMDEF_S_CONNECTED_MEDIA_PEND) ||
+ (dcb->fcb->state == FSMDEF_S_OUTGOING_ALERTING)) {
+
+ return (FALSE);
+ }
+ }
+ }
+ }
+
+ return (TRUE);
+}
+
+/**
+ *
+ * This function is called when a call is received on a
+ * line that has auto answer enabled and the autoAnswer
+ * timer has expired.
+ *
+ * @param data pointer to opaque data
+ *
+ * @return none
+ *
+ * @pre (fcb and fcb->dcb not_eq NULL)
+ * @pre (data should be fcb data)
+ */
+
+void
+fsmdef_auto_answer_timeout (void *data)
+{
+ static const char fname[] = "fsmdef_auto_answer_timeout";
+ int autoAnswerAlternate = 0;
+ int autoAnswerOverride = 0;
+ int headSetActive = 0;
+ int speakerEnabled = 1;
+ callid_t call_id;
+ char autoAnswerMode[MAX_LINE_AUTO_ANS_MODE_SIZE];
+ fsmdef_dcb_t *dcb;
+
+ call_id = (callid_t)(long)data;
+ if (call_id == CC_NO_CALL_ID) {
+ /* Invalid call id */
+ GSM_ERR_MSG(get_debug_string(FSMDEF_DBG1), 0, 0, fname, "invalid data");
+ return;
+ }
+
+ /* Retrieve dcb from call id */
+ dcb = fsmdef_get_dcb_by_call_id(call_id);
+ if (dcb == NULL) {
+ /*
+ * The only way this should happen is for the
+ * call to be released without cancelling the
+ * autoAnswer timer.
+ */
+ FSM_DEBUG_SM(DEB_F_PREFIX"AutoAnswer timer expired but no dcb was found.\n", DEB_F_PREFIX_ARGS(FSM, fname));
+ return;
+ }
+
+ /*
+ * The device-based config parameter autoAnswerIdleAlternate
+ * determines what state the phone must be in for autoAnswer
+ * feature to be enabled.
+ */
+ config_get_value(CFGID_AUTOANSWER_IDLE_ALTERNATE, &autoAnswerAlternate,
+ sizeof(autoAnswerAlternate));
+
+ if (fsmdef_check_auto_answer_allowed(autoAnswerAlternate, dcb->call_id)) {
+ /*
+ * Is headset active? No need to check if headset has been disabled
+ * on the phone because the headset will never be active if it has.
+ */
+ headSetActive = platGetAudioDeviceStatus(VCM_AUDIO_DEVICE_HEADSET);
+
+ /*
+ * If function call fails, just assume headset is not active
+ * and drive on
+ */
+ if (headSetActive == -1) {
+ FSM_DEBUG_SM(DEB_F_PREFIX"platGetAudioDeviceStatus() for headset failed.\n", DEB_F_PREFIX_ARGS(FSM, fname));
+ headSetActive = 0;
+ }
+
+ /*
+ * Determine where the audio should be sent
+ */
+ config_get_line_string(CFGID_LINE_AUTOANSWER_MODE, autoAnswerMode,
+ dcb->line, sizeof(autoAnswerMode));
+
+ /*
+ * Check to see if the speaker has been disabled
+ */
+ config_get_value(CFGID_SPEAKER_ENABLED, &speakerEnabled,
+ sizeof(speakerEnabled));
+
+ /*
+ * autoAnswer using speaker
+ */
+ if (strcasestr(autoAnswerMode, "speaker")) {
+ /*
+ * Speaker has not been disabled, normal processing.
+ */
+ if (speakerEnabled) {
+ /*
+ * Enable audio path to speaker if headset is not being used.
+ */
+ if (!headSetActive) {
+ platSetSpeakerMode(TRUE);
+ }
+ /* Send offhook event to GSM */
+ cc_int_feature(CC_SRC_UI, CC_SRC_GSM, dcb->call_id,
+ dcb->line, CC_FEATURE_ANSWER, NULL);
+ } else {
+
+ /*
+ * Speaker is disabled, but autoAnswer is enabled and says to
+ * use the speaker. Check the device-based override
+ * parameter to see what action to take. If override is
+ * set just return and let normal call processing happen.
+ * If not, terminate the call. The best SIP response we
+ * could come up in this situation is to send a 480
+ * Temporarily Unavailable.
+ */
+ config_get_value(CFGID_AUTOANSWER_OVERRIDE, &autoAnswerOverride,
+ sizeof(autoAnswerOverride));
+ if (!autoAnswerOverride) {
+ fsmdef_end_call(dcb, CC_TEMP_NOT_AVAILABLE);
+ }
+
+ }
+ } else if (strcasestr(autoAnswerMode, "headset")) {
+ /*
+ * autoAnswer using headset. If headset is not enabled just let
+ * the phone ring normally.
+ */
+ if (headSetActive) {
+ /* Send offhook event to GSM */
+ cc_int_feature(CC_SRC_UI, CC_SRC_GSM, dcb->call_id,
+ dcb->line, CC_FEATURE_ANSWER, NULL);
+ }
+ } else {
+ /*
+ * Unknown autoAnswer mode
+ */
+ FSM_DEBUG_SM(DEB_F_PREFIX"Unknown autoAnswer Mode: %s AutoAnswer is disabled.\n",
+ DEB_F_PREFIX_ARGS(FSM, fname), autoAnswerMode);
+ }
+ }
+}
+
+/*
+ * fsmdef_b2bjoin_invoke
+ *
+ * Description:
+ * This function implements the b2bjoin feature invocation.
+ *
+ * Parameters:
+ * fsmdef_dcb_t *dcb - dcb associated with this call
+ *
+ * Returns: None
+ */
+static void
+fsmdef_b2bjoin_invoke (fsmdef_dcb_t *dcb, cc_feature_data_t *join_data)
+{
+ cc_feature_data_t feature_data;
+ int join_across_lines;
+ cc_uint32_t major_ver;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ // Disable Join if the CUCM doesn't support it
+ platGetSISProtocolVer(&major_ver, NULL, NULL, NULL);
+
+ if ( major_ver < SIS_PROTOCOL_MAJOR_VERSION_UNISON ) {
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG1), dcb->call_id, dcb->line,
+ "fsmdef_b2bjoin_invoke", "Major sis is small than SIS_PROTOCOL_MAJOR_VERSION_UNISON, so, B2BJOIN is disabled");
+ fsm_display_feature_unavailable();
+ fsmdef_sm_ignore_ftr(dcb->fcb, __LINE__, CC_FEATURE_B2B_JOIN);
+ return;
+ }
+
+ config_get_value(CFGID_JOIN_ACROSS_LINES,
+ &join_across_lines, sizeof(join_across_lines));
+ /*
+ * Invoke B2BJoin feature towards SIP. It will send a REFER to CCM
+ */
+ if (join_data) {
+ cc_int_feature(CC_SRC_GSM, CC_SRC_SIP, dcb->call_id,
+ dcb->line, CC_FEATURE_B2B_JOIN, join_data);
+ } else {
+
+ if ((g_b2bjoin_pending == FALSE) && (dcb->fcb->state == FSMDEF_S_HOLDING)
+ && ((fsmdef_get_connected_call() != NULL) ||
+ (fsmdef_get_alertingout_call() != NULL))) {
+ /* Single Button Join case
+ * If Join is pressed on a held call while there is
+ * an active(connected or alerting) call, that completes the Join
+ */
+ feature_data.b2bjoin.b2bjoin_callid = dcb->call_id;
+ feature_data.b2bjoin.b2bjoin_joincallid = dcb->call_id;
+ cc_int_feature(CC_SRC_GSM, CC_SRC_SIP, dcb->call_id,
+ dcb->line, CC_FEATURE_B2B_JOIN, &feature_data);
+ return;
+ }
+
+ if ((g_numofselected_calls == 0) ||
+ ((g_b2bjoin_pending == FALSE) && (join_across_lines == JOIN_ACROSS_LINES_DISABLED) &&
+ (fsmdef_are_there_selected_calls_onotherline(dcb->line) == TRUE))) {
+ dcb->active_feature = CC_FEATURE_B2B_JOIN;
+ feature_data.select.select = TRUE;
+ fsmdef_select_invoke(dcb,&feature_data);
+ fsm_display_use_line_or_join_to_complete();
+ return;
+ }
+ if (g_b2bjoin_pending) {
+ if (join_across_lines == JOIN_ACROSS_LINES_DISABLED) {
+ if (fsmdef_are_join_calls_on_same_line(dcb->line) == FALSE) {
+
+ fsm_display_use_line_or_join_to_complete();
+ g_b2bjoin_pending = FALSE;
+ g_b2bjoin_callid = CC_NO_CALL_ID;
+ return;
+ }
+ }
+ if (dcb->call_id== g_b2bjoin_callid) {
+ /* If join is pending, pressing Join on the same call will cancel it */
+ g_b2bjoin_pending = FALSE;
+ g_b2bjoin_callid = CC_NO_CALL_ID;
+ /* Remove the check mark from it*/
+ cc_int_feature(CC_SRC_UI, CC_SRC_GSM, dcb->call_id,
+ dcb->line, CC_FEATURE_SELECT, NULL);
+ return;
+ }
+ feature_data.b2bjoin.b2bjoin_callid = dcb->call_id;
+ if( g_b2bjoin_callid == CC_NO_CALL_ID ){
+ feature_data.b2bjoin.b2bjoin_joincallid = dcb->call_id;
+ }
+ else{
+ feature_data.b2bjoin.b2bjoin_joincallid = g_b2bjoin_callid;
+ }
+
+ cc_int_feature(CC_SRC_GSM, CC_SRC_SIP, dcb->call_id,
+ dcb->line, CC_FEATURE_B2B_JOIN, &feature_data);
+
+ } else {
+ if ((g_numofselected_calls == 1) && (dcb->selected)) {
+ /*
+ * If this is only one selected call, pressing
+ * Join on it will start a new join operation
+ */
+ g_b2bjoin_pending = TRUE;
+ g_b2bjoin_callid = dcb->call_id;
+ fsm_display_use_line_or_join_to_complete();
+ return;
+ }
+ feature_data.b2bjoin.b2bjoin_callid = dcb->call_id;
+ feature_data.b2bjoin.b2bjoin_joincallid = dcb->call_id;
+ cc_int_feature(CC_SRC_GSM, CC_SRC_SIP, dcb->call_id,
+ dcb->line, CC_FEATURE_B2B_JOIN, &feature_data);
+ }
+ }
+ g_b2bjoin_pending = FALSE;
+ g_b2bjoin_callid = CC_NO_CALL_ID;
+}
+
+/*
+ * fsmdef_select_invoke
+ *
+ *
+ * Description:
+ * This function implements the join feature invocation.
+ *
+ * Parameters:
+ * fsmdef_dcb_t *dcb - dcb associated with this call
+ *
+ * Returns: None
+ */
+static void
+fsmdef_select_invoke (fsmdef_dcb_t *dcb, cc_feature_data_t *select_data)
+{
+ cc_feature_data_t feature_data;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ if (dcb->select_pending) {
+ /* We have sent a select but have not received a
+ * response yet, so diallow further selects till then
+ */
+ return;
+ }
+ if (select_data) {
+ feature_data.select.select = select_data->select.select;
+ } else {
+ if (dcb->selected == TRUE) {
+ feature_data.select.select = FALSE;
+ } else {
+ feature_data.select.select = TRUE;
+ }
+ }
+ if ((g_b2bjoin_pending) && (dcb->call_id== g_b2bjoin_callid)) {
+ /* If join is pending, pressing Select on the same call cancels join*/
+ g_b2bjoin_pending = FALSE;
+ g_b2bjoin_callid = CC_NO_CALL_ID;
+ }
+ dcb->select_pending = TRUE;;
+ cc_int_feature(CC_SRC_GSM, CC_SRC_SIP, dcb->call_id,
+ dcb->line, CC_FEATURE_SELECT, &feature_data);
+}
+
+/*
+ * handle_join_pending
+ *
+ *
+ * Description:
+ * This function checks if the join_pending flag
+ * needs to be cleared.due to the invocation of other features
+ *
+ * Parameters:
+ * fsmdef_dcb_t *dcb - dcb associated with this call
+ *
+ * Returns: None
+ */
+static void fsmdef_handle_join_pending (fsmdef_dcb_t *dcb)
+{
+ if ((g_b2bjoin_pending) && (dcb->call_id == g_b2bjoin_callid)) {
+ /* If join is pending, invoking any other feature cancels join*/
+ g_b2bjoin_pending = FALSE;
+ g_b2bjoin_callid = CC_NO_CALL_ID;
+ }
+}
+
+
+/*
+ * fsmdef_process_dialstring_for_callfwd
+ *
+ * Description:
+ * This function processes the dialstring event for callfwd.
+ *
+ * Parameters:
+ * sm_event_t *event - data associated with this call/dialstring
+ *
+ * Returns: sm_rcs_t
+ */
+static sm_rcs_t
+fsmdef_process_dialstring_for_callfwd (sm_event_t *event)
+{
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ /*
+ * For ccm case just return success.
+ * It will continue the call by sending INVITE
+ */
+ return (SM_RC_SUCCESS);
+}
+
+
+/*
+ * fsmdef_process_cfwd_softkey_event
+ *
+ * Description:
+ * This function processes the cfwd softkey press event for callfwd.
+ *
+ * Parameters:
+ * sm_event_t *event - data associated with this call/dialstring
+ *
+ * Returns: sm_rcs_t
+ */
+static sm_rcs_t
+fsmdef_process_cfwd_softkey_event (sm_event_t *event)
+{
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ cc_feature_t *msg = (cc_feature_t *) event->msg;
+ cc_features_t ftr_id = msg->feature_id;
+ cc_feature_data_t *ftr_data = &(msg->data);
+ cc_action_data_t cc_data;
+ int skMask[MAX_SOFT_KEYS];
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ // check if callfwd is active (i.e. set previously)
+ if (lsm_check_cfwd_all_ccm(dcb->line)) {
+ // call fsmdef_dialstring() version of the function specific
+ // to cfwd feature
+ return (fsmdef_cfwd_clear_ccm(fcb));
+ }
+
+
+ // code from here on is common to both modes/feature_id
+ if (fcb->state == FSMDEF_S_IDLE) {
+
+ /*
+ * The user is attempting to start a cfwdall call on a specific line:
+ * 1. need to place the connected call (if there is one) on hold,
+ * 2. clear any outgoing ringing calls,
+ * 3. initiate this call.
+ */
+ if (fsmdef_wait_to_start_new_call(TRUE, CC_SRC_GSM, dcb->call_id, dcb->line, ftr_id, ftr_data))
+ {
+ dcb->active_feature = CC_FEATURE_NONE;
+ return (SM_RC_END);
+ }
+
+
+ // go offhook and then move to dialing state to collect digits
+ //only contains in initial NOTIFY to CUCM
+ fsmdef_notify_hook_event(fcb,CC_MSG_OFFHOOK,
+ ftr_data->newcall.global_call_id,
+ ftr_data->newcall.prim_call_id,
+ ftr_data->newcall.hold_resume_reason,
+ CC_MONITOR_NONE,
+ (ftr_id == CC_FEATURE_CFWD_ALL) ? CFWDALL_SET:CFWDALL_NONE);
+ cc_call_state(dcb->call_id, dcb->line, CC_STATE_OFFHOOK,
+ ((cc_state_data_t *) (&(dcb->caller_id))));
+
+ fsmdef_call_cc_state_dialing(dcb, FALSE);
+
+ // stop the dial tone for parity with SCCP phone behavior
+ cc_data.tone.tone = VCM_INSIDE_DIAL_TONE;
+ (void)cc_call_action(dcb->call_id, dcb->line, CC_ACTION_STOP_TONE,
+ &cc_data);
+
+ // give different (zip-zip) tone rather than dial tone. zip_zip
+ // is not a permanent tone so it will end on it's own without
+ // us telling media termination to stop playing the tone.
+ cc_data.tone.tone = VCM_ZIP_ZIP;
+ (void)cc_call_action(dcb->call_id, dcb->line, CC_ACTION_PLAY_TONE,
+ &cc_data);
+
+ // move to collect digit info state
+ fsm_change_state(fcb, __LINE__, FSMDEF_S_COLLECT_INFO);
+ } else { // we must be in FSMDEF_S_COLLECT_INFO state
+ // stop the dial tone for parity with SCCP phone behavior
+ cc_data.tone.tone = VCM_INSIDE_DIAL_TONE;
+ (void)cc_call_action(dcb->call_id, dcb->line, CC_ACTION_STOP_TONE,
+ &cc_data);
+
+ // give different (zip-zip) tone rather than dial tone. zip_zip
+ // is not a permanent tone so it will end on it's own without
+ // us telling media termination to stop playing the tone.
+ cc_data.tone.tone = VCM_ZIP_ZIP;
+ (void)cc_call_action(dcb->call_id, dcb->line, CC_ACTION_PLAY_TONE,
+ &cc_data);
+ }
+ ui_control_feature(dcb->line, dcb->call_id, skMask, 1, FALSE);
+
+ return (SM_RC_END);
+}
+
+/**
+ * This function is a reduced version of the fsmdef_dialstring() function.
+ * It is customized for sending INVITE out to CCM to clear CFA state.
+ *
+ * @param[in] fcb The pointer to the fsm_fcb_t structure of this
+ * call chain.
+ *
+ * @pre (fcb not_eq NULL)
+ *
+ * @return sm_rsc_t indicates whether the execution of
+ * next statmachine.
+ */
+static sm_rcs_t
+fsmdef_cfwd_clear_ccm (fsm_fcb_t *fcb)
+{
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ cc_causes_t cause;
+ cc_msgbody_info_t msg_body;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ // to clear CFA in CCM mode... only put service uri... no dialstring.
+ fsmdef_append_dialstring_to_feature_uri(dcb, NULL);
+
+ // From here on all we need to do is send INVITE out.
+ // Since, its not a real call there is no need to update UI etc.
+ // Response to this call will be 5xx so it will be released by the SIP stack.
+ cause = gsmsdp_create_local_sdp(dcb, FALSE, TRUE, TRUE, TRUE, TRUE);
+ if (cause != CC_CAUSE_OK) {
+ FSM_DEBUG_SM(get_debug_string(FSM_DBG_SDP_BUILD_ERR));
+ return (fsmdef_release(fcb, cause, dcb->send_release));
+ }
+
+ /* Build SDP for sending out */
+ cause = gsmsdp_encode_sdp_and_update_version(dcb, &msg_body);
+ if (cause != CC_CAUSE_OK) {
+ FSM_DEBUG_SM(get_debug_string(FSM_DBG_SDP_BUILD_ERR));
+ return (fsmdef_release(fcb, cause, dcb->send_release));
+ }
+ cc_int_setup(CC_SRC_GSM, CC_SRC_SIP, dcb->call_id, dcb->line,
+ &(dcb->caller_id), dcb->alert_info, VCM_INSIDE_RING,
+ VCM_INSIDE_DIAL_TONE, NULL, NULL, FALSE, NULL, &msg_body);
+
+ /*
+ * Since we are sending setup to UI we will also have to send
+ * release to it to for sip stack to clean up the call
+ */
+ dcb->send_release = TRUE;
+
+ FSM_SET_FLAGS(dcb->msgs_sent, FSMDEF_MSG_SETUP);
+
+ fsm_change_state(fcb, __LINE__, FSMDEF_S_CALL_SENT);
+ return (SM_RC_END);
+}
+
+/*
+ * fsmdef_append_dialstring_to_feature_uri
+ *
+ * Description:
+ * This function appends dialstring to feature URI.
+ *
+ * Parameters:
+ * fsmdef_dcb_t *dcb, char *dialstring
+ *
+ * Return Value: none
+ *
+ * Note: TNP specific implementation.
+ */
+static void
+fsmdef_append_dialstring_to_feature_uri (fsmdef_dcb_t *dcb,
+ const char *dialstring)
+{
+ char service_uri[MAX_URL_LENGTH];
+
+ service_uri[0] = '\0';
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ if (dcb == NULL) {
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG_INVALID_DCB),
+ __FUNCTION__);
+ return;
+ }
+
+ switch (dcb->active_feature) {
+ case CC_FEATURE_CFWD_ALL:
+ config_get_string(CFGID_CALL_FORWARD_URI, service_uri,
+ sizeof(service_uri));
+ break;
+ default:
+ // do nothing
+ break;
+ }
+
+ if (service_uri[0] != NUL) {
+ dcb->caller_id.called_number =
+ strlib_update(dcb->caller_id.called_number, service_uri);
+ if (dialstring && dialstring[0]) {
+ dcb->caller_id.called_number =
+ strlib_append(dcb->caller_id.called_number, "-");
+ dcb->caller_id.called_number =
+ strlib_append(dcb->caller_id.called_number, dialstring);
+ }
+ } else {
+ FSM_DEBUG_SM(DEB_F_PREFIX"Configured Feature/Service URI Not Found For Feature[%d]\n", DEB_F_PREFIX_ARGS(FSM, "fsmdef_append_dialstring_to_feature_uri"), (int)dcb->active_feature);
+
+ if (dialstring && dialstring[0]) {
+ dcb->caller_id.called_number =
+ strlib_update(dcb->caller_id.called_number, dialstring);
+ }
+ }
+}
+
+
+/*
+ * fsmdef_is_feature_uri_configured
+ *
+ * Description:
+ * This function checks is a feature URI is configured.
+ *
+ * Parameters:
+ * cc_features_t ftr_id
+ *
+ * Return Value: TRUE or FALSE
+ *
+ * Note: TNP specific implementation.
+ */
+static boolean
+fsmdef_is_feature_uri_configured (cc_features_t ftr_id)
+{
+ char service_uri[MAX_URL_LENGTH];
+
+ service_uri[0] = '\0';
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ switch (ftr_id) {
+ case CC_FEATURE_CFWD_ALL:
+ config_get_string(CFGID_CALL_FORWARD_URI, service_uri,
+ sizeof(service_uri));
+ break;
+ default:
+ break;
+ }
+
+ if (service_uri[0] != NUL) {
+ return TRUE;
+ }
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Configured Feature/Service URI Not Found For Feature[%d]\n", DEB_F_PREFIX_ARGS(FSM, "fsmdef_is_feature_uri_configured"), (int)ftr_id);
+ return FALSE;
+}
+
+/*
+ * fsmdef_check_if_ok_for_dial_call
+ *
+ * Description:
+ * This function checks if there is a call in collecting info state
+ * on a given line.
+ *
+ * Parameters:
+ * line_t line
+ *
+ * Returns: TRUE or FALSE
+ */
+boolean
+fsmdef_check_if_ok_for_dial_call (line_t line)
+{
+
+ fsmdef_dcb_t *dcb;
+
+ FSM_FOR_ALL_CBS(dcb, fsmdef_dcbs, FSMDEF_MAX_DCBS) {
+ if (((dcb->line == line) && (dcb->call_id != CC_NO_CALL_ID)) &&
+ (dcb->fcb != NULL) &&
+ ((dcb->fcb->state == FSMDEF_S_COLLECT_INFO) ||
+ (dcb->fcb->state == FSMDEF_S_CALL_SENT) ||
+ (dcb->fcb->state == FSMDEF_S_OUTGOING_PROCEEDING) ||
+ (dcb->fcb->state == FSMDEF_S_KPML_COLLECT_INFO))) {
+ return (TRUE);
+ }
+ }
+ return (FALSE);
+}
+
+/*
+ * fsmdef_check_if_ok_to_ans_call
+ *
+ * Description:
+ * Checks if given call is in ringing state.
+ *
+ * Parameters:
+ * line
+ * call_id
+ *
+ * Returns: TRUE or FALSE
+ */
+
+boolean
+fsmdef_check_if_ok_to_ans_call (line_t line, callid_t call_id)
+{
+ fsmdef_dcb_t *dcb;
+
+ dcb = fsmdef_get_dcb_by_call_id(call_id);
+
+ if (dcb == NULL) {
+ return (FALSE);
+ }
+
+ if ((dcb->line != line) || ((dcb->fcb != NULL) && (dcb->fcb->state != FSMDEF_S_INCOMING_ALERTING))) {
+ return (FALSE);
+ }
+
+ return (TRUE);
+}
+
+/*
+ * fsmdef_check_if_ok_to_hold_call
+ *
+ * Description:
+ * Checks if the requested call is in connected state.
+ *
+ * Parameters:
+ * line
+ * call_id
+ *
+ * Returns: TRUE - if there is a connected or resume pending call
+ * FALSE - if the call is not in above state
+ */
+boolean
+fsmdef_check_if_ok_to_hold_call (line_t line, callid_t call_id)
+{
+ fsmdef_dcb_t *dcb;
+
+ dcb = fsmdef_get_dcb_by_call_id(call_id);
+
+ if (dcb == NULL) {
+
+ return (FALSE);
+ }
+
+ if ((dcb->line != line) ||
+ ((dcb->fcb != NULL) &&
+ ((dcb->fcb->state != FSMDEF_S_CONNECTED) &&
+ (dcb->fcb->state != FSMDEF_S_CONNECTED_MEDIA_PEND) &&
+ (dcb->fcb->state != FSMDEF_S_RESUME_PENDING)))) {
+
+ return (FALSE);
+ }
+
+ return (TRUE);
+}
+
+/*
+ * fsmdef_check_if_ok_to_resume_call
+ *
+ * Description:
+ * Checks if the requested call is in held state.
+ *
+ * Parameters:
+ * line
+ * call_id
+ *
+ * Returns: TRUE or FALSE
+ */
+boolean
+fsmdef_check_if_ok_to_resume_call (line_t line, callid_t call_id)
+{
+ fsmdef_dcb_t *dcb;
+
+ dcb = fsmdef_get_dcb_by_call_id(call_id);
+
+ if (dcb == NULL) {
+ return (FALSE);
+ }
+
+ if ((dcb->line != line) || ((dcb->fcb != NULL) &&(dcb->fcb->state != FSMDEF_S_HOLDING))) {
+ return (FALSE);
+ }
+
+ return (TRUE);
+}
+
+/*
+ * fsmdef_check_if_ok_to_run_feature
+ *
+ * Description:
+ * Checks if it is ok to run features on the call.
+ *
+ * Parameters:
+ * line
+ * call_id
+ *
+ * Returns: TRUE or FALSE
+ */
+boolean
+fsmdef_check_if_ok_to_run_feature (line_t line, callid_t call_id)
+{
+ fsmdef_dcb_t *dcb;
+
+ dcb = fsmdef_get_dcb_by_call_id(call_id);
+
+ if (dcb == NULL) {
+ return (FALSE);
+ }
+
+ if ((dcb->line != line) ||
+ ((dcb->fcb != NULL) &&
+ (dcb->fcb->state != FSMDEF_S_CONNECTED) &&
+ (dcb->fcb->state != FSMDEF_S_CONNECTED_MEDIA_PEND))) {
+ return (FALSE);
+ }
+
+ return (TRUE);
+}
+
+/*
+ * fsmdef_check_if_ok_to_monitor_update_call
+ *
+ * Description:
+ * Checks if it is ok to update the monitoring call.
+ *
+ * Parameters:
+ * line
+ * call_id
+ *
+ * Returns: TRUE or FALSE
+ */
+boolean
+fsmdef_check_if_ok_to_monitor_update_call (line_t line, callid_t call_id)
+{
+ fsmdef_dcb_t *dcb;
+
+ dcb = fsmdef_get_dcb_by_call_id(call_id);
+
+ if (dcb == NULL) {
+ return (FALSE);
+ }
+
+ if ((dcb->line != line) ||
+ ((dcb->fcb != NULL) &&
+ (dcb->fcb->state != FSMDEF_S_CONNECTED))) {
+ return (FALSE);
+ }
+
+ return (TRUE);
+}
+
+/*
+ * fsmdef_set_call_info_cc_call_state
+ *
+ * Description:
+ * Sets the called number to readable localized values
+ * if it is service URI based feature and invokes cc_call_state()
+ *
+ * Parameters:
+ * dcb
+ * state
+ *
+ * Returns: none
+ */
+static void
+fsmdef_set_call_info_cc_call_state (fsmdef_dcb_t *dcb, cc_states_t state, cc_causes_t cause)
+{
+ cc_state_data_t temp_data;
+ char tmp_str[CALL_BUBBLE_STR_MAX_LEN];
+ int rc = CPR_FAILURE;
+
+ tmp_str[0] = '\0';
+
+ switch (dcb->active_feature) {
+ case CC_FEATURE_CFWD_ALL:
+ rc = platGetPhraseText(STR_INDEX_CALL_FORWARD,
+ (char *) tmp_str,
+ CALL_BUBBLE_STR_MAX_LEN);
+ break;
+ default:
+ rc = CPR_FAILURE;
+ break;
+ }
+
+ switch (state) {
+
+ case CC_STATE_DIALING_COMPLETED:
+ temp_data.dialing_completed.caller_id = dcb->caller_id;
+ break;
+
+ case CC_STATE_CALL_SENT:
+ temp_data.call_sent.caller_id = dcb->caller_id;
+ break;
+
+ case CC_STATE_CALL_FAILED:
+ temp_data.call_failed.caller_id = dcb->caller_id;
+ temp_data.call_failed.cause = cause;
+ break;
+
+ default:
+ /* Set the call id for other states */
+ temp_data.offhook.caller_id = dcb->caller_id;
+ break;
+ }
+
+ if ((rc == CPR_SUCCESS) && strlen(tmp_str) > 0) {
+ temp_data.offhook.caller_id.called_number = tmp_str;
+ }
+
+ cc_call_state(dcb->call_id, dcb->line, state, &temp_data);
+}
+
+/*
+ * fsmdef_get_dcb_by_call_instance_id
+ *
+ * Description:
+ * This function returns fsmdef DCB that has a match for a given call
+ * instance ID of a given line.
+ *
+ * Parameters:
+ * line - the dn line
+ * call_instance_id - for call instance ID.
+ *
+ * Returns: pointer to fsmdef_dcb_t if a matching dcb is found otherwise
+ * returns NULL
+ */
+fsmdef_dcb_t *
+fsmdef_get_dcb_by_call_instance_id (line_t line, uint16_t call_instance_id)
+{
+ fsmdef_dcb_t *dcb;
+
+ FSM_FOR_ALL_CBS(dcb, fsmdef_dcbs, FSMDEF_MAX_DCBS) {
+ if ((dcb->caller_id.call_instance_id == call_instance_id) &&
+ (dcb->line == line)) {
+ return (dcb);
+ }
+ }
+ return (NULL);
+}
+
+/*
+ * fsmdef_ev_join
+ *
+ * Description:
+ * The fsmdef_ev_join function sends an offhook event
+ * to the barging call and sets its state to FSMDEF_S_JOINING.
+ *
+ * Parameters:
+ * data - pointer to the cc_feature_data_t
+ *
+ * Returns:
+ * none
+ */
+static void
+fsmdef_ev_join (cc_feature_data_t *data)
+{
+ fsm_fcb_t *fcb = NULL;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ fcb = fsm_get_fcb_by_call_id_and_type(data->newcall.join.join_call_id,
+ FSM_TYPE_DEF);
+ if (fcb) {
+ fsmdef_dcb_t *dcb = fcb->dcb;
+
+ cc_int_offhook(CC_SRC_GSM, CC_SRC_GSM, CC_NO_CALL_ID, CC_REASON_NONE,
+ dcb->call_id, dcb->line, NULL, CC_MONITOR_NONE,CFWDALL_NONE);
+ fsm_change_state(fcb, __LINE__, FSMDEF_S_JOINING);
+ }
+}
+
+/*
+ * fsmdef_ev_joining_connected_ack
+ *
+ * Description:
+ * The fsmdef_ev_joining_connected_ack negotiates the sdp in the
+ * ack(if there is one) and sets the fsm/ccapi state to connected
+ *
+ * Parameters:
+ * event - pointer to the sm_event_t
+ *
+ * Returns:
+ * sm_rcs_t value
+ */
+static sm_rcs_t
+fsmdef_ev_joining_connected_ack (sm_event_t *event)
+{
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ cc_connected_ack_t *msg = (cc_connected_ack_t *) event->msg;
+ cc_causes_t cause;
+ fsmcnf_ccb_t *ccb;
+ fsm_fcb_t *join_target_fcb;
+ cc_feature_data_t data;
+ cc_uint32_t major_sis_ver = SIS_PROTOCOL_MAJOR_VERSION_SEADRAGON;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ memset(&data, 0, sizeof(data));
+
+ /* Check the remote SDP. The far end may not have included the SDP in an
+ * earlier message, which means that the SDP must be in this message.
+ */
+ if (dcb->remote_sdp_in_ack == TRUE) {
+ cause = gsmsdp_negotiate_answer_sdp(fcb, &msg->msg_body);
+ if (cause != CC_CAUSE_OK) {
+ data.endcall.cause = cause;
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, dcb->call_id, dcb->line,
+ CC_FEATURE_END_CALL, &data);
+ return (SM_RC_END);
+ }
+ }
+
+ platGetSISProtocolVer(&major_sis_ver, NULL, NULL,NULL);
+
+ ccb = fsmcnf_get_ccb_by_call_id(dcb->call_id);
+
+ if (ccb) {
+ join_target_fcb = fsm_get_fcb_by_call_id_and_type(ccb->cnf_call_id,
+ FSM_TYPE_CNF);
+ if ((gsmsdp_is_media_encrypted(dcb) == FALSE) &&
+ (gsmsdp_is_media_encrypted((join_target_fcb!= NULL)?join_target_fcb->dcb:NULL) == TRUE) &&
+ (major_sis_ver < SIS_PROTOCOL_MAJOR_VERSION_MUSTER)) {
+ /*
+ * Target Call was secure, a non-secure is trying to Barge/Monitor,
+ * fail it
+ */
+ data.endcall.cause = CC_CAUSE_SECURITY_FAILURE;
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, dcb->call_id, dcb->line,
+ CC_FEATURE_END_CALL, &data);
+ return (SM_RC_END);
+ }
+ }
+
+ cc_call_state(dcb->call_id, dcb->line, CC_STATE_CONNECTED,
+ (cc_state_data_t *) &(dcb->caller_id));
+ /*
+ * If DSP is not able to start rx/tx channels, release the call
+ */
+ if (dcb->dsp_out_of_resources == TRUE) {
+ data.endcall.cause = CC_CAUSE_NO_MEDIA;
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, dcb->call_id, dcb->line,
+ CC_FEATURE_END_CALL, &data);
+ return (SM_RC_END);
+ }
+
+ if (ccb) {
+ /*
+ * Bridge the conference legs for the join call, even though
+ * it's done here, ccb should only be accessed from fsmcnf
+ */
+ ccb->active = TRUE;
+ ccb->bridged = TRUE;
+ }
+
+ /*
+ * Handle media capability changes if there is before transition to
+ * connected state.
+ */
+ return(fsmdef_transition_to_connected(fcb));
+}
+
+/*
+ * fsmdef_ev_joining_offhook
+ *
+ * Description:
+ * The fsmdef_ev_joining_offhook creates the local sdp
+ * for the sip stack to send 200 Ok out
+ *
+ * Parameters:
+ * event - pointer to the sm_event_t
+ *
+ * Returns:
+ * sm_rcs_t value
+ */
+static sm_rcs_t
+fsmdef_ev_joining_offhook (sm_event_t *event)
+{
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ cc_causes_t cause;
+ cc_msgbody_info_t msg_body;
+ cc_feature_data_t data;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ /* Build our response SDP to include in the connected */
+ cause = gsmsdp_encode_sdp_and_update_version(dcb, &msg_body);
+ if (cause != CC_CAUSE_OK) {
+ FSM_DEBUG_SM(get_debug_string(FSM_DBG_SDP_BUILD_ERR));
+ memset(&data, 0, sizeof(data));
+ data.endcall.cause = cause;
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, dcb->call_id, dcb->line,
+ CC_FEATURE_END_CALL, &data);
+ return (SM_RC_END);
+ }
+ cc_int_connected(CC_SRC_GSM, CC_SRC_SIP, dcb->call_id, dcb->line,
+ &(dcb->caller_id), NULL, &msg_body);
+
+ FSM_SET_FLAGS(dcb->msgs_sent, FSMDEF_MSG_CONNECTED);
+
+ return (SM_RC_END);
+}
+
+/*
+ * fsmdef_extract_join_target
+ *
+ * Description:
+ * The fsmdef_extract_join_target extract join target call id from
+ * the setup message and sends a JOIN event to that call
+ *
+ * Parameters:
+ * event - pointer to the sm_event_t
+ *
+ * Returns:
+ * TRUE or FALSE
+ */
+static boolean
+fsmdef_extract_join_target (sm_event_t *event)
+{
+ static const char fname[] = "fsmdef_extract_join_target";
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ cc_setup_t *msg = (cc_setup_t *) event->msg;
+ callid_t call_id = msg->call_id;
+ line_t line = msg->line;
+ fsmdef_dcb_t *dcb;
+ fsmdef_dcb_t *join_dcb;
+ cc_feature_data_t data;
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ dcb = fcb->dcb;
+
+ if ((msg->call_info.type == CC_FEAT_MONITOR) ||
+ (dcb->session == WHISPER_COACHING)) {
+
+ /* For now, null out the ui id */
+ lsm_set_ui_id(dcb->call_id, CC_NO_CALL_ID);
+ join_dcb =
+ fsmdef_get_dcb_by_call_id(msg->call_info.data.join.join_call_id);
+ if (join_dcb) {
+ dcb->group_id = join_dcb->group_id;
+ memset(&data, 0, sizeof(data));
+ data.newcall.join.join_call_id = call_id;
+
+ if (dcb->session == WHISPER_COACHING) {
+ data.newcall.cause = CC_CAUSE_MONITOR;
+ } else if (msg->call_info.type == CC_FEAT_MONITOR) {
+ data.newcall.cause = CC_CAUSE_MONITOR;
+ // set the session leg of this dcb to monitor
+ dcb->session = MONITOR;
+ }
+ FSM_DEBUG_SM(DEB_L_C_F_PREFIX" dcb-session type is = %s \n",
+ DEB_L_C_F_PREFIX_ARGS(FSM, dcb->line, dcb->call_id, fname),
+ dcb->session == WHISPER_COACHING ? "WHISPER_COACHING" :
+ dcb->session == MONITOR ? "MONITOR" : "PRIMARY");
+
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, join_dcb->call_id, line,
+ CC_FEATURE_JOIN, &data);
+ } else {
+ FSM_DEBUG_SM(DEB_L_C_F_PREFIX"Unable to find join target dcb\n",
+ DEB_L_C_F_PREFIX_ARGS(FSM, dcb->line, dcb->call_id, fname));
+ return (TRUE);
+ }
+ } else {
+ FSM_DEBUG_SM(DEB_L_C_F_PREFIX"Unable to find join target call information\n",
+ DEB_L_C_F_PREFIX_ARGS(FSM, dcb->line, dcb->call_id, fname));
+ return (TRUE);
+ }
+ return (FALSE);
+}
+
+
+/*
+ * fsmdef_ev_notify_feature
+ *
+ * Description:
+ * Handles NOTIFY event in different states.
+ *
+ * Parameters:
+ * msg - message pointer
+ * dcb - pointer to the fsmdef_dcb_t
+ *
+ * Returns:
+ * none
+ */
+static void
+fsmdef_ev_notify_feature (cc_feature_t *msg, fsmdef_dcb_t *dcb)
+{
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+}
+
+/*
+ * fsmdef_notify_hook_event
+ *
+ * Description:
+ * Send offhook/onhook events to SIP (DialogManager) task.
+ *
+ * Parameters:
+ * dcb - pointer to the fsmdef_dcb_t
+ *
+ * Returns:
+ * none
+ */
+static void
+fsmdef_notify_hook_event (fsm_fcb_t *fcb, cc_msgs_t msg, char *global_call_id,
+ callid_t prim_call_id,
+ cc_hold_resume_reason_e consult_reason,
+ monitor_mode_t monitor_mode,
+ cfwdall_mode_t cfwdall_mode)
+{
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__));
+
+ if (msg == CC_MSG_OFFHOOK) {
+ cc_int_offhook(CC_SRC_GSM, CC_SRC_SIP, prim_call_id, consult_reason,
+ fcb->dcb->call_id, fcb->dcb->line,
+ global_call_id, monitor_mode,cfwdall_mode);
+ } else if (msg == CC_MSG_ONHOOK) {
+ cc_int_onhook(CC_SRC_GSM, CC_SRC_SIP, prim_call_id,
+ consult_reason, fcb->dcb->call_id, fcb->dcb->line, FALSE, FALSE);
+ }
+ return;
+}
+
+/*
+ * fsmdef_update_callinfo_security_status
+ *
+ * Description:
+ * The fsmdef_update_callinfo_security_status function updates the call
+ * information that applies to TNP platform.
+ *
+ * Parameters:
+ * dcb - pointer to the fsmdef_dcb_t
+ * call_info - pointer to the cc_feature_data_call_info_t
+ *
+ * Returns:
+ * none
+ */
+static void
+fsmdef_update_callinfo_security_status (fsmdef_dcb_t *dcb,
+ cc_feature_data_call_info_t *call_info)
+{
+ /*
+ * Update security information
+ */
+ if (call_info->feature_flag & CC_SECURITY) {
+ if (sip_regmgr_get_sec_level(dcb->line) != AUTHENTICATED &&
+ sip_regmgr_get_sec_level(dcb->line) != ENCRYPTED ) {
+ // Signaling security can't be trusted downgrade security level to NOT_AUTHENTICATED
+ call_info->security = CC_SECURITY_NOT_AUTHENTICATED;
+ }
+
+ if (dcb->security != call_info->security) {
+ FSM_SET_SECURITY_STATUS(dcb, call_info->security);
+ if ( call_info->security == CC_SECURITY_ENCRYPTED )
+ ui_update_call_security(dcb->line, lsm_get_ui_id(dcb->call_id), CC_SECURITY_ENCRYPTED);
+ else
+ ui_update_call_security(dcb->line, lsm_get_ui_id(dcb->call_id), CC_SECURITY_UNKNOWN);
+
+ dcb->ui_update_required = TRUE;
+ }
+ }
+}
+
+/*
+ * fsmdef_check_retain_fwd_info_state
+ *
+ * Description: This function checks the "Retain Forward Information" config
+ * parameter (only for TNP). It returns TRUE if forward info is
+ * to be retained; FALSE otherwise. This config parameter is
+ * is used to change call bubble display from "Forward " to
+ * "From " when an incoming call is answered AND the config
+ * parameter value is set to TRUE. For non-TNP, this function
+ * will always return FALSE (i.e. not to retain fwd info).
+ *
+ * Parameters: none
+ *
+ * Return Value: TRUE or FALSE
+ */
+boolean
+fsmdef_check_retain_fwd_info_state (void)
+{
+ int retain_fwd_info_cfg = 0; /* default to Disabled (or 0) for no-op */
+
+ config_get_value(CFGID_RETAIN_FORWARD_INFORMATION,
+ &retain_fwd_info_cfg,
+ sizeof(retain_fwd_info_cfg));
+
+ if (!retain_fwd_info_cfg) {
+ return (FALSE); /* do NOT retain forward information */
+ } else {
+ return (TRUE); /* retain forward information */
+ }
+}
+
+void
+fsmdef_init (void)
+{
+ static const char fname[] = "fsmdef_init";
+ fsmdef_dcb_t *dcb;
+
+
+ /*
+ * Initialize the dcbs.
+ */
+ fsmdef_dcbs = (fsmdef_dcb_t *)
+ cpr_calloc(FSMDEF_MAX_DCBS, sizeof(fsmdef_dcb_t));
+ if (fsmdef_dcbs == NULL) {
+ FSM_DEBUG_SM(DEB_F_PREFIX"cpr_calloc returned NULL\n",
+ DEB_F_PREFIX_ARGS(FSM, fname));
+ return;
+ }
+
+ /* Create free media structure list */
+ if (!gsmsdp_create_free_media_list()) {
+ FSM_DEBUG_SM(DEB_F_PREFIX"Unable to create free media list\n",
+ DEB_F_PREFIX_ARGS(FSM, fname));
+ return;
+ }
+
+ DEF_DEBUG(DEB_F_PREFIX"Disabling mass registration print", DEB_F_PREFIX_ARGS(SIP_REG, fname));
+ FSM_FOR_ALL_CBS(dcb, fsmdef_dcbs, FSMDEF_MAX_DCBS) {
+ fsmdef_init_dcb(dcb, CC_NO_CALL_ID, FSMDEF_CALL_TYPE_NONE,
+ FSMDEF_NO_NUMBER, LSM_NO_LINE, NULL);
+ /*
+ * Allocate ringback delay timer for each dcb
+ */
+ dcb->ringback_delay_tmr = cprCreateTimer("Ringback Delay",
+ GSM_RINGBACK_DELAY_TIMER,
+ TIMER_EXPIRATION,
+ gsm_msg_queue);
+ if (dcb->ringback_delay_tmr == NULL) {
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG_TMR_CREATE_FAILED),
+ dcb->call_id, dcb->line, fname, "Ringback Delay");
+ return;
+ }
+
+ /*
+ * Allocate auto answer timer for each dcb
+ */
+ dcb->autoAnswerTimer = cprCreateTimer("Auto Answer",
+ GSM_AUTOANSWER_TIMER,
+ TIMER_EXPIRATION,
+ gsm_msg_queue);
+ if (dcb->autoAnswerTimer == NULL) {
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG_TMR_CREATE_FAILED),
+ dcb->call_id, dcb->line, fname, "Auto Answer");
+ (void)cprDestroyTimer(dcb->ringback_delay_tmr);
+ dcb->ringback_delay_tmr = NULL;
+ return;
+ }
+ dcb->revertTimer = cprCreateTimer("Call Reversion",
+ GSM_REVERSION_TIMER,
+ TIMER_EXPIRATION,
+ gsm_msg_queue);
+ dcb->reversionInterval = -1;
+ if (dcb->revertTimer == NULL) {
+ FSM_DEBUG_SM(get_debug_string(FSMDEF_DBG_TMR_CREATE_FAILED),
+ dcb->call_id, dcb->line, fname, "Hold Revertion");
+
+ (void)cprDestroyTimer(dcb->ringback_delay_tmr);
+ dcb->ringback_delay_tmr = NULL;
+ (void)cprDestroyTimer(dcb->autoAnswerTimer);
+ dcb->autoAnswerTimer = NULL;
+ return;
+ }
+ if (dcb == fsmdef_dcbs) {
+ g_disable_mass_reg_debug_print = TRUE;
+ }
+ }
+ g_disable_mass_reg_debug_print = FALSE;
+
+ /*
+ * Initialize the state/event table.
+ */
+ fsmdef_sm_table.min_state = FSMDEF_S_MIN;
+ fsmdef_sm_table.max_state = FSMDEF_S_MAX;
+ fsmdef_sm_table.min_event = CC_MSG_MIN;
+ fsmdef_sm_table.max_event = CC_MSG_MAX;
+ fsmdef_sm_table.table = (&(fsmdef_function_table[0][0]));
+}
+
+void
+fsmdef_shutdown (void)
+{
+ fsmdef_dcb_t *dcb;
+
+ FSM_FOR_ALL_CBS(dcb, fsmdef_dcbs, FSMDEF_MAX_DCBS) {
+ if (dcb->req_pending_tmr) {
+ (void)cprDestroyTimer(dcb->req_pending_tmr);
+ }
+ if (dcb->err_onhook_tmr) {
+ (void)cprDestroyTimer(dcb->err_onhook_tmr);
+ }
+ if (dcb->ringback_delay_tmr) {
+ (void)cprDestroyTimer(dcb->ringback_delay_tmr);
+ }
+ if (dcb->autoAnswerTimer) {
+ (void)cprDestroyTimer(dcb->autoAnswerTimer);
+ }
+ if (dcb->revertTimer) {
+ (void)cprDestroyTimer(dcb->revertTimer);
+ }
+
+ /* clean media list */
+ gsmsdp_clean_media_list(dcb);
+ }
+
+ /* destroy free media structure list */
+ gsmsdp_destroy_free_media_list();
+
+ cpr_free(fsmdef_dcbs);
+ fsmdef_dcbs = NULL;
+}
+
+static void
+fsmdef_update_calltype (fsm_fcb_t *fcb, cc_feature_t *msg) {
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ cc_feature_data_t *feat_data = &(msg->data);
+ cc_caller_id_t *caller_id;
+
+ if (msg->data_valid == FALSE) {
+ /* No data to use for update. Just ignore the event. */
+ return;
+ }
+
+ if (feat_data->call_info.feature_flag & CC_CALLER_ID) {
+ caller_id = &feat_data->call_info.caller_id;
+ if (caller_id->call_type == CC_CALL_FORWARDED) {
+ if (fsmdef_check_retain_fwd_info_state()) {
+ dcb->call_type = FSMDEF_CALL_TYPE_FORWARD;
+ }
+ }
+ }
+}
+
diff --git a/libs/sipcc/core/gsm/fsmxfr.c b/libs/sipcc/core/gsm/fsmxfr.c
new file mode 100755
index 0000000000..a6b022cdce
--- /dev/null
+++ b/libs/sipcc/core/gsm/fsmxfr.c
@@ -0,0 +1,3042 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "cpr_types.h"
+#include "cpr_stdlib.h"
+#include "cpr_stdio.h"
+#include "cpr_string.h"
+#include "fim.h"
+#include "lsm.h"
+#include "sm.h"
+#include "ccapi.h"
+#include "phone_debug.h"
+#include "text_strings.h"
+#include "fsm.h"
+#include "uiapi.h"
+#include "debug.h"
+#include "regmgrapi.h"
+#include "platform_api.h"
+
+extern fsmdef_dcb_t *fsmdef_dcbs;
+
+#define FSMXFR_NULL_DIALSTRING '\0'
+static fsmxfr_xcb_t *fsmxfr_xcbs;
+
+typedef enum fsmxfr_states_t_ {
+ FSMXFR_S_MIN = -1,
+ FSMXFR_S_IDLE,
+ FSMXFR_S_ACTIVE,
+ FSMXFR_S_MAX
+} fsmxfr_states_t;
+
+static const char *fsmxfr_state_names[] = {
+ "IDLE",
+ "ACTIVE"
+};
+
+
+static sm_rcs_t fsmxfr_ev_idle_setup(sm_event_t *event);
+static sm_rcs_t fsmxfr_ev_idle_feature(sm_event_t *event);
+static sm_rcs_t fsmxfr_ev_idle_dialstring(sm_event_t *event);
+static sm_rcs_t fsmxfr_ev_active_connected_ack(sm_event_t *event);
+static sm_rcs_t fsmxfr_ev_active_release(sm_event_t *event);
+static sm_rcs_t fsmxfr_ev_active_release_complete(sm_event_t *event);
+static sm_rcs_t fsmxfr_ev_active_feature(sm_event_t *event);
+static sm_rcs_t fsmxfr_ev_active_feature_ack(sm_event_t *event);
+static sm_rcs_t fsmxfr_ev_active_onhook(sm_event_t *event);
+static sm_rcs_t fsmxfr_ev_active_dialstring(sm_event_t *event);
+static sm_rcs_t fsmxfr_ev_active_proceeding(sm_event_t *event);
+
+static sm_function_t fsmxfr_function_table[FSMXFR_S_MAX][CC_MSG_MAX] =
+{
+/* FSMXFR_S_IDLE ------------------------------------------------------------ */
+ {
+ /* FSMXFR_E_SETUP */ fsmxfr_ev_idle_setup,
+ /* FSMXFR_E_SETUP_ACK */ NULL,
+ /* FSMXFR_E_PROCEEDING */ NULL,
+ /* FSMXFR_E_ALERTING */ NULL,
+ /* FSMXFR_E_CONNECTED */ NULL,
+ /* FSMXFR_E_CONNECTED_ACK */ NULL,
+ /* FSMXFR_E_RELEASE */ NULL,
+ /* FSMXFR_E_RELEASE_COMPLETE */ NULL,
+ /* FSMXFR_E_FEATURE */ fsmxfr_ev_idle_feature,
+ /* FSMXFR_E_FEATURE_ACK */ NULL,
+ /* FSMXFR_E_OFFHOOK */ NULL,
+ /* FSMXFR_E_ONHOOK */ NULL,
+ /* FSMXFR_E_LINE */ NULL,
+ /* FSMXFR_E_DIGIT_BEGIN */ NULL,
+ /* FSMXFR_E_DIGIT */ NULL,
+ /* FSMXFR_E_DIALSTRING */ fsmxfr_ev_idle_dialstring,
+ /* FSMXFR_E_MWI */ NULL,
+ /* FSMXFR_E_SESSION_AUDIT */ NULL
+ },
+
+/* FSMXFR_S_ACTIVE ---------------------------------------------------- */
+ {
+ /* FSMXFR_E_SETUP */ NULL,
+ /* FSMXFR_E_SETUP_ACK */ NULL,
+ /* FSMXFR_E_PROCEEDING */ fsmxfr_ev_active_proceeding,
+ /* FSMXFR_E_ALERTING */ NULL,
+ /* FSMXFR_E_CONNECTED */ NULL,
+ /* FSMXFR_E_CONNECTED_ACK */ fsmxfr_ev_active_connected_ack,
+ /* FSMXFR_E_RELEASE */ fsmxfr_ev_active_release,
+ /* FSMXFR_E_RELEASE_COMPLETE */ fsmxfr_ev_active_release_complete,
+ /* FSMXFR_E_FEATURE */ fsmxfr_ev_active_feature,
+ /* FSMXFR_E_FEATURE_ACK */ fsmxfr_ev_active_feature_ack,
+ /* FSMXFR_E_OFFHOOK */ NULL,
+ /* FSMXFR_E_ONHOOK */ fsmxfr_ev_active_onhook,
+ /* FSMXFR_E_LINE */ NULL,
+ /* FSMXFR_E_DIGIT_BEGIN */ NULL,
+ /* FSMXFR_E_DIGIT */ NULL,
+ /* FSMXFR_E_DIALSTRING */ fsmxfr_ev_active_dialstring,
+ /* FSMXFR_E_MWI */ NULL,
+ /* FSMXFR_E_SESSION_AUDIT */ NULL
+ }
+};
+
+static sm_table_t fsmxfr_sm_table;
+sm_table_t *pfsmxfr_sm_table = &fsmxfr_sm_table;
+
+const char *
+fsmxfr_state_name (int state)
+{
+ if ((state <= FSMXFR_S_MIN) || (state >= FSMXFR_S_MAX)) {
+ return (get_debug_string(GSM_UNDEFINED));
+ }
+
+ return (fsmxfr_state_names[state]);
+}
+
+
+static int
+fsmxfr_get_new_xfr_id (void)
+{
+ static int xfr_id = 0;
+
+ if (++xfr_id < 0) {
+ xfr_id = 1;
+ }
+
+ return (xfr_id);
+}
+
+/**
+ *
+ * Sets/rest transfer complete flag in the DCB so it can be used in
+ * UI to indicate if the call is ended because of xfer or endcall.
+ *
+ * @cns_call_id consult call id
+ * @Xfr_call_id transfer call id
+ *
+ * @return none
+ *
+ * @pre (none)
+ */
+void fsmxfr_mark_dcb_for_xfr_complete(callid_t cns_call_id, callid_t xfr_call_id,
+ boolean set_flag)
+{
+ fsm_fcb_t *cns_fcb, *xfr_fcb;
+
+ cns_fcb = fsm_get_fcb_by_call_id_and_type(cns_call_id,
+ FSM_TYPE_DEF);
+ xfr_fcb = fsm_get_fcb_by_call_id_and_type(xfr_call_id,
+ FSM_TYPE_DEF);
+ if (set_flag) {
+ if (cns_fcb && cns_fcb->dcb) {
+ FSM_SET_FLAGS(cns_fcb->dcb->flags, FSMDEF_F_XFER_COMPLETE);
+ }
+ if (xfr_fcb && xfr_fcb->dcb) {
+ FSM_SET_FLAGS(xfr_fcb->dcb->flags, FSMDEF_F_XFER_COMPLETE);
+ }
+ } else {
+ if (cns_fcb && cns_fcb->dcb) {
+ FSM_RESET_FLAGS(cns_fcb->dcb->flags, FSMDEF_F_XFER_COMPLETE);
+ }
+ if (xfr_fcb && xfr_fcb->dcb) {
+ FSM_RESET_FLAGS(xfr_fcb->dcb->flags, FSMDEF_F_XFER_COMPLETE);
+ }
+ }
+}
+
+/**
+ *
+ * Get active trasnfer state machine information (in active state).
+ *
+ * @param none
+ *
+ * @return fsm_fcb_t if there is a active trasnfer pending
+ * else NULL
+ *
+ * @pre (none)
+ */
+
+
+fsm_fcb_t *fsmxfr_get_active_xfer(void)
+{
+ fsm_fcb_t *fcb;
+ fsmxfr_xcb_t *xcb;
+
+ FSM_FOR_ALL_CBS(xcb, fsmxfr_xcbs, FSMXFR_MAX_XCBS) {
+ fcb = fsm_get_fcb_by_call_id_and_type(xcb->xfr_call_id,
+ FSM_TYPE_XFR);
+ if (fcb && fcb->state == FSMXFR_S_ACTIVE) {
+ return(fcb);
+ }
+ }
+
+ return(NULL);
+}
+
+
+static void
+fsmxfr_init_xcb (fsmxfr_xcb_t *xcb)
+{
+ if (xcb != NULL) {
+ xcb->xfr_id = FSM_NO_ID;
+ xcb->xfr_call_id = CC_NO_CALL_ID;
+ xcb->cns_call_id = CC_NO_CALL_ID;
+ xcb->xfr_line = CC_NO_LINE;
+ xcb->cns_line = CC_NO_LINE;
+ xcb->type = FSMXFR_TYPE_NONE;
+ xcb->method = CC_XFER_METHOD_NONE;
+ xcb->cnf_xfr = FALSE;
+ xcb->active = FALSE;
+ xcb->mode = FSMXFR_MODE_TRANSFEROR;
+ xcb->xfer_comp_req = FALSE;
+ xcb->xfr_orig = CC_SRC_MIN;
+
+ if (xcb->xcb2 != NULL) {
+ fsmxfr_init_xcb(xcb->xcb2);
+ xcb->xcb2 = NULL;
+ }
+
+ if (xcb->dialstring != NULL) {
+ cpr_free(xcb->dialstring);
+ xcb->dialstring = NULL;
+ }
+ if (xcb->queued_dialstring != NULL) {
+ cpr_free(xcb->queued_dialstring);
+ xcb->queued_dialstring = NULL;
+ }
+ if (xcb->referred_by != NULL) {
+ cpr_free(xcb->referred_by);
+ xcb->referred_by = NULL;
+ }
+ }
+}
+
+
+static fsmxfr_xcb_t *
+fsmxfr_get_xcb_by_xfr_id (int xfr_id)
+{
+ static const char fname[] = "fsmxfr_get_xcb_by_xfr_id";
+ fsmxfr_xcb_t *xcb;
+ fsmxfr_xcb_t *xcb_found = NULL;
+
+ FSM_FOR_ALL_CBS(xcb, fsmxfr_xcbs, FSMXFR_MAX_XCBS) {
+ if (xcb->xfr_id == xfr_id) {
+ xcb_found = xcb;
+
+ FSM_DEBUG_SM(get_debug_string(FSMXFR_DBG_PTR), xcb->xfr_id,
+ xcb->xfr_call_id, xcb->cns_call_id, fname, xcb);
+
+ break;
+ }
+ }
+
+
+ return (xcb_found);
+}
+
+
+/*
+ * Function: fsmxfr_get_new_xfr_context
+ *
+ * Parameters:
+ * xfr_call_id: call_id for the call initiating the transfer
+ * type: attended or unattended transfer
+ * method: BYE/ALSO or REFER method of transfer
+ * local: local or remote initiated transfer
+ *
+ * Description: This function creates a new transfer context by:
+ * - getting a free xcb
+ * - creating new xfr_id and cns_call_id
+ *
+ * Returns: xcb
+ *
+ */
+static fsmxfr_xcb_t *
+fsmxfr_get_new_xfr_context (callid_t xfr_call_id, line_t line, fsmxfr_types_t type,
+ cc_xfer_methods_t method, fsmxfr_modes_t mode)
+{
+ static const char fname[] = "fsmxfr_get_new_xfr_context";
+ fsmxfr_xcb_t *xcb;
+
+ xcb = fsmxfr_get_xcb_by_xfr_id(FSM_NO_ID);
+ if (xcb != NULL) {
+ xcb->xfr_id = fsmxfr_get_new_xfr_id();
+ xcb->xfr_call_id = xfr_call_id;
+ xcb->cns_call_id = cc_get_new_call_id();
+ xcb->xfr_line = line;
+ xcb->cns_line = line;
+ xcb->type = type;
+ xcb->method = method;
+ xcb->mode = mode;
+
+ FSM_DEBUG_SM(get_debug_string(FSMXFR_DBG_PTR), xcb->xfr_id,
+ xcb->xfr_call_id, xcb->cns_call_id, fname, xcb);
+ }
+
+ return (xcb);
+}
+
+
+fsmxfr_xcb_t *
+fsmxfr_get_xcb_by_call_id (callid_t call_id)
+{
+ fsmxfr_xcb_t *xcb;
+ fsmxfr_xcb_t *xcb_found = NULL;
+
+ FSM_FOR_ALL_CBS(xcb, fsmxfr_xcbs, FSMXFR_MAX_XCBS) {
+ if ((xcb->xfr_call_id == call_id) || (xcb->cns_call_id == call_id)) {
+ xcb_found = xcb;
+ break;
+ }
+ }
+
+ return (xcb_found);
+}
+
+/**
+ *
+ * Cancel tranfer operation by sending cancel event to SIP stack.
+ * This routine is used in roundtable phone.
+ *
+ * @param line, call_id, target_call_id, cause (implicit or explicit)
+ *
+ * @return void
+ *
+ * @pre (none)
+ */
+void
+fsmxfr_feature_cancel (fsmxfr_xcb_t *xcb, line_t line, callid_t call_id,
+ callid_t target_call_id,
+ cc_rcc_skey_evt_type_e cause)
+{
+ static const char fname[] = "fsmxfr_feature_cancel";
+ cc_feature_data_t data;
+ fsm_fcb_t *fcb_def;
+
+ DEF_DEBUG(DEB_F_PREFIX"Sending cancel call_id = %d, t_id=%d, cause = %d\n",
+ DEB_F_PREFIX_ARGS(GSM, fname), call_id, target_call_id, cause);
+
+ fcb_def = fsm_get_fcb_by_call_id_and_type(call_id, FSM_TYPE_DEF);
+
+ if ((cause == CC_SK_EVT_TYPE_EXPLI) &&
+ (fcb_def != NULL) && ((fcb_def->dcb->selected == FALSE) &&
+ ((fcb_def->state == FSMDEF_S_OUTGOING_ALERTING) ||
+ ((fcb_def->state == FSMDEF_S_CONNECTED) &&
+ (fcb_def->dcb->spoof_ringout_requested == TRUE) &&
+ (fcb_def->dcb->spoof_ringout_applied == TRUE))))) {
+
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, call_id,
+ line, CC_FEATURE_END_CALL, NULL);
+ }
+
+ fcb_def = fsm_get_fcb_by_call_id_and_type(target_call_id, FSM_TYPE_DEF);
+
+ if ((cause == CC_SK_EVT_TYPE_EXPLI) &&
+ (fcb_def != NULL) && ((fcb_def->dcb->selected == FALSE) &&
+ ((fcb_def->state == FSMDEF_S_OUTGOING_ALERTING) ||
+ ((fcb_def->state == FSMDEF_S_CONNECTED) &&
+ (fcb_def->dcb->spoof_ringout_requested == TRUE) &&
+ (fcb_def->dcb->spoof_ringout_applied == TRUE))))) {
+
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, target_call_id,
+ line, CC_FEATURE_END_CALL, NULL);
+ }
+
+ data.cancel.target_call_id = target_call_id;
+ data.cancel.call_id = call_id;
+ data.cancel.cause = cause;
+
+ cc_int_feature(CC_SRC_GSM, CC_SRC_SIP, call_id,
+ line, CC_FEATURE_CANCEL, &data);
+}
+
+
+void
+fsmxfr_update_xfr_context (fsmxfr_xcb_t *xcb, callid_t old_call_id,
+ callid_t new_call_id)
+{
+ static const char fname[] = "fsmxfr_update_xfr_context";
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered. \n", DEB_F_PREFIX_ARGS(FSM, "fsmxfr_update_xfr_context"));
+
+ if (xcb != NULL) {
+ if (old_call_id == xcb->xfr_call_id) {
+ xcb->xfr_call_id = new_call_id;
+ } else if (old_call_id == xcb->cns_call_id) {
+ xcb->cns_call_id = new_call_id;
+ }
+
+ FSM_DEBUG_SM(get_debug_string(FSMXFR_DBG_PTR), xcb->xfr_id,
+ xcb->xfr_call_id, xcb->cns_call_id, fname, xcb);
+ }
+}
+
+/*
+ * Function to get line number of other call associated in
+ * transfer.
+ *
+ * @param xcb and call_id.
+ *
+ * @return void
+ *
+ */
+line_t
+fsmxfr_get_other_line (fsmxfr_xcb_t *xcb, callid_t call_id)
+{
+ line_t other_line = CC_NO_LINE;
+
+ if (xcb != NULL) {
+ if (xcb->xfr_call_id == call_id) {
+ other_line = xcb->cns_line;
+ } else if (xcb->cns_call_id == call_id) {
+ other_line = xcb->xfr_line;
+ }
+ }
+
+ return (other_line);
+}
+
+callid_t
+fsmxfr_get_other_call_id (fsmxfr_xcb_t *xcb, callid_t call_id)
+{
+ callid_t other_call_id = CC_NO_CALL_ID;
+
+ if (xcb != NULL) {
+ if (xcb->xfr_call_id == call_id) {
+ other_call_id = xcb->cns_call_id;
+ } else if (xcb->cns_call_id == call_id) {
+ other_call_id = xcb->xfr_call_id;
+ }
+ }
+
+ return (other_call_id);
+}
+
+
+/*
+ * Function: fsmxfr_remove_fcb
+ *
+ * Parameters:
+ * xfr_id: xfr_id for the transfer
+ * call_id: call_id that identifies the fcb to be removed
+ *
+ * Description: This function will remove the fcb identified by the given
+ * call_id from the xcb. And the function will free the xcb
+ * if both fcbs have been removed.
+ *
+ * Returns: none
+ *
+ * Note: This is a helper function for fsmxfr_cleanup. It allows fsmxfr_cleanup
+ * to cleanup one fcb (one call involved in the transfer) independent
+ * of the other involved fcb.
+ */
+static void
+fsmxfr_remove_fcb (fsm_fcb_t *fcb, callid_t call_id)
+{
+ fsmxfr_xcb_t *xcb = fcb->xcb;
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered. \n", DEB_F_PREFIX_ARGS(FSM, "fsmxfr_remove_fcb"));
+
+ if (xcb != NULL) {
+ fsmxfr_update_xfr_context(xcb, call_id, CC_NO_CALL_ID);
+
+ /*
+ * Free the xcb if both fcb references have been removed.
+ */
+ if ((xcb->xfr_call_id == CC_NO_CALL_ID) &&
+ (xcb->cns_call_id == CC_NO_CALL_ID)) {
+ fsmxfr_init_xcb(xcb);
+ }
+ }
+}
+
+
+static void
+fsmxfr_cnf_cleanup (fsmxfr_xcb_t *xcb)
+{
+ fsmdef_dcb_t *xfr_dcb;
+ fsmdef_dcb_t *cns_dcb;
+ cc_feature_data_t ftr_data;
+
+ cns_dcb = fsm_get_dcb(xcb->cns_call_id);
+ xfr_dcb = fsm_get_dcb(xcb->xfr_call_id);
+
+ ftr_data.endcall.cause = CC_CAUSE_NORMAL;
+ ftr_data.endcall.dialstring[0] = '\0';
+ /*
+ * This is a conference transfer hence we are cleaning
+ * up both the lines
+ */
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM,
+ cns_dcb->call_id, cns_dcb->line,
+ CC_FEATURE_END_CALL, &ftr_data);
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM,
+ xfr_dcb->call_id, xfr_dcb->line,
+ CC_FEATURE_END_CALL, &ftr_data);
+}
+
+
+static void
+fsmxfr_cleanup (fsm_fcb_t *fcb, int fname, boolean both)
+{
+ fsm_fcb_t *other_fcb = NULL;
+ callid_t call_id = fcb->call_id;
+ callid_t other_call_id = CC_NO_CALL_ID;
+ line_t other_line;
+
+
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered. \n", DEB_F_PREFIX_ARGS(FSM, "fsmxfr_cleanup"));
+ other_call_id = fsmxfr_get_other_call_id(fcb->xcb, call_id);
+ other_line = fsmxfr_get_other_line(fcb->xcb, call_id);
+
+ if (other_call_id != CC_NO_CALL_ID) {
+ other_fcb = fsm_get_fcb_by_call_id_and_type(other_call_id,
+ FSM_TYPE_XFR);
+ }
+
+ if (fcb->xcb && (fcb->xcb->cnf_xfr != TRUE) &&
+ (call_id == fcb->xcb->xfr_call_id)) {
+
+ if (other_call_id != CC_NO_CALL_ID) {
+ /*
+ * Not clearing consulation call, so change consultation call
+ * attribute to display connected softkey set. Do not change
+ * softkey set if it is a transfer o
+ */
+ cc_call_attribute(other_call_id, other_line, NORMAL_CALL);
+ }
+ }
+ /*
+ * Check if the user wanted to cleanup the whole xcb.
+ * If so, then we will grab the other fcb first and call this function
+ * again with this other fcb. The whole xcb will be freed after this block
+ * of code because both call_ids will be -1, which tells
+ * fsmxfr_remove_fcb to free the xcb.
+ */
+ if (both) {
+ FSM_DEBUG_SM(DEB_F_PREFIX"clean both. \n", DEB_F_PREFIX_ARGS(FSM, "fsmxfr_cleanup"));
+
+ if (other_call_id != CC_NO_CALL_ID) {
+ if (other_fcb != NULL) {
+ fsmxfr_cleanup(other_fcb, fname, FALSE);
+ } else {
+ /*
+ * If there is no other FCB, we need to clean up so that the
+ * XCB will be deleted.
+ */
+ fsmxfr_update_xfr_context(fcb->xcb, other_call_id,
+ CC_NO_CALL_ID);
+ }
+ }
+ }
+
+ /*
+ * Remove the reference to this fcb from the xcb
+ */
+ fsmxfr_remove_fcb(fcb, fcb->call_id);
+
+ /*
+ * Move this fcb to the IDLE state
+ */
+ fsm_change_state(fcb, fname, FSMXFR_S_IDLE);
+
+ /*
+ * Reset the data for this fcb. The fcb is still included in a call
+ * so set the call_id and dcb values accordingly.
+ */
+ fsm_init_fcb(fcb, fcb->call_id, fcb->dcb, FSM_TYPE_XFR);
+}
+
+
+void
+fsmxfr_free_cb (fim_icb_t *icb, callid_t call_id)
+{
+ fsm_fcb_t *fcb = NULL;
+
+ if (call_id != CC_NO_CALL_ID) {
+ fcb = fsm_get_fcb_by_call_id_and_type(call_id, FSM_TYPE_XFR);
+
+ if (fcb != NULL) {
+ fsmxfr_cleanup(fcb, __LINE__, FALSE);
+ fsm_init_fcb(fcb, CC_NO_CALL_ID, FSMDEF_NO_DCB, FSM_TYPE_NONE);
+ }
+ }
+}
+
+
+fsmxfr_types_t
+fsmxfr_get_xfr_type (callid_t call_id)
+{
+ fsmxfr_xcb_t *xcb;
+ fsmxfr_types_t type = FSMXFR_TYPE_BLND_XFR;
+
+ xcb = fsmxfr_get_xcb_by_call_id(call_id);
+ if (xcb != NULL) {
+ type = xcb->type;
+ }
+
+ return (type);
+}
+
+
+cc_features_t
+fsmxfr_type_to_feature (fsmxfr_types_t type)
+{
+ cc_features_t feature;
+
+ if (type == FSMXFR_TYPE_XFR) {
+ feature = CC_FEATURE_XFER;
+ } else {
+ feature = CC_FEATURE_BLIND_XFER;
+ }
+
+ return (feature);
+}
+
+
+/*******************************************************************
+ * event functions
+ */
+
+
+static sm_rcs_t
+fsmxfr_ev_idle_setup (sm_event_t *event)
+{
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ cc_setup_t *msg = (cc_setup_t *) event->msg;
+ fsmxfr_xcb_t *xcb;
+
+ /*
+ * If this is the consultation call involved in a transfer,
+ * then set the rest of the data required to make the transfer
+ * happen. The data is the xcb in the fcb. The data is set now
+ * because we did not have the fcb when the transfer was
+ * initiated. The fcb is created when a new_call event is
+ * received by the FIM, not when a transfer event is received.
+ */
+
+ /*
+ * Ignore this event if this call is not involved in a transfer.
+ */
+ xcb = fsmxfr_get_xcb_by_call_id(msg->call_id);
+ if (xcb == NULL) {
+ return (SM_RC_DEF_CONT);
+ }
+ fcb->xcb = xcb;
+
+ fsm_change_state(fcb, __LINE__, FSMXFR_S_ACTIVE);
+
+ return (SM_RC_CONT);
+}
+
+
+static boolean
+fsmxfr_copy_dialstring (char **saved_dialstring, char *dialstring)
+{
+ char *tempstring;
+ int len;
+
+ if (saved_dialstring == NULL) {
+ return (FALSE);
+ }
+
+ /*
+ * Make sure we have a valid dialstring.
+ */
+ if ((dialstring == NULL) || (dialstring[0] == '\0')) {
+ return (FALSE);
+ }
+
+ /*
+ * Copy the dialstring to the xcb. We will need it later when
+ * SIP sends the RELEASE so that we can send out the
+ * NEWCALL to start the call to the target.
+ */
+ len = (strlen(dialstring) + 1) * sizeof(char);
+ tempstring = (char *) cpr_malloc(len);
+ if (tempstring != NULL) {
+ sstrncpy(tempstring, dialstring, len);
+
+ *saved_dialstring = tempstring;
+ }
+
+ return (TRUE);
+}
+
+static void
+fsmxfr_set_xfer_data (cc_causes_t cause, cc_xfer_methods_t method,
+ callid_t target_call_id, char *dialstring,
+ cc_feature_data_xfer_t *xfer)
+{
+ xfer->cause = cause;
+ xfer->method = method;
+ xfer->target_call_id = target_call_id;
+ sstrncpy(xfer->dialstring, dialstring, CC_MAX_DIALSTRING_LEN);
+}
+
+
+static boolean
+fsmxfr_remote_transfer (fsm_fcb_t *fcb, cc_features_t ftr_id,
+ callid_t call_id, line_t line, char *dialstring,
+ char *referred_by)
+{
+ fsmxfr_types_t type;
+ int free_lines;
+ cc_feature_data_t data;
+ fsmxfr_xcb_t *xcb;
+ fsmxfr_xcb_t *primary_xcb;
+ callid_t cns_call_id;
+ line_t newcall_line = 0;
+
+ memset(&data, 0, sizeof(cc_feature_data_t));
+
+ /*
+ * Make sure we have a free line for the consultation
+ * call if this is an attended transfer. We do not need this
+ * check for an unattended transfer, because the stack will
+ * send up a release for the call being transferred, which will
+ * then trigger the fsmxfr to send out the newcall in the same
+ * plane of the call being released.
+ */
+ if (ftr_id == CC_FEATURE_XFER) {
+ /*
+ * Make sure we have a free line to start the
+ * consultation call.
+ */
+ free_lines = lsm_get_instances_available_cnt(line, TRUE);
+ if (free_lines <= 0) {
+ /*
+ * No free lines - let the user know and end this
+ * request.
+ */
+ fsm_display_no_free_lines();
+
+ return (FALSE);
+ }
+ }
+
+ newcall_line = lsm_get_newcall_line(line);
+ if (newcall_line == NO_LINES_AVAILABLE) {
+ /*
+ * Error Pass Limit - let the user know and end this request.
+ */
+ lsm_ui_display_notify_str_index(STR_INDEX_ERROR_PASS_LIMIT);
+ return (FALSE);
+ }
+
+ /*
+ * Get a new xcb and new xfr id - This is the handle that will
+ * identify the xfr.
+ */
+ type = ((ftr_id == CC_FEATURE_XFER) ?
+ (FSMXFR_TYPE_XFR) : (FSMXFR_TYPE_BLND_XFR));
+
+ primary_xcb = fsmxfr_get_xcb_by_call_id(call_id);
+
+ xcb = fsmxfr_get_new_xfr_context(call_id, line, type, CC_XFER_METHOD_REFER,
+ FSMXFR_MODE_TRANSFEREE);
+ if (xcb == NULL) {
+ return (FALSE);
+ }
+
+ if (primary_xcb) {
+ fcb->xcb->xcb2 = xcb;
+ fcb->xcb->active = TRUE;
+ } else {
+ fcb->xcb = xcb;
+ }
+
+ xcb->cns_line = newcall_line;
+ cns_call_id = xcb->cns_call_id;
+ fsmxfr_set_xfer_data(CC_CAUSE_OK, CC_XFER_METHOD_REFER, cns_call_id,
+ FSMXFR_NULL_DIALSTRING, &(data.xfer));
+
+ cc_int_feature_ack(CC_SRC_GSM, CC_SRC_SIP, call_id,
+ line, ftr_id, &data, CC_CAUSE_NORMAL);
+
+ if (ftr_id == CC_FEATURE_XFER) {
+ /*
+ * This call needs to go on hold so we can start the
+ * consultation call. The call may already be on hold,
+ * so the event will just be silently ignored. We set
+ * the line number to 0xFF so that GSM will know this
+ * came from a transfer and we only want to put the call
+ * on local hold. We don't want to send an Invite Hold
+ * to the SIP stack.
+ */
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, call_id,
+ 0xFF, CC_FEATURE_HOLD, NULL);
+
+ /*
+ * Initiate the consultation call.
+ */
+
+ /*
+ * Make sure we have a valid dialstring.
+ */
+ if ((dialstring == NULL) || (dialstring[0] == '\0')) {
+ return (FALSE);
+ }
+
+ /*
+ * memset is done because if redirects[0].number is
+ * corrupted we might think that it is a blind
+ * transfer
+ */
+ memset(data.newcall.redirect.redirects[0].number, 0,
+ sizeof(CC_MAX_DIALSTRING_LEN));
+ data.newcall.cause = CC_CAUSE_XFER_REMOTE;
+ data.newcall.redirect.redirects[0].redirect_reason =
+ CC_REDIRECT_REASON_DEFLECTION;
+ sstrncpy(data.newcall.dialstring, dialstring, CC_MAX_DIALSTRING_LEN);
+
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, cns_call_id, newcall_line,
+ CC_FEATURE_NEW_CALL, &data);
+
+ FSM_DEBUG_SM(get_debug_string(FSMXFR_DBG_XFR_INITIATED),
+ xcb->xfr_id, call_id, cns_call_id, __LINE__);
+
+ fsm_change_state(fcb, __LINE__, FSMXFR_S_ACTIVE);
+ } else { /* CC_FEATURE_BLIND_XFER */
+ /*
+ * Make sure we have a valid dialstring.
+ */
+ if ((fsmxfr_copy_dialstring(&xcb->dialstring, dialstring) == TRUE) &&
+ (fsmxfr_copy_dialstring(&xcb->referred_by, referred_by) == TRUE)) {
+
+ fsm_change_state(fcb, __LINE__, FSMXFR_S_ACTIVE);
+ } else {
+ fsmxfr_cleanup(fcb, __LINE__, TRUE);
+ }
+ }
+
+ return (TRUE);
+}
+
+
+static sm_rcs_t
+fsmxfr_ev_idle_feature (sm_event_t *event)
+{
+ const char *fname = "fsmxfr_ev_idle_feature";
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ cc_feature_t *msg = (cc_feature_t *) event->msg;
+ callid_t call_id = msg->call_id;
+ line_t line = msg->line;
+ cc_srcs_t src_id = msg->src_id;
+ cc_features_t ftr_id = msg->feature_id;
+ cc_feature_data_t *ftr_data = &(msg->data);
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ fsm_fcb_t *other_fcb;
+ sm_rcs_t sm_rc = SM_RC_CONT;
+ fsmxfr_types_t type;
+ int free_lines;
+ cc_feature_data_t data;
+ cc_causes_t cause = msg->data.xfer.cause;
+ cc_xfer_methods_t method;
+ fsmxfr_xcb_t *xcb;
+ fsm_fcb_t *fcb_def;
+ fsm_fcb_t *cns_fcb, *con_fcb, *sel_fcb;
+ boolean int_rc = FALSE;
+ callid_t cns_call_id;
+ line_t newcall_line = 0;
+
+ memset(&data, 0, sizeof(data));
+ fsm_sm_ftr(ftr_id, src_id);
+
+ /*
+ * Consume the XFER events and don't pass them along to the other FSMs.
+ */
+ if ((ftr_id == CC_FEATURE_BLIND_XFER) || (ftr_id == CC_FEATURE_XFER)) {
+ sm_rc = SM_RC_END;
+ }
+
+ switch (src_id) {
+ case CC_SRC_UI:
+ switch (ftr_id) {
+ case CC_FEATURE_DIRTRXFR:
+
+ /* If there is a active xfer pending
+ * then link this transfer to active transfer
+ */
+ other_fcb = fsmxfr_get_active_xfer();
+ if (other_fcb) {
+ if (other_fcb->xcb == NULL) {
+ GSM_DEBUG_ERROR(GSM_F_PREFIX"Cannot find the active xfer\n", fname);
+ return (SM_RC_END);
+ }
+ /* End existing consult call and then link another
+ * call with the trasfer
+ */
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, other_fcb->xcb->cns_call_id,
+ other_fcb->xcb->cns_line, CC_FEATURE_END_CALL, NULL);
+ other_fcb->xcb->cns_call_id = call_id;
+
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, other_fcb->xcb->xfr_call_id,
+ other_fcb->xcb->xfr_line, CC_FEATURE_DIRTRXFR, NULL);
+
+ return(SM_RC_END);
+ }
+ fsm_get_fcb_by_selected_or_connected_call_fcb(call_id, &con_fcb, &sel_fcb);
+
+ /* If there is a call selected use that for direct transfer */
+ if (sel_fcb) {
+ other_fcb = sel_fcb;
+ } else if (con_fcb) {
+ other_fcb = con_fcb;
+ } else {
+ /* No connected call or selected call */
+ return(SM_RC_CONT);
+ }
+
+ /* Make sure atleast one call has been selected, connected and this call
+ * is not in the focus
+ */
+ if ((fsmutil_get_num_selected_calls() > 1) && (dcb->selected == FALSE)) {
+ //return error
+ return(SM_RC_CONT);
+ }
+
+ if (other_fcb->xcb == NULL || other_fcb->xcb->xfr_line != line) {
+ //Not on same line display a message
+ GSM_DEBUG_ERROR(GSM_F_PREFIX"Cannot find the active xfer\n", fname);
+ return(SM_RC_CONT);
+ }
+
+ xcb = fsmxfr_get_new_xfr_context(call_id, line, FSMXFR_TYPE_XFR,
+ CC_XFER_METHOD_REFER,
+ FSMXFR_MODE_TRANSFEROR);
+ if (xcb == NULL) {
+ break;
+ }
+
+ xcb->xfr_orig = src_id;
+ fcb->xcb = xcb;
+
+ xcb->type = FSMXFR_TYPE_DIR_XFR;
+ xcb->cns_call_id = other_fcb->dcb->call_id;
+
+ other_fcb->xcb = xcb;
+ /*
+ * Emulating user hitting transfer key for second time
+ * in attended transfer
+ */
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, dcb->call_id,
+ dcb->line, CC_FEATURE_DIRTRXFR, NULL);
+
+ fsm_change_state(fcb, __LINE__, FSMXFR_S_ACTIVE);
+
+ return(SM_RC_END);
+
+ case CC_FEATURE_BLIND_XFER:
+ case CC_FEATURE_XFER:
+
+ /* Connect the existing call to active trasnfer state
+ * machine. If the UI generates the event with target
+ * call_id in the data then terminate the existing consulatative
+ * call and link that to another call.
+ */
+ if ((cause != CC_CAUSE_XFER_CNF) &&
+ (ftr_data && msg->data_valid) &&
+ (ftr_data->xfer.target_call_id != CC_NO_CALL_ID) &&
+ ((cns_fcb = fsm_get_fcb_by_call_id_and_type(ftr_data->xfer.target_call_id,
+ FSM_TYPE_XFR)) != NULL)) {
+ /* In this case there is no active xcb but upper layer
+ * wants to complete a trasnfer with 2 different call_ids
+ */
+ xcb = fsmxfr_get_new_xfr_context(call_id, line, FSMXFR_TYPE_XFR,
+ CC_XFER_METHOD_REFER,
+ FSMXFR_MODE_TRANSFEROR);
+ if (xcb == NULL) {
+ return(SM_RC_END);
+ }
+
+ fcb->xcb = xcb;
+ cns_fcb->xcb = xcb;
+ xcb->type = FSMXFR_TYPE_DIR_XFR;
+
+ xcb->cns_call_id = ftr_data->xfer.target_call_id;
+
+ fcb_def = fsm_get_fcb_by_call_id_and_type(call_id, FSM_TYPE_DEF);
+
+ /* Find line information for target call.
+ */
+ if (fcb_def && fcb_def->dcb) {
+
+ xcb->cns_line = fcb_def->dcb->line;
+
+ } else {
+
+ return(SM_RC_END);
+ }
+
+ fsm_change_state(cns_fcb, __LINE__, FSMXFR_S_ACTIVE);
+ fsm_change_state(fcb, __LINE__, FSMXFR_S_ACTIVE);
+
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, xcb->xfr_call_id,
+ line, CC_FEATURE_DIRTRXFR, NULL);
+
+ return(SM_RC_END);
+ }
+
+ /*
+ * This call is the transferor and we are initiating a local
+ * transfer. So:
+ * 1. Make sure we have a free line to open a new call plane to
+ * collect digits (and place call) for the transfer target,
+ * 2. Create a new transfer context,
+ * 3. Place this call on hold,
+ * 4. Send a newcall feature back to the GSM so that the
+ * consultation call can be initiated.
+ */
+
+ /*
+ * Check for any other active features which may block
+ * the transfer.
+ */
+
+ /*
+ * The call must be in the connected state to initiate a transfer.
+ */
+ fcb_def = fsm_get_fcb_by_call_id_and_type(call_id, FSM_TYPE_DEF);
+ if ((fcb_def != NULL) &&
+ (fcb_def->state != FSMDEF_S_CONNECTED) &&
+ (cause != CC_CAUSE_XFER_CNF)) {
+ break;
+ }
+
+ /*
+ * If it's not a conference transfer make sure we have a free
+ * line to start the consultation call.
+ */
+ if (cause != CC_CAUSE_XFER_CNF) {
+ //CSCsz38962 don't use expline for local-initiated transfer
+ //free_lines = lsm_get_instances_available_cnt(line, TRUE);
+ free_lines = lsm_get_instances_available_cnt(line, FALSE);
+ if (free_lines <= 0) {
+ /*
+ * No free lines - let the user know and end this request.
+ */
+ fsm_display_no_free_lines();
+
+ break;
+ }
+
+ newcall_line = lsm_get_newcall_line(line);
+ if (newcall_line == NO_LINES_AVAILABLE) {
+ /*
+ * Error Pass Limit - let the user know and end this request.
+ */
+ lsm_ui_display_notify_str_index(STR_INDEX_ERROR_PASS_LIMIT);
+ return (FALSE);
+ }
+ }
+
+ /*
+ * Get a new xcb and new xfr id - This is the handle that will
+ * identify the xfr.
+ */
+ type = ((ftr_id == CC_FEATURE_XFER) ?
+ (FSMXFR_TYPE_XFR) : (FSMXFR_TYPE_BLND_XFR));
+
+ xcb = fsmxfr_get_new_xfr_context(call_id, line, type,
+ CC_XFER_METHOD_REFER,
+ FSMXFR_MODE_TRANSFEROR);
+ if (xcb == NULL) {
+ break;
+ }
+ xcb->xfr_orig = src_id;
+ fcb->xcb = xcb;
+ /*
+ * If not conference transfer initiate the consultation call.
+ * For conference transfer we already have both calls setup.
+ */
+ if (cause != CC_CAUSE_XFER_CNF) {
+ /*
+ * Set the consultative line to new line id.
+ */
+ xcb->cns_line = newcall_line;
+ /*
+ * Record the active feature if it is a blind xfer.
+ */
+ if (ftr_id == CC_FEATURE_BLIND_XFER) {
+ dcb->active_feature = ftr_id;
+ }
+
+ /*
+ * This call needs to go on hold so we can start the
+ * consultation call. Indicate feature indication should
+ * be send and set the feature reason.
+ */
+ data.hold.call_info.type = CC_FEAT_HOLD;
+ data.hold.call_info.data.hold_resume_reason = CC_REASON_XFER;
+ data.hold.msg_body.num_parts = 0;
+ data.hold.call_info.data.call_info_feat_data.protect = TRUE;
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, dcb->call_id, dcb->line,
+ CC_FEATURE_HOLD, &data);
+
+ cns_call_id = xcb->cns_call_id;
+ if (ftr_data->xfer.cause == CC_CAUSE_XFER_LOCAL_WITH_DIALSTRING) {
+ cc_int_dialstring(CC_SRC_GSM, CC_SRC_GSM, cns_call_id, newcall_line,
+ ftr_data->xfer.dialstring, NULL, 0);
+ } else {
+ data.newcall.cause = CC_CAUSE_XFER_LOCAL;
+ if (ftr_data->xfer.dialstring[0] != 0) {
+ data.newcall.cause = CC_CAUSE_XFER_BY_REMOTE;
+ sstrncpy(data.newcall.dialstring, ftr_data->xfer.dialstring,
+ CC_MAX_DIALSTRING_LEN);
+ }
+
+ if (ftr_data->xfer.global_call_id[0] != 0) {
+ sstrncpy(data.newcall.global_call_id,
+ ftr_data->xfer.global_call_id, CC_GCID_LEN);
+ }
+ data.newcall.prim_call_id = xcb->xfr_call_id;
+ data.newcall.hold_resume_reason = CC_REASON_XFER;
+
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, cns_call_id, newcall_line,
+ CC_FEATURE_NEW_CALL, &data);
+ }
+ FSM_DEBUG_SM(get_debug_string(FSMXFR_DBG_XFR_INITIATED),
+ xcb->xfr_id, call_id, cns_call_id, __LINE__);
+ } else {
+ other_fcb =
+ fsm_get_fcb_by_call_id_and_type(msg->data.xfer.target_call_id,
+ FSM_TYPE_XFR);
+ if (other_fcb == NULL) {
+ GSM_DEBUG_ERROR(GSM_F_PREFIX"Cannot find the active xfer\n", fname);
+ break;
+ }
+
+ other_fcb->xcb = xcb;
+ /*
+ * The xfr_call_id is the call that is being replaced by
+ * the cns_call_id.
+ */
+ fsmxfr_update_xfr_context(xcb, xcb->cns_call_id,
+ msg->data.xfer.target_call_id);
+ xcb->cnf_xfr = TRUE;
+ fsm_change_state(other_fcb, __LINE__, FSMXFR_S_ACTIVE);
+ /*
+ * Emulating user hitting transfer key for second time
+ * in attended transfer
+ */
+ cc_int_feature(CC_SRC_UI, CC_SRC_GSM, dcb->call_id,
+ dcb->line, CC_FEATURE_XFER, NULL);
+ }
+
+ fsm_change_state(fcb, __LINE__, FSMXFR_S_ACTIVE);
+ break;
+
+ default:
+ fsm_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ sm_rc = SM_RC_DEF_CONT;
+
+ break;
+ } /* switch (ftr_id) */
+
+ break;
+
+ case CC_SRC_GSM:
+ switch (ftr_id) {
+ case CC_FEATURE_NEW_CALL:
+
+ /*
+ * If this is the consultation call involved in a transfer,
+ * then set the rest of the data required to make the transfer
+ * happen. The data is the xcb in the fcb. The data is set now
+ * because we did not have the fcb when the transfer was
+ * initiated. The fcb is created when a new_call event is
+ * received by the FIM, not when a transfer event is received.
+ *
+ * Or this could be the call that originated the
+ * transfer (the transferor) and
+ * the person he was talking to (the transfer target) has
+ * decided to transfer the transferor to another target.
+ */
+
+ /*
+ * Ignore this event if this call is not involved in a transfer.
+ */
+ xcb = fsmxfr_get_xcb_by_call_id(call_id);
+ if (xcb == NULL) {
+ break;
+ }
+ fcb->xcb = xcb;
+
+ fsm_change_state(fcb, __LINE__, FSMXFR_S_ACTIVE);
+
+ break;
+
+ default:
+ fsm_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ sm_rc = SM_RC_DEF_CONT;
+
+ break;
+ } /* switch (ftr_id) */
+
+ break;
+
+ case CC_SRC_SIP:
+ switch (ftr_id) {
+ case CC_FEATURE_BLIND_XFER:
+ case CC_FEATURE_XFER:
+ if (msg->data_valid == FALSE) {
+ break;
+ }
+
+ method = msg->data.xfer.method;
+
+ switch (method) {
+ case CC_XFER_METHOD_BYE:
+ /*
+ * This is a remote initiated transfer using the
+ * BYE/ALSO method.
+ *
+ * The transferor has sent us, the transferee, a BYE with
+ * the transfer target.
+ *
+ * 1. Create a new transfer context
+ * 2. Ack the feature request.
+ *
+ * We need to wait for the RELEASE from SIP and then we will
+ * send out the NEWCALL to initiate the call to the target.
+ */
+
+ /*
+ * Transfer is valid only for a remote originated transfer.
+ */
+ if (msg->data.xfer.cause != CC_CAUSE_XFER_REMOTE) {
+ break;
+ }
+
+ /*
+ * Check for any other active features which may block
+ * the transfer.
+ */
+
+ /*
+ * Get a new xcb and new xfr id - This is the handle that will
+ * identify the xfr.
+ */
+ type = ((ftr_id == CC_FEATURE_XFER) ?
+ (FSMXFR_TYPE_XFR) : (FSMXFR_TYPE_BLND_XFR));
+
+ xcb = fsmxfr_get_new_xfr_context(call_id, line, type, method,
+ FSMXFR_MODE_TRANSFEREE);
+ if (xcb == NULL) {
+ break;
+ }
+ xcb->xfr_orig = src_id;
+ fcb->xcb = xcb;
+
+ fsmxfr_set_xfer_data(CC_CAUSE_OK, method,
+ xcb->cns_call_id,
+ FSMXFR_NULL_DIALSTRING, &(data.xfer));
+
+ cc_int_feature_ack(CC_SRC_GSM, CC_SRC_SIP, dcb->call_id,
+ dcb->line, ftr_id, &data, CC_CAUSE_NORMAL);
+
+ /*
+ * Make sure we have a valid dialstring.
+ */
+ if (fsmxfr_copy_dialstring(&xcb->dialstring,
+ msg->data.xfer.dialstring) == TRUE) {
+ fsm_change_state(fcb, __LINE__, FSMXFR_S_ACTIVE);
+ } else {
+ fsmxfr_feature_cancel(xcb, xcb->xfr_line, xcb->xfr_call_id,
+ xcb->cns_call_id, CC_SK_EVT_TYPE_IMPLI);
+ fsmxfr_cleanup(fcb, __LINE__, TRUE);
+ }
+
+ break;
+
+ case CC_XFER_METHOD_REFER:
+ /*
+ * This event is because:
+ * 1. we are the target involved in a transfer or
+ * 2. it is a remote initiated transfer using the REFER method.
+ *
+ * Case 1:
+ * The transferee has attempted to setup a call with us,
+ * the target. The call has been setup successfully so the
+ * SIP stack is informing us that we are the target.
+ *
+ * 1. Ack the request,
+ * 2. Create a new transfer context.
+ *
+ * Case 2:
+ * The transferor has sent us, the transferee, a REFER with
+ * the transfer target. We will attempt to contact the target
+ * and then report the result to the transferor.
+ *
+ * 1. Verify that we have a free line to start the
+ * consultation call,
+ * 2. Create a new transfer context,
+ * 3. Place this call on hold,
+ * 4. Send a newcall feature back to the GSM so that the
+ * consultation call can be initiated.
+ */
+
+ /*
+ * Check if this is case 1.
+ * We know this because the target_call_id can only be set
+ * for this case.
+ */
+ if ((msg->data.xfer.cause == CC_CAUSE_XFER_REMOTE) &&
+ (msg->data.xfer.target_call_id != CC_NO_CALL_ID)) {
+ type = ((ftr_id == CC_FEATURE_XFER) ?
+ (FSMXFR_TYPE_XFR) : (FSMXFR_TYPE_BLND_XFR));
+
+ xcb = fsmxfr_get_new_xfr_context(call_id, line, type,
+ CC_XFER_METHOD_REFER,
+ FSMXFR_MODE_TARGET);
+ if (xcb == NULL) {
+ break;
+ }
+ xcb->xfr_orig = src_id;
+ fcb->xcb = xcb;
+
+ /*
+ * The xfr_call_id is the call that is being replaced by
+ * the cns_call_id (which the stack supplied).
+ */
+ fsmxfr_update_xfr_context(xcb, xcb->cns_call_id,
+ msg->data.xfer.target_call_id);
+ cns_call_id = xcb->cns_call_id;
+ /*
+ * Set the correct xfer_data. The target_call_id must be
+ * CC_NO_CALL_ID so that the stack can tell that this is
+ * a case 1 transfer.
+ */
+ fsmxfr_set_xfer_data(CC_CAUSE_XFER_REMOTE,
+ method,
+ CC_NO_CALL_ID,
+ FSMXFR_NULL_DIALSTRING, &(data.xfer));
+
+ cc_int_feature_ack(CC_SRC_GSM, CC_SRC_SIP, dcb->call_id,
+ dcb->line, ftr_id, &data,
+ CC_CAUSE_NORMAL);
+
+ fsm_change_state(fcb, __LINE__, FSMXFR_S_ACTIVE);
+
+ break;
+ }
+
+ /*
+ * I guess we are at case 2...
+ * Transfer should be done only if call's present state
+ * is either on hold or connected
+ */
+ fcb_def =
+ fsm_get_fcb_by_call_id_and_type(call_id, FSM_TYPE_DEF);
+ if ((fcb_def->state == FSMDEF_S_CONNECTED) ||
+ (fcb_def->state == FSMDEF_S_CONNECTED_MEDIA_PEND) ||
+ (fcb_def->state == FSMDEF_S_RESUME_PENDING) ||
+ (fcb_def->state == FSMDEF_S_HOLD_PENDING) ||
+ (fcb_def->state == FSMDEF_S_HOLDING)) {
+ int_rc =
+ fsmxfr_remote_transfer(fcb, ftr_id, call_id, dcb->line,
+ msg->data.xfer.dialstring,
+ msg->data.xfer.referred_by);
+ }
+
+ if (int_rc == FALSE) {
+ fsmxfr_set_xfer_data(CC_CAUSE_ERROR, CC_XFER_METHOD_REFER,
+ CC_NO_CALL_ID,
+ FSMXFR_NULL_DIALSTRING, &(data.xfer));
+
+ cc_int_feature_ack(CC_SRC_GSM, CC_SRC_SIP, call_id,
+ line, ftr_id, &data, CC_CAUSE_ERROR);
+ }
+ break;
+
+ default:
+ break;
+ } /* switch (xfr_data->method) */
+
+ break;
+ case CC_FEATURE_NOTIFY:
+ if (ftr_data->notify.subscription != CC_SUBSCRIPTIONS_XFER) {
+ /* This notify is not for XFER subscription */
+ break;
+ }
+ data.notify.cause = msg->data.notify.cause;
+ data.notify.cause_code = msg->data.notify.cause_code;
+ data.notify.subscription = CC_SUBSCRIPTIONS_XFER;
+ data.notify.method = CC_XFER_METHOD_REFER;
+ data.notify.blind_xferror_gsm_id =
+ msg->data.notify.blind_xferror_gsm_id;
+ data.notify.final = TRUE;
+
+ if (data.notify.blind_xferror_gsm_id == CC_NO_CALL_ID) {
+ if (msg->data.notify.cause == CC_CAUSE_OK) {
+ data.endcall.cause = CC_CAUSE_OK;
+ sm_rc = SM_RC_END;
+ /*
+ * If dcb is NULL, we received a final NOTIFY after the
+ * the dcb was cleared. This can happen when we receive
+ * BYE before final NOTIFY on the result of the REFER
+ * sent for xfer. If dcb is NULL, just quietly ignore
+ * the NOTIFY event. Otherwise, kick off the release of
+ * the call.
+ */
+ if (dcb) {
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM,
+ dcb->call_id, dcb->line,
+ CC_FEATURE_END_CALL, &data);
+ }
+ }
+ } else {
+ cc_int_feature(CC_SRC_GSM, CC_SRC_SIP,
+ data.notify.blind_xferror_gsm_id,
+ line, CC_FEATURE_NOTIFY, &data);
+ }
+ break;
+
+ default:
+ fsm_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ sm_rc = SM_RC_DEF_CONT;
+ break;
+ } /* switch (ftr_id) */
+ break;
+
+ default:
+ fsm_sm_ignore_src(fcb, __LINE__, src_id);
+ sm_rc = SM_RC_DEF_CONT;
+ break;
+ } /* switch (src_id) */
+
+ return (sm_rc);
+}
+
+static sm_rcs_t
+fsmxfr_ev_idle_dialstring (sm_event_t *event)
+{
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ cc_feature_t *msg = (cc_feature_t *) event->msg;
+ callid_t call_id = msg->call_id;
+ fsmxfr_xcb_t *xcb;
+ sm_rcs_t sm_rc = SM_RC_CONT;
+
+ /*
+ * Ignore this event if this call is not involved in a transfer.
+ */
+ xcb = fsmxfr_get_xcb_by_call_id(call_id);
+ if (xcb == NULL) {
+ return sm_rc;
+ }
+ fcb->xcb = xcb;
+
+ fsm_change_state(fcb, __LINE__, FSMXFR_S_ACTIVE);
+ return (fsmxfr_ev_active_dialstring(event));
+}
+
+
+
+
+static sm_rcs_t
+fsmxfr_ev_active_proceeding (sm_event_t *event)
+{
+ cc_proceeding_t *msg = (cc_proceeding_t *) event->msg;
+ callid_t call_id = msg->call_id;
+ line_t line = msg->line;
+ cc_feature_data_t data;
+ fsmxfr_xcb_t *xcb;
+ fsm_fcb_t *other_fcb;
+ callid_t other_call_id;
+ line_t other_line;
+
+ /*
+ * Ignore this event if this call is not involved in a transfer
+ * or we are not the target of the transfer.
+ */
+ xcb = fsmxfr_get_xcb_by_call_id(call_id);
+ if ((xcb == NULL) || (xcb->mode != FSMXFR_MODE_TARGET)) {
+ return (SM_RC_CONT);
+ }
+
+ other_call_id = fsmxfr_get_other_call_id(xcb, call_id);
+ other_line = fsmxfr_get_other_line(xcb, call_id);
+ other_fcb = fsm_get_fcb_by_call_id_and_type(other_call_id, FSM_TYPE_DEF);
+
+ /*
+ * Release the transfer call.
+ *
+ * We need to release the transfer call (which is really
+ * the consultation call from the transferor to us
+ * the target), because we want the next call coming in
+ * to replace this one.
+ */
+ data.endcall.cause = CC_CAUSE_REPLACE;
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, other_call_id,
+ other_line, CC_FEATURE_END_CALL, &data);
+
+ /*
+ * Only answer the call if the call being replaced was connected
+ * or is currently connected, otherwise just let this call be setup
+ * normally so that it will ring.
+ */
+
+ if (other_fcb && (other_fcb->old_state == FSMDEF_S_CONNECTED ||
+ other_fcb->old_state == FSMDEF_S_CONNECTED_MEDIA_PEND ||
+ other_fcb->old_state == FSMDEF_S_RESUME_PENDING ||
+ other_fcb->state == FSMDEF_S_CONNECTED ||
+ other_fcb->state == FSMDEF_S_CONNECTED_MEDIA_PEND ||
+ other_fcb->state == FSMDEF_S_RESUME_PENDING)) {
+ cc_int_feature(CC_SRC_UI, CC_SRC_GSM, call_id,
+ line, CC_FEATURE_ANSWER, NULL);
+ }
+
+ return (SM_RC_CONT);
+}
+
+
+static sm_rcs_t
+fsmxfr_ev_active_connected_ack (sm_event_t *event)
+{
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ cc_connected_ack_t *msg = (cc_connected_ack_t *) event->msg;
+ fsmxfr_xcb_t *xcb;
+
+ /*
+ * If we are the target and this is the call from the transferree
+ * to the target, then we need to cleanup the rest of the transfer.
+ * We need to do this because the consultation call is already cleared
+ * from the transfer but the transfer call was not.
+ */
+
+ /*
+ * Ignore this event if this call is not involved in a transfer.
+ */
+ xcb = fsmxfr_get_xcb_by_call_id(msg->call_id);
+ if ((xcb == NULL) || (xcb->mode != FSMXFR_MODE_TARGET)) {
+ return (SM_RC_CONT);
+ }
+
+ /*
+ * Remove this call from the transfer.
+ */
+ fsmxfr_feature_cancel(xcb, xcb->xfr_line, xcb->xfr_call_id,
+ xcb->cns_call_id, CC_SK_EVT_TYPE_IMPLI);
+ fsmxfr_cleanup(fcb, __LINE__, FALSE);
+
+ return (SM_RC_CONT);
+}
+
+
+static sm_rcs_t
+fsmxfr_ev_active_release (sm_event_t *event)
+{
+ static const char fname[] = "fsmxfr_ev_active_release";
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ cc_release_t *msg = (cc_release_t *) event->msg;
+ callid_t call_id = msg->call_id;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ callid_t new_call_id;
+ callid_t other_call_id;
+ line_t other_line;
+ fsmxfr_xcb_t *xcb = fcb->xcb;
+ cc_feature_data_t data;
+ boolean secondary = FALSE;
+ cc_action_data_t action_data;
+ fsm_fcb_t *other_fcb;
+ FSM_DEBUG_SM(DEB_F_PREFIX"Entered. \n", DEB_F_PREFIX_ARGS(FSM, "fsmxfr_ev_active_release"));
+
+ /*
+ * Complete a transfer if we have a pending transfer.
+ */
+ memset(&data, 0, sizeof(cc_feature_data_t));
+
+ /*
+ * Check if this is a transfer of a transfer.
+ */
+ if (xcb == NULL) {
+ GSM_DEBUG_ERROR(GSM_F_PREFIX"Cannot find a transfer call to cancel.\n", fname);
+ return (SM_RC_CONT);
+ }
+
+ if ((xcb->active == TRUE) && (xcb->xcb2 != NULL)) {
+ xcb = xcb->xcb2;
+ secondary = TRUE;
+ }
+
+ if ((xcb->dialstring != NULL) && (xcb->dialstring[0] != '\0')) {
+ /*
+ * Grab the call_id for the call to the target.
+ * This will either already be in the xcb or we will need to
+ * get a new one. The call_id will be in the xcb if we are the
+ * transferee.
+ */
+ if (xcb->active == TRUE) {
+ new_call_id = cc_get_new_call_id();
+ fsmxfr_update_xfr_context(xcb, call_id, new_call_id);
+ } else {
+ new_call_id = fsmxfr_get_other_call_id(xcb, call_id);
+ if (secondary == TRUE) {
+ fsmxfr_update_xfr_context(fcb->xcb, call_id, new_call_id);
+ }
+ }
+
+ data.newcall.cause = CC_CAUSE_XFER_REMOTE;
+ sstrncpy(data.newcall.dialstring, xcb->dialstring,
+ CC_MAX_DIALSTRING_LEN);
+
+ cpr_free(xcb->dialstring);
+ xcb->dialstring = NULL;
+ memset(data.newcall.redirect.redirects[0].number, 0,
+ sizeof(CC_MAX_DIALSTRING_LEN));
+ if (xcb->referred_by != NULL) {
+ sstrncpy(data.newcall.redirect.redirects[0].number,
+ xcb->referred_by, CC_MAX_DIALSTRING_LEN);
+
+ cpr_free(xcb->referred_by);
+ xcb->referred_by = NULL;
+ }
+
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, new_call_id,
+ dcb->line, CC_FEATURE_NEW_CALL, &data);
+
+ FSM_DEBUG_SM(get_debug_string(FSMXFR_DBG_XFR_INITIATED), xcb->xfr_id,
+ xcb->xfr_call_id, xcb->cns_call_id, __LINE__);
+
+ if (secondary == TRUE) {
+ fsmxfr_init_xcb(xcb);
+ fcb->xcb->active = FALSE;
+ fcb->xcb->xcb2 = NULL;
+ fsmxfr_feature_cancel(xcb, xcb->xfr_line, xcb->xfr_call_id,
+ xcb->cns_call_id, CC_SK_EVT_TYPE_IMPLI);
+ fsmxfr_cleanup(fcb, __LINE__, FALSE);
+ } else if (xcb->active == TRUE) {
+ fsmxfr_feature_cancel(xcb, xcb->xfr_line, xcb->xfr_call_id,
+ xcb->cns_call_id, CC_SK_EVT_TYPE_IMPLI);
+ fsmxfr_cleanup(fcb, __LINE__, FALSE);
+ fcb->xcb->active = FALSE;
+ } else {
+ /*
+ * Reset the xcb call_id that was used for the call to the target.
+ * The value was just temporary and it needs to be reset so that
+ * the cleanup function works properly.
+ */
+ fsmxfr_update_xfr_context(xcb, new_call_id, CC_NO_CALL_ID);
+ fsmxfr_feature_cancel(xcb, xcb->xfr_line, xcb->xfr_call_id,
+ xcb->cns_call_id, CC_SK_EVT_TYPE_IMPLI);
+ fsmxfr_cleanup(fcb, __LINE__, TRUE);
+ }
+
+ xcb->active = FALSE;
+ } else {
+ if (secondary == TRUE) {
+ /*
+ * This is the secondary transfer of a primary transfer.
+ * We need to:
+ * 1. update the primary xcb to point to this just transferred
+ * call,
+ * 2. mark the primary xcb as inactive since we just completed the
+ * secondary transfer,
+ * 3. point the newly transferred call to the primary xcb and
+ * update the UI to show that this is a local transfer (the
+ * UI was set as though the call was a remote transfer).
+ * 4. blow away this secondary xcb and cleanup the fcb,
+ */
+ new_call_id = fsmxfr_get_other_call_id(xcb, call_id);
+ fsmxfr_update_xfr_context(fcb->xcb, call_id, new_call_id);
+
+ fcb->xcb->active = FALSE;
+
+ other_fcb = fsm_get_fcb_by_call_id_and_type(new_call_id,
+ FSM_TYPE_XFR);
+ if (other_fcb == NULL) {
+ return (SM_RC_CONT);
+ }
+ other_fcb->xcb = fcb->xcb;
+
+ fsmxfr_init_xcb(xcb);
+
+ action_data.update_ui.action = CC_UPDATE_XFER_PRIMARY;
+ (void)cc_call_action(other_fcb->dcb->call_id, dcb->line,
+ CC_ACTION_UPDATE_UI, &action_data);
+
+ fsmxfr_cleanup(fcb, __LINE__, FALSE);
+ } else {
+ /*
+ * One of the parties in the transfer has decided to release
+ * the call, so go ahead and cleanup this transfer.
+ */
+ other_call_id = fsmxfr_get_other_call_id(xcb, call_id);
+ other_line = fsmxfr_get_other_line(xcb, call_id);
+
+ other_fcb = fsm_get_fcb_by_call_id_and_type(other_call_id,
+ FSM_TYPE_XFR);
+ if (xcb->cnf_xfr) {
+ /*
+ * This is the transfer for bridging a transfer call so
+ * clear the second line also.
+ */
+ xcb->cnf_xfr = FALSE;
+ if (other_fcb == NULL) {
+ return (SM_RC_CONT);
+ }
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, other_call_id,
+ other_line, CC_FEATURE_END_CALL, NULL);
+ }
+
+ fsmxfr_feature_cancel(xcb, xcb->xfr_line, xcb->xfr_call_id, xcb->cns_call_id,
+ CC_SK_EVT_TYPE_IMPLI);
+ fsmxfr_cleanup(fcb, __LINE__, TRUE);
+
+ }
+ }
+
+ return (SM_RC_CONT);
+}
+
+
+static sm_rcs_t
+fsmxfr_ev_active_release_complete (sm_event_t *event)
+{
+ fsmxfr_cleanup((fsm_fcb_t *) event->data, __LINE__, TRUE);
+
+ return (SM_RC_CONT);
+}
+
+static char *fsmxfr_get_dialed_num (fsmdef_dcb_t *dcb)
+{
+ static const char fname[] = "fsmxfr_get_dialed_num";
+ char *tmp_called_number;
+ /* Get the dialed number only if the call is outgoing type */
+
+ tmp_called_number = lsm_get_gdialed_digits();
+
+ DEF_DEBUG(DEB_F_PREFIX"called_dialed_num = %s\n",
+ DEB_F_PREFIX_ARGS(GSM, fname), tmp_called_number);
+
+ /* Get dialed number to put in the refer-to header. If there
+ * is no dialed number then use RPID or from header value
+ */
+ if (tmp_called_number == NULL || (*tmp_called_number) == NUL) {
+
+ if (dcb->caller_id.called_number[0] != NUL) {
+ DEF_DEBUG(DEB_F_PREFIX"called_dcb_num = %s\n",
+ DEB_F_PREFIX_ARGS(GSM, fname), (char *)dcb->caller_id.called_number);
+ return((char *)dcb->caller_id.called_number);
+
+ } else {
+ DEF_DEBUG(DEB_F_PREFIX"calling_dcb_num = %s\n",
+ DEB_F_PREFIX_ARGS(GSM, fname), (char *)dcb->caller_id.calling_number);
+ return((char *)dcb->caller_id.calling_number);
+ }
+ }
+
+ /*
+ * if tmp_called_number is same as what we receive in RPID,
+ * then get the called name from RPID if provided.
+ */
+ if (dcb->caller_id.called_number != NULL &&
+ dcb->caller_id.called_number[0] != NUL) {
+ /* if Cisco PLAR string is used, use the RPID value */
+ if (strncmp(tmp_called_number, CC_CISCO_PLAR_STRING, sizeof(CC_CISCO_PLAR_STRING)) == 0) {
+ tmp_called_number = (char *)dcb->caller_id.called_number;
+ }
+ }
+
+ return(tmp_called_number);
+}
+
+static void
+fsmxfr_initiate_xfr (sm_event_t *event)
+{
+ static const char fname[] = "fsmxfr_initiate_xfr";
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ fsm_fcb_t *cns_fcb = NULL;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ fsmdef_dcb_t *xfr_dcb;
+ fsmdef_dcb_t *cns_dcb;
+ cc_feature_data_t data;
+ fsmxfr_xcb_t *xcb = fcb->xcb;
+ char *called_num = NULL;
+
+ /*
+ * Place the consultation call on hold.
+ */
+ if (xcb == NULL) {
+ GSM_DEBUG_ERROR(GSM_F_PREFIX"Cannot find the active xfer\n", fname);
+ return;
+ }
+
+ cns_dcb = fsm_get_dcb(xcb->cns_call_id);
+ cns_fcb = fsm_get_fcb_by_call_id_and_type(xcb->cns_call_id,
+ FSM_TYPE_DEF);
+ xfr_dcb = fsm_get_dcb(xcb->xfr_call_id);
+
+ /*
+ * If the consultation call is not connected
+ * treat it like a blind xfer.
+ */
+ if (cns_fcb != NULL) {
+ /*
+ * If the transfer key is pressed twice, before the sofkey gets
+ * updated in response to first transfer key, the 2nd transfer key
+ * press is treated as a transfer complete and we try to initate
+ * the transfer to the connected call itself. To prevent this, check
+ * the state of the call to see if we should
+ * ignore the 2nd transfer key press.
+ */
+ if ((cns_fcb->state == FSMDEF_S_COLLECT_INFO) ||
+ (cns_fcb->state == FSMDEF_S_OUTGOING_PROCEEDING) ||
+ (cns_fcb->state == FSMDEF_S_KPML_COLLECT_INFO)) {
+ FSM_DEBUG_SM(DEB_L_C_F_PREFIX"Ignore the xfer xid %d cid %d %d\n",
+ DEB_L_C_F_PREFIX_ARGS(FSM, xcb->xfr_line, xcb->xfr_call_id, "fsmxfr_initiate_xfr"),
+ xcb->xfr_id, xcb->xfr_call_id, xcb->cns_call_id);
+ return;
+ }
+
+ /*
+ * Indicate that xfer completion has been requested
+ */
+ xcb->xfer_comp_req = TRUE;
+
+ if (cns_fcb->state < FSMDEF_S_CONNECTED) {
+ data.endcall.cause = CC_CAUSE_NO_USER_RESP;
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, cns_dcb->call_id,
+ cns_dcb->line, CC_FEATURE_END_CALL, &data);
+ /*
+ * Instruct the stack to transfer the call.
+ */
+ called_num = fsmxfr_get_dialed_num(cns_dcb);
+ if (called_num && called_num[0] != '\0') {
+
+ fsmxfr_set_xfer_data(CC_CAUSE_XFER_LOCAL,
+ xcb->method, cns_dcb->call_id,
+ called_num,
+ &(data.xfer));
+
+ cc_int_feature(CC_SRC_GSM, CC_SRC_SIP, xfr_dcb->call_id,
+ xfr_dcb->line, CC_FEATURE_XFER, &data);
+ } else {
+ /*
+ * Can't transfer the call without a dialstring, so
+ * just cleanup the transfer.
+ */
+ fsmxfr_feature_cancel(xcb, xcb->xfr_line, xcb->xfr_call_id,
+ xcb->cns_call_id, CC_SK_EVT_TYPE_IMPLI);
+ fsmxfr_cleanup(fcb, __LINE__, TRUE);
+ if (xcb->cnf_xfr) {
+ /*
+ * If it is a conference transfer clear up the
+ * calls.
+ */
+ fsmxfr_cnf_cleanup(xcb);
+ }
+ }
+ } else {
+ /*
+ * If the consulation call is already on hold and
+ * the intial call isn't then place ourselves on
+ * hold (user hit the rocker arm switch). Otherwise,
+ * place the consulation call on hold. Make sure we
+ * do not send feature indication by setting the
+ * call info type to none.
+ */
+ data.hold.call_info.type = CC_FEAT_NONE;
+ data.hold.msg_body.num_parts = 0;
+ if (((cns_fcb->state == FSMDEF_S_HOLDING) ||
+ (cns_fcb->state == FSMDEF_S_HOLD_PENDING)) &&
+ ((fcb->state != FSMDEF_S_HOLDING) &&
+ (fcb->state != FSMDEF_S_HOLD_PENDING))) {
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, dcb->call_id, dcb->line,
+ CC_FEATURE_HOLD, &data);
+ } else {
+ /* just place on hold */
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM,
+ cns_dcb->call_id, cns_dcb->line,
+ CC_FEATURE_HOLD, &data);
+ }
+ }
+ }
+}
+
+static sm_rcs_t
+fsmxfr_ev_active_feature (sm_event_t *event)
+{
+ static const char fname[] = "fsmxfr_ev_active_feature";
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ cc_feature_t *msg = (cc_feature_t *) event->msg;
+ callid_t call_id = msg->call_id;
+ line_t line = msg->line;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ cc_srcs_t src_id = msg->src_id;
+ cc_features_t ftr_id = msg->feature_id;
+ cc_feature_data_t *feat_data = &(msg->data);
+ fsmdef_dcb_t *xfr_dcb, *cns_dcb;
+ cc_feature_data_t data;
+ sm_rcs_t sm_rc = SM_RC_CONT;
+ fsmxfr_xcb_t *xcb = fcb->xcb;
+ boolean int_rc;
+ char tmp_str[STATUS_LINE_MAX_LEN];
+ char *called_num = NULL;
+ fsm_fcb_t *cns_fcb = NULL;
+
+ fsm_sm_ftr(ftr_id, src_id);
+
+ if (xcb == NULL) {
+ GSM_DEBUG_ERROR(GSM_F_PREFIX"Cannot find the active xfer\n", fname);
+ return (SM_RC_CONT);
+ }
+
+ /*
+ * Consume the XFER and NOTIFY events and don't pass them along
+ * to the other FSMs.
+ */
+ if ((ftr_id == CC_FEATURE_BLIND_XFER) ||
+ (ftr_id == CC_FEATURE_XFER) || (ftr_id == CC_FEATURE_NOTIFY)) {
+ if (ftr_id == CC_FEATURE_NOTIFY) {
+ if (msg->data_valid &&
+ (msg->data.notify.subscription != CC_SUBSCRIPTIONS_XFER)) {
+ /* The subscription is not XFER, let the event flow through */
+ return (SM_RC_CONT);
+ }
+ }
+ sm_rc = SM_RC_END;
+ }
+
+ switch (src_id) {
+ case CC_SRC_UI:
+ switch (ftr_id) {
+ case CC_FEATURE_CANCEL:
+ sm_rc = SM_RC_END;
+ fsmxfr_feature_cancel(xcb, xcb->xfr_line, xcb->xfr_call_id, xcb->cns_call_id,
+ CC_SK_EVT_TYPE_EXPLI);
+ fsmxfr_cleanup(fcb, __LINE__, TRUE);
+ break;
+
+ case CC_FEATURE_XFER:
+ /* Connect the existing call to active trasnfer state
+ * machine. If the UI generates the event with target
+ * call_id in the data then terminate the existing consulatative
+ * call and link that to another call.
+ */
+ DEF_DEBUG(DEB_F_PREFIX"ACTIVE XFER call_id = %d, cns_id = %d, t_id=%d\n",
+ DEB_F_PREFIX_ARGS(GSM, fname), xcb->xfr_call_id,
+ feat_data->xfer.target_call_id, xcb->cns_call_id);
+
+ if (feat_data && msg->data_valid &&
+ (xcb->cns_call_id != feat_data->xfer.target_call_id)) {
+
+ cns_fcb = fsm_get_fcb_by_call_id_and_type(xcb->cns_call_id,
+ FSM_TYPE_DEF);
+
+ if (cns_fcb != NULL) {
+ DEF_DEBUG(DEB_F_PREFIX"INVOKE ACTIVE XFER call_id = %d, t_id=%d\n",
+ DEB_F_PREFIX_ARGS(GSM, fname), xcb->xfr_call_id,
+ feat_data->xfer.target_call_id);
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, xcb->xfr_call_id,
+ xcb->xfr_line, CC_FEATURE_DIRTRXFR, NULL);
+ }
+
+ return(SM_RC_END);
+ }
+ switch (xcb->method) {
+ case CC_XFER_METHOD_BYE:
+ case CC_XFER_METHOD_REFER:
+ /*
+ * This is the second transfer event for a local
+ * attended transfer with consultation.
+ *
+ * The user is attempting to complete the transfer, so
+ * 1. place the consultation call on hold,
+ * 2. instruct the stack to transfer the call.
+ */
+ fsmxfr_initiate_xfr(event);
+ lsm_set_hold_ringback_status(xcb->cns_call_id, FALSE);
+ break;
+
+ default:
+ fsm_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ break;
+ } /* switch (ftr_id) { */
+ break;
+ case CC_FEATURE_RESUME:
+ break;
+
+ case CC_FEATURE_END_CALL:
+ if (xcb->mode == FSMXFR_MODE_TRANSFEREE) {
+ xfr_dcb = fsm_get_dcb(xcb->xfr_call_id);
+ if (call_id == xcb->cns_call_id) {
+ /*
+ * Transferee ended call before transfer was completed.
+ * Notify the transfer call of the status of the
+ * transfer.
+ */
+ data.notify.cause = CC_CAUSE_ERROR;
+ data.notify.subscription = CC_SUBSCRIPTIONS_XFER;
+ data.notify.method = CC_XFER_METHOD_REFER;
+ data.notify.final = TRUE;
+ cc_int_feature(CC_SRC_GSM, CC_SRC_SIP, xfr_dcb->call_id,
+ xfr_dcb->line, CC_FEATURE_NOTIFY, &data);
+ }
+ }
+ lsm_set_hold_ringback_status(xcb->cns_call_id, TRUE);
+ fsmxfr_feature_cancel(xcb, xcb->xfr_line, xcb->xfr_call_id, xcb->cns_call_id,
+ CC_SK_EVT_TYPE_IMPLI);
+ fsmxfr_cleanup(fcb, __LINE__, TRUE);
+ break;
+
+ case CC_FEATURE_HOLD:
+ if ((msg->data_valid) &&
+ (feat_data->hold.call_info.data.hold_resume_reason == CC_REASON_SWAP ||
+ feat_data->hold.call_info.data.hold_resume_reason == CC_REASON_XFER ||
+ feat_data->hold.call_info.data.hold_resume_reason == CC_REASON_INTERNAL))
+ {
+ feat_data->hold.call_info.data.call_info_feat_data.protect = TRUE;
+ } else {
+ DEF_DEBUG(DEB_F_PREFIX"Invoke hold call_id = %d t_call_id=%d\n",
+ DEB_F_PREFIX_ARGS(GSM, fname), xcb->xfr_call_id, xcb->cns_call_id);
+ //Actual hold to this call, so break the feature layer.
+ ui_terminate_feature(xcb->xfr_line, xcb->xfr_call_id, xcb->cns_call_id);
+ fsmxfr_feature_cancel(xcb, xcb->xfr_line, xcb->xfr_call_id,
+ xcb->cns_call_id, CC_SK_EVT_TYPE_IMPLI);
+ fsmxfr_cleanup(fcb, __LINE__, TRUE);
+ }
+ fsm_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ break;
+
+ default:
+ fsm_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ break;
+ } /* switch (ftr_id) */
+
+ break;
+
+ case CC_SRC_GSM:
+ switch (ftr_id) {
+ case CC_FEATURE_DIRTRXFR:
+ xfr_dcb = fsm_get_dcb(xcb->xfr_call_id);
+ called_num = fsmxfr_get_dialed_num(xfr_dcb);
+
+ if (called_num && called_num[0] != '\0') {
+ fsmxfr_set_xfer_data(CC_CAUSE_XFER_LOCAL,
+ xcb->method, xcb->cns_call_id,
+ called_num,
+ &(data.xfer));
+
+ data.xfer.method = CC_XFER_METHOD_DIRXFR;
+
+ cc_int_feature(CC_SRC_GSM, CC_SRC_SIP,
+ call_id, line,
+ CC_FEATURE_XFER, &data);
+ } else {
+ /*
+ * Can't transfer the call without a dialstring, so
+ * just cleanup the transfer.
+ */
+ fsmxfr_feature_cancel(xcb, xcb->xfr_line, xcb->xfr_call_id,
+ xcb->cns_call_id, CC_SK_EVT_TYPE_IMPLI);
+ fsmxfr_cleanup(fcb, __LINE__, TRUE);
+ }
+ return(SM_RC_END);
+ case CC_FEATURE_END_CALL:
+ /*
+ * Only cleanup the whole xfer if we know that we don't have
+ * an outstanding blind transfer and if we are not the target.
+ * We need the xcb to hang around because other users (lsm,...)
+ * may still want to do something special and the xcb is the only
+ * way they know that the call is involved in a transfer.
+ */
+ if (xcb->type == FSMXFR_TYPE_BLND_XFR) {
+ fsmxfr_cleanup(fcb, __LINE__, FALSE);
+ } else if ((xcb->type == FSMXFR_TYPE_XFR) &&
+ (msg->data.endcall.cause == CC_CAUSE_NO_USER_RESP)) {
+
+ DEF_DEBUG(DEB_F_PREFIX"Xfer type =%d\n",
+ DEB_F_PREFIX_ARGS(GSM, fname), xcb->type);
+
+ if ((platGetPhraseText(STR_INDEX_TRANSFERRING,
+ (char *) tmp_str,
+ STATUS_LINE_MAX_LEN - 1)) == CPR_SUCCESS) {
+ lsm_ui_display_status(tmp_str, xcb->xfr_line, xcb->xfr_call_id);
+ }
+
+ if (xcb->xfer_comp_req == FALSE) {
+ fsmxfr_feature_cancel(xcb, xcb->xfr_line, xcb->xfr_call_id,
+ xcb->cns_call_id, CC_SK_EVT_TYPE_IMPLI);
+ } else {
+ // Mark it as transfer complete.
+ fsmxfr_mark_dcb_for_xfr_complete(xcb->cns_call_id,
+ xcb->xfr_call_id, TRUE);
+ }
+ fsmxfr_cleanup(fcb, __LINE__, FALSE);
+ } else if (xcb->mode == FSMXFR_MODE_TARGET) {
+ break;
+ } else {
+ /* Early attended transfer generates internal END_CALL event
+ * do not send cancel in that case
+ */
+ if (xcb->xfer_comp_req == FALSE) {
+ fsmxfr_feature_cancel(xcb, xcb->xfr_line, xcb->xfr_call_id,
+ xcb->cns_call_id, CC_SK_EVT_TYPE_IMPLI);
+ }
+ fsmxfr_cleanup(fcb, __LINE__, TRUE);
+ }
+ break;
+
+ case CC_FEATURE_HOLD:
+ ui_set_local_hold(dcb->line, dcb->call_id);
+ if(msg->data_valid) {
+ feat_data->hold.call_info.data.call_info_feat_data.protect = TRUE;
+ }
+ fsm_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ break;
+
+ default:
+ fsm_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ break;
+ } /* switch (ftr_id) */
+ break;
+
+ case CC_SRC_SIP:
+ switch (ftr_id) {
+ case CC_FEATURE_CALL_PRESERVATION:
+ DEF_DEBUG(DEB_F_PREFIX"Preservation call_id = %d t_call_id=%d\n",
+ DEB_F_PREFIX_ARGS(GSM, fname), xcb->xfr_call_id, xcb->cns_call_id);
+ ui_terminate_feature(xcb->xfr_line, xcb->xfr_call_id, xcb->cns_call_id);
+ fsmxfr_feature_cancel(xcb, xcb->xfr_line, xcb->xfr_call_id,
+ xcb->cns_call_id, CC_SK_EVT_TYPE_IMPLI);
+ fsmxfr_cleanup(fcb, __LINE__, TRUE);
+ break;
+
+ case CC_FEATURE_BLIND_XFER:
+ case CC_FEATURE_XFER:
+ if (msg->data_valid == FALSE) {
+ break;
+ }
+
+ /*
+ * Transfer is valid only for a remote originated transfer.
+ */
+ if (msg->data.xfer.cause != CC_CAUSE_XFER_REMOTE) {
+ break;
+ }
+
+ /*
+ * This call is already involved in a transfer as the transferor,
+ * but one of the parties, the transferee or target has decided to
+ * transfer that leg also. So, now we have a transfer of a transfer.
+ */
+ switch (msg->data.xfer.method) {
+ case CC_XFER_METHOD_BYE:
+ /*
+ * Check for any other active features which may block
+ * the transfer.
+ */
+
+ fsmxfr_set_xfer_data(CC_CAUSE_OK, CC_XFER_METHOD_BYE,
+ CC_NO_CALL_ID,
+ FSMXFR_NULL_DIALSTRING, &(data.xfer));
+
+ cc_int_feature_ack(CC_SRC_GSM, CC_SRC_SIP, dcb->call_id,
+ dcb->line, ftr_id, &data, CC_CAUSE_NORMAL);
+
+ /*
+ * Make sure we have a valid dialstring.
+ */
+ if (fsmxfr_copy_dialstring(&xcb->dialstring,
+ msg->data.xfer.dialstring) == FALSE) {
+ fsmxfr_feature_cancel(xcb, xcb->xfr_line, xcb->xfr_call_id, xcb->cns_call_id,
+ CC_SK_EVT_TYPE_IMPLI);
+ fsmxfr_cleanup(fcb, __LINE__, TRUE);
+ break;
+ }
+
+ /*
+ * Mark the active flag in the xcb. This flag is used later
+ * when the RELEASE comes from SIP, so that the GSM
+ * knows that this call is still involved in a transfer.
+ */
+ xcb->active = TRUE;
+
+ break;
+
+ case CC_XFER_METHOD_REFER:
+ int_rc = fsmxfr_remote_transfer(fcb, ftr_id, call_id, dcb->line,
+ msg->data.xfer.dialstring,
+ msg->data.xfer.referred_by);
+
+ if (int_rc == FALSE) {
+ fsmxfr_set_xfer_data(CC_CAUSE_ERROR, CC_XFER_METHOD_REFER,
+ CC_NO_CALL_ID,
+ FSMXFR_NULL_DIALSTRING, &(data.xfer));
+
+ cc_int_feature_ack(CC_SRC_GSM, CC_SRC_SIP, call_id,
+ dcb->line, ftr_id, &data,
+ CC_CAUSE_ERROR);
+ }
+ break;
+
+ default:
+ break;
+ } /* switch (msg->data.xfer.method) */
+
+ break;
+
+ case CC_FEATURE_NOTIFY:
+ /*
+ * This could be:
+ * 1. for an unattended transfer.
+ * The transferee is notifying us, the transferor, of the status
+ * of the transfer, ie. was the transferee able to connect to
+ * the target?
+ *
+ * 2. Or this is an attended transfer, and this is the call from
+ * the transferee to the target. The stack will NOTIFY the GSM
+ * of the status of the call after it receives a message
+ * from the network indicating success of failure.
+ */
+ if (msg->data_valid == FALSE) {
+ break;
+ }
+
+ /*
+ * Ack the request.
+ */
+ cc_int_feature_ack(CC_SRC_GSM, CC_SRC_SIP, dcb->call_id,
+ dcb->line, CC_FEATURE_NOTIFY, NULL,
+ CC_CAUSE_NORMAL);
+
+ switch (xcb->type) {
+ case FSMXFR_TYPE_BLND_XFR:
+ switch (msg->data.notify.method) {
+ case CC_XFER_METHOD_BYE:
+ /*
+ * This notification is really from the SIP stack.
+ * The network will not send a NOTIFY for a BYE/Also
+ * transfer, so the SIP stack just sends one up when
+ * it uses that method.
+ */
+
+ /*
+ * Release the transfer call.
+ */
+ data.endcall.cause = CC_CAUSE_OK;
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, dcb->call_id,
+ dcb->line, CC_FEATURE_END_CALL, &data);
+ break;
+
+ case CC_XFER_METHOD_REFER:
+ if (msg->data.notify.cause == CC_CAUSE_OK) {
+ /*
+ * Release the transfer call.
+ */
+ /* Set the dcb flag to indicate transfer is complete, so that
+ * it won't display endcall in this case
+ */
+ fsmxfr_mark_dcb_for_xfr_complete(xcb->cns_call_id,
+ xcb->xfr_call_id, TRUE);
+
+ data.endcall.cause = CC_CAUSE_OK;
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, dcb->call_id,
+ dcb->line, CC_FEATURE_END_CALL, &data);
+ } else {
+ fsmxfr_cleanup(fcb, __LINE__, TRUE);
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, dcb->call_id,
+ dcb->line, CC_FEATURE_RESUME, NULL);
+ }
+ break;
+
+ default:
+ break;
+ } /* switch (msg->data.notify.method) { */
+
+ break;
+ case FSMXFR_TYPE_DIR_XFR:
+ /*
+ * Clear the transfer call if the transfer was OK,
+ * else just cleanup the transfer. The consultation
+ * call will be released by the target.
+ */
+ xfr_dcb = fsm_get_dcb(xcb->xfr_call_id);
+ if (msg->data.notify.cause == CC_CAUSE_OK) {
+ data.endcall.cause = CC_CAUSE_OK;
+
+ fsmxfr_mark_dcb_for_xfr_complete(xcb->cns_call_id,
+ xcb->xfr_call_id, TRUE);
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM,
+ xfr_dcb->call_id,
+ xfr_dcb->line, CC_FEATURE_END_CALL,
+ &data);
+ } else {
+ lsm_ui_display_status(platform_get_phrase_index_str(TRANSFER_FAILED),
+ dcb->line, xcb->xfr_call_id);
+ lsm_ui_display_status(platform_get_phrase_index_str(TRANSFER_FAILED),
+ dcb->line, xcb->cns_call_id);
+ }
+ if (xcb->cnf_xfr) {
+ /*
+ * If it is a conference transfer clear up the
+ * calls.
+ */
+ fsmxfr_cnf_cleanup(xcb);
+ }
+ break;
+
+ case FSMXFR_TYPE_XFR:
+ switch (msg->data.notify.method) {
+ case CC_XFER_METHOD_BYE:
+ /*
+ * Release the consultation call.
+ */
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, xcb->cns_call_id,
+ dcb->line, CC_FEATURE_END_CALL, NULL);
+
+ /*
+ * Release the call being transferred.
+ */
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, xcb->xfr_call_id,
+ dcb->line, CC_FEATURE_END_CALL, NULL);
+ break;
+
+ case CC_XFER_METHOD_REFER:
+ /*
+ * This notification is from either the target (which is
+ * the consultation call) or the transferee (which is the
+ * transfer call).
+ *
+ * So, do the following based on each case:
+ *
+ * 1. consultation call: this is the transferee receiving
+ * notification of the status of the call from the
+ * transferee to the target.
+ * - notify the transfer call.
+ * - the transfer call will be released by the transferor
+ * after receiving the above notification and the
+ * consultation call will remain.
+ *
+ * 2. transfer call: this is the transferor receiving
+ * notification of the status of the call from the
+ * transferee to the target.
+ * - release the transfer call.
+ * - the consultation call will be released by the target.
+ */
+ xfr_dcb = fsm_get_dcb(xcb->xfr_call_id);
+ if (call_id == xcb->cns_call_id) {
+ /*
+ * Notify the transfer call of the status of the
+ * transfer.
+ */
+ data.notify.cause = msg->data.notify.cause;
+ data.notify.cause_code = msg->data.notify.cause_code;
+ data.notify.subscription = CC_SUBSCRIPTIONS_XFER;
+ data.notify.method = CC_XFER_METHOD_REFER;
+ data.notify.blind_xferror_gsm_id =
+ msg->data.notify.blind_xferror_gsm_id;
+ data.notify.final = TRUE;
+ if (data.notify.blind_xferror_gsm_id == CC_NO_CALL_ID) {
+ cc_int_feature(CC_SRC_GSM, CC_SRC_SIP,
+ xfr_dcb->call_id, xfr_dcb->line,
+ CC_FEATURE_NOTIFY, &data);
+ } else {
+ cc_int_feature(CC_SRC_GSM, CC_SRC_SIP,
+ data.notify.blind_xferror_gsm_id,
+ msg->line, CC_FEATURE_NOTIFY, &data);
+ }
+ } else {
+ /*
+ * Clear the transfer call if the transfer was OK,
+ * else just cleanup the transfer. The consultation
+ * call will be released by the target.
+ */
+ if (xcb == NULL) {
+ GSM_DEBUG_ERROR(GSM_F_PREFIX"Cannot find the active xfer\n", fname);
+ break;
+ }
+
+ if (msg->data.notify.cause == CC_CAUSE_OK) {
+ data.endcall.cause = CC_CAUSE_OK;
+
+ fsmxfr_mark_dcb_for_xfr_complete(xcb->cns_call_id,
+ xcb->xfr_call_id, TRUE);
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM,
+ xfr_dcb->call_id,
+ xfr_dcb->line, CC_FEATURE_END_CALL,
+ &data);
+ } else {
+ lsm_ui_display_status(platform_get_phrase_index_str(TRANSFER_FAILED),
+ dcb->line, xcb->xfr_call_id);
+ fsmxfr_mark_dcb_for_xfr_complete(xcb->cns_call_id,
+ xcb->xfr_call_id, FALSE);
+ fsmxfr_feature_cancel(xcb, xcb->xfr_line, xcb->xfr_call_id,
+ xcb->cns_call_id, CC_SK_EVT_TYPE_IMPLI);
+ /*
+ * Resume the consultation call.
+ * if xcb->cns_call_id == 0, then cns call is already ended.
+ */
+ if (xcb->cns_call_id != CC_NO_CALL_ID) {
+ lsm_ui_display_status(platform_get_phrase_index_str(TRANSFER_FAILED),
+ dcb->line, xcb->cns_call_id);
+ cns_dcb = fsm_get_dcb (xcb->cns_call_id);
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM,
+ xcb->cns_call_id, cns_dcb->line,
+ CC_FEATURE_RESUME, NULL);
+ }
+
+ if (xcb->cnf_xfr) {
+ /*
+ * If it is a conference transfer clear up the
+ * calls.
+ */
+ fsmxfr_cnf_cleanup(xcb);
+ }
+ }
+ fsmxfr_cleanup(fcb, __LINE__, TRUE);
+ } /* if (call_id == xcb->cns_call_id) */
+ break;
+
+ default:
+ break;
+ } /* switch (msg->data.notify.method) { */
+
+ break;
+
+ default:
+ break;
+ } /* switch (xcb->type) { */
+ break;
+
+ default:
+ fsm_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ break;
+ } /* switch (ftr_id) */
+ break;
+
+ default:
+ fsm_sm_ignore_src(fcb, __LINE__, src_id);
+ break;
+ } /* switch (src_id) */
+
+ return (sm_rc);
+}
+
+static void
+fsmxfr_requeue_blind_xfer_dialstring (fsmdef_dcb_t *dcb, fsmxfr_xcb_t *xcb)
+{
+ /*
+ * This is the result of the feature hold so we
+ * can clear the active feature.
+ */
+ dcb->active_feature = CC_FEATURE_NONE;
+
+ /*
+ * If there is a dialstring on the xcb, it is because the
+ * dialstring event for the consultative call has already
+ * been received. We delayed handling the dialstring until
+ * the result of the hold request has been received. We
+ * are now ready to process the dial string so requeue it
+ * for processing
+ */
+ if (xcb->queued_dialstring && xcb->queued_dialstring[0] != '\0') {
+ cc_dialstring(CC_SRC_UI, xcb->cns_call_id, dcb->line,
+ xcb->queued_dialstring);
+ cpr_free(xcb->queued_dialstring);
+ xcb->queued_dialstring = NULL;
+ }
+}
+
+static sm_rcs_t
+fsmxfr_ev_active_feature_ack (sm_event_t *event)
+{
+ static const char fname[] = "fsmxfr_ev_active_feature_ack";
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ cc_feature_ack_t *msg = (cc_feature_ack_t *) event->msg;
+ cc_srcs_t src_id = msg->src_id;
+ cc_features_t ftr_id = msg->feature_id;
+ fsmdef_dcb_t *dcb = fcb->dcb;
+ cc_feature_data_t data;
+ sm_rcs_t sm_rc = SM_RC_CONT;
+ fsmxfr_xcb_t *xcb = fcb->xcb;
+ fsmdef_dcb_t *xfr_dcb = NULL;
+ char *called_num = NULL;
+
+ fsm_sm_ftr(ftr_id, src_id);
+
+ /*
+ * Consume the XFER events and don't pass them along to the other FSMs.
+ */
+ if ((ftr_id == CC_FEATURE_BLIND_XFER) || (ftr_id == CC_FEATURE_XFER)) {
+ sm_rc = SM_RC_END;
+ }
+
+ if (xcb == NULL) {
+ GSM_DEBUG_ERROR(GSM_F_PREFIX"Cannot find the active xfer\n", fname);
+ return (sm_rc);
+ }
+
+ switch (src_id) {
+ case CC_SRC_SIP:
+ case CC_SRC_GSM:
+ switch (ftr_id) {
+ case CC_FEATURE_BLIND_XFER:
+ switch (xcb->type) {
+ case FSMXFR_TYPE_BLND_XFR:
+ switch (msg->data.xfer.method) {
+ case CC_XFER_METHOD_REFER:
+ /*
+ * Clear the call if the transfer was OK, else just cleanup
+ * the transfer.
+ */
+ if (msg->cause == CC_CAUSE_OK) {
+ // This does not indicate that transfer was successful. So wait for the NOTIFYs.
+ //data.endcall.cause = CC_CAUSE_OK;
+
+ //cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, dcb->call_id,
+ //dcb->line, CC_FEATURE_END_CALL, &data);
+ } else {
+ fsmxfr_feature_cancel(xcb, xcb->xfr_line, xcb->xfr_call_id,
+ xcb->cns_call_id, CC_SK_EVT_TYPE_IMPLI);
+ fsmxfr_cleanup(fcb, __LINE__, TRUE);
+ }
+ break;
+
+ default:
+ fsm_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ break;
+ } /* switch (msg->data.xfer.method) { */
+
+ break;
+
+ default:
+ break;
+ } /* switch (xcb->type) { */
+ break;
+
+ case CC_FEATURE_HOLD:
+ if (msg->cause == CC_CAUSE_REQUEST_PENDING) {
+ /*
+ * HOLD request is pending. Let this event drop through
+ * to the default sm for handling.
+ */
+ fsm_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ break;
+ }
+
+ /*
+ * If this is the hold response during a blind transfer,
+ * check to see if a dialstring has been queued for processing.
+ */
+ if (xcb->type == FSMXFR_TYPE_BLND_XFR &&
+ xcb->xfr_call_id == fcb->call_id) {
+ fsmxfr_requeue_blind_xfer_dialstring(dcb, xcb);
+ break;
+ }
+
+ /*
+ * If xfer soft key has not been pressed a second time then
+ * don't transfer the call.
+ */
+ if (!xcb->xfer_comp_req) {
+ break;
+ }
+
+
+ /* If there is any error reported from SIP stack then clear the
+ * transfer data. One such case is where digest authentication
+ * fails due to maximum retry (of 2). SIP stack generates a valid
+ * ACK event by setting cause code to ERROR
+ */
+ if (msg->cause == CC_CAUSE_ERROR) {
+
+ lsm_ui_display_status(platform_get_phrase_index_str(TRANSFER_FAILED),
+ xcb->xfr_line, xcb->xfr_call_id);
+ lsm_ui_display_status(platform_get_phrase_index_str(TRANSFER_FAILED),
+ xcb->cns_line, xcb->cns_call_id);
+ fsmxfr_feature_cancel(xcb, xcb->xfr_line, xcb->xfr_call_id, xcb->cns_call_id,
+ CC_SK_EVT_TYPE_IMPLI);
+ fsmxfr_cleanup(fcb, __LINE__, TRUE);
+
+ break;
+ }
+
+ /*
+ * Instruct the stack to transfer the call.
+ */
+ if (xcb->type == FSMXFR_TYPE_XFR) {
+ /*
+ * Check to see which side of the transfer
+ * the request is coming from. if it is from
+ * the XFR side, make sure the CNS side is
+ * indeed in the Held state.
+ */
+ if (xcb->cns_call_id == fcb->call_id) {
+ xfr_dcb = fsm_get_dcb(xcb->xfr_call_id);
+
+ called_num = fsmxfr_get_dialed_num(fcb->dcb);
+
+ if (called_num && called_num[0] != '\0') {
+ fsmxfr_set_xfer_data(CC_CAUSE_XFER_LOCAL,
+ xcb->method, fcb->dcb->call_id,
+ called_num,
+ &(data.xfer));
+ cc_int_feature(CC_SRC_GSM, CC_SRC_SIP, xfr_dcb->call_id,
+ xfr_dcb->line, CC_FEATURE_XFER, &data);
+ } else {
+ /*
+ * Can't transfer the call without a dialstring, so
+ * just cleanup the transfer.
+ */
+ fsmxfr_feature_cancel(xcb, xcb->xfr_line, xcb->xfr_call_id,
+ xcb->cns_call_id, CC_SK_EVT_TYPE_IMPLI);
+ fsmxfr_cleanup(fcb, __LINE__, TRUE);
+ }
+ } else {
+ /*
+ * This is hold response on the xfer call leg.
+ *
+ * Check to see if dialstring has been queued for
+ * processing. If so, it is requeued to GSM and
+ * we delay until the consultative call is setup.
+ */
+ //if (fsmxfr_requeue_blind_xfer_dialstring(dcb, xcb)) {
+ // break;
+ //}
+
+ /*
+ * Get the dcb of the consultative call.
+ */
+ xfr_dcb = fsm_get_dcb(xcb->cns_call_id);
+
+ /*
+ * We must wait for the hold request on the consultative
+ * call to complete before completing the xfer. The state
+ * of the consultative call must be FSMDEF_S_HOLDING.
+ * FSMDEF_S_HOLDING is not a completed hold request which
+ * is why it is not checked for here.
+ */
+ if (xfr_dcb->fcb->state != FSMDEF_S_HOLDING) {
+ break;
+ } else {
+
+ called_num = fsmxfr_get_dialed_num(xfr_dcb);
+
+ if (called_num && called_num[0] != '\0') {
+ fsmxfr_set_xfer_data(CC_CAUSE_XFER_LOCAL,
+ xcb->method, xfr_dcb->call_id,
+ called_num,
+ &(data.xfer));
+ cc_int_feature(CC_SRC_GSM, CC_SRC_SIP,
+ fcb->dcb->call_id, fcb->dcb->line,
+ CC_FEATURE_XFER, &data);
+ } else {
+ /*
+ * Can't transfer the call without a dialstring, so
+ * just cleanup the transfer.
+ */
+ fsmxfr_feature_cancel(xcb, xcb->xfr_line, xcb->xfr_call_id,
+ xcb->cns_call_id, CC_SK_EVT_TYPE_IMPLI);
+ fsmxfr_cleanup(fcb, __LINE__, TRUE);
+ }
+ }
+ }
+ }
+ break;
+
+ case CC_FEATURE_XFER:
+
+ if (msg->cause != CC_CAUSE_OK) {
+ lsm_ui_display_status(platform_get_phrase_index_str(TRANSFER_FAILED),
+ xcb->xfr_line, xcb->xfr_call_id);
+ lsm_ui_display_status(platform_get_phrase_index_str(TRANSFER_FAILED),
+ xcb->cns_line, xcb->cns_call_id);
+ fsmxfr_feature_cancel(xcb, xcb->xfr_line, xcb->xfr_call_id,
+ xcb->cns_call_id, CC_SK_EVT_TYPE_IMPLI);
+ fsmxfr_cleanup(fcb, __LINE__, TRUE);
+ } else {
+ fsm_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+ }
+ break;
+
+ default:
+ fsm_sm_ignore_ftr(fcb, __LINE__, ftr_id);
+
+ break;
+ } /* switch (ftr_id) */
+
+ break;
+
+ default:
+ fsm_sm_ignore_src(fcb, __LINE__, src_id);
+
+ break;
+ } /* switch (src_id) */
+
+ return (sm_rc);
+}
+
+
+static sm_rcs_t
+fsmxfr_ev_active_onhook (sm_event_t *event)
+{
+ static const char fname[] = "fsmxfr_ev_active_onhook";
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ cc_onhook_t *msg = (cc_onhook_t *) event->msg;
+ callid_t call_id = msg->call_id;
+ callid_t other_call_id;
+ fsmxfr_xcb_t *xcb = fcb->xcb;
+ fsm_fcb_t *other_fcb;
+ fsmdef_dcb_t *xfr_dcb;
+ cc_feature_data_t data;
+ fsm_fcb_t *cns_fcb, *xfr_fcb;
+ int onhook_xfer = 0;
+
+ if (xcb == NULL) {
+ GSM_DEBUG_ERROR(GSM_F_PREFIX"Cannot find the active xfer\n", fname);
+ return (SM_RC_CONT);
+ }
+
+ cns_fcb = fsm_get_fcb_by_call_id_and_type(xcb->cns_call_id, FSM_TYPE_DEF);
+ xfr_fcb = fsm_get_fcb_by_call_id_and_type(xcb->xfr_call_id, FSM_TYPE_DEF);
+
+ if (xcb->cnf_xfr) {
+ /*
+ * This is the conference transfer so clear the
+ * second line also.
+ */
+ xcb->cnf_xfr = FALSE;
+ other_call_id = fsmxfr_get_other_call_id(xcb, call_id);
+ other_fcb = fsm_get_fcb_by_call_id_and_type(other_call_id,
+ FSM_TYPE_XFR);
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, other_call_id,
+ other_fcb ? other_fcb->dcb->line:CC_NO_LINE, CC_FEATURE_END_CALL, NULL);
+ fsmxfr_cleanup(fcb, __LINE__, TRUE);
+ return (SM_RC_CONT);
+ }
+
+ if (xcb->mode == FSMXFR_MODE_TRANSFEREE) {
+ xfr_dcb = fsm_get_dcb(xcb->xfr_call_id);
+ if (call_id == xcb->cns_call_id) {
+ /*
+ * Transferee ended call before transfer was completed.
+ * Notify the transfer call of the status of the
+ * transfer.
+ *
+ * Note: This must be changed when fix is put in for configurable
+ * onhook xfer (CSCsb86757) so that 200 NOTIFY is sent when
+ * xfer is completed. fsmxfr_initiate_xfr will take care
+ * of this for us so just need to make sure the NOTIFY is
+ * sent to SIP stack only when xfer is abandoned due to
+ * onhook.
+ */
+ data.notify.cause = CC_CAUSE_ERROR;
+ data.notify.subscription = CC_SUBSCRIPTIONS_XFER;
+ data.notify.method = CC_XFER_METHOD_REFER;
+ data.notify.final = TRUE;
+ cc_int_feature(CC_SRC_GSM, CC_SRC_SIP, xfr_dcb->call_id,
+ xfr_dcb->line, CC_FEATURE_NOTIFY, &data);
+ if (cns_fcb && cns_fcb->state != FSMDEF_S_HOLDING &&
+ cns_fcb->state != FSMDEF_S_HOLD_PENDING) {
+ fsmxfr_feature_cancel(xcb, xfr_dcb->line,
+ xcb->xfr_call_id, xcb->cns_call_id, CC_SK_EVT_TYPE_IMPLI);
+
+ fsmxfr_cleanup(fcb, __LINE__, TRUE);
+ }
+ /*
+ * fix bug CSCtb23681.
+ */
+ if( xfr_dcb->fcb->state == FSMDEF_S_HOLDING )
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, xfr_dcb->call_id,xfr_dcb->line, CC_FEATURE_END_CALL, NULL);
+ return (SM_RC_CONT);
+ }
+ }
+
+ if (msg->softkey) {
+ /*
+ * Softkey set to TRUE indicates endcall softkey was pressed.
+ * This causes the call with focus to release.
+ */
+ if ((call_id == xcb->cns_call_id) &&
+ (cns_fcb->state == FSMDEF_S_HOLDING ||
+ cns_fcb->state == FSMDEF_S_HOLD_PENDING)) {
+ /* ignore the onhook event for the held consultation call */
+ } if (msg->active_list == CC_REASON_ACTIVECALL_LIST) {
+ /* Active call list has been requested also
+ * existing consult call is canceled
+ * But transfer state machine will remain
+ * intact as feature layer is still running.*/
+ xcb->cns_call_id = CC_NO_CALL_ID;
+ xcb->cns_line = CC_NO_LINE;
+
+ }else {
+ fsmxfr_feature_cancel(xcb, xcb->xfr_line,
+ xcb->xfr_call_id, xcb->cns_call_id, CC_SK_EVT_TYPE_IMPLI);
+
+ fsmxfr_cleanup(fcb, __LINE__, TRUE);
+ }
+ return (SM_RC_CONT);
+ } else {
+ /*
+ * Softkey set to FALSE indicates handset, speaker button, or
+ * headset went onhook. This causes the transfer to complete
+ * if onhook xfer is enabled by config.
+ */
+ config_get_value(CFGID_XFR_ONHOOK_ENABLED, &onhook_xfer,
+ sizeof(onhook_xfer));
+ if (onhook_xfer && ((cns_fcb->state == FSMDEF_S_OUTGOING_ALERTING)||
+ (cns_fcb->state == FSMDEF_S_CONNECTED))) {
+ fsmxfr_initiate_xfr(event);
+ return (SM_RC_END);
+ } else if (onhook_xfer && xfr_fcb &&
+ ((xfr_fcb->state == FSMDEF_S_OUTGOING_ALERTING)||
+ (xfr_fcb->state == FSMDEF_S_CONNECTED))) {
+ fsmxfr_initiate_xfr(event);
+ return (SM_RC_END);
+ } else {
+ fsmxfr_feature_cancel(xcb, xcb->xfr_line,
+ xcb->xfr_call_id, xcb->cns_call_id, CC_SK_EVT_TYPE_IMPLI);
+
+ fsmxfr_cleanup(fcb, __LINE__, TRUE);
+ return (SM_RC_CONT);
+ }
+ }
+}
+
+
+/*
+ * This event can only happen if the user initiated a blind transfer.
+ */
+static sm_rcs_t
+fsmxfr_ev_active_dialstring (sm_event_t *event)
+{
+ static const char fname[] = "fsmxfr_ev_active_dialstring";
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ cc_dialstring_t *msg = (cc_dialstring_t *) event->msg;
+ callid_t call_id = msg->call_id;
+ line_t line = msg->line;
+ fsmdef_dcb_t *xfr_dcb;
+ fsmxfr_xcb_t *xcb = fcb->xcb;
+ cc_feature_data_t data;
+ char *dialstring;
+
+ /*
+ * Make sure we have a valid dialstring.
+ */
+ dialstring = msg->dialstring;
+ if ((dialstring == NULL) || (dialstring[0] == '\0')) {
+ FSM_DEBUG_SM(DEB_L_C_F_PREFIX"dialstring= %c\n",
+ DEB_L_C_F_PREFIX_ARGS(FSM, msg->line, call_id, fname), '\0');
+ return (SM_RC_END);
+ }
+
+ FSM_DEBUG_SM(DEB_L_C_F_PREFIX"dialstring= %s\n",
+ DEB_L_C_F_PREFIX_ARGS(FSM, msg->line, call_id, fname), dialstring);
+
+ /*
+ * If this is a blind xfer and we have received the dialstring
+ * before the original call has received a response to the hold
+ * request, defer processing the dialstring event. active_feature
+ * will be set to CC_FEATURE_BLIND_XFER if we are still waiting
+ * for the hold response. The dial string is saved on the xcb
+ * until needed.
+ */
+ if (xcb == NULL) {
+ return (SM_RC_END);
+ }
+
+ xfr_dcb = fsm_get_dcb(xcb->xfr_call_id);
+ if (xfr_dcb == NULL) {
+ return (SM_RC_END);
+ }
+
+ if (xfr_dcb->active_feature == CC_FEATURE_BLIND_XFER) {
+ if (!fsmxfr_copy_dialstring(&xcb->queued_dialstring, dialstring)) {
+ GSM_DEBUG_ERROR(GSM_L_C_F_PREFIX"unable to copy dialstring\n",
+ msg->line, call_id, fname);
+ }
+ return (SM_RC_END);
+ }
+
+ if (xcb->type == FSMXFR_TYPE_BLND_XFR) {
+ lsm_set_hold_ringback_status(xcb->cns_call_id, FALSE);
+ }
+ /*
+ * Make sure that this event came from the consultation call and that
+ * this is a blind transfer. We ignore the event if this is a transfer
+ * with consultation, because we want to talk to the target. For an
+ * unattended transfer this event is the final event needed to complete
+ * the transfer.
+ */
+ if ((xcb->cns_call_id != call_id) || (xcb->type != FSMXFR_TYPE_BLND_XFR)) {
+ return (SM_RC_CONT);
+ }
+
+ switch (xcb->method) {
+ case CC_XFER_METHOD_BYE:
+ case CC_XFER_METHOD_REFER:
+ /*
+ * This is an unattended transfer so:
+ * 1. clear the consultation call,
+ * 2. instruct the stack to initiate the transfer.
+ */
+
+ /*
+ * Release this call because it was only used to collect digits.
+ */
+ data.endcall.cause = CC_CAUSE_NORMAL;
+ cc_int_feature(CC_SRC_GSM, CC_SRC_GSM, call_id,
+ line, CC_FEATURE_END_CALL, &data);
+
+
+ /*
+ * Send an event to the transferer call leg so it can send the called
+ * number to the transferee.
+ */
+ fsmxfr_set_xfer_data(CC_CAUSE_XFER_LOCAL, xcb->method, CC_NO_CALL_ID,
+ dialstring, &(data.xfer));
+
+ cc_int_feature(CC_SRC_GSM, CC_SRC_SIP, xcb->xfr_call_id,
+ line, fsmxfr_type_to_feature(xcb->type), &data);
+
+ FSM_DEBUG_SM(get_debug_string(FSMXFR_DBG_XFR_INITIATED),
+ xcb->xfr_id, xcb->xfr_call_id, xcb->cns_call_id, __LINE__);
+
+ break;
+
+ default:
+ break;
+ } /* switch (xcb->method) */
+
+ return (SM_RC_END);
+}
+
+
+cc_int32_t
+fsmxfr_show_cmd (cc_int32_t argc, const char *argv[])
+{
+ fsmxfr_xcb_t *xcb;
+ int i = 0;
+
+ PR_ASSERT( i == 0 );
+ /*
+ * Check if need help.
+ */
+ if ((argc == 2) && (argv[1][0] == '?')) {
+ debugif_printf("%s", "show fsmxfr\n");
+ return (0);
+ }
+
+ debugif_printf("%s", "\n------------------------ FSMXFR xcbs -------------------------");
+ debugif_printf("%s", "\ni xfr_id xcb type method xfr_call_id cns_call_id");
+ debugif_printf("%s", "\n--------------------------------------------------------------\n");
+
+ FSM_FOR_ALL_CBS(xcb, fsmxfr_xcbs, FSMXFR_MAX_XCBS) {
+ debugif_printf("%-2d %-6d 0x%8p %-4d %-6d %-11d %-11d\n",
+ i++, xcb->xfr_id, xcb, xcb->type, xcb->method,
+ xcb->xfr_call_id, xcb->cns_call_id);
+ }
+
+ return (0);
+}
+
+
+void
+fsmxfr_init (void)
+{
+ fsmxfr_xcb_t *xcb;
+
+
+ /*
+ * Initialize the xcbs.
+ */
+ fsmxfr_xcbs = (fsmxfr_xcb_t *)
+ cpr_calloc(FSMXFR_MAX_XCBS, sizeof(fsmxfr_xcb_t));
+
+ FSM_FOR_ALL_CBS(xcb, fsmxfr_xcbs, FSMXFR_MAX_XCBS) {
+ fsmxfr_init_xcb(xcb);
+ }
+
+ /*
+ * Initialize the state/event table.
+ */
+ fsmxfr_sm_table.min_state = FSMXFR_S_MIN;
+ fsmxfr_sm_table.max_state = FSMXFR_S_MAX;
+ fsmxfr_sm_table.min_event = CC_MSG_MIN;
+ fsmxfr_sm_table.max_event = CC_MSG_MAX;
+ fsmxfr_sm_table.table = (&(fsmxfr_function_table[0][0]));
+}
+
+cc_transfer_mode_e
+cc_is_xfr_call (callid_t call_id)
+{
+ static const char fname[] = "cc_is_xfr_call";
+ int mode;
+
+ if (call_id == CC_NO_CALL_ID) {
+ return CC_XFR_MODE_NONE;
+ }
+ mode = fsmutil_is_xfr_leg(call_id, fsmxfr_xcbs, FSMXFR_MAX_XCBS);
+
+ switch (mode) {
+ case FSMXFR_MODE_TRANSFEROR:
+ FSM_DEBUG_SM(DEB_F_PREFIX"xfer mode is transferor for call id = %d\n", DEB_F_PREFIX_ARGS(FSM, fname), call_id);
+ return CC_XFR_MODE_TRANSFEROR;
+ case FSMXFR_MODE_TRANSFEREE:
+ FSM_DEBUG_SM(DEB_F_PREFIX"xfer mode is transferee for call id = %d\n", DEB_F_PREFIX_ARGS(FSM, fname), call_id);
+ return CC_XFR_MODE_TRANSFEREE;
+ case FSMXFR_MODE_TARGET:
+ FSM_DEBUG_SM(DEB_F_PREFIX"xfer mode is target for call id = %d\n", DEB_F_PREFIX_ARGS(FSM, fname), call_id);
+ return CC_XFR_MODE_TARGET;
+ default:
+ FSM_DEBUG_SM(DEB_F_PREFIX"invalid xfer mode %d for call id = %d\n", DEB_F_PREFIX_ARGS(FSM, fname), mode, call_id);
+ return CC_XFR_MODE_NONE;
+ }
+}
+
+void
+fsmxfr_shutdown (void)
+{
+ cpr_free(fsmxfr_xcbs);
+ fsmxfr_xcbs = NULL;
+}
+
+int
+fsmutil_is_xfr_consult_call (callid_t call_id)
+{
+ return fsmutil_is_xfr_consult_leg(call_id, fsmxfr_xcbs, FSMXFR_MAX_XCBS);
+}
+
+callid_t
+fsmxfr_get_consult_call_id (callid_t call_id)
+{
+ fsmxfr_xcb_t *xcb;
+
+ xcb = fsmxfr_get_xcb_by_call_id(call_id);
+
+ if (xcb && call_id == xcb->xfr_call_id) {
+ return (fsmxfr_get_other_call_id(xcb, call_id));
+ } else {
+ return (CC_NO_CALL_ID);
+ }
+}
+
+callid_t
+fsmxfr_get_primary_call_id (callid_t call_id)
+{
+ fsmxfr_xcb_t *xcb;
+
+ xcb = fsmxfr_get_xcb_by_call_id(call_id);
+
+ if (xcb && (xcb->cns_call_id == call_id)) {
+ return (fsmxfr_get_other_call_id(xcb, call_id));
+ } else {
+ return (CC_NO_CALL_ID);
+ }
+}
diff --git a/libs/sipcc/core/gsm/gsm.c b/libs/sipcc/core/gsm/gsm.c
new file mode 100755
index 0000000000..fdf9e83f39
--- /dev/null
+++ b/libs/sipcc/core/gsm/gsm.c
@@ -0,0 +1,608 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "cpr_types.h"
+#include "cpr_memory.h"
+#include "cpr_stdio.h"
+#include "cpr_stdlib.h"
+#include "cpr_ipc.h"
+#include "cpr_errno.h"
+#include "cpr_time.h"
+#include "cpr_rand.h"
+#include "cpr_timers.h"
+#include "cpr_threads.h"
+#include "phone.h"
+#include "phntask.h"
+#include "gsm.h"
+#include "lsm.h"
+#include "vcm.h"
+#include "fsm.h"
+#include "phone_debug.h"
+#include "debug.h"
+#include "fim.h"
+#include "gsm_sdp.h"
+#include "ccsip_subsmanager.h"
+#include "dialplanint.h"
+#include "kpmlmap.h"
+#include "subapi.h"
+#include "platform_api.h"
+
+static void sub_process_feature_msg(uint32_t cmd, void *msg);
+static void sub_process_feature_notify(ccsip_sub_not_data_t *msg, callid_t call_id,
+ callid_t other_call_id);
+static void sub_process_b2bcnf_msg(uint32_t cmd, void *msg);
+void fsmb2bcnf_get_sub_call_id_from_ccb(fsmcnf_ccb_t *ccb, callid_t *cnf_call_id,
+ callid_t *cns_call_id);
+cprMsgQueue_t gsm_msg_queue;
+void destroy_gsm_thread(void);
+void dp_shutdown();
+extern void dcsm_process_jobs(void);
+extern void dcsm_init(void);
+extern void dcsm_shutdown(void);
+
+/* Flag to see whether we can start processing events */
+
+static boolean gsm_initialized = FALSE;
+extern cprThread_t gsm_thread;
+static media_timer_callback_fp* media_timer_callback = NULL;
+
+/**
+ * Add media falsh one time timer call back. It's for ROUNDTABLE only.
+ */
+void
+gsm_set_media_callback(media_timer_callback_fp* callback) {
+ media_timer_callback = callback;
+}
+
+void
+gsm_set_initialized (void)
+{
+ gsm_initialized = TRUE;
+}
+
+boolean
+gsm_get_initialize_state (void)
+{
+ return gsm_initialized;
+}
+
+cprBuffer_t
+gsm_get_buffer (uint16_t size)
+{
+ return cpr_malloc(size);
+}
+
+
+cpr_status_e
+gsm_send_msg (uint32_t cmd, cprBuffer_t buf, uint16_t len)
+{
+ phn_syshdr_t *syshdr;
+
+ syshdr = (phn_syshdr_t *) cprGetSysHeader(buf);
+ if (!syshdr) {
+ return CPR_FAILURE;
+ }
+ syshdr->Cmd = cmd;
+ syshdr->Len = len;
+
+ if (cprSendMessage(gsm_msg_queue, buf, (void **) &syshdr) == CPR_FAILURE) {
+ cprReleaseSysHeader(syshdr);
+ return CPR_FAILURE;
+ }
+ return CPR_SUCCESS;
+}
+
+
+boolean
+gsm_process_msg (uint32_t cmd, void *msg)
+{
+ static const char fname[] = "gsm_process_msg";
+ boolean release_msg = TRUE;
+ cc_msgs_t msg_id = ((cc_setup_t *)msg)->msg_id;
+ int event_id = msg_id;
+
+ GSM_DEBUG(DEB_F_PREFIX"cmd= 0x%x\n", DEB_F_PREFIX_ARGS(GSM, fname), cmd);
+
+ switch (cmd) {
+ case GSM_GSM:
+ case GSM_SIP:
+ if (gsm_initialized) {
+
+ if (event_id == CC_MSG_FEATURE &&
+ (((cc_feature_t *) msg)->feature_id == CC_FEATURE_CAC_RESP_PASS)) {
+
+ fsm_cac_process_bw_avail_resp ();
+
+ /* Release all memory for CC_FEATURE_CAC_..message */
+ release_msg = TRUE;
+
+ GSM_DEBUG(DEB_F_PREFIX"CAC Message Processed: 0x%x\n", DEB_F_PREFIX_ARGS(GSM, fname), cmd);
+ } else if (event_id == CC_MSG_FEATURE &&
+ (((cc_feature_t *) msg)->feature_id == CC_FEATURE_CAC_RESP_FAIL)) {
+
+ fsm_cac_process_bw_failed_resp ();
+
+ /* Release all memory for CC_FEATURE_CAC_..message */
+ release_msg = TRUE;
+
+ GSM_DEBUG(DEB_F_PREFIX"CAC Message Processed: 0x%x\n", DEB_F_PREFIX_ARGS(GSM, fname), cmd);
+ } else {
+
+ release_msg = fim_process_event(msg, FALSE);
+ GSM_DEBUG(DEB_F_PREFIX"Message Processed: 0x%x\n", DEB_F_PREFIX_ARGS(GSM, fname), cmd);
+ }
+ }
+ if (release_msg == TRUE) {
+ fim_free_event(msg);
+ }
+ break;
+
+ default:
+ GSM_DEBUG(DEB_F_PREFIX"Unknown Cmd received: 0x%x\n", DEB_F_PREFIX_ARGS(GSM, fname), cmd);
+ break;
+ }
+
+ return(release_msg);
+}
+
+
+void
+gsm_process_timer_expiration (void *msg)
+{
+ static const char fname[] = "gsm_process_timer_expiration";
+ cprCallBackTimerMsg_t *timerMsg;
+ void *timeout_msg = NULL;
+
+ timerMsg = (cprCallBackTimerMsg_t *) msg;
+ TMR_DEBUG(DEB_F_PREFIX"Timer %s expired\n", DEB_F_PREFIX_ARGS(GSM, fname), timerMsg->expiredTimerName);
+
+ switch (timerMsg->expiredTimerId) {
+
+ case GSM_MULTIPART_TONES_TIMER:
+ case GSM_CONTINUOUS_TONES_TIMER:
+ lsm_tmr_tones_callback(timerMsg->usrData);
+ break;
+
+ case GSM_ERROR_ONHOOK_TIMER:
+ fsmdef_error_onhook_timeout(timerMsg->usrData);
+ break;
+
+ case GSM_AUTOANSWER_TIMER:
+ fsmdef_auto_answer_timeout(timerMsg->usrData);
+ break;
+
+ case GSM_REVERSION_TIMER:
+ fsmdef_reversion_timeout((callid_t)(long)timerMsg->usrData);
+ break;
+
+ case GSM_CAC_FAILURE_TIMER:
+ fsm_cac_process_bw_fail_timer(timerMsg->usrData);
+ break;
+
+ case GSM_DIAL_TIMEOUT_TIMER:
+ dp_dial_timeout(timerMsg->usrData);
+ break;
+
+ case GSM_KPML_INTER_DIGIT_TIMER:
+ kpml_inter_digit_timer_callback(timerMsg->usrData);
+ break;
+ case GSM_KPML_CRITICAL_DIGIT_TIMER:
+ case GSM_KPML_EXTRA_DIGIT_TIMER:
+ break;
+
+ case GSM_KPML_SUBSCRIPTION_TIMER:
+ kpml_subscription_timer_callback(timerMsg->usrData);
+ break;
+
+ case GSM_REQ_PENDING_TIMER:
+ timeout_msg = fsmdef_feature_timer_timeout(
+ CC_FEATURE_REQ_PEND_TIMER_EXP,
+ timerMsg->usrData);
+ break;
+
+ case GSM_RINGBACK_DELAY_TIMER:
+ timeout_msg = fsmdef_feature_timer_timeout(
+ CC_FEATURE_RINGBACK_DELAY_TIMER_EXP,
+ timerMsg->usrData);
+ break;
+ case GSM_FLASH_ONCE_TIMER:
+ if (media_timer_callback != NULL) {
+ (* ((media_timer_callback)))();
+ }
+ break;
+ case GSM_TONE_DURATION_TIMER:
+ lsm_tone_duration_tmr_callback(timerMsg->usrData);
+ break;
+ default:
+ GSM_ERR_MSG(GSM_F_PREFIX"unknown timer %d\n", fname,
+ timerMsg->expiredTimerName);
+ break;
+ }
+
+ /*
+ * If there is a timer message to be processed by state machine,
+ * hands it to GSM state machine here.
+ */
+ if (timeout_msg != NULL) {
+ /* Let state machine handle glare timer expiration */
+ gsm_process_msg(GSM_GSM, timeout_msg);
+ cpr_free(timeout_msg);
+ }
+}
+
+static void
+gsm_init (void)
+{
+ /* Placeholder for any initialization tasks */
+}
+
+void
+gsm_shutdown (void)
+{
+ gsm_initialized = FALSE;
+
+ lsm_shutdown();
+ fsm_shutdown();
+ fim_shutdown();
+ dcsm_shutdown();
+}
+
+void
+gsm_reset (void)
+{
+ dp_reset();
+ lsm_reset();
+ fsmutil_free_all_shown_calls_ci_map();
+}
+
+void
+GSMTask (void *arg)
+{
+ static const char fname[] = "GSMTask";
+ void *msg;
+ phn_syshdr_t *syshdr;
+ boolean release_msg = TRUE;
+
+ /*
+ * Get the GSM message queue handle
+ * A hack until the tasks in irx are
+ * CPRized.
+ */
+ gsm_msg_queue = (cprMsgQueue_t) arg;
+ if (!gsm_msg_queue) {
+ GSM_ERR_MSG(GSM_F_PREFIX"invalid input, exiting\n", fname);
+ return;
+ }
+
+ if (platThreadInit("GSMTask") != 0) {
+ return;
+ }
+ /*
+ * Adjust relative priority of GSM thread.
+ */
+ (void) cprAdjustRelativeThreadPriority(GSM_THREAD_RELATIVE_PRIORITY);
+
+ /*
+ * Initialize all the GSM modules
+ */
+ lsm_init();
+ fsm_init();
+ fim_init();
+ gsm_init();
+ dcsm_init();
+
+ cc_init();
+
+ fsmutil_init_shown_calls_ci_map();
+ /*
+ * On Win32 platform, the random seed is stored per thread; therefore,
+ * each thread needs to seed the random number. It is recommended by
+ * MS to do the following to ensure randomness across application
+ * restarts.
+ */
+ cpr_srand((unsigned int)time(NULL));
+
+ /*
+ * Cache random numbers for SRTP keys
+ */
+ gsmsdp_cache_crypto_keys();
+
+ while (1) {
+
+ release_msg = TRUE;
+
+ msg = cprGetMessage(gsm_msg_queue, TRUE, (void **) &syshdr);
+ if (msg) {
+ switch (syshdr->Cmd) {
+ case TIMER_EXPIRATION:
+ gsm_process_timer_expiration(msg);
+ break;
+
+ case GSM_SIP:
+ case GSM_GSM:
+ release_msg = gsm_process_msg(syshdr->Cmd, msg);
+ break;
+
+ case DP_MSG_INIT_DIALING:
+ case DP_MSG_DIGIT_STR:
+ case DP_MSG_STORE_DIGIT:
+ case DP_MSG_DIGIT:
+ case DP_MSG_DIAL_IMMEDIATE:
+ case DP_MSG_REDIAL:
+ case DP_MSG_ONHOOK:
+ case DP_MSG_OFFHOOK:
+ case DP_MSG_UPDATE:
+ case DP_MSG_DIGIT_TIMER:
+ case DP_MSG_CANCEL_OFFHOOK_TIMER:
+ dp_process_msg(syshdr->Cmd, msg);
+ break;
+
+ case SUB_MSG_B2BCNF_SUBSCRIBE_RESP:
+ case SUB_MSG_B2BCNF_NOTIFY:
+ case SUB_MSG_B2BCNF_TERMINATE:
+ sub_process_b2bcnf_msg(syshdr->Cmd, msg);
+ break;
+
+ case SUB_MSG_FEATURE_SUBSCRIBE_RESP:
+ case SUB_MSG_FEATURE_NOTIFY:
+ case SUB_MSG_FEATURE_TERMINATE:
+ sub_process_feature_msg(syshdr->Cmd, msg);
+ break;
+
+ case SUB_MSG_KPML_SUBSCRIBE:
+ case SUB_MSG_KPML_TERMINATE:
+ case SUB_MSG_KPML_NOTIFY_ACK:
+ case SUB_MSG_KPML_SUBSCRIBE_TIMER:
+ case SUB_MSG_KPML_DIGIT_TIMER:
+ kpml_process_msg(syshdr->Cmd, msg);
+ break;
+
+ case REG_MGR_STATE_CHANGE:
+ gsm_reset();
+ break;
+ case THREAD_UNLOAD:
+ destroy_gsm_thread();
+ break;
+
+ default:
+ GSM_ERR_MSG(GSM_F_PREFIX"Unknown message\n", fname);
+ break;
+ }
+
+ cprReleaseSysHeader(syshdr);
+ if (release_msg == TRUE) {
+ cpr_free(msg);
+ }
+
+ /* Check if there are pending messages for dcsm
+ * if it in the right state perform its operation
+ */
+ dcsm_process_jobs();
+ }
+ }
+}
+
+/**
+ * This function will process SUBSCRIBED feature NOTIFY messages.
+ *
+ * @param[in] msg - pointer to ccsip_sub_not_data_t
+ *
+ * @return none
+ *
+ * @pre (msg != NULL)
+ */
+static void sub_process_b2bcnf_sub_resp (ccsip_sub_not_data_t *msg)
+{
+ static const char fname[] = "sub_process_b2bcnf_sub_resp";
+
+ callid_t call_id = CC_NO_CALL_ID;
+ callid_t other_call_id = CC_NO_CALL_ID;
+ cc_causes_t cause;
+
+ fsmb2bcnf_get_sub_call_id_from_ccb ((fsmcnf_ccb_t *)(msg->request_id),
+ &call_id, &other_call_id);
+
+ if (msg->u.subs_result_data.status_code == 200 ||
+ msg->u.subs_result_data.status_code == 202 ) {
+
+ cause = CC_CAUSE_OK;
+
+ GSM_DEBUG(DEB_F_PREFIX"B2BCNF subs response = OK\n",
+ DEB_F_PREFIX_ARGS(GSM,fname));
+
+ } else {
+
+ GSM_DEBUG(DEB_F_PREFIX"B2BCNF subs response = ERROR\n",
+ DEB_F_PREFIX_ARGS(GSM,fname));
+
+ cause = CC_CAUSE_ERROR;
+ }
+
+ cc_feature_ack(CC_SRC_GSM, call_id, msg->line_id, CC_FEATURE_B2BCONF, NULL, cause);
+}
+
+/**
+ * This function will process b2bcnf feature NOTIFY messages.
+ *
+ * @param[in] cmd - command
+ * @param[in] msg - pointer to ccsip_sub_not_data_t
+ *
+ * @return none
+ *
+ * @pre (msg != NULL)
+ */
+static void sub_process_b2bcnf_msg (uint32_t cmd, void *msg)
+{
+ static const char fname[] = "sub_process_b2bcnf_msg";
+ cc_feature_data_t data;
+ callid_t call_id, other_call_id = CC_NO_CALL_ID;
+
+ fsmb2bcnf_get_sub_call_id_from_ccb((fsmcnf_ccb_t *)((ccsip_sub_not_data_t *)msg)->request_id,
+ &call_id, &other_call_id);
+ switch (cmd) {
+ case SUB_MSG_B2BCNF_SUBSCRIBE_RESP:
+ GSM_DEBUG(DEB_F_PREFIX"B2BCNF subs response\n",
+ DEB_F_PREFIX_ARGS(GSM,fname));
+ sub_process_b2bcnf_sub_resp((ccsip_sub_not_data_t *)msg);
+ break;
+
+ case SUB_MSG_B2BCNF_NOTIFY:
+ GSM_DEBUG(DEB_F_PREFIX"B2BCNF subs notify\n",
+ DEB_F_PREFIX_ARGS(GSM,fname));
+ sub_process_feature_notify((ccsip_sub_not_data_t *)msg, call_id, other_call_id);
+ break;
+ case SUB_MSG_B2BCNF_TERMINATE:
+ /*
+ * This is posted by SIP stack if it is shutting down or rolling over.
+ * if so, notify b2bcnf to cleanup state machine.
+ */
+ GSM_DEBUG(DEB_F_PREFIX"B2BCNF subs terminate\n",
+ DEB_F_PREFIX_ARGS(GSM,fname));
+
+ data.notify.subscription = CC_SUBSCRIPTIONS_REMOTECC;
+ data.notify.method = CC_RCC_METHOD_REFER;
+ data.notify.data.rcc.feature = CC_FEATURE_B2BCONF;
+
+ data.notify.cause = CC_CAUSE_ERROR;
+
+ cc_feature(CC_SRC_GSM, call_id, 0, CC_FEATURE_NOTIFY, &data);
+
+ break;
+ default:
+ GSM_DEBUG(DEB_F_PREFIX"B2BCNF subs unknown event\n",
+ DEB_F_PREFIX_ARGS(GSM,fname));
+ break;
+ }
+}
+
+/**
+ * This function will process SUBSCRIBED feature NOTIFY messages.
+ *
+ * @param[in] cmd - command
+ * @param[in] msg - pointer to ccsip_sub_not_data_t
+ *
+ * @return none
+ *
+ * @pre (msg != NULL)
+ */
+static void sub_process_feature_msg (uint32_t cmd, void *msg)
+{
+ callid_t call_id;
+ cc_feature_ack_t temp_msg;
+
+ switch (cmd) {
+ case SUB_MSG_FEATURE_SUBSCRIBE_RESP:
+ /*
+ * if the response in non-2xx final, we should reset the active feature.
+ */
+ call_id = (callid_t)(((ccsip_sub_not_data_t *)msg)->request_id);
+ if (((ccsip_sub_not_data_t *)msg)->u.subs_result_data.status_code > 299) {
+ memset(&temp_msg, 0, sizeof(temp_msg));
+ temp_msg.msg_id = CC_MSG_FEATURE_ACK;
+ temp_msg.src_id = CC_SRC_GSM;
+ temp_msg.call_id = call_id;
+ fim_process_event((void *)&temp_msg, FALSE);
+ }
+ break;
+ case SUB_MSG_FEATURE_NOTIFY:
+ call_id = (callid_t)(((ccsip_sub_not_data_t *)msg)->request_id);
+ sub_process_feature_notify((ccsip_sub_not_data_t *)msg, call_id,
+ CC_NO_CALL_ID);
+ break;
+ case SUB_MSG_FEATURE_TERMINATE:
+ /*
+ * This is posted by SIP stack if it is shutting down or rolling over.
+ * if so, sip stack already cleaned up the subscription. so do nothing.
+ */
+ break;
+ }
+}
+
+/**
+ * This function will process SUBSCRIBED feature NOTIFY messages.
+ *
+ * @param[in] msg - pointer to ccsip_sub_not_data_t
+ *
+ * @return none
+ *
+ * @pre (msg != NULL)
+ */
+static void sub_process_feature_notify (ccsip_sub_not_data_t *msg, callid_t call_id,
+ callid_t other_call_id)
+{
+ static const char fname[] = "sub_process_feature_notify";
+ ccsip_event_data_t *ev_data;
+ cc_feature_ack_t temp_msg;
+
+
+ /*
+ * send response to NOTIFY.
+ */
+ (void)sub_int_notify_ack(msg->sub_id, SIP_STATUS_SUCCESS, msg->u.notify_ind_data.cseq);
+
+ /*
+ * if the subscription state is terminated, clean up the subscription.
+ */
+ if (msg->u.notify_ind_data.subscription_state == SUBSCRIPTION_STATE_TERMINATED) {
+ /*
+ * post SIPSPI_EV_CC_SUBSCRIPTION_TERMINATED.
+ * do not force SUB/NOT mgr to cleanup SCB immediately, because we may have to handle digest
+ * challenges to terminating SUBSCRIBE sent.
+ */
+ (void)sub_int_subscribe_term(msg->sub_id, FALSE, msg->request_id, CC_SUBSCRIPTIONS_REMOTECC);
+
+ }
+ ev_data = msg->u.notify_ind_data.eventData;
+ msg->u.notify_ind_data.eventData = NULL;
+ if (ev_data == NULL) {
+ GSM_ERR_MSG(DEB_F_PREFIX"No body in the NOTIFY message\n",
+ DEB_F_PREFIX_ARGS(GSM, fname));
+ /*
+ * if (no content & subscription state is TERMINATED
+ * then reset active_feature to NONE.
+ */
+ if (msg->u.notify_ind_data.subscription_state == SUBSCRIPTION_STATE_TERMINATED) {
+ memset(&temp_msg, 0, sizeof(temp_msg));
+ temp_msg.msg_id = CC_MSG_FEATURE_ACK;
+ temp_msg.src_id = CC_SRC_GSM;
+ temp_msg.call_id = call_id;
+ fim_process_event((void *)&temp_msg, FALSE);
+ }
+ return;
+ }
+
+ // other types of event data is not supported as of now.
+ free_event_data(ev_data);
+}
+
+/*
+ * return TRUE if GSM is considered idle,
+ * currently this means lsm is idle
+ * FALSE otherwise.
+ */
+boolean
+gsm_is_idle (void)
+{
+ if (lsm_is_phone_idle()) {
+ return (TRUE);
+ }
+ return (FALSE);
+}
+
+/*
+ * Function: destroy_gsm_thread
+ * Description: shutdown gsm and kill gsm thread
+ * Parameters: none
+ * Returns: none
+ */
+void destroy_gsm_thread()
+{
+ static const char fname[] = "destroy_gsm_thread";
+ DEF_DEBUG(DEB_F_PREFIX"Unloading GSM and destroying GSM thread\n",
+ DEB_F_PREFIX_ARGS(SIP_CC_INIT, fname));
+ gsm_shutdown();
+ dp_shutdown();
+ kpml_shutdown();
+ (void) cprDestroyThread(gsm_thread);
+}
diff --git a/libs/sipcc/core/gsm/gsm_sdp.c b/libs/sipcc/core/gsm/gsm_sdp.c
new file mode 100644
index 0000000000..2f18f474b2
--- /dev/null
+++ b/libs/sipcc/core/gsm/gsm_sdp.c
@@ -0,0 +1,6610 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "cpr_in.h"
+#include "cpr_rand.h"
+#include "cpr_stdlib.h"
+#include "lsm.h"
+#include "fsm.h"
+#include "ccapi.h"
+#include "ccsip_sdp.h"
+#include "sdp.h"
+#include "gsm.h"
+#include "gsm_sdp.h"
+#include "util_string.h"
+#include "rtp_defs.h"
+#include "debug.h"
+#include "dtmf.h"
+#include "prot_configmgr.h"
+#include "dns_utils.h"
+#include "sip_interface_regmgr.h"
+#include "platform_api.h"
+#include "vcm.h"
+//#include "prlog.h"
+#include "plstr.h"
+#include "sdp_private.h"
+
+//TODO Need to place this in a portable location
+#define MULTICAST_START_ADDRESS 0xe1000000
+#define MULTICAST_END_ADDRESS 0xefffffff
+
+/* Only first octet contains codec type */
+#define GET_CODEC_TYPE(a) ((uint8_t)((a) & 0XFF))
+
+#define GSMSDP_SET_MEDIA_DIABLE(media) \
+ (media->src_port = 0)
+
+#define CAST_DEFAULT_BITRATE 320000
+/*
+ * The maximum number of media lines per call. This puts the upper limit
+ * on * the maximum number of media lines per call to resource hogging.
+ * The value of 8 is intended up to 2 audio and 2 video streams with
+ * each stream can offer IPV4 and IPV6 alternate network address type
+ * in ANAT group (RFC-4091).
+ */
+#define GSMSDP_MAX_MLINES_PER_CALL (8)
+
+/*
+ * Permanent number of free media structure elements for media structure
+ * that represents media line in the SDP. The maximum number of elements
+ * is set to equal number of call or LSM_MAX_CALLS. This should be enough
+ * to minimumly allow typical a single audio media stream per call scenario
+ * without using dynamic memory.
+ *
+ * If more media structures are needed than this number, the addition
+ * media structures are allocated from heap and they will be freed back
+ * from heap after thehy are not used. The only time where the heap
+ * is used when phone reaches the maximum call capacity and each one
+ * of the call is using more than one media lines.
+ */
+#define GSMSDP_PERM_MEDIA_ELEMS (LSM_MAX_CALLS)
+
+/*
+ * The permanent free media structure elements use static array.
+ * It is to ensure a low overhead for this a typical single audio call.
+ */
+static fsmdef_media_t gsmsdp_free_media_chunk[GSMSDP_PERM_MEDIA_ELEMS];
+static sll_lite_list_t gsmsdp_free_media_list;
+
+typedef enum {
+ MEDIA_TABLE_GLOBAL,
+ MEDIA_TABLE_SESSION
+} media_table_e;
+
+/* Forward references */
+static cc_causes_t
+gsmsdp_init_local_sdp (const char *peerconnection, cc_sdp_t **sdp_pp);
+
+static void
+gsmsdp_set_media_capability(fsmdef_media_t *media,
+ const cc_media_cap_t *media_cap);
+static fsmdef_media_t *
+gsmsdp_add_media_line(fsmdef_dcb_t *dcb_p, const cc_media_cap_t *media_cap,
+ uint8_t cap_index, uint16_t level,
+ cpr_ip_type addr_type, boolean offer);
+
+
+extern cc_media_cap_table_t g_media_table;
+
+extern boolean g_disable_mass_reg_debug_print;
+/**
+ * A wraper function to return the media capability supported by
+ * the platform and session. This is a convient place if policy
+ * to get the capability table as it applies to the session
+ * updates the media_cap_tbl ptr in dcb
+ *
+ * @param[in]dcb - pointer to the fsmdef_dcb_t
+
+ *
+ * @return - pointer to the the media capability table for session
+ */
+static const cc_media_cap_table_t *gsmsdp_get_media_capability (fsmdef_dcb_t *dcb_p)
+{
+ static const char *fname = "gsmsdp_get_media_capability";
+ int sdpmode = 0;
+
+ if (g_disable_mass_reg_debug_print == FALSE) {
+ GSM_DEBUG(DEB_F_PREFIX"dcb video pref %x\n",
+ DEB_F_PREFIX_ARGS(GSM, fname), dcb_p->video_pref);
+ }
+
+ config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
+
+ if ( dcb_p->media_cap_tbl == NULL ) {
+ dcb_p->media_cap_tbl = (cc_media_cap_table_t*) cpr_malloc(sizeof(cc_media_cap_table_t));
+ if ( dcb_p->media_cap_tbl == NULL ) {
+ GSM_ERR_MSG(GSM_L_C_F_PREFIX"media table malloc failed.\n",
+ dcb_p->line, dcb_p->call_id, fname);
+ return NULL;
+ }
+ }
+
+ *(dcb_p->media_cap_tbl) = g_media_table;
+
+ /*
+ * Turn off two default streams, this is temporary
+ * until we can handle multiple streams properly
+ */
+ if (sdpmode) {
+ dcb_p->media_cap_tbl->cap[CC_AUDIO_1].enabled = TRUE;
+ dcb_p->media_cap_tbl->cap[CC_VIDEO_1].enabled = TRUE;
+ dcb_p->media_cap_tbl->cap[CC_AUDIO_1].support_direction = SDP_DIRECTION_RECVONLY;
+ dcb_p->media_cap_tbl->cap[CC_VIDEO_1].support_direction = SDP_DIRECTION_RECVONLY;
+ dcb_p->media_cap_tbl->cap[CC_DATACHANNEL_1].enabled = TRUE;
+ } else {
+ dcb_p->media_cap_tbl->cap[CC_DATACHANNEL_1].enabled = FALSE;
+
+ if ( dcb_p->video_pref == SDP_DIRECTION_INACTIVE) {
+ // do not enable video
+ dcb_p->media_cap_tbl->cap[CC_VIDEO_1].enabled = FALSE;
+ }
+
+ if ( dcb_p->video_pref == SDP_DIRECTION_RECVONLY ) {
+ if ( dcb_p->media_cap_tbl->cap[CC_VIDEO_1].support_direction == SDP_DIRECTION_SENDRECV ) {
+ dcb_p->media_cap_tbl->cap[CC_VIDEO_1].support_direction = dcb_p->video_pref;
+ }
+
+ if ( dcb_p->media_cap_tbl->cap[CC_VIDEO_1].support_direction == SDP_DIRECTION_SENDONLY ) {
+ dcb_p->media_cap_tbl->cap[CC_VIDEO_1].support_direction = SDP_DIRECTION_INACTIVE;
+ DEF_DEBUG(GSM_L_C_F_PREFIX"video capability disabled to SDP_DIRECTION_INACTIVE from sendonly\n",
+ dcb_p->line, dcb_p->call_id, fname);
+ }
+ } else if ( dcb_p->video_pref == SDP_DIRECTION_SENDONLY ) {
+ if ( dcb_p->media_cap_tbl->cap[CC_VIDEO_1].support_direction == SDP_DIRECTION_SENDRECV ) {
+ dcb_p->media_cap_tbl->cap[CC_VIDEO_1].support_direction = dcb_p->video_pref;
+ }
+
+ if ( dcb_p->media_cap_tbl->cap[CC_VIDEO_1].support_direction == SDP_DIRECTION_RECVONLY ) {
+ dcb_p->media_cap_tbl->cap[CC_VIDEO_1].support_direction = SDP_DIRECTION_INACTIVE;
+ DEF_DEBUG(GSM_L_C_F_PREFIX"video capability disabled to SDP_DIRECTION_INACTIVE from recvonly\n",
+ dcb_p->line, dcb_p->call_id, fname);
+ }
+ } // else if requested is SENDRECV just go by capability
+ }
+
+ return (dcb_p->media_cap_tbl);
+}
+
+/*
+ * Process a single constraint for one media capablity
+ */
+void gsmsdp_process_cap_constraint(cc_media_cap_t *cap,
+ const char *constraint) {
+ /* Check constraint string for values "TRUE" or "FALSE"
+ (currently set in PeerConnectionImpl.cpp, with only
+ two possible hardcoded values).
+ TODO -- The values that constraints can take are
+ fairly narrow and enumerated; they should probably
+ use an enumeration rather than a string. See bug 811360.
+ */
+ if (constraint[0] == 'F') {
+ cap->support_direction &= ~SDP_DIRECTION_FLAG_RECV;
+ } else if (constraint[0] == 'T') {
+ cap->support_direction |= SDP_DIRECTION_FLAG_RECV;
+ }
+}
+
+/*
+ * Process constraints only related to media capabilities., i.e
+ * OfferToReceiveAudio, OfferToReceiveVideo
+ */
+void gsmsdp_process_cap_constraints(fsmdef_dcb_t *dcb,
+ const cc_media_constraints_t* constraints) {
+ int i = 0;
+
+ for (i=0; iconstraint_count; i++) {
+ if (strcmp(constraints_table[OfferToReceiveAudio].name,
+ constraints->constraints[i]->name) == 0) {
+ gsmsdp_process_cap_constraint(&dcb->media_cap_tbl->cap[CC_AUDIO_1],
+ constraints->constraints[i]->value);
+ } else if (strcmp(constraints_table[OfferToReceiveVideo].name,
+ constraints->constraints[i]->name) == 0) {
+ gsmsdp_process_cap_constraint(&dcb->media_cap_tbl->cap[CC_VIDEO_1],
+ constraints->constraints[i]->value);
+ }
+ }
+}
+
+/**
+ * Copy an fsmdef_media_t's payload list to its previous_sdp's payload list
+ *
+ * @param[in]media - pointer to the fsmdef_media_t to update
+ */
+void gsmsdp_copy_payloads_to_previous_sdp (fsmdef_media_t *media)
+{
+ // static const char *fname = "gsmsdp_copy_payloads_to_previous_sdp";
+
+ if ((!media->payloads) && (NULL != media->previous_sdp.payloads))
+ {
+ cpr_free(media->previous_sdp.payloads);
+ media->previous_sdp.payloads = NULL;
+ media->previous_sdp.num_payloads = 0;
+ }
+
+ /* Ensure that there is enough space to hold all the payloads */
+ if (media->num_payloads > media->previous_sdp.num_payloads)
+ {
+ media->previous_sdp.payloads =
+ cpr_realloc(media->previous_sdp.payloads,
+ media->num_payloads * sizeof(vcm_payload_info_t));
+ }
+
+ /* Copy the payloads over */
+ media->previous_sdp.num_payloads = media->num_payloads;
+ memcpy(media->previous_sdp.payloads, media->payloads,
+ media->num_payloads * sizeof(vcm_payload_info_t));
+ media->previous_sdp.num_payloads = media->num_payloads;
+}
+
+/**
+ * Find an entry for the specified codec type in the vcm_payload_info_t
+ * list array.
+ *
+ * @param[in]codec - Codec type to find
+ * @param[in]payload_info - Array of payload info entries
+ * @param[in]num_payload_info - Total number of elements in payload_info
+ * @param[in]instance - Which instance of the codec to find
+ * (e.g., if more than one entry for a codec type)
+ *
+ * @return Pointer to the payload info if found;
+ * NULL when no match is found.
+ */
+vcm_payload_info_t *gsmsdp_find_info_for_codec(rtp_ptype codec,
+ vcm_payload_info_t *payload_info,
+ int num_payload_info,
+ int instance) {
+ int i;
+ for (i = 0; i < num_payload_info; i++) {
+ if (payload_info[i].codec_type == codec)
+ {
+ instance--;
+ if (instance == 0) {
+ return &(payload_info[i]);
+ }
+ }
+ }
+ return NULL;
+}
+
+
+/**
+ * Sets up the media track table
+ *
+ * @param[in]dcb - pointer to the fsmdef_dcb_t
+ *
+ * @return - pointer to the the media track table for session
+ */
+static const cc_media_remote_stream_table_t *gsmsdp_get_media_stream_table (fsmdef_dcb_t *dcb_p)
+{
+ static const char *fname = "gsmsdp_get_media_stream_table";
+ if ( dcb_p->remote_media_stream_tbl == NULL ) {
+ dcb_p->remote_media_stream_tbl = (cc_media_remote_stream_table_t*) cpr_malloc(sizeof(cc_media_remote_stream_table_t));
+ memset(dcb_p->remote_media_stream_tbl, 0, sizeof(cc_media_remote_stream_table_t));
+
+ if ( dcb_p->remote_media_stream_tbl == NULL ) {
+
+ GSM_ERR_MSG(GSM_L_C_F_PREFIX"media track table malloc failed.\n",
+ dcb_p->line, dcb_p->call_id, fname);
+ return NULL;
+ }
+ }
+
+ return (dcb_p->remote_media_stream_tbl);
+}
+
+/**
+ * The function creates a free media structure elements list. The
+ * free list is global for all calls. The function must be called once
+ * during GSM initializtion.
+ *
+ * @param None.
+ *
+ * @return TRUE - free media structure list is created
+ * successfully.
+ * FALSE - failed to create free media structure
+ * list.
+ */
+boolean
+gsmsdp_create_free_media_list (void)
+{
+ uint32_t i;
+ fsmdef_media_t *media;
+
+ /* initialize free media_list structure */
+ (void)sll_lite_init(&gsmsdp_free_media_list);
+
+ /*
+ * Populate the free list:
+ * Break the entire chunk into multiple free elements and link them
+ * onto to the free media list.
+ */
+ media = &gsmsdp_free_media_chunk[0]; /* first element */
+ for (i = 0; i < GSMSDP_PERM_MEDIA_ELEMS; i++) {
+ (void)sll_lite_link_head(&gsmsdp_free_media_list,
+ (sll_lite_node_t *)media);
+ media = media + 1; /* next element */
+ }
+
+ /* Successful create media free list */
+ return (TRUE);
+}
+
+/**
+ * The function destroys the free media structure list. It should be
+ * call during GSM shutdown.
+ *
+ * @param None.
+ *
+ * @return None.
+ */
+void
+gsmsdp_destroy_free_media_list (void)
+{
+ /*
+ * Although the free chunk is not allocated but,
+ * NULL out the free list header to indicate that the
+ * there is not thing from the free chunk.
+ */
+ (void)sll_lite_init(&gsmsdp_free_media_list);
+}
+
+/**
+ * The function allocates a media structure. The function
+ * attempts to obtain a free media structure from the free media
+ * structure list first. If free list is empty then the media structure
+ * is allocated from a memory pool.
+ *
+ * @param None.
+ *
+ * @return pointer to the fsmdef_media_t if successful or
+ * NULL when there is no free media structure
+ * is available.
+ */
+static fsmdef_media_t *
+gsmsdp_alloc_media (void)
+{
+ static const char fname[] = "gsmsdp_alloc_media";
+ fsmdef_media_t *media = NULL;
+
+ /* Get a media element from the free list */
+ media = (fsmdef_media_t *)sll_lite_unlink_head(&gsmsdp_free_media_list);
+ if (media == NULL) {
+ /* no free element from cache, allocate it from the pool */
+ media = cpr_malloc(sizeof(fsmdef_media_t));
+ GSM_DEBUG(DEB_F_PREFIX"get from dynamic pool, media %x\n",
+ DEB_F_PREFIX_ARGS(GSM, fname), media);
+ }
+ return (media);
+}
+
+/**
+ * The function frees a media structure back to the free list or
+ * heap. If the media structure is from the free list then it
+ * is put back to the free list otherwise it will be freed
+ * back to the dynamic pool.
+ *
+ * @param[in]media - pointer to fsmdef_media_t to free back to
+ * free list.
+ *
+ * @return pointer to the fsmdef_media_t if successful
+ * NULL when there is no free media structure
+ * is available.
+ */
+static void
+gsmsdp_free_media (fsmdef_media_t *media)
+{
+ static const char fname[] = "gsmsdp_free_media";
+
+ if (media == NULL) {
+ return;
+ }
+
+ if (media-> video != NULL ) {
+ vcmFreeMediaPtr(media->video);
+ }
+
+ if(media->payloads != NULL) {
+ cpr_free(media->payloads);
+ media->payloads = NULL;
+ media->num_payloads = 0;
+ }
+ /*
+ * Check to see if the element is part of the
+ * free chunk space.
+ */
+ if ((media >= &gsmsdp_free_media_chunk[0]) &&
+ (media <= &gsmsdp_free_media_chunk[GSMSDP_PERM_MEDIA_ELEMS-1])) {
+ /* the element is part of free chunk, put it back to the list */
+ (void)sll_lite_link_head(&gsmsdp_free_media_list,
+ (sll_lite_node_t *)media);
+ } else {
+ /* this element is from the dynamic pool, free it back */
+ cpr_free(media);
+ GSM_DEBUG(DEB_F_PREFIX"free media 0x%x to dynamic pool\n",
+ DEB_F_PREFIX_ARGS(GSM, fname), media);
+ }
+}
+
+/**
+ * Initialize the media entry. The function initializes media
+ * entry.
+ *
+ * @param[in]media - pointer to fsmdef_media_t of the media entry to be
+ * initialized.
+ *
+ * @return none
+ *
+ * @pre (media not_eq NULL)
+ */
+static void
+gsmsdp_init_media (fsmdef_media_t *media)
+{
+ media->refid = CC_NO_MEDIA_REF_ID;
+ media->type = SDP_MEDIA_INVALID; /* invalid (free entry) */
+ media->packetization_period = ATTR_PTIME;
+ media->max_packetization_period = ATTR_MAXPTIME;
+ media->mode = (uint16_t)vcmGetILBCMode();
+ media->vad = VCM_VAD_OFF;
+ /* Default to audio codec */
+ media->level = 0;
+ media->dest_port = 0;
+ media->dest_addr = ip_addr_invalid;
+ media->is_multicast = FALSE;
+ media->multicast_port = 0;
+ media->avt_payload_type = RTP_NONE;
+ media->src_port = 0;
+ media->src_addr = ip_addr_invalid;
+ media->rcv_chan = FALSE;
+ media->xmit_chan = FALSE;
+
+ media->direction = SDP_DIRECTION_INACTIVE;
+ media->direction_set = FALSE;
+ media->transport = SDP_TRANSPORT_INVALID;
+ media->tias_bw = SDP_INVALID_VALUE;
+ media->profile_level = 0;
+
+ media->previous_sdp.avt_payload_type = RTP_NONE;
+ media->previous_sdp.dest_addr = ip_addr_invalid;
+ media->previous_sdp.dest_port = 0;
+ media->previous_sdp.direction = SDP_DIRECTION_INACTIVE;
+ media->previous_sdp.packetization_period = media->packetization_period;
+ media->previous_sdp.max_packetization_period = media->max_packetization_period;
+ media->previous_sdp.payloads = NULL;
+ media->previous_sdp.num_payloads = 0;
+ media->previous_sdp.tias_bw = SDP_INVALID_VALUE;
+ media->previous_sdp.profile_level = 0;
+
+ media->hold = FSM_HOLD_NONE;
+ media->flags = 0; /* clear all flags */
+ media->cap_index = CC_MAX_MEDIA_CAP; /* max is invalid value */
+ media->video = NULL;
+ media->candidate_ct = 0;
+ media->rtcp_mux = FALSE;
+ media->protocol = NULL;
+ media->payloads = NULL;
+ media->num_payloads = 0;
+}
+
+/**
+ *
+ * Returns a pointer to a new the fsmdef_media_t for a given dcb.
+ * The default media parameters will be intialized for the known or
+ * supported media types. The new media is also added to the media list
+ * in the dcb.
+ *
+ * @param[in]dcb_p - pointer to the fsmdef_dcb_t
+ * @param[in]media_type - sdp_media_e.
+ * @param[in]level - uint16_t for media line level.
+ *
+ * @return pointer to the fsmdef_media_t of the corresponding
+ * media entry in the dcb.
+ * @pre (dcb not_eq NULL)
+ */
+static fsmdef_media_t *
+gsmsdp_get_new_media (fsmdef_dcb_t *dcb_p, sdp_media_e media_type,
+ uint16_t level)
+{
+ static const char fname[] = "gsmsdp_get_new_media";
+ fsmdef_media_t *media;
+ static media_refid_t media_refid = CC_NO_MEDIA_REF_ID;
+ sll_lite_return_e sll_lite_ret;
+
+ /* check to ensue we do not handle too many media lines */
+ if (GSMSDP_MEDIA_COUNT(dcb_p) >= GSMSDP_MAX_MLINES_PER_CALL) {
+ GSM_ERR_MSG(GSM_L_C_F_PREFIX"exceeding media lines per call\n",
+ dcb_p->line, dcb_p->call_id, fname);
+ return (NULL);
+ }
+
+ /* allocate new media entry */
+ media = gsmsdp_alloc_media();
+ if (media != NULL) {
+ /* initialize the media entry */
+ gsmsdp_init_media(media);
+
+ /* assigned media reference id */
+ if (++media_refid == CC_NO_MEDIA_REF_ID) {
+ media_refid = 1;
+ }
+ media->refid = media_refid;
+ media->type = media_type;
+ media->level = level;
+
+ /* append the media to the active list */
+ sll_lite_ret = sll_lite_link_tail(&dcb_p->media_list,
+ (sll_lite_node_t *)media);
+ if (sll_lite_ret != SLL_LITE_RET_SUCCESS) {
+ /* fails to put the new media entry on to the list */
+ GSM_ERR_MSG(GSM_L_C_F_PREFIX"error %d when add media to list\n",
+ dcb_p->line, dcb_p->call_id, fname, sll_lite_ret);
+ gsmsdp_free_media(media);
+ media = NULL;
+ }
+ }
+ return (media);
+}
+
+/**
+ * The function removes the media entry from the list of a given call and
+ * then deallocates the media entry.
+ *
+ * @param[in]dcb - pointer to fsmdef_def_t for the dcb whose
+ * media to be removed from.
+ * @param[in]media - pointer to fsmdef_media_t for the media
+ * entry to be removed.
+ *
+ * @return none
+ *
+ * @pre (dcb not_eq NULL)
+ */
+static void gsmsdp_remove_media (fsmdef_dcb_t *dcb_p, fsmdef_media_t *media)
+{
+ static const char fname[] = "gsmsdp_remove_media";
+ cc_action_data_t data;
+
+ if (media == NULL) {
+ GSM_ERR_MSG(GSM_L_C_F_PREFIX"removing NULL media\n",
+ dcb_p->line, dcb_p->call_id, fname);
+ return;
+ }
+
+ if (media->rcv_chan || media->xmit_chan) {
+ /* stop media, if it is opened */
+ data.stop_media.media_refid = media->refid;
+ (void)cc_call_action(dcb_p->call_id, dcb_p->line, CC_ACTION_STOP_MEDIA,
+ &data);
+ }
+ /* remove this media off the list */
+ (void)sll_lite_remove(&dcb_p->media_list, (sll_lite_node_t *)media);
+
+ /* Release the port */
+ vcmRxReleasePort(media->cap_index, dcb_p->group_id, media->refid,
+ lsm_get_ms_ui_call_handle(dcb_p->line, dcb_p->call_id, CC_NO_CALL_ID), media->src_port);
+
+ /* free media structure */
+ gsmsdp_free_media(media);
+}
+
+/**
+ * The function performs cleaning media list of a given call. It walks
+ * through the list and deallocates each media entries.
+ *
+ * @param[in]dcb - pointer to fsmdef_def_t for the dcb whose
+ * media list to be cleaned.
+ *
+ * @return none
+ *
+ * @pre (dcb not_eq NULL)
+ */
+void gsmsdp_clean_media_list (fsmdef_dcb_t *dcb_p)
+{
+ fsmdef_media_t *media = NULL;
+
+ while (TRUE) {
+ /* unlink head and free the media */
+ media = (fsmdef_media_t *)sll_lite_unlink_head(&dcb_p->media_list);
+ if (media != NULL) {
+ gsmsdp_free_media(media);
+ } else {
+ break;
+ }
+ }
+}
+
+/**
+ *
+ * The function is used for per call media list initialization. It is
+ * an interface function to other module for initializing the media list
+ * used during a call.
+ *
+ * @param[in]dcb_p - pointer to the fsmdef_dcb_t where the media list
+ * will be attached to.
+ *
+ * @return None.
+ * @pre (dcb not_eq NULL)
+ */
+void gsmsdp_init_media_list (fsmdef_dcb_t *dcb_p)
+{
+ const cc_media_cap_table_t *media_cap_tbl;
+ const cc_media_remote_stream_table_t *media_track_tbl;
+ const char fname[] = "gsmsdp_init_media_list";
+
+ /* do the actual media element list initialization */
+ (void)sll_lite_init(&dcb_p->media_list);
+
+ media_cap_tbl = gsmsdp_get_media_capability(dcb_p);
+
+ if (media_cap_tbl == NULL) {
+ GSM_ERR_MSG(GSM_L_C_F_PREFIX"no media capbility available\n",
+ dcb_p->line, dcb_p->call_id, fname);
+ }
+
+ media_track_tbl = gsmsdp_get_media_stream_table(dcb_p);
+
+ if (media_track_tbl == NULL) {
+ GSM_ERR_MSG(GSM_L_C_F_PREFIX"no media tracks available\n",
+ dcb_p->line, dcb_p->call_id, fname);
+ }
+}
+
+/**
+ *
+ * Returns a pointer to the fsmdef_media_t in the dcb for the
+ * correspoinding media level in the SDP.
+ *
+ * @param[in]dcb_p - pointer to the fsmdef_dcb_t
+ * @param[in]level - uint16_t for media line level.
+ *
+ * @return pointer to the fsmdef_media_t of the corresponding
+ * media entry in the dcb.
+ * @pre (dcb not_eq NULL)
+ */
+static fsmdef_media_t *
+gsmsdp_find_media_by_level (fsmdef_dcb_t *dcb_p, uint16_t level)
+{
+ fsmdef_media_t *media = NULL;
+
+ /*
+ * search the all entries that has a valid media and matches
+ * the level.
+ */
+ GSMSDP_FOR_ALL_MEDIA(media, dcb_p) {
+ if (media->level == level) {
+ /* found a match */
+ return (media);
+ }
+ }
+ return (NULL);
+}
+
+/**
+ *
+ * Returns a pointer to the fsmdef_media_t in the dcb for the
+ * correspoinding reference ID.
+ *
+ * @param[in]dcb_p - pointer to the fsmdef_dcb_t
+ * @param[in]refid - media reference ID to look for.
+ *
+ * @return pointer to the fsmdef_media_t of the corresponding
+ * media entry in the dcb.
+ * @pre (dcb not_eq NULL)
+ */
+fsmdef_media_t *
+gsmsdp_find_media_by_refid (fsmdef_dcb_t *dcb_p, media_refid_t refid)
+{
+ fsmdef_media_t *media = NULL;
+
+ /*
+ * search the all entries that has a valid media and matches
+ * the reference ID.
+ */
+ GSMSDP_FOR_ALL_MEDIA(media, dcb_p) {
+ if (media->refid == refid) {
+ /* found a match */
+ return (media);
+ }
+ }
+ return (NULL);
+}
+
+/**
+ *
+ * Returns a pointer to the fsmdef_media_t in the dcb for the
+ * correspoinding capability index.
+ *
+ * @param[in]dcb_p - pointer to the fsmdef_dcb_t
+ * @param[in]cap_index - capability table index.
+ *
+ * @return pointer to the fsmdef_media_t of the corresponding
+ * media entry in the dcb.
+ * @pre (dcb not_eq NULL)
+ */
+static fsmdef_media_t *
+gsmsdp_find_media_by_cap_index (fsmdef_dcb_t *dcb_p, uint8_t cap_index)
+{
+ fsmdef_media_t *media = NULL;
+
+ /*
+ * search the all entries that has a valid media and matches
+ * the reference ID.
+ */
+ GSMSDP_FOR_ALL_MEDIA(media, dcb_p) {
+ if (media->cap_index == cap_index) {
+ /* found a match */
+ return (media);
+ }
+ }
+ return (NULL);
+
+}
+
+/**
+ *
+ * Returns a pointer to the fsmdef_media_t in the dcb for the
+ * first audio type in the SDP.
+ *
+ * @param[in]dcb_p - pointer to the fsmdef_dcb_t.
+ *
+ * @return pointer to the fsmdef_media_t of the corresponding
+ * media entry in the dcb.
+ * @pre (dcb not_eq NULL)
+ */
+fsmdef_media_t *gsmsdp_find_audio_media (fsmdef_dcb_t *dcb_p)
+{
+ fsmdef_media_t *media = NULL;
+
+ /*
+ * search the all entries that has a valid media and matches
+ * SDP_MEDIA_AUDIO type.
+ */
+ GSMSDP_FOR_ALL_MEDIA(media, dcb_p) {
+ if (media->type == SDP_MEDIA_AUDIO) {
+ /* found a match */
+ return (media);
+ }
+ }
+ return (NULL);
+}
+
+/**
+ *
+ * The function finds an unused media line given type.
+ *
+ * @param[in]sdp - void pointer of thd SDP libray handle.
+ * @param[in]media_type - media type of the unused line.
+ *
+ * @return level (line) of the unused one if found or
+ * 0 if there is no unused one found.
+ */
+static uint16_t
+gsmsdp_find_unused_media_line_with_type (void *sdp, sdp_media_e media_type)
+{
+ uint16_t num_m_lines, level;
+ int32_t port;
+
+ num_m_lines = sdp_get_num_media_lines(sdp);
+ for (level = 1; level <= num_m_lines; level++) {
+ port = sdp_get_media_portnum(sdp, level);
+ if (port == 0) {
+ /* This slot is not used, check the type */
+ if (sdp_get_media_type(sdp, level) == media_type) {
+ /* Found an empty slot that has the same media type */
+ return (level);
+ }
+ }
+ }
+ /* no unused media line of the given type found */
+ return (0);
+}
+
+/**
+ *
+ * The function returns the media cap entry pointer to the caller based
+ * on the index.
+ *
+ * @param[in]cap_index - uint8_t for index of the media cap table.
+ *
+ * @return pointer to the media cap entry if one is available.
+ * NULL if none is available.
+ *
+ */
+static const cc_media_cap_t *
+gsmsdp_get_media_cap_entry_by_index (uint8_t cap_index, fsmdef_dcb_t *dcb_p)
+{
+ const cc_media_cap_table_t *media_cap_tbl;
+
+ media_cap_tbl = dcb_p->media_cap_tbl;
+
+ if (media_cap_tbl == NULL) {
+ return (NULL);
+ }
+
+ if (cap_index >= CC_MAX_MEDIA_CAP) {
+ return (NULL);
+ }
+ return (&media_cap_tbl->cap[cap_index]);
+}
+
+/**
+ *
+ * Returns a pointer to the fsmdef_media_t in the dcb for the
+ * corresponding media line. It looks for another media line
+ * with the same type and cap_index but different level
+ *
+ * @param[in]dcb_p - pointer to the fsmdef_dcb_t
+ * @param[in]media - current media level.
+ *
+ * @return pointer to the fsmdef_media_t of the corresponding
+ * media entry in the dcb.
+ * @pre (dcb not_eq NULL)
+ */
+fsmdef_media_t *
+gsmsdp_find_anat_pair (fsmdef_dcb_t *dcb_p, fsmdef_media_t *media)
+{
+ fsmdef_media_t *searched_media = NULL;
+
+ /*
+ * search the all entries that has a the same capability index
+ * but at a different level. The only time that this is true is
+ * both media are in the same ANAT group.
+ */
+ GSMSDP_FOR_ALL_MEDIA(searched_media, dcb_p) {
+ if ((searched_media->cap_index == media->cap_index) &&
+ (searched_media->level != media->level)) {
+ /* found a match */
+ return (searched_media);
+ }
+ }
+ return (NULL);
+}
+
+/**
+ *
+ * The function queries platform to see if the platform is capable
+ * of handle mixing additional media or not.
+ *
+ * P2: This may go away when integrate with the platform.
+ *
+ * @param[in]dcb_p - pointer to the fsmdef_dcb_t structure.
+ * @param[in]media_type - media type to be mixed.
+ *
+ * @return TRUE the media can be mixed.
+ * FALSE the media can not be mixed
+ *
+ * @pre (dcb_p not_eq NULL)
+ */
+static boolean
+gsmsdp_platform_addition_mix (fsmdef_dcb_t *dcb_p, sdp_media_e media_type)
+{
+ return (FALSE);
+}
+
+
+/**
+ *
+ * The function updates the local time stamp during SDP offer/answer
+ * processing.
+ *
+ * @param[in]dcb_p - pointer to the fsmdef_dcb_t
+ * @param[in]offer - boolean indicates this is procssing an offered
+ * SDP
+ * @param[in]initial_offer - boolean indicates this is processin an
+ * initial offered SDP.
+ *
+ * @return none.
+ * @pre (dcb not_eq NULL)
+ */
+static void
+gsmsdp_update_local_time_stamp (fsmdef_dcb_t *dcb_p, boolean offer,
+ boolean initial_offer)
+{
+ const char fname[] = "gsmsdp_update_local_time_stamp";
+ void *local_sdp_p;
+ void *remote_sdp_p;
+
+ local_sdp_p = dcb_p->sdp->src_sdp;
+ remote_sdp_p = dcb_p->sdp->dest_sdp;
+
+ /*
+ * If we are processing an offer sdp, need to set the
+ * start time and stop time based on the remote SDP
+ */
+ if (initial_offer) {
+ /*
+ * Per RFC3264, time description of answer must equal that
+ * of the offer.
+ */
+ (void) sdp_set_time_start(local_sdp_p,
+ sdp_get_time_start(remote_sdp_p));
+ (void) sdp_set_time_stop(local_sdp_p, sdp_get_time_stop(remote_sdp_p));
+ } else if (offer) {
+ /*
+ * Set t= line based on remote SDP
+ */
+ if (sdp_timespec_valid(remote_sdp_p) != TRUE) {
+ GSM_DEBUG(DEB_L_C_F_PREFIX"\nTimespec is invalid.\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname));
+ (void) sdp_set_time_start(local_sdp_p, "0");
+ (void) sdp_set_time_stop(local_sdp_p, "0");
+ } else {
+ if (sdp_get_time_start(local_sdp_p) !=
+ sdp_get_time_start(remote_sdp_p)) {
+ (void) sdp_set_time_start(local_sdp_p,
+ sdp_get_time_start(remote_sdp_p));
+ }
+ if (sdp_get_time_stop(local_sdp_p) !=
+ sdp_get_time_stop(remote_sdp_p)) {
+ (void) sdp_set_time_stop(local_sdp_p,
+ sdp_get_time_stop(remote_sdp_p));
+ }
+ }
+ }
+}
+
+/**
+ *
+ * The function gets the local source address address and puts it into
+ * the media entry.
+ *
+ * @param[in]media - pointer to fsmdef_media_t structure to
+ * get the local address into.
+ *
+ * @return none.
+ * @pre (media not_eq NULL)
+ */
+static void
+gsmsdp_get_local_source_v4_address (fsmdef_media_t *media)
+{
+ int nat_enable = 0;
+ char curr_media_ip[MAX_IPADDR_STR_LEN];
+ cpr_ip_addr_t addr;
+ const char fname[] = "gsmsdp_get_local_source_v4_address";
+
+ /*
+ * Get device address.
+ */;
+ config_get_value(CFGID_NAT_ENABLE, &nat_enable, sizeof(nat_enable));
+ if (nat_enable == 0) {
+ init_empty_str(curr_media_ip);
+ config_get_value(CFGID_MEDIA_IP_ADDR, curr_media_ip,
+ MAX_IPADDR_STR_LEN);
+ if (is_empty_str(curr_media_ip) == FALSE) {
+
+ str2ip(curr_media_ip, &addr);
+ util_ntohl(&addr, &addr);
+ if (util_check_if_ip_valid(&media->src_addr) == FALSE) {
+ // Update the media Src address only if it is invalid
+ media->src_addr = addr;
+ GSM_ERR_MSG("%s: Update IP %s", fname, curr_media_ip);
+ }
+ } else {
+ sip_config_get_net_device_ipaddr(&media->src_addr);
+ }
+ } else {
+ sip_config_get_nat_ipaddr(&media->src_addr);
+ }
+}
+
+/*
+ *
+ * The function gets the local source address address and puts it into
+ * the media entry.
+ *
+ * @param[in]media - pointer to fsmdef_media_t structure to
+ * get the local address into.
+ *
+ * @return none.
+ * @pre (media not_eq NULL)
+ */
+static void
+gsmsdp_get_local_source_v6_address (fsmdef_media_t *media)
+{
+ int nat_enable = 0;
+
+ /*
+ * Get device address.
+ */
+ config_get_value(CFGID_NAT_ENABLE, &nat_enable, sizeof(nat_enable));
+ if (nat_enable == 0) {
+ sip_config_get_net_ipv6_device_ipaddr(&media->src_addr);
+ } else {
+ sip_config_get_nat_ipaddr(&media->src_addr);
+ }
+}
+
+/**
+ * Set the connection address into the SDP.
+ *
+ * @param[in]sdp_p - pointer to SDP (type void)
+ * @param[in]level - media level or line.
+ * @param[in]addr - string representation of IP address.
+ * Assumed to be IPV6 if larger than 15.
+ *
+ * @return none.
+ * @pre (sdp_p not_eq NULL) and (addr not_eq NULL)
+ *
+ */
+static void
+gsmsdp_set_connection_address (void *sdp_p, uint16_t level, char *addr)
+{
+ /*
+ * c= line
+ */
+
+ (void) sdp_set_conn_nettype(sdp_p, level, SDP_NT_INTERNET);
+
+ if (addr && (strlen(addr) > strlen("123.123.123.123")))
+ {
+ // Long IP address, must be IPV6
+ (void) sdp_set_conn_addrtype(sdp_p, level, SDP_AT_IP6);
+ }
+ else
+ {
+ (void) sdp_set_conn_addrtype(sdp_p, level, SDP_AT_IP4);
+ }
+
+ (void) sdp_set_conn_address(sdp_p, level, addr);
+}
+
+/*
+ * gsmsdp_set_2543_hold_sdp
+ *
+ * Description:
+ *
+ * Manipulates the local SDP of the specified DCB to indicate hold
+ * to the far end using 2543 style signaling.
+ *
+ * Parameters:
+ *
+ * dcb_p - Pointer to the DCB whose SDP is to be manipulated.
+ *
+ */
+static void
+gsmsdp_set_2543_hold_sdp (fsmdef_dcb_t *dcb_p, uint16 level)
+{
+ (void) sdp_set_conn_nettype(dcb_p->sdp->src_sdp, level, SDP_NT_INTERNET);
+ (void) sdp_set_conn_addrtype(dcb_p->sdp->src_sdp, level, SDP_AT_IP4);
+ (void) sdp_set_conn_address(dcb_p->sdp->src_sdp, level, "0.0.0.0");
+}
+
+
+/*
+ * gsmsdp_set_video_media_attributes
+ *
+ * Description:
+ *
+ * Add the specified video media format to the SDP.
+ *
+ * Parameters:
+ *
+ * media_type - The media type (format) to add to the specified SDP.
+ * sdp_p - Pointer to the SDP the media attribute is to be added to.
+ * level - The media level of the SDP where the media attribute is to be added.
+ * payload_number - AVT payload type if the media attribute being added is
+ * RTP_AVT.
+ *
+ */
+static void
+gsmsdp_set_video_media_attributes (uint32_t media_type, void *cc_sdp_p, uint16_t level,
+ uint16_t payload_number)
+{
+ uint16_t a_inst;
+ void *sdp_p = ((cc_sdp_t*)cc_sdp_p)->src_sdp;
+
+ switch (media_type) {
+ case RTP_H263:
+ case RTP_H264_P0:
+ case RTP_H264_P1:
+ case RTP_VP8:
+ /*
+ * add a=rtpmap line
+ */
+ if (sdp_add_new_attr(sdp_p, level, 0, SDP_ATTR_RTPMAP, &a_inst)
+ != SDP_SUCCESS) {
+ return;
+ }
+
+ (void) sdp_attr_set_rtpmap_payload_type(sdp_p, level, 0, a_inst,
+ payload_number);
+
+ switch (media_type) {
+ case RTP_H263:
+ (void) sdp_attr_set_rtpmap_encname(sdp_p, level, 0, a_inst,
+ SIPSDP_ATTR_ENCNAME_H263v2);
+ (void) sdp_attr_set_rtpmap_clockrate(sdp_p, level, 0, a_inst,
+ RTPMAP_VIDEO_CLOCKRATE);
+ break;
+ case RTP_H264_P0:
+ case RTP_H264_P1:
+ (void) sdp_attr_set_rtpmap_encname(sdp_p, level, 0, a_inst,
+ SIPSDP_ATTR_ENCNAME_H264);
+ (void) sdp_attr_set_rtpmap_clockrate(sdp_p, level, 0, a_inst,
+ RTPMAP_VIDEO_CLOCKRATE);
+ break;
+ case RTP_VP8:
+ (void) sdp_attr_set_rtpmap_encname(sdp_p, level, 0, a_inst,
+ SIPSDP_ATTR_ENCNAME_VP8);
+ (void) sdp_attr_set_rtpmap_clockrate(sdp_p, level, 0, a_inst,
+ RTPMAP_VIDEO_CLOCKRATE);
+ break;
+ }
+ GSM_DEBUG("gsmsdp_set_video_media_attributes- populate attribs %d\n", payload_number );
+
+ vcmPopulateAttribs(cc_sdp_p, level, media_type, payload_number, FALSE);
+
+ break;
+
+ default:
+ break;
+ }
+}
+
+/*
+ * gsmsdp_set_media_attributes
+ *
+ * Description:
+ *
+ * Add the specified media format to the SDP.
+ *
+ * Parameters:
+ *
+ * media_type - The media type (format) to add to the specified SDP.
+ * sdp_p - Pointer to the SDP the media attribute is to be added to.
+ * level - The media level of the SDP where the media attribute is to be added.
+ * payload_number - AVT payload type if the media attribute being added is
+ * RTP_AVT.
+ *
+ */
+static void
+gsmsdp_set_media_attributes (uint32_t media_type, void *sdp_p, uint16_t level,
+ uint16_t payload_number)
+{
+ uint16_t a_inst, a_inst2, a_inst3, a_inst4;
+ int maxavbitrate = 0;
+ int maxcodedaudiobw = 0;
+ int usedtx = 0;
+ int stereo = 0;
+ int useinbandfec = 0;
+ int cbr = 0;
+ int maxptime = 0;
+
+
+ config_get_value(CFGID_MAXAVBITRATE, &maxavbitrate, sizeof(maxavbitrate));
+ config_get_value(CFGID_MAXCODEDAUDIOBW, &maxcodedaudiobw, sizeof(maxcodedaudiobw));
+ config_get_value(CFGID_USEDTX, &usedtx, sizeof(usedtx));
+ config_get_value(CFGID_STEREO, &stereo, sizeof(stereo));
+ config_get_value(CFGID_USEINBANDFEC, &useinbandfec, sizeof(useinbandfec));
+ config_get_value(CFGID_CBR, &cbr, sizeof(cbr));
+ config_get_value(CFGID_MAXPTIME, &maxptime, sizeof(maxptime));
+
+
+
+ switch (media_type) {
+ case RTP_PCMU: // type 0
+ case RTP_PCMA: // type 8
+ case RTP_G729: // type 18
+ case RTP_G722: // type 9
+ case RTP_ILBC:
+ case RTP_L16:
+ case RTP_ISAC:
+ case RTP_OPUS:
+ /*
+ * add a=rtpmap line
+ */
+ if (sdp_add_new_attr(sdp_p, level, 0, SDP_ATTR_RTPMAP, &a_inst)
+ != SDP_SUCCESS) {
+ return;
+ }
+
+ (void) sdp_attr_set_rtpmap_payload_type(sdp_p, level, 0, a_inst,
+ payload_number);
+
+ switch (media_type) {
+ case RTP_PCMU:
+ (void) sdp_attr_set_rtpmap_encname(sdp_p, level, 0, a_inst,
+ SIPSDP_ATTR_ENCNAME_PCMU);
+ (void) sdp_attr_set_rtpmap_clockrate(sdp_p, level, 0, a_inst,
+ RTPMAP_CLOCKRATE);
+ break;
+ case RTP_PCMA:
+ (void) sdp_attr_set_rtpmap_encname(sdp_p, level, 0, a_inst,
+ SIPSDP_ATTR_ENCNAME_PCMA);
+ (void) sdp_attr_set_rtpmap_clockrate(sdp_p, level, 0, a_inst,
+ RTPMAP_CLOCKRATE);
+ break;
+ case RTP_G729:
+ {
+
+ (void) sdp_attr_set_rtpmap_encname(sdp_p, level, 0, a_inst,
+ SIPSDP_ATTR_ENCNAME_G729);
+ if (sdp_add_new_attr(sdp_p, level, 0, SDP_ATTR_FMTP, &a_inst2)
+ != SDP_SUCCESS) {
+ return;
+ }
+ (void) sdp_attr_set_fmtp_payload_type(sdp_p, level, 0, a_inst2,
+ payload_number);
+ (void) sdp_attr_set_fmtp_annexb(sdp_p, level, 0, a_inst2, FALSE);
+ (void) sdp_attr_set_rtpmap_clockrate(sdp_p, level, 0, a_inst,
+ RTPMAP_CLOCKRATE);
+ }
+ break;
+
+ case RTP_G722:
+ (void) sdp_attr_set_rtpmap_encname(sdp_p, level, 0, a_inst,
+ SIPSDP_ATTR_ENCNAME_G722);
+ (void) sdp_attr_set_rtpmap_clockrate(sdp_p, level, 0, a_inst,
+ RTPMAP_CLOCKRATE);
+ break;
+
+ case RTP_L16:
+ (void) sdp_attr_set_rtpmap_encname(sdp_p, level, 0, a_inst,
+ SIPSDP_ATTR_ENCNAME_L16_256K);
+
+ (void) sdp_attr_set_rtpmap_clockrate(sdp_p, level, 0, a_inst,
+ RTPMAP_L16_CLOCKRATE);
+ break;
+
+ case RTP_ILBC:
+ (void) sdp_attr_set_rtpmap_encname(sdp_p, level, 0, a_inst,
+ SIPSDP_ATTR_ENCNAME_ILBC);
+ if (sdp_add_new_attr(sdp_p, level, 0, SDP_ATTR_FMTP, &a_inst2)
+ != SDP_SUCCESS) {
+ return;
+ }
+ (void) sdp_attr_set_fmtp_payload_type(sdp_p, level, 0, a_inst2,
+ payload_number);
+ (void) sdp_attr_set_fmtp_mode(sdp_p, level, 0, a_inst2, vcmGetILBCMode());
+
+ (void) sdp_attr_set_rtpmap_clockrate(sdp_p, level, 0, a_inst,
+ RTPMAP_CLOCKRATE);
+ break;
+
+ case RTP_ISAC:
+ (void) sdp_attr_set_rtpmap_encname(sdp_p, level, 0, a_inst,
+ SIPSDP_ATTR_ENCNAME_ISAC);
+
+ (void) sdp_attr_set_rtpmap_clockrate(sdp_p, level, 0, a_inst,
+ RTPMAP_ISAC_CLOCKRATE);
+ break;
+
+ case RTP_OPUS:
+ (void) sdp_attr_set_rtpmap_encname(sdp_p, level, 0, a_inst,
+ SIPSDP_ATTR_ENCNAME_OPUS);
+
+ (void) sdp_attr_set_rtpmap_clockrate(sdp_p, level, 0, a_inst,
+ RTPMAP_OPUS_CLOCKRATE);
+ (void) sdp_attr_set_rtpmap_num_chan (sdp_p, level, 0, a_inst, 2);
+
+ /* a=fmtp options */
+ if (maxavbitrate || maxcodedaudiobw || usedtx || stereo || useinbandfec || cbr) {
+ if (sdp_add_new_attr(sdp_p, level, 0, SDP_ATTR_FMTP, &a_inst2)
+ != SDP_SUCCESS) {
+ return;
+ }
+
+ (void) sdp_attr_set_fmtp_payload_type (sdp_p, level, 0, a_inst2, payload_number);
+
+ if (maxavbitrate)
+ sdp_attr_set_fmtp_max_average_bitrate (sdp_p, level, 0, a_inst2, FMTP_MAX_AVERAGE_BIT_RATE);
+
+ if(usedtx)
+ sdp_attr_set_fmtp_usedtx (sdp_p, level, 0, a_inst2, FALSE);
+
+ if(stereo)
+ sdp_attr_set_fmtp_stereo (sdp_p, level, 0, a_inst2, FALSE);
+
+ if(useinbandfec)
+ sdp_attr_set_fmtp_useinbandfec (sdp_p, level, 0, a_inst2, FALSE);
+
+ if(maxcodedaudiobw) {
+ sdp_attr_set_fmtp_maxcodedaudiobandwidth (sdp_p, level, 0, a_inst2,
+ max_coded_audio_bandwidth_table[opus_fb].name);
+ }
+
+ if(cbr)
+ sdp_attr_set_fmtp_cbr (sdp_p, level, 0, a_inst2, FALSE);
+ }
+
+ /* a=ptime attribute */
+ if (sdp_add_new_attr(sdp_p, level, 0, SDP_ATTR_PTIME, &a_inst3)
+ != SDP_SUCCESS) {
+ return;
+ }
+
+ sdp_attr_set_simple_u32(sdp_p, SDP_ATTR_PTIME, level, 0, a_inst3, ATTR_PTIME);
+
+ if(maxptime) {
+ /* a=maxptime attribute */
+ if (sdp_add_new_attr(sdp_p, level, 0, SDP_ATTR_MAXPTIME, &a_inst4)
+ != SDP_SUCCESS) {
+ return;
+ }
+
+ sdp_attr_set_simple_u32(sdp_p, SDP_ATTR_MAXPTIME, level, 0, a_inst4, ATTR_MAXPTIME);
+ }
+
+ break;
+ }
+ break;
+
+ case RTP_AVT:
+ /*
+ * add a=rtpmap line
+ */
+ if (sdp_add_new_attr(sdp_p, level, 0, SDP_ATTR_RTPMAP, &a_inst)
+ != SDP_SUCCESS) {
+ return;
+ }
+ (void) sdp_attr_set_rtpmap_encname(sdp_p, level, 0, a_inst,
+ SIPSDP_ATTR_ENCNAME_TEL_EVENT);
+ (void) sdp_attr_set_rtpmap_payload_type(sdp_p, level, 0, a_inst,
+ payload_number);
+ (void) sdp_attr_set_rtpmap_clockrate(sdp_p, level, 0, a_inst,
+ RTPMAP_CLOCKRATE);
+
+ /*
+ * Malloc the mediainfo structure
+ */
+ if (sdp_add_new_attr(sdp_p, level, 0, SDP_ATTR_FMTP, &a_inst)
+ != SDP_SUCCESS) {
+ return;
+ }
+ (void) sdp_attr_set_fmtp_payload_type(sdp_p, level, 0, a_inst,
+ payload_number);
+ (void) sdp_attr_set_fmtp_range(sdp_p, level, 0, a_inst,
+ SIPSDP_NTE_DTMF_MIN,
+ SIPSDP_NTE_DTMF_MAX);
+
+
+ break;
+
+ default:
+ /* The remaining coded types aren't supported, but are listed below
+ * as a reminder
+ * RTP_CELP = 1,
+ * RTP_GSM = 3,
+ * RTP_G726 = 2,
+ * RTP_G723 = 4,
+ * RTP_DVI4 = 5,
+ * RTP_DVI4_II = 6,
+ * RTP_LPC = 7,
+ * RTP_G722 = 9,
+ * RTP_G728 = 15,
+ * RTP_JPEG = 26,
+ * RTP_NV = 28,
+ * RTP_H261 = 31
+ */
+
+ break;
+ }
+}
+
+/*
+ * gsmsdp_set_sctp_attributes
+ *
+ * Description:
+ *
+ * Add the specified SCTP media format to the SDP.
+ *
+ * Parameters:
+ *
+ * sdp_p - Pointer to the SDP the media attribute is to be added to.
+ * level - The media level of the SDP where the media attribute is to be added.
+ */
+static void
+gsmsdp_set_sctp_attributes (void *sdp_p, uint16_t level, fsmdef_media_t *media)
+{
+ uint16_t a_inst;
+
+ if (sdp_add_new_attr(sdp_p, level, 0, SDP_ATTR_FMTP, &a_inst)
+ != SDP_SUCCESS) {
+ return;
+ }
+
+ /* Use SCTP port in place of fmtp payload type */
+ (void) sdp_attr_set_fmtp_payload_type(sdp_p, level, 0, a_inst, media->sctp_port);
+
+ sdp_attr_set_fmtp_data_channel_protocol (sdp_p, level, 0, a_inst, WEBRTC_DATA_CHANNEL_PROT);
+
+ sdp_attr_set_fmtp_streams (sdp_p, level, 0, a_inst, 16);
+}
+
+/*
+ * gsmsdp_set_remote_sdp
+ *
+ * Description:
+ *
+ * Sets the specified SDP as the remote SDP in the DCB.
+ *
+ * Parameters:
+ *
+ * dcb_p - Pointer to the DCB.
+ * sdp_p - Pointer to the SDP to be set as the remote SDP in the DCB.
+ */
+static void
+gsmsdp_set_remote_sdp (fsmdef_dcb_t *dcb_p, cc_sdp_t *sdp_p)
+{
+ dcb_p->remote_sdp_present = TRUE;
+}
+
+/*
+ * gsmsdp_get_sdp_direction_attr
+ *
+ * Description:
+ *
+ * Given a sdp_direction_e enumerated type, returns a sdp_attr_e
+ * enumerated type.
+ *
+ * Parameters:
+ *
+ * direction - The SDP direction used to determine which sdp_attr_e to return.
+ *
+ */
+static sdp_attr_e
+gsmsdp_get_sdp_direction_attr (sdp_direction_e direction)
+{
+ sdp_attr_e sdp_attr = SDP_ATTR_SENDRECV;
+
+ switch (direction) {
+ case SDP_DIRECTION_INACTIVE:
+ sdp_attr = SDP_ATTR_INACTIVE;
+ break;
+ case SDP_DIRECTION_SENDONLY:
+ sdp_attr = SDP_ATTR_SENDONLY;
+ break;
+ case SDP_DIRECTION_RECVONLY:
+ sdp_attr = SDP_ATTR_RECVONLY;
+ break;
+ case SDP_DIRECTION_SENDRECV:
+ sdp_attr = SDP_ATTR_SENDRECV;
+ break;
+ default:
+ GSM_ERR_MSG("\nFSMDEF ERROR: replace with formal error text");
+ }
+
+ return sdp_attr;
+}
+
+/*
+ * gsmsdp_set_sdp_direction
+ *
+ * Description:
+ *
+ * Adds a direction attribute to the given media line in the
+ * specified SDP.
+ *
+ * Parameters:
+ *
+ * media - pointer to the fsmdef_media_t for the media entry.
+ * direction - The direction to use when setting the direction attribute.
+ * sdp_p - Pointer to the SDP to set the direction attribute against.
+ */
+static void
+gsmsdp_set_sdp_direction (fsmdef_media_t *media,
+ sdp_direction_e direction, void *sdp_p)
+{
+ sdp_attr_e sdp_attr = SDP_ATTR_SENDRECV;
+ uint16_t a_instance = 0;
+
+ /*
+ * Convert the direction to an SDP direction attribute.
+ */
+ sdp_attr = gsmsdp_get_sdp_direction_attr(direction);
+ if (media->level) {
+ (void) sdp_add_new_attr(sdp_p, media->level, 0, sdp_attr, &a_instance);
+ } else {
+ /* Just in case that there is no level defined, add to the session */
+ (void) sdp_add_new_attr(sdp_p, SDP_SESSION_LEVEL, 0, sdp_attr,
+ &a_instance);
+ }
+}
+
+/*
+ * gsmsdp_get_ice_attributes
+ *
+ * Description:
+ *
+ * Returns the ice attribute strings at a given level
+ *
+ * Parameters:
+ *
+ * session - true = session level attributes, false = media line attribs
+ * level - The media level of the SDP where the media attribute exists.
+ * sdp_p - Pointer to the SDP whose ice candidates are being searched.
+ * ice_attribs - return ice attribs at this level in an array
+ * attributes_ctp - count of array of media line attributes
+ */
+
+static boolean
+gsmsdp_get_ice_attributes (sdp_attr_e sdp_attr, uint16_t level, void *sdp_p, char ***ice_attribs, int *attributes_ctp)
+{
+ uint16_t num_a_lines = 0;
+ uint16_t i;
+ sdp_result_e result;
+ char* ice_attrib;
+
+ result = sdp_attr_num_instances(sdp_p, level, 0, sdp_attr, &num_a_lines);
+ if (result != SDP_SUCCESS) {
+ GSM_ERR_MSG("enumerating ICE attributes failed\n");
+ return FALSE;
+ }
+
+ if (num_a_lines < 1) {
+ GSM_ERR_MSG("enumerating ICE attributes returned 0 attributes\n");
+ return TRUE;
+ }
+
+ *ice_attribs = (char **)cpr_malloc(num_a_lines * sizeof(char *));
+
+ if (!(*ice_attribs))
+ return FALSE;
+
+ *attributes_ctp = 0;
+
+ for (i = 0; i < num_a_lines; i++) {
+ result = sdp_attr_get_ice_attribute (sdp_p, level, 0, sdp_attr, (uint16_t) (i + 1),
+ &ice_attrib);
+ if (result != SDP_SUCCESS) {
+ GSM_ERR_MSG("Failed to retrieve ICE attribute\n");
+ cpr_free(*ice_attribs);
+ return FALSE;
+ }
+ (*ice_attribs)[i] = (char *) cpr_calloc(1, strlen(ice_attrib) + 1);
+ if(!(*ice_attribs)[i])
+ return FALSE;
+
+ sstrncpy((*ice_attribs)[i], ice_attrib, strlen(ice_attrib) + 1);
+ (*attributes_ctp)++;
+ }
+
+ return TRUE;
+}
+
+/*
+ * gsmsdp_set_attributes
+ *
+ * Description:
+ *
+ * Adds an ice attribute attributes to the specified SDP.
+ *
+ * Parameters:
+ *
+ * session - true = session level attribute, false = media line attribute
+ * level - The media level of the SDP where the media attribute exists.
+ * sdp_p - Pointer to the SDP to set the ice candidate attribute against.
+ * ice_attrib - ice attribute to set
+ */
+static void
+gsmsdp_set_ice_attribute (sdp_attr_e sdp_attr, uint16_t level, void *sdp_p, char *ice_attrib)
+{
+ uint16_t a_instance = 0;
+ sdp_result_e result;
+
+ result = sdp_add_new_attr(sdp_p, level, 0, sdp_attr, &a_instance);
+ if (result != SDP_SUCCESS) {
+ GSM_ERR_MSG("Failed to add attribute\n");
+ return;
+ }
+
+ result = sdp_attr_set_ice_attribute(sdp_p, level, 0, sdp_attr, a_instance, ice_attrib);
+ if (result != SDP_SUCCESS) {
+ GSM_ERR_MSG("Failed to set attribute\n");
+ }
+}
+
+/*
+ * gsmsdp_set_rtcp_mux_attribute
+ *
+ * Description:
+ *
+ * Adds an ice attribute attributes to the specified SDP.
+ *
+ * Parameters:
+ *
+ * session - true = session level attribute, false = media line attribute
+ * level - The media level of the SDP where the media attribute exists.
+ * sdp_p - Pointer to the SDP to set the ice candidate attribute against.
+ * rtcp_mux - ice attribute to set
+ */
+static void
+gsmsdp_set_rtcp_mux_attribute (sdp_attr_e sdp_attr, uint16_t level, void *sdp_p, boolean rtcp_mux)
+{
+ uint16_t a_instance = 0;
+ sdp_result_e result;
+
+ result = sdp_add_new_attr(sdp_p, level, 0, sdp_attr, &a_instance);
+ if (result != SDP_SUCCESS) {
+ GSM_ERR_MSG("Failed to add attribute\n");
+ return;
+ }
+
+ result = sdp_attr_set_rtcp_mux_attribute(sdp_p, level, 0, sdp_attr, a_instance, rtcp_mux);
+ if (result != SDP_SUCCESS) {
+ GSM_ERR_MSG("Failed to set attribute\n");
+ }
+}
+
+/*
+ * gsmsdp_set_dtls_fingerprint_attribute
+ *
+ * Description:
+ *
+ * Adds an dtls fingerprint attribute attributes to the specified SDP.
+ *
+ * Parameters:
+ *
+ * session - true = session level attribute, false = media line attribute
+ * level - The media level of the SDP where the media attribute exists.
+ * sdp_p - Pointer to the SDP to set the ice candidate attribute against.
+ * hash_func - hash function string, e.g. "sha-1"
+ * hash_func_len - string len
+ * fingerprint - fingerprint attribute to set
+ * fingerprint_len - string len of fingerprint
+ */
+static void
+gsmsdp_set_dtls_fingerprint_attribute (sdp_attr_e sdp_attr, uint16_t level, void *sdp_p,
+ char *hash_func,char *fingerprint)
+{
+ uint16_t a_instance = 0;
+ sdp_result_e result;
+ char hash_and_fingerprint[FSMDEF_MAX_DIGEST_ALG_LEN + FSMDEF_MAX_DIGEST_LEN + 2];
+
+ snprintf(hash_and_fingerprint, sizeof(hash_and_fingerprint),
+ "%s %s", hash_func, fingerprint);
+
+ result = sdp_add_new_attr(sdp_p, level, 0, sdp_attr, &a_instance);
+ if (result != SDP_SUCCESS) {
+ GSM_ERR_MSG("Failed to add attribute\n");
+ return;
+ }
+
+ result = sdp_attr_set_dtls_fingerprint_attribute(sdp_p, level, 0, sdp_attr, a_instance, hash_and_fingerprint);
+ if (result != SDP_SUCCESS) {
+ GSM_ERR_MSG("Failed to set dtls fingerprint attribute\n");
+ }
+}
+
+/*
+ * gsmsdp_remove_sdp_direction
+ *
+ * Description:
+ *
+ * Removes the direction attribute corresponding to the passed in direction
+ * from the media line of the specified SDP.
+ *
+ * Parameters:
+ *
+ * media - pointer to the fsmdef_media_t for the media entry.
+ * direction - The direction whose corresponding direction attribute
+ * is to be removed.
+ * sdp_p - Pointer to the SDP where the direction attribute is to be
+ * removed.
+ */
+static void
+gsmsdp_remove_sdp_direction (fsmdef_media_t *media,
+ sdp_direction_e direction, void *sdp_p)
+{
+ sdp_attr_e sdp_attr = SDP_ATTR_SENDRECV;
+
+ sdp_attr = gsmsdp_get_sdp_direction_attr(direction);
+ (void) sdp_delete_attr(sdp_p, media->level, 0, sdp_attr, 1);
+}
+
+/*
+ * gsmsdp_set_local_sdp_direction
+ *
+ * Description:
+ *
+ * Sets the direction attribute for the local SDP.
+ *
+ * Parameters:
+ *
+ * dcb_p - The DCB where the local SDP is located.
+ * media - Pointer to fsmdef_media_t for the media entry of the SDP.
+ * direction - The media direction to set into the local SDP.
+ */
+void
+gsmsdp_set_local_sdp_direction (fsmdef_dcb_t *dcb_p,
+ fsmdef_media_t *media,
+ sdp_direction_e direction)
+{
+ /*
+ * If media direction was previously set, remove the direction attribute
+ * before adding the specified direction. Save the direction in previous
+ * direction before clearing it.
+ */
+ if (media->direction_set) {
+ media->previous_sdp.direction = media->direction;
+ gsmsdp_remove_sdp_direction(media, media->direction,
+ dcb_p->sdp ? dcb_p->sdp->src_sdp : NULL );
+ media->direction_set = FALSE;
+ }
+ gsmsdp_set_sdp_direction(media, direction, dcb_p->sdp ? dcb_p->sdp->src_sdp : NULL);
+ /*
+ * We could just get the direction from the local SDP when we need it in
+ * GSM, but setting the direction in the media structure gives a quick way
+ * to access the media direction.
+ */
+ media->direction = direction;
+ media->direction_set = TRUE;
+}
+
+/*
+ * gsmsdp_get_remote_sdp_direction
+ *
+ * Description:
+ *
+ * Returns the media direction from the specified SDP. We will check for the
+ * media direction attribute at the session level and the first AUDIO media line.
+ * If the direction attribute is specified at the media level, the media level setting
+ * overrides the session level attribute.
+ *
+ * Parameters:
+ *
+ * dcb_p - pointer to the fsmdef_dcb_t.
+ * level - media line level.
+ * dest_addr - pointer to the remote address.
+ */
+static sdp_direction_e
+gsmsdp_get_remote_sdp_direction (fsmdef_dcb_t *dcb_p, uint16_t level,
+ cpr_ip_addr_t *dest_addr)
+{
+ sdp_direction_e direction = SDP_DIRECTION_SENDRECV;
+ cc_sdp_t *sdp_p = dcb_p->sdp;
+ uint16_t media_attr;
+ uint16_t i;
+ static const sdp_attr_e dir_attr_array[] = {
+ SDP_ATTR_INACTIVE,
+ SDP_ATTR_RECVONLY,
+ SDP_ATTR_SENDONLY,
+ SDP_ATTR_SENDRECV,
+ SDP_MAX_ATTR_TYPES
+ };
+
+ if (!sdp_p->dest_sdp) {
+ return direction;
+ }
+
+ media_attr = 0; /* media level attr. count */
+ /*
+ * Now check for direction as a media attribute. If found, the
+ * media attribute takes precedence over direction specified
+ * as a session attribute.
+ *
+ * In order to find out whether there is a direction attribute
+ * associated with a media line (or even at the
+ * session level) or not is to get the number of instances of
+ * that attribute via the sdp_attr_num_instances() first. The is
+ * because the sdp_get_media_direction() always returns a valid
+ * direction value even when there is no direction attribute with
+ * the media line (or session level).
+ *
+ * Note: there is no single attribute value to pass to the
+ * sdp_attr_num_instances() to get number a direction attribute that
+ * represents inactive, recvonly, sendonly, sendrcv. We have to
+ * look for each one of them individually.
+ */
+ for (i = 0; (dir_attr_array[i] != SDP_MAX_ATTR_TYPES); i++) {
+ if (sdp_attr_num_instances(sdp_p->dest_sdp, level, 0,
+ dir_attr_array[i], &media_attr) ==
+ SDP_SUCCESS) {
+ if (media_attr) {
+ /* There is direction attribute in the media line */
+ direction = sdp_get_media_direction(sdp_p->dest_sdp,
+ level, 0);
+ break;
+ }
+ }
+ }
+
+ /*
+ * Check for the direction attribute. The direction can be specified
+ * as a session attribute or a media stream attribute. If the direction
+ * is specified as a session attribute, the direction is applicable to
+ * all media streams in the SDP.
+ */
+ if (media_attr == 0) {
+ /* no media level direction, get the direction from session */
+ direction = sdp_get_media_direction(sdp_p->dest_sdp,
+ SDP_SESSION_LEVEL, 0);
+ }
+
+ /*
+ * To support legacy way of signaling remote hold, we will interpret
+ * c=0.0.0.0 to be a=inactive
+ */
+ if (dest_addr->type == CPR_IP_ADDR_IPV4 &&
+ dest_addr->u.ip4 == 0) {
+
+ direction = SDP_DIRECTION_INACTIVE;
+ } else {
+
+ //todo IPv6: reject the request.
+ }
+ return direction;
+}
+
+/**
+ *
+ * The function overrides direction for some special feature
+ * processing.
+ *
+ * @param[in]dcb_p - pointer to the fsmdef_dcb_t
+ * @param[in]media - pointer to fsmdef_media_t for the media to
+ * override the direction.
+ *
+ * @return None.
+ * @pre (dcb_p not_eq NULL) and (media not_eq NULL)
+ */
+static void
+gsmsdp_feature_overide_direction (fsmdef_dcb_t *dcb_p, fsmdef_media_t *media)
+{
+ /*
+ * Disable video if this is a BARGE with video
+ */
+ if ( CC_IS_VIDEO(media->cap_index) &&
+ dcb_p->join_call_id != CC_NO_CALL_ID ){
+ media->support_direction = SDP_DIRECTION_INACTIVE;
+ }
+
+ if (CC_IS_VIDEO(media->cap_index) && media->support_direction == SDP_DIRECTION_INACTIVE) {
+ DEF_DEBUG(GSM_F_PREFIX"video capability disabled to SDP_DIRECTION_INACTIVE \n", "gsmsdp_feature_overide_direction");
+ }
+}
+
+/*
+ * gsmsdp_negotiate_local_sdp_direction
+ *
+ * Description:
+ *
+ * Given an offer SDP, return the corresponding answer SDP direction.
+ *
+ * local hold remote direction support direction new local direction
+ * enabled inactive any inactive
+ * enabled sendrecv sendonly sendonly
+ * enabled sendrecv recvonly inactive
+ * enabled sendrecv sendrecv sendonly
+ * enabled sendrecv inactive inactive
+ * enabled sendonly any inactive
+ * enabled recvonly sendrecv sendonly
+ * enabled recvonly sendonly sendonly
+ * enabled recvonly recvonly inactive
+ * enabled recvonly inactive inactive
+ * disabled inactive any inactive
+ * disabled sendrecv sendrecv sendrecv
+ * disabled sendrecv sendonly sendonly
+ * disabled sendrecv recvonly recvonly
+ * disabled sendrecv inactive inactive
+ * disabled sendonly sendrecv recvonly
+ * disabled sendonly sendonly inactive
+ * disabled sendonly recvonly recvonly
+ * disabled sendonly inactive inactive
+ * disabled recvonly sendrecv sendonly
+ * disabled recvonly sendonly sendonly
+ * disabled recvonly recvonly inactive
+ * disabled recvonly inactive inactive
+ *
+ * Parameters:
+ *
+ * dcb_p - pointer to the fsmdef_dcb_t.
+ * media - pointer to the fsmdef_media_t for the current media entry.
+ * local_hold - Boolean indicating if local hold feature is enabled
+ */
+static sdp_direction_e
+gsmsdp_negotiate_local_sdp_direction (fsmdef_dcb_t *dcb_p,
+ fsmdef_media_t *media,
+ boolean local_hold)
+{
+ sdp_direction_e direction = SDP_DIRECTION_SENDRECV;
+ sdp_direction_e remote_direction = gsmsdp_get_remote_sdp_direction(dcb_p,
+ media->level, &media->dest_addr);
+
+ if (remote_direction == SDP_DIRECTION_SENDRECV) {
+ if (local_hold) {
+ if ((media->support_direction == SDP_DIRECTION_SENDRECV) ||
+ (media->support_direction == SDP_DIRECTION_SENDONLY)) {
+ direction = SDP_DIRECTION_SENDONLY;
+ } else {
+ direction = SDP_DIRECTION_INACTIVE;
+ }
+ } else {
+ direction = media->support_direction;
+ }
+ } else if (remote_direction == SDP_DIRECTION_SENDONLY) {
+ if (local_hold) {
+ direction = SDP_DIRECTION_INACTIVE;
+ } else {
+ if ((media->support_direction == SDP_DIRECTION_SENDRECV) ||
+ (media->support_direction == SDP_DIRECTION_RECVONLY)) {
+ direction = SDP_DIRECTION_RECVONLY;
+ } else {
+ direction = SDP_DIRECTION_INACTIVE;
+ }
+ }
+ } else if (remote_direction == SDP_DIRECTION_INACTIVE) {
+ direction = SDP_DIRECTION_INACTIVE;
+ } else if (remote_direction == SDP_DIRECTION_RECVONLY) {
+ if ((media->support_direction == SDP_DIRECTION_SENDRECV) ||
+ (media->support_direction == SDP_DIRECTION_SENDONLY)) {
+ direction = SDP_DIRECTION_SENDONLY;
+ } else {
+ direction = SDP_DIRECTION_INACTIVE;
+ }
+ }
+
+ return direction;
+}
+
+/*
+ * gsmsdp_add_default_audio_formats_to_local_sdp
+ *
+ * Description:
+ *
+ * Add all supported media formats to the local SDP of the specified DCB
+ * at the specified media level. If the call is involved in a conference
+ * call, only add G.711 formats.
+ *
+ * Parameters
+ *
+ * dcb_p - The DCB whose local SDP is to be updated with the default media formats.
+ * sdp_p - Pointer to the local sdp structure. This is added so call to this
+ * routine can be made irrespective of whether we have a dcb or not(To
+ * handle out-of-call options request for example)
+ * media - Pointer to fsmdef_media_t for the media entry of the SDP.
+ *
+ */
+static void
+gsmsdp_add_default_audio_formats_to_local_sdp (fsmdef_dcb_t *dcb_p,
+ cc_sdp_t * sdp_p,
+ fsmdef_media_t *media)
+{
+ static const char fname[] = "gsmsdp_add_default_audio_formats_to_local_sdp";
+ int local_media_types[CC_MAX_MEDIA_TYPES];
+ int16_t local_avt_payload_type = RTP_NONE;
+ DtmfOutOfBandTransport_t transport = DTMF_OUTOFBAND_NONE;
+ int type_cnt;
+ void *local_sdp_p = NULL;
+ uint16_t media_format_count;
+ uint16_t level;
+ int i;
+
+ if (media) {
+ level = media->level;
+ } else {
+ level = 1;
+ }
+ local_sdp_p = (void *) sdp_p->src_sdp;
+
+ /*
+ * Create list of supported codecs. Get all the codecs that the phone
+ * supports.
+ */
+ media_format_count = sip_config_local_supported_codecs_get(
+ (rtp_ptype *) local_media_types,
+ CC_MAX_MEDIA_TYPES);
+ /*
+ * If there are no media payloads, it's because we are making an
+ * initial offer. We will be opening our receive port so we need to specify
+ * the media payload type to be used initially. We set the media payload
+ * type in the dcb to do this. Until we receive an answer from the far
+ * end, we will use our first choice payload type. i.e. the first payload
+ * type sent in our AUDIO media line.
+ */
+
+ if (dcb_p && media && media->num_payloads == 0) {
+
+ if (media->payloads &&
+ (media->num_payloads < media_format_count)) {
+ cpr_free(media->payloads);
+ media->payloads = NULL;
+ }
+
+ if (!media->payloads) {
+ media->payloads = cpr_calloc(media_format_count,
+ sizeof(vcm_payload_info_t));
+ }
+
+ media->num_payloads = 0;
+ for (i = 0; i < media_format_count; i++) {
+ if (local_media_types[i] > RTP_NONE) {
+ media->payloads[i].codec_type = local_media_types[i];
+ media->payloads[i].local_rtp_pt = local_media_types[i];
+ media->payloads[i].remote_rtp_pt = local_media_types[i];
+ media->num_payloads++;
+ }
+ }
+ gsmsdp_copy_payloads_to_previous_sdp(media);
+ }
+
+ /*
+ * Get configured OOB DTMF setting and avt payload type if applicable
+ */
+ config_get_value(CFGID_DTMF_OUTOFBAND, &transport, sizeof(transport));
+
+ if ((transport == DTMF_OUTOFBAND_AVT) ||
+ (transport == DTMF_OUTOFBAND_AVT_ALWAYS)) {
+ int temp_payload_type = RTP_NONE;
+
+ config_get_value(CFGID_DTMF_AVT_PAYLOAD,
+ &(temp_payload_type),
+ sizeof(temp_payload_type));
+ local_avt_payload_type = (uint16_t) temp_payload_type;
+ }
+
+ /*
+ * add all the audio media types
+ */
+ for (type_cnt = 0;
+ (type_cnt < media_format_count) &&
+ (local_media_types[type_cnt] > RTP_NONE);
+ type_cnt++) {
+
+ if (sdp_add_media_payload_type(local_sdp_p, level,
+ (uint16_t)local_media_types[type_cnt],
+ SDP_PAYLOAD_NUMERIC) != SDP_SUCCESS) {
+ GSM_ERR_MSG(GSM_L_C_F_PREFIX"Adding media payload type failed\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname));
+ }
+
+ if (media->support_direction != SDP_DIRECTION_INACTIVE) {
+ gsmsdp_set_media_attributes(local_media_types[type_cnt], local_sdp_p,
+ level, (uint16_t)local_media_types[type_cnt]);
+ }
+ }
+
+ /*
+ * add the avt media type
+ */
+ if (local_avt_payload_type > RTP_NONE) {
+ if (sdp_add_media_payload_type(local_sdp_p, level,
+ local_avt_payload_type,
+ SDP_PAYLOAD_NUMERIC) != SDP_SUCCESS) {
+ GSM_ERR_MSG(GSM_L_C_F_PREFIX"Adding AVT payload type failed\n",
+ dcb_p->line, dcb_p->call_id, fname);
+ }
+
+ if (media->support_direction != SDP_DIRECTION_INACTIVE) {
+ gsmsdp_set_media_attributes(RTP_AVT, local_sdp_p, level,
+ local_avt_payload_type);
+ if (media) {
+ media->avt_payload_type = local_avt_payload_type;
+ }
+ }
+ }
+}
+
+/*
+ * gsmsdp_add_default_video_formats_to_local_sdp
+ *
+ * Description:
+ *
+ * Add all supported media formats to the local SDP of the specified DCB
+ * at the specified media level. If the call is involved in a conference
+ * call, only add G.711 formats.
+ *
+ * Parameters
+ *
+ * dcb_p - The DCB whose local SDP is to be updated with the default media formats.
+ * sdp_p - Pointer to the local sdp structure. This is added so call to this
+ * routine can be made irrespective of whether we have a dcb or not(To
+ * handle out-of-call options request for example)
+ * media - Pointer to fsmdef_media_t for the media entry of the SDP.
+ *
+ */
+static void
+gsmsdp_add_default_video_formats_to_local_sdp (fsmdef_dcb_t *dcb_p,
+ cc_sdp_t * sdp_p,
+ fsmdef_media_t *media)
+{
+ static const char fname[] = "gsmsdp_add_default_video_formats_to_local_sdp";
+ int video_media_types[CC_MAX_MEDIA_TYPES];
+ int type_cnt;
+ void *local_sdp_p = NULL;
+ uint16_t video_format_count;
+ uint16_t level;
+ line_t line = 0;
+ callid_t call_id = 0;
+ int i;
+
+ if (dcb_p && media) {
+ line = dcb_p->line;
+ call_id = dcb_p->call_id;
+ }
+ GSM_DEBUG(DEB_L_C_F_PREFIX"\n", DEB_L_C_F_PREFIX_ARGS(GSM, line, call_id, fname));
+
+ if (media) {
+ level = media->level;
+ } else {
+ level = 2;
+ }
+ local_sdp_p = (void *) sdp_p->src_sdp;
+
+ /*
+ * Create list of supported codecs. Get all the codecs that the phone supports.
+ */
+
+ video_format_count = sip_config_video_supported_codecs_get( (rtp_ptype *) video_media_types,
+ CC_MAX_MEDIA_TYPES, TRUE /*offer*/);
+
+ GSM_DEBUG(DEB_L_C_F_PREFIX"video_count=%d\n", DEB_L_C_F_PREFIX_ARGS(GSM, line, call_id, fname), video_format_count);
+ /*
+ * If the there are no media payloads, its because we are making an
+ * initial offer. We will be opening our receive port so we need to specify
+ * the media payload type to be used initially. We set the media payload
+ * type in the dcb to do this. Until we receive an answer from the far
+ * end, we will use our first choice payload type. i.e. the first payload
+ * type sent in our video media line.
+ */
+ if (dcb_p && media && media->num_payloads == 0) {
+ if (media->payloads &&
+ (media->num_payloads < video_format_count)) {
+ cpr_free(media->payloads);
+ media->payloads = NULL;
+ }
+
+ if (!media->payloads) {
+ media->payloads = cpr_calloc(video_format_count,
+ sizeof(vcm_payload_info_t));
+ }
+
+ media->num_payloads = 0;
+ for (i = 0; i < video_format_count; i++) {
+ if (video_media_types[i] > RTP_NONE) {
+ media->payloads[i].codec_type = video_media_types[i];
+ media->payloads[i].local_rtp_pt = video_media_types[i];
+ media->payloads[i].remote_rtp_pt = video_media_types[i];
+ media->num_payloads++;
+ }
+ }
+ gsmsdp_copy_payloads_to_previous_sdp(media);
+ }
+
+
+ /*
+ * add all the video media types
+ */
+ for (type_cnt = 0;
+ (type_cnt < video_format_count) &&
+ (video_media_types[type_cnt] > RTP_NONE);
+ type_cnt++) {
+
+ if (sdp_add_media_payload_type(local_sdp_p, level,
+ (uint16_t)video_media_types[type_cnt],
+ SDP_PAYLOAD_NUMERIC) != SDP_SUCCESS) {
+ GSM_ERR_MSG(GSM_L_C_F_PREFIX"SDP ERROR(1)\n",
+ line, call_id, fname);
+ }
+
+ if (media->support_direction != SDP_DIRECTION_INACTIVE) {
+ gsmsdp_set_video_media_attributes(video_media_types[type_cnt], sdp_p,
+ level, (uint16_t)video_media_types[type_cnt]);
+ }
+ }
+}
+
+/**
+ * This function sets the mid attr at the media level
+ * and labels the relevant media streams when phone is
+ * operating in a dual stack mode
+ *
+ * @param[in]src_sdp_p - Our source sdp.
+ * @param[in]level - The level of the media that we are operating on.
+ *
+ * @return - None
+ *
+ */
+static void gsmsdp_set_mid_attr (void *src_sdp_p, uint16_t level)
+{
+ uint16 inst_num;
+
+ if (platform_get_ip_address_mode() == CPR_IP_MODE_DUAL) {
+ /*
+ * add a=mid line
+ */
+ (void) sdp_add_new_attr(src_sdp_p, level, 0, SDP_ATTR_MID, &inst_num);
+
+ (void) sdp_attr_set_simple_u32(src_sdp_p, SDP_ATTR_MID, level, 0,
+ inst_num, level);
+ }
+}
+
+/**
+ * This function sets the anat attr to the session level
+ * and labels the relevant media streams
+ *
+ * @param[in]media - The media line that we are operating on.
+ * @param[in]dcb_p - Pointer to the DCB whose local SDP is to be updated.
+ *
+ * @return - None
+ *
+ */
+static void gsmsdp_set_anat_attr (fsmdef_dcb_t *dcb_p, fsmdef_media_t *media)
+{
+ void *src_sdp_p = (void *) dcb_p->sdp->src_sdp;
+ void *dest_sdp_p = (void *) dcb_p->sdp->dest_sdp;
+ uint16 inst_num;
+ uint16_t num_group_lines= 0;
+ uint16_t num_anat_lines = 0;
+ u32 group_id_1, group_id_2;
+ uint16_t i;
+ fsmdef_media_t *group_media;
+
+
+ if (dest_sdp_p == NULL) {
+ /* If this is our initial offer */
+ if (media->addr_type == SDP_AT_IP4) {
+ group_media = gsmsdp_find_anat_pair(dcb_p, media);
+ if (group_media != NULL) {
+ /*
+ * add a=group line
+ */
+ (void) sdp_add_new_attr(src_sdp_p, SDP_SESSION_LEVEL, 0, SDP_ATTR_GROUP, &inst_num);
+
+ (void) sdp_set_group_attr(src_sdp_p, SDP_SESSION_LEVEL, 0, inst_num, SDP_GROUP_ATTR_ANAT);
+
+ (void) sdp_set_group_num_id(src_sdp_p, SDP_SESSION_LEVEL, 0, inst_num, 2);
+ (void) sdp_set_group_id(src_sdp_p, SDP_SESSION_LEVEL, 0, inst_num, group_media->level);
+ (void) sdp_set_group_id(src_sdp_p, SDP_SESSION_LEVEL, 0, inst_num, media->level);
+ }
+ }
+ } else {
+ /* This is an answer, check if the offer rcvd had anat grouping */
+ (void) sdp_attr_num_instances(dest_sdp_p, SDP_SESSION_LEVEL, 0, SDP_ATTR_GROUP,
+ &num_group_lines);
+
+ for (i = 1; i <= num_group_lines; i++) {
+ if (sdp_get_group_attr(dest_sdp_p, SDP_SESSION_LEVEL, 0, i) == SDP_GROUP_ATTR_ANAT) {
+ num_anat_lines++;
+ }
+ }
+
+ for (i = 1; i <= num_anat_lines; i++) {
+ group_id_1 = sdp_get_group_id(dest_sdp_p, SDP_SESSION_LEVEL, 0, i, 1);
+ group_id_2 = sdp_get_group_id(dest_sdp_p, SDP_SESSION_LEVEL, 0, i, 2);
+
+ if ((media->level == group_id_1) || (media->level == group_id_2)) {
+
+ group_media = gsmsdp_find_anat_pair(dcb_p, media);
+ if (group_media != NULL) {
+ if (sdp_get_group_attr(src_sdp_p, SDP_SESSION_LEVEL, 0, i) != SDP_GROUP_ATTR_ANAT) {
+ /*
+ * add a=group line
+ */
+ (void) sdp_add_new_attr(src_sdp_p, SDP_SESSION_LEVEL, 0, SDP_ATTR_GROUP, &inst_num);
+ (void) sdp_set_group_attr(src_sdp_p, SDP_SESSION_LEVEL, 0, inst_num, SDP_GROUP_ATTR_ANAT);
+
+ }
+ (void) sdp_set_group_num_id(src_sdp_p, SDP_SESSION_LEVEL, 0, i, 2);
+ (void) sdp_set_group_id(src_sdp_p, SDP_SESSION_LEVEL, 0, i, group_media->level);
+ (void) sdp_set_group_id(src_sdp_p, SDP_SESSION_LEVEL, 0, i, media->level);
+
+ } else {
+ /*
+ * add a=group line
+ */
+ (void) sdp_add_new_attr(src_sdp_p, SDP_SESSION_LEVEL, 0, SDP_ATTR_GROUP, &inst_num);
+ (void) sdp_set_group_attr(src_sdp_p, SDP_SESSION_LEVEL, 0, inst_num, SDP_GROUP_ATTR_ANAT);
+
+ (void) sdp_set_group_num_id(src_sdp_p, SDP_SESSION_LEVEL, 0, inst_num, 1);
+ (void) sdp_set_group_id(src_sdp_p, SDP_SESSION_LEVEL, 0, inst_num, media->level);
+ }
+
+ }
+ }
+ }
+ gsmsdp_set_mid_attr (src_sdp_p, media->level);
+}
+
+/*
+ * gsmsdp_update_local_sdp_media
+ *
+ * Description:
+ *
+ * Adds an AUDIO media line to the local SDP of the specified DCB. If all_formats
+ * is TRUE, sets all media formats supported by the phone into the local SDP, else
+ * only add the single negotiated media format. If an AUDIO media line already
+ * exists in the local SDP, remove it as this function completely rebuilds the
+ * AUDIO media line and will do so at the same media level as the pre-existing
+ * AUDIO media line.
+ *
+ * Parameters:
+ *
+ * dcb_p - Pointer to the DCB whose local SDP is to be updated.
+ * cc_sdp_p - Pointer to the SDP being updated.
+ * all_formats - If true, all supported media formats will be added to the
+ * AUDIO media line of the SDP. Otherwise, only the single
+ * negotiated media format is added.
+ * media - Pointer to fsmdef_media_t for the media entry of the SDP.
+ * transport - transport type to for this media line.
+ *
+ */
+static void
+gsmsdp_update_local_sdp_media (fsmdef_dcb_t *dcb_p, cc_sdp_t *cc_sdp_p,
+ boolean all_formats, fsmdef_media_t *media,
+ sdp_transport_e transport)
+{
+ static const char fname[] = "gsmsdp_update_local_sdp_media";
+ uint16_t port;
+ sdp_result_e result;
+ uint16_t level;
+ void *sdp_p;
+ int sdpmode = 0;
+ int i = 0;
+
+ if (!dcb_p || !media) {
+ GSM_ERR_MSG(get_debug_string(FSMDEF_DBG_INVALID_DCB), fname);
+ return;
+ }
+ level = media->level;
+ port = media->src_port;
+
+ config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
+
+ sdp_p = cc_sdp_p ? (void *) cc_sdp_p->src_sdp : NULL;
+
+ if (sdp_p == NULL) {
+
+ gsmsdp_init_local_sdp(dcb_p->peerconnection, &(dcb_p->sdp));
+
+ cc_sdp_p = dcb_p->sdp;
+ if ((cc_sdp_p == NULL) || (cc_sdp_p->src_sdp == NULL)) {
+ GSM_ERR_MSG(GSM_L_C_F_PREFIX"sdp is NULL and init failed \n",
+ dcb_p->line, dcb_p->call_id, fname);
+ return;
+ }
+ sdp_p = (void *) cc_sdp_p->src_sdp;
+ } else {
+
+ /*
+ * Remove the audio stream. Reset direction_set flag since
+ * all media attributes have just been removed.
+ */
+ sdp_delete_media_line(sdp_p, level);
+ media->direction_set = FALSE;
+ }
+
+ result = sdp_insert_media_line(sdp_p, level);
+ if (result != SDP_SUCCESS) {
+ GSM_ERR_MSG(GSM_L_C_F_PREFIX"Inserting media line to Sdp failed\n",
+ dcb_p->line, dcb_p->call_id, fname);
+ return;
+ }
+
+ if (media->support_direction != SDP_DIRECTION_INACTIVE) {
+ gsmsdp_set_connection_address(sdp_p, media->level, dcb_p->ice_default_candidate_addr);
+ }
+
+ (void) sdp_set_media_type(sdp_p, level, media->type);
+
+
+ (void) sdp_set_media_portnum(sdp_p, level, port, media->sctp_port);
+
+ /* Set media transport and crypto attributes if it is for SRTP */
+ gsmsdp_update_local_sdp_media_transport(dcb_p, sdp_p, media, transport,
+ all_formats);
+
+ if (all_formats) {
+ /*
+ * Add all supported media formats to the local sdp.
+ */
+ switch (media->type) {
+ case SDP_MEDIA_AUDIO:
+ gsmsdp_add_default_audio_formats_to_local_sdp(dcb_p, cc_sdp_p,
+ media);
+ break;
+ case SDP_MEDIA_VIDEO:
+ gsmsdp_add_default_video_formats_to_local_sdp(dcb_p, cc_sdp_p,
+ media);
+ break;
+ case SDP_MEDIA_APPLICATION:
+ gsmsdp_set_sctp_attributes (sdp_p, level, media);
+ break;
+ default:
+ GSM_ERR_MSG(GSM_L_C_F_PREFIX"SDP ERROR media %d for level %d is not"
+ " supported\n",
+ dcb_p->line, dcb_p->call_id, fname, media->level);
+ break;
+ }
+ } else {
+ /*
+ * Add negotiated codec list to the sdp
+ */
+ for(i = 0; i < media->num_payloads; i++) {
+ result =
+ sdp_add_media_payload_type(sdp_p, level,
+ (uint16_t)(media->payloads[i].local_rtp_pt),
+ SDP_PAYLOAD_NUMERIC);
+
+ if (result != SDP_SUCCESS) {
+ GSM_ERR_MSG(GSM_L_C_F_PREFIX"Adding dynamic payload type failed\n",
+ dcb_p->line, dcb_p->call_id, fname);
+ }
+
+ switch (media->type) {
+ case SDP_MEDIA_AUDIO:
+ gsmsdp_set_media_attributes(media->payloads[i].codec_type,
+ sdp_p, level,
+ (uint16_t)(media->payloads[i].local_rtp_pt));
+ break;
+ case SDP_MEDIA_VIDEO:
+ gsmsdp_set_video_media_attributes(media->payloads[i].codec_type,
+ cc_sdp_p, level,
+ (uint16_t)(media->payloads[i].local_rtp_pt));
+ break;
+ case SDP_MEDIA_APPLICATION:
+ gsmsdp_set_sctp_attributes (sdp_p, level, media);
+ break;
+ default:
+ GSM_ERR_MSG(GSM_L_C_F_PREFIX"SDP ERROR media %d for level %d is"
+ " not supported\n",
+ dcb_p->line, dcb_p->call_id, fname, media->level);
+ break;
+ }
+
+ }//end for
+
+ /*
+ * add the avt media type
+ */
+ if (media->avt_payload_type > RTP_NONE) {
+ result = sdp_add_media_payload_type(sdp_p, level,
+ (uint16_t)media->avt_payload_type,
+ SDP_PAYLOAD_NUMERIC);
+ if (result != SDP_SUCCESS) {
+ GSM_ERR_MSG(GSM_L_C_F_PREFIX"Adding AVT payload type failed\n",
+ dcb_p->line, dcb_p->call_id, fname);
+ }
+ gsmsdp_set_media_attributes(RTP_AVT, sdp_p, level,
+ (uint16_t) media->avt_payload_type);
+ }
+ }
+
+ if (!sdpmode)
+ gsmsdp_set_anat_attr(dcb_p, media);
+}
+
+/*
+ * gsmsdp_update_local_sdp
+ *
+ * Description:
+ *
+ * Updates the local SDP of the DCB based on the remote SDP.
+ *
+ * Parameters:
+ *
+ * dcb_p - Pointer to the DCB whose local SDP is to be updated.
+ * offer - Indicates whether the remote SDP was received in an offer
+ * or an answer.
+ * initial_offer - this media line is initial offer.
+ * media - Pointer to fsmdef_media_t for the media entry of the SDP.
+ *
+ * Return:
+ * TRUE - update the local SDP was successfull.
+ * FALSE - update the local SDP failed.
+ */
+static boolean
+gsmsdp_update_local_sdp (fsmdef_dcb_t *dcb_p, boolean offer,
+ boolean initial_offer,
+ fsmdef_media_t *media)
+{
+ static const char fname[] = "gsmsdp_update_local_sdp";
+ cc_action_data_t data;
+ sdp_direction_e direction;
+ boolean local_hold = (boolean)FSM_CHK_FLAGS(media->hold, FSM_HOLD_LCL);
+
+ if (media->src_port == 0) {
+ GSM_DEBUG(DEB_L_C_F_PREFIX"allocate receive port for media line\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname));
+ /*
+ * Source port has not been allocated, this could mean we
+ * processing an initial offer SDP, SDP that requets to insert
+ * a media line or re-insert a media line.
+ */
+ data.open_rcv.is_multicast = FALSE;
+ data.open_rcv.listen_ip = ip_addr_invalid;
+ data.open_rcv.port = 0;
+ data.open_rcv.keep = FALSE;
+ /*
+ * Indicate type of media (audio/video etc) becase some for supporting
+ * video over vieo, the port is obtained from other entity.
+ */
+ data.open_rcv.media_type = media->type;
+ data.open_rcv.media_refid = media->refid;
+ if (cc_call_action(dcb_p->call_id, dcb_p->line, CC_ACTION_OPEN_RCV,
+ &data) == CC_RC_SUCCESS) {
+ /* allocate port successful, save the port */
+ media->src_port = data.open_rcv.port;
+ media->rcv_chan = FALSE; /* mark no RX chan yet */
+ } else {
+ GSM_ERR_MSG(GSM_L_C_F_PREFIX"allocate rx port failed\n",
+ dcb_p->line, dcb_p->call_id, fname);
+ return (FALSE);
+ }
+ }
+
+ /*
+ * Negotiate direction based on remote SDP.
+ */
+ direction = gsmsdp_negotiate_local_sdp_direction(dcb_p, media, local_hold);
+
+ /*
+ * Update Transmit SRTP transmit key if this SRTP session.
+ */
+ if (media->transport == SDP_TRANSPORT_RTPSAVP) {
+ gsmsdp_update_crypto_transmit_key(dcb_p, media, offer,
+ initial_offer, direction);
+ }
+
+ if (offer == TRUE) {
+ gsmsdp_update_local_sdp_media(dcb_p, dcb_p->sdp, FALSE, media,
+ media->transport);
+ }
+
+ /*
+ * Set local sdp direction.
+ */
+ if (media->direction_set) {
+ if (media->direction != direction) {
+ gsmsdp_set_local_sdp_direction(dcb_p, media, direction);
+ }
+ } else {
+ gsmsdp_set_local_sdp_direction(dcb_p, media, direction);
+ }
+ return (TRUE);
+}
+
+/*
+ * gsmsdp_update_local_sdp_for_multicast
+ *
+ * Description:
+ *
+ * Updates the local SDP of the DCB based on the remote SDP for
+ * multicast. Populates the local sdp with the same addr:port as
+ * in the offer and the same direction as in the offer (as per
+ * rfc3264).
+ *
+ * Parameters:
+ *
+ * dcb_p - Pointer to the DCB whose local SDP is to be updated.
+ * portnum - Remote port.
+ * media - Pointer to fsmdef_media_t for the media entry of the SDP.
+ * offer - boolean indicating an offer SDP if true.
+ * initial_offer - boolean indicating an initial offer SDP if true.
+ *
+ */
+static boolean
+gsmsdp_update_local_sdp_for_multicast (fsmdef_dcb_t *dcb_p,
+ uint16_t portnum,
+ fsmdef_media_t *media,
+ boolean offer,
+ boolean initial_offer)
+{
+ static const char fname[] = "gsmsdp_update_local_sdp_for_multicast";
+ sdp_direction_e direction;
+ char addr_str[MAX_IPADDR_STR_LEN];
+ uint16_t level;
+ char *p_addr_str;
+ char *strtok_state;
+
+ level = media->level;
+
+ GSM_DEBUG(DEB_L_C_F_PREFIX"%d %d %d\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname),
+ portnum, level, initial_offer);
+
+ direction = gsmsdp_get_remote_sdp_direction(dcb_p, media->level,
+ &media->dest_addr);
+ GSM_DEBUG(DEB_L_C_F_PREFIX"sdp direction: %d\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname), direction);
+ /*
+ * Update Transmit SRTP transmit key any way to clean up the
+ * tx condition that we may have offered prior.
+ */
+ gsmsdp_update_crypto_transmit_key(dcb_p, media, offer, initial_offer,
+ direction);
+
+ gsmsdp_update_local_sdp_media(dcb_p, dcb_p->sdp, FALSE,
+ media, media->transport);
+
+ /*
+ * Set local sdp direction same as on remote SDP for multicast
+ */
+ if ((direction == SDP_DIRECTION_RECVONLY) || (direction == SDP_DIRECTION_INACTIVE)) {
+ if ((media->support_direction == SDP_DIRECTION_SENDRECV) ||
+ (media->support_direction == SDP_DIRECTION_RECVONLY)) {
+ /*
+ * Echo same direction back in our local SDP but set the direction
+ * in DCB to recvonly so that LSM operations on rcv port work
+ * without modification.
+ */
+ } else {
+ direction = SDP_DIRECTION_INACTIVE;
+ GSM_DEBUG(DEB_L_C_F_PREFIX"media line"
+ " does not support receive stream\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname));
+ }
+ gsmsdp_set_local_sdp_direction(dcb_p, media, direction);
+ media->direction_set = TRUE;
+ } else {
+ /*
+ * return FALSE indicating error
+ */
+ return (FALSE);
+ }
+
+ /*
+ * Set the ip addr to the multicast ip addr.
+ */
+ ipaddr2dotted(addr_str, &media->dest_addr);
+ p_addr_str = PL_strtok_r(addr_str, "[ ]", &strtok_state);
+
+ /*
+ * Set the local SDP port number to match far ends port number.
+ */
+ (void) sdp_set_media_portnum(dcb_p->sdp->src_sdp, level, portnum, 0);
+
+ /*
+ * c= line
+ */
+ (void) sdp_set_conn_nettype(dcb_p->sdp->src_sdp, level, SDP_NT_INTERNET);
+ (void) sdp_set_conn_addrtype(dcb_p->sdp->src_sdp, level, media->addr_type);
+ (void) sdp_set_conn_address(dcb_p->sdp->src_sdp, level, p_addr_str);
+
+ return (TRUE);
+}
+
+/*
+ * gsmsdp_get_remote_avt_payload_type
+ *
+ * Description:
+ *
+ * Returns the AVT payload type of the given audio line in the specified SDP.
+ *
+ * Parameters:
+ *
+ * level - The media level of the SDP where the media attribute is to be found.
+ * sdp_p - Pointer to the SDP whose AVT payload type is being searched.
+ *
+ */
+static int
+gsmsdp_get_remote_avt_payload_type (uint16_t level, void *sdp_p)
+{
+ uint16_t i;
+ uint16_t ptype;
+ int remote_avt_payload_type = RTP_NONE;
+ uint16_t num_a_lines = 0;
+ const char *encname = NULL;
+
+ /*
+ * Get number of RTPMAP attributes for the media line
+ */
+ (void) sdp_attr_num_instances(sdp_p, level, 0, SDP_ATTR_RTPMAP,
+ &num_a_lines);
+
+ /*
+ * Loop through AUDIO media line RTPMAP attributes. The last
+ * NET dynamic payload type will be returned.
+ */
+ for (i = 0; i < num_a_lines; i++) {
+ ptype = sdp_attr_get_rtpmap_payload_type(sdp_p, level, 0,
+ (uint16_t) (i + 1));
+ if (sdp_media_dynamic_payload_valid(sdp_p, ptype, level)) {
+ encname = sdp_attr_get_rtpmap_encname(sdp_p, level, 0,
+ (uint16_t) (i + 1));
+ if (encname) {
+ if (cpr_strcasecmp(encname, SIPSDP_ATTR_ENCNAME_TEL_EVENT) == 0) {
+ remote_avt_payload_type = ptype;
+ }
+ }
+ }
+ }
+ return (remote_avt_payload_type);
+}
+
+
+#define MIX_NEAREND_STRING "X-mix-nearend"
+
+/*
+ * gsmsdp_negotiate_codec
+ *
+ * Description:
+ *
+ * Negotiates an acceptable codec from the local and remote SDPs
+ *
+ * Parameters:
+ *
+ * dcb_p - Pointer to DCB whose codec is being negotiated
+ * sdp_p - Pointer to local and remote SDP
+ * media - Pointer to the fsmdef_media_t for a given media entry whose
+ * codecs are being negotiated.
+ * offer - Boolean indicating if the remote SDP came in an OFFER.
+ *
+ * Returns:
+ *
+ * codec > 0: most preferred negotiated codec
+ * <= 0: negotiation failed
+ */
+static int
+gsmsdp_negotiate_codec (fsmdef_dcb_t *dcb_p, cc_sdp_t *sdp_p,
+ fsmdef_media_t *media, boolean offer,
+ boolean initial_offer, uint16 media_level)
+{
+ static const char fname[] = "gsmsdp_negotiate_codec";
+ rtp_ptype pref_codec = RTP_NONE;
+ uint16_t i;
+ uint16_t j;
+ int *master_list_p = NULL;
+ int *slave_list_p = NULL;
+ DtmfOutOfBandTransport_t transport = DTMF_OUTOFBAND_NONE;
+ int avt_payload_type;
+ uint16_t num_remote_types;
+ uint16_t num_local_types;
+ uint16_t num_master_types;
+ uint16_t num_slave_types;
+ int remote_codecs[CC_MAX_MEDIA_TYPES];
+ int remote_payload_types[CC_MAX_MEDIA_TYPES];
+ int local_codecs[CC_MAX_MEDIA_TYPES];
+ sdp_payload_ind_e pt_indicator;
+ uint32 ptime = 0;
+ uint32 maxptime = 0;
+ const char* attr_label;
+ uint16_t level;
+ boolean explicit_reject = FALSE;
+ boolean found_codec = FALSE;
+ // int32_t num_match_payloads = 0;
+ int codec = RTP_NONE;
+ int remote_pt = RTP_NONE;
+ int32_t payload_types_count = 0; /* count for allocating right amout
+ of memory for media->payloads */
+ int temp;
+ u16 a_inst;
+ vcm_payload_info_t *payload_info = NULL;
+ vcm_payload_info_t *previous_payload_info;
+
+ if (!dcb_p || !sdp_p || !media) {
+ return (RTP_NONE);
+ }
+
+ level = media_level;
+ attr_label = sdp_attr_get_simple_string(sdp_p->dest_sdp,
+ SDP_ATTR_LABEL, level, 0, 1);
+
+ if (attr_label != NULL) {
+ if (strcmp(attr_label, MIX_NEAREND_STRING) == 0) {
+ dcb_p->session = WHISPER_COACHING;
+ }
+ }
+ /*
+ * Obtain list of payload types from the remote SDP
+ */
+ num_remote_types = sdp_get_media_num_payload_types(sdp_p->dest_sdp, level);
+
+ if (num_remote_types > CC_MAX_MEDIA_TYPES) {
+ num_remote_types = CC_MAX_MEDIA_TYPES;
+ }
+
+ for (i = 0; i < num_remote_types; i++) {
+ temp = sdp_get_media_payload_type(sdp_p->dest_sdp, level,
+ (uint16_t) (i + 1), &pt_indicator);
+ remote_codecs[i] = GET_CODEC_TYPE(temp);
+ remote_payload_types[i] = GET_DYN_PAYLOAD_TYPE_VALUE(temp);
+ }
+
+ /*
+ * Get all the codecs that the phone supports.
+ */
+ if (media->type == SDP_MEDIA_AUDIO) {
+ num_local_types = sip_config_local_supported_codecs_get(
+ (rtp_ptype *)local_codecs,
+ CC_MAX_MEDIA_TYPES);
+ } else if (media->type == SDP_MEDIA_VIDEO) {
+ num_local_types = sip_config_video_supported_codecs_get(
+ (rtp_ptype *)local_codecs, CC_MAX_MEDIA_TYPES, offer);
+ } else {
+ GSM_DEBUG(DEB_L_C_F_PREFIX"unsupported media type %d\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname),
+ media->type);
+ return (RTP_NONE);
+ }
+
+ /*
+ * Set the AVT payload type to whatever value the farend wants to use,
+ * but only if we have AVT turned on and the farend wants it
+ * or if we are configured to always send it
+ */
+ config_get_value(CFGID_DTMF_OUTOFBAND, &transport, sizeof(transport));
+
+ /*
+ * Save AVT payload type for use by gsmsdp_compare_to_previous_sdp
+ */
+ media->previous_sdp.avt_payload_type = media->avt_payload_type;
+
+ switch (transport) {
+ case DTMF_OUTOFBAND_AVT:
+ avt_payload_type = gsmsdp_get_remote_avt_payload_type(
+ media->level, sdp_p->dest_sdp);
+ if (avt_payload_type > RTP_NONE) {
+ media->avt_payload_type = avt_payload_type;
+ } else {
+ media->avt_payload_type = RTP_NONE;
+ }
+ break;
+
+ case DTMF_OUTOFBAND_AVT_ALWAYS:
+ avt_payload_type = gsmsdp_get_remote_avt_payload_type(
+ media->level, sdp_p->dest_sdp);
+ if (avt_payload_type > RTP_NONE) {
+ media->avt_payload_type = avt_payload_type;
+ } else {
+ /*
+ * If we are AVT_ALWAYS and the remote end is not using AVT,
+ * then send DTMF as out-of-band and use our configured
+ * payload type.
+ */
+ config_get_value(CFGID_DTMF_AVT_PAYLOAD,
+ &media->avt_payload_type,
+ sizeof(media->avt_payload_type));
+
+ GSM_DEBUG(DEB_L_C_F_PREFIX"AVT_ALWAYS forcing out-of-band DTMF,"
+ " payload_type = %d\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line,
+ dcb_p->call_id, fname),
+ media->avt_payload_type);
+ }
+ break;
+
+ case DTMF_OUTOFBAND_NONE:
+ default:
+ media->avt_payload_type = RTP_NONE;
+ break;
+ }
+
+ /*
+ * Find a matching codec in our local list with the remote list.
+ * The local list was created with our preferred codec first in the list,
+ * so this will ensure that we will match the preferred codec with the
+ * remote list first, before matching other codecs.
+ */
+ pref_codec = sip_config_preferred_codec();
+ if (pref_codec != RTP_NONE) {
+ /*
+ * If a preferred codec was configured and the platform
+ * currently can do this codec, then it would be the
+ * first element of the local_codecs because of the
+ * logic in sip_config_local_supported_codec_get().
+ */
+ if (local_codecs[0] != pref_codec) {
+ /*
+ * preferred codec is configured but it is not avaible
+ * currently, treat it as there is no codec available.
+ */
+ pref_codec = RTP_NONE;
+ }
+ }
+
+ if (pref_codec == RTP_NONE) {
+ master_list_p = remote_codecs;
+ slave_list_p = local_codecs;
+ num_master_types = num_remote_types;
+ num_slave_types = num_local_types;
+ GSM_DEBUG(DEB_L_C_F_PREFIX"Remote Codec list is Master\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname));
+ } else {
+ master_list_p = local_codecs;
+ slave_list_p = remote_codecs;
+ num_master_types = num_local_types;
+ num_slave_types = num_remote_types;
+ GSM_DEBUG(DEB_L_C_F_PREFIX"Local Codec list is Master\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname));
+ }
+
+ /*
+ * Save payload information for use by gsmspd_compare_to_previous_sdp
+ */
+ gsmsdp_copy_payloads_to_previous_sdp(media);
+
+ /*
+ * Setup payload info structure list to store matched payload details
+ * in the SDP.
+ */
+ media->num_payloads = 0;
+ if(num_master_types <= num_slave_types ) {
+ payload_types_count = num_master_types;
+ } else {
+ payload_types_count = num_slave_types;
+ }
+
+ /* Remove any previously allocated lists */
+ if (media->payloads) {
+ cpr_free(media->payloads);
+ }
+
+ /* Allocate memory for PT value, local PT and remote PT. */
+ media->payloads = cpr_calloc(payload_types_count,
+ sizeof(vcm_payload_info_t));
+
+ /* Store the ptime and maxptime parameter for this m= section */
+ if (media->type == SDP_MEDIA_AUDIO) {
+ ptime = sdp_attr_get_simple_u32(sdp_p->dest_sdp,
+ SDP_ATTR_PTIME, level, 0, 1);
+ if (ptime != 0) {
+ media->packetization_period = (uint16_t) ptime;
+ }
+ maxptime = sdp_attr_get_simple_u32(sdp_p->dest_sdp,
+ SDP_ATTR_MAXPTIME, level, 0, 1);
+ if (maxptime != 0) {
+ media->max_packetization_period = (uint16_t) maxptime;
+ }
+ }
+
+ for (i = 0; i < num_master_types; i++) {
+ for (j = 0; j < num_slave_types; j++) {
+ if (master_list_p[i] == slave_list_p[j]) {
+
+ /* We've found a codec in common. Configure the coresponding
+ payload information structure */
+ codec = slave_list_p[j];
+ payload_info = &(media->payloads[media->num_payloads]);
+
+ if (master_list_p == remote_payload_types) {
+ remote_pt = remote_payload_types[i];
+ } else {
+ remote_pt = remote_payload_types[j];
+ }
+
+ payload_info->codec_type = codec;
+ payload_info->local_rtp_pt = remote_pt;
+ payload_info->remote_rtp_pt = remote_pt;
+
+ /* If the negotiated payload type in an answer is different from
+ what we sent in our offer, we set the local payload type to
+ our default (since that's what we put in our offer) */
+ if (!offer) {
+ previous_payload_info =
+ gsmsdp_find_info_for_codec(codec,
+ media->previous_sdp.payloads,
+ media->previous_sdp.num_payloads, 0);
+ if ((previous_payload_info == NULL) ||
+ (previous_payload_info->local_rtp_pt
+ != payload_info->local_rtp_pt)) {
+ payload_info->local_rtp_pt = codec;
+ }
+ }
+
+ if (media->type == SDP_MEDIA_AUDIO) {
+
+ if (sdp_attr_rtpmap_payload_valid(sdp_p->dest_sdp, level, 0,
+ &a_inst, remote_pt) ) {
+ /* Set the number of channels -- if omitted,
+ default is 1 */
+ payload_info->audio.channels =
+ sdp_attr_get_rtpmap_num_chan(sdp_p->dest_sdp,
+ level, 0, a_inst);
+ if (payload_info->audio.channels == 0) {
+ payload_info->audio.channels = 1;
+ }
+
+ /* Set frequency = clock rate. This is generally
+ correct. Codecs can override this assumption on a
+ case-by-case basis in the switch construct below. */
+ payload_info->audio.frequency =
+ sdp_attr_get_rtpmap_clockrate(sdp_p->dest_sdp,
+ level, 0, a_inst);
+ } else {
+ GSM_DEBUG(DEB_L_C_F_PREFIX"Could not find rtpmap "
+ "entry for payload %d -- setting defaults\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line,
+ dcb_p->call_id, fname), codec);
+ payload_info->audio.channels = 1;
+ /* See http://www.iana.org/assignments/rtp-parameters/
+ rtp-parameters.xml */
+ switch (codec) {
+ case STATIC_RTP_AVP_DVI4_16000_1:
+ codec = RTP_DVI4;
+ payload_info->audio.frequency = 16000;
+ break;
+ case STATIC_RTP_AVP_L16_44100_2:
+ codec = RTP_L16;
+ payload_info->audio.frequency = 44100;
+ payload_info->audio.channels = 2;
+ break;
+ case STATIC_RTP_AVP_L16_44100_1:
+ codec = RTP_L16;
+ payload_info->audio.frequency = 44100;
+ break;
+ case STATIC_RTP_AVP_DVI4_11025_1:
+ codec = RTP_DVI4;
+ payload_info->audio.frequency = 11025;
+ break;
+ case STATIC_RTP_AVP_DVI4_22050_1:
+ codec = RTP_DVI4;
+ payload_info->audio.frequency = 22050;
+ break;
+ default:
+ payload_info->audio.frequency = 8000;
+ }
+ }
+
+
+ switch (codec) {
+ case RTP_PCMA:
+ case RTP_PCMU:
+ /* 20 ms = 1/50th of a second */
+ payload_info->audio.packet_size =
+ payload_info->audio.frequency / 50;
+
+ payload_info->audio.bitrate = 8 *
+ payload_info->audio.frequency *
+ payload_info->audio.channels;
+ break;
+
+
+ case RTP_OPUS:
+ if (!sdp_attr_rtpmap_payload_valid(sdp_p->dest_sdp,
+ level, 0, &a_inst, remote_pt) ||
+ (payload_info->audio.frequency
+ != RTPMAP_OPUS_CLOCKRATE) ||
+ (payload_info->audio.channels != 2)) {
+
+ /* Be conservative in what we accept: any
+ implementation that does not use a 48 kHz
+ clockrate or 2 channels is broken. */
+ explicit_reject = TRUE;
+ continue; // keep looking
+ }
+
+ /* ********************************************* */
+ /* TODO !! FIXME !! XXX
+ * We can't support two-channel Opus until we merge
+ * in webrtc.org upstream, rev 3050 or later. See
+ http://code.google.com/p/webrtc/issues/detail?id=1013
+ * for details. We also need to have proper
+ * handling of the sprop-stereo and stereo SDP
+ * values before we use stereo encoding/decoding.
+ * Details in Mozilla Bug 818618.
+ */
+ payload_info->audio.channels = 1;
+ /* ********************************************* */
+
+ /* Store fmtp options */
+ sdp_attr_get_fmtp_max_average_bitrate (
+ sdp_p->dest_sdp, level, 0, 1,
+ &payload_info->opus.max_average_bitrate);
+
+ payload_info->opus.maxcodedaudiobandwidth =
+ sdp_attr_get_fmtp_maxcodedaudiobandwidth(
+ sdp_p->dest_sdp, level, 0, 1);
+
+ sdp_attr_get_fmtp_usedtx (sdp_p->dest_sdp, level, 0,
+ 1, &payload_info->opus.usedtx);
+
+ sdp_attr_get_fmtp_stereo (sdp_p->dest_sdp, level, 0,
+ 1, &payload_info->opus.stereo);
+
+ sdp_attr_get_fmtp_useinbandfec (sdp_p->dest_sdp,
+ level, 0, 1, &payload_info->opus.useinbandfec);
+
+ sdp_attr_get_fmtp_cbr (sdp_p->dest_sdp, level, 0, 1,
+ &payload_info->opus.cbr);
+
+ /* Copied from media/webrtc/trunk/src/modules/
+ audio_coding/main/source/acm_codec_database.cc */
+ payload_info->audio.frequency = 32000;
+ payload_info->audio.packet_size = 960;
+ payload_info->audio.bitrate = 32000;
+ break;
+
+ case RTP_ISAC:
+ /* TODO: Update these from proper SDP constructs */
+ payload_info->audio.frequency = 16000;
+ payload_info->audio.packet_size = 480;
+ payload_info->audio.bitrate = 32000;
+ break;
+
+ case RTP_ILBC:
+ payload_info->ilbc.mode =
+ (uint16_t)sdp_attr_get_fmtp_mode_for_payload_type(
+ sdp_p->dest_sdp, level, 0, remote_pt);
+
+ /* TODO -- These should be updated to reflect the
+ actual frequency */
+ if (payload_info->ilbc.mode == SIPSDP_ILBC_MODE20)
+ {
+ payload_info->audio.packet_size = 160;
+ payload_info->audio.bitrate = 15200;
+ }
+ else /* mode = 30 */
+ {
+ payload_info->audio.packet_size = 240;
+ payload_info->audio.bitrate = 13300;
+ }
+ break;
+
+ default:
+ GSM_DEBUG(DEB_L_C_F_PREFIX"codec=%d not setting "
+ "codec parameters (not implemented)\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line,
+ dcb_p->call_id, fname), codec);
+ payload_info->audio.packet_size = -1;
+ payload_info->audio.bitrate = -1;
+ } /* end switch */
+
+
+ } else if (media->type == SDP_MEDIA_VIDEO) {
+ if ( media-> video != NULL ) {
+ vcmFreeMediaPtr(media->video);
+ media->video = NULL;
+ }
+
+ if (!vcmCheckAttribs(codec, sdp_p, level,
+ &media->video)) {
+ GSM_DEBUG(DEB_L_C_F_PREFIX"codec= %d ignored - "
+ "attribs not accepted\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line,
+ dcb_p->call_id, fname), codec);
+ explicit_reject = TRUE;
+ continue; /* keep looking */
+ }
+
+ /* cache the negotiated profile_level and bandwidth */
+ media->previous_sdp.tias_bw = media->tias_bw;
+ media->tias_bw = ccsdpGetBandwidthValue(sdp_p,level, 1);
+ if ( (attr_label =
+ ccsdpAttrGetFmtpProfileLevelId(sdp_p,level,0,1))
+ != NULL ) {
+ media->previous_sdp.profile_level =
+ media->profile_level;
+ sscanf(attr_label,"%x", &media->profile_level);
+ }
+
+ /* This should ultimately use RFC 6236 a=imageattr
+ if present */
+ switch (codec) {
+ case RTP_VP8:
+ payload_info->video.width = 640;
+ payload_info->video.height = 480;
+ break;
+ case RTP_I420:
+ payload_info->video.width = 176;
+ payload_info->video.height = 144;
+ break;
+ default:
+ GSM_DEBUG(DEB_L_C_F_PREFIX"codec=%d not setting "
+ "codec parameters (not implemented)\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line,
+ dcb_p->call_id, fname), codec);
+ payload_info->video.width = -1;
+ payload_info->video.height = -1;
+ }
+ } /* end video */
+
+ GSM_DEBUG(DEB_L_C_F_PREFIX"codec= %d\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line,
+ dcb_p->call_id, fname), codec);
+
+
+ found_codec = TRUE;
+ if(media->num_payloads >= payload_types_count) {
+ /* We maxed our allocated memory -- processing is done. */
+ return codec;
+ }
+
+ /* Incrementing this number serves as a "commit" for the
+ payload_info. If we bail out of the loop before this
+ happens, then the collected information is abandoned. */
+ media->num_payloads++;
+
+ if(offer) {
+ /* If we are creating an answer, return after the first match.
+ TODO -- Eventually, we'll (probably) want to answer with
+ all the codecs we can receive. See bug 814227. */
+ return codec;
+ }
+ }
+ }
+ }
+
+ /* Return the most preferred codec */
+ if(found_codec) {
+ return (media->payloads[0].codec_type);
+ }
+
+ /*
+ * CSCsv84705 - we could not negotiate a common codec because
+ * the local list is empty. This condition could happen when
+ * using g729 in locally mixed conference in which another call
+ * to vcm_get_codec_list() would return 0 or no codec. So if
+ * this is a not an init offer, we should just go ahead and use
+ * the last negotiated codec if the remote list matches with
+ * currently used.
+ */
+ if (!initial_offer && !explicit_reject) {
+ for (i = 0; i < num_remote_types; i++) {
+ if (media->num_payloads != 0 && media->payloads[0].codec_type ==
+ remote_payload_types[i]) {
+ GSM_DEBUG(DEB_L_C_F_PREFIX"local codec list was empty codec= %d"
+ " local=%d remote =%d\n", DEB_L_C_F_PREFIX_ARGS(GSM,
+ dcb_p->line, dcb_p->call_id, fname),
+ media->payloads[0].codec_type,
+ media->payloads[0].local_rtp_pt,
+ media->payloads[0].remote_rtp_pt);
+ return (media->payloads[0].codec_type);
+ }
+ }
+ }
+
+ return (RTP_NONE);
+}
+
+static void
+gsmsdp_negotiate_datachannel_attribs(fsmdef_dcb_t* dcb_p, cc_sdp_t* sdp_p, uint16_t level, fsmdef_media_t* media)
+{
+ uint32 num_streams;
+ // char *protocol;
+
+ sdp_attr_get_fmtp_streams (sdp_p->dest_sdp, level, 0, 1, &num_streams);
+
+ media->streams = num_streams;
+
+ if(media->protocol == NULL) {
+ media->protocol = cpr_malloc(SDP_MAX_STRING_LEN+1);
+ if (media->protocol == NULL)
+ return;
+ }
+ sdp_attr_get_fmtp_data_channel_protocol(sdp_p->dest_sdp, level, 0, 1, media->protocol);
+
+ media->sctp_port = sdp_attr_get_fmtp_payload_type (sdp_p->dest_sdp, level, 0, 1);
+
+ /* Increment port for answer SDP */
+ media->sctp_port++;
+}
+
+/*
+ * gsmsdp_add_unsupported_stream_to_local_sdp
+ *
+ * Description:
+ *
+ * Adds a rejected media line to the local SDP. If there is already a media line at
+ * the specified level, check to see if it matches the corresponding media line in the
+ * remote SDP. If it does not, remove the media line from the local SDP so that
+ * the corresponding remote SDP media line can be added. Note that port will be set
+ * to zero indicating the media line is rejected.
+ *
+ * Parameters:
+ *
+ * scp_p - Pointer to the local and remote SDP.
+ * level - The media line level being rejected.
+ */
+static void
+gsmsdp_add_unsupported_stream_to_local_sdp (cc_sdp_t *sdp_p,
+ uint16_t level)
+{
+ static const char fname[] = "gsmsdp_add_unsupported_stream_to_local_sdp";
+ uint32_t remote_pt;
+ sdp_payload_ind_e remote_pt_indicator;
+ // cpr_ip_addr_t addr;
+
+ if (sdp_p == NULL) {
+ GSM_ERR_MSG(GSM_F_PREFIX"sdp is null.\n", fname);
+ return;
+ }
+
+ if (sdp_get_media_type(sdp_p->src_sdp, level) != SDP_MEDIA_INVALID) {
+ sdp_delete_media_line(sdp_p->src_sdp, level);
+ }
+
+ if (sdp_p->dest_sdp == NULL) {
+ GSM_ERR_MSG(GSM_F_PREFIX"no remote SDP available\n", fname);
+ return;
+ }
+
+ /*
+ * Insert media line at the specified level.
+ */
+ if (sdp_insert_media_line(sdp_p->src_sdp, level) != SDP_SUCCESS) {
+ GSM_ERR_MSG(GSM_F_PREFIX"failed to insert a media line\n", fname);
+ return;
+ }
+
+ /*
+ * Set the attributes of the media line. Specify port = 0 to
+ * indicate media line is rejected.
+ */
+ (void) sdp_set_media_type(sdp_p->src_sdp, level,
+ sdp_get_media_type(sdp_p->dest_sdp, level));
+ (void) sdp_set_media_portnum(sdp_p->src_sdp, level, 0, 0);
+ (void) sdp_set_media_transport(sdp_p->src_sdp, level,
+ sdp_get_media_transport(sdp_p->dest_sdp, level));
+
+ remote_pt = sdp_get_media_payload_type(sdp_p->dest_sdp, level, 1,
+ &remote_pt_indicator);
+ /*
+ * Don't like having to cast the payload type but sdp_get_media_payload_type
+ * returns a uint32_t but sdp_add_media_payload_type takes a uint16_t payload type.
+ * This needs to be fixed in Rootbeer.
+ */
+ (void) sdp_add_media_payload_type(sdp_p->src_sdp, level,
+ (uint16_t) remote_pt,
+ remote_pt_indicator);
+ /*
+ * The rejected media line needs to have "c=" line since
+ * we currently do not include the "c=" at the session level.
+ * The sdp parser in other end point such as the SDP parser
+ * in the CUCM and in the phone ensures that there
+ * is at least one "c=" line that can be used with each media
+ * line. Such the parser will flag unsupported media line without
+ * "c=" in that media line and at the session as error.
+ *
+ * The solution to have "c=" at the session level and
+ * omitting "c=" at the media level all together can also
+ * resolve this problem. Since the phone is also supporting
+ * ANAT group for IPV4/IPV6 offering therefore selecting
+ * session level and determining not to include "c=" line
+ * at the media level can become complex. For this reason, the
+ * unsupported media line will have "c=" with 0.0.0.0 address instead.
+ */
+ gsmsdp_set_connection_address(sdp_p->src_sdp, level, "0.0.0.0");
+}
+
+/*
+ * gsmsdp_get_remote_media_address
+ *
+ * Description:
+ *
+ * Extract the remote address from the given sdp.
+ *
+ * Parameters:
+ *
+ * fcb_p - Pointer to the FCB containing thhe DCB whose media lines are
+ * being negotiated
+ * sdp_p - Pointer to the the remote SDP
+ * level - media line level.
+ * dest_addr - pointer to the cpr_ip_addr_t structure to return
+ * remote address.
+ *
+ * Returns:
+ * FALSE - fails.
+ * TRUE - success.
+ *
+ */
+static boolean
+gsmsdp_get_remote_media_address (fsmdef_dcb_t *dcb_p,
+ cc_sdp_t * sdp_p, uint16_t level,
+ cpr_ip_addr_t *dest_addr)
+{
+ const char fname[] = "gsmsdp_get_remote_media_address";
+ const char *addr_str = NULL;
+ int dns_err_code;
+ boolean stat;
+
+ *dest_addr = ip_addr_invalid;
+
+ stat = sdp_connection_valid(sdp_p->dest_sdp, level);
+ if (stat) {
+ addr_str = sdp_get_conn_address(sdp_p->dest_sdp, level);
+ } else {
+ /* Address not at the media level. Try the session level. */
+ stat = sdp_connection_valid(sdp_p->dest_sdp, SDP_SESSION_LEVEL);
+ if (stat) {
+ addr_str = sdp_get_conn_address(sdp_p->dest_sdp, SDP_SESSION_LEVEL);
+ }
+ }
+
+ if (stat && addr_str) {
+ /* Assume that this is dotted address */
+ if (str2ip(addr_str, dest_addr) != 0) {
+ /* It could be Fully Qualify DN, need to add DNS look up here */
+ dns_err_code = dnsGetHostByName(addr_str, dest_addr, 100, 1);
+ if (dns_err_code) {
+ *dest_addr = ip_addr_invalid;
+ stat = FALSE;
+ GSM_ERR_MSG(GSM_L_C_F_PREFIX"DNS remote address error %d"
+ " with media at %d\n", dcb_p->line, dcb_p->call_id,
+ fname, dns_err_code, level);
+ }
+ }
+ } else {
+ /*
+ * No address the media level or the session level.
+ */
+ GSM_ERR_MSG(GSM_L_C_F_PREFIX"No remote address from SDP with at %d\n",
+ dcb_p->line, dcb_p->call_id, fname, level);
+ }
+ /*
+ * Convert the remote address to host address to be used. It was
+ * found out that without doing so, the softphone can crash when
+ * in attempt to setup remote address to transmit API of DSP
+ * implementation on win32.
+ */
+ util_ntohl(dest_addr, dest_addr);
+ return (stat);
+}
+
+/* Function gsmsdp_is_multicast_address
+ *
+ * Inputs: - IP Address
+ *
+ * Returns: YES if is multicast address, no if otherwise
+ *
+ * Purpose: This is a utility function that tests to see if the passed
+ * address is a multicast address. It does so by verifying that the
+ * address is between 225.0.0.0 and 239.255.255.255.
+ *
+ * Note: Addresses passed are not in network byte order.
+ *
+ * Note2: Addresses between 224.0.0.0 and 224.255.255.225 are also multicast
+ * addresses, but 224.0.0.0 to 224.0.0.255 are reserved and it is recommended
+ * to start at 225.0.0.0. We need to research to see if this is a reasonable
+ * restriction.
+ *
+ */
+int
+gsmsdp_is_multicast_address (cpr_ip_addr_t theIpAddress)
+{
+ if (theIpAddress.type == CPR_IP_ADDR_IPV4) {
+ /*
+ * Address already in host format
+ */
+ if ((theIpAddress.u.ip4 >= MULTICAST_START_ADDRESS) &&
+ (theIpAddress.u.ip4 <= MULTICAST_END_ADDRESS)) {
+ return (TRUE);
+ }
+ } else {
+ //todo IPv6: Check IPv6 multicast address here.
+
+ }
+ return (FALSE);
+}
+
+/**
+ *
+ * The function assigns or associate the new media line in the
+ * offered SDP to an entry in the media capability table.
+ *
+ * @param[in]dcb_p - pointer to the fsmdef_dcb_t
+ * @param[in]sdp_p - pointer to cc_sdp_t that contains the retmote SDP.
+ * @param[in]level - uint16_t for media line level.
+ *
+ * @return Pointer to the fsmdef_media_t if successfully
+ * found the anat pair media line otherwise return NULL.
+ *
+ * @pre (dcb not_eq NULL)
+ * @pre (sdp_p not_eq NULL)
+ * @pre (media not_eq NULL)
+ */
+static fsmdef_media_t*
+gsmsdp_find_anat_media_line (fsmdef_dcb_t *dcb_p, cc_sdp_t *sdp_p, uint16_t level)
+{
+ fsmdef_media_t *anat_media = NULL;
+ u32 group_id_1, group_id_2;
+ u32 dst_mid, group_mid;
+ uint16_t num_group_lines= 0;
+ uint16_t num_anat_lines = 0;
+ uint16_t i;
+
+ /*
+ * Get number of ANAT groupings at the session level for the media line
+ */
+ (void) sdp_attr_num_instances(sdp_p->dest_sdp, SDP_SESSION_LEVEL, 0, SDP_ATTR_GROUP,
+ &num_group_lines);
+
+ for (i = 1; i <= num_group_lines; i++) {
+ if (sdp_get_group_attr(sdp_p->dest_sdp, SDP_SESSION_LEVEL, 0, i) == SDP_GROUP_ATTR_ANAT) {
+ num_anat_lines++;
+ }
+ }
+
+ for (i = 1; i <= num_anat_lines; i++) {
+
+ dst_mid = sdp_attr_get_simple_u32(sdp_p->dest_sdp, SDP_ATTR_MID, level, 0, 1);
+ group_id_1 = sdp_get_group_id(sdp_p->dest_sdp, SDP_SESSION_LEVEL, 0, i, 1);
+ group_id_2 = sdp_get_group_id(sdp_p->dest_sdp, SDP_SESSION_LEVEL, 0, i, 2);
+
+ if (dst_mid == group_id_1) {
+ GSMSDP_FOR_ALL_MEDIA(anat_media, dcb_p) {
+ group_mid = sdp_attr_get_simple_u32(sdp_p->src_sdp,
+ SDP_ATTR_MID, (uint16_t) group_id_2, 0, 1);
+ if (group_mid == group_id_2) {
+ /* found a match */
+ return (anat_media);
+ }
+ }
+ } else if (dst_mid == group_id_2) {
+ GSMSDP_FOR_ALL_MEDIA(anat_media, dcb_p) {
+ group_mid = sdp_attr_get_simple_u32(sdp_p->src_sdp,
+ SDP_ATTR_MID, (uint16_t) group_id_1, 0, 1);
+ if (group_mid == group_id_1) {
+ /* found a match */
+ return (anat_media);
+ }
+ }
+ }
+ }
+ return (anat_media);
+}
+
+/**
+ *
+ * The function validates if all the anat groupings
+ * have the right number of ids and their media type
+ * is not the same
+ *
+ * @param[in]sdp_p - pointer to the cc_sdp_t.
+ *
+ * @return TRUE - anat validation passes
+ * FALSE - anat validation fails
+ *
+ * @pre (dcb not_eq NULL)
+ * @pre (sdp_p not_eq NULL)
+ */
+static boolean
+gsmsdp_validate_anat (cc_sdp_t *sdp_p)
+{
+ u16 i, num_group_id;
+ u32 group_id_1, group_id_2;
+ sdp_media_e media_type_gid1, media_type_gid2;
+ uint16_t num_group_lines= 0;
+ uint16_t num_anat_lines = 0;
+
+ /*
+ * Get number of ANAT groupings at the session level for the media line
+ */
+ (void) sdp_attr_num_instances(sdp_p->dest_sdp, SDP_SESSION_LEVEL, 0, SDP_ATTR_GROUP,
+ &num_group_lines);
+
+ for (i = 1; i <= num_group_lines; i++) {
+ if (sdp_get_group_attr(sdp_p->dest_sdp, SDP_SESSION_LEVEL, 0, i) == SDP_GROUP_ATTR_ANAT) {
+ num_anat_lines++;
+ }
+ }
+
+ for (i = 1; i <= num_anat_lines; i++) {
+ num_group_id = sdp_get_group_num_id (sdp_p->dest_sdp, SDP_SESSION_LEVEL, 0, i);
+ if ((num_group_id <=0) || (num_group_id > 2)) {
+ /* This anat line has zero or more than two grouping, this is invalid */
+ return (FALSE);
+ } else if (num_group_id == 2) {
+ /* Make sure that these anat groupings are not of same type */
+ group_id_1 = sdp_get_group_id(sdp_p->dest_sdp, SDP_SESSION_LEVEL, 0, i, 1);
+ group_id_2 = sdp_get_group_id(sdp_p->dest_sdp, SDP_SESSION_LEVEL, 0, i, 2);
+ media_type_gid1 = sdp_get_media_type(sdp_p->dest_sdp, (u16) group_id_1);
+ media_type_gid2 = sdp_get_media_type(sdp_p->dest_sdp, (u16) group_id_2);
+ if (media_type_gid1 != media_type_gid2) {
+ /* Group id types do not match */
+ return (FALSE);
+ }
+ if (group_id_1 != sdp_attr_get_simple_u32(sdp_p->dest_sdp, SDP_ATTR_MID, (u16) group_id_1, 0, 1)) {
+ /* Group id does not match the mid at the corresponding line */
+ return (FALSE);
+ }
+ if (group_id_2 != sdp_attr_get_simple_u32(sdp_p->dest_sdp, SDP_ATTR_MID, (u16) group_id_2, 0, 1)) {
+ return (FALSE);
+ }
+ }
+ }
+
+ return (TRUE);
+}
+
+/**
+ *
+ * The function validates if all the destination
+ * Sdp m lines have mid values and if those mid values match
+ * the source Sdp mid values
+ *
+ * @param[in]sdp_p - pointer to the cc_sdp_t
+ * @param[in]level - uint16_t for media line level.
+ *
+ * @return TRUE - mid validation passes
+ * FALSE - mid validation fails
+ *
+ * @pre (dcb not_eq NULL)
+ * @pre (sdp_p not_eq NULL)
+ */
+static boolean
+gsmsdp_validate_mid (cc_sdp_t *sdp_p, uint16_t level)
+{
+ int32 src_mid, dst_mid;
+ u16 i;
+ uint16_t num_group_lines= 0;
+ uint16_t num_anat_lines = 0;
+
+ /*
+ * Get number of ANAT groupings at the session level for the media line
+ */
+ (void) sdp_attr_num_instances(sdp_p->dest_sdp, SDP_SESSION_LEVEL, 0, SDP_ATTR_GROUP,
+ &num_group_lines);
+
+ for (i = 1; i <= num_group_lines; i++) {
+ if (sdp_get_group_attr(sdp_p->dest_sdp, SDP_SESSION_LEVEL, 0, i) == SDP_GROUP_ATTR_ANAT) {
+ num_anat_lines++;
+ }
+ }
+
+
+ if (num_anat_lines > 0) {
+ dst_mid = sdp_attr_get_simple_u32(sdp_p->dest_sdp, SDP_ATTR_MID, level, 0, 1);
+ if (dst_mid == 0) {
+ return (FALSE);
+ }
+ if (sdp_get_group_attr(sdp_p->src_sdp, SDP_SESSION_LEVEL, 0, 1) == SDP_GROUP_ATTR_ANAT) {
+ src_mid = sdp_attr_get_simple_u32(sdp_p->src_sdp, SDP_ATTR_MID, level, 0, 1);
+ if (dst_mid != src_mid) {
+ return (FALSE);
+ }
+ }
+
+ }
+ return (TRUE);
+}
+
+/**
+ *
+ * The function negotiates the type of the media lines
+ * based on anat attributes and ipv4/ipv6 settinsg.
+ *
+ * @param[in]dcb_p - pointer to the fsmdef_dcb_t
+ * @param[in]media - pointer to the fsmdef_media_t
+ *
+ * @return TRUE - this media line can be kept
+ * FALSE - this media line can not be kept
+ *
+ * @pre (dcb not_eq NULL)
+ * @pre (sdp_p not_eq NULL)
+ */
+static boolean
+gsmsdp_negotiate_addr_type (fsmdef_dcb_t *dcb_p, fsmdef_media_t *media)
+{
+ static const char fname[] = "gsmsdp_negotiate_addr_type";
+ cpr_ip_type media_addr_type;
+ cpr_ip_mode_e ip_mode;
+ fsmdef_media_t *group_media;
+
+ media_addr_type = media->dest_addr.type;
+ if ((media_addr_type != CPR_IP_ADDR_IPV4) &&
+ (media_addr_type != CPR_IP_ADDR_IPV6)) {
+ /* Unknown/unsupported address type */
+ GSM_ERR_MSG(GSM_L_C_F_PREFIX"address type is not IPv4 or IPv6\n",
+ dcb_p->line, dcb_p->call_id, fname);
+ return (FALSE);
+ }
+ ip_mode = platform_get_ip_address_mode();
+ /*
+ * find out whether this media line is part of an ANAT group or not.
+ */
+ group_media = gsmsdp_find_anat_pair(dcb_p, media);
+
+ /*
+ * It is possible that we have a media sink/source device that
+ * attached to the phone, then we only accept IPV4 for these device.
+ *
+ * The code below is using FSM_MEDIA_F_SUPPORT_SECURITY as indication
+ * whether this media line is mapped to the off board device or not.
+ * When we get a better API to find out then use the better API than
+ * checking the FSM_MEDIA_F_SUPPORT_SECURITY.
+ */
+ if (!FSM_CHK_FLAGS(media->flags, FSM_MEDIA_F_SUPPORT_SECURITY)) {
+ if (media_addr_type != CPR_IP_ADDR_IPV4) {
+ /* off board device we do not allow other address type but IPV4 */
+ GSM_DEBUG(DEB_L_C_F_PREFIX"offboard device does not support IPV6\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname));
+ return (FALSE);
+ }
+
+ /*
+ * P2:
+ * Need an API to get address from the off board device. For now,
+ * use our local address.
+ */
+ if ((ip_mode == CPR_IP_MODE_DUAL) || (ip_mode == CPR_IP_MODE_IPV4)) {
+ if (group_media != NULL) {
+ /*
+ * this media line is part of ANAT group, keep the previous
+ * one negotiated media line.
+ */
+ return (FALSE);
+ }
+ gsmsdp_get_local_source_v4_address(media);
+ return (TRUE);
+ }
+ /* phone is IPV6 only mode */
+ return (FALSE);
+ }
+
+ if (ip_mode == CPR_IP_MODE_DUAL) {
+ /*
+ * In dual mode, IPV6 is preferred address type. If there is an
+ * ANAT then select the media line that has IPV6 address.
+ */
+ if (group_media == NULL) {
+ /*
+ * no pair media line found, this can be the first media
+ * line negotiate. Keep this media line for now.
+ */
+ if (media_addr_type == CPR_IP_ADDR_IPV4) {
+ gsmsdp_get_local_source_v4_address(media);
+ } else {
+ gsmsdp_get_local_source_v6_address(media);
+ }
+ return (TRUE);
+ }
+
+ /*
+ * Found a ANAT pair media structure that this media line
+ * is part of.
+ */
+ if (media_addr_type == CPR_IP_ADDR_IPV4) {
+ /*
+ * This media line is IPV4, keep the other line that have
+ * been accepted before i.e. it shows up first therefore
+ * the other one has preference.
+ */
+ return (FALSE);
+ }
+
+ /* This media line is IPV6 */
+ if (group_media->src_addr.type == CPR_IP_ADDR_IPV4) {
+ /*
+ * The previous media line part of ANAT group is IPV4. The
+ * phone policy is to select IPV6 for media stream. Remove
+ * the previous media line and keep this media line (IPV6).
+ */
+ gsmsdp_add_unsupported_stream_to_local_sdp(dcb_p->sdp,
+ group_media->level);
+ gsmsdp_remove_media(dcb_p, group_media);
+ /* set this media line source address to IPV6 */
+ gsmsdp_get_local_source_v6_address(media);
+ return (TRUE);
+ }
+ /*
+ * keep the previous one is also IPV6, remove this one i.e.
+ * the one found has higher preferecne although this is not
+ * a valid ANAT grouping.
+ */
+ return (FALSE);
+ }
+
+ /*
+ * The phone is not in dual mode, the address type must be from the media
+ * line must match the address type that the phone is supporting.
+ */
+ if ((ip_mode == CPR_IP_MODE_IPV6) &&
+ (media_addr_type == CPR_IP_ADDR_IPV4)) {
+ /* incompatible address type */
+ return (FALSE);
+ }
+ if ((ip_mode == CPR_IP_MODE_IPV4) &&
+ (media_addr_type == CPR_IP_ADDR_IPV6)) {
+ /* incompatible address type */
+ return (FALSE);
+ }
+
+ if (group_media != NULL) {
+ /*
+ * This meida line is part of an ANAT group, keep the previous
+ * media line and throw away this line.
+ */
+ return (FALSE);
+ }
+
+ /*
+ * We have a compatible address type, set the source address based on
+ * the address type from the remote media line.
+ */
+ if (media_addr_type == CPR_IP_ADDR_IPV4) {
+ gsmsdp_get_local_source_v4_address(media);
+ } else {
+ gsmsdp_get_local_source_v6_address(media);
+ }
+ /* keep this media line */
+ return (TRUE);
+}
+
+/**
+ *
+ * The function finds the best media capability that matches the offer
+ * media line according to the media table specified.
+ *
+ * @param[in]dcb_p - pointer to the fsmdef_dcb_t
+ * @param[in]sdp_p - pointer to cc_sdp_t that contains the retmote SDP.
+ * @param[in]media - pointer to the fsmdef_media_t.
+ * @param[in]media_table - media table to use (global or session)
+ *
+ * @return cap_index - the best match for the offer
+ *
+ * @pre (dcb_p not_eq NULL)
+ * @pre (sdp_p not_eq NULL)
+ * @pre (media not_eq NULL)
+ */
+static uint8_t
+gsmdsp_find_best_match_media_cap_index (fsmdef_dcb_t *dcb_p,
+ cc_sdp_t *sdp_p,
+ fsmdef_media_t *media,
+ media_table_e media_table)
+{
+ const cc_media_cap_t *media_cap;
+ uint8_t cap_index, candidate_cap_index;
+ boolean srtp_fallback;
+ sdp_direction_e remote_direction, support_direction;
+ sdp_transport_e remote_transport;
+ sdp_media_e media_type;
+
+ remote_transport = sdp_get_media_transport(sdp_p->dest_sdp, media->level);
+ remote_direction = gsmsdp_get_remote_sdp_direction(dcb_p, media->level,
+ &media->dest_addr);
+ srtp_fallback = sip_regmgr_srtp_fallback_enabled(dcb_p->line);
+ media_type = media->type;
+
+
+ /*
+ * Select the best suitable media capability entry that
+ * match this media line.
+ *
+ * The following rules are used:
+ *
+ * 1) rule out entry that is invalid or not enabled or with
+ * different media type.
+ * 2) rule out entry that has been used by other existing
+ * media line.
+ *
+ * After the above rules applies look for the better match for
+ * direction support and security support. The platform should
+ * arrange the capability table in preference order with
+ * higher prefered entry placed at the lower index in the table.
+ */
+ candidate_cap_index = CC_MAX_MEDIA_CAP;
+ for (cap_index = 0; cap_index < CC_MAX_MEDIA_CAP; cap_index++) {
+ /* Find the cap entry that has the same media type and enabled */
+ if (media_table == MEDIA_TABLE_GLOBAL) {
+ media_cap = &g_media_table.cap[cap_index];
+ } else {
+ media_cap = gsmsdp_get_media_cap_entry_by_index(cap_index,dcb_p);
+ }
+ if ((media_cap == NULL) || !media_cap->enabled ||
+ (media_cap->type != media_type)) {
+ /* does not exist, not enabled or not the same type */
+ continue;
+ }
+
+ /* Check for already in used */
+ if (gsmsdp_find_media_by_cap_index(dcb_p, cap_index) != NULL) {
+ /* this capability entry has been used */
+ continue;
+ }
+
+ /*
+ * Check for security support. The rules below attempts to
+ * use entry that support security unless there is no entry
+ * and the SRTP fallback is enabled. If the remote offer is not
+ * SRTP just ignore the supported security and proceed on i.e.
+ * any entry is ok.
+ */
+ if (remote_transport == SDP_TRANSPORT_RTPSAVP) {
+ if (!media_cap->support_security && !srtp_fallback) {
+ /*
+ * this entry does not support security and SRTP fallback
+ * is not enabled.
+ */
+ continue;
+ }
+ if (!media_cap->support_security) {
+ /*
+ * this entry is not support security but srtp fallback
+ * is enabled, it potentially can be used
+ */
+ candidate_cap_index = cap_index;
+ }
+ }
+
+ /*
+ * Check for suitable direction support. The rules for matching
+ * directions are not exact rules. Try to match the closely
+ * offer as much as possible. This is the best we know. We can
+ * not guess what the real capability of the offer may have or will
+ * change in the future (re-invite).
+ */
+ support_direction = media_cap->support_direction;
+ if (remote_direction == SDP_DIRECTION_INACTIVE) {
+ if (support_direction != SDP_DIRECTION_SENDRECV) {
+ /* prefer send and receive for inactive */
+ candidate_cap_index = cap_index;
+ }
+ } else if (remote_direction == SDP_DIRECTION_RECVONLY) {
+ if ((support_direction != SDP_DIRECTION_SENDRECV) &&
+ (support_direction != SDP_DIRECTION_SENDONLY)) {
+ /* incompatible direction */
+ continue;
+ } else if (support_direction != SDP_DIRECTION_SENDONLY) {
+ candidate_cap_index = cap_index;
+ }
+ } else if (remote_direction == SDP_DIRECTION_SENDONLY) {
+ if ((support_direction != SDP_DIRECTION_SENDRECV) &&
+ (support_direction != SDP_DIRECTION_RECVONLY)) {
+ /* incompatible direction */
+ continue;
+ } else if (support_direction != SDP_DIRECTION_RECVONLY) {
+ candidate_cap_index = cap_index;
+ }
+ } else if (remote_direction == SDP_DIRECTION_SENDRECV) {
+ if (support_direction != SDP_DIRECTION_SENDRECV) {
+ candidate_cap_index = cap_index;
+ }
+ }
+
+ if (candidate_cap_index == cap_index) {
+ /* this entry is not exactly best match, try other ones */
+ continue;
+ }
+ /* this is the first best match found, use it */
+ break;
+ }
+
+ if (cap_index == CC_MAX_MEDIA_CAP) {
+ if (candidate_cap_index != CC_MAX_MEDIA_CAP) {
+ /* We have a candidate entry to use */
+ cap_index = candidate_cap_index;
+ }
+ }
+
+ return cap_index;
+}
+
+/**
+ *
+ * The function finds the best media capability that matches the offer
+ * media line.
+ *
+ * @param[in]dcb_p - pointer to the fsmdef_dcb_t
+ * @param[in]sdp_p - pointer to cc_sdp_t that contains the retmote SDP.
+ * @param[in]media - pointer to the fsmdef_media_t.
+ *
+ * @return TRUE - successful assigning a capability entry
+ * to the media line.
+ * FALSE - failed to assign a capability entry to the
+ * media line.
+ *
+ * @pre (dcb_p not_eq NULL)
+ * @pre (sdp_p not_eq NULL)
+ * @pre (media not_eq NULL)
+ */
+static boolean
+gsmsdp_assign_cap_entry_to_incoming_media (fsmdef_dcb_t *dcb_p,
+ cc_sdp_t *sdp_p,
+ fsmdef_media_t *media)
+{
+ static const char fname[] = "gsmsdp_assign_cap_entry_to_incoming_media";
+ const cc_media_cap_t *media_cap;
+ uint8_t cap_index;
+ fsmdef_media_t *anat_media;
+
+ /*
+ * Find an existing media line that this media line belongs to the
+ * same media group. If found, the same cap_index will be used.
+ */
+ anat_media = gsmsdp_find_anat_media_line(dcb_p, sdp_p, media->level);
+ if (anat_media != NULL) {
+ media_cap = gsmsdp_get_media_cap_entry_by_index(anat_media->cap_index, dcb_p);
+ if (media_cap == NULL) {
+ GSM_ERR_MSG(GSM_L_C_F_PREFIX"no media capability\n",
+ dcb_p->line, dcb_p->call_id, fname);
+ return (FALSE);
+ }
+ gsmsdp_set_media_capability(media, media_cap);
+ /* found the existing media line in the same ANAT group */
+ media->cap_index = anat_media->cap_index;
+ return (TRUE);
+ }
+
+
+ cap_index = gsmdsp_find_best_match_media_cap_index(dcb_p,
+ sdp_p,
+ media,
+ MEDIA_TABLE_SESSION);
+
+ if (cap_index == CC_MAX_MEDIA_CAP) {
+ GSM_ERR_MSG(GSM_L_C_F_PREFIX"reached max streams supported or"
+ " no suitable media capability\n",
+ dcb_p->line, dcb_p->call_id, fname);
+ return (FALSE);
+ }
+
+ /* set the capabilities to the media and associate with it */
+ media_cap = gsmsdp_get_media_cap_entry_by_index(cap_index,dcb_p);
+ if (media_cap == NULL) {
+ GSM_ERR_MSG(GSM_L_C_F_PREFIX"no media cap\n",
+ dcb_p->line, dcb_p->call_id, fname);
+ return (FALSE);
+ }
+ gsmsdp_set_media_capability(media, media_cap);
+
+ /* override the direction for special feature */
+ gsmsdp_feature_overide_direction(dcb_p, media);
+ if (media->support_direction == SDP_DIRECTION_INACTIVE) {
+ GSM_DEBUG(DEB_L_C_F_PREFIX"feature overrides direction to inactive,"
+ " no capability assigned\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname));
+ return (FALSE);
+ }
+
+ media->cap_index = cap_index;
+ GSM_DEBUG(DEB_L_C_F_PREFIX"assign media cap index %d\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname), cap_index);
+ return (TRUE);
+}
+
+/**
+ *
+ * The function handles negotiate adding of a media line.
+ *
+ * @param[in]dcb_p - pointer to the fsmdef_dcb_t
+ * @param[in]media_type - media type.
+ * @param[in]level - media line.
+ * @param[in]remote_port - remote port
+ * @param[in]offer - boolean indicates offer or answer.
+ *
+ * @return pointer to fsmdef_media_t if media is successfully
+ * added or return NULL.
+ *
+ * @pre (dcb_p not_eq NULL)
+ * @pre (sdp_p not_eq NULL)
+ * @pre (remote_addr not_eq NULL)
+ */
+static fsmdef_media_t *
+gsmsdp_negotiate_add_media_line (fsmdef_dcb_t *dcb_p,
+ sdp_media_e media_type,
+ uint16_t level,
+ uint16_t remote_port,
+ boolean offer)
+{
+ static const char fname[] = "gsmsdp_negotiate_add_media_line";
+ fsmdef_media_t *media;
+
+ if (remote_port == 0) {
+ /*
+ * This media line is new but marked as disbaled.
+ */
+ return (NULL);
+ }
+
+ if (!offer) {
+ /*
+ * This is not an offer, the remote end wants to add
+ * a new media line in the answer.
+ */
+ GSM_ERR_MSG(GSM_L_C_F_PREFIX"remote trying add media in answer SDP\n",
+ dcb_p->line, dcb_p->call_id, fname);
+ return (NULL);
+ }
+
+ /*
+ * Allocate a new raw media structure but not filling completely yet.
+ */
+ media = gsmsdp_get_new_media(dcb_p, media_type, level);
+ if (media == NULL) {
+ /* unable to add another media */
+ return (NULL);
+ }
+
+ /*
+ * If this call is locally held, mark the media with local hold so
+ * that the negotiate direction will have the correct direction.
+ */
+ if ((dcb_p->fcb->state == FSMDEF_S_HOLDING) ||
+ (dcb_p->fcb->state == FSMDEF_S_HOLD_PENDING)) {
+ /* the call is locally held, set the local held status */
+ FSM_SET_FLAGS(media->hold, FSM_HOLD_LCL);
+ }
+ return (media);
+}
+
+/**
+ *
+ * The function handles negotiate remove of a media line. Note the
+ * removal of a media line does not actaully removed from the offer/answer
+ * SDP.
+ *
+ * @param[in]dcb_p - pointer to the fsmdef_dcb_t
+ * @param[in]media - pointer to the fsmdef_media_t for the media entry
+ * to deactivate.
+ * @param[in]remote_port - remote port from the remote's SDP.
+ * @param[in]offer - boolean indicates offer or answer.
+ *
+ * @return TRUE - when line is inactive.
+ * FALSE - when line remains to be further processed.
+ *
+ * @pre (dcb not_eq NULL) and (media not_eq NULL)
+ */
+static boolean
+gsmsdp_negotiate_remove_media_line (fsmdef_dcb_t *dcb_p,
+ fsmdef_media_t *media,
+ uint16_t remote_port,
+ boolean offer)
+{
+ static const char fname[] = "gsmsdp_negotiate_remove_media_line";
+
+ if (offer) {
+ /* This is an offer SDP from the remote */
+ if (remote_port != 0) {
+ /* the remote quests media is not for removal */
+ return (FALSE);
+ }
+ /*
+ * Remote wants to remove the media line or to keep the media line
+ * disabled. Fall through.
+ */
+ } else {
+ /* This is an answer SDP from the remote */
+ if ((media->src_port != 0) && (remote_port != 0)) {
+ /* the media line is not for removal */
+ return (FALSE);
+ }
+ /*
+ * There are 3 possible causes:
+ * 1) our offered port is 0 and remote's port is 0
+ * 2) our offered port is 0 and remote's port is not 0.
+ * 3) our offered port is not 0 and remote's port is 0.
+ *
+ * In any of these cases, the media line will not be used.
+ */
+ if ((media->src_port == 0) && (remote_port != 0)) {
+ /* we offer media line removal but the remote does not comply */
+ GSM_ERR_MSG(GSM_L_C_F_PREFIX"remote insists on keeping media line\n",
+ dcb_p->line, dcb_p->call_id, fname);
+ }
+ }
+
+ /*
+ * This media line is to be removed.
+ */
+ return (TRUE);
+}
+
+/*
+ * Find a media line based on the media type.
+ */
+fsmdef_media_t* gsmsdp_find_media_by_media_type(fsmdef_dcb_t *dcb_p, sdp_media_e media_type) {
+
+ fsmdef_media_t *media = NULL;
+
+ /*
+ * search the all entries that has a valid media and matches the media type
+ */
+ GSMSDP_FOR_ALL_MEDIA(media, dcb_p) {
+ if (media->type == media_type) {
+ /* found a match */
+ return (media);
+ }
+ }
+ return (NULL);
+}
+
+/*
+ * gsmsdp_negotiate_media_lines
+ *
+ * Description:
+ *
+ * Walk down the media lines provided in the remote sdp. Compare each
+ * media line to the corresponding media line in the local sdp. If
+ * the media line does not exist in the local sdp, add it. If the media
+ * line exists in the local sdp but is different from the remote sdp,
+ * change the local sdp to match the remote sdp. If the media line
+ * is an AUDIO format, negotiate the codec and update the local sdp
+ * as needed.
+ *
+ * Parameters:
+ *
+ * fcb_p - Pointer to the FCB containing thhe DCB whose media lines are being negotiated
+ * sdp_p - Pointer to the local and remote SDP
+ * initial_offer - Boolean indicating if the remote SDP came in the first OFFER of this session
+ * offer - Boolean indicating if the remote SDP came in an OFFER.
+ * notify_stream_added - Boolean indicating the UI should be notified of streams added
+ *
+ */
+cc_causes_t
+gsmsdp_negotiate_media_lines (fsm_fcb_t *fcb_p, cc_sdp_t *sdp_p, boolean initial_offer,
+ boolean offer, boolean notify_stream_added, boolean create_answer)
+{
+ static const char fname[] = "gsmsdp_negotiate_media_lines";
+ cc_causes_t cause = CC_CAUSE_OK;
+ uint16_t num_m_lines = 0;
+ uint16_t num_local_m_lines = 0;
+ uint16_t i = 0;
+ sdp_media_e media_type;
+ fsmdef_dcb_t *dcb_p = fcb_p->dcb;
+ uint16_t port;
+ boolean update_local_ret_value = TRUE;
+ sdp_transport_e transport;
+ uint16_t crypto_inst;
+ boolean media_found = FALSE;
+ cpr_ip_addr_t remote_addr;
+ boolean new_media;
+ sdp_direction_e video_avail = SDP_DIRECTION_INACTIVE;
+ boolean unsupported_line;
+ fsmdef_media_t *media;
+ uint8_t cap_index;
+ sdp_direction_e remote_direction;
+ // boolean result;
+ int sdpmode = 0;
+ // char *session_pwd;
+ // cc_action_data_t data;
+ int j=0;
+ int rtcpmux = 0;
+ tinybool rtcp_mux = FALSE;
+ sdp_result_e sdp_res;
+
+ config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
+
+ num_m_lines = sdp_get_num_media_lines(sdp_p->dest_sdp);
+ if (num_m_lines == 0) {
+ GSM_DEBUG(DEB_L_C_F_PREFIX"no media lines found.\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname));
+ return CC_CAUSE_NO_MEDIA;
+ }
+
+ /*
+ * Validate the anat values
+ */
+ if (!gsmsdp_validate_anat(sdp_p)) {
+ /* Failed anat validation */
+ GSM_DEBUG(DEB_L_C_F_PREFIX"failed anat validation\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname));
+ return (CC_CAUSE_NO_MEDIA);
+ }
+
+ /*
+ * Process each media line in the remote SDP
+ */
+ for (i = 1; i <= num_m_lines; i++) {
+ unsupported_line = FALSE; /* assume line will be supported */
+ new_media = FALSE;
+ media = NULL;
+ media_type = sdp_get_media_type(sdp_p->dest_sdp, i);
+
+ /*
+ * Only perform these checks when called from createanswer
+ * because at this point we are concerned as to which m= lines
+ * have been created in the answer.
+ */
+ if (create_answer) {
+
+ /* Since the incoming SDP might not be in the same order as
+ our media, we find them by type rather than location
+ for this check. Note that we're not checking for the
+ value of any _particular_ m= section; we're just checking
+ whether (at least) one of the specified type exists. */
+ media = gsmsdp_find_media_by_media_type(dcb_p, media_type);
+
+ if (media_type == SDP_MEDIA_AUDIO && !media) {
+ /* continue if answer will not add this m= line */
+ continue;
+ }
+
+ if (media_type == SDP_MEDIA_VIDEO && !media) {
+ continue;
+ }
+
+ if (media_type == SDP_MEDIA_APPLICATION && !media) {
+ continue;
+ }
+ }
+
+ port = (uint16_t) sdp_get_media_portnum(sdp_p->dest_sdp, i);
+ GSM_DEBUG(DEB_L_C_F_PREFIX"Port is %d at %d %d\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname),
+ port, i, initial_offer);
+
+ switch (media_type) {
+ case SDP_MEDIA_AUDIO:
+ case SDP_MEDIA_VIDEO:
+ case SDP_MEDIA_APPLICATION:
+ /*
+ * Get remote address before other negotiations process in case
+ * the address 0.0.0.0 (old style hold) to be used
+ * for direction negotiation.
+ */
+ if (!gsmsdp_get_remote_media_address(dcb_p, sdp_p, i,
+ &remote_addr)) {
+ /* failed to get the remote address */
+ GSM_DEBUG(DEB_L_C_F_PREFIX"unable to get remote addr at %d\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname), i);
+ unsupported_line = TRUE;
+ break;
+ }
+
+ /*
+ * Find the corresponding media entry in the dcb to see
+ * this has been negiotiated previously (from the
+ * last offer/answer session).
+ */
+ if(!create_answer)
+ media = gsmsdp_find_media_by_level(dcb_p, i);
+
+ if (media == NULL) {
+ /* No previous media, negotiate adding new media line. */
+ media = gsmsdp_negotiate_add_media_line(dcb_p, media_type, i,
+ port, offer);
+ if (media == NULL) {
+ /* new one can not be added */
+ unsupported_line = TRUE;
+ break;
+ }
+ /*
+ * This media is a newly added, it is by itself an
+ * initial offer of this line.
+ */
+ new_media = TRUE;
+ GSM_DEBUG(DEB_L_C_F_PREFIX"new media entry at %d\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname), i);
+ } else if (media->type == media_type) {
+ /*
+ * Use the remote port to determine whether the
+ * media line is to be removed from the SDP.
+ */
+ if (gsmsdp_negotiate_remove_media_line(dcb_p, media, port,
+ offer)) {
+ /* the media line is to be removed from the SDP */
+ unsupported_line = TRUE;
+ GSM_DEBUG(DEB_L_C_F_PREFIX"media at %d is removed\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname), i);
+ break;
+ }
+ } else {
+ /* The media at the same level but not the expected type */
+ GSM_ERR_MSG(GSM_L_C_F_PREFIX"mismatch media type at %d\n",
+ dcb_p->line, dcb_p->call_id, fname, i);
+ unsupported_line = TRUE;
+ break;
+ }
+
+ /* Do not negotiate if media is set to inactive */
+ if (SDP_DIRECTION_INACTIVE == media->direction) {
+ break;
+ }
+
+ /* Reset multicast flag and port */
+ media->is_multicast = FALSE;
+ media->multicast_port = 0;
+
+ /* Update remote address */
+ media->previous_sdp.dest_addr = media->dest_addr;
+ media->dest_addr = remote_addr;
+
+ /*
+ * Associate the new media (for adding new media line) to
+ * the capability table.
+ */
+ if (media->cap_index == CC_MAX_MEDIA_CAP) {
+ if (!gsmsdp_assign_cap_entry_to_incoming_media(dcb_p, sdp_p,
+ media)) {
+ unsupported_line = TRUE;
+ GSM_DEBUG(DEB_L_C_F_PREFIX"unable to assign capability entry at %d\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname), i);
+ // Check if we need to update the UI that video has been offered
+ if ( offer && media_type == SDP_MEDIA_VIDEO &&
+ ( ( g_media_table.cap[CC_VIDEO_1].support_direction !=
+ SDP_DIRECTION_INACTIVE) ) ) {
+ // passed basic checks, now on to more expensive checks...
+ remote_direction = gsmsdp_get_remote_sdp_direction(dcb_p,
+ media->level,
+ &media->dest_addr);
+ cap_index = gsmdsp_find_best_match_media_cap_index(dcb_p,
+ sdp_p,
+ media,
+ MEDIA_TABLE_GLOBAL);
+
+ GSM_DEBUG(DEB_L_C_F_PREFIX"remote_direction: %d global match %sfound\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname),
+ remote_direction, (cap_index != CC_MAX_MEDIA_CAP) ? "" : "not ");
+ if ( cap_index != CC_MAX_MEDIA_CAP &&
+ remote_direction != SDP_DIRECTION_INACTIVE ) {
+ // this is an offer and platform can support video
+ GSM_DEBUG(DEB_L_C_F_PREFIX"\n\n\n\nUpdate video Offered Called %d\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname), remote_direction);
+ lsm_update_video_offered(dcb_p->line, dcb_p->call_id, remote_direction);
+ }
+ }
+ break;
+ }
+ }
+
+ /*
+ * Negotiate address type and take only address type
+ * that can be accepted.
+ */
+ if (!gsmsdp_negotiate_addr_type(dcb_p, media)) {
+ unsupported_line = TRUE;
+ break;
+ }
+
+ /*
+ * Negotiate RTP/SRTP. The result is the media transport
+ * which could be RTP/SRTP or fail.
+ */
+ transport = gsmsdp_negotiate_media_transport(dcb_p, sdp_p,
+ offer, media,
+ &crypto_inst, i);
+ if (transport == SDP_TRANSPORT_INVALID) {
+ /* unable to negotiate transport */
+ unsupported_line = TRUE;
+ GSM_DEBUG(DEB_L_C_F_PREFIX"transport mismatch at %d\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname), i);
+ break;
+ }
+
+ /* Don't need to negotiate a codec for an m= applicaton line */
+ if (SDP_MEDIA_APPLICATION != media_type) {
+
+ /*
+ * Negotiate to a single codec
+ */
+ if (gsmsdp_negotiate_codec(dcb_p, sdp_p, media, offer, initial_offer, i) ==
+ RTP_NONE) {
+ /* unable to negotiate codec */
+ unsupported_line = TRUE;
+ /* Failed codec negotiation */
+ cause = CC_CAUSE_PAYLOAD_MISMATCH;
+ GSM_DEBUG(DEB_L_C_F_PREFIX"codec mismatch at %d\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname), i);
+ break;
+ }
+ } else {
+ gsmsdp_negotiate_datachannel_attribs(dcb_p, sdp_p, i, media);
+ }
+
+ /*
+ * Both media transport (RTP/SRTP) and codec are
+ * now negotiated to common ones, update transport
+ * parameters to be used for SRTP, if there is any.
+ */
+ gsmsdp_update_negotiated_transport(dcb_p, sdp_p, media,
+ crypto_inst, transport, i);
+ GSM_DEBUG(DEB_F_PREFIX"local transport after updating negotiated: %d\n",DEB_F_PREFIX_ARGS(GSM, fname), sdp_get_media_transport(dcb_p->sdp->src_sdp, 1));
+ /*
+ * Add to or update media line to the local SDP as needed.
+ */
+ if (gsmsdp_is_multicast_address(media->dest_addr)) {
+ /*
+ * Multicast, if the address is multicast
+ * then change the local sdp and do the necessary
+ * call to set up reception of multicast packets
+ */
+ GSM_DEBUG(DEB_L_C_F_PREFIX"Got multicast offer\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname));
+ media->is_multicast = TRUE;
+ media->multicast_port = port;
+ update_local_ret_value =
+ gsmsdp_update_local_sdp_for_multicast(dcb_p, port,
+ media, offer,
+ new_media);
+ } else {
+ update_local_ret_value = gsmsdp_update_local_sdp(dcb_p,
+ offer,
+ new_media,
+ media);
+ }
+ GSM_DEBUG(DEB_F_PREFIX"local transport after updateing local SDP: %d\n",DEB_F_PREFIX_ARGS(GSM, fname), sdp_get_media_transport(dcb_p->sdp->src_sdp, 1));
+
+ /*
+ * Successful codec negotiated cache direction for ui video update
+ */
+ if (media_type == SDP_MEDIA_VIDEO ) {
+ video_avail = media->direction;
+ }
+
+ if (update_local_ret_value == TRUE) {
+ media->previous_sdp.dest_port = media->dest_port;
+ media->dest_port = port;
+ if (media_type == SDP_MEDIA_AUDIO || sdpmode) {
+ /* at least found one workable audio media line */
+ media_found = TRUE;
+ }
+ } else {
+ /*
+ * Rejecting multicast because direction is not RECVONLY
+ */
+ unsupported_line = TRUE;
+ update_local_ret_value = TRUE;
+ }
+
+ /*
+ * Negotiate rtcp-mux
+ */
+
+ sdp_res = sdp_attr_get_rtcp_mux_attribute (sdp_p->dest_sdp, i,
+ 0, SDP_ATTR_RTCP_MUX, 1, &rtcp_mux);
+
+ if (SDP_SUCCESS == sdp_res) {
+ media->rtcp_mux = TRUE;
+ }
+
+ if (!unsupported_line) {
+
+ if (sdpmode) {
+ int j;
+
+ /* Set ICE */
+ for (j=0; jcandidate_ct; j++) {
+ gsmsdp_set_ice_attribute (SDP_ATTR_ICE_CANDIDATE, media->level,
+ sdp_p->src_sdp, media->candidatesp[j]);
+ }
+
+ config_get_value(CFGID_RTCPMUX, &rtcpmux, sizeof(rtcpmux));
+ if (rtcpmux) {
+ gsmsdp_set_rtcp_mux_attribute (SDP_ATTR_RTCP_MUX, media->level, sdp_p->src_sdp, TRUE);
+ }
+
+ if (notify_stream_added) {
+ /*
+ * Add track to remote streams in dcb
+ */
+ int pc_stream_id = 0;
+
+ if (SDP_MEDIA_APPLICATION != media_type) {
+ lsm_add_remote_stream (dcb_p->line, dcb_p->call_id, media, &pc_stream_id);
+ gsmsdp_add_remote_stream(i-1, pc_stream_id, dcb_p, media);
+ } else {
+ /*
+ * Inform VCM that a Data Channel has been negotiated
+ */
+ lsm_data_channel_negotiated(dcb_p->line, dcb_p->call_id, media, &pc_stream_id);
+ }
+ }
+ }
+ }
+
+ break;
+
+ default:
+ /* Not a support media type stream */
+ unsupported_line = TRUE;
+ break;
+ }
+
+ if (unsupported_line) {
+ /* add this line to unsupported line */
+ gsmsdp_add_unsupported_stream_to_local_sdp(sdp_p, i);
+ gsmsdp_set_mid_attr(sdp_p->src_sdp, i);
+ /* Remove the media if one to be removed */
+ if (media != NULL) {
+ /* remove this media off the list */
+ gsmsdp_remove_media(dcb_p, media);
+ }
+ }
+ if (!gsmsdp_validate_mid(sdp_p, i)) {
+ /* Failed mid validation */
+ cause = CC_CAUSE_NO_MEDIA;
+ GSM_DEBUG(DEB_L_C_F_PREFIX"failed mid validation at %d\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname), i);
+ }
+ }
+
+ /*
+ * Must have at least one media found and at least one audio
+ * line.
+ */
+ if (!media_found) {
+ if (cause != CC_CAUSE_PAYLOAD_MISMATCH) {
+ cause = CC_CAUSE_NO_MEDIA;
+ }
+ } else {
+ if (cause == CC_CAUSE_PAYLOAD_MISMATCH) {
+ /*
+ * some media lines have codec mismatch but there are some
+ * that works, do not return error.
+ */
+ cause = CC_CAUSE_OK;
+ }
+
+ /*
+ * If we are processing an offer sdp, need to set the
+ * start time and stop time based on the remote SDP
+ */
+ gsmsdp_update_local_time_stamp(dcb_p, offer, initial_offer);
+
+ /*
+ * workable media line was found. Need to make sure we don't
+ * advertise more than workable media lines. Loop through
+ * remaining media lines in local SDP and set port to zero.
+ */
+ num_local_m_lines = sdp_get_num_media_lines(sdp_p->src_sdp);
+ if (num_local_m_lines > num_m_lines) {
+ for (i = num_m_lines + 1; i <= num_local_m_lines; i++) {
+ (void) sdp_set_media_portnum(sdp_p->src_sdp, i, 0, 0);
+ }
+ }
+
+ /*
+ * Update UI for Remote Stream Added
+ */
+ if (sdpmode) {
+
+ /* Fail negotiation if DTLS is not in SDP */
+ cause = gsmsdp_configure_dtls_data_attributes(fcb_p);
+ if (cause != CC_CAUSE_OK) {
+ GSM_DEBUG("gsmsdp_negotiate_media_lines- DTLS negotiation failed\n");
+ return cause;
+ }
+
+ /* ToDO(emannion)
+ * Fail negotiation if ICE is not negotiated.
+ */
+
+ /*
+ * Bubble the stream added event up to the PC UI
+ */
+ if (notify_stream_added) {
+ for (j=0; j < CC_MAX_STREAMS; j++ ) {
+ /* If this stream has been created it should have > 0 tracks. */
+ if (dcb_p->remote_media_stream_tbl->streams[j].num_tracks) {
+ ui_on_remote_stream_added(evOnRemoteStreamAdd, dcb_p->line, dcb_p->call_id,
+ dcb_p->caller_id.call_instance_id, dcb_p->remote_media_stream_tbl->streams[j]);
+
+ /* Setting num_tracks == 0 indicates stream not set */
+ dcb_p->remote_media_stream_tbl->streams[j].num_tracks = 0;
+ }
+ }
+ }
+ }
+ }
+ /*
+ * We have negotiated the line, clear flag that we have set
+ * that we are waiting for an answer SDP in ack.
+ */
+ dcb_p->remote_sdp_in_ack = FALSE;
+
+ /*
+ * check to see if UI needs to be updated for video
+ */
+ GSM_DEBUG(DEB_L_C_F_PREFIX"Update video Avail Called %d\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname),video_avail);
+
+ // update direction but preserve the cast attrib
+ dcb_p->cur_video_avail &= CC_ATTRIB_CAST;
+ dcb_p->cur_video_avail |= (uint8_t)video_avail;
+
+ lsm_update_video_avail(dcb_p->line, dcb_p->call_id, dcb_p->cur_video_avail);
+
+ return cause;
+}
+
+/*
+ * This function returns boolean parameters indicating what media types
+ * exist in the offered SDP.
+ */
+cc_causes_t
+gsmsdp_get_offered_media_types (fsm_fcb_t *fcb_p, cc_sdp_t *sdp_p, boolean *has_audio,
+ boolean *has_video, boolean *has_data)
+{
+ cc_causes_t cause = CC_CAUSE_OK;
+ uint16_t num_m_lines = 0;
+ uint16_t i = 0;
+ sdp_media_e media_type;
+ fsmdef_dcb_t *dcb_p = fcb_p->dcb;
+ // boolean result;
+
+ num_m_lines = sdp_get_num_media_lines(sdp_p->dest_sdp);
+ if (num_m_lines == 0) {
+ GSM_DEBUG(DEB_L_C_F_PREFIX"no media lines found.\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, __FUNCTION__));
+ return CC_CAUSE_NO_MEDIA;
+ }
+
+ *has_audio = FALSE;
+ *has_video = FALSE;
+ *has_data = FALSE;
+
+ /*
+ * Process each media line in the remote SDP
+ */
+ for (i = 1; i <= num_m_lines; i++) {
+ media_type = sdp_get_media_type(sdp_p->dest_sdp, i);
+
+ if(SDP_MEDIA_AUDIO == media_type)
+ *has_audio = TRUE;
+ else if(SDP_MEDIA_VIDEO == media_type)
+ *has_video = TRUE;
+ else if(SDP_MEDIA_APPLICATION == media_type)
+ *has_data = TRUE;
+ }
+
+ return cause;
+}
+
+/*
+ * gsmsdp_init_local_sdp
+ *
+ * Description:
+ *
+ * This function initializes the local sdp for generation of an offer sdp or
+ * an answer sdp. The following sdp values are initialized.
+ *
+ * v= line
+ * o= line
+ * s= line
+ * t= line
+ *
+ * Parameters:
+ *
+ * peerconnection - handle to peerconnection object
+ * sdp_pp - Pointer to the local sdp
+ *
+ * returns cc_causes_t
+ * CC_CAUSE_OK - indicates success
+ * CC_CAUSE_ERROR - indicates failure
+ */
+static cc_causes_t
+gsmsdp_init_local_sdp (const char *peerconnection, cc_sdp_t **sdp_pp)
+{
+ char addr_str[MAX_IPADDR_STR_LEN];
+ cpr_ip_addr_t ipaddr;
+ unsigned long session_id = 0;
+ char session_version_str[GSMSDP_VERSION_STR_LEN];
+ void *local_sdp_p = NULL;
+ cc_sdp_t *sdp_p = NULL;
+ int nat_enable = 0;
+ char *p_addr_str;
+ cpr_ip_mode_e ip_mode;
+ char *strtok_state;
+
+ if (!peerconnection || !sdp_pp) {
+ return CC_CAUSE_ERROR;
+ }
+
+ ip_mode = platform_get_ip_address_mode();
+ /*
+ * Get device address. We will need this later.
+ */
+ config_get_value(CFGID_NAT_ENABLE, &nat_enable, sizeof(nat_enable));
+ if (nat_enable == 0) {
+ if ((ip_mode == CPR_IP_MODE_DUAL) || (ip_mode == CPR_IP_MODE_IPV6)) {
+ sip_config_get_net_ipv6_device_ipaddr(&ipaddr);
+ } else if (ip_mode == CPR_IP_MODE_IPV4) {
+ sip_config_get_net_device_ipaddr(&ipaddr);
+ }
+ } else {
+ sip_config_get_nat_ipaddr(&ipaddr);
+ }
+
+
+ ipaddr2dotted(addr_str, &ipaddr);
+
+ p_addr_str = PL_strtok_r(addr_str, "[ ]", &strtok_state);
+
+ /*
+ * Create the local sdp struct
+ */
+ if (*sdp_pp == NULL) {
+ sipsdp_src_dest_create(peerconnection,
+ CCSIP_SRC_SDP_BIT, sdp_pp);
+ } else {
+ sdp_p = *sdp_pp;
+ if (sdp_p->src_sdp != NULL) {
+ sipsdp_src_dest_free(CCSIP_SRC_SDP_BIT, sdp_pp);
+ }
+ sipsdp_src_dest_create(peerconnection,
+ CCSIP_SRC_SDP_BIT, sdp_pp);
+ }
+ sdp_p = *sdp_pp;
+
+ if ( sdp_p == NULL )
+ return CC_CAUSE_ERROR;
+
+ local_sdp_p = sdp_p->src_sdp;
+
+ /*
+ * v= line
+ */
+ (void) sdp_set_version(local_sdp_p, SIPSDP_VERSION);
+
+ /*
+ * o= line
+ *
+ */
+ (void) sdp_set_owner_username(local_sdp_p, SIPSDP_ORIGIN_USERNAME);
+
+ session_id = abs(cpr_rand() % 28457);
+ snprintf(session_version_str, sizeof(session_version_str), "%d",
+ (int) session_id);
+ (void) sdp_set_owner_sessionid(local_sdp_p, session_version_str);
+
+ snprintf(session_version_str, sizeof(session_version_str), "%d", 0);
+ (void) sdp_set_owner_version(local_sdp_p, session_version_str);
+
+ (void) sdp_set_owner_network_type(local_sdp_p, SDP_NT_INTERNET);
+
+ if ((ip_mode == CPR_IP_MODE_DUAL) || (ip_mode == CPR_IP_MODE_IPV6)) {
+ (void) sdp_set_owner_address_type(local_sdp_p, SDP_AT_IP6);
+ } else if (ip_mode == CPR_IP_MODE_IPV4) {
+ (void) sdp_set_owner_address_type(local_sdp_p, SDP_AT_IP4);
+ }
+ (void) sdp_set_owner_address(local_sdp_p, p_addr_str);
+
+ /*
+ * s= line
+ */
+ (void) sdp_set_session_name(local_sdp_p, SIPSDP_SESSION_NAME);
+
+ /*
+ * t= line
+ * We init these to zero. If we are building an answer sdp, these will
+ * be reset from the offer sdp.
+ */
+ (void) sdp_set_time_start(local_sdp_p, "0");
+ (void) sdp_set_time_stop(local_sdp_p, "0");
+
+ return CC_CAUSE_OK;
+}
+
+/**
+ * The function sets the capabilities from media capability to the
+ * media structure.
+ *
+ * @param[in]media - pointer to the fsmdef_media_t to be set with
+ * capabilites from the media_cap.
+ * @param[in]media_cap - media capability to be used with this new media
+ * line.
+ *
+ * @return None.
+ *
+ * @pre (media not_eq NULL)
+ * @pre (media_cap not_eq NULL)
+ */
+static void
+gsmsdp_set_media_capability (fsmdef_media_t *media,
+ const cc_media_cap_t *media_cap)
+{
+ /* set default direction */
+ media->direction = media_cap->support_direction;
+ media->support_direction = media_cap->support_direction;
+ if (media_cap->support_security) {
+ /* support security */
+ FSM_SET_FLAGS(media->flags, FSM_MEDIA_F_SUPPORT_SECURITY);
+ }
+}
+
+/**
+ * The function adds a media line into the local SDP.
+ *
+ * @param[in]dcb_p - pointer to the fsmdef_dcb_t
+ * @param[in]media_cap - media capability to be used with this new media
+ * line.
+ * @param[in]cap_index - media capability entry index to associate with
+ * the media line.
+ * @param[in]level - media line order in the SDP so called level.
+ * @param[in]addr_type - cpr_ip_type for address of the media line to add.
+ *
+ * @return Pointer to the fsmdef_media_t if successfully
+ * add a new line otherwise return NULL.
+ *
+ * @pre (dcb_p not_eq NULL)
+ * @pre (media_cap not_eq NULL)
+ */
+static fsmdef_media_t *
+gsmsdp_add_media_line (fsmdef_dcb_t *dcb_p, const cc_media_cap_t *media_cap,
+ uint8_t cap_index, uint16_t level,
+ cpr_ip_type addr_type, boolean offer)
+{
+ static const char fname[] = "gsmsdp_add_media_line";
+ cc_action_data_t data;
+ fsmdef_media_t *media = NULL;
+ int i=0;
+ int rtcpmux = 0;
+ int sctp_port = 0;
+
+ switch (media_cap->type) {
+ case SDP_MEDIA_AUDIO:
+ case SDP_MEDIA_VIDEO:
+ case SDP_MEDIA_APPLICATION:
+ media = gsmsdp_get_new_media(dcb_p, media_cap->type, level);
+ if (media == NULL) {
+ /* should not happen */
+ GSM_ERR_MSG(GSM_L_C_F_PREFIX"no media entry available\n",
+ dcb_p->line, dcb_p->call_id, fname);
+ return (NULL);
+ }
+
+ /* set capabilities */
+ gsmsdp_set_media_capability(media, media_cap);
+
+ /* associate this media line to the capability entry */
+ media->cap_index = cap_index; /* keep the media cap entry index */
+
+ /* override the direction for special feature */
+ gsmsdp_feature_overide_direction(dcb_p, media);
+ if (media->support_direction == SDP_DIRECTION_INACTIVE) {
+ GSM_DEBUG(DEB_L_C_F_PREFIX"feature overrides direction to inactive"
+ " no media added\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname));
+
+ /*
+ * For an answer, SDP_DIRECTION_INACTIVE will now add an m=
+ * line but it is disabled.
+ */
+ if (!offer) {
+ media->src_port = 0;
+ } else {
+ gsmsdp_remove_media(dcb_p, media);
+ return (NULL);
+ }
+ }
+
+ if (media->support_direction != SDP_DIRECTION_INACTIVE) {
+ /*
+ * Get the local RTP port. The src port will be set in the dcb
+ * within the call to cc_call_action(CC_ACTION_OPEN_RCV)
+ */
+ data.open_rcv.is_multicast = FALSE;
+ data.open_rcv.listen_ip = ip_addr_invalid;
+ data.open_rcv.port = 0;
+ data.open_rcv.keep = FALSE;
+ /*
+ * Indicate type of media (audio/video etc) becase some for
+ * supporting video over vieo, the port is obtained from other
+ * entity.
+ */
+ data.open_rcv.media_type = media->type;
+ data.open_rcv.media_refid = media->refid;
+ if (cc_call_action(dcb_p->call_id, dcb_p->line,
+ CC_ACTION_OPEN_RCV,
+ &data) != CC_RC_SUCCESS) {
+ GSM_ERR_MSG(GSM_L_C_F_PREFIX"allocate rx port failed\n",
+ dcb_p->line, dcb_p->call_id, fname);
+ gsmsdp_remove_media(dcb_p, media);
+ return (NULL);
+ }
+
+ /* allocate port successful, save the port */
+
+ media->src_port = data.open_rcv.port;
+
+ if(media_cap->type == SDP_MEDIA_APPLICATION) {
+ config_get_value(CFGID_SCTP_PORT, &sctp_port, sizeof(sctp_port));
+ media->sctp_port = sctp_port;
+ }
+
+ /*
+ * Setup the local soruce address.
+ */
+ if (addr_type == CPR_IP_ADDR_IPV6) {
+ gsmsdp_get_local_source_v6_address(media);
+ } else if (addr_type == CPR_IP_ADDR_IPV4) {
+ gsmsdp_get_local_source_v4_address(media);
+ } else {
+ GSM_ERR_MSG(GSM_L_C_F_PREFIX"invalid IP address mode\n",
+ dcb_p->line, dcb_p->call_id, fname);
+ gsmsdp_remove_media(dcb_p, media);
+ return (NULL);
+ }
+
+ }
+
+ /*
+ * Initialize the media transport for RTP or SRTP (or do not thing
+ * and leave to the gsmsdp_update_local_sdp_media to set default)
+ */
+ gsmsdp_init_sdp_media_transport(dcb_p, dcb_p->sdp->src_sdp, media);
+
+
+ gsmsdp_update_local_sdp_media(dcb_p, dcb_p->sdp, TRUE, media,
+ media->transport);
+
+ if (media->support_direction != SDP_DIRECTION_INACTIVE) {
+
+ gsmsdp_set_local_sdp_direction(dcb_p, media, media->direction);
+
+ /*
+ * wait until here to set ICE candidates as SDP is now initialized
+ */
+ for (i=0; icandidate_ct; i++) {
+ gsmsdp_set_ice_attribute (SDP_ATTR_ICE_CANDIDATE, level, dcb_p->sdp->src_sdp, media->candidatesp[i]);
+ }
+
+ config_get_value(CFGID_RTCPMUX, &rtcpmux, sizeof(rtcpmux));
+ if (rtcpmux) {
+ gsmsdp_set_rtcp_mux_attribute (SDP_ATTR_RTCP_MUX, level, dcb_p->sdp->src_sdp, TRUE);
+ }
+
+
+ /*
+ * Since we are initiating an initial offer and opening a
+ * receive port, store initial media settings.
+ */
+ media->previous_sdp.avt_payload_type = media->avt_payload_type;
+ media->previous_sdp.direction = media->direction;
+ media->previous_sdp.packetization_period = media->packetization_period;
+ gsmsdp_copy_payloads_to_previous_sdp(media);
+ break;
+ }
+
+ default:
+ /* Unsupported media type, not added */
+ GSM_DEBUG(DEB_L_C_F_PREFIX"media type %d is not supported\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname), media_cap->type);
+ break;
+ }
+ return (media);
+}
+
+/*
+ * gsmsdp_create_local_sdp
+ *
+ * Description:
+ *
+ * Parameters:
+ *
+ * dcb_p - Pointer to the DCB whose local SDP is to be updated.
+ * force_streams_enabled - temporarily generate SDP even when no
+ * streams are added
+ *
+ * returns cc_causes_t
+ * CC_CAUSE_OK - indicates success
+ * CC_CAUSE_ERROR - indicates failure
+ */
+cc_causes_t
+gsmsdp_create_local_sdp (fsmdef_dcb_t *dcb_p, boolean force_streams_enabled,
+ boolean audio, boolean video, boolean data, boolean offer)
+{
+ static const char fname[] = "gsmsdp_create_local_sdp";
+ uint16_t level;
+ const cc_media_cap_table_t *media_cap_tbl;
+ const cc_media_cap_t *media_cap;
+ cpr_ip_mode_e ip_mode;
+ uint8_t cap_index;
+ fsmdef_media_t *media;
+ boolean has_audio;
+ int sdpmode = 0;
+ boolean media_enabled;
+
+ if ( CC_CAUSE_OK != gsmsdp_init_local_sdp(dcb_p->peerconnection,
+ &(dcb_p->sdp)) )
+ return CC_CAUSE_ERROR;
+
+ config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
+
+ dcb_p->src_sdp_version = 0;
+
+ media_cap_tbl = dcb_p->media_cap_tbl;
+
+ if (media_cap_tbl == NULL) {
+ /* should not happen */
+ GSM_ERR_MSG(GSM_L_C_F_PREFIX"no media capbility available\n",
+ dcb_p->line, dcb_p->call_id, fname);
+ return (CC_CAUSE_ERROR);
+ }
+
+ media_cap = &media_cap_tbl->cap[0];
+ level = 0;
+ for (cap_index = 0; cap_index < CC_MAX_MEDIA_CAP-1; cap_index++) {
+
+ /* Build local m lines based on m lines that were in the offered SDP */
+ media_enabled = TRUE;
+ if (FALSE == audio && SDP_MEDIA_AUDIO == media_cap->type) {
+ media_enabled = FALSE;
+ } else if (FALSE == video && SDP_MEDIA_VIDEO == media_cap->type) {
+ media_enabled = FALSE;
+ } else if (FALSE == data && SDP_MEDIA_APPLICATION == media_cap->type) {
+ media_enabled = FALSE;
+ }
+
+ /*
+ * Add each enabled media line to the SDP
+ */
+ if (media_enabled && ( media_cap->enabled || force_streams_enabled)) {
+ level = level + 1; /* next level */
+ ip_mode = platform_get_ip_address_mode();
+ if (ip_mode >= CPR_IP_MODE_IPV6) {
+ if (gsmsdp_add_media_line(dcb_p, media_cap, cap_index,
+ level, CPR_IP_ADDR_IPV6, offer)
+ == NULL) {
+ /* fail to add a media line, go back one level */
+ level = level - 1;
+ }
+
+ if (ip_mode == CPR_IP_MODE_DUAL) {
+ level = level + 1; /* next level */
+ if (gsmsdp_add_media_line(dcb_p, media_cap, cap_index,
+ level, CPR_IP_ADDR_IPV4, offer) ==
+ NULL) {
+ /* fail to add a media line, go back one level */
+ level = level - 1;
+ }
+ }
+ } else {
+ if (gsmsdp_add_media_line(dcb_p, media_cap, cap_index, level,
+ CPR_IP_ADDR_IPV4, offer) == NULL) {
+ /* fail to add a media line, go back one level */
+ level = level - 1;
+ }
+ }
+ }
+ /* next capability */
+ media_cap++;
+ }
+
+ if (level == 0) {
+ /*
+ * Did not find media line for the SDP and we do not
+ * support SDP without any media line.
+ */
+ GSM_ERR_MSG(GSM_L_C_F_PREFIX"no media line for SDP\n",
+ dcb_p->line, dcb_p->call_id, fname);
+ return (CC_CAUSE_ERROR);
+ }
+
+ /*
+ *
+ * This is a suitable place to add ice ufrag and pwd to the SDP
+ */
+
+ if (dcb_p->ice_ufrag)
+ gsmsdp_set_ice_attribute (SDP_ATTR_ICE_UFRAG, SDP_SESSION_LEVEL, dcb_p->sdp->src_sdp, dcb_p->ice_ufrag);
+ if (dcb_p->ice_pwd)
+ gsmsdp_set_ice_attribute (SDP_ATTR_ICE_PWD, SDP_SESSION_LEVEL, dcb_p->sdp->src_sdp, dcb_p->ice_pwd);
+
+ if(strlen(dcb_p->digest_alg) > 0)
+ gsmsdp_set_dtls_fingerprint_attribute (SDP_ATTR_DTLS_FINGERPRINT, SDP_SESSION_LEVEL,
+ dcb_p->sdp->src_sdp, dcb_p->digest_alg, dcb_p->digest);
+
+ if (!sdpmode) {
+
+ /*
+ * Ensure that there is at least one audio line.
+ */
+ has_audio = FALSE;
+ GSMSDP_FOR_ALL_MEDIA(media, dcb_p) {
+ if (media->type == SDP_MEDIA_AUDIO) {
+ has_audio = TRUE; /* found one audio line, done */
+ break;
+ }
+ }
+ if (!has_audio) {
+ /* No audio, do not allow */
+ GSM_ERR_MSG(GSM_L_C_F_PREFIX"no audio media line for SDP\n",
+ dcb_p->line, dcb_p->call_id, fname);
+ return (CC_CAUSE_ERROR);
+ }
+ }
+
+ return CC_CAUSE_OK;
+}
+
+/**
+ * The function creates a SDP that contains phone's current
+ * capability for an option.
+ *
+ * @param[in/out]sdp_pp - pointer to a pointer to cc_sdp_t to return
+ * the created SDP.
+ * @return none.
+ * @pre (sdp_pp not_eq NULL)
+ */
+void
+gsmsdp_create_options_sdp (cc_sdp_t ** sdp_pp)
+{
+ cc_sdp_t *sdp_p;
+
+ /* This empty string represents to associated peerconnection object */
+ if (gsmsdp_init_local_sdp("", sdp_pp) == CC_CAUSE_ERROR) {
+ return;
+ }
+
+ sdp_p = *sdp_pp;
+
+ /*
+ * Insert media line at level 1.
+ */
+ if (sdp_insert_media_line(sdp_p->src_sdp, 1) != SDP_SUCCESS) {
+ // Error
+ return;
+ }
+
+ (void) sdp_set_media_type(sdp_p->src_sdp, 1, SDP_MEDIA_AUDIO);
+ (void) sdp_set_media_portnum(sdp_p->src_sdp, 1, 0, 0);
+ gsmsdp_set_media_transport_for_option(sdp_p->src_sdp, 1);
+
+ /*
+ * Add all supported media formats to the local sdp.
+ */
+ gsmsdp_add_default_audio_formats_to_local_sdp(NULL, sdp_p, NULL);
+
+ /* Add Video m line if video caps are enabled */
+ if ( g_media_table.cap[CC_VIDEO_1].enabled == TRUE ) {
+ if (sdp_insert_media_line(sdp_p->src_sdp, 2) != SDP_SUCCESS) {
+ // Error
+ return;
+ }
+
+ (void) sdp_set_media_type(sdp_p->src_sdp, 2, SDP_MEDIA_VIDEO);
+ (void) sdp_set_media_portnum(sdp_p->src_sdp, 2, 0, 0);
+ gsmsdp_set_media_transport_for_option(sdp_p->src_sdp, 2);
+
+ gsmsdp_add_default_video_formats_to_local_sdp(NULL, sdp_p, NULL);
+ }
+}
+
+/**
+ * The function checks and removes media capability for the media
+ * lines that is to be removed.
+ *
+ * @param[in]dcb_p - Pointer to DCB
+ *
+ * @return TRUE - if there is a media line removed.
+ * FALSE - if there is no media line to remove.
+ *
+ * @pre (dcb_p not_eq NULL)
+ */
+static boolean
+gsmsdp_check_remove_local_sdp_media (fsmdef_dcb_t *dcb_p)
+{
+ static const char fname[] = "gsmsdp_check_remove_local_sdp_media";
+ fsmdef_media_t *media, *media_to_remove;
+ const cc_media_cap_t *media_cap;
+ boolean removed = FALSE;
+
+ media = GSMSDP_FIRST_MEDIA_ENTRY(dcb_p);
+ while (media) {
+ media_cap = gsmsdp_get_media_cap_entry_by_index(media->cap_index,dcb_p);
+ if (media_cap != NULL) {
+ /* found the corresponding capability of the media line */
+ if (!media_cap->enabled) {
+ GSM_DEBUG(DEB_L_C_F_PREFIX"remove media at level %d\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname), media->level);
+ /* set the media line to unused */
+ gsmsdp_add_unsupported_stream_to_local_sdp(dcb_p->sdp,
+ media->level);
+ /*
+ * remember the media to remove and get the next media to
+ * work on before removing this media off the linked list.
+ */
+ media_to_remove = media;
+ media = GSMSDP_NEXT_MEDIA_ENTRY(media);
+
+ /* remove the media from the list */
+ gsmsdp_remove_media(dcb_p, media_to_remove);
+ removed = TRUE;
+ continue;
+ }
+ }
+ media = GSMSDP_NEXT_MEDIA_ENTRY(media);
+ }
+ return (removed);
+}
+
+/**
+ * The function checks and adds media capability for the media
+ * lines that is to be added.
+ *
+ * @param[in]dcb_p - Pointer to DCB
+ * @param[in]hold - TRUE indicates the newly media line
+ * should have direction that indicates hold.
+ *
+ * @return TRUE - if there is a media line added.
+ * FALSE - if there is no media line to added.
+ *
+ * @pre (dcb_p not_eq NULL)
+ */
+static boolean
+gsmsdp_check_add_local_sdp_media (fsmdef_dcb_t *dcb_p, boolean hold)
+{
+ static const char fname[] = "gsmsdp_check_add_local_sdp_media";
+ fsmdef_media_t *media;
+ const cc_media_cap_t *media_cap;
+ uint8_t cap_index;
+ uint16_t num_m_lines, level_to_use;
+ void *src_sdp;
+ boolean need_mix = FALSE;
+ boolean added = FALSE;
+ cpr_ip_mode_e ip_mode;
+ cpr_ip_type ip_addr_type[2]; /* for 2 IP address types */
+ uint16_t i, num_ip_addrs;
+
+ if (fsmcnf_get_ccb_by_call_id(dcb_p->call_id) != NULL) {
+ /*
+ * This call is part of a local conference. The mixing
+ * support will be needed for additional media line.
+ * If platform does not have capability to support mixing
+ * of a particular media type for the local conference, either
+ * leg in the conference will not see addition media line
+ * added.
+ */
+ need_mix = TRUE;
+ }
+
+ /*
+ * Find new media entries to be added.
+ */
+ src_sdp = dcb_p->sdp ? dcb_p->sdp->src_sdp : NULL;
+ for (cap_index = 0; cap_index < CC_MAX_MEDIA_CAP; cap_index++) {
+ media_cap = gsmsdp_get_media_cap_entry_by_index(cap_index, dcb_p);
+ if (media_cap == NULL) {
+ GSM_ERR_MSG(GSM_L_C_F_PREFIX"no media capbility available\n",
+ dcb_p->line, dcb_p->call_id, fname);
+ continue;
+ }
+ if (!media_cap->enabled) {
+ /* this entry is disabled, skip it */
+ continue;
+ }
+ media = gsmsdp_find_media_by_cap_index(dcb_p, cap_index);
+ if (media != NULL) {
+ /* this media entry exists, skip it */
+ continue;
+ }
+
+ /*
+ * This is a new entry the capability table to be added.
+ */
+ if (CC_IS_AUDIO(cap_index) && need_mix) {
+ if (!gsmsdp_platform_addition_mix(dcb_p, media_cap->type)) {
+ /* platform can not support additional mixing of this type */
+ GSM_DEBUG(DEB_L_C_F_PREFIX"no support addition mixing for %d "
+ "media type\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname),
+ media_cap->type);
+ continue;
+ }
+ }
+
+ /*
+ * It depends on current address mode, if the mode is dual mode then
+ * we need to add 2 media lines.
+ */
+ ip_mode = platform_get_ip_address_mode();
+ switch (ip_mode) {
+ case CPR_IP_MODE_DUAL:
+ /* add both addresses, IPV6 line is first as it is prefered */
+ num_ip_addrs = 2;
+ ip_addr_type[0] = CPR_IP_ADDR_IPV6;
+ ip_addr_type[1] = CPR_IP_ADDR_IPV4;
+ break;
+ case CPR_IP_MODE_IPV6:
+ /* add IPV6 address only */
+ num_ip_addrs = 1;
+ ip_addr_type[0] = CPR_IP_ADDR_IPV6;
+ break;
+ default:
+ /* add IPV4 address only */
+ num_ip_addrs = 1;
+ ip_addr_type[0] = CPR_IP_ADDR_IPV4;
+ break;
+ }
+ /* add media line or lines */
+ for (i = 0; i < num_ip_addrs; i++) {
+ /*
+ * This is a new stream to add, find an unused media line
+ * in the SDP. Find the unused media line that has the same
+ * media type as the one to be added. The RFC-3264 allows reuse
+ * any unused slot in the SDP body but it was recomended to use
+ * the same type to increase the chance of interoperability by
+ * using the unuse slot that has the same media type.
+ */
+ level_to_use = gsmsdp_find_unused_media_line_with_type(src_sdp,
+ media_cap->type);
+ if (level_to_use == 0) {
+ /* no empty slot is found, add a new line to the SDP */
+ num_m_lines = sdp_get_num_media_lines(src_sdp);
+ level_to_use = num_m_lines + 1;
+ }
+ GSM_DEBUG(DEB_L_C_F_PREFIX"add media at level %d\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname), level_to_use);
+
+ /* add a new media */
+ media = gsmsdp_add_media_line(dcb_p, media_cap, cap_index,
+ level_to_use, ip_addr_type[i], FALSE);
+ if (media != NULL) {
+ /* successfully add a new media line */
+ if (hold) {
+ /* this new media needs to be sent out with hold */
+ gsmsdp_set_local_hold_sdp(dcb_p, media);
+ }
+ added = TRUE;
+ } else {
+ GSM_ERR_MSG(GSM_L_C_F_PREFIX"Unable to add a new media\n",
+ dcb_p->line, dcb_p->call_id, fname);
+ }
+ }
+ }
+ return (added);
+}
+
+/**
+ * The function checks support direction changes and updates the support
+ * direction of media lines.
+ *
+ * @param[in]dcb_p - Pointer to DCB
+ * @param[in]no_sdp_update - TRUE indicates do not update SDP.
+ *
+ * @return TRUE - if there is a media line support direction
+ * changes.
+ * FALSE - if there is no media line that has
+ * support direction change.
+ *
+ * @pre (dcb_p not_eq NULL)
+ */
+static boolean
+gsmsdp_check_direction_change_local_sdp_media (fsmdef_dcb_t *dcb_p,
+ boolean no_sdp_update)
+{
+ static const char fname[] = "gsmsdp_check_direction_change_local_sdp_media";
+ fsmdef_media_t *media;
+ const cc_media_cap_t *media_cap;
+ boolean direction_change = FALSE;
+ sdp_direction_e save_supported_direction;
+
+ media = GSMSDP_FIRST_MEDIA_ENTRY(dcb_p);
+ while (media) {
+ media_cap = gsmsdp_get_media_cap_entry_by_index(media->cap_index, dcb_p);
+ if (media_cap != NULL) {
+ if (media->support_direction !=
+ media_cap->support_direction) {
+ /*
+ * There is a possibility that supported direction has
+ * been overrided due to some feature. Check to see
+ * the supported direction remains the same after override
+ * take place. If it is different then there is a direction
+ * change.
+ */
+ save_supported_direction = media->support_direction;
+ media->support_direction = media_cap->support_direction;
+ gsmsdp_feature_overide_direction(dcb_p, media);
+ if (media->support_direction == save_supported_direction) {
+ /* nothing change after override */
+ } else {
+ /* there is no override, this is a change */
+ direction_change = TRUE;
+ }
+ if (direction_change) {
+ /* Support direction changed */
+ GSM_DEBUG(DEB_L_C_F_PREFIX"change support direction at level %d"
+ " from %d to %d\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname),
+ media->level, media->support_direction,
+ media_cap->support_direction);
+ if (no_sdp_update) {
+ /*
+ * The caller does not want to update SDP.
+ */
+ media->direction = media_cap->support_direction;
+ } else {
+ /*
+ * Need to update direction in the SDP.
+ * The direction in the media structure will
+ * be set by the gsmsdp_set_local_sdp_direction.
+ */
+ gsmsdp_set_local_sdp_direction(dcb_p, media,
+ media->support_direction);
+ }
+ }
+ }
+ }
+ media = GSMSDP_NEXT_MEDIA_ENTRY(media);
+ }
+ return (direction_change);
+}
+
+/**
+ * The function resets media specified takes the hold state into account
+ *
+ * @param[in]dcb_p - Pointer to DCB
+ * @param[in]media - Media to be updated
+ * @param[in]hold - Set media line will be set to hold.
+ */
+static void gsmsdp_reset_media(fsmdef_dcb_t *dcb_p, fsmdef_media_t *media, boolean hold){
+ gsmsdp_reset_local_sdp_media(dcb_p, media, hold);
+ if (hold) {
+ gsmsdp_set_local_hold_sdp(dcb_p, media);
+ } else {
+ gsmsdp_set_local_resume_sdp(dcb_p, media);
+ }
+}
+
+/**
+ *
+ * This functions checks if the media IP Address has changed
+ *
+ * Convert the configMedia IP String to Ip address format,
+ * check if it is valid and then compare to current media source
+ * address, if the address is valid and the media source and
+ * config media ip differ, then
+ *
+ * 1) Stop the media to close the socket
+ * 2) Set flag to true, to initiate re-invite
+ * 3) Update the media src addr
+ * 4) Update the c= line to reflect the new IP address source
+ *
+ * @param[in]dcb_p - Pointer to DCB
+ * @return TRUE - if IP changed
+ * FALSE - if no no IP changed
+ *
+ * @pre (dcb_p not_eq NULL)
+ */
+boolean
+gsmsdp_media_ip_changed (fsmdef_dcb_t *dcb_p)
+{
+ static const char fname[] = "gsmsdp_media_ip_changed";
+ boolean ip_changed = FALSE;
+ cpr_ip_addr_t addr ;
+ char curr_media_ip[MAX_IPADDR_STR_LEN];
+ char addr_str[MAX_IPADDR_STR_LEN];
+ fsmdef_media_t *media;
+
+ /*
+ * Check if media IP has changed
+ */
+ init_empty_str(curr_media_ip);
+ config_get_value(CFGID_MEDIA_IP_ADDR, curr_media_ip,
+ MAX_IPADDR_STR_LEN);
+ if (!is_empty_str(curr_media_ip)) {
+ str2ip(curr_media_ip, &addr);
+ util_ntohl(&addr, &addr);
+ GSMSDP_FOR_ALL_MEDIA(media, dcb_p) {
+ if ((util_check_if_ip_valid(&media->src_addr) == TRUE) &&
+ (util_check_if_ip_valid(&addr) == TRUE) &&
+ (util_compare_ip(&media->src_addr, &addr) == FALSE)) {
+ ipaddr2dotted(curr_media_ip, &media->src_addr); // for logging
+
+ (void)cc_call_action(dcb_p->call_id, dcb_p->line,
+ CC_ACTION_STOP_MEDIA,
+ NULL);
+ ip_changed = TRUE;
+ media->src_addr = addr;
+ if (dcb_p->sdp != NULL) {
+ gsmsdp_set_connection_address(dcb_p->sdp->src_sdp,
+ media->level,
+ dcb_p->ice_default_candidate_addr);
+ }
+ ipaddr2dotted(addr_str, &media->src_addr); // for logging
+ GSM_ERR_MSG("%s MEDIA IP_CHANGED: after Update IP %s"\
+ " before %s" ,fname, addr_str, curr_media_ip );
+ }
+ }
+ }
+
+ return (ip_changed);
+}
+
+/**
+ * this function will check whether the media ip addres in local sdp is same as to
+ * media IP provided by application. If IP differs, then re-INVITE request is posted.
+ */
+boolean is_gsmsdp_media_ip_updated_to_latest( fsmdef_dcb_t * dcb ) {
+ cpr_ip_addr_t media_ip_in_host_order ;
+ char curr_media_ip[MAX_IPADDR_STR_LEN];
+ fsmdef_media_t *media;
+
+ init_empty_str(curr_media_ip);
+ config_get_value(CFGID_MEDIA_IP_ADDR, curr_media_ip, MAX_IPADDR_STR_LEN);
+ if (is_empty_str(curr_media_ip) == FALSE) {
+ str2ip(curr_media_ip, &media_ip_in_host_order);
+ util_ntohl(&media_ip_in_host_order, &media_ip_in_host_order);
+
+ GSMSDP_FOR_ALL_MEDIA(media, dcb) {
+ if (util_check_if_ip_valid(&media->src_addr) == TRUE) {
+ if (util_compare_ip(&media->src_addr, &media_ip_in_host_order) == FALSE) {
+ return FALSE;
+ }
+ }
+ }
+ }
+ return TRUE;
+}
+
+
+/**
+ *
+ * The function checks for media capability changes and updates the
+ * local SDP for the changes. The function also provides a couple of options
+ * 1) reset the unchange media lines to initialize the codec list,
+ * crypto etc. and 2) an option to update media directions for all
+ * media lines for hold. 3)
+ *
+ * @param[in]dcb_p - Pointer to DCB
+ * @param[in]reset - Reset the unchanged media lines to include all
+ * codecs etc. again.
+ * @param[in]hold - Set media line will be set to hold.
+ *
+ * @return TRUE - if media changes occur.
+ * FALSE - if no media change occur.
+ *
+ * @pre (dcb_p not_eq NULL)
+ */
+boolean
+gsmsdp_update_local_sdp_media_capability (fsmdef_dcb_t *dcb_p, boolean reset,
+ boolean hold)
+{
+ static const char fname[] = "gsmsdp_update_local_sdp_media_capability";
+ fsmdef_media_t *media;
+ boolean change_found = FALSE;
+ boolean check_for_change = FALSE;
+
+ change_found = gsmsdp_media_ip_changed(dcb_p);
+
+ /*
+ * check to see if media capability table has changed, by checking
+ * the ID.
+ */
+ if ((g_media_table.id != dcb_p->media_cap_tbl->id) || reset) {
+
+ /*
+ * capabilty table ID different or we are doing a reset for
+ * the full offer again, need to check for various changes.
+ * Update capabilities to match platform caps
+ */
+ check_for_change = TRUE;
+ }
+
+ /*
+ * Find any capability changes. The changes allowed are:
+ * 1) media entry is disabled (to be removed).
+ * 2) supported direction change.
+ * 3) new media entry is enabled (to be added) keep it the last one.
+ *
+ * Find a media to be removed first so that if there is another
+ * media line to add then there might be an unused a media line in the
+ * SDP to use.
+ */
+ if (check_for_change && gsmsdp_check_remove_local_sdp_media(dcb_p)) {
+ /* there were some media lines removed */
+ change_found = TRUE;
+ }
+
+ /*
+ * Find media lines that may have direction changes
+ */
+ if ( check_for_change &&
+ gsmsdp_check_direction_change_local_sdp_media(dcb_p, reset)) {
+ /* there were media lines that directions changes */
+ change_found = TRUE;
+ }
+
+ /*
+ * Reset all the existing media lines to have full codec etc.
+ * again if the caller requested.
+ */
+ if (reset) {
+ GSMSDP_FOR_ALL_MEDIA(media, dcb_p) {
+ gsmsdp_reset_media(dcb_p, media, hold);
+ }
+ }
+
+ /*
+ * Find new media entries to be added.
+ */
+ if ( check_for_change && gsmsdp_check_add_local_sdp_media(dcb_p, hold)) {
+ change_found = TRUE;
+ }
+
+ if (change_found) {
+ GSM_DEBUG(DEB_L_C_F_PREFIX"media capability change found \n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname));
+ }
+
+
+ /* report back any changes made */
+ return (change_found);
+}
+
+/*
+ * gsmsdp_reset_local_sdp_media
+ *
+ * Description:
+ *
+ * This function initializes the media portion of the local sdp. The following
+ * lines are initialized.
+ *
+ * m= line
+ * a= session level line
+ *
+ * Parameters:
+ *
+ * dcb_p - Pointer to DCB whose local SDP media is to be initialized
+ * media - Pointer to fsmdef_media_t for the media entry of the SDP.
+ * If the value is NULL, it indicates all medie entries i the
+ * dcb is reset.
+ * hold - Boolean indicating if SDP is being initialized for sending hold
+ *
+ */
+void
+gsmsdp_reset_local_sdp_media (fsmdef_dcb_t *dcb_p, fsmdef_media_t *media,
+ boolean hold)
+{
+ fsmdef_media_t *start_media, *end_media;
+
+ if (media == NULL) {
+ /* NULL value of the given media indicates for all media */
+ start_media = GSMSDP_FIRST_MEDIA_ENTRY(dcb_p);
+ end_media = NULL; /* NULL means till the end of the list */
+ } else {
+ /* given media, uses the provided media */
+ start_media = media;
+ end_media = media;
+ }
+
+ GSMSDP_FOR_MEDIA_LIST(media, start_media, end_media, dcb_p) {
+ if (!GSMSDP_MEDIA_ENABLED(media)) {
+ continue;
+ }
+
+ /*
+ * Reset media transport in preparation for hold or resume.
+ * It is possible that transport media may
+ * change from the current media transport (for SRTP re-offer
+ * to a different end point).
+ */
+ gsmsdp_reset_sdp_media_transport(dcb_p, dcb_p->sdp ? dcb_p->sdp->src_sdp : NULL,
+ media, hold);
+
+ gsmsdp_update_local_sdp_media(dcb_p, dcb_p->sdp, TRUE, media,
+ media->transport);
+
+
+ /*
+ * a= line
+ * If hold is being signaled, do not alter the media direction. This
+ * will be taken care of by the state machine handler function.
+ */
+ if (!hold) {
+ /*
+ * We are not locally held, set direction to the supported
+ * direction.
+ */
+ gsmsdp_set_local_sdp_direction(dcb_p, media,
+ media->support_direction);
+ }
+ }
+}
+
+/*
+ * gsmsdp_set_local_hold_sdp
+ *
+ * Description:
+ *
+ * Manipulates the local SDP of the specified DCB to indicate hold
+ * to the far end.
+ *
+ * Parameters:
+ *
+ * dcb_p - Pointer to the DCB whose SDP is to be manipulated.
+ * media - Pointer to the fsmdef_media_t for the current media entry.
+ * If the value is NULL, it indicates all medie entries i the
+ * dcb is reset.
+ */
+void
+gsmsdp_set_local_hold_sdp (fsmdef_dcb_t *dcb_p, fsmdef_media_t *media)
+{
+ int old_style_hold = 0;
+ fsmdef_media_t *start_media, *end_media;
+
+ if (media == NULL) {
+ /* NULL value of the given media indicates for all media */
+ start_media = GSMSDP_FIRST_MEDIA_ENTRY(dcb_p);
+ end_media = NULL; /* NULL means till the end of the list */
+ } else {
+ /* given media, uses the provided media */
+ start_media = media;
+ end_media = media;
+ }
+
+ GSMSDP_FOR_MEDIA_LIST(media, start_media, end_media, dcb_p) {
+ if (!GSMSDP_MEDIA_ENABLED(media)) {
+ continue;
+ }
+ /*
+ * Check if configuration indicates that the old style hold should be
+ * signaled per RFC 2543. That is, c=0.0.0.0. Although
+ * 2543 does not speak to the SDP direction attribute, we set
+ * the direction to INACTIVE to be consistent with the connection
+ * address setting.
+ */
+ config_get_value(CFGID_2543_HOLD, &old_style_hold,
+ sizeof(old_style_hold));
+ if (old_style_hold) {
+ gsmsdp_set_2543_hold_sdp(dcb_p, media->level);
+ gsmsdp_set_local_sdp_direction(dcb_p, media,
+ SDP_DIRECTION_INACTIVE);
+ } else {
+ /*
+ * RFC3264 states that hold is signaled by setting the media
+ * direction attribute to SENDONLY if in SENDRECV mode.
+ * INACTIVE if RECVONLY mode (mutual hold).
+ */
+ if (media->direction == SDP_DIRECTION_SENDRECV ||
+ media->direction == SDP_DIRECTION_SENDONLY) {
+ gsmsdp_set_local_sdp_direction(dcb_p, media,
+ SDP_DIRECTION_SENDONLY);
+ } else {
+ gsmsdp_set_local_sdp_direction(dcb_p, media,
+ SDP_DIRECTION_INACTIVE);
+ }
+ }
+ }
+}
+
+/*
+ * gsmsdp_set_local_resume_sdp
+ *
+ * Description:
+ *
+ * Manipulates the local SDP of the specified DCB to indicate hold
+ * to the far end.
+ *
+ * Parameters:
+ *
+ * dcb_p - Pointer to the DCB whose SDP is to be manipulated.
+ * media - Pointer to the fsmdef_media_t for the current media entry.
+ *
+ */
+void
+gsmsdp_set_local_resume_sdp (fsmdef_dcb_t *dcb_p, fsmdef_media_t *media)
+{
+ fsmdef_media_t *start_media, *end_media;
+
+ if (media == NULL) {
+ /* NULL value of the given media indicates for all media */
+ start_media = GSMSDP_FIRST_MEDIA_ENTRY(dcb_p);
+ end_media = NULL; /* NULL means till the end of the list */
+ } else {
+ /* given media, uses the provided media */
+ start_media = media;
+ end_media = media;
+ }
+
+ GSMSDP_FOR_MEDIA_LIST(media, start_media, end_media, dcb_p) {
+ if (!GSMSDP_MEDIA_ENABLED(media)) {
+ continue;
+ }
+ /*
+ * We are not locally held, set direction to the supported
+ * direction.
+ */
+ gsmsdp_set_local_sdp_direction(dcb_p, media, media->support_direction);
+ }
+}
+
+/*
+ * gsmsdp_encode_sdp
+ *
+ * Description:
+ * The function encodes SDP from the internal SDP representation
+ * to the SDP body to be sent out.
+ *
+ * Parameters:
+ * sdp_p - pointer to the internal SDP info. block.
+ * msg_body - pointer to the msg body info. block.
+ *
+ * Returns:
+ * cc_causes_t to indicate failure or success.
+ */
+cc_causes_t
+gsmsdp_encode_sdp (cc_sdp_t *sdp_p, cc_msgbody_info_t *msg_body)
+{
+ char *sdp_body;
+ cc_msgbody_t *part;
+ uint32_t body_length;
+
+ if (msg_body == NULL) {
+ return CC_CAUSE_ERROR;
+ }
+
+ /* Support single SDP encoding for now */
+ sdp_body = sipsdp_write_to_buf(sdp_p, &body_length);
+
+ if (sdp_body == NULL) {
+ return CC_CAUSE_ERROR;
+ } else if (body_length == 0) {
+ cpr_free(sdp_body);
+ return CC_CAUSE_ERROR;
+ }
+
+ /* Clear off the bodies info */
+ cc_initialize_msg_body_parts_info(msg_body);
+
+ /* Set up for one SDP entry */
+ msg_body->num_parts = 1;
+ msg_body->content_type = cc_content_type_SDP;
+ part = &msg_body->parts[0];
+ part->body = sdp_body;
+ part->body_length = body_length;
+ part->content_type = cc_content_type_SDP;
+ part->content_disposition.required_handling = FALSE;
+ part->content_disposition.disposition = cc_disposition_session;
+ part->content_id = NULL;
+ return CC_CAUSE_OK;
+}
+
+/*
+ * gsmsdp_encode_sdp_and_update_version
+ *
+ * Description:
+ * The function encodes SDP from the internal SDP representation
+ * to the SDP body to be sent out. It also post-increments the owner
+ * version number to prepare for the next SDP to be sent out.
+ *
+ * Parameters:
+ * sdp_p - pointer to DCB whose local SDP is to be encoded.
+ * msg_body - pointer to the msg body info. block.
+ *
+ * Returns:
+ * cc_causes_t to indicate failure or success.
+ */
+cc_causes_t
+gsmsdp_encode_sdp_and_update_version (fsmdef_dcb_t *dcb_p, cc_msgbody_info_t *msg_body)
+{
+ char version_str[GSMSDP_VERSION_STR_LEN];
+
+ snprintf(version_str, sizeof(version_str), "%d", dcb_p->src_sdp_version);
+
+ if ( dcb_p->sdp == NULL || dcb_p->sdp->src_sdp == NULL )
+ {
+ if ( CC_CAUSE_OK != gsmsdp_init_local_sdp(dcb_p->peerconnection,
+ &(dcb_p->sdp)) )
+ {
+ return CC_CAUSE_ERROR;
+ }
+ }
+ (void) sdp_set_owner_version(dcb_p->sdp->src_sdp, version_str);
+
+ if (gsmsdp_encode_sdp(dcb_p->sdp, msg_body) != CC_CAUSE_OK) {
+ return CC_CAUSE_ERROR;
+ }
+
+ dcb_p->src_sdp_version++;
+ return CC_CAUSE_OK;
+}
+
+/*
+ * gsmsdp_get_sdp
+ *
+ * Description:
+ * The function searches the SDP from the the all of msg. body parts.
+ * All body parts having the content type SDP will be stored at the
+ * given destination arrays. The number of SDP body are returned to
+ * indicate the number of SDP bodies found. The function searches
+ * the msg body in backward to order to form SDP in the destination array
+ * to be from the highest to the lowest preferences.
+ *
+ * Parameters:
+ * msg_body - pointer to the incoming message body or cc_msgbody_info_t.
+ * part_array - pointer to pointer of cc_msgbody_t to store the
+ * sorted order of the incoming SDP.
+ * max_part - the maximum number of SDP can be written to the
+ * part_array or the part_array size.
+ * Returns:
+ * The number of SDP parts found.
+ */
+static uint32_t
+gsmsdp_get_sdp_body (cc_msgbody_info_t *msg_body,
+ cc_msgbody_t **part_array,
+ uint32_t max_parts)
+{
+ uint32_t i, count;
+ cc_msgbody_t *part;
+
+ if ((msg_body == NULL) || (msg_body->num_parts == 0)) {
+ /* No msg. body or no body parts in the msg. */
+ return (0);
+ }
+ /*
+ * Extract backward. The SDP are sent from the lowest
+ * preference to the highest preference. The highest
+ * preference will be extracted first into the given array
+ * so that when we negotiate, the SDP we will attempt to
+ * negotiate from the remote's highest to the lowest
+ * preferences.
+ */
+ count = 0;
+ part = &msg_body->parts[msg_body->num_parts - 1];
+ for (i = 0; (i < msg_body->num_parts) && (i < max_parts); i++) {
+ if (part->content_type == cc_content_type_SDP) {
+ /* Found an SDP, keep the pointer to the part */
+ *part_array = part; /* save pointer to SDP entry */
+ part_array++; /* next entry */
+ count++;
+ }
+ /* next one backward */
+ part--;
+ }
+ /* return the number of SDP bodies found */
+ return (count);
+}
+
+/*
+ * gsmsdp_realloc_dest_sdp
+ *
+ * Description:
+ * The function re-allocates the internal SDP info. block for the
+ * remote or destination SDP. If there the SDP info. or the
+ * SDP block does not exist, the new one is allocated. If SDP block
+ * exists, the current one is released and is replaced by a new one.
+ *
+ * Parameters:
+ * dcb_p - pointer to fsmdef_dcb_t.
+ *
+ * Returns:
+ * cc_causes_t to indicate failure or success.
+ */
+static cc_causes_t
+gsmsdp_realloc_dest_sdp (fsmdef_dcb_t *dcb_p)
+{
+ /* There are SDPs to process, prepare for parsing the SDP */
+ if (dcb_p->sdp == NULL) {
+ /* Create internal SDP information block with dest sdp block */
+ sipsdp_src_dest_create(dcb_p->peerconnection,
+ CCSIP_DEST_SDP_BIT, &dcb_p->sdp);
+ } else {
+ /*
+ * SDP info. block exists, remove the previously received
+ * remote or destination SDP and create a new one for
+ * the new SDP.
+ */
+ if (dcb_p->sdp->dest_sdp) {
+ sipsdp_src_dest_free(CCSIP_DEST_SDP_BIT, &dcb_p->sdp);
+ }
+ sipsdp_src_dest_create(dcb_p->peerconnection,
+ CCSIP_DEST_SDP_BIT, &dcb_p->sdp);
+ }
+
+ /* No SDP info block and parsed control block are available */
+ if ((dcb_p->sdp == NULL) || (dcb_p->sdp->dest_sdp == NULL)) {
+ /* Unable to create internal SDP structure to parse SDP. */
+ return CC_CAUSE_ERROR;
+ }
+ return CC_CAUSE_OK;
+}
+
+/*
+ * gsmsdp_negotiate_answer_sdp
+ *
+ * Description:
+ *
+ * Interface function used to negotiate an ANSWER SDP.
+ *
+ * Parameters:
+ *
+ * fcb_p - Pointer to the FCB containing the DCB whose local SDP is being negotiated.
+ * msg_body - Pointer to the cc_msgbody_info_t that contain the remote
+ *
+ */
+cc_causes_t
+gsmsdp_negotiate_answer_sdp (fsm_fcb_t *fcb_p, cc_msgbody_info_t *msg_body)
+{
+ static const char fname[] = "gsmsdp_negotiate_answer_sdp";
+ fsmdef_dcb_t *dcb_p = fcb_p->dcb;
+ cc_msgbody_t *sdp_bodies[CC_MAX_BODY_PARTS];
+ uint32_t i, num_sdp_bodies;
+ cc_causes_t status;
+ char *sdp_body;
+
+ /* Get just the SDP bodies */
+ num_sdp_bodies = gsmsdp_get_sdp_body(msg_body, &sdp_bodies[0],
+ CC_MAX_BODY_PARTS);
+ GSM_DEBUG(DEB_F_PREFIX"\n",DEB_F_PREFIX_ARGS(GSM, fname));
+ if (num_sdp_bodies == 0) {
+ /*
+ * Clear the call - we don't have any remote SDP info!
+ */
+ return CC_CAUSE_ERROR;
+ }
+
+ /* There are SDPs to process, prepare for parsing the SDP */
+ if (gsmsdp_realloc_dest_sdp(dcb_p) != CC_CAUSE_OK) {
+ /* Unable to create internal SDP structure to parse SDP. */
+ return CC_CAUSE_ERROR;
+ }
+
+ /*
+ * Parse the SDP into internal structure,
+ * now just parse one
+ */
+ status = CC_CAUSE_ERROR;
+ for (i = 0; (i < num_sdp_bodies); i++) {
+ if ((sdp_bodies[i]->body != NULL) && (sdp_bodies[i]->body_length > 0)) {
+ /* Found a body */
+ sdp_body = sdp_bodies[i]->body;
+ if (sdp_parse(dcb_p->sdp->dest_sdp, &sdp_body,
+ (uint16_t)sdp_bodies[i]->body_length)
+ == SDP_SUCCESS) {
+ status = CC_CAUSE_OK;
+ break;
+ }
+ }
+ }
+ if (status != CC_CAUSE_OK) {
+ /* Error parsing SDP */
+ return status;
+ }
+
+ gsmsdp_set_remote_sdp(dcb_p, dcb_p->sdp);
+
+ status = gsmsdp_negotiate_media_lines(fcb_p, dcb_p->sdp, FALSE, FALSE, TRUE, TRUE);
+ GSM_DEBUG(DEB_F_PREFIX"returns with %d\n",DEB_F_PREFIX_ARGS(GSM, fname), status);
+ return (status);
+}
+
+
+
+
+/*
+ * gsmsdp_negotiate_offer_sdp
+ *
+ * Description:
+ *
+ * Interface function used to negotiate an OFFER SDP.
+ *
+ * Parameters:
+ *
+ * fcb_p - Pointer to the FCB containing the DCB whose local SDP is being negotiated.
+ * msg_body - Pointer to remote SDP body infostructure.
+ * init - Boolean indicating if the local SDP should be initialized as if this is the
+ * first local SDP of this session.
+ *
+ */
+cc_causes_t
+gsmsdp_negotiate_offer_sdp (fsm_fcb_t *fcb_p,
+ cc_msgbody_info_t *msg_body, boolean init)
+{
+ cc_causes_t status;
+ fsmdef_dcb_t *dcb_p = fcb_p->dcb;
+
+ status = gsmsdp_process_offer_sdp(fcb_p, msg_body, init);
+ if (status != CC_CAUSE_OK)
+ return status;
+
+ /*
+ * If a new error code has been added to sdp processing please make sure
+ * the sip side is aware of it
+ */
+ status = gsmsdp_negotiate_media_lines(fcb_p, dcb_p->sdp, init, TRUE, FALSE, FALSE);
+ return (status);
+}
+
+
+/*
+ * gsmsdp_process_offer_sdp
+ *
+ * Description:
+ *
+ * Interface function used to process an OFFER SDP.
+ * Does not negotiate.
+ *
+ * Parameters:
+ *
+ * fcb_p - Pointer to the FCB containing the DCB whose local SDP is being negotiated.
+ * msg_body - Pointer to remote SDP body infostructure.
+ * init - Boolean indicating if the local SDP should be initialized as if this is the
+ * first local SDP of this session.
+ *
+ */
+cc_causes_t
+gsmsdp_process_offer_sdp (fsm_fcb_t *fcb_p,
+ cc_msgbody_info_t *msg_body, boolean init)
+{
+ static const char fname[] = "gsmsdp_process_offer_sdp";
+ fsmdef_dcb_t *dcb_p = fcb_p->dcb;
+ cc_causes_t status;
+ cc_msgbody_t *sdp_bodies[CC_MAX_BODY_PARTS];
+ uint32_t i, num_sdp_bodies;
+ char *sdp_body;
+
+ /* Get just the SDP bodies */
+ num_sdp_bodies = gsmsdp_get_sdp_body(msg_body, &sdp_bodies[0],
+ CC_MAX_BODY_PARTS);
+ GSM_DEBUG(DEB_L_C_F_PREFIX"Init is %d\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname), init);
+ if (num_sdp_bodies == 0) {
+ /*
+ * No remote SDP. So we will offer in our response and receive far end
+ * answer in the ack. Only need to create local sdp if this is first offer
+ * of a session. Otherwise, we will send what we have.
+ */
+ if (init) {
+ if ( CC_CAUSE_OK != gsmsdp_create_local_sdp(dcb_p, FALSE, TRUE, TRUE, TRUE, TRUE)) {
+ return CC_CAUSE_ERROR;
+ }
+ } else {
+ /*
+ * Reset all media entries that we have to offer all capabilities
+ */
+ (void)gsmsdp_update_local_sdp_media_capability(dcb_p, TRUE, FALSE);
+ }
+ dcb_p->remote_sdp_in_ack = TRUE;
+ return CC_CAUSE_OK;
+ }
+
+ /* There are SDPs to process, prepare for parsing the SDP */
+ if (gsmsdp_realloc_dest_sdp(dcb_p) != CC_CAUSE_OK) {
+ /* Unable to create internal SDP structure to parse SDP. */
+ return CC_CAUSE_ERROR;
+ }
+
+ /*
+ * Parse the SDP into internal structure,
+ * now just parse one
+ */
+ status = CC_CAUSE_ERROR;
+ for (i = 0; (i < num_sdp_bodies); i++) {
+ if ((sdp_bodies[i]->body != NULL) && (sdp_bodies[i]->body_length > 0)) {
+ /* Found a body */
+ sdp_body = sdp_bodies[i]->body;
+ if (sdp_parse(dcb_p->sdp->dest_sdp, &sdp_body,
+ (uint16_t)sdp_bodies[i]->body_length)
+ == SDP_SUCCESS) {
+ status = CC_CAUSE_OK;
+ break;
+ }
+ }
+ }
+ if (status != CC_CAUSE_OK) {
+ /* Error parsing SDP */
+ return status;
+ }
+
+ if (init) {
+ (void)gsmsdp_init_local_sdp(dcb_p->peerconnection, &(dcb_p->sdp));
+ /* Note that there should not a previous version here as well */
+ }
+
+ gsmsdp_set_remote_sdp(dcb_p, dcb_p->sdp);
+
+ return (status);
+}
+
+/*
+ * gsmsdp_install_peer_ice_attributes
+ *
+ * Read ICE parameters from the SDP and set them into
+ * the ice engine. Check SESSION_LEVEL first then each media line.
+ *
+ * fcb_p - pointer to the fcb
+ *
+ */
+cc_causes_t
+gsmsdp_install_peer_ice_attributes(fsm_fcb_t *fcb_p)
+{
+ char *ufrag;
+ char *pwd;
+ char **candidates;
+ int candidate_ct;
+ sdp_result_e sdp_res;
+ short vcm_res;
+ fsmdef_dcb_t *dcb_p = fcb_p->dcb;
+ cc_sdp_t *sdp_p = dcb_p->sdp;
+ fsmdef_media_t *media;
+ // int level;
+ short result;
+
+ /* Tolerate missing ufrag/pwd here at the session level
+ because it might be at the media level */
+ sdp_res = sdp_attr_get_ice_attribute(sdp_p->dest_sdp, SDP_SESSION_LEVEL, 0,
+ SDP_ATTR_ICE_UFRAG, 1, &ufrag);
+ if (sdp_res != SDP_SUCCESS)
+ ufrag = NULL;
+
+ sdp_res = sdp_attr_get_ice_attribute(sdp_p->dest_sdp, SDP_SESSION_LEVEL, 0,
+ SDP_ATTR_ICE_PWD, 1, &pwd);
+ if (sdp_res != SDP_SUCCESS)
+ pwd = NULL;
+
+ if (ufrag && pwd) {
+ vcm_res = vcmSetIceSessionParams(dcb_p->peerconnection, ufrag, pwd);
+ if (vcm_res)
+ return (CC_CAUSE_ERROR);
+ }
+
+ /* Now process all the media lines */
+ GSMSDP_FOR_ALL_MEDIA(media, dcb_p) {
+ if (!GSMSDP_MEDIA_ENABLED(media))
+ continue;
+
+ sdp_res = sdp_attr_get_ice_attribute(sdp_p->dest_sdp, media->level, 0,
+ SDP_ATTR_ICE_UFRAG, 1, &ufrag);
+ if (sdp_res != SDP_SUCCESS)
+ ufrag = NULL;
+
+ sdp_res = sdp_attr_get_ice_attribute(sdp_p->dest_sdp, media->level, 0,
+ SDP_ATTR_ICE_PWD, 1, &pwd);
+ if (sdp_res != SDP_SUCCESS)
+ pwd = NULL;
+
+ candidate_ct = 0;
+ candidates = NULL;
+ result = gsmsdp_get_ice_attributes (SDP_ATTR_ICE_CANDIDATE, media->level, sdp_p->dest_sdp,
+ &candidates, &candidate_ct);
+ if(!result)
+ return (CC_CAUSE_ERROR);
+
+ /* Set ICE parameters into ICE engine */
+
+ vcm_res = vcmSetIceMediaParams(dcb_p->peerconnection, media->level, ufrag, pwd,
+ candidates, candidate_ct);
+
+ /* Clean up */
+ if(candidates) {
+ int i;
+
+ for (i=0; idcb;
+ cc_sdp_t *sdp_p = dcb_p->sdp;
+ fsmdef_media_t *media;
+ // int level = SDP_SESSION_LEVEL;
+ // short result;
+ char *token;
+ char line_to_split[FSMDEF_MAX_DIGEST_ALG_LEN + FSMDEF_MAX_DIGEST_LEN + 2];
+ char *delim = " ";
+ char digest_alg[FSMDEF_MAX_DIGEST_ALG_LEN];
+ char digest[FSMDEF_MAX_DIGEST_LEN];
+ char *strtok_state;
+ cc_causes_t cause = CC_CAUSE_OK;
+
+ /* First check for session level algorithm and key */
+ sdp_session_res = sdp_attr_get_dtls_fingerprint_attribute (sdp_p->dest_sdp, SDP_SESSION_LEVEL,
+ 0, SDP_ATTR_DTLS_FINGERPRINT, 1, &session_fingerprint);
+
+ /* Now process all the media lines */
+ GSMSDP_FOR_ALL_MEDIA(media, dcb_p) {
+ if (!GSMSDP_MEDIA_ENABLED(media))
+ continue;
+
+ /* check for media level algorithm and key */
+ sdp_res = sdp_attr_get_dtls_fingerprint_attribute (sdp_p->dest_sdp, media->level,
+ 0, SDP_ATTR_DTLS_FINGERPRINT, 1, &fingerprint);
+
+ if (SDP_SUCCESS == sdp_res ) {
+ if (strlen(fingerprint) >= sizeof(line_to_split))
+ return CC_CAUSE_ERROR;
+ sstrncpy(line_to_split, fingerprint, sizeof(line_to_split));
+ } else if (SDP_SUCCESS == sdp_session_res) {
+ if (strlen(session_fingerprint) >= sizeof(line_to_split))
+ return CC_CAUSE_ERROR;
+ sstrncpy(line_to_split, session_fingerprint, sizeof(line_to_split));
+ } else {
+ cause = CC_CAUSE_ERROR;
+ continue;
+ }
+
+ if (SDP_SUCCESS == sdp_res || SDP_SUCCESS == sdp_session_res) {
+ if(!(token = PL_strtok_r(line_to_split, delim, &strtok_state)))
+ return CC_CAUSE_ERROR;
+
+ if (strlen(token) >= sizeof(digest_alg))
+ return CC_CAUSE_ERROR;
+
+ sstrncpy(digest_alg, token, sizeof(digest_alg));
+ if(!(token = PL_strtok_r(NULL, delim, &strtok_state)))
+ return CC_CAUSE_ERROR;
+
+ if (strlen(token) >= sizeof(digest))
+ return CC_CAUSE_ERROR;
+
+ sstrncpy(digest, token, sizeof(digest));
+
+ if (strlen(digest_alg) >= sizeof(media->negotiated_crypto.algorithm))
+ return CC_CAUSE_ERROR;
+
+ sstrncpy(media->negotiated_crypto.algorithm, digest_alg, sizeof(media->negotiated_crypto.algorithm));
+ if (strlen(media->negotiated_crypto.algorithm) == 0) {
+ return CC_CAUSE_ERROR;
+ }
+
+ if (strlen(digest) >= sizeof(media->negotiated_crypto.digest))
+ return CC_CAUSE_ERROR;
+
+ sstrncpy(media->negotiated_crypto.digest, digest, sizeof(media->negotiated_crypto.digest));
+ if (strlen(media->negotiated_crypto.digest) == 0) {
+ return CC_CAUSE_ERROR;
+ }
+
+ /* Here we have DTLS data */
+ cause = CC_CAUSE_OK;
+
+ } else {
+ GSM_DEBUG(DEB_F_PREFIX"DTLS attribute error\n",
+ DEB_F_PREFIX_ARGS(GSM, __FUNCTION__));
+ return CC_CAUSE_ERROR;
+ }
+ }
+
+ return cause;
+}
+
+/*
+ * gsmsdp_free
+ *
+ * Description:
+ * The function frees SDP resources that were allocated during the
+ * course of the call.
+ *
+ * Parameters:
+ * dcb_p - pointer to fsmdef_dcb_t.
+ */
+void
+gsmsdp_free (fsmdef_dcb_t *dcb_p)
+{
+ if ((dcb_p != NULL) && (dcb_p->sdp != NULL)) {
+ sipsdp_free(&dcb_p->sdp);
+ dcb_p->sdp = NULL;
+ }
+}
+
+/*
+ * gsmsdp_sdp_differs_from_previous_sdp
+ *
+ * Description:
+ *
+ * Interface function used to compare newly received SDP to previously
+ * received SDP. Returns FALSE if attributes of interest are the same.
+ * Otherwise, returns TRUE.
+ *
+ * Parameters:
+ *
+ * rcv_only - If TRUE, check for receive port perspective.
+ * media - Pointer to the fsmdef_media_t for the current media entry.
+ */
+boolean
+gsmsdp_sdp_differs_from_previous_sdp (boolean rcv_only, fsmdef_media_t *media)
+{
+ static const char fname[] = "gsmsdp_sdp_differs_from_previous_sdp";
+ char prev_addr_str[MAX_IPADDR_STR_LEN];
+ char dest_addr_str[MAX_IPADDR_STR_LEN];
+ int i;
+
+ /* Consider attributes of interest for both directions */
+
+ if ((0 == media->num_payloads) || (0 == media->previous_sdp.num_payloads) ||
+ (media->num_payloads != media->previous_sdp.num_payloads)){
+ GSM_DEBUG(DEB_F_PREFIX"previous # payloads: %d new # payloads: %d\n",
+ DEB_F_PREFIX_ARGS(GSM, fname),
+ media->previous_sdp.num_payloads, media->num_payloads);
+ }
+
+ if (media->previous_sdp.avt_payload_type != media->avt_payload_type){
+ GSM_DEBUG(DEB_F_PREFIX"previous avt PT: %d new avt PT: %d\n",
+ DEB_F_PREFIX_ARGS(GSM, fname),
+ media->previous_sdp.avt_payload_type,
+ media->avt_payload_type);
+ return TRUE;
+ }
+
+ for (i = 0; i < media->num_payloads; i++) {
+ if ((media->previous_sdp.payloads[i].remote_rtp_pt !=
+ media->payloads[i].remote_rtp_pt) ||
+ (media->previous_sdp.payloads[i].codec_type !=
+ media->payloads[i].codec_type)){
+ GSM_DEBUG(DEB_F_PREFIX"previous dynamic payload (PT) #%d: "
+ "%d; new dynamic payload: %d\n",
+ DEB_F_PREFIX_ARGS(GSM, fname), i,
+ media->previous_sdp.payloads[i].remote_rtp_pt,
+ media->payloads[i].remote_rtp_pt);
+ GSM_DEBUG(DEB_F_PREFIX"previous codec #%d: %d; new codec: %d\n",
+ DEB_F_PREFIX_ARGS(GSM, fname), i,
+ media->previous_sdp.payloads[i].codec_type,
+ media->payloads[i].codec_type);
+ return TRUE;
+ }
+ }
+
+ /*
+ * Consider attributes of interest for transmit directions.
+ * If previous dest port is 0 then this is the first time
+ * we received sdp for comparison. We treat this situation
+ * as if addr and port did not change.
+ */
+ if ( (media->previous_sdp.dest_port != 0) && (rcv_only == FALSE)) {
+ if ((util_compare_ip(&(media->previous_sdp.dest_addr),
+ &(media->dest_addr)) == FALSE) ||
+ (media->previous_sdp.dest_port != media->dest_port)) {
+ prev_addr_str[0] = '\0'; /* ensure valid string if convesion fails */
+ dest_addr_str[0] = '\0';
+ ipaddr2dotted(prev_addr_str, &media->previous_sdp.dest_addr);
+ ipaddr2dotted(dest_addr_str, &media->dest_addr);
+ GSM_DEBUG(DEB_F_PREFIX"previous address: %s new address: %s\n",
+ DEB_F_PREFIX_ARGS(GSM, fname), prev_addr_str, dest_addr_str);
+ GSM_DEBUG(DEB_F_PREFIX"previous port: %d new port: %d\n",
+ DEB_F_PREFIX_ARGS(GSM, fname), media->previous_sdp.dest_port, media->dest_port);
+ return TRUE;
+ } else if ( media->tias_bw != media->previous_sdp.tias_bw) {
+ GSM_DEBUG(DEB_F_PREFIX"previous bw: %d new bw: %d\n",
+ DEB_F_PREFIX_ARGS(GSM, fname), media->previous_sdp.tias_bw, media->tias_bw);
+ return TRUE;
+ } else if ( media->profile_level != media->previous_sdp.profile_level) {
+ GSM_DEBUG(DEB_F_PREFIX"previous prof_level: %X new prof_level: %X\n",
+ DEB_F_PREFIX_ARGS(GSM, fname), media->previous_sdp.profile_level, media->profile_level);
+ return TRUE;
+ }
+ }
+
+
+ /* Check crypto parameters if we are doing SRTP */
+ if (gsmsdp_crypto_params_change(rcv_only, media)) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/*
+ * gsmsdp_add_remote_stream
+ *
+ * Description:
+ *
+ * For each remote media stream add a track to the dcb for the
+ * current session.
+ *
+ * Parameters:
+ *
+ * idx - Stream index
+ * pc_stream_id - stream id from vcm layer, will be set as stream id
+ *
+ * dcb_p - Pointer to the DCB whose SDP is to be manipulated.
+ * media - Pointer to the fsmdef_media_t for the current media entry.
+ */
+void gsmsdp_add_remote_stream(uint16_t idx, int pc_stream_id, fsmdef_dcb_t *dcb_p, fsmdef_media_t *media) {
+
+ /*
+ * This function is in its infancy, but when complete will create a list
+ * of streams, each with its list of tracks and associated data.
+ * Currently this just creates 1 track per 1 stream.
+ */
+
+ PR_ASSERT(idx < CC_MAX_STREAMS);
+
+ if (idx < CC_MAX_STREAMS) {
+ dcb_p->remote_media_stream_tbl->streams[idx].num_tracks = 1;
+ dcb_p->remote_media_stream_tbl->streams[idx].media_stream_id = pc_stream_id;
+ dcb_p->remote_media_stream_tbl->streams[idx].track[0].media_stream_track_id = idx+1;
+ dcb_p->remote_media_stream_tbl->streams[idx].track[0].video = (media->type == 0 ? FALSE : TRUE);
+ }
+}
+
+cc_causes_t
+gsmsdp_find_level_from_mid(fsmdef_dcb_t * dcb_p, const char * mid, uint16_t *level) {
+
+ fsmdef_media_t *media;
+ u32 mid_id;
+ char buf[5];
+
+ GSMSDP_FOR_ALL_MEDIA(media, dcb_p) {
+ if (!GSMSDP_MEDIA_ENABLED(media))
+ continue;
+
+ mid_id = sdp_attr_get_simple_u32(dcb_p->sdp->dest_sdp, SDP_ATTR_MID, media->level, 0, 1);
+ snprintf(buf, sizeof(buf), "%u", mid_id);
+ if (strcmp(mid, buf) == 0) {
+ *level = media->level;
+ return CC_CAUSE_OK;
+ }
+ }
+ return CC_CAUSE_VALUE_NOT_FOUND;
+}
diff --git a/libs/sipcc/core/gsm/gsm_sdp_crypto.c b/libs/sipcc/core/gsm/gsm_sdp_crypto.c
new file mode 100644
index 0000000000..93e8d32e05
--- /dev/null
+++ b/libs/sipcc/core/gsm/gsm_sdp_crypto.c
@@ -0,0 +1,1914 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include
+#include
+
+#include "cpr_types.h"
+#include "cpr_rand.h"
+#include "sdp.h"
+#include "fsm.h"
+#include "gsm_sdp.h"
+#include "util_string.h"
+#include "lsm.h"
+#include "sip_interface_regmgr.h"
+#include "plat_api.h"
+
+static const char *gsmsdp_crypto_suite_name[SDP_SRTP_MAX_NUM_CRYPTO_SUITES] =
+{
+ "SDP_SRTP_UNKNOWN_CRYPTO_SUITE",
+ "SDP_SRTP_AES_CM_128_HMAC_SHA1_32",
+ "SDP_SRTP_AES_CM_128_HMAC_SHA1_80",
+ "SDP_SRTP_F8_128_HMAC_SHA1_80"
+};
+
+/*
+ * Cached random number pool. The size of the pool is for 10 key sets
+ * ahead. The number of cached keys are arbitrary picked to be large
+ * enough to sustain the number of basic calls.
+ */
+#define RAND_POOL_SIZE ((VCM_SRTP_MAX_KEY_SIZE+VCM_SRTP_MAX_SALT_SIZE)*10)
+#define RAND_REQ_LIMIT 256 /* limit random number request */
+static unsigned char rand_pool[RAND_POOL_SIZE]; /* random number pool */
+static int rand_pool_bytes = 0; /* current numbers in rand pool */
+
+/*
+ * Default key life time that phone supports,
+ * should be "2^48" but CCM does not support the value. Leave the
+ * life time to blank.
+ */
+#define GSMSDP_DEFALT_KEY_LIFETIME NULL
+
+/* Default algorithmID */
+#define GSMSDP_DEFAULT_ALGORITHM_ID VCM_AES_128_COUNTER
+
+/*
+ * Function: gsmsdp_cache_crypto_keys
+ *
+ * Parameters:
+ * N/A
+ *
+ * Description:
+ * The function fills the crypto graphically random number pool
+ * so that when SRTP key (and salt) is needed it is first obtained from
+ * cached pool during the call for a better response to the real time
+ * signalling event.
+ *
+ * Returns:
+ * N/A
+ */
+void
+gsmsdp_cache_crypto_keys (void)
+{
+ int number_to_fill;
+ int accumulate_bytes;
+ int bytes;
+
+ /*
+ * Only attempt to fill the cache when the pool needs to be
+ * filled and the phone is idle.
+ */
+ if ((rand_pool_bytes == RAND_POOL_SIZE) || !lsm_is_phone_idle()) {
+ return;
+ }
+
+ number_to_fill = RAND_POOL_SIZE - rand_pool_bytes;
+ accumulate_bytes = 0;
+
+ while (accumulate_bytes < number_to_fill) {
+ bytes = number_to_fill - accumulate_bytes;
+ /*
+ * Limit the request the number bytes for each request to
+ * crypto graphic random number generator to prevent
+ * error. There is a maximum limit to per request.
+ */
+ if (bytes > RAND_REQ_LIMIT) {
+ bytes = RAND_REQ_LIMIT;
+ }
+
+ if (platGenerateCryptoRand(&rand_pool[accumulate_bytes], &bytes)) {
+ accumulate_bytes += bytes;
+ } else {
+ /*
+ * Failed to get the crypto random number, uses the
+ * cpr_rand(), to keep the call going.
+ */
+ rand_pool[accumulate_bytes] = (uint8_t) (cpr_rand() & 0xff);
+ accumulate_bytes++;
+ }
+ }
+ rand_pool_bytes = RAND_POOL_SIZE;
+}
+
+/*
+ * Function: gsmsdp_get_rand_from_cached_pool
+ *
+ * Parameters:
+ * dst_buf - pointer to the unsigned char for the buffer to
+ * store random number obtained from the cached pool.
+ * req_bytes - number of random number requested.
+ *
+ * Description:
+ * The function gets the random number from the cache pool.
+ *
+ * Returns:
+ * The number of random number obtained from the pool.
+ */
+static int
+gsmsdp_get_rand_from_cached_pool (unsigned char *dst_buf, int req_bytes)
+{
+ int bytes;
+
+ if (rand_pool_bytes == 0) {
+ /* the pool is empty */
+ return 0;
+ }
+
+ if (rand_pool_bytes >= req_bytes) {
+ /* There are enough bytes from the pool */
+ bytes = req_bytes;
+ } else {
+ /*
+ * pool does not have enough random bytes, give whatever
+ * remains in the pool
+ */
+ bytes = rand_pool_bytes;
+ }
+
+ memcpy(dst_buf, &rand_pool[RAND_POOL_SIZE - rand_pool_bytes], bytes);
+ rand_pool_bytes -= bytes;
+
+ /* Returns the actual number of bytes gotten from the pool */
+ return (bytes);
+}
+
+/*
+ * Function: gsmsdp_generate_key
+ *
+ * Description:
+ * The function generates key and salt for SRTP.
+ *
+ * Parameters:
+ * algorithmID - algorithm ID
+ * key - pointer to vcm_crypto_key_t to store key output.
+ *
+ * Returns:
+ * None
+ */
+static void
+gsmsdp_generate_key (uint32_t algorithmID, vcm_crypto_key_t * key)
+{
+ int accumulate_len, len, total_bytes, bytes_from_cache;
+ uint8_t random[sizeof(key->key) + sizeof(key->salt)];
+ uint8_t key_len, salt_len;
+
+ if (algorithmID == VCM_AES_128_COUNTER) {
+ key_len = VCM_AES_128_COUNTER_KEY_SIZE;
+ salt_len = VCM_AES_128_COUNTER_SALT_SIZE;
+ } else {
+ /* Unsupported algorithm */
+ key_len = VCM_SRTP_MAX_KEY_SIZE;
+ salt_len = VCM_SRTP_MAX_SALT_SIZE;
+ }
+
+ /*
+ * Request random bytes one time for both key and salt to avoid
+ * the overhead of platGenerateCryptoRand().
+ *
+ * The size of random byes should be based on the algorithmID
+ * used but since at this time only AES128 is used.
+ */
+ accumulate_len = 0;
+ total_bytes = key_len + salt_len;
+
+ while (accumulate_len < total_bytes) {
+ len = total_bytes - accumulate_len;
+
+ /* Attempt to get random number from cached pool first */
+ bytes_from_cache =
+ gsmsdp_get_rand_from_cached_pool(&random[accumulate_len], len);
+ if (bytes_from_cache) {
+ /* There are some random number from the cache */
+ accumulate_len += bytes_from_cache;
+ } else {
+ /*
+ * The cached random number in the pool is empty.
+ *
+ * Attempt to get all of the random bytes in one request but
+ * if the number of random bytes is not enough then requesting
+ * until all bytes are accumulated.
+ */
+ if (len > RAND_REQ_LIMIT) {
+ len = RAND_REQ_LIMIT;
+ }
+ if (platGenerateCryptoRand(&random[accumulate_len], &len)) {
+ accumulate_len += len;
+ } else {
+ /*
+ * Failed to get the crypto random number, uses the
+ * cpr_rand(), to keep the call going.
+ */
+ random[accumulate_len] = (uint8_t) (cpr_rand() & 0xff);
+ accumulate_len++;
+ }
+ }
+ }
+
+ /*
+ * Filled in key and salt from the random bytes generated.
+ */
+ key->key_len = key_len;
+ memcpy(&key->key[0], &random[0], key->key_len);
+
+ key->salt_len = salt_len;
+ memcpy(&key->salt[0], &random[key->key_len], key->salt_len);
+}
+
+/*
+ * Function: gsmsdp_is_supported_crypto_suite
+ *
+ * Description:
+ * The function checks whether the given crypto suite from SDP
+ * is supported or not.
+ *
+ * Parameters:
+ * crypto_suite - sdp_srtp_crypto_suite_t type to be checked
+ *
+ * Returns:
+ * TRUE - the crypto suite is supported.
+ * FALSE - the crypto suite is not supported.
+ */
+static boolean
+gsmsdp_is_supported_crypto_suite (sdp_srtp_crypto_suite_t crypto_suite)
+{
+ switch (crypto_suite) {
+ case SDP_SRTP_AES_CM_128_HMAC_SHA1_32:
+ /* These are the supported crypto suites */
+ return (TRUE);
+ default:
+ return (FALSE);
+ }
+}
+
+/*
+ * Function: gsmsdp_is_valid_keysize
+ *
+ * Description:
+ * The function checks whether the given key size is valid.
+ *
+ * Parameters:
+ * crypto_suite - sdp_srtp_crypto_suite_t type
+ * key_size - key size to check
+ *
+ * Returns:
+ * TRUE - the key size is valid
+ * FALSE - the key size is not valid
+ */
+static boolean
+gsmsdp_is_valid_key_size (sdp_srtp_crypto_suite_t crypto_suite,
+ unsigned char key_size)
+{
+ /*
+ * Make sure the size fits the maximum key size currently supported.
+ * This to make sure that when a longer key size is added but
+ * the maximum key size is not updated.
+ */
+ if (key_size > VCM_SRTP_MAX_KEY_SIZE) {
+ return (FALSE);
+ }
+
+ /* Check key size against crypto suite */
+ switch (crypto_suite) {
+ case SDP_SRTP_AES_CM_128_HMAC_SHA1_32:
+ if (key_size == VCM_AES_128_COUNTER_KEY_SIZE) {
+ return (TRUE);
+ }
+ break;
+
+ default:
+ break;
+ }
+ return (FALSE);
+}
+
+/*
+ * Function: gsmsdp_is_valid_salt_size
+ *
+ * Description:
+ * The function checks whether the given salt size is valid.
+ *
+ * Parameters:
+ * crypto_suite - sdp_srtp_crypto_suite_t type
+ * salt_size - salt size to check
+ *
+ * Returns:
+ * TRUE - the salt size is valid
+ * FALSE - the salt size is not valid
+ */
+static boolean
+gsmsdp_is_valid_salt_size (sdp_srtp_crypto_suite_t crypto_suite,
+ unsigned char salt_size)
+{
+ /*
+ * Make sure the size fits the maximum salt size currently supported.
+ * This to make sure that when a longer salt size is added but
+ * the maximum salt size is not updated.
+ */
+ if (salt_size > VCM_SRTP_MAX_SALT_SIZE) {
+ return (FALSE);
+ }
+
+ /* Check salt size against crypter suite */
+ switch (crypto_suite) {
+ case SDP_SRTP_AES_CM_128_HMAC_SHA1_32:
+ if (salt_size == VCM_AES_128_COUNTER_SALT_SIZE) {
+ return (TRUE);
+ }
+ break;
+
+ default:
+ break;
+ }
+ return (FALSE);
+}
+
+/*
+ * Function: gsmdsp_cmp_key
+ *
+ * Description:
+ * The function compares 2 keys.
+ *
+ * Parameters:
+ * key1 - pointer to vcm_crypto_key_t
+ * key2 - pointer to vcm_crypto_key_t
+ *
+ * Returns:
+ * TRUE - the 2 keys are different
+ * FALSE - the 2 keys are the same
+ */
+static boolean
+gsmdsp_cmp_key (vcm_crypto_key_t *key1, vcm_crypto_key_t *key2)
+{
+ if ((key1 == NULL) && (key2 != NULL)) {
+ /* No key 1 but has key 2 -> different */
+ return (TRUE);
+ }
+ if ((key1 != NULL) && (key2 == NULL)) {
+ /* Has key 1 but no key 2 -> different */
+ return (TRUE);
+ }
+ if ((key1 == NULL) && (key2 == NULL)) {
+ /* No key 1 and no key 2 -> same */
+ return (FALSE);
+ }
+ /*
+ * At this point pointer to key1 and key2 should not be NULL. Compare
+ * the key content
+ */
+ if ((key1->key_len != key2->key_len) || (key1->salt_len != key2->salt_len)) {
+ /* Key length or salt length are not the same */
+ return (TRUE);
+ }
+ if (key1->key_len != 0) {
+ if (memcmp(key1->key, key2->key, key1->key_len)) {
+ return (TRUE);
+ }
+ }
+ if (key1->salt_len != 0) {
+ if (memcmp(key1->salt, key2->salt, key1->salt_len)) {
+ return (TRUE);
+ }
+ }
+ /* Both keys are the same */
+ return (FALSE);
+}
+
+/*
+ * Function: gsmsdp_is_supported_session_parm
+ *
+ * Description:
+ * The function checks to see whether the session parameters given
+ * is supported or not.
+ *
+ * Parameters:
+ * session_parms - pointer to string of session parameters
+ *
+ * Returns:
+ * TRUE - the session parameters are supported
+ * FALSE - the session parameters are not supported
+ */
+static boolean
+gsmsdp_is_supported_session_parm (const char *session_parms)
+{
+ int len;
+ const char *parm_ptr;
+ long strtol_result;
+ char *strtol_end;
+
+ if (session_parms == NULL) {
+ /* No session parameters, this is acceptable */
+ return (TRUE);
+ }
+ /*
+ * Only WSH is allowed even though the phone does not support it.
+ * The session param string can only have "WSH=nn" or (size of 6).
+ */
+ len = strlen(session_parms);
+ if (strcmp(session_parms, "WSH=") && (len == 6)) {
+ parm_ptr = &session_parms[sizeof("WSH=") - 1]; /* point the wsh value */
+
+ errno = 0;
+ strtol_result = strtol(parm_ptr, &strtol_end, 10);
+
+ /* minimum value of WSH is 64 */
+ if (errno || parm_ptr == strtol_end || strtol_result < 64 || strtol_result > INT_MAX) {
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+ /* Other parameters are not supported */
+ return (FALSE);
+}
+
+/*
+ * Function: gsmsdp_crypto_suite_to_algorithmID
+ *
+ * Description:
+ * The function converts the given crypto suite from SDP into
+ * internal enumeration suitable for using with SRTP lib.
+ *
+ * Parameters:
+ * crypto_suite - sdp_srtp_crypto_suite_t type to converted into
+ * internal algorithm ID
+ *
+ * Returns:
+ * value VCM algorithmID
+ */
+static vcm_crypto_algorithmID
+gsmsdp_crypto_suite_to_algorithmID (sdp_srtp_crypto_suite_t crypto_suite)
+{
+ /* Convert the supported crypto suite into the algorithm ID */
+ switch (crypto_suite) {
+ case SDP_SRTP_AES_CM_128_HMAC_SHA1_32:
+ return (VCM_AES_128_COUNTER);
+ default:
+ return (VCM_INVLID_ALGORITM_ID);
+ }
+}
+
+/*
+ * Function: gsmsdp_algorithmID_to_crypto_suite
+ *
+ * Description:
+ * The function converts the given crypto suite from SDP into
+ * internal enumeration suitable for using with SRTP lib.
+ *
+ * Parameters:
+ * algorithmID - algorithm ID to be converted into crypto suite
+ *
+ * Returns:
+ * crypto suite that is corresponding to the internal algorithmID
+ */
+static sdp_srtp_crypto_suite_t
+gsmsdp_algorithmID_to_crypto_suite (vcm_crypto_algorithmID algorithmID)
+{
+ /* Convert the supported crypto suite into the crypto suite */
+ switch (algorithmID) {
+ case VCM_AES_128_COUNTER:
+ return (SDP_SRTP_AES_CM_128_HMAC_SHA1_32);
+ default:
+ return (SDP_SRTP_UNKNOWN_CRYPTO_SUITE);
+ }
+}
+
+
+/*
+ * Function: gsmsdp_crypto_suite_string
+ *
+ * Description:
+ * The function converts crypto suite to string name.
+ *
+ * Parameters:
+ * crypto_suite - sdp_srtp_crypto_suite_t
+ *
+ * Returns:
+ * string constant of the corresponding crypto suite
+ */
+static const char *
+gsmsdp_crypto_suite_string (sdp_srtp_crypto_suite_t crypto_suite)
+{
+ if (crypto_suite >= SDP_SRTP_MAX_NUM_CRYPTO_SUITES) {
+ return (gsmsdp_crypto_suite_name[SDP_SRTP_UNKNOWN_CRYPTO_SUITE]);
+ }
+ return (gsmsdp_crypto_suite_name[crypto_suite]);
+}
+
+/*
+ * Function: gsmsdp_get_key_from_sdp
+ *
+ * Description:
+ * The function checks the key from the SDP.
+ *
+ * Parameters:
+ * dcb_p - pointer to the DCB.
+ * sdp_p - pointer to remote's SDP (void)
+ * level - the media level of the SDP of the media line.
+ * inst_num - instance number of the crypto attribute.
+ * key_st - pointer to fsmdef_crypto_key_t for the key to be returned.
+ * If pointer is NULL, the function acts as key validation.
+ *
+ * Returns:
+ * TRUE - The key is valid.
+ * FALSE - The key is not valid.
+ */
+static boolean
+gsmsdp_get_key_from_sdp (fsmdef_dcb_t *dcb_p, void *sdp_p, uint16_t level,
+ uint16_t inst_num, vcm_crypto_key_t *key_st)
+{
+ const char *fname = "gsmsdp_get_key_from_sdp";
+ unsigned char key_size;
+ unsigned char salt_size;
+ const char *key, *salt;
+ sdp_srtp_crypto_suite_t crypto_suite;
+
+ /* Get the crypto suite */
+ crypto_suite = sdp_attr_get_sdescriptions_crypto_suite(sdp_p,
+ level, 0, inst_num);
+
+ /* Get key */
+ key_size = sdp_attr_get_sdescriptions_key_size(sdp_p, level, 0, inst_num);
+ if (!gsmsdp_is_valid_key_size(crypto_suite, key_size)) {
+ GSM_DEBUG_ERROR(GSM_L_C_F_PREFIX
+ "SDP has invalid key size %d at media level %d\n",
+ dcb_p->line, dcb_p->call_id, fname, key_size, level);
+ return (FALSE);
+ }
+
+ key = sdp_attr_get_sdescriptions_key(sdp_p, level, 0, inst_num);
+ if (key == NULL) {
+ GSM_DEBUG_ERROR(GSM_L_C_F_PREFIX
+ "SDP has no key at media level %d\n",
+ dcb_p->line, dcb_p->call_id, fname, level);
+ return (FALSE);
+ }
+
+ /* Get salt */
+ salt_size = sdp_attr_get_sdescriptions_salt_size(sdp_p, level, 0, inst_num);
+ if (!gsmsdp_is_valid_salt_size(crypto_suite, salt_size)) {
+ GSM_DEBUG_ERROR(GSM_L_C_F_PREFIX
+ "SDP has invalid salt size %d at media level %d\n",
+ dcb_p->line, dcb_p->call_id, fname, salt_size, level);
+ return (FALSE);
+ }
+ salt = sdp_attr_get_sdescriptions_salt(sdp_p, level, 0, inst_num);
+ if (salt == NULL) {
+ GSM_DEBUG_ERROR(GSM_L_C_F_PREFIX
+ "SDP has no salt at media level %d\n",
+ dcb_p->line, dcb_p->call_id, fname, level);
+ return (FALSE);
+ }
+
+ /*
+ * Key and salt have been sanity check including their sizes,
+ * copy key and salt if the caller requests for it.
+ */
+ if (key_st != NULL) {
+ /* The caller needs to copy of the key */
+ key_st->key_len = key_size;
+ memcpy(key_st->key, key, key_size);
+ key_st->salt_len = salt_size;
+ memcpy(key_st->salt, salt, salt_size);
+ }
+ return (TRUE);
+}
+
+/*
+ * Function: gsmsdp_local_offer_srtp
+ *
+ * Description:
+ * The function checks whether the local (phone) SRTP has been offered.
+ *
+ * Parameters:
+ * media - pointer to the fsmdef_media_t for the media entry.
+ *
+ * Returns:
+ * TRUE - local has offered SRTP
+ * FALSE - local has not offered SRTP
+ */
+static boolean
+gsmsdp_local_offer_srtp (fsmdef_media_t *media)
+{
+ /*
+ * Use the local tag as an indication whether we have offered,
+ * SRTP or not.
+ */
+ if (media->local_crypto.tag == SDP_INVALID_VALUE) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+/*
+ * Function: gsmsdp_clear_local_offer_srtp
+ *
+ * Description:
+ * The function clears the flag to mark that the local SRTP has
+ * been offered.
+ *
+ * Parameters:
+ * media - pointer to the fsmdef_media_t for the media entry.
+ *
+ * Returns:
+ * none
+ */
+static void
+gsmsdp_clear_local_offer_srtp (fsmdef_media_t *media)
+{
+ /*
+ * Use the local tag as an indication whether we have offered,
+ * SRTP or not.
+ */
+ media->local_crypto.tag = SDP_INVALID_VALUE;
+}
+
+/*
+ * Function: gsmsdp_check_common_crypto_param
+ *
+ * Description:
+ * The function checks common crypto parameters that can be shared
+ * by selecting an offer and checking the answer SDP.
+ *
+ * Parameters:
+ * dcb_p - pointer to the DCB whose local SDP is to be updated
+ * cc_sdp_p - pointer to cc_sdp_t structure
+ * level - the media level of the SDP of the media line
+ * inst - crypto attribute instance number of the
+ * answer crypto line
+ * offer - boolean indicates offer if it is set to TRUE
+ *
+ * Returns:
+ * TRUE - when crypto parameters are valid and acceptable
+ * FALSE - when crypto parameters are not valid or not acceptable
+ */
+static boolean
+gsmsdp_check_common_crypto_param (fsmdef_dcb_t *dcb_p, void *sdp_p,
+ uint16_t level, uint16_t inst, boolean offer)
+{
+ const char *fname = "gsmsdp_check_common_crypto_param";
+ const char *dir_str; /* direction string */
+ const char *session_parms;
+ const char *mki_value = NULL;
+ uint16_t mki_length = 0;
+
+ if (offer) {
+ dir_str = "Offer"; /* the caller is working on an offer SDP */
+ } else {
+ dir_str = "Answer"; /* the caller is working on an answer SDP */
+ }
+
+ /* Validate the key */
+ if (!gsmsdp_get_key_from_sdp(dcb_p, sdp_p, level, inst, NULL)) {
+ GSM_DEBUG_ERROR(GSM_L_C_F_PREFIX
+ "%s SDP has invalid key at media level %d\n",
+ dcb_p->line, dcb_p->call_id, fname, dir_str, level);
+ return (FALSE);
+ }
+
+ /* Check MKI, we do not support it */
+ if (sdp_attr_get_sdescriptions_mki(sdp_p, level, 0, inst,
+ &mki_value, &mki_length)
+ != SDP_SUCCESS) {
+ /* something is wrong with decoding MKI field, do not use it */
+ GSM_DEBUG_ERROR(GSM_L_C_F_PREFIX
+ "Fail to obtain MKI from %s SDP at media level %d\n",
+ dcb_p->line, dcb_p->call_id, fname, dir_str, level);
+ return (FALSE);
+ }
+ if (mki_length) {
+ /* this crypto line has MKI specified, we do not support it */
+ GSM_DEBUG_ERROR(GSM_L_C_F_PREFIX
+ "%s SDP has MKI %d (not supported) at media level %d\n",
+ dcb_p->line, dcb_p->call_id, fname, dir_str, mki_length,
+ level);
+ return (FALSE);
+ }
+
+ /* Check session parameters */
+ session_parms = sdp_attr_get_sdescriptions_session_params(sdp_p,
+ level, 0, inst);
+ if (!gsmsdp_is_supported_session_parm(session_parms)) {
+ /* some unsupported session parameters are found */
+ GSM_DEBUG_ERROR(GSM_L_C_F_PREFIX
+ "%s SDP has unsupported session param at media level %d\n",
+ dcb_p->line, dcb_p->call_id, fname, dir_str, level);
+ return (FALSE);
+ }
+
+ /* This is good and acceptable one */
+ return (TRUE);
+}
+
+/*
+ * Function: gsmsdp_select_offer_crypto
+ *
+ * Description:
+ * Select remote the crypto attributes from the remote offered SDP.
+ *
+ * Parameters:
+ * dcb_p - pointer to the DCB
+ * sdp_p - pointer to remote's SDP (void)
+ * level - the media level of the SDP of the media line
+ * crypto_inst - pointer to crypto attribute instance number of the
+ * selected crypto line
+ *
+ * Returns:
+ * TRUE - when matching crypto parameters are found.
+ * FALSE - when matching crypto parameters are not found.
+ */
+static boolean
+gsmsdp_select_offer_crypto (fsmdef_dcb_t *dcb_p, void *sdp_p, uint16_t level,
+ uint16_t *crypto_inst)
+{
+ const char *fname = "gsmsdp_select_offer_crypto";
+ uint16_t num_attrs = 0; /* number of attributes */
+ uint16_t attr;
+ int32_t tag;
+ sdp_attr_e attr_type;
+ sdp_result_e rc;
+ sdp_srtp_crypto_suite_t crypto_suite;
+
+ /* Find the number of attributes at this level of media line */
+ rc = sdp_get_total_attrs(sdp_p, level, 0, &num_attrs);
+ if (rc != SDP_SUCCESS) {
+ GSM_DEBUG_ERROR(GSM_L_C_F_PREFIX
+ "Failed finding attributes for media level %d\n",
+ dcb_p->line, dcb_p->call_id, fname, level);
+ return (FALSE);
+ }
+
+ /*
+ * Search all crypto attributes to find a valid one that phone
+ * can support.
+ *
+ * The search starts from the first attributes to the higher. The
+ * attributes are listed from the most preferred attribute to the
+ * least in the SDP.
+ */
+ for (attr = 1; attr <= num_attrs; attr++) {
+ rc = sdp_get_attr_type(sdp_p, level, 0, attr, &attr_type, crypto_inst);
+ if ((rc != SDP_SUCCESS) || (attr_type != SDP_ATTR_SDESCRIPTIONS)) {
+ /* Can't not get the attribute or it is not sdescription */
+ continue;
+ }
+ /*
+ * Found a crypto attribute, try to match the supported crypto suite
+ */
+ crypto_suite = sdp_attr_get_sdescriptions_crypto_suite(sdp_p,
+ level, 0,
+ *crypto_inst);
+ if (!gsmsdp_is_supported_crypto_suite(crypto_suite)) {
+ /* this one is we can not support, look further */
+ continue;
+ }
+ /* get crypto tag */
+ tag = sdp_attr_get_sdescriptions_tag(sdp_p, level, 0, *crypto_inst);
+ if (tag == SDP_INVALID_VALUE) {
+ /* no tag associated with this crypto attribute */
+ continue;
+ }
+
+ /* Check common crypto parameters */
+ if (!gsmsdp_check_common_crypto_param(dcb_p, sdp_p, level,
+ *crypto_inst, TRUE)) {
+ /* Some thing is wrong with the common crypto parameters */
+ continue;
+ }
+
+ /* Found a good crypto attribute to use */
+ return (TRUE);
+ }
+
+ GSM_DEBUG_ERROR(GSM_L_C_F_PREFIX
+ "Failed finding supported crypto attribute for media level %d\n",
+ dcb_p->line, dcb_p->call_id, fname, level);
+ return (FALSE);
+}
+
+/*
+ * Function: gsmsdp_check_answer_crypto_param
+ *
+ * Description:
+ * The function processes the answer crypto attributes.
+ *
+ * Parameters:
+ * dcb_p - pointer to the DCB whose local SDP is to be updated
+ * cc_sdp_p - pointer to cc_sdp_t structure
+ * media - pointer to the media for the SDP of the media line
+ * crypto_inst - pointer to crypto attribute instance number of the
+ * answer crypto line.
+ *
+ * Returns:
+ * TRUE - when matching crypto parameters are found
+ * FALSE - when matching crypto parameters are not found
+ */
+static boolean
+gsmsdp_check_answer_crypto_param (fsmdef_dcb_t *dcb_p, cc_sdp_t * cc_sdp_p,
+ fsmdef_media_t *media, uint16_t *crypto_inst)
+{
+ const char *fname = "gsmsdp_check_answer_crypto_param";
+ uint16_t num_attrs = 0; /* number of attributes */
+ uint16_t attr;
+ uint16_t num_crypto_attr = 0;
+ int32_t dest_crypto_tag, offered_tag;
+ sdp_attr_e attr_type;
+ sdp_result_e rc;
+ sdp_srtp_crypto_suite_t crypto_suite;
+ vcm_crypto_algorithmID algorithmID;
+ void *dest_sdp = cc_sdp_p->dest_sdp;
+ uint16_t temp_inst, inst = 0;
+ uint16_t level;
+
+ level = media->level;
+ /* Clear the crypto instance */
+ *crypto_inst = 0;
+
+ /* Find the number of attributes at this level of media line */
+ if (sdp_get_total_attrs(dest_sdp, level, 0, &num_attrs) != SDP_SUCCESS) {
+ GSM_DEBUG(DEB_L_C_F_PREFIX
+ "Failed finding attributes for media level %d\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname), level);
+ return (FALSE);
+ }
+
+ /*
+ * Check to make sure that there is only crypto attribute in the
+ * answer SDP.
+ */
+ for (attr = 1, num_crypto_attr = 0; attr <= num_attrs; attr++) {
+ rc = sdp_get_attr_type(dest_sdp, level, 0, attr, &attr_type,
+ &temp_inst);
+ if ((rc == SDP_SUCCESS) && (attr_type == SDP_ATTR_SDESCRIPTIONS)) {
+ num_crypto_attr++;
+ inst = temp_inst;
+ }
+ }
+ if (num_crypto_attr != 1) {
+ /* The remote answers with zero or more than one crypto attribute */
+ GSM_DEBUG_ERROR(GSM_L_C_F_PREFIX
+ "Answer SDP contains invalid number of"
+ " crypto attributes %d for media level %d\n",
+ dcb_p->line, dcb_p->call_id, fname,
+ num_crypto_attr, level);
+ return (FALSE);
+ }
+
+ /*
+ * Check to make sure that the tag in the answer SDP is one of the
+ * offered SDP.
+ * Note: At this time of implementation there is only one crypto
+ * line sent out. When more than one cypher suites are supported,
+ * then the answer tag should be used to find the corresponding
+ * local crypto parameter.
+ */
+ dest_crypto_tag = sdp_attr_get_sdescriptions_tag(dest_sdp, level, 0, inst);
+
+ /*
+ * Selecting tag, if we have made an offer and have not received an answer
+ * before this one then tag to match is from the offered tag otherwise
+ * use the negotiated tag to match. The later case can occur as the
+ * following:
+ * phone --- INVITE+SDP ----> CCM
+ * <--- 100 -----
+ * <--- 183+SDP -----
+ * <--- 200+SDP -----
+ * The first 183+SDP will conclude the offer/answer. The 200+SDP
+ * is also an answer which also contains negotiated tag.
+ */
+ if (gsmsdp_local_offer_srtp(media)) {
+ /*
+ * We have made an offered and has not received an answer before
+ * this one, use the tag from the local crypto.
+ */
+ offered_tag = media->local_crypto.tag;
+ algorithmID = media->local_crypto.algorithmID;
+ } else {
+ /* offer/answer has complete, use negotiated crypto */
+ offered_tag = media->negotiated_crypto.tag;
+ algorithmID = media->negotiated_crypto.algorithmID;
+ }
+ if (dest_crypto_tag != offered_tag) {
+ GSM_DEBUG_ERROR(GSM_L_C_F_PREFIX
+ "Answer SDP contains wrong tag %d vs %d"
+ " for the media level %d\n",
+ dcb_p->line, dcb_p->call_id, fname,
+ dest_crypto_tag, offered_tag, level);
+ return (FALSE);
+ }
+
+ /* Check make sure that crypto suite is the same one that is offered */
+ crypto_suite = sdp_attr_get_sdescriptions_crypto_suite(dest_sdp, level,
+ 0, inst);
+ if (gsmsdp_crypto_suite_to_algorithmID(crypto_suite) != algorithmID) {
+ GSM_DEBUG_ERROR(GSM_L_C_F_PREFIX
+ "Answer SDP mismatch crypto suite %s at media level %d\n",
+ dcb_p->line, dcb_p->call_id, fname,
+ gsmsdp_crypto_suite_string(crypto_suite), level);
+ return (FALSE);
+ }
+
+ /* Check common crypto parameters */
+ if (!gsmsdp_check_common_crypto_param(dcb_p, dest_sdp, level,
+ inst, FALSE)) {
+ /* Some thing is wrong with the common crypto parameters */
+ return (FALSE);
+ }
+
+ *crypto_inst = inst;
+ return (TRUE);
+}
+
+/*
+ *
+ * Function: gsmsdp_negotiate_offer_crypto
+ *
+ * Description:
+ * The function handles crypto parameters negotiation for
+ * an offer SDP.
+ *
+ * Parameters:
+ * dcb_p - pointer to the DCB whose local SDP is to be updated
+ * cc_sdp_p - pointer to cc_sdp_t structure
+ * media - pointer to fsmdef_media_t where the media transport is.
+ * crypto_inst - pointer to crypto attribute instance number of the
+ * selected crypto line
+ *
+ * Returns:
+ * transport - sdp_transport_e for RTP or SRTP or invalid
+ */
+static sdp_transport_e
+gsmsdp_negotiate_offer_crypto (fsmdef_dcb_t *dcb_p, cc_sdp_t *cc_sdp_p,
+ fsmdef_media_t *media, uint16_t *crypto_inst, uint16 dest_level)
+{
+ sdp_transport_e remote_transport;
+ sdp_transport_e negotiated_transport = SDP_TRANSPORT_INVALID;
+ void *sdp_p = cc_sdp_p->dest_sdp;
+ int sdpmode = 0;
+
+ config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
+ *crypto_inst = 0;
+ remote_transport = sdp_get_media_transport(sdp_p, dest_level);
+
+ /* negotiate media transport */
+ switch (remote_transport) {
+ case SDP_TRANSPORT_RTPAVP:
+ /* Remote offers RTP for media transport, negotiated transport to RTP */
+ negotiated_transport = SDP_TRANSPORT_RTPAVP;
+ break;
+
+ case SDP_TRANSPORT_RTPSAVP:
+
+ /* Remote offer SRTP for media transport */
+ if (((sip_regmgr_get_sec_level(dcb_p->line) == ENCRYPTED) &&
+ FSM_CHK_FLAGS(media->flags, FSM_MEDIA_F_SUPPORT_SECURITY)) || sdpmode) {
+ /* The signalling with this line is encrypted, try to use SRTP */
+ if (gsmsdp_select_offer_crypto(dcb_p, sdp_p, dest_level, crypto_inst)) {
+ /* Found a suitable crypto line from the remote offer */
+ negotiated_transport = SDP_TRANSPORT_RTPSAVP;
+ }
+ }
+
+ if (negotiated_transport == SDP_TRANSPORT_INVALID) {
+ /*
+ * Unable to find a suitable crypto or the signaling is
+ * not secure. Fall back to RTP if fallback is enabled.
+ */
+ if (sip_regmgr_srtp_fallback_enabled(dcb_p->line)) {
+ negotiated_transport = SDP_TRANSPORT_RTPAVP;
+ }
+ }
+ break;
+
+ case SDP_TRANSPORT_RTPSAVPF:
+ /* Remote offers Extended SRTP for media transport */
+ negotiated_transport = SDP_TRANSPORT_RTPSAVPF;
+ break;
+
+ case SDP_TRANSPORT_SCTPDTLS:
+ negotiated_transport = SDP_TRANSPORT_SCTPDTLS;
+ break;
+
+ default:
+ /* Unknown */
+ break;
+ }
+ return (negotiated_transport);
+}
+
+/*
+ *
+ * Function: gsmsdp_negotiate_answer_crypto
+ *
+ * Description:
+ * The function handles crypto parameters negotiation for
+ * an answer SDP.
+ *
+ * Parameters:
+ * dcb_p - pointer to the DCB whose local SDP is to be updated
+ * cc_sdp_p - pointer to cc_sdp_t structure
+ * media - pointer to fsmdef_media_t where the media transport is.
+ * crypto_inst - pointer to crypto attribute instance number of the
+ * answer crypto line
+ *
+ * Returns:
+ * transport - sdp_transport_e for RTP or SRTP or invalid
+ */
+static sdp_transport_e
+gsmsdp_negotiate_answer_crypto (fsmdef_dcb_t *dcb_p, cc_sdp_t *cc_sdp_p,
+ fsmdef_media_t *media, uint16_t *crypto_inst)
+{
+ const char *fname = "gsmsdp_check_answer_crypto";
+ sdp_transport_e remote_transport, local_transport;
+ sdp_transport_e negotiated_transport = SDP_TRANSPORT_INVALID;
+ uint16_t level;
+
+ level = media->level;
+ *crypto_inst = 0;
+ remote_transport = sdp_get_media_transport(cc_sdp_p->dest_sdp, level);
+ local_transport = sdp_get_media_transport(cc_sdp_p->src_sdp, level);
+ GSM_DEBUG(GSM_F_PREFIX "remote transport %d\n", fname, remote_transport);
+ GSM_DEBUG(GSM_F_PREFIX "local transport %d\n", fname, local_transport);
+
+ /* negotiate media transport */
+ switch (remote_transport) {
+ case SDP_TRANSPORT_RTPAVP:
+ /* Remote answer with RTP */
+ if (local_transport == SDP_TRANSPORT_RTPSAVP) {
+ if (sip_regmgr_srtp_fallback_enabled(dcb_p->line)) {
+ /* Fall back allows, falls back to RTP */
+ negotiated_transport = SDP_TRANSPORT_RTPAVP;
+ }
+ } else {
+ /* local and remote are using RTP */
+ negotiated_transport = SDP_TRANSPORT_RTPAVP;
+ }
+ break;
+
+ case SDP_TRANSPORT_RTPSAVP:
+ GSM_DEBUG(GSM_F_PREFIX "remote SAVP case\n", fname);
+ /* Remote answer with SRTP */
+ if (local_transport == SDP_TRANSPORT_RTPSAVP) {
+ GSM_DEBUG(GSM_F_PREFIX "local SAVP case\n", fname);
+ /* Remote and local media transport are using SRTP */
+ if (gsmsdp_check_answer_crypto_param(dcb_p, cc_sdp_p, media,
+ crypto_inst)) {
+ /* Remote's answer crypto parameters are ok */
+ negotiated_transport = SDP_TRANSPORT_RTPSAVP;
+ GSM_DEBUG(GSM_F_PREFIX "crypto params verified\n", fname);
+ }
+ } else {
+ /* we offered RTP but remote comes back with SRTP, fail */
+ }
+ break;
+
+ case SDP_TRANSPORT_RTPSAVPF:
+ negotiated_transport = SDP_TRANSPORT_RTPSAVPF;
+ break;
+
+ case SDP_TRANSPORT_SCTPDTLS:
+ negotiated_transport = SDP_TRANSPORT_SCTPDTLS;
+ break;
+
+ default:
+ /* Unknown */
+ break;
+ }
+ GSM_DEBUG(GSM_F_PREFIX "negotiated transport %d\n", fname, negotiated_transport);
+ return (negotiated_transport);
+}
+
+/*
+ *
+ * Function: gsmsdp_negotiate_media_transport
+ *
+ * Description:
+ * The function is a wrapper for negotiation RTP or SRTP for offer
+ * or answer SDP. The negotiated crypto attributes instance number
+ * will be returned via pointer crypto_inst.
+ *
+ * Parameters:
+ * dcb_p - pointer to the DCB whose local SDP is to be updated.
+ * cc_sdp_p - pointer to cc_sdp_t structure that contains remote SDP.
+ * offer - boolean indicates the remote SDP is an offer SDP.
+ * media - pointer to fsmdef_media_t where the media transport is.
+ * crypto_inst - pointer to crypto attribute instance number of the
+ * selected crypto line.
+ *
+ * Returns:
+ * transport - sdp_transport_e for RTP or SRTP or invalid
+ */
+sdp_transport_e
+gsmsdp_negotiate_media_transport (fsmdef_dcb_t *dcb_p, cc_sdp_t *cc_sdp_p,
+ boolean offer, fsmdef_media_t *media,
+ uint16_t *crypto_inst, uint16 level)
+{
+ sdp_transport_e transport;
+
+ /* negotiate media transport based on offer or answer from the remote */
+ if (offer) {
+ transport = gsmsdp_negotiate_offer_crypto(dcb_p, cc_sdp_p, media,
+ crypto_inst, level);
+ } else {
+ transport = gsmsdp_negotiate_answer_crypto(dcb_p, cc_sdp_p, media,
+ crypto_inst);
+ }
+ return (transport);
+}
+
+/*
+ *
+ * Function: gsmsdp_add_single_crypto_attr
+ *
+ * Description:
+ * The function adds a single crypto attributes to the SDP.
+ *
+ * Parameters:
+ * cc_sdp_p - pointer to SDP
+ * level - the media level of the SDP where the media transport is
+ * crypto_suite - crypto suite
+ * key - pointer to SRTP key (fsmdef_crypto_key_t)
+ * lifetime - pointer to string const for the life time
+ *
+ * Returns:
+ * sdp_result_e
+ */
+static sdp_result_e
+gsmsdp_add_single_crypto_attr (void *sdp_p, uint16_t level, int32_t tag,
+ sdp_srtp_crypto_suite_t crypto_suite,
+ vcm_crypto_key_t * key, char *lifetime)
+{
+ sdp_result_e rc;
+ uint16 inst_num;
+
+ if (key == NULL) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /*
+ * Add crypto attributes tag to the SDP, the tag is using
+ * from the remote tag which should have been negotiated.
+ */
+ rc = sdp_add_new_attr(sdp_p, level, 0, SDP_ATTR_SDESCRIPTIONS, &inst_num);
+ if (rc != SDP_SUCCESS) {
+ return (rc);
+ }
+
+ rc = sdp_attr_set_sdescriptions_tag(sdp_p, level, 0, inst_num, tag);
+ if (rc != SDP_SUCCESS) {
+ return (rc);
+ }
+
+ /* Add crypto suite */
+ rc = sdp_attr_set_sdescriptions_crypto_suite(sdp_p, level, 0, inst_num,
+ crypto_suite);
+ if (rc != SDP_SUCCESS) {
+ return (rc);
+ }
+
+ /* Add local key */
+ rc = sdp_attr_set_sdescriptions_key(sdp_p, level, 0, inst_num,
+ (char *) key->key);
+ if (rc != SDP_SUCCESS) {
+ return (rc);
+ }
+
+ rc = sdp_attr_set_sdescriptions_key_size(sdp_p, level, 0, inst_num,
+ key->key_len);
+ if (rc != SDP_SUCCESS) {
+ return (rc);
+ }
+
+ /* Add salt */
+ rc = sdp_attr_set_sdescriptions_salt(sdp_p, level, 0, inst_num,
+ (char *) key->salt);
+ if (rc != SDP_SUCCESS) {
+ return (rc);
+ }
+
+ rc = sdp_attr_set_sdescriptions_salt_size(sdp_p, level, 0, inst_num,
+ key->salt_len);
+ if (rc != SDP_SUCCESS) {
+ return (rc);
+ }
+
+ if (lifetime != NULL) {
+ rc = sdp_attr_set_sdescriptions_lifetime(sdp_p, level, 0, inst_num,
+ lifetime);
+ }
+ return (rc);
+}
+
+/*
+ *
+ * Function: gsmsdp_add_all_crypto_lines
+ *
+ * Parameters:
+ *
+ * dcb_p - pointer to the DCB whose local SDP is to be updated.
+ * sdp_p - pointer to SDP.
+ * media - pointer to fsmdef_media_t where the media transport is.
+ *
+ * Description:
+ * The function adds all crypto lines to the SDP.
+ *
+ * Returns:
+ * N/A.
+ */
+static void
+gsmsdp_add_all_crypto_lines (fsmdef_dcb_t *dcb_p, void *sdp_p,
+ fsmdef_media_t *media)
+{
+ const char *fname = "gsmsdp_add_all_crypto_lines";
+ sdp_srtp_crypto_suite_t crypto_suite;
+
+ /*
+ * Add all crypto lines, currently there is only one crypto
+ * line to add.
+ */
+ media->local_crypto.tag = 1;
+ media->local_crypto.algorithmID = GSMSDP_DEFAULT_ALGORITHM_ID;
+
+ /* Generate key */
+ gsmsdp_generate_key(media->local_crypto.algorithmID,
+ &media->local_crypto.key);
+
+ /* Get the crypto suite based on the algorithm ID */
+ crypto_suite =
+ gsmsdp_algorithmID_to_crypto_suite(media->local_crypto.algorithmID);
+ if (gsmsdp_add_single_crypto_attr(sdp_p, media->level,
+ media->local_crypto.tag, crypto_suite, &media->local_crypto.key,
+ GSMSDP_DEFALT_KEY_LIFETIME) != SDP_SUCCESS) {
+ GSM_DEBUG_ERROR(GSM_L_C_F_PREFIX
+ "Failed to add crypto attributes\n",
+ dcb_p->line, dcb_p->call_id, fname);
+ }
+}
+
+/*
+ * Function: gsmsdp_init_crypto_context
+ *
+ * Description:
+ * Initializes crypto context.
+ *
+ * Parameters:
+ * media - pointer to the fsmdef_media_t for the media entry.
+ *
+ * Returns:
+ * none
+ */
+static void
+gsmsdp_init_crypto_context (fsmdef_media_t *media)
+{
+ /* initialize local crypto parameters */
+ media->local_crypto.tag = SDP_INVALID_VALUE;
+ media->local_crypto.algorithmID = VCM_NO_ENCRYPTION;
+ media->local_crypto.key.key_len = 0;
+ media->local_crypto.key.salt_len = 0;
+
+ /* Initialized negotiated crypto parameter */
+ media->negotiated_crypto.tag = SDP_INVALID_VALUE;
+ media->negotiated_crypto.algorithmID = VCM_NO_ENCRYPTION;
+ media->negotiated_crypto.tx_key.key_len = 0;
+ media->negotiated_crypto.tx_key.salt_len = 0;
+ media->negotiated_crypto.rx_key.key_len = 0;
+ media->negotiated_crypto.rx_key.salt_len = 0;
+
+ media->negotiated_crypto.flags = 0;
+}
+
+/*
+ * Function: gsmsdp_init_sdp_media_transport
+ *
+ * Description:
+ * The prepares or initializes crypto context for a fresh negotiation.
+ *
+ * Parameters:
+ * dcb_p - pointer to the fsmdef_dcb_t
+ * sdp - pointer to SDP (void)
+ * media - pointer to the fsmdef_media_t for the media entry.
+ *
+ * Returns:
+ * N/A
+ */
+void
+gsmsdp_init_sdp_media_transport (fsmdef_dcb_t *dcb_p, void *sdp_p,
+ fsmdef_media_t *media)
+{
+ int rtpsavpf = 0;
+ int sdpmode = 0;
+
+ /* Initialize crypto context */
+ gsmsdp_init_crypto_context(media);
+
+ config_get_value(CFGID_RTPSAVPF, &rtpsavpf, sizeof(rtpsavpf));
+ config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
+
+ if (SDP_MEDIA_APPLICATION == media->type) {
+ media->transport = SDP_TRANSPORT_SCTPDTLS;
+ } else if (rtpsavpf) {
+ media->transport = SDP_TRANSPORT_RTPSAVPF;
+ } else if (sdpmode) {
+ media->transport = SDP_TRANSPORT_RTPSAVP;
+ } else if ((sip_regmgr_get_sec_level(dcb_p->line) != ENCRYPTED) ||
+ (!FSM_CHK_FLAGS(media->flags, FSM_MEDIA_F_SUPPORT_SECURITY))) {
+ /*
+ * The signaling is not encrypted or this media can not support
+ * security.
+ */
+ media->transport = SDP_TRANSPORT_RTPAVP;
+ } else {
+ media->transport = SDP_TRANSPORT_RTPSAVP;
+ }
+}
+
+/*
+ * Function: gsmsdp_reset_sdp_media_transport
+ *
+ * Description:
+ * The function resets media transport during mid call such as resume.
+ * The media transport may change from the current negotiated media.
+ *
+ * Parameters:
+ * dcb_p - pointer to the fsmdef_dcb_t
+ * sdp - pointer to SDP (void)
+ * media - pointer to fsmdef_media_t where the media transport is.
+ * hold - indicates call is being hold
+ *
+ * Returns:
+ * N/A.
+ */
+void
+gsmsdp_reset_sdp_media_transport (fsmdef_dcb_t *dcb_p, void *sdp_p,
+ fsmdef_media_t *media, boolean hold)
+{
+ if (hold) {
+ /* We are sending out hold, uses the same transport as negotiated */
+ } else {
+ /* Resuming a call */
+ if ((sip_regmgr_get_cc_mode(dcb_p->line) == REG_MODE_CCM)) {
+ /*
+ * In CCM mode, try to resume with full SRTP offer again
+ * if the current signalling is encrypted. In CCM mode,
+ * CCM will assist in crypto negotiation and fall back to
+ * RTP if necessary. This is useful when resuming a different
+ * end point and the new end point support SRTP even when the
+ * current media is not SRTP. For an example, when holding
+ * a call that was transferred to a new end point which
+ * it may be able to support SRTP.
+ */
+ gsmsdp_init_sdp_media_transport(dcb_p,
+ dcb_p->sdp ? dcb_p->sdp->src_sdp : NULL,
+ media);
+ } else {
+ /*
+ * In non CCM mode, we do not know whether the new end
+ * point supports SRTP fall back and no assistance from
+ * CCM in negotiating of the crypto parameter, play safe by
+ * resuming with the same media transport.
+ */
+ }
+ }
+}
+
+/*
+ * Function: gsmsdp_set_media_transport_for_option
+ *
+ * Parameters:
+ * sdp - pointer to SDP (void).
+ * level - the media level of the SDP where the media transport is.
+ *
+ * Description:
+ * The function sets media transport for OPTION message.
+ *
+ * Returns:
+ * N/A.
+ */
+void
+gsmsdp_set_media_transport_for_option (void *sdp_p, uint16_t level)
+{
+ const char *fname = "gsmsdp_set_media_transport_for_option";
+ uint32_t algorithmID;
+ vcm_crypto_key_t key;
+ sdp_srtp_crypto_suite_t crypto_suite;
+
+
+ /* Use line 1 to determine whether to have RTP or SRTP */
+ if (sip_regmgr_get_sec_level(1) != ENCRYPTED) {
+ /* line one is none secure, use RTP */
+ (void) sdp_set_media_transport(sdp_p, level, SDP_TRANSPORT_RTPAVP);
+ return;
+ }
+
+ /* Advertise SRTP with default attributes */
+ (void) sdp_set_media_transport(sdp_p, level, SDP_TRANSPORT_RTPSAVP);
+
+ /* Generate dummy key */
+ crypto_suite = SDP_SRTP_AES_CM_128_HMAC_SHA1_32;
+ algorithmID = gsmsdp_crypto_suite_to_algorithmID(crypto_suite);
+ gsmsdp_generate_key(algorithmID, &key);
+
+ /* Add crypto attributes */
+ if (gsmsdp_add_single_crypto_attr(sdp_p, level, 1, crypto_suite, &key,
+ GSMSDP_DEFALT_KEY_LIFETIME) != SDP_SUCCESS) {
+ GSM_DEBUG_ERROR(GSM_F_PREFIX
+ "Failed to add crypto attributes\n",
+ fname);
+ }
+}
+
+/*
+ * Function: gsmsdp_update_local_sdp_media_transport
+ *
+ * Description:
+ * The function updates the crypto attributes to the local SDP.
+ *
+ * Parameters:
+ * dcb_p - pointer to the fsmdef_dcb_t
+ * sdp - pointer to SDP (void)
+ * media - pointer to fsmdef_media_t where the media transport is.
+ * sdp_transport_e - current media transport
+ * all - indicates that the update for new offer SDP
+ *
+ * Returns:
+ * none
+ */
+void
+gsmsdp_update_local_sdp_media_transport (fsmdef_dcb_t *dcb_p, void *sdp_p,
+ fsmdef_media_t *media,
+ sdp_transport_e transport, boolean all)
+{
+ const char *fname = "gsmsdp_update_local_sdp_media_transport";
+ sdp_srtp_crypto_suite_t crypto_suite;
+ uint16_t level;
+
+ level = media->level;
+ /* Get the current transport before delete the media line */
+ if (transport == SDP_TRANSPORT_INVALID) {
+ /*
+ * The transport is not specified, get it from the negotiated
+ * transport. This condition can occur when receive initial
+ * offered SDP.
+ */
+ transport = media->transport;
+ }
+
+ /*
+ * set media transport in local SDP only first time so that we remember what we offered.
+ */
+ if (sdp_get_media_transport(sdp_p, level) == SDP_TRANSPORT_INVALID) {
+ (void) sdp_set_media_transport(sdp_p, level, transport);
+ }
+
+ if (transport != SDP_TRANSPORT_RTPSAVP) {
+ /*
+ * transport is not SRTP, if this is the fall back to RTP then
+ * the existing crypto lines should have been removed by the
+ * media transport negotiation and thus no code is added here.
+ * The reason for this is not to call to the remove all crypto
+ * line all the time i.e. only removed them when related to
+ * SRTP media transport.
+ */
+ return;
+ }
+
+ /* Add crypto attributes to local SDP. */
+ if (all || (media->negotiated_crypto.tag == SDP_INVALID_VALUE)) {
+ /* This is new offer or mid call media change occurs ,
+ * or could be the result of sending full offer during mid-call invite
+ * without SDP (delayed media invite) as well
+ */
+ if (media->negotiated_crypto.tag == SDP_INVALID_VALUE) {
+ /*
+ * This is the first time or fresh offering add all crypto
+ * lines.
+ */
+ gsmsdp_add_all_crypto_lines(dcb_p, sdp_p, media);
+ return;
+ } else {
+ /* Fall through below and use existing crypto parameters */
+ }
+ }
+
+ /*
+ * tag and algorithm ID are from the negotiated crypto parameters.
+ */
+ crypto_suite =
+ gsmsdp_algorithmID_to_crypto_suite(
+ media->negotiated_crypto.algorithmID);
+ if (gsmsdp_add_single_crypto_attr(sdp_p, level,
+ media->negotiated_crypto.tag,
+ crypto_suite,
+ &media->negotiated_crypto.tx_key,
+ GSMSDP_DEFALT_KEY_LIFETIME)
+ != SDP_SUCCESS) {
+ GSM_DEBUG_ERROR(GSM_L_C_F_PREFIX
+ "Failed to add crypto attributes\n",
+ dcb_p->line, dcb_p->call_id, fname);
+ }
+}
+
+/*
+ * Function: gsmsdp_update_crypto_transmit_key
+ *
+ * Description:
+ * The function updates transmit key for SRTP session.
+ *
+ * Parameters:
+ * dcb_p - pointer to the fsmdef_dcb_t
+ * media - pointer to fsmdef_media_t where the media transport is.
+ * offer - boolean indicates it is an offer
+ * initial_offer - boolean indicates it is an initial offer
+ * direction - new offered media direction
+ *
+ * Returns:
+ * none
+ */
+void
+gsmsdp_update_crypto_transmit_key (fsmdef_dcb_t *dcb_p,
+ fsmdef_media_t *media,
+ boolean offer,
+ boolean initial_offer,
+ sdp_direction_e direction)
+{
+ const char *fname = "gsmsdp_update_crypto_transmit_key";
+ boolean generate_key = FALSE;
+
+ if (media->transport != SDP_TRANSPORT_RTPSAVP) {
+ return;
+ }
+
+ if (initial_offer || offer) {
+ /* This is an offer SDP, see if a new key needs to be generated */
+ if (initial_offer) {
+ /* An initial offer always needs new key */
+ generate_key = TRUE;
+ } else if ((util_compare_ip(&(media->previous_sdp.dest_addr),
+ &(media->dest_addr)) == FALSE) &&
+ media->dest_addr.type != CPR_IP_ADDR_INVALID) {
+ //Todo IPv6: IPv6 does not support 0.0.0.0 hold.
+
+ GSM_DEBUG(DEB_L_C_F_PREFIX
+ "Received offer with dest. address changes\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname));
+ /*
+ * This is just an offer and the destination address changes to
+ * is not 0.0.0.0 (hold) address, new key may be needed. There
+ * is a scenario where we get a delay media INVITE during the
+ * resume call (from the CCM for an example) and we have sent
+ * out 200 OK (offer SDP) with crypto parameters. Upon receiving
+ * ACK with SDP, the SIP stack in this notify GSM as a
+ * FEATURE MEDIA to GSM. GSM treats this as an offer SDP.
+ * This code path is entered with offer flag set where it should
+ * be an answer to our 200 OK offer early on. Check for this
+ * condition to see if we have an offer sent prior and if so
+ * do not generate new key if we already sent an offer out
+ * and has not get and answer SDP. Otherwise we will be generating
+ * a new key and do not sent out the key to the remote end which
+ * result in wrong local transmit key is being used.
+ */
+ if (gsmsdp_local_offer_srtp(media)) {
+ /*
+ * We have sent out an offer but has not got an answer,
+ * use the already generated key
+ */
+ media->negotiated_crypto.tx_key = media->local_crypto.key;
+ GSM_DEBUG(DEB_L_C_F_PREFIX
+ "Local offered SDP has been sent, use offered key\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname));
+ } else {
+ generate_key = TRUE;
+ }
+ } else if ((media->direction == SDP_DIRECTION_INACTIVE) &&
+ (direction != SDP_DIRECTION_INACTIVE)) {
+ if (!gsmsdp_local_offer_srtp(media)) {
+ /*
+ * Received an offer that changes the direction from
+ * inactive to some thing other than inactive, then
+ * generate a new key. The phone could be transferred
+ * to a new endpoint without destination address changes.
+ * This is possible if there is a passthrough MTP in
+ * between. The remote end point may be changed
+ * behind MTP but from this phone the destination addr.
+ * stays the same.
+ */
+ generate_key = TRUE;
+ GSM_DEBUG(DEB_L_C_F_PREFIX
+ "Received direction changes from inactive\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname));
+ }
+ } else if (media->negotiated_crypto.tx_key.key_len == 0) {
+ if (gsmsdp_local_offer_srtp(media)) {
+ /*
+ * This an answer to our offer sent similar to
+ * the address change scenario above (delayed media, we
+ * sent SDP in 200OK and got SDP in ACK but GSM treats
+ * SDP in ACK case as an offer rather than an answer).
+ * Use the key in the offered SDP.
+ */
+ media->negotiated_crypto.tx_key = media->local_crypto.key;
+ GSM_DEBUG(DEB_L_C_F_PREFIX
+ "Local offered SDP has been sent, use offered key\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname));
+ } else {
+ /*
+ * Do not have negotiated transmit key.
+ *
+ * The scenario that this can occur is when the
+ * call transition from RTP to SRTP in mid-call.
+ */
+ generate_key = TRUE;
+ GSM_DEBUG(DEB_L_C_F_PREFIX
+ "Received offer but no tx key, generate new key\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname));
+ }
+ } else {
+ /* No need to generate new key */
+ }
+ if (generate_key) {
+ /*
+ * This is an initial offer or mid-call offer and
+ * some conditions changes , generate a new transmit key.
+ */
+ gsmsdp_generate_key(media->negotiated_crypto.algorithmID,
+ &media->negotiated_crypto.tx_key);
+ GSM_DEBUG(DEB_L_C_F_PREFIX
+ "Generate tx key\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname));
+ media->negotiated_crypto.flags |= FSMDEF_CRYPTO_TX_CHANGE;
+ }
+ } else {
+ /* This is an answer to our offer, set the tx key to the local key
+ *
+ * Note that when adding support to offer multiple crypto suite to
+ * the remote end, we need to select the corresponding local offer
+ * SDP from the matching tag. At this point, we only support one
+ * crypto to offer and just get to that entry
+ */
+ if (gsmdsp_cmp_key(&media->local_crypto.key,
+ &media->negotiated_crypto.tx_key)) {
+ media->negotiated_crypto.flags |= FSMDEF_CRYPTO_TX_CHANGE;
+ GSM_DEBUG(DEB_L_C_F_PREFIX
+ "tx key changes in answered SDP\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname));
+ }
+ media->negotiated_crypto.tx_key = media->local_crypto.key; /* tx key */
+ }
+ /* Complete offer/answer, clear condition that we have made an offered */
+ gsmsdp_clear_local_offer_srtp(media);
+}
+
+/*
+ * Function: gsmsdp_update_negotiated_transport
+ *
+ * Description:
+ * The function updates the transport and crypto parameters after the
+ * all negotiated parameters has been done.
+ *
+ * Parameters:
+ * dcb_p - pointer to the fsmdef_dcb_t
+ * sdp - pointer to cc_sdp_t structure
+ * level - pointer to fsmdef_media_t where the media transport is.
+ * crypto_inst - pointer to crypto attribute instance number of the
+ * selected crypto line
+ * sdp_transport_e - negotiated media transport
+ *
+ * Returns:
+ * none
+ */
+void
+gsmsdp_update_negotiated_transport (fsmdef_dcb_t *dcb_p,
+ cc_sdp_t *cc_sdp_p,
+ fsmdef_media_t *media,
+ uint16_t crypto_inst,
+ sdp_transport_e transport,
+ uint16 dest_level)
+{
+ const char *fname = "gsmsdp_update_negotiated_transport";
+ sdp_srtp_crypto_suite_t crypto_suite;
+ void *dest_sdp = cc_sdp_p->dest_sdp;
+ vcm_crypto_algorithmID algorithmID;
+ vcm_crypto_key_t key;
+ uint16_t level;
+
+ level = dest_level;
+ /*
+ * Also detect changes of the crypto parameters for Tx and Rx.
+ * It is done here to avoid adding last crypto parameters for Tx and
+ * Rx into the dcb structure since the parameters include key which
+ * are rather long. This minimize the dcb's increasing.
+ */
+ /* reset changes flags */
+ media->negotiated_crypto.flags &= ~(FSMDEF_CRYPTO_TX_CHANGE |
+ FSMDEF_CRYPTO_RX_CHANGE);
+ /*
+ * Detect the transport change between RTP to SRTP or ignore
+ * the first time transition from invalid transport. This
+ * prevents the change bits to be set for first time in RTP
+ * connection and causes the RX to be closed unnecessary.
+ */
+ if ((media->transport != SDP_TRANSPORT_INVALID) &&
+ (transport != media->transport)) {
+ /* We could fallback to RTP or resume from RTP to SRTP */
+ media->negotiated_crypto.flags |= (FSMDEF_CRYPTO_TX_CHANGE |
+ FSMDEF_CRYPTO_RX_CHANGE);
+ GSM_DEBUG(DEB_L_C_F_PREFIX
+ "SDP media transport changed to %d\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname), transport);
+ }
+ /* Update the negotiated media transport */
+ media->transport = transport;
+
+ if (media->transport != SDP_TRANSPORT_RTPSAVP) {
+ /*
+ * negotiate media transport to RTP, clear local offer SDP
+ * condition.
+ */
+ GSM_DEBUG(DEB_L_C_F_PREFIX
+ "SDP media transport is RTP\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname));
+ return;
+ }
+
+ GSM_DEBUG(DEB_L_C_F_PREFIX "SDP media transport is SRTP\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname));
+
+ /*
+ * Get the crypto parameters from the remote's SDP,
+ * the parameters should already be validated during the
+ * media transport negotiation. Update the negotiated crypto parameter.
+ */
+ crypto_suite = sdp_attr_get_sdescriptions_crypto_suite(dest_sdp, level,
+ 0, crypto_inst);
+
+ /* Save the negotiated algorithm ID */
+ algorithmID = gsmsdp_crypto_suite_to_algorithmID(crypto_suite);
+ if (algorithmID != media->negotiated_crypto.algorithmID) {
+ media->negotiated_crypto.flags |= (FSMDEF_CRYPTO_TX_CHANGE |
+ FSMDEF_CRYPTO_RX_CHANGE);
+ GSM_DEBUG(DEB_L_C_F_PREFIX "SDP algorithm ID change to %d\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname), algorithmID);
+ }
+ media->negotiated_crypto.algorithmID = algorithmID;
+
+ /* Save the negotiated crypto line tag */
+ media->negotiated_crypto.tag = sdp_attr_get_sdescriptions_tag(dest_sdp,
+ level, 0,
+ crypto_inst);
+
+ /* Get the remote's key */
+ (void) gsmsdp_get_key_from_sdp(dcb_p, dest_sdp, level, crypto_inst, &key);
+ if (gsmdsp_cmp_key(&key, &media->negotiated_crypto.rx_key)) {
+ media->negotiated_crypto.flags |= FSMDEF_CRYPTO_RX_CHANGE;
+ GSM_DEBUG(DEB_L_C_F_PREFIX "SDP rx key changes\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, dcb_p->line, dcb_p->call_id, fname));
+ }
+ media->negotiated_crypto.rx_key = key;
+}
+
+/*
+ * Function: gsmsdp_is_crypto_ready
+ *
+ * Parameters:
+ * media - pointer to fsmdef_media_t where the media transport is.
+ * rx - boolean indicates receiver.
+ *
+ * Description:
+ * The function returns to the caller whether receiver/transmitter is
+ * ready for open.
+ *
+ * Returns:
+ * TRUE - when the receiver is ready to received.
+ * FALSE - when the receive is not ready.
+ */
+boolean
+gsmsdp_is_crypto_ready (fsmdef_media_t *media, boolean rx)
+{
+ /*
+ * If we offered SRTP then we need to wait for the negotiated key before
+ * allowing the Rx/Tx to be opened. If we did not offer (we received
+ * an offered SDP instead then we should have key negotiated).
+ */
+ if (media->transport == SDP_TRANSPORT_RTPAVP || media->transport == SDP_TRANSPORT_RTPSAVPF) {
+ return (TRUE);
+ }
+
+ /*
+ * Local has offered SRTP, check to see if the key is available.
+ */
+ if (rx) {
+ if (media->negotiated_crypto.rx_key.key_len == 0) {
+ /* Have not received remote's crypto parameter yet, can't open Rx */
+ return (FALSE);
+ }
+ } else {
+ if (media->negotiated_crypto.tx_key.key_len == 0) {
+ /* Have not received remote's crypto parameter yet, can't open Tx */
+ return (FALSE);
+ }
+ }
+ /* Have remote's key */
+ return (TRUE);
+}
+
+/*
+ * Function: gsmsdp_is_media_encrypted
+ *
+ * Description:
+ * The function returns to the caller whether the media is
+ * encrypted or not.
+ *
+ * Parameters:
+ * dcb_p - pointer to the fsmdef_dcb_t.
+ *
+ * Returns:
+ * TRUE - when the media is encrypted.
+ * FALSE - when the media is not encrypted.
+ */
+boolean
+gsmsdp_is_media_encrypted (fsmdef_dcb_t *dcb_p)
+{
+ fsmdef_media_t *media;
+ uint8_t num_encrypted;
+
+ if (dcb_p == NULL) {
+ return(FALSE);
+ }
+ num_encrypted = 0;
+ GSMSDP_FOR_ALL_MEDIA(media, dcb_p) {
+ if (!GSMSDP_MEDIA_ENABLED(media)) {
+ continue;
+ }
+
+ if (media->transport == SDP_TRANSPORT_RTPSAVP || media->transport == SDP_TRANSPORT_RTPSAVPF) {
+ num_encrypted++;
+ }
+ }
+
+ if ((num_encrypted == 0) ||
+ (num_encrypted != GSMSDP_MEDIA_COUNT(dcb_p))) {
+ /*
+ * the call does not have any media that is encrypted or
+ * there are some medias that are not encrypted. This is
+ * considered as non secure leg.
+ */
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+/*
+ * Function: gsmsdp_crypto_params_change
+ *
+ * Description:
+ * The function returns to the caller whether the crypto parameters
+ * change from the previous SDP or not.
+ *
+ * Parameters:
+ * rcv_only - If TRUE, check for receive port perspective.
+ * media - pointer to fsmdef_media_t where the media transport is.
+ *
+ * Returns:
+ * TRUE - when crypto parameters changed
+ * FALSE - when crypto parameters did not change
+ */
+boolean
+gsmsdp_crypto_params_change (boolean rcv_only, fsmdef_media_t *media)
+{
+ if (rcv_only) {
+ if (media->negotiated_crypto.flags & FSMDEF_CRYPTO_RX_CHANGE) {
+ return (TRUE);
+ }
+ } else {
+ if (media->negotiated_crypto.flags & FSMDEF_CRYPTO_TX_CHANGE) {
+ return (TRUE);
+ }
+ }
+ return (FALSE);
+}
+
+/**
+ * The function resets crypto parameters change status.
+ *
+ * @param[in] media - pointer to fsmdef_media_t.
+ *
+ * @return None.
+ *
+ * @pre (media not_eq NULL)
+ */
+void
+gsmsdp_crypto_reset_params_change (fsmdef_media_t *media)
+{
+ media->negotiated_crypto.flags &= ~(FSMDEF_CRYPTO_RX_CHANGE |
+ FSMDEF_CRYPTO_TX_CHANGE);
+}
diff --git a/libs/sipcc/core/gsm/h/fim.h b/libs/sipcc/core/gsm/h/fim.h
new file mode 100755
index 0000000000..5eeb26a354
--- /dev/null
+++ b/libs/sipcc/core/gsm/h/fim.h
@@ -0,0 +1,66 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _FIM_H_
+#define _FIM_H_
+
+#include "sm.h"
+#include "fsm.h"
+
+/*
+ * This is an overlay structure.
+ * Every entity cb must have these two fields at the start of the cb
+ */
+typedef struct fim_cb_hdr_ {
+ callid_t call_id;
+ int state;
+} fim_cb_hdr_t;
+
+#ifndef fim_icb_t__
+#define fim_icb_t__
+struct fim_icb_t_;
+typedef struct fim_icb_t_ fim_icb_t;
+#endif
+
+typedef void (*fim_func_t)(fim_icb_t *elem, callid_t call_id);
+
+typedef struct fim_scb_t_ {
+ fsm_types_t type;
+ sm_table_t *sm;
+ fim_func_t get_cb;
+ fim_func_t free_cb;
+} fim_scb_t;
+
+struct fim_icb_t_ {
+ struct fim_icb_t_ *next_chn;
+ struct fim_icb_t_ *next_icb;
+ callid_t call_id;
+ boolean ui_locked;
+ void *cb;
+ fim_scb_t *scb;
+};
+
+
+const char *fim_event_name(int event);
+boolean fim_process_event(void *data, boolean cac_passed);
+void fim_free_event(void *data);
+void fim_init(void);
+void fim_shutdown(void);
+void fsmcnf_free_cb(fim_icb_t *icb, callid_t call_id);
+void fsmxfr_free_cb(fim_icb_t *icb, callid_t call_id);
+void fsmdef_free_cb(fim_icb_t *icb, callid_t call_id);
+void fsmb2bcnf_free_cb(fim_icb_t *icb, callid_t call_id);
+
+void fim_lock_ui(callid_t call_id);
+void fim_unlock_ui(callid_t call_id);
+
+cc_causes_t
+fsm_cac_process_bw_avail_resp(void);
+cc_causes_t
+fsm_cac_process_bw_failed_resp(void);
+cc_causes_t
+fsm_cac_call_bandwidth_req(callid_t call_id, uint32_t sessions,
+ void *msg);
+
+#endif /* _FIM_H_ */
diff --git a/libs/sipcc/core/gsm/h/fsm.h b/libs/sipcc/core/gsm/h/fsm.h
new file mode 100755
index 0000000000..c009179ad1
--- /dev/null
+++ b/libs/sipcc/core/gsm/h/fsm.h
@@ -0,0 +1,768 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _FSM_H_
+#define _FSM_H_
+
+#include "cpr_types.h"
+#include "sm.h"
+#include "ccapi.h"
+#include "vcm.h"
+#include "ccsip_core.h"
+#include "sll_lite.h"
+#include "sessionConstants.h"
+#include "ccsdp.h"
+
+/* TODO: BLASBERG
+ * fsm.h only needs the following from ccsip_core.h
+ * should put basic sip types into a separate hdr file
+typedef enum {
+ ALERTING_NONE,
+ ALERTING_OLD,
+ ALERTING_TONE,
+ ALERTING_RING
+} alertingType;
+*/
+
+
+#define FSMCNF_MAX_CCBS (LSM_MAX_LINES)
+#define FSMXFR_MAX_XCBS (LSM_MAX_LINES)
+#define FSM_NO_ID (0)
+#define FSMDEF_NO_DCB (NULL)
+#define FSMDEF_ERR_ONHOOK_TMR_SECS (20)
+
+#define FSMDEF_MAX_DIGEST_ALG_LEN 10
+#define FSMDEF_MAX_DIGEST_LEN 32 * 3
+
+// Should match define for SIP stack MAX_SIP_URL_LENGTH
+#define FSMDEF_MAX_CALLER_ID_LEN (256)
+
+#ifndef fim_icb_t__
+#define fim_icb_t__
+struct fim_icb_t_;
+typedef struct fim_icb_t_ fim_icb_t;
+#endif
+
+typedef enum {
+ PRIMARY,
+ MONITOR,
+ LOCAL_CONF,
+ WHISPER_COACHING
+} fsm_session_t;
+
+typedef enum {
+ DIAL_MODE_NUMERIC,
+ DIAL_MODE_URL
+} dialMode_t;
+
+typedef enum {
+ FSMDEF_CALL_TYPE_MIN = -1,
+ FSMDEF_CALL_TYPE_NONE = CC_CALL_TYPE_NONE,
+ FSMDEF_CALL_TYPE_INCOMING = CC_CALL_TYPE_INCOMING,
+ FSMDEF_CALL_TYPE_OUTGOING = CC_CALL_TYPE_OUTGOING,
+ FSMDEF_CALL_TYPE_FORWARD = CC_CALL_TYPE_FORWARDED,
+ FSMDEF_CALL_TYPE_MAX
+} fsmdef_call_types_t;
+
+typedef enum {
+ FSMDEF_S_MIN = -1,
+ FSMDEF_S_IDLE,
+ FSMDEF_S_COLLECT_INFO,
+ FSMDEF_S_CALL_SENT,
+ FSMDEF_S_OUTGOING_PROCEEDING,
+ FSMDEF_S_KPML_COLLECT_INFO,
+ FSMDEF_S_OUTGOING_ALERTING,
+ FSMDEF_S_INCOMING_ALERTING,
+ FSMDEF_S_CONNECTING,
+ FSMDEF_S_JOINING,
+ FSMDEF_S_CONNECTED,
+ FSMDEF_S_CONNECTED_MEDIA_PEND,
+ FSMDEF_S_RELEASING,
+ FSMDEF_S_HOLD_PENDING,
+ FSMDEF_S_HOLDING,
+ FSMDEF_S_RESUME_PENDING,
+ FSMDEF_S_PRESERVED,
+ FSMDEF_S_MAX
+} fsmdef_states_t;
+
+typedef enum {
+ FSMDEF_MRTONE_NO_ACTION = 0,
+ FSMDEF_MRTONE_PLAYED_MONITOR_TONE,
+ FSMDEF_MRTONE_PLAYED_RECORDER_TONE,
+ FSMDEF_MRTONE_PLAYED_BOTH_TONES,
+ FSMDEF_MRTONE_RESUME_MONITOR_TONE,
+ FSMDEF_MRTONE_RESUME_RECORDER_TONE,
+ FSMDEF_MRTONE_RESUME_BOTH_TONES
+} fsmdef_monrec_tone_action_e;
+
+typedef enum {
+ FSMDEF_PLAYTONE_NO_ACTION = 0,
+ FSMDEF_PLAYTONE_ZIP
+} fsmdef_play_tone_action_e;
+
+/* Local crypto parameter is the local parameters to offer */
+typedef struct fsmdef_crypto_param_t_ {
+ int32_t tag; /* crypto attribute tag */
+ vcm_crypto_algorithmID algorithmID; /* encryption algorithm. */
+ vcm_crypto_key_t key; /* local key */
+} fsmdef_crypto_param_t;
+
+/* Negotiated crypto parameter */
+#define FSMDEF_CRYPTO_TX_CHANGE (1 << 0) /* crypto Tx parms. change */
+#define FSMDEF_CRYPTO_RX_CHANGE (1 << 1) /* crypto Tx parms. change */
+typedef struct fsmdef_negotiated_crypto_t_ {
+ int32_t tag; /* crypto attribute tag */
+ vcm_crypto_algorithmID algorithmID; /* algorithm ID */
+ vcm_crypto_key_t tx_key; /* tx key */
+ vcm_crypto_key_t rx_key; /* rx key */
+ uint32_t flags; /* misc. flags. */
+ char algorithm[FSMDEF_MAX_DIGEST_ALG_LEN];
+ char digest[FSMDEF_MAX_DIGEST_LEN];
+} fsmdef_negotiated_crypto_t;
+
+/*
+ * Saved attributes of interest from previously received SDP
+ */
+typedef struct fsmdef_previous_sdp_ {
+ uint16_t dest_port;
+ cpr_ip_addr_t dest_addr;
+ int32_t avt_payload_type;
+
+ /*
+ * This field contains the number of elements in the payloads field.
+ */
+ int32_t num_payloads;
+ vcm_payload_info_t* payloads;
+
+ uint16_t packetization_period;
+ uint16_t max_packetization_period;
+ sdp_direction_e direction;
+ int32_t tias_bw;
+ int32_t profile_level;
+} fsmdef_previous_sdp_t;
+
+typedef struct fsmdef_media_t_ {
+ sll_lite_node_t node; /* link node, must be first member of struct */
+ media_refid_t refid; /* media reference id */
+ sdp_media_e type; /* audio, video etc. media */
+ sdp_addrtype_e addr_type;/* ipv4, ipv6 */
+ int32_t avt_payload_type;
+ vcm_vad_t vad;
+ uint16_t packetization_period;
+ uint16_t max_packetization_period;
+ uint16_t mode;
+ uint16_t level;
+ boolean direction_set;
+ sdp_direction_e direction; /* current negotiated direction */
+ sdp_direction_e support_direction; /* supported direction */
+ sdp_transport_e transport;
+ uint16_t src_port; /* source port for this media stream */
+ cpr_ip_addr_t src_addr; /* source addr for this media stream */
+ uint16_t dest_port; /* destination port for this media stream */
+ cpr_ip_addr_t dest_addr; /* destination addr for this media straam */
+ /* Flag to indicate if Multicast */
+ boolean is_multicast;
+ uint16_t multicast_port;
+ /*
+ * rcv_chan indicates if the receive media stream has been opened
+ */
+ boolean rcv_chan;
+ /*
+ * xmit_chan indicates if the transmit media stream has been opened
+ */
+ boolean xmit_chan;
+
+ /*
+ * SRTP support.
+ */
+ fsmdef_negotiated_crypto_t negotiated_crypto;
+
+ /*
+ * Local crypto holds the local offered crypto set, keeps it in the
+ * dcb for fast access. The alternative to be kept in the
+ * SDP structure but is slower in retrieving it. In the future,
+ * it is possible that more than 1 crypto lines are offered but
+ * for now it is one.
+ */
+ fsmdef_crypto_param_t local_crypto;
+
+ /*
+ * Used to track previously received SDP for comparisons to
+ * newly received media to determine if RTP port recycling is
+ * required. Eliminates unnecessary recycling of ports which
+ * causes breaks in the audio stream.
+ */
+ fsmdef_previous_sdp_t previous_sdp;
+
+ /*
+ * hold tracks the hold state. The flag is a bit map so it is possible that
+ * the phone may have multiple holding states, ie. local and remote
+ */
+ uint32_t hold;
+ /*
+ * Flags fields for various bit flags
+ */
+#define FSM_MEDIA_F_SUPPORT_SECURITY (1 << 0) /* supported security */
+ uint32_t flags;
+
+ /*
+ * capability index. The index into the media capbilty table
+ * that this media entry is coresponding to.
+ */
+ uint8_t cap_index;
+
+ /* Values cached from attributes */
+ int32_t tias_bw;
+ int32_t profile_level;
+
+ void *video;
+
+ /* ICE Candidates */
+ char **candidatesp;
+ int candidate_ct;
+
+ /*
+ * rtcp-mux indicates media stream is muxed for RTP and RTCP
+ */
+ boolean rtcp_mux;
+
+ /*
+ * port number used in m= data channel line
+ */
+ uint16_t sctp_port;
+
+ /*
+ * Data Channel properties
+ */
+ uint32 streams;
+ char *protocol;
+
+ /*
+ * This field contains the number of elements in the payloads field.
+ */
+ int32_t num_payloads;
+
+ /*
+ * List of active lists of payloads negotiated
+ */
+ vcm_payload_info_t* payloads;
+
+} fsmdef_media_t;
+
+struct fsm_fcb_t_;
+
+typedef struct {
+ callid_t call_id;
+ callid_t join_call_id;
+ line_t line;
+ cc_caller_id_t caller_id;
+ groupid_t group_id;
+ int digit_cnt;
+ fsmdef_call_types_t call_type;
+ fsm_session_t session;
+ boolean send_release;
+ int msgs_sent;
+ int msgs_rcvd;
+ boolean onhook_received;
+
+ /*
+ * inband indicates if inband alerting is active
+ */
+ boolean inband;
+
+ /*
+ * inband_received indicates if inband alerting has been received.
+ * Once set, this bool stays set until dcb is reset.
+ */
+ boolean inband_received;
+
+ /*
+ * outofband tracks the payload type for outofband DTMF
+ */
+ int outofband;
+
+ /*
+ * Boolean indication of whether call was originated by phone or
+ * far end party.
+ */
+ boolean inbound;
+
+ /*
+ * The following data tracks the RTP info
+ */
+ boolean remote_sdp_present;
+ boolean remote_sdp_in_ack;
+ uint16_t src_sdp_version;
+ cc_sdp_t *sdp;
+
+ /* media list corresponding to m lines */
+ sll_lite_list_t media_list;
+
+ /*
+ * dial_mode tracks the state of the dialing mode icon, ie. alphanumeric or
+ * numeric
+ */
+ dialMode_t dial_mode;
+
+ /*
+ * pd_updated tracks whether or not the personal directory has
+ * been updated
+ */
+ boolean pd_updated;
+
+ /* tracks the ringing pattern to play */
+ vcm_ring_mode_t alerting_ring;
+
+ /* tracks the tone to play */
+ vcm_tones_t alerting_tone;
+
+ /* tracks the direction to play the tone. */
+ uint16_t tone_direction;
+
+ /* Was an alert-info header present, if so what did it contain */
+ cc_alerting_type alert_info;
+
+ /* used to determine when SIP stack releases the call early. */
+ boolean early_error_release;
+
+ /* used to determine when we are played a tone via the dialplan */
+ boolean dialplan_tone;
+
+ /* active tone (i.e. tone currently being played or requested to be played) */
+ vcm_tones_t active_tone;
+
+ /* indicates the action of monitor and recorder tones */
+ fsmdef_monrec_tone_action_e monrec_tone_action;
+
+ /* monitor/recorder tone direction to play out to */
+ uint16_t monitor_tone_direction;
+ uint16_t recorder_tone_direction;
+
+ /* indicates the action of play tone for a single time */
+ fsmdef_play_tone_action_e play_tone_action;
+
+ struct fsm_fcb_t_ *fcb;
+
+ /* Feature that is currently active */
+ cc_features_t active_feature;
+
+ /* Reason for hold */
+ cc_hold_resume_reason_e hold_reason;
+
+ /* Feature invocation state.
+ * Each feature will correspond to unique bit in variable.
+ * Bit will be Set if feature is invoked and awaiting feature ACK.
+ * Bit will be Cleared if feature is ACKed or not yet invoked.
+ * Each array element will hold invocation state for 32 features.
+ * The resource manager utility is utilized to maintain the bit settings.
+ */
+ void *feature_invocation_state;
+
+ /* TRUE if CCM has requested phone to show ringout UI */
+ boolean spoof_ringout_requested;
+ /* TRUE if GSM has applied ringout due to CCMs request to show ringout UI */
+ boolean spoof_ringout_applied;
+
+ /* Timer to go on hook after any call error */
+ cprTimer_t err_onhook_tmr;
+
+ /* Request pending timer */
+ cprTimer_t req_pending_tmr;
+
+ /* Ringback delay timer */
+ cprTimer_t ringback_delay_tmr;
+
+ /*
+ * save of orientation from callInfo to update UI at any time
+ * other than during call info. update such as after Tx start in
+ * order to update security icon.
+ */
+ cc_orientation_e orientation;
+
+ /*
+ * This boolean is used to short circuit sending UI update requests to the platform
+ * so that requests are only made when one of the call ui components requires
+ * updating. The same is done for placed call history.
+ */
+ boolean ui_update_required;
+ boolean placed_call_update_required;
+
+ boolean is_conf_call;
+
+ cc_security_e security;
+ cc_policy_e policy;
+
+ /* auto answer timer */
+ cprTimer_t autoAnswerTimer;
+ int32_t reversionInterval;
+ cprTimer_t revertTimer;
+
+ boolean dsp_out_of_resources;
+
+ boolean selected;
+
+ boolean select_pending;
+
+ boolean call_not_counted_in_mnc_bt;
+
+ /*
+ * The media_cap holds the current media caps of the call
+ */
+ cc_media_cap_table_t *media_cap_tbl;
+
+ /*
+ * Holds the remote stream track information to be passed to UI
+ */
+ cc_media_remote_stream_table_t *remote_media_stream_tbl;
+
+ /*
+ * Holds the local stream track information passed in from the UI
+ */
+ cc_media_local_track_table_t *local_media_track_tbl;
+
+#define FSMDEF_F_HOLD_REQ_PENDING (1 << 0)/* hold feature pending */
+#define FSMDEF_F_XFER_COMPLETE (1 << 1)/* hold feature pending */
+ uint32_t flags; /* misc. flags. */
+
+ int log_disp;
+
+ uint8_t cur_video_avail;
+ sdp_direction_e video_pref;
+ unsigned int callref; /* Callref (CI) from CUCM */
+
+ char peerconnection[PC_HANDLE_SIZE]; /* A handle to the peerconnection */
+ boolean peerconnection_set;
+
+ char *ice_ufrag;
+ char *ice_pwd;
+ char ice_default_candidate_addr[MAX_IPADDR_STR_LEN];
+
+ char digest_alg[FSMDEF_MAX_DIGEST_ALG_LEN];
+ char digest[FSMDEF_MAX_DIGEST_LEN];
+
+} fsmdef_dcb_t;
+
+typedef enum fsm_types_t_ {
+ FSM_TYPE_MIN = -1,
+ FSM_TYPE_NONE = FSM_TYPE_MIN,
+ FSM_TYPE_HEAD,
+ FSM_TYPE_CNF,
+ FSM_TYPE_B2BCNF,
+ FSM_TYPE_XFR,
+ FSM_TYPE_DEF,
+ FSM_TYPE_MAX
+} fsm_types_t;
+
+typedef enum fsm_hold_t_ {
+ FSM_HOLD_MIN = -1,
+ FSM_HOLD_NONE = 0,
+ FSM_HOLD_LCL = 1,
+ FSM_HOLD_MAX = 2
+} fsm_hold_t;
+
+typedef struct fsm_data_def_t_ {
+ int hold;
+} fsm_data_def_t;
+
+typedef struct fsm_data_xfr_t_ {
+ int xfr_id;
+} fsm_data_xfr_t;
+
+typedef struct fsm_data_t_ {
+ union {
+ fsm_data_def_t def;
+ fsm_data_xfr_t xfr;
+ } data;
+} fsm_data_t;
+
+typedef struct fsmcnf_ccb_t_ {
+ cc_srcs_t cnf_orig;
+ int cnf_id;
+ callid_t cnf_call_id;
+ callid_t cns_call_id;
+ line_t cnf_line;
+ line_t cns_line;
+ boolean active;
+ boolean bridged;
+
+/* The following field encodes flags */
+#define JOINED 0x1
+#define XFER 0x2
+#define LCL_CNF 0x4
+ uint32_t flags;
+ boolean cnf_ftr_ack;
+} fsmcnf_ccb_t;
+
+typedef enum fsmxfr_types_t_ {
+ FSMXFR_TYPE_MIN = -1,
+ FSMXFR_TYPE_NONE,
+ FSMXFR_TYPE_XFR,
+ FSMXFR_TYPE_BLND_XFR,
+ FSMXFR_TYPE_DIR_XFR,
+ FSMXFR_TYPE_MAX
+} fsmxfr_types_t;
+
+typedef enum fsmxfr_modes_t_ {
+ FSMXFR_MODE_MIN = -1,
+ FSMXFR_MODE_TRANSFEROR,
+ FSMXFR_MODE_TRANSFEREE,
+ FSMXFR_MODE_TARGET
+} fsmxfr_modes_t;
+
+struct fsmxfr_xcb_t_;
+typedef struct fsmxfr_xcb_t_ {
+ cc_srcs_t xfr_orig;
+ int xfr_id;
+ callid_t xfr_call_id;
+ callid_t cns_call_id;
+ line_t xfr_line;
+ line_t cns_line;
+ fsmxfr_types_t type;
+ cc_xfer_methods_t method;
+ char *dialstring;
+ char *queued_dialstring;
+ char *referred_by;
+ boolean active;
+ boolean cnf_xfr;
+ boolean xfer_comp_req;
+ fsmxfr_modes_t mode;
+ struct fsmxfr_xcb_t_ *xcb2;
+} fsmxfr_xcb_t;
+
+
+typedef struct fsm_fcb_t_ {
+ callid_t call_id;
+
+ int state;
+ int old_state;
+
+ fsm_types_t fsm_type;
+
+
+ /*
+ * fsmdef specific data
+ */
+ fsmdef_dcb_t *dcb;
+
+ /*
+ * fsmxfr specific data
+ */
+
+ fsmxfr_xcb_t *xcb;
+ /*
+ * fsmcnf specific data
+ */
+ fsmcnf_ccb_t *ccb;
+
+ /*
+ * fsmb2bcnf specific data
+ */
+ fsmcnf_ccb_t *b2bccb;
+
+} fsm_fcb_t;
+
+typedef enum {
+ FSMDEF_MSG_MIN = -1,
+ FSMDEF_MSG_NONE = 0,
+ FSMDEF_MSG_SETUP = 1,
+ FSMDEF_MSG_SETUP_ACK = 2,
+ FSMDEF_MSG_PROCEEDING = 4,
+ FSMDEF_MSG_ALERTING = 8,
+ FSMDEF_MSG_CONNECTED = 16,
+ FSMDEF_MSG_CONNECTED_ACK = 32,
+ FSMDEF_MSG_RELEASE = 64,
+ FSMDEF_MSG_RELEASE_COMPLETE = 128,
+ FSMDEF_MSG_MAX
+} fsmdef_msgs_t;
+
+#define FSM_FOR_ALL_CBS(cb, cbs, max_cbs) \
+ for ((cb) = (cbs); (cb) <= &((cbs)[(max_cbs-1)]); (cb)++)
+
+#define FSM_CHK_FLAGS(flags, flag) ((flags) & (flag))
+#define FSM_SET_FLAGS(flags, flag) ((flags) |= (flag))
+#define FSM_RESET_FLAGS(flags, flag) ((flags) &= ~(flag))
+void *fsmdef_feature_timer_timeout(cc_features_t feature_id, void *);
+void fsmdef_end_call(fsmdef_dcb_t *dcb, cc_causes_t cause);
+void fsm_sm_ftr(cc_features_t ftr_id, cc_srcs_t src_id);
+void fsm_sm_ignore_ftr(fsm_fcb_t *fcb, int fname,
+ cc_features_t ftr_id);
+void fsm_sm_ignore_src(fsm_fcb_t *fcb, int fname, cc_srcs_t src_id);
+const char *fsm_state_name(fsm_types_t type, int id);
+const char *fsm_type_name(fsm_types_t type);
+fsmdef_dcb_t *fsm_get_dcb(callid_t call_id);
+void fsm_init_scb(fim_icb_t *icb, callid_t call_id);
+fsm_fcb_t *fsm_get_fcb_by_call_id(callid_t call_id);
+fsm_fcb_t *fsm_get_fcb_by_call_id_and_type(callid_t call_id, fsm_types_t type);
+void
+fsm_get_fcb_by_selected_or_connected_call_fcb(callid_t call_id, fsm_fcb_t **con_fcb_found,
+ fsm_fcb_t **sel_fcb_found);
+fsm_fcb_t *fsm_get_new_fcb(callid_t call_id, fsm_types_t fsm_type);
+void fsm_init(void);
+void fsm_shutdown(void);
+void fsm_release(fsm_fcb_t *fcb, int fname, cc_causes_t cause);
+void fsm_change_state(fsm_fcb_t *fcb, int fname, int new_state);
+void fsm_init_fcb(fsm_fcb_t *fcb, callid_t call_id, fsmdef_dcb_t *dcb,
+ fsm_types_t type);
+void fsm_display_no_free_lines(void);
+void fsm_display_use_line_or_join_to_complete(void);
+void fsm_display_feature_unavailable(void);
+void fsm_set_call_status_feature_unavailable(callid_t call_id, line_t line);
+
+cc_causes_t fsm_get_new_outgoing_call_context(callid_t call_id, line_t line,
+ fsm_fcb_t *fcb, boolean expline);
+cc_causes_t fsm_get_new_incoming_call_context(callid_t call_id, fsm_fcb_t *fcb,
+ const char *called_number,
+ boolean expline);
+sm_rcs_t fsmdef_release(fsm_fcb_t *fcb, cc_causes_t cause,
+ boolean send_release);
+int fsmdef_get_call_type_by_call_id(callid_t call_id);
+fsmdef_call_types_t fsmdef_get_call_id_by_call_ref(int call_ref);
+fsmdef_dcb_t *fsmdef_get_dcb_by_call_id(callid_t call_id);
+void fsmdef_init_dcb(fsmdef_dcb_t *dcb, callid_t call_id,
+ fsmdef_call_types_t call_type,
+ const char *called_number, line_t line,
+ fsm_fcb_t *fcb);
+cc_causes_t fsm_set_fcb_dcbs (fsmdef_dcb_t *dcb);
+fsmdef_dcb_t *fsmdef_get_new_dcb(callid_t call_id);
+void fsmdef_init(void);
+int fsmdef_get_active_call_cnt(callid_t callId);
+fsmdef_dcb_t *fsmdef_get_connected_call(void);
+boolean fsmdef_are_join_calls_on_same_line(line_t line);
+boolean fsmdef_are_there_selected_calls_onotherline(line_t line);
+fsmdef_dcb_t *fsmdef_get_other_dcb_by_line(callid_t call_id, line_t line);
+int fsmdef_get_dcbs_in_held_state(fsmdef_dcb_t **dcb,
+ callid_t ignore_call_id);
+sm_rcs_t fsmdef_offhook(fsm_fcb_t *fcb, cc_msgs_t msg_id, callid_t call_id,
+ line_t line, const char *dial_string, sm_event_t *event,
+ char *global_call_id, callid_t prim_call_id,
+ cc_hold_resume_reason_e consult_reason,
+ monitor_mode_t monitor_mode);
+
+sm_rcs_t fsmdef_dialstring(fsm_fcb_t *fcb, const char *dialstring,
+ cc_redirect_t *redirect, boolean replace,
+ cc_call_info_t *call_info);
+
+fsmcnf_ccb_t *fsmcnf_get_ccb_by_call_id(callid_t call_id);
+callid_t fsmcnf_get_other_call_id(fsmcnf_ccb_t *ccb, callid_t call_id);
+
+void fsmxfr_update_xfr_context(fsmxfr_xcb_t *xcb, callid_t old_call_id,
+ callid_t new_call_id);
+fsmxfr_xcb_t *fsmxfr_get_xcb_by_call_id(callid_t call_id);
+callid_t fsmxfr_get_other_call_id(fsmxfr_xcb_t *xcb, callid_t call_id);
+fsmxfr_types_t fsmxfr_get_xfr_type(callid_t call_id);
+cc_features_t fsmxfr_type_to_feature(fsmxfr_types_t type);
+
+#ifdef _WIN32
+extern void NotifyStateChange(callid_t callid, int32_t state);
+#define NOTIFY_STATE_CHANGE(fcb,callid,state) NotifyStateChange(callid,state);dcsm_update_gsm_state(fcb,callid,state)
+#else
+#define NOTIFY_STATE_CHANGE(fcb,callid,state) dcsm_update_gsm_state(fcb,callid,state)
+#endif
+
+const char *fsmdef_state_name(int id);
+const char *fsmxfr_state_name(int id);
+const char *fsmcnf_state_name(int id);
+
+void fsm_cac_init(void);
+void fsmcnf_init(void);
+void fsmxfr_init(void);
+void fsmdef_init(void);
+void fsmcnf_shutdown(void);
+void fsmxfr_shutdown(void);
+void fsmdef_shutdown(void);
+void fsm_cac_shutdown(void);
+void fsm_cac_call_release_cleanup(callid_t call_id);
+
+void fsmdef_reversion_timeout(callid_t call_id);
+void fsm_cac_process_bw_fail_timer(void *tmr_data);
+void fsmdef_auto_answer_timeout(void *);
+const char *fsmb2bcnf_state_name(int id);
+void fsmb2bcnf_init(void);
+void fsmb2bcnf_shutdown(void);
+int fsmutil_is_b2bcnf_consult_call(callid_t call_id);
+callid_t fsmxfr_get_consult_call_id(callid_t call_id);
+callid_t fsmb2bcnf_get_consult_call_id(callid_t call_id);
+callid_t fsmb2bcnf_get_primary_call_id(callid_t call_id);
+boolean fsmdef_check_if_ok_for_dial_call(line_t line);
+boolean fsmdef_check_if_ok_to_ans_call(line_t line, callid_t call_id);
+boolean fsmdef_check_if_ok_to_resume_call(line_t line, callid_t call_id);
+boolean fsmdef_check_if_ok_to_hold_call(line_t line, callid_t call_id);
+boolean fsmdef_check_if_ok_to_monitor_update_call(line_t line, callid_t call_id);
+boolean fsmdef_check_if_ok_to_run_feature(line_t line, callid_t call_id);
+fsmdef_dcb_t *fsmdef_get_dcb_by_call_instance_id(line_t line,
+ uint16 call_instance_id);
+boolean fsmb2bcnf_check_if_ok_to_setup_conf (callid_t call_id);
+boolean fsmdef_check_if_chaperone_call_exist (void);
+void fsmdef_call_cc_state_dialing(fsmdef_dcb_t *dcb, boolean suppressStutter);
+/* This macro is to identify incoming joining call */
+#define fsm_is_joining_call(feat_data) \
+ ((feat_data.newcall.join.join_call_id != CC_NO_CALL_ID) && \
+ ((feat_data.newcall.cause == CC_CAUSE_BARGE) || \
+ (feat_data.newcall.cause == CC_CAUSE_MONITOR)))
+/* These macros are for SRTP support */
+#define FSM_GET_SECURITY_STATUS(dcb) (dcb->security)
+#define FSM_SET_SECURITY_STATUS(dcb, status) (dcb->security = status)
+#define FSM_GET_POLICY(dcb) (dcb->policy)
+#define FSM_SET_POLICY(dcb, status) (dcb->policy = status)
+#define FSM_GET_CACHED_ORIENTATION(dcb) (dcb->orientation)
+#define FSM_SET_CACHED_ORIENTATION(dcb, value) (dcb->orientation = value)
+#define FSM_NEGOTIATED_CRYPTO_ALGORITHM_ID(media) \
+ ((media->transport == SDP_TRANSPORT_RTPSAVP || \
+ media->transport == SDP_TRANSPORT_RTPSAVPF) ? \
+ media->negotiated_crypto.algorithmID : VCM_NO_ENCRYPTION)
+#define FSM_NEGOTIATED_CRYPTO_RX_KEY(media) \
+ &media->negotiated_crypto.rx_key
+#define FSM_NEGOTIATED_CRYPTO_TX_KEY(media) \
+ &media->negotiated_crypto.tx_key
+
+#define FSM_NEGOTIATED_CRYPTO_DIGEST_ALGORITHM(media) \
+ media->negotiated_crypto.algorithm
+
+#define FSM_NEGOTIATED_CRYPTO_DIGEST(media) \
+ media->negotiated_crypto.digest
+
+int fsmutil_get_call_attr(fsmdef_dcb_t *dcb, line_t line, callid_t call_id);
+uint16_t fsmutil_get_ci_id(line_t line);
+void fsmutil_init_ci_map(void);
+void fsmdef_platform_dcb_init(fsmdef_dcb_t *dcb);
+void fsmutil_free_all_ci_id(void);
+void fsmutil_free_ci_id(uint16_t id, line_t line);
+void fsmutil_set_ci_id(uint16_t id, line_t line);
+void fsmutil_free_ci_map(void);
+void fsmutil_show_ci_map(void);
+void fsmutil_init_shown_calls_ci_map(void);
+void fsmutil_free_all_shown_calls_ci_map(void);
+void fsmutil_clear_shown_calls_ci_element(uint16_t id, line_t line);
+void fsmutil_set_shown_calls_ci_element(uint16_t id, line_t line);
+boolean fsmutil_is_shown_calls_ci_element_set(uint16_t id, line_t line);
+
+
+callid_t fsmxfr_get_primary_call_id(callid_t call_id);
+uint16_t fsmutil_get_num_selected_calls(void);
+int fsmutil_is_cnf_consult_call(callid_t call_id);
+int fsmutil_is_cnf_consult_leg(callid_t call_id, fsmcnf_ccb_t *fsmcnf_ccbs,
+ uint16_t max_ccbs);
+int fsmutil_is_xfr_consult_call(callid_t call_id);
+int fsmutil_is_xfr_consult_leg(callid_t call_id, fsmxfr_xcb_t *fsmxfr_xcbs,
+ uint16_t max_xcbs);
+void fsmutil_init_groupid(fsmdef_dcb_t *dcb, callid_t call_id,
+ fsmdef_call_types_t call_type);
+void fsmutil_process_feature_ack(fsmdef_dcb_t *dcb, cc_features_t feature_id);
+void fsmutil_clear_all_feature_invocation_state(fsmdef_dcb_t *dcb);
+void fsmutil_init_feature_invocation_state(fsmdef_dcb_t *dcb);
+void fsmutil_free_feature_invocation_state(fsmdef_dcb_t *dcb);
+
+void fsmdef_error_onhook_timeout(void *data);
+
+int fsmutil_is_xfr_leg(callid_t call_id, fsmxfr_xcb_t *fsmxfr_xcbs,
+ unsigned short max_xcbs);
+int fsmutil_is_cnf_leg(callid_t call_id, fsmcnf_ccb_t *fsmcnf_ccbs,
+ unsigned short max_ccbs);
+
+void fsm_display_control_ringin_calls(boolean hide);
+void fsmdef_update_media_cap_feature_event(cc_feature_t *msg);
+boolean fsmcnd_conf_call_id_valid(fsmcnf_ccb_t *ccb);
+
+boolean fsmdef_check_retain_fwd_info_state(void);
+#endif
diff --git a/libs/sipcc/core/gsm/h/gsm.h b/libs/sipcc/core/gsm/h/gsm.h
new file mode 100755
index 0000000000..ba6cafccfc
--- /dev/null
+++ b/libs/sipcc/core/gsm/h/gsm.h
@@ -0,0 +1,59 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _GSM_H_
+#define _GSM_H_
+
+#include "cpr_types.h"
+#include "cpr_memory.h"
+#include "cpr_ipc.h"
+#include "cpr_stdio.h"
+
+#define GSM_ERR_MSG err_msg
+typedef void(* media_timer_callback_fp) (void);
+void gsm_set_media_callback(media_timer_callback_fp* callback);
+
+void gsm_set_initialized(void);
+cpr_status_e gsm_send_msg(uint32_t cmd, cprBuffer_t buf, uint16_t len);
+cprBuffer_t gsm_get_buffer(uint16_t size);
+boolean gsm_is_idle(void);
+
+/*
+ * List of timers that the GSM task is responsible for.
+ * CPR will send a msg to the GSM task when these
+ * timers expire. CPR expects a timer id when the timer
+ * is created, this enum serves that purpose.
+ */
+typedef enum {
+ GSM_ERROR_ONHOOK_TIMER,
+ GSM_AUTOANSWER_TIMER,
+ GSM_DIAL_TIMEOUT_TIMER,
+ GSM_KPML_INTER_DIGIT_TIMER,
+ GSM_KPML_CRITICAL_DIGIT_TIMER,
+ GSM_KPML_EXTRA_DIGIT_TIMER,
+ GSM_KPML_SUBSCRIPTION_TIMER,
+ GSM_MULTIPART_TONES_TIMER,
+ GSM_CONTINUOUS_TONES_TIMER,
+ GSM_REQ_PENDING_TIMER,
+ GSM_RINGBACK_DELAY_TIMER,
+ GSM_REVERSION_TIMER,
+ GSM_FLASH_ONCE_TIMER,
+ GSM_CAC_FAILURE_TIMER,
+ GSM_TONE_DURATION_TIMER
+} gsmTimerList_t;
+
+/*
+ * The common code creating the GSM timers needs to have
+ * access to the gsm_msg_queue variable since CPR
+ * needs to know where to send the timer expiration
+ * message.
+ */
+extern cprMsgQueue_t gsm_msg_queue;
+
+extern void kpml_process_msg(uint32_t cmd, void *msg);
+extern void dp_process_msg(uint32_t cmd, void *msg);
+extern void kpml_init(void);
+extern void kpml_shutdown(void);
+
+#endif
diff --git a/libs/sipcc/core/gsm/h/gsm_sdp.h b/libs/sipcc/core/gsm/h/gsm_sdp.h
new file mode 100644
index 0000000000..25ae4cfdb9
--- /dev/null
+++ b/libs/sipcc/core/gsm/h/gsm_sdp.h
@@ -0,0 +1,139 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _GSM_SDP_H_
+#define _GSM_SDP_H_
+
+
+#define GSMSDP_VERSION_STR_LEN (20)
+
+#define GSMSDP_MEDIA_VALID(media) \
+ ((media != NULL) && (media->refid != CC_NO_MEDIA_REF_ID))
+
+#define GSMSDP_MEDIA_ENABLED(media) \
+ (GSMSDP_MEDIA_VALID(media) && (media->src_port != 0))
+
+#define GSMSDP_MEDIA_COUNT(dcb) \
+ (SLL_LITE_NODE_COUNT(&dcb->media_list))
+
+#define GSMSDP_FIRST_MEDIA_ENTRY(dcb) \
+ ((fsmdef_media_t *)SLL_LITE_LINK_HEAD(&dcb->media_list))
+
+#define GSMSDP_NEXT_MEDIA_ENTRY(media) \
+ ((fsmdef_media_t *)SLL_LITE_LINK_NEXT_NODE(media))
+
+#define GSMSDP_FOR_MEDIA_LIST(media, start_media, end_media, dcb) \
+ for (media = start_media; (media != NULL); \
+ media = (media != end_media ? \
+ GSMSDP_NEXT_MEDIA_ENTRY(media) : NULL))
+
+#define GSMSDP_FOR_ALL_MEDIA(media, dcb) \
+ for (media = GSMSDP_FIRST_MEDIA_ENTRY(dcb); (media != NULL); \
+ media = GSMSDP_NEXT_MEDIA_ENTRY(media))
+
+typedef struct {
+ const char *name;
+ int value;
+} gsmsdp_key_table_entry_t;
+
+typedef enum constraints_ {
+ OfferToReceiveAudio = 0,
+ OfferToReceiveVideo = 1,
+ VoiceActivityDetection = 2
+} constraints;
+
+static const gsmsdp_key_table_entry_t constraints_table[] = {
+ {"OfferToReceiveAudio", OfferToReceiveAudio},
+ {"OfferToReceiveVideo", OfferToReceiveVideo},
+ {"VoiceActivityDetection", VoiceActivityDetection}
+};
+
+cc_causes_t gsmsdp_create_local_sdp(fsmdef_dcb_t *dcb_p, boolean force_streams_enabled,
+ boolean audio, boolean video, boolean data, boolean offer);
+void gsmsdp_create_options_sdp(cc_sdp_t **sdp_pp);
+void gsmsdp_reset_local_sdp_media(fsmdef_dcb_t *dcb, fsmdef_media_t *media,
+ boolean hold);
+void gsmsdp_set_local_sdp_direction(fsmdef_dcb_t *dcb_p, fsmdef_media_t *media,
+ sdp_direction_e direction);
+void gsmsdp_set_local_hold_sdp(fsmdef_dcb_t *dcb, fsmdef_media_t *media);
+void gsmsdp_set_local_resume_sdp(fsmdef_dcb_t *dcb, fsmdef_media_t *media);
+cc_causes_t gsmsdp_negotiate_answer_sdp(fsm_fcb_t *fcb,
+ cc_msgbody_info_t *msg_body);
+cc_causes_t gsmsdp_negotiate_offer_sdp(fsm_fcb_t *fcb,
+ cc_msgbody_info_t *msg_body,
+ boolean init);
+cc_causes_t gsmsdp_process_offer_sdp(fsm_fcb_t *fcb,
+ cc_msgbody_info_t *msg_body,
+ boolean init);
+cc_causes_t
+gsmsdp_negotiate_media_lines (fsm_fcb_t *fcb_p, cc_sdp_t *sdp_p, boolean initial_offer,
+ boolean offer, boolean notify_stream_added, boolean create_answer);
+
+boolean gsmsdp_sdp_differs_from_previous_sdp(boolean rcv_only,
+ fsmdef_media_t *media);
+cc_causes_t gsmsdp_encode_sdp(cc_sdp_t *sdp_p, cc_msgbody_info_t *msg_body);
+cc_causes_t gsmsdp_encode_sdp_and_update_version(fsmdef_dcb_t *dcb_p,
+ cc_msgbody_info_t *msg_body);
+void gsmsdp_free(fsmdef_dcb_t *dcb_p);
+fsmdef_media_t *gsmsdp_find_audio_media(fsmdef_dcb_t *dcb_p);
+
+#define gsmsdp_is_srtp_supported() (TRUE)
+extern void gsmsdp_init_sdp_media_transport(fsmdef_dcb_t *dcb,
+ void *sdp,
+ fsmdef_media_t *media);
+extern void gsmsdp_reset_sdp_media_transport(fsmdef_dcb_t *dcb,
+ void *sdp,
+ fsmdef_media_t *media,
+ boolean hold);
+extern sdp_transport_e gsmsdp_negotiate_media_transport(fsmdef_dcb_t *dcb_p,
+ cc_sdp_t *cc_sdp_p,
+ boolean offer,
+ fsmdef_media_t *media,
+ uint16_t *inst_num,
+ uint16 level);
+extern void gsmsdp_update_local_sdp_media_transport(fsmdef_dcb_t *dcb_p,
+ void *sdp_p,
+ fsmdef_media_t *media,
+ sdp_transport_e transport,
+ boolean all);
+extern void gsmsdp_update_negotiated_transport(fsmdef_dcb_t *dcb_p,
+ cc_sdp_t *cc_sdp_p,
+ fsmdef_media_t *media,
+ uint16_t crypto_inst,
+ sdp_transport_e transport,
+ uint16 level);
+extern void gsmsdp_update_crypto_transmit_key(fsmdef_dcb_t *dcb_p,
+ fsmdef_media_t *media,
+ boolean offer,
+ boolean initial_offer,
+ sdp_direction_e direction);
+extern void gsmsdp_set_media_transport_for_option(void *sdp, uint16 level);
+extern boolean gsmsdp_is_crypto_ready(fsmdef_media_t *media, boolean rx);
+extern boolean gsmsdp_is_media_encrypted(fsmdef_dcb_t *dcb_p);
+extern boolean gsmsdp_crypto_params_change(boolean rcv_only,
+ fsmdef_media_t *media);
+extern void gsmsdp_crypto_reset_params_change(fsmdef_media_t *media);
+extern void gsmsdp_cache_crypto_keys(void);
+extern boolean gsmsdp_create_free_media_list(void);
+extern void gsmsdp_destroy_free_media_list(void);
+extern void gsmsdp_init_media_list(fsmdef_dcb_t *dcb_p);
+extern void gsmsdp_clean_media_list(fsmdef_dcb_t *dcb);
+extern fsmdef_media_t *gsmsdp_find_media_by_refid(fsmdef_dcb_t *dcb_p,
+ media_refid_t refid);
+extern boolean gsmsdp_handle_media_cap_change(fsmdef_dcb_t *dcb_p,
+ boolean refresh, boolean hold);
+extern boolean gsmsdp_update_local_sdp_media_capability(fsmdef_dcb_t *dcb_p,
+ boolean refresh, boolean hold);
+boolean is_gsmsdp_media_ip_updated_to_latest( fsmdef_dcb_t * dcb );
+
+void gsmsdp_add_remote_stream(uint16_t idx, int pc_stream_id, fsmdef_dcb_t * dcb, fsmdef_media_t *media);
+cc_causes_t gsmsdp_install_peer_ice_attributes(fsm_fcb_t *fcb_p);
+cc_causes_t gsmsdp_configure_dtls_data_attributes(fsm_fcb_t *fcb_p);
+cc_causes_t gsmsdp_find_level_from_mid(fsmdef_dcb_t * dcb, const char * mid, uint16_t *level);
+void gsmsdp_process_cap_constraints(fsmdef_dcb_t *dcb, const cc_media_constraints_t* constraints);
+cc_causes_t
+gsmsdp_get_offered_media_types (fsm_fcb_t *fcb_p, cc_sdp_t *sdp_p, boolean *has_audio, boolean *has_video, boolean *has_data);
+fsmdef_media_t* gsmsdp_find_media_by_media_type(fsmdef_dcb_t *dcb, sdp_media_e media_type);
+#endif
+
diff --git a/libs/sipcc/core/gsm/h/lsm.h b/libs/sipcc/core/gsm/h/lsm.h
new file mode 100755
index 0000000000..b0df529747
--- /dev/null
+++ b/libs/sipcc/core/gsm/h/lsm.h
@@ -0,0 +1,180 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _LSM_H_
+#define _LSM_H_
+
+#include "cpr_types.h"
+#include "ccapi.h"
+#include "uiapi.h"
+#include "fsm.h"
+
+
+#define LSM_NO_LINE (0)
+#define LSM_NO_INSTANCE (0)
+#define NO_LINES_AVAILABLE (0)
+
+/* FIXME GS - Breaking my own rule - need to figure out how to do a platform
+ * specific include file here
+ */
+#define LSM_MAX_LINES MAX_REG_LINES
+#define LSM_MAX_INSTANCES (MAX_CALLS_PER_LINE-1)
+#define LSM_MAX_EXP_INSTANCES MAX_CALLS_PER_LINE
+#define LSM_MAX_CALLS MAX_CALLS
+
+#define NO_FREE_LINES_TIMEOUT (10)
+#define CALL_ALERT_TIMEOUT (10)
+
+/*
+ * Used to play busy verfication tone
+ */
+#define BUSY_VERIFICATION_DELAY (10000)
+
+/*
+ * Temp until added to config
+ */
+#define TOH_DELAY (10000)
+
+/*
+ * Used to play msg waiting and stutter dialtones.
+ * Both tones are 100ms on/off repeating 10 and
+ * 3 times respectively, followed by steady dialtone.
+ * Due to DSP limitations we first tell the DSP to
+ * play the 100ms on/off pairs the correct number of
+ * times, set a timer, and then tell it to play dialtone.
+ */
+#define MSG_WAITING_DELAY (2050)
+#define STUTTER_DELAY (650)
+
+/*
+ * Used to play the busy verfication tone which
+ * is two seconds of dialtone followed by the
+ * callwaiting tone every ten seconds.
+ */
+#define BUSY_VERIFY_DELAY (12000)
+
+
+/* LSM states */
+typedef enum {
+ LSM_S_MIN = -1,
+ LSM_S_NONE = LSM_S_MIN,
+ LSM_S_IDLE,
+ LSM_S_PENDING,
+ LSM_S_OFFHOOK,
+ LSM_S_ONHOOK,
+ LSM_S_PROCEED,
+ LSM_S_RINGOUT,
+ LSM_S_RINGIN,
+ LSM_S_CONNECTED,
+ LSM_S_BUSY,
+ LSM_S_CONGESTION,
+ LSM_S_HOLDING,
+ LSM_S_CWT,
+ LSM_S_XFER,
+ LSM_S_ATTN_XFER,
+ LSM_S_CONF,
+ LSM_S_INVALID_NUMBER,
+ LSM_S_MAX
+} lsm_states_t;
+
+boolean lsm_is_phone_idle(void);
+int lsm_get_instances_available_cnt(line_t line, boolean expline);
+void lsm_increment_call_chn_cnt(line_t line);
+void lsm_decrement_call_chn_cnt(line_t line);
+line_t lsm_get_newcall_line(line_t line);
+callid_t lsm_get_active_call_id(void);
+line_t lsm_get_line_by_call_id(callid_t call_id);
+/*
+ * The lsm_get_facility_by_called_number() and the lsm_get_facility_by_line()
+ * below are defined to allow be used by fsm state mechine to bind the
+ * LSM to the FSM default state machine only.
+ */
+cc_causes_t lsm_get_facility_by_called_number(callid_t call_id,
+ const char *called_number,
+ line_t *free_line,
+ boolean expline, void *dcb);
+cc_causes_t lsm_get_facility_by_line(callid_t call_id, line_t line,
+ boolean exp, void *dcb);
+char lsm_digit2ch(int digit);
+void lsm_set_active_call_id(callid_t call_id);
+void lsm_init(void);
+void lsm_shutdown(void);
+void lsm_reset(void);
+void lsm_ui_display_notify(const char *pNotifyStr, unsigned long timeout);
+void lsm_ui_display_status(const char *pStatusStr, line_t line,
+ callid_t call_id);
+string_t lsm_parse_displaystr(string_t displaystr);
+void lsm_speaker_mode(short mode);
+void lsm_add_remote_stream (line_t line, callid_t call_id, fsmdef_media_t *media, int *pc_stream_id);
+
+#ifdef _WIN32
+void terminate_active_calls(void);
+#endif
+
+const char *lsm_state_name(lsm_states_t id);
+void lsm_set_cfwd_all_nonccm(line_t line, char *callfwd_dialstring);
+void lsm_set_cfwd_all_ccm(line_t line, char *callfwd_dialstring);
+void lsm_clear_cfwd_all_nonccm(line_t line);
+void lsm_clear_cfwd_all_ccm(line_t line);
+int lsm_check_cfwd_all_nonccm(line_t line);
+int lsm_check_cfwd_all_ccm(line_t line);
+char *lsm_is_phone_forwarded(line_t line);
+void lsm_tmr_tones_callback(void *);
+void lsm_update_placed_callinfo(void *dcb);
+void lsm_start_multipart_tone_timer(vcm_tones_t tone, uint32_t delay,
+ callid_t callId);
+void lsm_start_continuous_tone_timer(vcm_tones_t tone, uint32_t delay,
+ callid_t callId);
+void lsm_start_tone_duration_timer(vcm_tones_t tone, uint32_t delay,
+ cc_call_handle_t call_handle);
+void lsm_stop_multipart_tone_timer(void);
+void lsm_stop_continuous_tone_timer(void);
+void lsm_stop_tone_duration_timer(void);
+void lsm_tone_duration_tmr_callback(void *data);
+void lsm_tone_start_with_duration (vcm_tones_t tone, short alert_info, cc_call_handle_t call_handle, groupid_t group_id,
+ streamid_t stream_id, uint16_t direction, uint32_t duration);
+void lsm_update_active_tone(vcm_tones_t tone, callid_t call_id);
+boolean lsm_is_tx_channel_opened(callid_t call_id);
+void lsm_update_monrec_tone_action (vcm_tones_t tone, callid_t call_id, uint16_t direction);
+void lsm_downgrade_monrec_tone_action(vcm_tones_t tone, callid_t call_id);
+char *lsm_get_gdialed_digits();
+void lsm_set_hold_ringback_status(callid_t call_id, boolean ringback_status);
+
+extern callid_t lsm_get_ui_id(callid_t call_id);
+extern cc_call_handle_t lsm_get_ms_ui_call_handle(line_t line, callid_t call_id, callid_t ui_id);
+extern void lsm_set_ui_id(callid_t call_id, callid_t ui_id);
+extern lsm_states_t lsm_get_state(callid_t call_id);
+
+extern void lsm_set_lcb_dusting_call(callid_t call_id);
+extern void lsm_set_lcb_call_priority(callid_t call_id);
+extern boolean lsm_is_it_priority_call(callid_t call_id);
+extern void lsm_play_tone(cc_features_t feature_id);
+extern boolean lsm_callwaiting(void);
+extern void lsm_display_control_ringin_call (callid_t call_id, line_t line, boolean hide);
+extern line_t lsm_find_next_available_line(line_t line, boolean same_dn, boolean incoming);
+extern line_t lsm_get_available_line (boolean incoming);
+extern boolean lsm_is_line_available(line_t line, boolean incoming);
+extern void lsm_ui_display_notify_str_index(int str_index);
+extern cc_causes_t lsm_allocate_call_bandwidth(callid_t call_id, int sessions);
+extern void lsm_update_gcid(callid_t call_id, char * gcid);
+extern void lsm_set_lcb_prevent_ringing(callid_t call_id);
+extern void lsm_remove_lcb_prevent_ringing(callid_t call_id);
+extern void lsm_set_lcb_dialed_str_flag(callid_t call_id);
+void lsm_update_video_avail(line_t line, callid_t call_id, int dir);
+void lsm_update_video_offered(line_t line, callid_t call_id, int dir);
+callid_t lsm_get_callid_from_ui_id (callid_t uid);
+void lsm_set_video_mute (callid_t call_id, int mute);
+int lsm_get_video_mute (callid_t call_id);
+void lsm_set_video_window (callid_t call_id, int flags, int x, int y, int h, int w);
+void lsm_get_video_window (callid_t call_id, int *flags, int *x, int *y, int *h, int *w);
+boolean lsm_is_kpml_subscribed (callid_t call_id);
+void
+lsm_util_tone_start_with_speaker_as_backup (vcm_tones_t tone, short alert_info,
+ cc_call_handle_t call_handle, groupid_t group_id,
+ streamid_t stream_id, uint16_t direction);
+
+void lsm_data_channel_negotiated (line_t line, callid_t call_id, fsmdef_media_t *media, int *pc_stream_id);
+
+#endif //_LSM_H_
+
diff --git a/libs/sipcc/core/gsm/h/lsm_private.h b/libs/sipcc/core/gsm/h/lsm_private.h
new file mode 100644
index 0000000000..438cc869a6
--- /dev/null
+++ b/libs/sipcc/core/gsm/h/lsm_private.h
@@ -0,0 +1,58 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _LSM_PRIV_H_
+#define _LSM_PRIV_H_
+
+#include "phone_types.h"
+#include "ccapi.h"
+
+#define LSM_ERR_MSG err_msg
+
+#define LSM_DEFAULT_LINE (1)
+#define LSM_DEFAULT_INSTANCE (1)
+#define LSM_DEFAULT_PLANE (1)
+#define LSM_DEFAULT_SPEAKER (0)
+
+#define LSM_MAX_LCBS (LSM_MAX_CALLS)
+
+#define LSM_FLAGS_SECURE_MEDIA (1 << 0) /* encrypted tx media */
+#define LSM_FLAGS_SECURE_MEDIA_UPDATE (1 << 1) /* update secure media icon needed */
+#define LSM_FLAGS_ANSWER_PENDING (1 << 2) /* answer is pending */
+#define LSM_FLAGS_DIALED_STRING (1 << 3) /* dialed a string */
+#define LSM_FLAGS_CALL_PRIORITY_URGENT (1 << 4)
+#define LSM_FLAGS_PREVENT_RINGING (1 << 5)
+#define LSM_FLAGS_DUSTING (1 << 6) /* the call is a dusting call */
+
+
+typedef struct lsm_lcb_t_ {
+ callid_t call_id;
+ line_t line;
+ call_events previous_call_event;
+ lsm_states_t state;
+ int mru;
+ boolean enable_ringback;
+ callid_t ui_id;
+ uint32_t flags;
+ fsmdef_dcb_t *dcb; /* the corresponding DCB chain for this lcm */
+ char *gcid; /*global call identifier */
+ int vid_mute;
+ int vid_flags;
+ int vid_x;
+ int vid_y;
+ int vid_h;
+ int vid_w;
+} lsm_lcb_t;
+
+typedef struct lsm_info_t_ {
+ int call_in_progress;
+ callid_t active_call_id;
+ int active_call_plane;
+ line_t primary_line;
+ int speaker;
+} lsm_info_t;
+
+lsm_lcb_t *lsm_get_lcb_by_call_id(callid_t call_id);
+
+#endif
diff --git a/libs/sipcc/core/gsm/h/sm.h b/libs/sipcc/core/gsm/h/sm.h
new file mode 100755
index 0000000000..840aced0df
--- /dev/null
+++ b/libs/sipcc/core/gsm/h/sm.h
@@ -0,0 +1,44 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _SM_H_
+#define _SM_H_
+
+#include "phone_debug.h"
+
+typedef enum {
+ SM_RC_MIN = -2,
+ SM_RC_ERROR = -1,
+ SM_RC_SUCCESS,
+ SM_RC_CONT,
+ SM_RC_DEF_CONT,
+ SM_RC_END,
+ SM_RC_CLEANUP,
+ SM_RC_FSM_ERROR,
+ SM_RC_CSM_ERROR,
+ SM_RC_MAX
+} sm_rcs_t;
+
+typedef struct _sm_event_t {
+ int state;
+ int event;
+ void *data;
+ void *msg;
+} sm_event_t;
+
+typedef sm_rcs_t (*sm_function_t)(sm_event_t *event);
+
+typedef struct _sm_table_t {
+ int min_state;
+ int max_state;
+ int min_event;
+ int max_event;
+ sm_function_t *table;
+} sm_table_t;
+
+sm_rcs_t sm_process_event(sm_table_t *tbl, sm_event_t *event );
+sm_rcs_t sm_process_event2(int state_id, int event_id, sm_table_t *tbl,
+ void *msg, void *cb);
+
+#endif
diff --git a/libs/sipcc/core/gsm/lsm.c b/libs/sipcc/core/gsm/lsm.c
new file mode 100755
index 0000000000..f55e04b1c6
--- /dev/null
+++ b/libs/sipcc/core/gsm/lsm.c
@@ -0,0 +1,6610 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include
+#include "cpr_types.h"
+#include "cpr_stdlib.h"
+#include "cpr_locks.h"
+#include "cpr_stdio.h"
+#include "cpr_timers.h"
+#include "cpr_in.h"
+#include "cpr_errno.h"
+#include "phone_types.h"
+#include "phone.h"
+#include "sdp.h"
+#include "lsm.h"
+#include "phone_debug.h"
+#include "fsm.h"
+#include "gsm_sdp.h"
+#include "vcm.h"
+#include "ccsip_pmh.h"
+#include "dtmf.h"
+#include "debug.h"
+#include "rtp_defs.h"
+#include "lsm_private.h"
+#include "dialplanint.h"
+#include "kpmlmap.h"
+#include "prot_configmgr.h"
+#include "dialplan.h"
+#include "sip_interface_regmgr.h"
+#include "gsm.h"
+#include "phntask.h"
+#include "fim.h"
+#include "util_string.h"
+#include "platform_api.h"
+
+#ifndef NO
+#define NO (0)
+#endif
+
+#ifndef YES
+#define YES (1)
+#endif
+
+#define CALL_INFO_NONE (string_t)""
+
+#define FROM_NOTIFY_PRI 1 // Same as SCCP phone behavior
+#define LSM_DISPLAY_STR_LEN 256
+
+static cc_rcs_t lsm_stop_tone (lsm_lcb_t *lcb, cc_action_data_tone_t *data);
+
+extern cc_media_cap_table_t g_media_table;
+
+static lsm_lcb_t *lsm_lcbs;
+static uint32_t lsm_call_perline[MAX_REG_LINES];
+boolean lsm_mnc_reached[MAX_REG_LINES]; // maxnumcalls reached
+static boolean lsm_bt_reached[MAX_REG_LINES]; //busy trigger reached
+
+/* This variable is used locally to reflect the CFA state (set/clear)
+ * when in CCM mode.
+ */
+static boolean cfwdall_state_in_ccm_mode[MAX_REG_LINES+1] ;
+
+static const char *lsm_state_names[LSM_S_MAX] = {
+ "IDLE",
+ "PENDING",
+ "OFFHOOK",
+ "ONHOOK",
+ "PROCEED",
+ "RINGOUT",
+ "RINGIN",
+ "CONNECTED",
+ "BUSY",
+ "CONGESTION",
+ "HOLDING",
+ "CWT",
+ "XFER",
+ "ATTN_XFER",
+ "CONF",
+ "INVALID_NUMBER"
+};
+
+static const char *cc_state_names[] = {
+ "OFFHOOK",
+ "DIALING",
+ "DIALING_COMPLETED",
+ "CALL_SENT",
+ "FAR_END_PROCEEDING",
+ "FAR_END_ALERTING",
+ "CALL_RECEIVED",
+ "ALERTING",
+ "ANSWERED",
+ "CONNECTED",
+ "HOLD",
+ "RESUME",
+ "ONHOOK",
+ "CALL_FAILED",
+ "HOLD_REVERT",
+ "STATE_UNKNOWN"
+};
+
+
+static const char *cc_action_names[] = {
+ "SPEAKER",
+ "DIAL_MODE",
+ "MWI",
+ "MWI_LAMP",
+ "OPEN_RCV",
+ "UPDATE_UI",
+ "MEDIA",
+ "RINGER",
+ "LINE_RINGER",
+ "PLAY_TONE",
+ "STOP_TONE",
+ "STOP_MEDIA",
+ "START_RCV",
+ "ANSWER_PENDING",
+ "PLAY_BLF_ALERT_TONE"
+};
+
+/* names are corresponds to vcm_ring_mode_t structure */
+static const char *vm_alert_names[] = {
+ "NONE",
+// "RINGER_OFF",
+ "VCM_RING_OFF",
+ "VCM_INSIDE_RING",
+ "VCM_OUTSIDE_RING",
+ "VCM_FEATURE_RING",
+ "VCM_BELLCORE_DR1",
+ "VCM_RING_OFFSET",
+ "VCM_BELLCORE_DR2",
+ "VCM_BELLCORE_DR3",
+ "VCM_BELLCORE_DR4",
+ "VCM_BELLCORE_DR5",
+ "VCM_BELLCORE_MAX",
+ "VCM_FLASHONLY_RING",
+ "VCM_STATION_PRECEDENCE_RING",
+ "VCM_MAX_RING"
+};
+
+/* Enum just to make code read better */
+/* the following values must be in sync with the values listed in edcs-387610 */
+typedef enum {
+ DISABLE = 1,
+ FLASH_ONLY = 2,
+ RING_ONCE = 3,
+ RING = 4,
+ BEEP_ONLY = 5
+} config_value_type_t;
+
+cprTimer_t lsm_tmr_tones;
+cprTimer_t lsm_continuous_tmr_tones;
+cprTimer_t lsm_tone_duration_tmr;
+static uint32_t lsm_tmr_tones_ticks;
+static int callWaitingDelay;
+static int ringSettingIdle;
+static int ringSettingActive;
+
+/* Ring mode set by remote-cc app */
+static cc_rcc_ring_mode_e cc_line_ringer_mode[MAX_REG_LINES+1] =
+ {CC_RING_DEFAULT};
+// Following data has to be non-stack b/c the way SIP stack uses it.
+// It is used by the lsm_is_phone_forwarded() function only.
+static char cfwdall_url[MAX_URL_LENGTH];
+
+static void lsm_update_inalert_status(line_t line, callid_t call_id,
+ cc_state_data_alerting_t * data,
+ boolean notify);
+static void lsm_util_start_tone(vcm_tones_t tone, short alert_info,
+ cc_call_handle_t call_handle, groupid_t group_id,
+ streamid_t stream_id, uint16_t direction);
+
+const char *
+lsm_state_name (lsm_states_t id)
+{
+ if ((id <= LSM_S_MIN) || (id >= LSM_S_MAX)) {
+ return get_debug_string(GSM_UNDEFINED);
+ }
+
+ return (lsm_state_names[id]);
+}
+
+
+static const char *
+cc_state_name (cc_states_t id)
+{
+ if ((id <= CC_STATE_MIN) || (id >= CC_STATE_MAX)) {
+ return (get_debug_string(GSM_UNDEFINED));
+ }
+
+ return (cc_state_names[id]);
+}
+
+
+static const char *
+cc_action_name (cc_actions_t id)
+{
+ if ((id <= CC_ACTION_MIN) || (id >= CC_ACTION_MAX)) {
+ return (get_debug_string(GSM_UNDEFINED));
+ }
+
+ return (cc_action_names[id]);
+}
+
+
+char
+lsm_digit2ch (int digit)
+{
+ switch (digit) {
+ case 0x0:
+ case 0x1:
+ case 0x2:
+ case 0x3:
+ case 0x4:
+ case 0x5:
+ case 0x6:
+ case 0x7:
+ case 0x8:
+ case 0x9:
+ return (char)(digit + '0');
+ case 0x0e:
+ return ('*');
+ case 0x0f:
+ return ('#');
+ default:
+ return ('x');
+ }
+}
+
+
+void
+lsm_debug_entry (callid_t call_id, line_t line, const char *fname)
+{
+ LSM_DEBUG(get_debug_string(LSM_DBG_ENTRY), call_id, line, fname);
+}
+
+static void
+lsm_ui_call_state (call_events event, line_t line, lsm_lcb_t *lcb, cc_causes_t cause)
+{
+ if (lcb->previous_call_event != event) {
+ lcb->previous_call_event = event;
+
+ /* For local conference case, the second call is hidden
+ * so do not show that when the call is held, resumed,
+ * or moved to other state. This should be done only
+ * when local bridge is active
+ */
+ ui_call_state(event, line, lcb->ui_id, cause);
+ }
+ else if(event == evConnected) {
+ //This is for Chaperone Conference case, if conference changed to a normal call,
+ //then need to update the call state to refresh the key's status. like re-enable
+ //Confrn key
+ ui_call_state(event, line, lcb->ui_id, cause);
+ }
+}
+
+/**
+ * This function will control the display of the ringingin call based on the hide arg.
+ *
+ * @param[in] call_id - call id
+ * @param[in] line - line on which call is ringing.
+ * @param[in] hide - whether to hide or not
+ *
+ * @return none
+ *
+ * @pre (call_id != CC_NO_CALL_ID) and (line != 0)
+ */
+void lsm_display_control_ringin_call (callid_t call_id, line_t line, boolean hide)
+{
+ lsm_lcb_t *lcb;
+
+ lcb = lsm_get_lcb_by_call_id(call_id);
+ if (lcb != NULL) {
+ ui_call_state(evRingIn, line, lcb->ui_id, CC_CAUSE_NORMAL);
+ }
+}
+
+/**
+ * This function will be invoked by DEF SM to set if it is a dusting call.
+ * @param[in] call_id - GSM call id.
+ *
+ * @return none
+ *
+ * @pre (call_id != CC_NO_CALL_ID)
+ */
+void lsm_set_lcb_dusting_call (callid_t call_id)
+{
+ lsm_lcb_t *lcb;
+
+ lcb = lsm_get_lcb_by_call_id(call_id);
+ if (lcb != NULL) {
+ FSM_SET_FLAGS(lcb->flags, LSM_FLAGS_DUSTING);
+ }
+}
+
+/**
+ * This function will be invoked by DEF SM to set call priority.
+ *
+ * @param[in] call_id - GSM call id.
+ *
+ * @return none
+ *
+ * @pre (call_id != CC_NO_CALL_ID)
+ */
+void lsm_set_lcb_call_priority (callid_t call_id)
+{
+ lsm_lcb_t *lcb;
+
+ lcb = lsm_get_lcb_by_call_id(call_id);
+ if (lcb != NULL) {
+ FSM_SET_FLAGS(lcb->flags, LSM_FLAGS_CALL_PRIORITY_URGENT);
+ }
+}
+
+
+/**
+ * This function sets the LSM_FLAGS_DIALED_STRING bit in lcb->flags
+ *
+ * @param[in] call_id - GSM call id.
+ *
+ * @return none
+ *
+ * @pre (call_id != CC_NO_CALL_ID)
+ */
+void lsm_set_lcb_dialed_str_flag (callid_t call_id)
+{
+ lsm_lcb_t *lcb;
+
+ lcb = lsm_get_lcb_by_call_id(call_id);
+ if (lcb != NULL) {
+ FSM_SET_FLAGS(lcb->flags, LSM_FLAGS_DIALED_STRING);
+ }
+}
+
+/**
+ * This function will be invoked by DEF SM to set gcid in lcb.
+ *
+ * @param[in] call_id - GSM call id.
+ * @param[in] gcid - GCID provided by CUCM.
+ *
+ * @return none
+ *
+ * @pre (call_id != CC_NO_CALL_ID)
+ */
+void lsm_update_gcid (callid_t call_id, char * gcid)
+{
+ lsm_lcb_t *lcb;
+
+ lcb = lsm_get_lcb_by_call_id(call_id);
+ if (lcb != NULL) {
+ if (lcb->gcid == NULL) {
+ lcb->gcid = (char *)cpr_malloc(CC_GCID_LEN);
+ sstrncpy(lcb->gcid, gcid, CC_GCID_LEN);
+ }
+ }
+
+}
+/**
+ * This function will be invoked by DEF SM.
+ * it will check if there is a RINGIN call
+ * with the same GCID. If so, it will set a flag to prevent ringing.
+ *
+ * @param[in] call_id - GSM call id.
+ *
+ * @return none
+ *
+ * @pre (call_id != CC_NO_CALL_ID)
+ */
+void lsm_set_lcb_prevent_ringing (callid_t call_id)
+{
+ lsm_lcb_t *lcb;
+ char *gcid;
+
+ lcb = lsm_get_lcb_by_call_id(call_id);
+ if (lcb == NULL) {
+ return;
+ }
+
+ gcid = lcb->gcid;
+ if (gcid == NULL) {
+ return;
+ }
+
+ LSM_DEBUG(DEB_L_C_F_PREFIX"gcid=%d.\n",
+ DEB_L_C_F_PREFIX_ARGS(LSM, lcb->line, call_id, "lsm_set_lcb_prevent_ringing"), gcid);
+
+ FSM_FOR_ALL_CBS(lcb, lsm_lcbs, LSM_MAX_LCBS) {
+ if (lcb->state == LSM_S_RINGIN) {
+ if ((lcb->gcid != NULL) && (strncmp(gcid, lcb->gcid, CC_GCID_LEN) == 0)) {
+ LSM_DEBUG(DEB_L_C_F_PREFIX"found ringing call.\n",
+ DEB_L_C_F_PREFIX_ARGS(LSM, lcb->line, lcb->call_id, "lsm_set_lcb_prevent_ringing"), gcid);
+ FSM_SET_FLAGS(lcb->flags, LSM_FLAGS_PREVENT_RINGING);
+ }
+ break;
+ }
+ }
+}
+
+void lsm_remove_lcb_prevent_ringing (callid_t call_id)
+{
+ lsm_lcb_t *lcb;
+ char *gcid;
+
+ lcb = lsm_get_lcb_by_call_id(call_id);
+ if (lcb == NULL) {
+ return;
+ }
+
+ gcid = lcb->gcid;
+ if (gcid == NULL) {
+ return;
+ }
+
+ LSM_DEBUG(DEB_L_C_F_PREFIX"gcid=%d.\n",
+ DEB_L_C_F_PREFIX_ARGS(LSM, lcb->line, call_id, "lsm_remove_lcb_prevent_ringing"), gcid);
+
+ FSM_FOR_ALL_CBS(lcb, lsm_lcbs, LSM_MAX_LCBS) {
+ if (lcb->state == LSM_S_RINGIN) {
+ if ((lcb->gcid != NULL) && (strncmp(gcid, lcb->gcid, CC_GCID_LEN) == 0)) {
+ //FSM_RESET_FLAGS(lcb->flags, LSM_FLAGS_ANSWER_PENDING);
+ lcb->flags = 0;
+ LSM_DEBUG(DEB_L_C_F_PREFIX"found ringing call, gcid=%d, lcb->flags=%d.\n",
+ DEB_L_C_F_PREFIX_ARGS(LSM, lcb->line, lcb->call_id, "lsm_remove_lcb_prevent_ringing"), gcid, lcb->flags);
+ }
+ break;
+ }
+ }
+}
+
+/**
+ * This function finds if the call is a priority call.
+ *
+ * @param[in] call_id - GSM call id.
+ *
+ * @return none
+ *
+ * @pre (call_id != CC_NO_CALL_ID)
+ */
+boolean lsm_is_it_priority_call (callid_t call_id)
+{
+ lsm_lcb_t *lcb;
+
+ lcb = lsm_get_lcb_by_call_id(call_id);
+ if (lcb == NULL) {
+ return FALSE;
+ }
+ if (FSM_CHK_FLAGS(lcb->flags, LSM_FLAGS_CALL_PRIORITY_URGENT)) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * Function: lsm_internal_update_call_info
+ *
+ * Parameters:
+ * lcb - pointer to lsm_lcb_t.
+ * dcb - pointer to fsmdef_dcb_t.
+ *
+ * Description: This is an internal function of LSM for updating call
+ * information to the UI that is not directly driven by the
+ * the explicit CALL INFO event from call control.
+ *
+ * It is a convenient function that used by some of the
+ * LSM handling function that needs to update call information
+ * to the UI during media changes.
+ *
+ * Returns:
+ * None.
+ *
+ */
+static void
+lsm_internal_update_call_info (lsm_lcb_t *lcb, fsmdef_dcb_t *dcb)
+{
+ boolean inbound;
+ calltype_t call_type;
+ fsmcnf_ccb_t *ccb;
+
+ if ((lcb == NULL) || (dcb == NULL)) {
+ return;
+ }
+
+ if (!dcb->ui_update_required) {
+ return;
+ }
+
+ /* For local conference, do not update the primary
+ * call bubbles call-info. Primary call is already
+ * displaying To conference in this case
+ * But dcb-> caller_id should be updated to
+ * refresh the UI when the call is dropped
+ */
+ ccb = fsmcnf_get_ccb_by_call_id(lcb->call_id);
+ if (ccb && (ccb->flags & LCL_CNF) && (ccb->active)
+ && (ccb->cnf_call_id == lcb->call_id)) {
+ return;
+ }
+ dcb->ui_update_required = FALSE;
+
+ /* Derive orientation of the call */
+ switch (dcb->orientation) {
+ case CC_ORIENTATION_FROM:
+ inbound = TRUE;
+ break;
+
+ case CC_ORIENTATION_TO:
+ inbound = FALSE;
+ break;
+
+ default:
+ /*
+ * No orientation available, use the direction when call was started
+ */
+ inbound = dcb->inbound;
+ break;
+ }
+
+ if ((dcb->call_type == FSMDEF_CALL_TYPE_FORWARD)
+ && fsmdef_check_retain_fwd_info_state()) {
+ call_type = (inbound) ? (calltype_t)dcb->call_type:FSMDEF_CALL_TYPE_OUTGOING;
+ } else {
+ if (inbound) {
+ call_type = FSMDEF_CALL_TYPE_INCOMING;
+ } else {
+ call_type = FSMDEF_CALL_TYPE_OUTGOING;
+ }
+ }
+
+ ui_call_info(dcb->caller_id.calling_name,
+ dcb->caller_id.calling_number,
+ dcb->caller_id.alt_calling_number,
+ dcb->caller_id.display_calling_number,
+ dcb->caller_id.called_name,
+ dcb->caller_id.called_number,
+ dcb->caller_id.display_called_number,
+ dcb->caller_id.orig_called_name,
+ dcb->caller_id.orig_called_number,
+ dcb->caller_id.last_redirect_name,
+ dcb->caller_id.last_redirect_number,
+ call_type,
+ lcb->line, lcb->ui_id,
+ dcb->caller_id.call_instance_id,
+ FSM_GET_SECURITY_STATUS(dcb),
+ FSM_GET_POLICY(dcb));
+
+}
+
+/**
+ * The function opens receive channel or allocates receive port. It depends
+ * on the "keep" member of the cc_action_data_open_rcv_t structure set
+ * up by the caller to whether opens a receive channel or just
+ * to allocate a receive port.
+ *
+ * @param[in] lcb - pointer to the lsm_lcb_t.
+ * @param[in/out] data - pointer to the cc_action_data_open_rcv_t.
+ * Upon a successful return, the port element
+ * of this structure will be filled with the actual
+ * receive port.
+ * @param[in] media - pointer to the fsmdef_media_t if a specific
+ * media to be operated on.
+ *
+ * @return CC_RC_ERROR or CC_RC_SUCCESS.
+ *
+ * @pre (lcb is_not NULL) and (data is_not NULL)
+ */
+static cc_rcs_t
+lsm_open_rx (lsm_lcb_t *lcb, cc_action_data_open_rcv_t *data,
+ fsmdef_media_t *media)
+{
+ static const char fname[] = "lsm_open_rx";
+ int port_allocated = 0;
+ cc_rcs_t rc = CC_RC_ERROR;
+ fsmdef_dcb_t *dcb;
+ int sdpmode = 0;
+
+ dcb = lcb->dcb;
+ if (dcb == NULL) {
+ return (rc);
+ }
+
+ /*
+ * P2: At this point, it is a guess that refid from media structure
+ * may be needed. If it turns out to be not the case, then the
+ * code below that looks up media should be removed including
+ * the media parameter that is passed in.
+ */
+ if (media == NULL) {
+ /* no explicit media parameter specified, look up based on refID */
+ if (data->media_refid != CC_NO_MEDIA_REF_ID) {
+ media = gsmsdp_find_media_by_refid(dcb,
+ data->media_refid);
+ }
+ if (media == NULL) {
+ LSM_DEBUG(get_debug_string(LSM_DBG_INT1), lcb->call_id,
+ lcb->line, fname, "no media refID %d found",
+ data->media_refid);
+ return (rc);
+ }
+ }
+
+ LSM_DEBUG(get_debug_string(LSM_DBG_INT1), lcb->call_id, lcb->line, fname,
+ "requested port", data->port);
+
+
+ sdpmode = 0;
+ config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
+
+ if (data->keep == TRUE) {
+ if (sdpmode && strlen(dcb->peerconnection)) {
+ /* If we are doing ICE, don't try to re-open */
+ port_allocated = data->port;
+ }
+ else {
+ //Todo IPv6: Add interface call for IPv6
+ (void) vcmRxOpen(media->cap_index, dcb->group_id, media->refid,
+ lsm_get_ms_ui_call_handle(lcb->line, lcb->call_id, lcb->ui_id), data->port,
+ media->is_multicast ? &media->dest_addr:&media->src_addr, data->is_multicast,
+ &port_allocated);
+ }
+ if (port_allocated != -1) {
+ data->port = (uint16_t)port_allocated;
+ rc = CC_RC_SUCCESS;
+ }
+ } else {
+
+ if (sdpmode) {
+ if (!strlen(dcb->peerconnection)) {
+ vcmRxAllocPort(media->cap_index, dcb->group_id, media->refid,
+ lsm_get_ms_ui_call_handle(lcb->line, lcb->call_id, lcb->ui_id),
+ data->port,
+ &port_allocated);
+ if (port_allocated != -1) {
+ data->port = (uint16_t)port_allocated;
+ rc = CC_RC_SUCCESS;
+ }
+ } else {
+ char **candidates;
+ int candidate_ct;
+ char *default_addr;
+
+ vcmRxAllocICE(media->cap_index, dcb->group_id, media->refid,
+ lsm_get_ms_ui_call_handle(lcb->line, lcb->call_id, lcb->ui_id),
+ dcb->peerconnection,
+ media->level,
+ &default_addr, &port_allocated,
+ &candidates, &candidate_ct);
+
+ // Check that we got a valid address and port
+ if (default_addr && (strlen(default_addr) > 0) && (port_allocated != -1)) {
+ sstrncpy(dcb->ice_default_candidate_addr, default_addr, sizeof(dcb->ice_default_candidate_addr));
+
+ data->port = (uint16_t)port_allocated;
+ media->candidate_ct = candidate_ct;
+ media->candidatesp = candidates;
+ rc = CC_RC_SUCCESS;
+ }
+ }
+ }
+ }
+
+ LSM_DEBUG(get_debug_string(LSM_DBG_INT1), lcb->call_id, lcb->line, fname,
+ "allocated port", port_allocated);
+
+ return (rc);
+}
+/*
+ * This function updates the dscp value based on whether video is enable or not
+ * and video is active or not.
+ * @param[in] dcb - pointer to the fsmdef_dcb.
+ */
+
+void lsm_update_dscp_value(fsmdef_dcb_t *dcb)
+{
+ static const char fname[] = "lsm_update_dscp_value";
+ int dscp = 184; /* default 184 used for DSCP */
+ // depending upon video is enabled or disabled ,set the dscp value.
+ if (dcb != NULL && dcb->cur_video_avail != SDP_DIRECTION_INACTIVE ) {
+ config_get_value(CFGID_DSCP_VIDEO, (int *)&dscp, sizeof(dscp));
+ } else {
+ config_get_value(CFGID_DSCP_AUDIO, (int *)&dscp, sizeof(dscp));
+ }
+ // We would use DSCP for video for both audio and video streams if this is a video call
+ if (dcb != NULL) {
+ LSM_DEBUG(DEB_L_C_F_PREFIX"Setting dscp=%d for Rx group_id=%d \n",
+ DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, dcb->call_id, fname), dscp, dcb->group_id);
+ vcmSetRtcpDscp(dcb->group_id, dscp);
+ }
+}
+
+/**
+ * The function closes receive channel for a given media entry.
+ * The receive channel may not be closed if the caller intents to
+ * fresh the channel i.e close if needed but otherwise leave it open.
+ * When the caller indicates refreshing, the receive channel
+ * will be closed only when there is a difference in current SDP and
+ * the previous SDP.
+ *
+ * @param[in] lcb - pointer to the lsm_lcb_t.
+ * @param[in] refresh - channel to be refreshed i.e. close if necessary.
+ * @param[in] media - pointer to the fsmdef_media_t for the
+ * media entry to be refresh.
+ *
+ * If the value of media is NULL, it indicates that
+ * all current inused media entries.
+ *
+ * @return None.
+ *
+ * @pre (lcb is_not NULL)
+ */
+static void
+lsm_close_rx (lsm_lcb_t *lcb, boolean refresh, fsmdef_media_t *media)
+{
+ static const char fname[] = "lsm_close_rx";
+ fsmdef_media_t *start_media, *end_media;
+ fsmdef_dcb_t *dcb;
+ int sdpmode = 0;
+
+ dcb = lcb->dcb;
+ if (dcb == NULL) {
+ LSM_ERR_MSG(get_debug_string(DEBUG_INPUT_NULL), fname);
+ return;
+ }
+
+ LSM_DEBUG(DEB_L_C_F_PREFIX"Called with refresh set to %d\n",
+ DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, dcb->call_id, fname), refresh);
+
+ if (media == NULL) {
+ /* NULL value of the given media indicates for all media */
+ start_media = GSMSDP_FIRST_MEDIA_ENTRY(dcb);
+ end_media = NULL; /* NULL means till the end of the list */
+ } else {
+ /* given media, uses the provided media */
+ start_media = media;
+ end_media = media;
+ }
+
+ /* close receive port on the media(s) */
+ GSMSDP_FOR_MEDIA_LIST(media, start_media, end_media, dcb) {
+ if (media->rcv_chan) {
+ /*
+ * If caller is releasing the port or if the caller is
+ * recycling the receive port and the codec has changed, close the
+ * receive port. Also stop bridging of media streams.
+ */
+ if (!refresh ||
+ (refresh &&
+ gsmsdp_sdp_differs_from_previous_sdp(TRUE, media))) {
+ LSM_DEBUG(get_debug_string(LSM_DBG_INT1), dcb->call_id,
+ dcb->line, fname, "port closed",
+ media->src_port);
+
+ config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
+ if (!sdpmode) {
+
+ vcmRxClose(media->cap_index, dcb->group_id, media->refid,
+ lsm_get_ms_ui_call_handle(lcb->line, lcb->call_id, lcb->ui_id));
+ }
+ media->rcv_chan = FALSE;
+ }
+ }
+ }
+}
+
+/**
+ * The function closes transmit channel for a given media entry.
+ * The transmit channel may not be closed if the caller intents to
+ * fresh the port i.e close if needed but otherwise leave it open.
+ * When the caller indicates refreshing, the transmit channel
+ * will be closed only when there is a difference in current SDP and
+ * the previous SDP.
+ *
+ * @param[in] lcb - pointer to the lsm_lcb_t.
+ * @param[in] refresh - channel to be refreshed i.e. close if necessary.
+ * @param[in] media - pointer to the fsmdef_media_t for the
+ * media entry to be refresh.
+ *
+ * If the value of media is NULL, it indicates that
+ * all current inused media entries.
+ *
+ * @return None.
+ *
+ * @pre (lcb is_not NULL)
+ */
+static void
+lsm_close_tx (lsm_lcb_t *lcb, boolean refresh, fsmdef_media_t *media)
+{
+ fsmdef_media_t *start_media, *end_media;
+ fsmdef_dcb_t *dcb;
+ static const char fname[] = "lsm_close_tx";
+ int sdpmode = 0;
+
+ dcb = lcb->dcb;
+ if (dcb == NULL) {
+ LSM_ERR_MSG(get_debug_string(DEBUG_INPUT_NULL), fname);
+ return;
+ }
+ LSM_DEBUG(DEB_L_C_F_PREFIX"called with refresh set to %d\n",
+ DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, dcb->call_id, fname), refresh);
+
+ config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
+
+ if (media == NULL) {
+ /* NULL value of the given media indicates for all media */
+ start_media = GSMSDP_FIRST_MEDIA_ENTRY(dcb);
+ end_media = NULL; /* NULL means till the end of the list */
+ } else {
+ /* given media, uses the provided media */
+ start_media = media;
+ end_media = media;
+ }
+
+ /*
+ * Close the RTP, but only if this call is using it and the capabilities
+ * have changed.
+ */
+ GSMSDP_FOR_MEDIA_LIST(media, start_media, end_media, dcb) {
+ if (media->xmit_chan == TRUE) {
+
+ if (!refresh ||
+ (refresh &&
+ gsmsdp_sdp_differs_from_previous_sdp(FALSE, media))) {
+
+ if (!sdpmode) {
+ vcmTxClose(media->cap_index, dcb->group_id, media->refid,
+ lsm_get_ms_ui_call_handle(lcb->line, lcb->call_id, lcb->ui_id));
+ }
+
+ if (dcb->active_tone == VCM_MONITORWARNING_TONE || dcb->active_tone == VCM_RECORDERWARNING_TONE) {
+ LSM_DEBUG(DEB_L_C_F_PREFIX"%s: Found active_tone: %d being played, current monrec_tone_action: %d. Need stop tone. \n",
+ DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, dcb->call_id, fname), fname,
+ dcb->active_tone, dcb->monrec_tone_action);
+ (void) lsm_stop_tone(lcb, NULL);
+ }
+ media->xmit_chan = FALSE;
+ LSM_DEBUG(DEB_L_C_F_PREFIX"closed",
+ DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, dcb->call_id, fname));
+ }
+ }
+ }
+}
+
+/**
+ * The function starts receive channel for a given media entry.
+ *
+ * @param[in] lcb - pointer to the lsm_lcb_t.
+ * @param[in] fname - pointer to to const. char for the name
+ * of the function that calls to this function.
+ * It is for debuging purpose.
+ * @param[in] media - pointer to the fsmdef_media_t for the
+ * media entry to be refresh.
+ *
+ * If the value of media is NULL, it indicates that
+ * all current inused media entries.
+ *
+ * @return None.
+ *
+ * @pre (lcb is_not NULL)
+ */
+static void
+lsm_rx_start (lsm_lcb_t *lcb, const char *fname, fsmdef_media_t *media)
+{
+ static const char fname1[] = "lsm_rx_start";
+ cc_action_data_open_rcv_t open_rcv;
+ uint16_t port;
+ groupid_t group_id = CC_NO_GROUP_ID;
+ callid_t call_id = lcb->call_id;
+ vcm_mixing_mode_t mix_mode = VCM_NO_MIX;
+ vcm_mixing_party_t mix_party = VCM_PARTY_NONE;
+ int ret_val;
+ fsmdef_media_t *start_media, *end_media;
+ boolean has_checked_conference = FALSE;
+ fsmdef_dcb_t *dcb, *grp_id_dcb;
+ vcm_mediaAttrs_t attrs;
+ int sdpmode = 0;
+ int pc_stream_id = 0;
+ int pc_track_id = 0;
+ attrs.video.opaque = NULL;
+
+ dcb = lcb->dcb;
+ if (dcb == NULL) {
+ LSM_ERR_MSG(get_debug_string(DEBUG_INPUT_NULL), fname1);
+ return;
+ }
+ group_id = dcb->group_id;
+ if (media == NULL) {
+ /* NULL value of the given media indicates for all media */
+ start_media = GSMSDP_FIRST_MEDIA_ENTRY(dcb);
+ end_media = NULL; /* NULL means till the end of the list */
+ } else {
+ /* given media, uses the provided media */
+ start_media = media;
+ end_media = media;
+ }
+
+ /* Start receive channel for the media(s) */
+ GSMSDP_FOR_MEDIA_LIST(media, start_media, end_media, dcb) {
+ if (!GSMSDP_MEDIA_ENABLED(media)) {
+ /* this entry is not enabled */
+ continue;
+ }
+
+ /*
+ * Check to see if the receive port can be opened.
+ * For SRTP, the receive can not be opened if the remote's crypto
+ * parameters are not received yet.
+ */
+ if (!gsmsdp_is_crypto_ready(media, TRUE)) {
+ LSM_DEBUG(DEB_L_C_F_PREFIX"%s: Not ready to open receive port (%d)\n",
+ DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, dcb->call_id, fname1), fname, media->src_port);
+ continue;
+ }
+
+ /*
+ * Open the RTP receive channel if it is not already open.
+ */
+ LSM_DEBUG(get_debug_string(LSM_DBG_INT1), dcb->call_id, dcb->line,
+ fname1, "rcv chan", media->rcv_chan);
+ if (media->rcv_chan == FALSE) {
+
+ memset(&open_rcv, 0, sizeof(open_rcv));
+ port = media->src_port;
+
+ if (media->is_multicast &&
+ (media->direction == SDP_DIRECTION_RECVONLY)) {
+ open_rcv.is_multicast = media->is_multicast;
+ open_rcv.listen_ip = media->dest_addr;
+ port = media->multicast_port;
+ }
+ open_rcv.port = port;
+ open_rcv.keep = TRUE;
+ open_rcv.media_type = media->type;
+
+ if (!has_checked_conference) {
+ switch(dcb->session)
+ {
+ case WHISPER_COACHING:
+ mix_mode = VCM_MIX;
+ mix_party = VCM_PARTY_TxBOTH_RxNONE;
+ grp_id_dcb = fsmdef_get_dcb_by_call_id(dcb->join_call_id);
+ if (grp_id_dcb == NULL) {
+ LSM_ERR_MSG(get_debug_string(DEBUG_INPUT_NULL), fname1);
+ } else {
+ group_id = grp_id_dcb->group_id;
+ }
+ break;
+
+ case MONITOR:
+ case LOCAL_CONF:
+ //AgentGreeting is MIX RXBOTH, SilentMonitoring is MIX TXBOTH
+ //so we have to use VCM_PARTY_BOTH for case MONITOR
+ mix_mode = VCM_MIX;
+ mix_party = VCM_PARTY_BOTH;
+ break;
+ case PRIMARY:
+ default:
+ mix_mode = VCM_NO_MIX;
+ mix_party = VCM_PARTY_NONE;
+ break;
+ }
+ has_checked_conference = TRUE;
+ }
+
+ if (lsm_open_rx(lcb, &open_rcv, media) != CC_RC_SUCCESS) {
+ LSM_ERR_MSG(LSM_L_C_F_PREFIX"%s: open receive port (%d) failed.\n",
+ dcb->line, dcb->call_id, fname1,
+ fname, media->src_port);
+ } else {
+ /* successful open receive channel */
+ media->rcv_chan = TRUE; /* recevied channel is created */
+ /* save the source RX port */
+ if (media->is_multicast) {
+ media->multicast_port = open_rcv.port;
+ } else {
+ media->src_port = open_rcv.port;
+ }
+
+ /* TODO(ekr@rtfm.com): Needs changing for when we have > 2 streams */
+ if ( media->cap_index == CC_VIDEO_1 ) {
+ attrs.video.opaque = media->video;
+ pc_stream_id = 1;
+ } else {
+ attrs.audio.packetization_period = media->packetization_period;
+ attrs.audio.max_packetization_period = media->max_packetization_period;
+ attrs.audio.avt_payload_type = media->avt_payload_type;
+ attrs.audio.mixing_mode = mix_mode;
+ attrs.audio.mixing_party = mix_party;
+ pc_stream_id = 0;
+ }
+ pc_track_id = 0;
+ dcb->cur_video_avail &= ~CC_ATTRIB_CAST;
+
+ config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
+ if (dcb->peerconnection) {
+ ret_val = vcmRxStartICE(media->cap_index, group_id, media->refid,
+ media->level,
+ pc_stream_id,
+ pc_track_id,
+ lsm_get_ms_ui_call_handle(dcb->line, call_id, CC_NO_CALL_ID),
+ dcb->peerconnection,
+ media->num_payloads,
+ media->payloads,
+ FSM_NEGOTIATED_CRYPTO_DIGEST_ALGORITHM(media),
+ FSM_NEGOTIATED_CRYPTO_DIGEST(media),
+ &attrs);
+ } else if (!sdpmode) {
+ if (media->payloads == NULL) {
+ LSM_ERR_MSG(get_debug_string(DEBUG_INPUT_NULL), fname1);
+ return;
+ }
+ ret_val = vcmRxStart(media->cap_index, group_id, media->refid,
+ lsm_get_ms_ui_call_handle(dcb->line, call_id, CC_NO_CALL_ID),
+ media->payloads,
+ media->is_multicast ? &media->dest_addr:&media->src_addr,
+ port,
+ FSM_NEGOTIATED_CRYPTO_ALGORITHM_ID(media),
+ FSM_NEGOTIATED_CRYPTO_RX_KEY(media),
+ &attrs);
+ if (ret_val == -1) {
+ dcb->dsp_out_of_resources = TRUE;
+ return;
+ }
+ } else {
+ ret_val = CC_RC_ERROR;
+ }
+
+ lsm_update_dscp_value(dcb);
+
+ if (dcb->play_tone_action == FSMDEF_PLAYTONE_ZIP)
+ {
+ vcm_tones_t tone = VCM_ZIP;
+ uint16_t direction = dcb->tone_direction;
+
+ LSM_DEBUG(DEB_L_C_F_PREFIX"%s: Found play_tone_action: %d. Need to play tone.\n",
+ DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, dcb->call_id, fname), fname, dcb->play_tone_action);
+
+ // reset to initialized values
+ dcb->play_tone_action = FSMDEF_PLAYTONE_NO_ACTION;
+ dcb->tone_direction = VCM_PLAY_TONE_TO_EAR;
+
+ lsm_util_tone_start_with_speaker_as_backup(tone, VCM_ALERT_INFO_OFF,
+ lsm_get_ms_ui_call_handle(dcb->line, dcb->call_id, CC_NO_CALL_ID),
+ dcb->group_id,
+ ((media != NULL) ? media->refid : CC_NO_MEDIA_REF_ID),
+ direction);
+ }
+ }
+ }
+ }
+}
+
+/**
+ * The function starts transmit channel for a given media entry.
+ *
+ * @param[in] lcb - pointer to the lsm_lcb_t.
+ * @param[in] fname - pointer to to const. char for the name
+ * of the function that calls to this function.
+ * It is for debuging purpose.
+ * @param[in] media - pointer to the fsmdef_media_t for the
+ * media entry to be refresh.
+ *
+ * If the value of media is NULL, it indicates that
+ * all current inused media entries.
+ *
+ * @return None.
+ *
+ * @pre (lcb is_not NULL)
+ */
+
+#define LSM_TMP_VAD_LEN 64
+
+static void
+lsm_tx_start (lsm_lcb_t *lcb, const char *fname, fsmdef_media_t *media)
+{
+ static const char fname1[] = "lsm_tx_start";
+ int dscp = 184; /* default 184 used for DSCP */
+ char tmp[LSM_TMP_VAD_LEN];
+ fsmcnf_ccb_t *ccb = NULL;
+ groupid_t group_id;
+ callid_t call_id = lcb->call_id;
+ vcm_mixing_mode_t mix_mode = VCM_NO_MIX;
+ vcm_mixing_party_t mix_party = VCM_PARTY_NONE;
+ fsmdef_media_t *start_media, *end_media;
+ boolean has_checked_conference = FALSE;
+ fsmdef_dcb_t *dcb;
+ vcm_mediaAttrs_t attrs;
+ int sdpmode;
+ long strtol_result;
+ char *strtol_end;
+
+ attrs.video.opaque = NULL;
+
+ dcb = lcb->dcb;
+ if (dcb == NULL) {
+ LSM_ERR_MSG(get_debug_string(DEBUG_INPUT_NULL), fname1);
+ return;
+ }
+ // Set the DSCP value for RTP stream.
+ if ( media != NULL ){
+ // We would use DSCP for video for both audio and video streams if this
+ // is a video call
+ if ( dcb->cur_video_avail != SDP_DIRECTION_INACTIVE ) {
+ config_get_value(CFGID_DSCP_VIDEO, (int *)&dscp, sizeof(dscp));
+ } else if ( CC_IS_AUDIO(media->cap_index)){
+ // audio stream for audio only call shall use the DSCP for audio
+ // value.
+ config_get_value(CFGID_DSCP_AUDIO, (int *)&dscp, sizeof(dscp));
+ }
+ }
+ group_id = dcb->group_id;
+ LSM_DEBUG(DEB_L_C_F_PREFIX"invoked\n", DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, dcb->call_id, fname1));
+
+ if (media == NULL) {
+ /* NULL value of the given media indicates for all media */
+ start_media = GSMSDP_FIRST_MEDIA_ENTRY(dcb);
+ end_media = NULL; /* NULL means till the end of the list */
+ } else {
+ /* given media, uses the provided media */
+ start_media = media;
+ end_media = media;
+ }
+
+ /* Start receive channel for the media(s) */
+ GSMSDP_FOR_MEDIA_LIST(media, start_media, end_media, dcb) {
+ if (!GSMSDP_MEDIA_ENABLED(media)) {
+ /* this entry is not enabled */
+ continue;
+ }
+ /*
+ * Check to see if the transmit port can be opened.
+ * For SRTP, the transmit port can not be opened if the remote's crypto
+ * parameters are not received yet.
+ */
+ if (!gsmsdp_is_crypto_ready(media, FALSE)) {
+ LSM_DEBUG(DEB_L_C_F_PREFIX"%s: Not ready to open transmit port\n",
+ DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, dcb->call_id, fname1), fname);
+ continue;
+ }
+ if (media->xmit_chan == FALSE && dcb->remote_sdp_present &&
+ media->dest_addr.type != CPR_IP_ADDR_INVALID && media->dest_port) {
+
+ /* evaluate the mode and group id once for all media entries */
+ if (!has_checked_conference) {
+ switch(dcb->session)
+ {
+ case WHISPER_COACHING:
+ mix_mode = VCM_MIX;
+ mix_party = VCM_PARTY_TxBOTH_RxNONE;
+ group_id = fsmdef_get_dcb_by_call_id(dcb->join_call_id)->group_id;
+ break;
+
+ case MONITOR:
+ case LOCAL_CONF:
+ //AgentGreeting is MIX RXBOTH, SilentMonitoring is MIX TXBOTH
+ //so we have to use VCM_PARTY_BOTH for case MONITOR
+ mix_mode = VCM_MIX;
+ mix_party = VCM_PARTY_BOTH;
+ break;
+ case PRIMARY:
+ default:
+ mix_mode = VCM_NO_MIX;
+ mix_party = VCM_PARTY_NONE;
+ break;
+ }
+ has_checked_conference = TRUE;
+ }
+
+ /*
+ * Set the VAD value.
+ */
+ /* can't use vad on conference calls - the dsp can't handle it. */
+ ccb = fsmcnf_get_ccb_by_call_id(lcb->call_id);
+ if (ccb != NULL) {
+ media->vad = VCM_VAD_OFF;
+ } else {
+ config_get_string(CFGID_ENABLE_VAD, tmp, sizeof(tmp));
+
+ errno = 0;
+
+ strtol_result = strtol(tmp, &strtol_end, 10);
+
+ if (errno || tmp == strtol_end ||
+ strtol_result < VCM_VAD_OFF || strtol_result > VCM_VAD_ON) {
+ LSM_ERR_MSG("%s parse error of vad: %s", __FUNCTION__, tmp);
+ return;
+ }
+
+ media->vad = (vcm_vad_t) strtol_result;
+ }
+
+ /*
+ * Open the transmit port and start sending, but only if we have
+ * the SDP for the remote end.
+ */
+
+ sdpmode = 0;
+ config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
+ if (!sdpmode) {
+
+ if (vcmTxOpen(media->cap_index, dcb->group_id, media->refid,
+ lsm_get_ms_ui_call_handle(lcb->line, lcb->call_id, lcb->ui_id)) != 0) {
+ LSM_DEBUG(DEB_L_C_F_PREFIX"%s: vcmTxOpen failed\n",
+ DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, dcb->call_id, fname1), fname);
+ continue;
+ }
+ }
+
+ media->xmit_chan = TRUE;
+
+ attrs.mute = FALSE;
+ if ( CC_IS_VIDEO(media->cap_index)) {
+ attrs.video.opaque = media->video;
+ if (lcb->vid_mute) {
+ attrs.mute = TRUE;
+ }
+
+ } else if ( CC_IS_AUDIO(media->cap_index)){
+ attrs.audio.packetization_period = media->packetization_period;
+ attrs.audio.max_packetization_period = media->max_packetization_period;
+ attrs.audio.avt_payload_type = media->avt_payload_type;
+ attrs.audio.vad = media->vad;
+ attrs.audio.mixing_mode = mix_mode;
+ attrs.audio.mixing_party = mix_party;
+ }
+
+ dcb->cur_video_avail &= ~CC_ATTRIB_CAST;
+
+ if (media->payloads == NULL) {
+ LSM_ERR_MSG(get_debug_string(DEBUG_INPUT_NULL), fname1);
+ return;
+ }
+ if (!strlen(dcb->peerconnection)){
+ if (vcmTxStart(media->cap_index, group_id,
+ media->refid,
+ lsm_get_ms_ui_call_handle(dcb->line, call_id, CC_NO_CALL_ID),
+ media->payloads,
+ (short)dscp,
+ &media->src_addr,
+ media->src_port,
+ &media->dest_addr,
+ media->dest_port,
+ FSM_NEGOTIATED_CRYPTO_ALGORITHM_ID(media),
+ FSM_NEGOTIATED_CRYPTO_TX_KEY(media),
+ &attrs) == -1)
+ {
+ LSM_DEBUG(DEB_L_C_F_PREFIX"%s: vcmTxStart failed\n",
+ DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, dcb->call_id, fname1), fname);
+ dcb->dsp_out_of_resources = TRUE;
+ return;
+ }
+ }
+ else {
+ if (vcmTxStartICE(media->cap_index, group_id,
+ media->refid,
+ media->level,
+ /* TODO(emannion): his perhaps needs some error checking for validity.
+ See gsmsdp_get_media_cap_entry_by_index. */
+ dcb->media_cap_tbl->cap[media->cap_index].pc_stream,
+ dcb->media_cap_tbl->cap[media->cap_index].pc_track,
+ lsm_get_ms_ui_call_handle(dcb->line, call_id, CC_NO_CALL_ID),
+ dcb->peerconnection,
+ media->payloads,
+ (short)dscp,
+ FSM_NEGOTIATED_CRYPTO_DIGEST_ALGORITHM(media),
+ FSM_NEGOTIATED_CRYPTO_DIGEST(media),
+ &attrs) == -1)
+ {
+ LSM_DEBUG(DEB_L_C_F_PREFIX"%s: vcmTxStartICE failed\n",
+ DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, dcb->call_id, fname1), fname);
+ dcb->dsp_out_of_resources = TRUE;
+ return;
+ }
+ }
+
+ lsm_update_dscp_value(dcb);
+
+ LSM_DEBUG(DEB_L_C_F_PREFIX"%s: vcmTxStart started\n",
+ DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, dcb->call_id, fname1), fname);
+
+ if ( dcb->monrec_tone_action != FSMDEF_MRTONE_NO_ACTION)
+ {
+ vcm_tones_t tone = VCM_NO_TONE;
+ uint16_t direction = VCM_PLAY_TONE_TO_EAR;
+ boolean play_both_tones = FALSE;
+
+ LSM_DEBUG(DEB_L_C_F_PREFIX"%s: Found monrec_tone_action: %d. Need to restart playing tone.\n",
+ DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, dcb->call_id, fname), fname, dcb->monrec_tone_action);
+
+ switch (dcb->monrec_tone_action) {
+ case FSMDEF_MRTONE_RESUME_MONITOR_TONE:
+ tone = VCM_MONITORWARNING_TONE;
+ direction = dcb->monitor_tone_direction;
+ break;
+
+ case FSMDEF_MRTONE_RESUME_RECORDER_TONE:
+ tone = VCM_RECORDERWARNING_TONE;
+ direction = dcb->recorder_tone_direction;
+ break;
+
+ case FSMDEF_MRTONE_RESUME_BOTH_TONES:
+ play_both_tones = TRUE;
+ tone = VCM_MONITORWARNING_TONE;
+ direction = dcb->monitor_tone_direction;
+ break;
+
+ default:
+ break;
+ }
+
+ if (play_both_tones == TRUE) {
+ lsm_util_tone_start_with_speaker_as_backup(VCM_RECORDERWARNING_TONE, VCM_ALERT_INFO_OFF,
+ lsm_get_ms_ui_call_handle(dcb->line, dcb->call_id, CC_NO_CALL_ID),
+ dcb->group_id,
+ ((media != NULL) ? media->refid : CC_NO_MEDIA_REF_ID),
+ dcb->recorder_tone_direction);
+ }
+
+ lsm_util_tone_start_with_speaker_as_backup(tone, VCM_ALERT_INFO_OFF, lsm_get_ms_ui_call_handle(dcb->line, dcb->call_id, CC_NO_CALL_ID),
+ dcb->group_id,
+ ((media != NULL) ? media->refid : CC_NO_MEDIA_REF_ID),
+ direction);
+ }
+ }
+ }
+}
+
+
+static cc_rcs_t
+lsm_start_tone (lsm_lcb_t *lcb, cc_action_data_tone_t *data)
+{
+ callid_t call_id = lcb->call_id;
+ fsmdef_media_t *media;
+
+ if (lcb->dcb == NULL) {
+ /* No dcb to work with */
+ return (CC_RC_ERROR);
+ }
+ media = gsmsdp_find_audio_media(lcb->dcb);
+
+ lsm_util_start_tone(data->tone, VCM_ALERT_INFO_OFF, lsm_get_ms_ui_call_handle(lcb->line, call_id, CC_NO_CALL_ID), lcb->dcb->group_id,
+ ((media != NULL) ? media->refid : CC_NO_MEDIA_REF_ID),
+ VCM_PLAY_TONE_TO_EAR);
+
+ return (CC_RC_SUCCESS);
+}
+
+static cc_rcs_t
+lsm_stop_tone (lsm_lcb_t *lcb, cc_action_data_tone_t *data)
+{
+ /* NOTE: For now, ignore data input parameter that may contain the tone type.
+ * We'll check active_tone in the dcb for the call_id and see if there
+ * is a valid tone playing. If so, then and only then issue tone stop.
+ */
+ static const char fname[] = "lsm_stop_tone";
+ callid_t call_id;
+ fsmdef_dcb_t *dcb;
+
+ if (lcb == NULL) {
+ LSM_DEBUG(DEB_F_PREFIX"NULL lcb passed\n", DEB_F_PREFIX_ARGS(LSM, fname));
+ return (CC_RC_ERROR);
+ }
+ call_id = lcb->call_id;
+
+ dcb = lcb->dcb;
+ if (dcb == NULL) {
+ LSM_DEBUG(DEB_F_PREFIX" NULL dcb passed for call_id = %d\n", DEB_F_PREFIX_ARGS(LSM, fname), call_id);
+ return (CC_RC_ERROR);
+ }
+
+ /* for tnp do call stop only if active_tone is other than VCM_NO_TONE */
+ if (dcb->active_tone != VCM_NO_TONE) {
+ fsmdef_media_t *media = gsmsdp_find_audio_media(lcb->dcb);
+ vcmToneStop(dcb->active_tone, dcb->group_id,
+ ((media != NULL) ? media->refid : CC_NO_MEDIA_REF_ID),
+ lsm_get_ms_ui_call_handle(lcb->line, lcb->call_id, lcb->ui_id));
+ /*
+ * Both periodic tones, recording and monitoring, can be active at the
+ * same time. And because we only keep track of last tone, requested to
+ * play, through active_tone, so when the tone to be stopped is of
+ * periodic type, then it could be that both type of periodic tones
+ * could be playing and both should be stopped. If the second periodic
+ * tone is not playing then media server will ignore the stop request.
+ */
+ if (dcb->active_tone == VCM_RECORDERWARNING_TONE ||
+ dcb->active_tone == VCM_MONITORWARNING_TONE)
+ {
+ vcmToneStop(dcb->active_tone == VCM_RECORDERWARNING_TONE ?
+ VCM_MONITORWARNING_TONE : VCM_RECORDERWARNING_TONE,
+ dcb->group_id,
+ ((media != NULL) ? media->refid : CC_NO_MEDIA_REF_ID),
+ lsm_get_ms_ui_call_handle(lcb->line, lcb->call_id, lcb->ui_id));
+
+ /* in case need to play back the tone again when tx channel active */
+ switch (dcb->monrec_tone_action) {
+ case FSMDEF_MRTONE_PLAYED_MONITOR_TONE:
+ dcb->monrec_tone_action = FSMDEF_MRTONE_RESUME_MONITOR_TONE;
+ break;
+
+ case FSMDEF_MRTONE_PLAYED_RECORDER_TONE:
+ dcb->monrec_tone_action = FSMDEF_MRTONE_RESUME_RECORDER_TONE;
+ break;
+
+ case FSMDEF_MRTONE_PLAYED_BOTH_TONES:
+ dcb->monrec_tone_action = FSMDEF_MRTONE_RESUME_BOTH_TONES;
+ break;
+
+ default:
+ break;
+ }
+
+ LSM_DEBUG(DEB_L_C_F_PREFIX"%s: Setting monrec_tone_action: %d so resume to play correct tone.\n",
+ DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, dcb->call_id, fname), fname,
+ dcb->monrec_tone_action);
+ }
+ dcb->active_tone = VCM_NO_TONE;
+ } else {
+ LSM_DEBUG(DEB_L_C_F_PREFIX"Ignoring tone stop request\n",
+ DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, call_id, fname));
+ }
+
+ return (CC_RC_SUCCESS);
+}
+
+/*
+ * Function
+ *
+ * @param[in] tone - tone type
+ * @param[in] alert_info - alertinfo header
+ * @param[in] call_handle- call handle
+ * @param[in] direction - network, speaker, both
+ * @param[in] duration - length of time for tone to be played
+ *
+ * @return none
+ */
+void
+lsm_tone_start_with_duration (vcm_tones_t tone, short alert_info,
+ cc_call_handle_t call_handle, groupid_t group_id,
+ streamid_t stream_id, uint16_t direction,
+ uint32_t duration)
+{
+
+ static const char *fname = "lsm_tone_start_with_duration";
+
+ DEF_DEBUG(DEB_L_C_F_PREFIX"tone=%-2d: direction=%-2d duration=%-2d\n",
+ DEB_L_C_F_PREFIX_ARGS(LSM, GET_LINE_ID(call_handle), GET_CALL_ID(call_handle), fname),
+ tone, direction, duration);
+
+ /*
+ * play the tone. audio path is always set by MSUI module.
+ */
+ vcmToneStart (tone, alert_info, call_handle, group_id, stream_id, direction);
+
+ lsm_update_active_tone (tone, GET_CALL_ID(call_handle));
+
+ lsm_start_tone_duration_timer (tone, duration, call_handle);
+}
+
+/*
+ * Function: lsm_get_used_instances_cnt
+ *
+ * @param line - line number
+ *
+ * Description: find the number of used instances for this particular line
+ *
+ * @return number of used instances
+ *
+ */
+int lsm_get_used_instances_cnt (line_t line)
+{
+ static const char fname[] = "lsm_get_used_instances_cnt";
+ int used_instances = 0;
+ lsm_lcb_t *lcb;
+
+ if (!sip_config_check_line(line)) {
+ LSM_ERR_MSG(LSM_F_PREFIX"invalid line (%d)\n", fname, line);
+
+ return (-1);
+ }
+
+ /*
+ * Count home many instances are already in use for this particular line.
+ */
+ FSM_FOR_ALL_CBS(lcb, lsm_lcbs, LSM_MAX_LCBS) {
+ if ((lcb->call_id != CC_NO_CALL_ID) &&
+ (lcb->line == line) &&
+ (lcb->state != LSM_S_IDLE)) {
+ used_instances++;
+ }
+ }
+
+ return (used_instances);
+}
+
+/*
+ * Function: lsm_get_all_used_instances_cnt
+ *
+ * Description: find the number of used instances for all lines
+ *
+ * @return number of used instances for all lines
+ *
+ */
+int lsm_get_all_used_instances_cnt ()
+{
+ int used_instances = 0;
+ lsm_lcb_t *lcb;
+
+ /*
+ * Count home many instances are already in use for all lines.
+ */
+ FSM_FOR_ALL_CBS(lcb, lsm_lcbs, LSM_MAX_LCBS) {
+ if ((lcb->call_id != CC_NO_CALL_ID) &&
+ (lcb->state != LSM_S_IDLE)) {
+ used_instances++;
+ }
+ }
+
+ return (used_instances);
+}
+
+/*
+ * Function: lsm_increment_call_chn_cnt
+ *
+ * @param line - line number
+ *
+ * Description:
+ *
+ * @return none
+ *
+ */
+void lsm_increment_call_chn_cnt (line_t line)
+{
+ uint32_t maxnumcalls = 0;
+ uint32_t busy_trigger = 0;
+ static const char fname[] = "lsm_increment_call_chn_cnt";
+
+ if ( line <=0 || line > MAX_REG_LINES ) {
+ LSM_ERR_MSG(LSM_F_PREFIX"invalid line (%d)\n", fname, line);
+ return;
+ }
+ lsm_call_perline[line-1]++;
+ config_get_line_value(CFGID_LINE_MAXNUMCALLS, &maxnumcalls, sizeof(maxnumcalls), line);
+ config_get_line_value(CFGID_LINE_BUSY_TRIGGER, &busy_trigger, sizeof(busy_trigger), line);
+ if (lsm_call_perline[line-1] == maxnumcalls) {
+ lsm_mnc_reached[line-1] = TRUE;;
+ ui_mnc_reached(line, TRUE);
+ }
+ if (lsm_call_perline[line - 1] == busy_trigger) {
+ lsm_bt_reached[line - 1] = TRUE;;
+ }
+
+ LSM_DEBUG(DEB_F_PREFIX"number of calls on line[%d]=%d"
+ "MaxNumCalls[%d]_reached=%s BusyTrigger[%d]_reached=%s\n",
+ DEB_F_PREFIX_ARGS(LSM, fname),
+ line, lsm_call_perline[line-1],
+ maxnumcalls, (lsm_mnc_reached[line-1] == TRUE) ? "TRUE" : "FALSE",
+ busy_trigger,(lsm_bt_reached[line-1] == TRUE) ? "TRUE" : "FALSE");
+}
+
+/*
+ * Function: lsm_decrement_call_chn_cnt
+ *
+ * @param line - line number
+ *
+ * Description:
+ *
+ * @return none
+ *
+ */
+void lsm_decrement_call_chn_cnt (line_t line)
+{
+ uint32_t maxnumcalls = 0;
+ uint32_t busy_trigger = 0;
+ static const char fname[] = "lsm_decrement_call_chn_cnt";
+
+ if ( line <=0 || line > MAX_REG_LINES ) {
+ LSM_ERR_MSG(LSM_F_PREFIX"invalid line (%d)\n", fname, line);
+ return;
+ }
+
+ lsm_call_perline[line-1]--;
+ config_get_line_value(CFGID_LINE_MAXNUMCALLS, &maxnumcalls, sizeof(maxnumcalls), line);
+ config_get_line_value(CFGID_LINE_BUSY_TRIGGER, &busy_trigger, sizeof(busy_trigger), line);
+ if (lsm_call_perline[line-1] <= (maxnumcalls-1)) {
+ lsm_mnc_reached[line-1] = FALSE;
+ ui_mnc_reached(line, FALSE);
+ }
+ if (lsm_call_perline[line - 1] == (busy_trigger -1)) {
+ lsm_bt_reached[line - 1] = FALSE;;
+ }
+ LSM_DEBUG(DEB_F_PREFIX"number of calls on line[%d]=%d"
+ "MaxNumCalls[%d]_reached=%s BusyTrigger[%d]_reached=%s\n",
+ DEB_F_PREFIX_ARGS(LSM, fname),
+ line, lsm_call_perline[line-1],
+ maxnumcalls, (lsm_mnc_reached[line-1] == TRUE) ? "TRUE" : "FALSE",
+ busy_trigger,(lsm_bt_reached[line-1] == TRUE) ? "TRUE" : "FALSE");
+}
+
+#define NO_ROLLOVER 0
+#define ROLLOVER_ACROSS_SAME_DN 1
+#define ROLLOVER_NEXT_AVAILABLE_LINE 2
+
+/*
+ * Function: lsm_find_next_available_line
+ *
+ * @param line - line number
+ * @param same_dn - whether lines with same DN to be looked at.
+ * @param incoming - whether we are looking for an available line for an anticipated incoming call.
+ *
+ * Description:
+ *
+ *
+ * @return found line number
+ *
+ */
+line_t lsm_find_next_available_line (line_t line, boolean same_dn, boolean incoming)
+{
+ char current_line_dn_name[MAX_LINE_NAME_SIZE];
+ char dn_name[MAX_LINE_NAME_SIZE];
+ uint32_t line_feature;
+ line_t i, j;
+ boolean *limit_reached;
+
+ /* determine whether to use MNC or BT limit */
+ if (incoming == TRUE) {
+ limit_reached = lsm_bt_reached;
+ }
+ else {
+ limit_reached = lsm_mnc_reached;
+ }
+
+ config_get_line_string(CFGID_LINE_NAME, current_line_dn_name, line, sizeof(current_line_dn_name));
+ /* This line has exhausted its limit, start rollover */
+ /* First, search the lines on top of the current one */
+ for (i=line+1; i <= MAX_REG_LINES; i++) {
+ config_get_line_value(CFGID_LINE_FEATURE, &line_feature, sizeof(line_feature), i);
+
+ /* if it is not a DN, skip it */
+ if (line_feature != cfgLineFeatureDN) {
+ continue;
+ }
+ /* Does this line have room to take the call */
+ if (limit_reached[i-1] == FALSE) {
+ if (same_dn == TRUE) {
+ config_get_line_string(CFGID_LINE_NAME, dn_name, i, sizeof(dn_name));
+ /* Does this line have the same DN */
+ if (cpr_strcasecmp(dn_name, current_line_dn_name) == 0) {
+ return (i);
+ }
+ } else {
+ return (i);
+ }
+ }
+ }
+ /*
+ * We went up to the top and couldn't find an available line,
+ * start from line 1 and search up to the current line, thus
+ * we are treating the available lines as a circular pool
+ */
+
+ for (j=1; j <= line; j++) {
+ config_get_line_value(CFGID_LINE_FEATURE, &line_feature, sizeof(line_feature), j);
+
+ /* if it is not a DN, skip it */
+ if (line_feature != cfgLineFeatureDN) {
+ continue;
+ }
+ /* Does this line have room to take the call */
+ if (limit_reached[j-1] == FALSE) {
+ if (same_dn == TRUE) {
+ config_get_line_string(CFGID_LINE_NAME, dn_name, j, sizeof(dn_name));
+ /* Does this line have the same DN */
+ if (cpr_strcasecmp(dn_name, current_line_dn_name) == 0) {
+ return (j);
+ }
+ } else {
+ return (j);
+ }
+ }
+ }
+
+ return (NO_LINES_AVAILABLE);
+}
+/*
+ * Function: lsm_get_newcall_line
+ *
+ * @param line - line number
+ *
+ * Description: find out a line that has room to make a
+ * new call based on the rollover settings
+ *
+ * @return found line number
+ *
+ */
+line_t lsm_get_newcall_line (line_t line)
+{
+ static const char fname[] = "lsm_get_newcall_line";
+ int rollover;
+ line_t found_line;
+
+ if (!lsm_mnc_reached[line-1]) {
+ /* Still room for extra calls on this line */
+ return (line);
+ }
+
+ config_get_value(CFGID_ROLLOVER, &rollover, sizeof(int));
+
+ if (rollover == NO_ROLLOVER) {
+ DEF_DEBUG(DEB_F_PREFIX"NO Rollover, no lines\n", DEB_F_PREFIX_ARGS(LSM, fname));
+ return (NO_LINES_AVAILABLE);
+ }
+
+
+ if (rollover == ROLLOVER_ACROSS_SAME_DN) {
+ /* Look for a line with the same DN */
+ return (lsm_find_next_available_line(line, TRUE, FALSE));
+ }
+
+ if (rollover == ROLLOVER_NEXT_AVAILABLE_LINE) {
+ /* Look for a line with the same DN first */
+ found_line = lsm_find_next_available_line(line, TRUE, FALSE);
+
+ if (found_line == NO_LINES_AVAILABLE) {
+ /*
+ * If nothing found, just look for any line, does
+ * not necessarily have to have the same DN
+ */
+ return (lsm_find_next_available_line(line, FALSE, FALSE));
+ } else {
+ return (found_line);
+ }
+ }
+
+ DEF_DEBUG(DEB_F_PREFIX"No lines available\n", DEB_F_PREFIX_ARGS(LSM, fname));
+
+ return (NO_LINES_AVAILABLE);
+}
+
+/*
+ * Function: lsm_get_available_line
+ *
+ * @param incoming - whether we are looking for an available line for an anticipated incoming call.
+ *
+ * Description: find out a line that has room to make a
+ * new call starting from the first line.
+ *
+ * @return found line number
+ *
+ */
+line_t lsm_get_available_line (boolean incoming)
+{
+ line_t line = 1; /* start with line 1 */
+
+ if (incoming == FALSE) {
+ if (!lsm_mnc_reached[line-1]) {
+ /* Still room for extra calls on this line */
+ return (line);
+ }
+ }
+ else {
+ if (!lsm_bt_reached[line-1]) {
+ /* Still room for extra calls on this line */
+ return (line);
+ }
+ }
+ return (lsm_find_next_available_line(line, FALSE, incoming));
+}
+
+/*
+ * Function: lsm_is_line_available_for_outgoing_call
+ *
+ * @param line
+ * @param incoming - whether we are looking for an available line for an anticipated incoming call.
+ *
+ * Description: find out if the line has room to make a new call
+ *
+ * @return TRUE/FALSE
+ *
+ */
+boolean lsm_is_line_available (line_t line, boolean incoming)
+{
+ if (incoming == FALSE) {
+ if (!lsm_mnc_reached[line-1]) {
+ /* Still room for extra calls on this line */
+ return (TRUE);
+ }
+ }
+ else {
+ if (!lsm_bt_reached[line-1]) {
+ /* Still room for incoming calls on this line */
+ return (TRUE);
+ }
+ }
+ return (FALSE);
+}
+
+/*
+ * lsm_get_instances_available_cnt
+ *
+ * return the number of available instances for this particular line
+ *
+ * NOTE: The function can return negative values, which the user should read
+ * as no available lines.
+ */
+int
+lsm_get_instances_available_cnt (line_t line, boolean expline)
+{
+ static const char fname[] = "lsm_get_instances_available_cnt";
+ int max_instances;
+ int used_instances = 0;
+ int free_instances;
+
+ if (!sip_config_check_line(line)) {
+ LSM_ERR_MSG(LSM_F_PREFIX"invalid line (%d)\n", fname, line);
+
+ return (-1);
+ }
+
+ used_instances = lsm_get_used_instances_cnt(line);
+
+ max_instances = (expline) ? (LSM_MAX_EXP_INSTANCES) : (LSM_MAX_INSTANCES);
+
+ free_instances = max_instances - used_instances;
+
+ if(free_instances > 0){
+ int all_used_instances = lsm_get_all_used_instances_cnt();
+ int all_max_instances = (expline) ? (LSM_MAX_CALLS) : (LSM_MAX_CALLS - 1);
+ int all_free_instances = all_max_instances - all_used_instances;
+ free_instances = ((free_instances < all_free_instances) ? free_instances : all_free_instances);
+ LSM_DEBUG("lsm_get_instances_available_cnt: line=%d, expline=%d, free=%d, all_used=%d, all_max=%d, all_free=%d\n",
+ line, expline, free_instances, all_used_instances, all_max_instances, all_free_instances);
+
+ }
+ LSM_DEBUG("lsm_get_instances_available_cnt: line=%d, expline=%d, free_instances=%d\n",
+ line, expline, free_instances);
+ return (free_instances);
+}
+
+
+static void
+lsm_init_lcb (lsm_lcb_t *lcb)
+{
+ lcb->call_id = CC_NO_CALL_ID;
+ lcb->line = LSM_NO_LINE;
+ lcb->previous_call_event = evMaxEvent;
+ lcb->state = LSM_S_IDLE;
+ lcb->mru = 0;
+ lcb->enable_ringback = TRUE;
+ lcb->flags = 0;
+ lcb->dcb = NULL;
+ lcb->gcid = NULL;
+ lcb->vid_flags = 0; //set to not visible
+ lcb->ui_id = CC_NO_CALL_ID;
+}
+
+/**
+ * Return the port back to Media service component
+ * @param [in] lcb - lsm control block
+ *
+ */
+static void lsm_release_port (lsm_lcb_t *lcb)
+{
+ static const char fname[] = "lsm_release_port";
+ fsmdef_media_t *start_media, *end_media;
+ fsmdef_dcb_t *dcb;
+ fsmdef_media_t *media;
+ int sdpmode = 0;
+
+ dcb = lcb->dcb;
+ if (dcb == NULL) {
+ LSM_ERR_MSG(get_debug_string(DEBUG_INPUT_NULL), fname);
+ return;
+ }
+
+ config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
+
+ LSM_DEBUG(DEB_L_C_F_PREFIX,
+ DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, dcb->call_id, fname));
+
+ start_media = GSMSDP_FIRST_MEDIA_ENTRY(dcb);
+ end_media = NULL; /* NULL means till the end of the list */
+
+ GSMSDP_FOR_MEDIA_LIST(media, start_media, end_media, dcb) {
+ if (!sdpmode) {
+ vcmRxReleasePort(media->cap_index, dcb->group_id, media->refid,
+ lsm_get_ms_ui_call_handle(lcb->line, lcb->call_id, lcb->ui_id), media->src_port);
+ }
+ }
+}
+
+static void
+lsm_free_lcb (lsm_lcb_t *lcb)
+{
+ lsm_release_port(lcb);
+ cpr_free(lcb->gcid);
+ lsm_init_lcb(lcb);
+}
+
+
+/**
+ * lsm_get_free_lcb
+ * return a free instance of the given line
+ *
+ * @param[in]call_id - gsm call id to allocate the lcb instance with.
+ * @param[in]line - line that the lcb instnce will be associated with
+ * @param[in]dcb - fsmdef_dcb_t structure that the lcb instance will
+ * be associated with.
+ * @return pointer to lsm_lcb_t if there is an available lcb otherwise
+ * returns NULL.
+ * @pre (dcb not_eq NULL)
+ */
+static lsm_lcb_t *
+lsm_get_free_lcb (callid_t call_id, line_t line, fsmdef_dcb_t *dcb)
+{
+ static const char fname[] = "lsm_get_free_lcb";
+ static int mru = 0;
+ lsm_lcb_t *lcb;
+ lsm_lcb_t *lcb_found = NULL;
+
+ if (!sip_config_check_line(line)) {
+ LSM_ERR_MSG(LSM_F_PREFIX"invalid line (%d)\n", fname, line);
+
+ return (NULL);
+ }
+
+
+ /*
+ * Set mru (most recently used).
+ * Used to determine which call came in first.
+ */
+ if (++mru < 0) {
+ mru = 1;
+ }
+
+ /*
+ * Find a free lcb.
+ */
+ FSM_FOR_ALL_CBS(lcb, lsm_lcbs, LSM_MAX_LCBS) {
+ if ((lcb->call_id == CC_NO_CALL_ID) && (lcb->state == LSM_S_IDLE)) {
+ lcb_found = lcb;
+ lcb->call_id = call_id;
+ lcb->line = line;
+ lcb->state = LSM_S_PENDING;
+ lcb->mru = mru;
+ lcb->dcb = dcb;
+ // start unmuted if txPref is true
+ lcb->vid_mute = cc_media_getVideoAutoTxPref() ? FALSE : TRUE;
+
+ lcb->ui_id = call_id; /* default UI ID is the same as call_id */
+ break;
+ }
+ }
+
+ return (lcb_found);
+}
+
+
+lsm_lcb_t *
+lsm_get_lcb_by_call_id (callid_t call_id)
+{
+ lsm_lcb_t *lcb;
+ lsm_lcb_t *lcb_found = NULL;
+ LSM_DEBUG(DEB_L_C_F_PREFIX"call_id=%d.\n",
+ DEB_L_C_F_PREFIX_ARGS(LSM, 0, call_id, "lsm_get_lcb_by_call_id"), call_id);
+
+ FSM_FOR_ALL_CBS(lcb, lsm_lcbs, LSM_MAX_LCBS) {
+ if (lcb->call_id == call_id) {
+ lcb_found = lcb;
+ break;
+ }
+ }
+
+ return (lcb_found);
+}
+
+/**
+ * This function returns the LSM state for the given call_id.
+ *
+ * @param[in] call_id - call id
+ *
+ * @return lsm_states_t of the given call_id. If the
+ * there is no call associated with the given
+ * call ID it returns the LSM_S_NONE.
+ */
+lsm_states_t
+lsm_get_state (callid_t call_id)
+{
+ lsm_lcb_t *lcb;
+
+ lcb = lsm_get_lcb_by_call_id(call_id);
+
+ if (lcb == NULL) {
+ /* there is no call for this call id */
+ return (LSM_S_NONE);
+ }
+ return (lcb->state);
+}
+
+static void
+lsm_change_state (lsm_lcb_t *lcb, int line_num, lsm_states_t new_state)
+{
+ static const char fname1[] = "lsm_change_state";
+ LSM_DEBUG(DEB_L_C_F_PREFIX"%d: %s -> %s\n",
+ DEB_L_C_F_PREFIX_ARGS(LSM, lcb->line, lcb->call_id, fname1),
+ line_num, lsm_state_name(lcb->state), lsm_state_name(new_state));
+
+ lcb->state = new_state;
+}
+
+boolean
+lsm_is_phone_idle (void)
+{
+ static const char fname[] = "lsm_is_phone_idle";
+ boolean idle = TRUE;
+ lsm_lcb_t *lcb;
+
+ if(!lsm_lcbs){
+ LSM_DEBUG(DEB_F_PREFIX"No lsm line cb\n", DEB_F_PREFIX_ARGS(LSM, fname));
+ return (idle);
+ }
+
+ FSM_FOR_ALL_CBS(lcb, lsm_lcbs, LSM_MAX_LCBS) {
+ if ((lcb->call_id != CC_NO_CALL_ID) && (lcb->state != LSM_S_IDLE)) {
+ idle = FALSE;
+ break;
+ }
+ }
+
+ return (idle);
+}
+
+
+
+/*
+ * Function: lsm_is_phone_inactive
+ *
+ * Parameters: None.
+ *
+ * Description: Determines if the phone is inactive. Inactive means the phone
+ * as active at some point, but now it is not - there are still
+ * calls on the phone but they are probably in a holding state.
+ * This is different from idle, which means that there are not
+ * any calls on the phone.
+ *
+ * Returns:
+ * inactive: FALSE: phone is not inactive
+ * TRUE: phone is inactive
+ */
+boolean
+lsm_is_phone_inactive (void)
+{
+ boolean inactive = TRUE;
+ lsm_lcb_t *lcb;
+
+ FSM_FOR_ALL_CBS(lcb, lsm_lcbs, LSM_MAX_LCBS) {
+ if ((lcb->call_id != CC_NO_CALL_ID) &&
+ ((lcb->state == LSM_S_OFFHOOK) ||
+ (lcb->state == LSM_S_PENDING) ||
+ (lcb->state == LSM_S_PROCEED) ||
+ (lcb->state == LSM_S_RINGOUT) ||
+ (lcb->state == LSM_S_RINGIN) ||
+ (lcb->state == LSM_S_CONNECTED))) {
+ inactive = FALSE;
+ break;
+ }
+ }
+
+ return (inactive);
+}
+
+/*
+ * Function: lsm_callwaiting
+ *
+ * Parameters: None.
+ *
+ * Description: Determines if the phone is in a state that this
+ * call will be handled by the callwaiting code. TNP
+ * phones allow call-waiting when dialing digits while
+ * the legacy phones do not.
+ *
+ * Returns:
+ * inactive: FALSE: Treat as a normal call on an idle phone
+ * TRUE: Display incoming call and play call waiting tone
+ */
+boolean
+lsm_callwaiting (void)
+{
+ lsm_lcb_t *lcb;
+
+ FSM_FOR_ALL_CBS(lcb, lsm_lcbs, LSM_MAX_LCBS) {
+ if (lcb->call_id != CC_NO_CALL_ID) {
+ switch (lcb->state) {
+ case LSM_S_OFFHOOK:
+ case LSM_S_PROCEED:
+ case LSM_S_RINGOUT:
+ case LSM_S_CONNECTED:
+ return (TRUE);
+
+ default:
+ break;
+ }
+ }
+ }
+
+ return (FALSE);
+}
+
+static callid_t
+lsm_find_state (lsm_states_t state)
+{
+ callid_t found_callid = CC_NO_CALL_ID;
+ lsm_lcb_t *lcb;
+
+ FSM_FOR_ALL_CBS(lcb, lsm_lcbs, LSM_MAX_LCBS) {
+ if ((lcb->call_id != CC_NO_CALL_ID) && (lcb->state == state)) {
+ found_callid = lcb->call_id;
+ break;
+ }
+ }
+
+ return (found_callid);
+}
+
+/**
+ * lsm_get_facility_by_called_number
+ * return facility by the given called_number.
+ *
+ * @param[in]call_id - gsm's call_id for a new call.
+ * @param[in]called_number - pointer to the called number.
+ * @paran[in/out]free_line - pointer to the line_t to store
+ * the result line number corresponding
+ * to the called number given.
+ * @param[in]expline - boolean indicating extra instance
+ * is needed.
+ * @param[in]dcb - pointer to void but it must be
+ * a pointer to fsmdef_dcb_t to bind with
+ * the new LCB. The reason to use a void
+ * pointer is the declaration of the function
+ * is in lsm.h. The lsm.h file is used by
+ * components outside gsm environment. Those
+ * modules would need to include the fsm.h
+ * which is not desirable. Using void pointer
+ * avoids this problem.
+ *
+ * @return cc_cause_t
+ *
+ * @pre (called_number not_eq NULL)
+ * @pre (free_line not_eq NULL)
+ * @pre (dcb not_eq NULL)
+ */
+cc_causes_t
+lsm_get_facility_by_called_number (callid_t call_id,
+ const char *called_number,
+ line_t *free_line, boolean expline,
+ void *dcb)
+{
+ static const char fname[] = "lsm_get_facility_by_called_number";
+ line_t line;
+ lsm_lcb_t *lcb;
+ int free_instances;
+ line_t madn_line;
+
+ lsm_debug_entry(call_id, 0, fname);
+ LSM_DEBUG(DEB_F_PREFIX"called_number= %s\n", DEB_F_PREFIX_ARGS(LSM, fname), called_number);
+
+ //line = sip_config_get_line_by_called_number(1, called_number);
+ line = 1;
+ if (line == 0) {
+ return (CC_CAUSE_UNASSIGNED_NUM);
+ }
+ *free_line = line;
+
+ /* check for a MADN line */
+ madn_line = sip_config_get_line_by_called_number((line_t)(line + 1),
+ called_number);
+
+ /*
+ * Check to see if we even have any available instances.
+ */
+ free_instances = lsm_get_instances_available_cnt(line, expline);
+
+ /* if it is a MADN line and it already has a call, then go to next
+ * line with this MADN number.
+ */
+ if ((madn_line) && (free_instances < 2)) {
+ while (madn_line) {
+ free_instances = lsm_get_instances_available_cnt(madn_line, expline);
+ if (free_instances == 2) {
+ *free_line = line = madn_line;
+ break;
+ }
+ madn_line = sip_config_get_line_by_called_number((line_t)(madn_line + 1),
+ called_number);
+ }
+ if (madn_line == 0) {
+ return (CC_CAUSE_BUSY);
+ }
+ }
+
+ if (free_instances <= 0) {
+ return (CC_CAUSE_BUSY);
+ }
+
+ lcb = lsm_get_free_lcb(call_id, line, (fsmdef_dcb_t *)dcb);
+ if (lcb == NULL) {
+ return (CC_CAUSE_NO_RESOURCE);
+ }
+
+ return (CC_CAUSE_OK);
+}
+
+/**
+ * lsm_allocate_call_bandwidth
+ *
+ * @param[in] none.
+ *
+ * The wlan interface puts into unique situation where call control
+ * has to allocate the worst case bandwith before creating a
+ * inbound or outbound call. The function call will interface through
+ * media API into wlan to get the call bandwidth. The function
+ * return is asynchronous and will block till the return media
+ * callback signals to continue the execution.
+ *
+ * @return true if the bandwidth can be allocated else false.
+ * @pre none
+ */
+
+cc_causes_t lsm_allocate_call_bandwidth (callid_t call_id, int sessions)
+{
+ //get line for vcm
+ line_t line = lsm_get_line_by_call_id(call_id);
+ //cc_feature(CC_SRC_GSM, call_id, 0, CC_FEATURE_CAC_RESP_PASS, NULL);
+
+ /* Activate the wlan before allocating bandwidth */
+ vcmActivateWlan(TRUE);
+
+ if (vcmAllocateBandwidth(lsm_get_ms_ui_call_handle(line, call_id, CC_NO_CALL_ID), sessions)) {
+ return(CC_CAUSE_OK);
+ }
+
+ return(CC_CAUSE_CONGESTION);
+}
+
+/**
+ * lsm_get_facility_by_line
+ * return facility by the given line
+ *
+ * @param[in]call_id - gsm's call_id for a new call.
+ * @param[in]line - line
+ * @param[in]expline - boolean indicating extra instance
+ * is needed.
+ * @param[in]dcb - pointer to void but it must be
+ * a pointer to fsmdef_dcb_t to bind with
+ * the new LCB. The reason to use a void
+ * pointer is the declaration of the function
+ * is in lsm.h. The lsm.h file is used by
+ * components outside gsm environment. Those
+ * modules would need to include the fsm.h
+ * which is not desirable. Using void pointer
+ * avoids this problem.
+ *
+ * @return cc_cause_t
+ * @pre (dcb not_eq NULL)
+ */
+cc_causes_t
+lsm_get_facility_by_line (callid_t call_id, line_t line, boolean expline,
+ void *dcb)
+{
+ static const char fname[] = "lsm_get_facility_by_line";
+ lsm_lcb_t *lcb;
+ int free_instances;
+
+ LSM_DEBUG(get_debug_string(LSM_DBG_INT1), call_id, line, fname,
+ "exp", expline);
+
+ /*
+ * Check to see if we even have any available instances
+ */
+ free_instances = lsm_get_instances_available_cnt(line, expline);
+ if (free_instances <= 0) {
+ return (CC_CAUSE_BUSY);
+ }
+
+ lcb = lsm_get_free_lcb(call_id, line, (fsmdef_dcb_t *)dcb);
+ if (lcb == NULL) {
+ return (CC_CAUSE_NO_RESOURCE);
+ }
+
+ return (CC_CAUSE_OK);
+}
+
+
+#ifdef _WIN32
+/* This function enumerates over the lcbs
+ * and attempts to terminate the call
+ * This is used by softphone when
+ * it exits and the softphone is
+ * still engaged in a call
+ */
+void
+terminate_active_calls (void)
+{
+ callid_t call_id = CC_NO_CALL_ID;
+ lsm_lcb_t *lcb;
+ line_t line;
+
+ FSM_FOR_ALL_CBS(lcb, lsm_lcbs, LSM_MAX_LCBS) {
+ if (lcb->call_id != CC_NO_CALL_ID) {
+ line = lsm_get_line_by_call_id(lcb->call_id);
+ /* Currently cc_feature does a better job of releasing the call
+ * compared to cc_onhook.
+ */
+ //cc_onhook(CC_SRC_UI, call_id, line);
+ cc_feature(CC_SRC_UI, call_id, line, CC_FEATURE_END_CALL, NULL);
+ call_id = lcb->call_id;
+ }
+ }
+}
+
+
+#endif
+
+line_t
+lsm_get_line_by_call_id (callid_t call_id)
+{
+ fsmdef_dcb_t *dcb;
+ line_t line;
+
+ dcb = fsmdef_get_dcb_by_call_id(call_id);
+
+ if (dcb != NULL) {
+ line = dcb->line;
+ } else {
+ line = LSM_DEFAULT_LINE;
+ }
+
+ return (line);
+}
+
+/*
+ * This is a callback function for those tones that are
+ * played in two parts (stutter and msgwaiting) or played
+ * every x seconds, but are not steady tones (call waiting).
+ *
+ * @param[in] data The gsm ID (callid_t) of the call of the
+ * tones timer has timeout.
+ *
+ * @return N/A
+ */
+void
+lsm_tmr_tones_callback (void *data)
+{
+ static const char fname[] = "lsm_tmr_tones_callback";
+ callid_t call_id;
+ fsmdef_dcb_t *dcb = NULL;
+ fsmdef_media_t *media;
+
+ LSM_DEBUG(DEB_F_PREFIX"invoked", DEB_F_PREFIX_ARGS(LSM, fname));
+
+ call_id = (callid_t)(long)data;
+ if (call_id == CC_NO_CALL_ID) {
+ /* Invalid call id */
+ LSM_DEBUG(DEB_F_PREFIX"invalid call id\n", DEB_F_PREFIX_ARGS(LSM, fname));
+ return;
+ }
+
+ /*
+ * A call-waiting tone should be played if these conditions are met:
+ * 1. A line must be ringing for an incoming call
+ * 2. The phone must be in a state that we handle callwaiting
+ */
+ /* Retrieve dcb from call id */
+ dcb = fsmdef_get_dcb_by_call_id(call_id);
+ if (dcb == NULL) {
+ LSM_DEBUG(DEB_F_PREFIX"no dcb found for call_id %d\n", DEB_F_PREFIX_ARGS(LSM, fname), call_id);
+ return;
+ }
+
+ media = gsmsdp_find_audio_media(dcb);
+
+ if ((lsm_find_state(LSM_S_RINGIN) > CC_NO_CALL_ID) && (lsm_callwaiting())) {
+
+ /* Determine what tone/ringing pattern to play */
+ switch (dcb->alert_info) {
+
+ case ALERTING_RING:
+
+ /* Need to map the alerting patterns to the call waiting patterns */
+ switch (dcb->alerting_ring) {
+ case VCM_BELLCORE_DR2:
+ lsm_util_start_tone(VCM_CALL_WAITING_2_TONE, NO, lsm_get_ms_ui_call_handle(dcb->line, dcb->call_id, CC_NO_CALL_ID), dcb->group_id,
+ ((media != NULL) ? media->refid : CC_NO_MEDIA_REF_ID),
+ dcb->tone_direction);
+ break;
+ case VCM_BELLCORE_DR3:
+ lsm_util_start_tone(VCM_CALL_WAITING_3_TONE, NO, lsm_get_ms_ui_call_handle(dcb->line, dcb->call_id, CC_NO_CALL_ID), dcb->group_id,
+ ((media != NULL) ? media->refid : CC_NO_MEDIA_REF_ID),
+ dcb->tone_direction);
+ break;
+ case VCM_BELLCORE_DR4:
+ lsm_util_start_tone(VCM_CALL_WAITING_4_TONE, NO, lsm_get_ms_ui_call_handle(dcb->line, dcb->call_id, CC_NO_CALL_ID), dcb->group_id,
+ ((media != NULL) ? media->refid : CC_NO_MEDIA_REF_ID),
+ dcb->tone_direction);
+ break;
+ default:
+ lsm_util_start_tone(VCM_CALL_WAITING_TONE, NO, lsm_get_ms_ui_call_handle(dcb->line, dcb->call_id, CC_NO_CALL_ID), dcb->group_id,
+ ((media != NULL) ? media->refid : CC_NO_MEDIA_REF_ID),
+ dcb->tone_direction);
+ }
+ break;
+
+ case ALERTING_TONE:
+
+ /* Busy verify is just 2 secs of dialtone followed by
+ * a call waiting tone every 10 secs. The rest of the
+ * tones are just played once.
+ */
+ switch (dcb->alerting_tone) {
+ case VCM_BUSY_VERIFY_TONE:
+ lsm_util_start_tone(VCM_CALL_WAITING_TONE, NO, lsm_get_ms_ui_call_handle(dcb->line, dcb->call_id, CC_NO_CALL_ID), dcb->group_id,
+ ((media != NULL) ? media->refid : CC_NO_MEDIA_REF_ID),
+ dcb->tone_direction);
+ if (cprStartTimer(lsm_tmr_tones, BUSY_VERIFICATION_DELAY,
+ (void *)(long)dcb->call_id) == CPR_FAILURE) {
+ LSM_DEBUG(get_debug_string(DEBUG_GENERAL_SYSTEMCALL_FAILED),
+ fname, "cprStartTimer", cpr_errno);
+ }
+ break;
+
+ case VCM_CALL_WAITING_TONE:
+ case VCM_CALL_WAITING_2_TONE:
+ case VCM_CALL_WAITING_3_TONE:
+ case VCM_CALL_WAITING_4_TONE:
+ lsm_util_start_tone(dcb->alerting_tone, NO, lsm_get_ms_ui_call_handle(dcb->line, dcb->call_id, CC_NO_CALL_ID), dcb->group_id,
+ ((media != NULL) ? media->refid : CC_NO_MEDIA_REF_ID),
+ dcb->tone_direction);
+ break;
+
+ case VCM_MSG_WAITING_TONE:
+ case VCM_STUTTER_TONE:
+ lsm_util_start_tone(VCM_INSIDE_DIAL_TONE, NO, lsm_get_ms_ui_call_handle(dcb->line, dcb->call_id, CC_NO_CALL_ID), dcb->group_id,
+ ((media != NULL) ? media->refid : CC_NO_MEDIA_REF_ID),
+ dcb->tone_direction);
+ lsm_tmr_tones_ticks = 0;
+ break;
+ default:
+ break;
+ }
+ break;
+
+ default:
+ lsm_util_start_tone(VCM_CALL_WAITING_TONE, NO, lsm_get_ms_ui_call_handle(dcb->line, dcb->call_id, CC_NO_CALL_ID), dcb->group_id,
+ ((media != NULL) ? media->refid : CC_NO_MEDIA_REF_ID),
+ dcb->tone_direction);
+
+ break;
+ }
+
+ } else if (dcb->dialplan_tone) {
+ dcb->dialplan_tone = FALSE;
+ switch (dcb->alert_info) {
+
+ case ALERTING_TONE:
+ /*
+ * Currently the only supported multi-part tones
+ * played via the dialplan are Message Waiting and
+ * Stutter dialtones.
+ */
+ switch (dcb->alerting_tone) {
+ case VCM_MSG_WAITING_TONE:
+ case VCM_STUTTER_TONE:
+ lsm_util_start_tone(VCM_INSIDE_DIAL_TONE, NO, lsm_get_ms_ui_call_handle(dcb->line, dcb->call_id, CC_NO_CALL_ID), dcb->group_id,
+ ((media != NULL) ? media->refid : CC_NO_MEDIA_REF_ID),
+ dcb->tone_direction);
+ break;
+
+ case VCM_HOLD_TONE:
+ lsm_util_start_tone(dcb->alerting_tone, NO, lsm_get_ms_ui_call_handle(dcb->line, dcb->call_id, CC_NO_CALL_ID), dcb->group_id,
+ ((media != NULL) ? media->refid : CC_NO_MEDIA_REF_ID),
+ dcb->tone_direction);
+ break;
+
+ default:
+ break;
+ }
+
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+/*
+ * Function : lsm_start_multipart_tone_timer
+ * Parameters : Tone: 2nd part of tone to play
+ * Delay: Time to delay between playing the 1st and 2nd parts of the tone
+ * CallId: Used to retrieve the dcb for this call
+ * Purpose : This function is used to set up the dcb to play the 2nd part of
+ * the tone. A timer is started to allow the 1st tone to played to
+ * completion before the 2nd part is started.
+ */
+void
+lsm_start_multipart_tone_timer (vcm_tones_t tone,
+ uint32_t delay,
+ callid_t callId)
+{
+ static const char fname[] = "lsm_start_multipart_tone_timer";
+ fsmdef_dcb_t *dcb;
+
+ /* Set up dcb for timer callback function */
+ dcb = fsmdef_get_dcb_by_call_id(callId);
+ dcb->alert_info = ALERTING_TONE;
+ dcb->alerting_tone = tone;
+ dcb->dialplan_tone = TRUE;
+
+ if (cprCancelTimer(lsm_tmr_tones) == CPR_FAILURE) {
+ LSM_DEBUG(get_debug_string(DEBUG_GENERAL_SYSTEMCALL_FAILED),
+ fname, "cprCancelTimer", cpr_errno);
+ }
+ if (cprStartTimer(lsm_tmr_tones, delay, (void *)(long)dcb->call_id) ==
+ CPR_FAILURE) {
+ LSM_DEBUG(get_debug_string(DEBUG_GENERAL_SYSTEMCALL_FAILED),
+ fname, "cprStartTimer", cpr_errno);
+ }
+}
+
+/*
+ * Function : lsm_stop_multipart_tone_timer
+ * Parameters : None
+ * Purpose : Called from vcm_stop_tones. That function
+ * will stop the 1st part of the tone, this
+ * function cancels the timer so the 2nd part
+ * will never be played.
+ */
+void
+lsm_stop_multipart_tone_timer (void)
+{
+ static const char fname[] = "lsm_stop_multipart_tone_timer";
+
+ if (cprCancelTimer(lsm_tmr_tones) == CPR_FAILURE) {
+ LSM_DEBUG(get_debug_string(DEBUG_GENERAL_SYSTEMCALL_FAILED),
+ fname, "cprCancelTimer", cpr_errno);
+ }
+}
+
+/*
+ * Function : lsm_start_continuous_tone_timer
+ * Parameters : Tone: tone to play
+ * Delay: Time to delay between playing the tone
+ * CallId: Used to retrieve the dcb for this call
+ * Purpose : This function is used to set up the dcb to play a tone continuously.
+ * An example being the tone on hold tone.
+ */
+void
+lsm_start_continuous_tone_timer (vcm_tones_t tone,
+ uint32_t delay,
+ callid_t callId)
+{
+ static const char fname[] = "lsm_start_continuous_tone_timer";
+ fsmdef_dcb_t *dcb;
+
+ /* Set up dcb for timer callback function */
+ dcb = fsmdef_get_dcb_by_call_id(callId);
+ dcb->alert_info = ALERTING_TONE;
+ dcb->alerting_tone = tone;
+ dcb->dialplan_tone = TRUE;
+
+ if (cprCancelTimer(lsm_continuous_tmr_tones) == CPR_FAILURE) {
+ LSM_DEBUG(get_debug_string(DEBUG_GENERAL_SYSTEMCALL_FAILED),
+ fname, "cprCancelTimer", cpr_errno);
+ }
+ if (cprStartTimer(lsm_continuous_tmr_tones, delay, (void *)(long)dcb->call_id)
+ == CPR_FAILURE) {
+ LSM_DEBUG(get_debug_string(DEBUG_GENERAL_SYSTEMCALL_FAILED),
+ fname, "cprStartTimer", cpr_errno);
+ }
+}
+
+/*
+ * Function : lsm_stop_continuous_tone_timer
+ * Parameters : None
+ * Purpose : Called from vcm_stop_tones. That function
+ * will stop the the tone, this function cancels
+ * the timer subsequent playing of the tone is not
+ * performed
+ */
+void
+lsm_stop_continuous_tone_timer (void)
+{
+ static const char fname[] = "lsm_stop_continuous_tone_timer";
+
+ if (cprCancelTimer(lsm_continuous_tmr_tones) == CPR_FAILURE) {
+ LSM_DEBUG(get_debug_string(DEBUG_GENERAL_SYSTEMCALL_FAILED),
+ fname, "cprCancelTimer", cpr_errno);
+ }
+}
+
+/*
+ * Function : lsm_start_tone_duration_timer
+ * Parameters : Tone: tone type to play
+ * Duration: length of time for tone to play
+ * call_handle: Used to retrieve the dcb for this call
+ * Purpose : This function is used to set up the dcb to play the tone for
+ * a specified length of time.
+ */
+void
+lsm_start_tone_duration_timer (vcm_tones_t tone,
+ uint32_t duration,
+ cc_call_handle_t call_handle)
+{
+ static const char fname[] = "lsm_start_tone_duration_timer";
+ fsmdef_dcb_t *dcb;
+
+ /* Set up dcb for timer callback function */
+ dcb = fsmdef_get_dcb_by_call_id(GET_CALL_ID(call_handle));
+
+ if (cprCancelTimer(lsm_tone_duration_tmr) == CPR_FAILURE) {
+ LSM_DEBUG(get_debug_string(DEBUG_GENERAL_SYSTEMCALL_FAILED),
+ fname, "cprCancelTimer", cpr_errno);
+ }
+ if (cprStartTimer(lsm_tone_duration_tmr, duration*1000, (void *)(long)dcb->call_id) ==
+ CPR_FAILURE) {
+ LSM_DEBUG(get_debug_string(DEBUG_GENERAL_SYSTEMCALL_FAILED),
+ fname, "cprStartTimer", cpr_errno);
+ }
+}
+
+/*
+ * Function : lsm_stop_tone_duration_timer
+ * Parameters : None
+ * Purpose : Called from vcm_stop_tones. That function
+ * will stop the tone.
+ */
+void
+lsm_stop_tone_duration_timer (void)
+{
+ static const char fname[] = "lsm_stop_tone_duration_timer";
+
+ if (cprCancelTimer(lsm_tone_duration_tmr) == CPR_FAILURE) {
+ LSM_DEBUG(get_debug_string(DEBUG_GENERAL_SYSTEMCALL_FAILED),
+ fname, "cprCancelTimer", cpr_errno);
+ }
+}
+
+/*
+ * This is a callback function for those tones that are
+ * played in two parts (stutter and msgwaiting) or played
+ * every x seconds, but are not steady tones (call waiting).
+ *
+ * @param[in] data The gsm ID (callid_t) of the call of the
+ * tones timer has timeout.
+ *
+ * @return N/A
+ */
+void
+lsm_tone_duration_tmr_callback (void *data)
+{
+ static const char fname[] = "lsm_tone_duration_tmr_callback";
+ callid_t call_id;
+ fsmdef_dcb_t *dcb = NULL;
+ fsmdef_media_t *media;
+
+ LSM_DEBUG(DEB_F_PREFIX"invoked", DEB_F_PREFIX_ARGS(LSM, fname));
+
+ call_id = (callid_t)(long)data;
+ if (call_id == CC_NO_CALL_ID) {
+ /* Invalid call id */
+ LSM_DEBUG(DEB_F_PREFIX"invalid call id\n", DEB_F_PREFIX_ARGS(LSM, fname));
+ return;
+ }
+
+ /* Retrieve dcb from call id */
+ dcb = fsmdef_get_dcb_by_call_id(call_id);
+ if (dcb == NULL) {
+ LSM_DEBUG(DEB_F_PREFIX"no dcb found for call_id %d\n", DEB_F_PREFIX_ARGS(LSM, fname), call_id);
+ return;
+ }
+
+ media = gsmsdp_find_audio_media(dcb);
+
+ vcmToneStop(dcb->active_tone, dcb->group_id,
+ ((media != NULL) ? media->refid : CC_NO_MEDIA_REF_ID),
+ lsm_get_ms_ui_call_handle(dcb->line, dcb->call_id, CC_NO_CALL_ID));
+
+ /* Up until this point, only sip core has started the call release procedure */
+ /* since upon receipt of the BYE. Now that tone is completed playing as requested */
+ /* in the BYE, need to continue processing with call clearing. */
+
+ cc_int_release(CC_SRC_GSM, CC_SRC_GSM, call_id, dcb->line, CC_CAUSE_NORMAL, NULL, NULL);
+}
+
+/*
+ * LSM internal function that checks if any calls are in a pending
+ * answer condition. Such a condition occurs when the GSM has delayed
+ * answering an incoming call while trying to clear other calls.
+ *
+ * @return call_id if found, else CC_NO_CALL_ID.
+ */
+static callid_t
+lsm_answer_pending (void)
+{
+ callid_t found_callid = CC_NO_CALL_ID;
+ lsm_lcb_t *lcb;
+
+ FSM_FOR_ALL_CBS(lcb, lsm_lcbs, LSM_MAX_LCBS) {
+ if ((lcb->call_id != CC_NO_CALL_ID) &&
+ (FSM_CHK_FLAGS(lcb->flags, LSM_FLAGS_ANSWER_PENDING))) {
+
+ found_callid = lcb->call_id;
+ break;
+ }
+ }
+
+ return (found_callid);
+}
+
+/**
+ *
+ * Hold Reversion Alert - plays the ringer once.
+ *
+ * @param lsm_lcb_t lcb for this call
+ * @param callid_t gsm_id
+ * @param line_t line
+ *
+ * @return none
+ *
+ * @pre (lcb not_eq NULL)
+ */
+static void
+lsm_reversion_ringer (lsm_lcb_t *lcb, callid_t call_id, line_t line)
+{
+ vcm_ring_mode_t ringerMode = VCM_INSIDE_RING;
+ vcm_tones_t toneMode = VCM_CALL_WAITING_TONE;
+
+ if (!lsm_callwaiting()) {
+ config_get_line_value(CFGID_LINE_RING_SETTING_IDLE,
+ &ringSettingIdle, sizeof(ringSettingIdle),
+ line);
+ if (cc_line_ringer_mode[line] == CC_RING_DISABLE) {
+ ringerMode = VCM_FLASHONLY_RING;
+ } else if (ringSettingIdle == DISABLE) {
+ ringerMode = VCM_RING_OFF;
+ } else if (ringSettingIdle == FLASH_ONLY) {
+ ringerMode = VCM_FLASHONLY_RING;
+ }
+
+ vcmControlRinger(ringerMode, YES, NO, line, call_id);
+
+ } else {
+ lsm_tmr_tones_ticks = 0;
+
+ config_get_line_value(CFGID_LINE_RING_SETTING_ACTIVE,
+ &ringSettingActive, sizeof(ringSettingActive),
+ line);
+ if (ringSettingActive == DISABLE) {
+ ringerMode = VCM_RING_OFF;
+ } else if (ringSettingActive == FLASH_ONLY) {
+ ringerMode = VCM_FLASHONLY_RING;
+ }
+
+ if (ringSettingActive == BEEP_ONLY) {
+ fsmdef_media_t *media = gsmsdp_find_audio_media(lcb->dcb);
+
+ lsm_util_start_tone(toneMode, NO, lsm_get_ms_ui_call_handle(line, call_id, CC_NO_CALL_ID), lcb->dcb->group_id,
+ ((media != NULL) ? media->refid : CC_NO_MEDIA_REF_ID),
+ VCM_PLAY_TONE_TO_EAR);
+ } else {
+ vcmControlRinger(ringerMode, YES, NO, line, call_id);
+ }
+ }
+}
+
+/**
+ * This function will set beep only settings.
+ *
+ * @param[in] dcb - DEF S/M control block
+ * @param[out] toneMode_p - pointer to tone mode
+ *
+ * @return none
+ */
+static void
+lsm_set_beep_only_settings (fsmdef_dcb_t *dcb, vcm_tones_t *toneMode_p)
+{
+ switch (dcb->alert_info) {
+ /*
+ * Map BTS requested ring pattern to corresponding call waiting
+ * pattern if phone is already offhook. All call waiting tones
+ * must be played every ten seconds and msg waiting and stutter
+ * dialtone are multi-part tones that play and then after
+ * 100 ms give steady dialtone. Set a timer to call the tone
+ * callback function for those tones.
+ */
+ case ALERTING_RING:
+ lsm_tmr_tones_ticks = callWaitingDelay;
+ switch (dcb->alerting_ring) {
+ case VCM_BELLCORE_DR2:
+ *toneMode_p = VCM_CALL_WAITING_2_TONE;
+ break;
+
+ case VCM_BELLCORE_DR3:
+ *toneMode_p = VCM_CALL_WAITING_3_TONE;
+ break;
+
+ case VCM_BELLCORE_DR4:
+ *toneMode_p = VCM_CALL_WAITING_4_TONE;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ /* BTS wishes to override call waiting tone */
+ case ALERTING_TONE:
+ /*
+ * In violation of the spec, BTS will send tones in the
+ * Alert-Info header and if the phone is offhook, wants
+ * the phone to play the tone specified in the Alert-Info
+ * header instead of the normal call waiting tone. If this
+ * line is connected to a call manager follow the spec and
+ * always play the call waiting tone regardless of what was
+ * received in the Alert-Info header.
+ */
+ if (sip_regmgr_get_cc_mode(dcb->line) == REG_MODE_CCM) {
+ dcb->alerting_tone = VCM_CALL_WAITING_TONE;
+ LSM_DEBUG(DEB_F_PREFIX"%s - Overriding value in Alert-Info header as line %d is \
+ connected to a Call Manager.\n",
+ DEB_F_PREFIX_ARGS(LSM, "lsm_set_beep_only_settings"), dcb->line);
+ }
+ *toneMode_p = dcb->alerting_tone;
+ switch (dcb->alerting_tone) {
+ case VCM_MSG_WAITING_TONE:
+ lsm_tmr_tones_ticks = MSG_WAITING_DELAY;
+ break;
+
+ case VCM_STUTTER_TONE:
+ lsm_tmr_tones_ticks = STUTTER_DELAY;
+ break;
+
+ case VCM_BUSY_VERIFY_TONE:
+ lsm_tmr_tones_ticks = BUSY_VERIFY_DELAY;
+ break;
+
+ case VCM_CALL_WAITING_TONE:
+ case VCM_CALL_WAITING_2_TONE:
+ case VCM_CALL_WAITING_3_TONE:
+ case VCM_CALL_WAITING_4_TONE:
+ lsm_tmr_tones_ticks = callWaitingDelay;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ lsm_tmr_tones_ticks = callWaitingDelay;
+ }
+}
+
+/**
+ *
+ * Set ringer mode based on remote-cc input and configuration parameters. If there
+ * any other call pending then it should play call waiting tone.
+ *
+ * @param lsm_lcb_t lcb for this call
+ * @param callid_t gsm_id
+ * @param line_t line
+ *
+ * @return none
+ *
+ * @pre (lcb not_eq NULL)
+ */
+static void
+lsm_set_ringer (lsm_lcb_t *lcb, callid_t call_id, line_t line, int alerting)
+{
+ static const char fname[] = "lsm_set_ringer";
+ fsmdef_dcb_t *dcb;
+ boolean ringer_set = FALSE;
+ callid_t other_call_id = CC_NO_CALL_ID;
+ callid_t priority_call_id = CC_NO_CALL_ID;
+ int callHoldRingback = 0;
+ int dcb_cnt = 0;
+ int i = 0;
+ fsmxfr_xcb_t *xcb;
+ fsmcnf_ccb_t *ccb;
+ lsm_lcb_t *lcb2;
+ fsmdef_dcb_t *dcbs[LSM_MAX_CALLS];
+ vcm_ring_mode_t ringerMode = VCM_INSIDE_RING;
+ short ringOnce = NO;
+ boolean alertInfo = NO;
+ vcm_tones_t toneMode = VCM_CALL_WAITING_TONE;
+ fsmdef_media_t *media;
+ boolean isDusting = FSM_CHK_FLAGS(lcb->flags, LSM_FLAGS_DUSTING) ? TRUE : FALSE;
+ int sdpmode = 0;
+
+
+ LSM_DEBUG(DEB_L_C_F_PREFIX"Entered, state=%d.\n",
+ DEB_L_C_F_PREFIX_ARGS(LSM, line, call_id, fname), lcb->state);
+
+ config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
+
+ /*
+ * The ringer (or call-waiting tone) should be on if these
+ * conditions are met:
+ * 1. A line is ringing for an incoming call and no calls
+ * with a pending answer
+ * 2. A line is on hold
+ * and
+ * 3. No lines are connected
+ *
+ * Otherwise, turn on the call-waiting tones.
+ *
+ */
+
+ if (priority_call_id == CC_NO_CALL_ID) {
+ /* get the call_id of the line that triggers this if it is ringing and
+ pass down the correct line variable and its ring type and let the ring
+ manager decides. Originally we only find line first line in ringing state
+ which results in issue where Flash only line follows by audio ring line
+ ringing simultaneously, the phone does not ring audibly.
+ */
+ if (lcb->state == LSM_S_RINGIN) {
+ other_call_id = call_id;
+ } else {
+ other_call_id = lsm_find_state(LSM_S_RINGIN);
+ }
+ }
+
+ if (((priority_call_id != CC_NO_CALL_ID) || (other_call_id != CC_NO_CALL_ID)) &&
+ (lsm_answer_pending() == CC_NO_CALL_ID)) {
+ /*sam
+ * may need to add (ringout and rtp open) to this check.
+ * It is possible that inband alerting is active for an outgoing call.
+ */
+ dcb = fsmdef_get_dcb_by_call_id((priority_call_id != CC_NO_CALL_ID) ?
+ priority_call_id : other_call_id);
+ lcb = lsm_get_lcb_by_call_id((priority_call_id != CC_NO_CALL_ID) ?
+ priority_call_id : other_call_id);
+ isDusting = ((lcb != NULL) && FSM_CHK_FLAGS(lcb->flags, LSM_FLAGS_DUSTING)) ? TRUE : FALSE;
+
+ /*
+ * TNP has line-based ringing so update the line parameter so
+ * if reflects what line is ringing, not which line had an action
+ * taken against it, i.e. if line 1 hangs up and line 2 is ringing,
+ * line will be equal to 1 (since that line hung-up), but it needs
+ * to be 2 since that is the line actually ringing. 40/60 can
+ * get away with this since it is device-based ringing. If there
+ * are multiple lines in the RINGIN state, the ringing will be
+ * based on the first line in the RINGIN state found. Could add
+ * the check if (other_call_id != callid) but line will equal
+ * dcb->line if the callids are the same so save a few CPU cycles
+ * by not having the check. No need to do a #ifdef TNP since
+ * it does matter which line we use on the 40/60 as it is device based.
+ */
+ line = dcb->line;
+
+ if (!lsm_callwaiting()) {
+
+ LSM_DEBUG(DEB_L_C_F_PREFIX"No call waiting, lcb->line=%d, lcb->flag=%d.\n",
+ DEB_L_C_F_PREFIX_ARGS(LSM, line, lcb->call_id, fname),
+ lcb->line,
+ lcb->flags);
+
+ ringer_set = TRUE;
+ lsm_tmr_tones_ticks = 0;
+
+ /*
+ * CFGID_LINE_RING_SETTING_IDLE is a config parameter that
+ * tells the phone what action to take for an incoming
+ * call on a phone with no active calls.
+ *
+ */
+
+ if (isDusting) {
+ ringSettingIdle = FLASH_ONLY;
+ }
+ else if (FSM_CHK_FLAGS(lcb->flags, LSM_FLAGS_PREVENT_RINGING)) {
+ /*
+ * If this phone is both calling and called device, do not play ring.
+ */
+ ringSettingIdle = DISABLE;
+ } else if (cc_line_ringer_mode[line] == CC_RING_DISABLE) {
+ /*
+ * Disable - no ring or flash
+ */
+ ringSettingIdle = FLASH_ONLY;
+ } else if (cc_line_ringer_mode[line] == CC_RING_ENABLE) {
+ ringSettingIdle = RING;
+ } else {
+ config_get_line_value(CFGID_LINE_RING_SETTING_IDLE,
+ &ringSettingIdle, sizeof(ringSettingIdle),
+ line);
+ }
+ LSM_DEBUG(DEB_L_C_F_PREFIX"Ring set mode=%d.\n",
+ DEB_L_C_F_PREFIX_ARGS(LSM, line, call_id, fname), ringSettingIdle);
+
+ /*
+ * Disable - no ring or flash
+ */
+ if (ringSettingIdle == DISABLE) {
+ ringerMode = VCM_RING_OFF;
+
+ /*
+ * Flash Only - No ringing, just flash.
+ */
+ } else if (ringSettingIdle == FLASH_ONLY) {
+ ringerMode = VCM_FLASHONLY_RING;
+
+ /*
+ * Ring once - ring the phone once
+ */
+ } else if (ringSettingIdle == RING_ONCE) {
+ ringOnce = YES;
+
+ /*
+ * Ring - normal operation. Ring the phone until answered,
+ * forwarded, or disconnected.
+ */
+ } else if (ringSettingIdle == RING) {
+
+ /* Determine what tone/ringing pattern to play */
+ switch (dcb->alert_info) {
+ case ALERTING_NONE:
+ /* This is the default case nothing to do */
+ break;
+
+ case ALERTING_RING:
+ ringerMode = dcb->alerting_ring;
+ break;
+
+ case ALERTING_OLD:
+ default:
+ alertInfo = YES;
+ }
+ } else if (ringSettingIdle == BEEP_ONLY) {
+ lsm_set_beep_only_settings (dcb, &toneMode);
+
+ }
+ LSM_DEBUG(DEB_L_C_F_PREFIX"Alert info=%d, ringSettingIdle=%d, ringerMode=%d\n",
+ DEB_L_C_F_PREFIX_ARGS(LSM, line, call_id, fname),
+ dcb->alert_info,
+ ringSettingIdle,
+ ringerMode);
+
+ /*
+ * If an active call is being held while there is an incoming
+ * call AND ringSettingBusyStationPolicy is 0, this flag will
+ * be false.
+ */
+ if (alerting) {
+ /*
+ * If the line is connected to a CCM, Bellcore-Dr1 means
+ * play the defined ringer once. Bellcore-dr2 means play
+ * the defined ringer twice.
+ */
+ if (sip_regmgr_get_cc_mode(line) == REG_MODE_CCM) {
+ if (ringerMode == VCM_BELLCORE_DR1) {
+ ringerMode = VCM_INSIDE_RING;
+ } else if (ringerMode == VCM_BELLCORE_DR2) {
+ ringerMode = VCM_OUTSIDE_RING;
+ }
+ }
+ if (ringSettingIdle == BEEP_ONLY) {
+
+ LSM_DEBUG(DEB_L_C_F_PREFIX"Idle phone RING SETTING: Beep_only\n",
+ DEB_L_C_F_PREFIX_ARGS(LSM, line, call_id, fname));
+
+ media = gsmsdp_find_audio_media(lcb->dcb);
+ lsm_util_tone_start_with_speaker_as_backup(toneMode, NO, lsm_get_ms_ui_call_handle(line, call_id, CC_NO_CALL_ID),
+ lcb->dcb->group_id,
+ ((media != NULL) ? media->refid : CC_NO_MEDIA_REF_ID),
+ VCM_PLAY_TONE_TO_EAR);
+ } else {
+ LSM_DEBUG(DEB_L_C_F_PREFIX"Idle phone RING SETTING: ringer Mode = %s,"
+ " Ring once = %d, alertInfo = %d\n",
+ DEB_L_C_F_PREFIX_ARGS(LSM, line, call_id, fname),
+ vm_alert_names[ringerMode], ringOnce, alertInfo);
+
+ vcmControlRinger(ringerMode, ringOnce, alertInfo, line, lcb->ui_id);
+ }
+ }
+
+ if ( lcb->state != LSM_S_HOLDING &&
+ lcb->state != LSM_S_RINGIN ) {
+ ui_set_call_status(platform_get_phrase_index_str(CALL_ALERTING),
+ line, lcb->ui_id);
+ }
+ } else {
+
+ // Ring off all lines.
+ FSM_FOR_ALL_CBS(lcb2, lsm_lcbs, LSM_MAX_LCBS) {
+ if ((lcb2->call_id != CC_NO_CALL_ID) &&
+ (lcb2->state == LSM_S_RINGIN) )
+ {
+ LSM_DEBUG(DEB_L_C_F_PREFIX"Call waiting RING SETTING: "
+ "ringer Mode = RING_OFF, Ring once = NO, alertInfo = NO\n",
+ DEB_L_C_F_PREFIX_ARGS(LSM, lcb2->line, lcb2->call_id, fname));
+ vcmControlRinger(VCM_RING_OFF, NO, NO, lcb2->line, call_id);
+ }
+ }
+ ringer_set = TRUE;
+ lsm_tmr_tones_ticks = 0;
+
+ /*
+ * ringSettingActive is a TNP only config parameter that
+ * tells the phone what action to take for an incoming
+ * call on a phone with an active call.
+ */
+ if (isDusting) {
+ ringSettingActive = FLASH_ONLY;
+ } else {
+ config_get_line_value(CFGID_LINE_RING_SETTING_ACTIVE,
+ &ringSettingActive, sizeof(ringSettingActive),
+ line);
+ }
+
+ /*
+ * Disable - no ring or flash
+ */
+ if (ringSettingActive == DISABLE) {
+ ringerMode = VCM_RING_OFF;
+
+ /*
+ * Flash Only - No ringing, just flash.
+ */
+ } else if (ringSettingActive == FLASH_ONLY) {
+ ringerMode = VCM_FLASHONLY_RING;
+
+ /*
+ * Ring once - ring the phone once
+ */
+ } else if (ringSettingActive == RING_ONCE) {
+ ringOnce = YES;
+
+ /*
+ * Ring - Ring the phone until answered, forwarded or
+ * disconnected.
+ *
+ * NOTE: This code is replicated above under checking
+ * RING_SETTING_IDLE above. Putting this common code
+ * in a function call saved a miniscule amount of memory
+ * at the cost of an additional function call for every
+ * call. It was decided it was not worth the cost, but
+ * has been documented in case the phone gets very,
+ * very low on memory in the future.
+ */
+ } else if (ringSettingActive == RING) {
+
+ /* Determine what tone/ringing pattern to play */
+ switch (dcb->alert_info) {
+ case ALERTING_NONE:
+ /* This is the default case nothing to do */
+ break;
+
+ case ALERTING_RING:
+ ringerMode = dcb->alerting_ring;
+ break;
+
+ case ALERTING_OLD:
+ default:
+ alertInfo = YES;
+ }
+
+ /*
+ * BeepOnly - normal operation. Play call waiting tone.
+ */
+ } else if (ringSettingActive == BEEP_ONLY) {
+ lsm_set_beep_only_settings (dcb, &toneMode);
+
+ }
+
+ /*
+ * If an active call is being held while there is an incoming
+ * call AND ringSettingBusyStationPolicy is 0, this flag will
+ * be false.
+ */
+ if (alerting) {
+ /*
+ * The code above has set the variables to play either the ringer
+ * or a tone based on the ringSettingBusy. If the config variable
+ * is beeponly then call start_tone else call control_ringer.
+ */
+ if (ringSettingActive == BEEP_ONLY) {
+ media = gsmsdp_find_audio_media(dcb);
+
+ lsm_util_start_tone(toneMode, NO, lsm_get_ms_ui_call_handle(line, call_id, CC_NO_CALL_ID), dcb->group_id,
+ ((media != NULL) ? media->refid : CC_NO_MEDIA_REF_ID),
+ VCM_PLAY_TONE_TO_EAR);
+ } else {
+
+ LSM_DEBUG(DEB_L_C_F_PREFIX"Active call RING SETTING: "
+ "ringer Mode = %s, Ring once = %d, alertInfo = %d\n",
+ DEB_L_C_F_PREFIX_ARGS(LSM, line, call_id, fname),
+ vm_alert_names[ringerMode], ringOnce, alertInfo);
+
+ vcmControlRinger(ringerMode, ringOnce, alertInfo, line, lcb->ui_id);
+ }
+ }
+
+ /*
+ * Start a timer to play multiple part tones if needed.
+ */
+ if (lsm_tmr_tones_ticks > 0) {
+ if (cprCancelTimer(lsm_tmr_tones) == CPR_FAILURE) {
+ LSM_DEBUG(get_debug_string(DEBUG_GENERAL_SYSTEMCALL_FAILED),
+ fname, "cprCancelTimer", cpr_errno);
+ }
+ if (cprStartTimer(lsm_tmr_tones, lsm_tmr_tones_ticks,
+ (void *)(long)dcb->call_id) == CPR_FAILURE) {
+ LSM_DEBUG(get_debug_string(DEBUG_GENERAL_SYSTEMCALL_FAILED),
+ fname, "cprStartTimer", cpr_errno);
+ }
+ }
+ }
+ } else if (lcb->state == LSM_S_IDLE) {
+ /*
+ * This line just hungup so let's check to see if call hold ringback
+ * is enabled and if we have any other holding lines. If so ring to
+ * alert the user that a line is still around.
+ */
+ config_get_value(CFGID_CALL_HOLD_RINGBACK, &callHoldRingback,
+ sizeof(callHoldRingback));
+ if (callHoldRingback & 0x1) {
+ callid_t ui_id;
+
+ dcb_cnt = fsmdef_get_dcbs_in_held_state(dcbs, call_id);
+ for (i = 0, dcb = dcbs[i]; i < dcb_cnt; i++, dcb = dcbs[i]) {
+ ccb = fsmcnf_get_ccb_by_call_id(call_id);
+ xcb = fsmxfr_get_xcb_by_call_id(call_id);
+ if ((lsm_is_phone_inactive() == TRUE) &&
+ (ccb == NULL) && (xcb == NULL) &&
+ (lcb->enable_ringback == TRUE)) {
+ LSM_DEBUG(DEB_L_C_F_PREFIX"Applying ringback\n",
+ DEB_L_C_F_PREFIX_ARGS(LSM, lcb->line, lcb->call_id, fname));
+ ringer_set = TRUE;
+
+ LSM_DEBUG(DEB_L_C_F_PREFIX"Hold RINGBACK SETTING: ringer Mode = "
+ "VCM_INSIDE_RING, Ring once = YES, alertInfo = YES\n",
+ DEB_L_C_F_PREFIX_ARGS(LSM, line, dcb->call_id, fname));
+ vcmControlRinger(VCM_INSIDE_RING, YES, YES, line, call_id);
+
+ /* Find the corresponding LCB to get to the UI ID */
+ ui_id = lsm_get_ui_id(dcb->call_id);
+ ui_set_call_status(platform_get_phrase_index_str(CALL_INITIATE_HOLD),
+ dcb->line, ui_id);
+ }
+ }
+ }
+ }
+
+ if (ringer_set == FALSE) {
+
+ LSM_DEBUG(DEB_L_C_F_PREFIX"Ringer_set = False : "
+ "ringer Mode = VCM_RING_OFF, Ring once = NO, alertInfo = NO\n",
+ DEB_L_C_F_PREFIX_ARGS(LSM, line, call_id, fname));
+
+
+ if (!sdpmode) {
+ vcmControlRinger(VCM_RING_OFF, NO, NO, line, call_id);
+ }
+
+ }
+}
+
+static cc_rcs_t
+lsm_offhook (lsm_lcb_t *lcb, cc_state_data_offhook_t *data)
+{
+ callid_t call_id = lcb->call_id;
+ line_t line = lcb->line;
+ fsmxfr_xcb_t *xcb;
+ lsm_lcb_t *lcb2;
+ callid_t call_id2;
+ int attr;
+ fsmdef_dcb_t *dcb;
+
+ dcb = lcb->dcb;
+ if (dcb == NULL) {
+ return (CC_RC_ERROR);
+ }
+
+ lsm_change_state(lcb, __LINE__, LSM_S_OFFHOOK);
+
+ /*
+ * Disable the ringer since the user is going offhook. Only calls
+ * in the RINGIN state should have ringing enabled.
+ */
+ FSM_FOR_ALL_CBS(lcb2, lsm_lcbs, LSM_MAX_LCBS) {
+ if ((lcb2->call_id != CC_NO_CALL_ID) &&
+ (lcb2->state == LSM_S_RINGIN)) {
+
+ vcmControlRinger(VCM_RING_OFF, NO, NO, lcb2->line, lcb2->call_id);
+ }
+ }
+
+ dp_offhook(line, call_id);
+
+ attr = fsmutil_get_call_attr(dcb, line, call_id);
+
+ ui_new_call(evOffHook, line, lcb->ui_id, attr,
+ dcb->caller_id.call_instance_id,
+ (boolean)FSM_CHK_FLAGS(lcb->flags, LSM_FLAGS_DIALED_STRING));
+
+ xcb = fsmxfr_get_xcb_by_call_id(call_id);
+ if (xcb != NULL) {
+ call_id2 = ((lcb->call_id == xcb->xfr_call_id) ?
+ (xcb->cns_call_id) : (xcb->xfr_call_id));
+ lcb2 = lsm_get_lcb_by_call_id(call_id2);
+ }
+
+ //vcmActivateWlan(TRUE);
+
+ vcmEnableSidetone(YES);
+
+ return (CC_RC_SUCCESS);
+}
+
+
+static cc_rcs_t
+lsm_dialing (lsm_lcb_t *lcb, cc_state_data_dialing_t *data)
+{
+ fsmxfr_xcb_t *xcb = NULL;
+ int stutterMsgWaiting = 0;
+ fsmdef_dcb_t *dcb = lcb->dcb;
+ fsmdef_media_t *media = gsmsdp_find_audio_media(dcb);
+
+
+ if ( dcb == NULL) {
+ return (CC_RC_ERROR);
+ }
+
+ /* don't provide dial tone on transfer unless we are the transferor. */
+ xcb = fsmxfr_get_xcb_by_call_id(lcb->call_id);
+ if ((xcb != NULL) && (xcb->mode != FSMXFR_MODE_TRANSFEROR)) {
+ return (CC_RC_SUCCESS);
+ }
+
+ /*
+ * Start dial tone if no digits have been entered
+ */
+ if ((data->play_dt == TRUE)
+ && (dp_check_for_plar_line(lcb->line) == FALSE)
+ ) {
+
+ /* get line based AMWI config */
+ config_get_value(CFGID_LINE_MESSAGE_WAITING_AMWI + lcb->line - 1, &stutterMsgWaiting,
+ sizeof(stutterMsgWaiting));
+ if ( stutterMsgWaiting != 1 && stutterMsgWaiting != 0) {
+ /* AMWI is not configured. Fallback on config for stutter dial tone */
+ config_get_value(CFGID_STUTTER_MSG_WAITING, &stutterMsgWaiting,
+ sizeof(stutterMsgWaiting));
+ stutterMsgWaiting &= 0x1; /* LSB indicates on/off */
+ }
+
+ if ( (data->suppress_stutter == FALSE) &&
+ (ui_line_has_mwi_active(lcb->line)) && /* has msgs waiting */
+ stutterMsgWaiting ) {
+ lsm_util_start_tone(VCM_STUTTER_TONE, FALSE, lsm_get_ms_ui_call_handle(lcb->line, CC_NO_CALL_ID, lcb->ui_id),
+ dcb->group_id,
+ ((media != NULL) ? media->refid : CC_NO_MEDIA_REF_ID),
+ VCM_PLAY_TONE_TO_EAR);
+ } else {
+ lsm_util_start_tone(VCM_INSIDE_DIAL_TONE, FALSE, lsm_get_ms_ui_call_handle(lcb->line, CC_NO_CALL_ID, lcb->ui_id),
+ dcb->group_id,
+ ((media != NULL) ? media->refid : CC_NO_MEDIA_REF_ID),
+ VCM_PLAY_TONE_TO_EAR);
+ }
+ }
+
+ /*
+ * For round table phone, post WAITINGFORDIGITS event,
+ * so that UI can pop up dialing screen.
+ * For TNP, this event gets ignored.
+ */
+ ui_call_state(evWaitingForDigits, lcb->line, lcb->ui_id, CC_CAUSE_NORMAL);
+
+
+ return (CC_RC_SUCCESS);
+}
+
+
+static cc_rcs_t
+lsm_dialing_completed (lsm_lcb_t *lcb, cc_state_data_dialing_completed_t *data)
+{
+ line_t line = lcb->line;
+ fsmdef_dcb_t *dcb = lcb->dcb;
+
+ if (dcb == NULL) {
+ return (CC_RC_ERROR);
+ }
+
+ lsm_change_state(lcb, __LINE__, LSM_S_PROCEED);
+
+ /* If KPML is enabled then do not change UI state to
+ * proceed, more digit to collect
+ */
+ if (dp_get_kpml_state()) {
+ return (CC_RC_SUCCESS);
+ }
+
+ ui_call_info(data->caller_id.calling_name,
+ data->caller_id.calling_number,
+ data->caller_id.alt_calling_number,
+ data->caller_id.display_calling_number,
+ data->caller_id.called_name,
+ data->caller_id.called_number,
+ data->caller_id.display_called_number,
+ data->caller_id.orig_called_name,
+ data->caller_id.orig_called_number,
+ data->caller_id.last_redirect_name,
+ data->caller_id.last_redirect_number,
+ (calltype_t)dcb->call_type,
+ line, lcb->ui_id,
+ dcb->caller_id.call_instance_id,
+ FSM_GET_SECURITY_STATUS(dcb),
+ FSM_GET_POLICY(dcb));
+
+ lsm_ui_call_state(evProceed, line, lcb, CC_CAUSE_NORMAL);
+
+ (void) lsm_stop_tone(lcb, NULL);
+
+ return (CC_RC_SUCCESS);
+}
+
+
+static cc_rcs_t
+lsm_call_sent (lsm_lcb_t *lcb, cc_state_data_call_sent_t *data)
+{
+ line_t line = lcb->line;
+ fsmdef_dcb_t *dcb;
+ char tmp_str[STATUS_LINE_MAX_LEN];
+ fsmdef_media_t *media;
+ static const char fname[] = "lsm_call_sent";
+
+ dcb = lcb->dcb;
+ if (dcb == NULL) {
+ return (CC_RC_ERROR);
+ }
+
+ lsm_change_state(lcb, __LINE__, LSM_S_PROCEED);
+
+ (void) lsm_stop_tone(lcb, NULL);
+
+ /*
+ * We go ahead and start a rx port if our local SDP indicates
+ * the need in an attempt to be 3264 compliant. Since we have
+ * not yet locked down the codec, we will use preferred codec if
+ * configured. If not, we use the first codec in our local
+ * list of supported codecs. The codec list was initialized
+ * in fsmdef_init_local_sdp.
+ */
+ GSMSDP_FOR_ALL_MEDIA(media, dcb) {
+ if (!GSMSDP_MEDIA_ENABLED(media)) {
+ continue;
+ }
+ LSM_DEBUG(DEB_F_PREFIX"%d %d %d\n", DEB_F_PREFIX_ARGS(LSM, fname), media->direction_set,
+ media->direction, media->is_multicast);
+ if ((media->direction_set) &&
+ ((media->direction == SDP_DIRECTION_SENDRECV) ||
+ (media->direction == SDP_DIRECTION_RECVONLY))) {
+
+ lsm_rx_start(lcb, cc_state_name(CC_STATE_FAR_END_ALERTING),
+ media);
+ }
+ }
+
+ if (!dp_get_kpml_state()) {
+ if ((platGetPhraseText(STR_INDEX_CALLING,
+ (char *) tmp_str,
+ STATUS_LINE_MAX_LEN - 1)) == CPR_SUCCESS) {
+ ui_set_call_status(tmp_str, line, lcb->ui_id);
+ }
+ }
+
+ /*
+ * cancel offhook to first digit timer.
+ */
+ dp_int_cancel_offhook_timer(line, lcb->call_id);
+
+ return (CC_RC_SUCCESS);
+}
+
+
+static cc_rcs_t
+lsm_far_end_proceeding (lsm_lcb_t *lcb,
+ cc_state_data_far_end_proceeding_t * data)
+{
+ line_t line = lcb->line;
+ fsmdef_dcb_t *dcb;
+
+ lsm_change_state(lcb, __LINE__, LSM_S_PROCEED);
+
+ if (!dp_get_kpml_state()) {
+ ui_set_call_status(platform_get_phrase_index_str(CALL_PROCEEDING_IN),
+ line, lcb->ui_id);
+ /*
+ * update placed call info in call history with dialed digits
+ */
+ dcb = lcb->dcb;
+ if (dcb != NULL && dcb->placed_call_update_required) {
+ lsm_update_placed_callinfo(dcb);
+ dcb->placed_call_update_required = FALSE;
+ }
+ }
+
+
+ return (CC_RC_SUCCESS);
+}
+
+
+static cc_rcs_t
+lsm_far_end_alerting (lsm_lcb_t *lcb, cc_state_data_far_end_alerting_t *data)
+{
+ static const char fname[] = "lsm_far_end_alerting";
+ callid_t call_id = lcb->call_id;
+ line_t line = lcb->line;
+ fsmdef_dcb_t *dcb;
+ const char *status = NULL;
+ fsmcnf_ccb_t *ccb;
+ boolean rcv_port_started = FALSE;
+ char tmp_str[STATUS_LINE_MAX_LEN];
+ boolean spoof_ringout;
+ fsmdef_media_t *media;
+ call_events call_state;
+ fsmdef_media_t *audio_media;
+ boolean is_session_progress = FALSE;
+
+
+ /*
+ * Need to check if rcv_chan is already open and if we will be
+ * receiving inband ringing. The recv_chan should always be
+ * open since we always open a receive channel when initiating a
+ * call. If inband ringing will be sent by the far end, we
+ * will close the receive port and reopen it using the codec
+ * negotiated when we received the SDP in the far ends call
+ * proceeding message. We want to close the receive port well
+ * ahead of reopening it due to some issue in the dsp where
+ * a close followed immediately by an open causes a reset of
+ * the DSP.
+ */
+ dcb = lcb->dcb;
+ if (dcb == NULL) {
+ return (CC_RC_ERROR);
+ }
+ audio_media = gsmsdp_find_audio_media(dcb);
+
+ if (dcb->inband) {
+ /* close (with refresh) all media entries */
+ lsm_close_rx(lcb, TRUE, NULL);
+ lsm_close_tx(lcb, TRUE, NULL);
+ }
+
+ /*
+ * Check to see if we need to spoof ring out in connected or holding
+ * state.
+ *
+ * The LSM can be in holding state when the user is resuming
+ * currently held call that was early transferred to another party
+ * and the other party has not answered the call yet.
+ */
+ if (dcb->spoof_ringout_requested &&
+ ((lcb->state == LSM_S_CONNECTED) || (lcb->state == LSM_S_HOLDING))) {
+ /* Spoof ring out is requested in the connected/holding state */
+ spoof_ringout = TRUE;
+ } else {
+ spoof_ringout = FALSE;
+ }
+ lsm_change_state(lcb, __LINE__, LSM_S_RINGOUT);
+
+ /* Don't send the dialplan update msg if CFWD_ALL. Otherwise the invalid
+ * redial numer is saved. (CSCsv08816)
+ */
+ if (dcb->active_feature != CC_FEATURE_CFWD_ALL) {
+ dp_int_update(line, call_id, data->caller_id.called_number);
+ }
+
+
+ /*
+ * Check for inband alerting or spoof ringout.
+ * If no inband alerting and this is not a spoof ringout case,
+ * just update the status line to show we are alerting. The local
+ * ringback tone will not be started until the ringback delay timer
+ * expires.
+ */
+ if (dcb->inband != TRUE || spoof_ringout) {
+ status = platform_get_phrase_index_str(CALL_ALERTING_LOCAL);
+
+ if (spoof_ringout) {
+
+ if (audio_media) {
+
+ /*
+ * Ringback delay timer is not used for spoof ringout case
+ * so start local ringback tone now.
+ */
+ lsm_util_start_tone(VCM_ALERTING_TONE, FALSE, lsm_get_ms_ui_call_handle(line, call_id, CC_NO_CALL_ID),
+ dcb->group_id,audio_media->refid,
+ VCM_PLAY_TONE_TO_EAR);
+ }
+
+ }
+ } else {
+ is_session_progress = TRUE;
+ (void) lsm_stop_tone(lcb, NULL);
+
+ if ((platGetPhraseText(STR_INDEX_SESSION_PROGRESS,
+ (char *) tmp_str,
+ STATUS_LINE_MAX_LEN - 1)) == CPR_SUCCESS) {
+ status = tmp_str;
+ }
+
+ /* start receive and transmit for all media entries that are active */
+ GSMSDP_FOR_ALL_MEDIA(media, dcb) {
+ if (!GSMSDP_MEDIA_ENABLED(media)) {
+ /* this entry is not active */
+ continue;
+ }
+ LSM_DEBUG(DEB_L_C_F_PREFIX"direction_set:%d direction:%d"
+ " dest_addr:0x%x is_multicast:%d\n",
+ DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, dcb->call_id, fname),
+ media->direction_set,
+ media->direction, media->dest_addr,
+ media->is_multicast);
+
+ if (media->direction_set) {
+ if (media->direction == SDP_DIRECTION_SENDRECV ||
+ media->direction == SDP_DIRECTION_RECVONLY) {
+ lsm_rx_start(lcb,
+ cc_state_name(CC_STATE_FAR_END_ALERTING),
+ media);
+ rcv_port_started = TRUE;
+ }
+
+ if (media->direction == SDP_DIRECTION_SENDRECV ||
+ media->direction == SDP_DIRECTION_SENDONLY) {
+ lsm_tx_start(lcb,
+ cc_state_name(CC_STATE_FAR_END_ALERTING),
+ media);
+ }
+ }
+ }
+
+ if (!rcv_port_started) {
+ /*
+ * Since we had SDP we thought inband ringback was in order but
+ * media attributes indicate the receive port is to remain
+ * closed. In this case, go ahead and apply local ringback tone
+ * or user will hear silence. We do not depend on ringback delay
+ * timer to start the local ringback tone so we have to start it
+ * here.
+ */
+ status = platform_get_phrase_index_str(CALL_ALERTING_LOCAL);
+ lsm_util_start_tone(VCM_ALERTING_TONE, FALSE, lsm_get_ms_ui_call_handle(line, call_id, CC_NO_CALL_ID), dcb->group_id,
+ ((audio_media != NULL) ? audio_media->refid :
+ CC_NO_MEDIA_REF_ID),
+ VCM_PLAY_TONE_TO_EAR);
+ } else {
+ lsm_set_ringer(lcb, call_id, line, YES);
+ }
+ }
+
+ ccb = fsmcnf_get_ccb_by_call_id(call_id);
+
+ /* Update call information */
+ lsm_internal_update_call_info(lcb, dcb);
+
+ /* This is the case where remote end of the call has been early trasnfered
+ * to another endpoint.
+ */
+
+ ccb = fsmcnf_get_ccb_by_call_id(lcb->call_id);
+
+ if ((ccb != NULL) && (ccb->active == TRUE) &&
+ (ccb->flags & LCL_CNF)) {
+ call_state = evConference;
+ } else {
+ call_state = evRingOut;
+ }
+
+ /* If an invalid DN is dialed during CFA then CCM sends 183/Session Progress
+ * (a.k.a. far end alerting) so it can play the invalid DN announcement. In
+ * this case CCM sends 404 Not Found after playing the announcement. If we
+ * are here due to that situation then don't propagate call info or status
+ * to UI side as it will display "Session Progress" on the status line and
+ * will log the DN in Placed calls; and we don't want either. Just skip the
+ * update and following 404 Not Found will take care of playing/displaying
+ * Reorder. Note that this condition may occur only in TNP/CCM mode.
+ */
+ if (dcb->active_feature != CC_FEATURE_CFWD_ALL) {
+ if(!is_session_progress) {//CSCtc18750
+ /*
+ * update placed call info in call history with dialed digits
+ */
+ if (dcb->placed_call_update_required) {
+ lsm_update_placed_callinfo(dcb);
+ dcb->placed_call_update_required = FALSE;
+ }
+
+ if (status) {
+ ui_set_call_status(status, line, lcb->ui_id);
+ }
+ }
+
+ lsm_ui_call_state(call_state, line, lcb, CC_CAUSE_NORMAL);
+
+ }
+ /* For roundtable phones, UI will be in dial state, which is different from TNP UI,
+ * TNP UI does not have different dialing layer. In this case offhook dialing screen
+ * does not vanish untill GSM provides procced call status, hence all the softkeys are
+ * available during CFWD, which is not correct
+ */
+ if (dcb->active_feature == CC_FEATURE_CFWD_ALL) {
+ lsm_ui_call_state(evReorder, line, lcb, CC_CAUSE_NORMAL);
+ }
+
+ return (CC_RC_SUCCESS);
+}
+
+
+static cc_rcs_t
+lsm_call_received (lsm_lcb_t *lcb, cc_state_data_call_received_t *data)
+{
+ return (CC_RC_SUCCESS);
+}
+
+
+static cc_rcs_t
+lsm_alerting (lsm_lcb_t *lcb, cc_state_data_alerting_t *data)
+{
+ callid_t call_id = lcb->call_id;
+ line_t line = lcb->line;
+ fsmdef_dcb_t *dcb;
+
+ dcb = lcb->dcb;
+ if (dcb == NULL) {
+ return (CC_RC_ERROR);
+ }
+
+ lsm_change_state(lcb, __LINE__, LSM_S_RINGIN);
+
+ dcb->ui_update_required = TRUE;
+ lsm_internal_update_call_info(lcb, dcb);
+
+ ui_new_call(evRingIn, line, lcb->ui_id, NORMAL_CALL,
+ dcb->caller_id.call_instance_id, FALSE);
+
+ fsmutil_set_shown_calls_ci_element(dcb->caller_id.call_instance_id, line);
+ lsm_ui_call_state(evRingIn, line, lcb, CC_CAUSE_NORMAL);
+ lsm_update_inalert_status(line, lcb->ui_id, data, TRUE);
+
+
+ lsm_set_ringer(lcb, call_id, line, YES);
+
+ return (CC_RC_SUCCESS);
+}
+
+
+static cc_rcs_t
+lsm_answered (lsm_lcb_t *lcb, cc_state_data_answered_t *data)
+{
+ line_t line = lcb->line;
+ fsmdef_dcb_t *dcb;
+
+ dcb = lcb->dcb;
+ if (dcb == NULL) {
+ return (CC_RC_ERROR);
+ }
+
+ lsm_change_state(lcb, __LINE__, LSM_S_OFFHOOK);
+
+
+ lsm_internal_update_call_info(lcb, dcb);
+
+ vcmControlRinger(VCM_RING_OFF, NO, NO, line, dcb->call_id);
+
+ lsm_ui_call_state(evOffHook, line, lcb, CC_CAUSE_NORMAL);
+
+ //vcmActivateWlan(TRUE);
+
+ (void) lsm_stop_tone(lcb, NULL);
+
+ return (CC_RC_SUCCESS);
+}
+
+/**
+ *
+ * Function updates media paths based on the negotated parameters.
+ *
+ * @param lcb line control block
+ * @param caller_fname caller function name
+ *
+ * @return none
+ *
+ * @pre (dcb not_eq NULL)
+ * @pre (fname not_eq NULL)
+ */
+static void
+lsm_update_media (lsm_lcb_t *lcb, const char *caller_fname)
+{
+ static const char fname[] = "lsm_update_media";
+ fsmdef_dcb_t *dcb;
+ fsmdef_media_t *media;
+ boolean rx_refresh;
+ boolean tx_refresh;
+ char addr_str[MAX_IPADDR_STR_LEN];
+ int i;
+
+ dcb = lcb->dcb;
+ if (dcb == NULL) {
+ LSM_ERR_MSG(get_debug_string(DEBUG_INPUT_NULL),
+ fname);
+ return;
+ }
+
+ addr_str[0] = '\0';
+
+ /*
+ * Close rx and tx port for media change. Check media direction
+ * to see if port should be closed or remain open. If the port
+ * needs to be kept open, lsm_close_* functions will check to
+ * see if any media attributes have changed. If anything has
+ * changed, the port is closed, otherwise the port remains
+ * open. If media direction is not set, treat as if set to inactive.
+ * Also, if multicast leave rx_refresh and tx_refresh to FALSE to
+ * force a socket close.
+ */
+ GSMSDP_FOR_ALL_MEDIA(media, dcb) {
+ if (!GSMSDP_MEDIA_ENABLED(media) ||
+ FSM_CHK_FLAGS(media->hold, FSM_HOLD_LCL)) {
+ /* this entry is not active or locally held */
+ continue;
+ }
+
+ rx_refresh = FALSE;
+ tx_refresh = FALSE;
+
+ if ((media->direction_set) && (media->is_multicast == FALSE)) {
+ if (media->direction == SDP_DIRECTION_SENDRECV ||
+ media->direction == SDP_DIRECTION_RECVONLY) {
+ rx_refresh = TRUE;
+ }
+ if (media->direction == SDP_DIRECTION_SENDRECV ||
+ media->direction == SDP_DIRECTION_SENDONLY) {
+ tx_refresh = TRUE;
+ }
+ }
+
+ lsm_close_rx(lcb, rx_refresh, media);
+ lsm_close_tx(lcb, tx_refresh, media);
+
+ if (LSMDebug) {
+ /* debug is enabled, format the dest addr into string */
+ ipaddr2dotted(addr_str, &media->dest_addr);
+ for (i = 0; i < media->num_payloads; i++)
+ {
+ LSM_DEBUG(DEB_L_C_F_PREFIX"%d rx, tx refresh's are %d %d"
+ ", dir=%d, payload=%d addr=%s, multicast=%d\n",
+ DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line,
+ dcb->call_id, fname), media->refid, rx_refresh,
+ tx_refresh, media->direction,
+ media->payloads[i], addr_str, media->is_multicast );
+ }
+ }
+ if (rx_refresh ||
+ (media->is_multicast &&
+ media->direction_set &&
+ media->direction == SDP_DIRECTION_RECVONLY)) {
+ lsm_rx_start(lcb, caller_fname, media);
+ }
+ if (tx_refresh) {
+ lsm_tx_start(lcb, caller_fname, media);
+ }
+ if ( rx_refresh &&
+ (media->cap_index == CC_VIDEO_1)) {
+ // force an additional update so UI can refresh the remote view
+ ui_update_video_avail(dcb->line, lcb->ui_id, dcb->cur_video_avail);
+ LSM_DEBUG(DEB_L_C_F_PREFIX"Video Avail Called %d",
+ DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, lcb->ui_id, fname), dcb->cur_video_avail);
+ }
+ }
+}
+
+/**
+ *
+ * Function to set media attributes and set the ui state.
+ *
+ * @param lcb line control block
+ * @param line line
+ * @param fname caller function name
+ *
+ * @return none
+ *
+ * @pre (dcb not_eq NULL)
+ * @pre (fname not_eq NULL)
+ */
+static void
+lsm_call_state_media (lsm_lcb_t *lcb, line_t line, const char *fname)
+{
+ fsmcnf_ccb_t *ccb;
+ fsmdef_dcb_t *dcb;
+ call_events call_state;
+ callid_t call_id = lcb->call_id;
+
+ dcb = lcb->dcb;
+ if (dcb == NULL) {
+ LSM_ERR_MSG(get_debug_string(DEBUG_INPUT_NULL),
+ "lsm_call_state_media");
+ return;
+ }
+
+ ccb = fsmcnf_get_ccb_by_call_id(call_id);
+
+ /* Update media parametes to the platform */
+ lsm_update_media(lcb, fname);
+
+ if ((ccb != NULL) && (ccb->active == TRUE)) {
+ /* For joined call leg, do not change UI state to conf. */
+ if ((ccb->flags & JOINED) ||
+ (fname == cc_state_name(CC_STATE_RESUME))) {
+ call_state = evConnected;
+ } else {
+ call_state = evConference;
+ }
+ } else {
+ call_state = evConnected;
+ }
+
+ /*
+ * Possible media changes, update call information and followed
+ * by the state update. This is important sequence for 7940/60
+ * SIP to force the BTXML update.
+ */
+ // Commenting out original code for CSCsv72370. Leaving here for reference.
+ // lsm_internal_update_call_info(lcb, dcb);
+
+ lsm_ui_call_state(call_state, line, lcb, CC_CAUSE_NORMAL);
+ // CSCsv72370 - Important sequence for TNP this follows state change
+ lsm_internal_update_call_info(lcb, dcb);
+}
+
+
+static cc_rcs_t
+lsm_connected (lsm_lcb_t *lcb, cc_state_data_connected_t *data)
+{
+ callid_t call_id = lcb->call_id;
+ line_t line = lcb->line;
+ fsmdef_dcb_t *dcb;
+ int alerting = YES;
+ call_events original_call_event;
+ int ringSettingBusyStationPolicy;
+ boolean tone_stop_bool = TRUE;
+ int sdpmode = 0;
+ boolean start_ice = FALSE;
+
+ config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
+
+ dcb = lcb->dcb;
+ if (dcb == NULL) {
+ return (CC_RC_ERROR);
+ }
+
+ original_call_event = lcb->previous_call_event;
+ /*
+ * If a held call is being resumed, check the
+ * policy to see if the phone should resume alerting.
+ */
+ if (lcb->state == LSM_S_HOLDING) {
+ config_get_value(CFGID_RING_SETTING_BUSY_POLICY,
+ &ringSettingBusyStationPolicy,
+ sizeof(ringSettingBusyStationPolicy));
+ if (0 == ringSettingBusyStationPolicy) {
+ alerting = NO;
+ }
+
+ /*
+ * CSCtd31671: When agent phone resumes from a held call with
+ * monitor warning tone, the tone should not be stopped.
+ */
+ if(lcb->dcb->active_tone == VCM_MONITORWARNING_TONE || lcb->dcb->active_tone == VCM_RECORDERWARNING_TONE)
+ tone_stop_bool = FALSE;
+ }
+
+ /* Don't try to start ICE unless this is the first time connecting.
+ * TODO(ekr@rtfm.com): Is this the right ICE start logic? What about restarts
+ */
+ if (strlen(dcb->peerconnection) && lcb->state != LSM_S_CONNECTED)
+ start_ice = TRUE;
+
+ lsm_change_state(lcb, __LINE__, LSM_S_CONNECTED);
+
+ if (!sdpmode) {
+ if (tone_stop_bool == TRUE)
+ (void) lsm_stop_tone(lcb, NULL);
+ }
+
+ /* Start ICE */
+ if (start_ice) {
+ short res = vcmStartIceChecks(dcb->peerconnection);
+ /* TODO(emannion): Set state to dead here. */
+ if (res)
+ return CC_RC_SUCCESS;
+ }
+
+ /*
+ * Open the RTP receive channel.
+ */
+ lsm_call_state_media(lcb, line, cc_state_name(CC_STATE_CONNECTED));
+
+
+ if (!sdpmode) {
+ vcmEnableSidetone(YES);
+
+ lsm_set_ringer(lcb, call_id, line, alerting);
+ }
+
+ FSM_RESET_FLAGS(lcb->flags, LSM_FLAGS_ANSWER_PENDING);
+ FSM_RESET_FLAGS(lcb->flags, LSM_FLAGS_DUSTING);
+
+ /*
+ * update placed call info in call history with dialed digits
+ */
+ if (dcb->placed_call_update_required) {
+ lsm_update_placed_callinfo(dcb);
+ dcb->placed_call_update_required = FALSE;
+ }
+
+ /*
+ * If UI state was changed, update status line.
+ */
+ if (lcb->previous_call_event != original_call_event) {
+ if (lcb->previous_call_event == evConference) {
+ } else {
+
+ ui_set_call_status(platform_get_phrase_index_str(CALL_CONNECTED),
+ line, lcb->ui_id);
+ }
+ }
+ ui_update_video_avail(line, lcb->ui_id, dcb->cur_video_avail);
+ return (CC_RC_SUCCESS);
+}
+
+/**
+ * Function: lsm_hold_reversion
+ * Perform Hold Reversion on the given call
+ * any other call pending then it should play call waiting tone.
+ *
+ * @param lsm_lcb_t lcb for this call
+ *
+ * @return cc_rcs_t SUCCESS or FAILURE of the operation
+ *
+ * @pre (lcb not_eq NULL)
+ */
+
+static cc_rcs_t
+lsm_hold_reversion (lsm_lcb_t *lcb)
+{
+ callid_t call_id = lcb->call_id;
+ line_t line = lcb->line;
+
+ // Update call state on the JAVA side
+ lsm_ui_call_state(evHoldRevert, line, lcb, CC_CAUSE_NORMAL);
+
+ if (lsm_find_state(LSM_S_RINGIN) > CC_NO_CALL_ID) {
+ // No Reversion ringing if we have calls in ringing state
+ return CC_RC_SUCCESS;
+ }
+ ui_set_notification(line, call_id,
+ (char *)INDEX_STR_HOLD_REVERSION, CALL_ALERT_TIMEOUT,
+ FALSE, HR_NOTIFY_PRI);
+ lsm_reversion_ringer(lcb, call_id, line);
+
+ return (CC_RC_SUCCESS);
+}
+
+/*
+ * lsm_hold_local
+ *
+ * Move the phone into the Hold state.
+ *
+ * Function is used when the local side initiated the hold.
+ */
+static cc_rcs_t
+lsm_hold_local (lsm_lcb_t *lcb, cc_state_data_hold_t *data)
+{
+ callid_t call_id = lcb->call_id;
+ line_t line = lcb->line;
+ fsmdef_dcb_t *dcb;
+ cc_causes_t cause;
+ int ringSettingBusyStationPolicy;
+
+ dcb = lcb->dcb;
+ if (dcb == NULL) {
+ return (CC_RC_ERROR);
+ }
+
+ /*
+ * Stop ringer if spoofing ringout for CCM
+ */
+ if (dcb->spoof_ringout_applied) {
+ (void) lsm_stop_tone(lcb, NULL);
+ }
+
+ /* hard close receive and transmit channels for all media entries */
+ lsm_close_rx(lcb, FALSE, NULL);
+ lsm_close_tx(lcb, FALSE, NULL);
+ /*
+ * Note that local hold does not have any newer UI information from the
+ * network. Note need to update the call information and the UI will
+ * be collapsed with "blocked" icon to indicate hold.
+ */
+
+ lsm_change_state(lcb, __LINE__, LSM_S_HOLDING);
+ /* Round table phones need cause for the transfer or conference
+ Do not set the cause if the conference or transfer is created by
+ remote-cc
+ */
+ cause = CC_CAUSE_NORMAL;
+ if (data->reason == CC_REASON_XFER) {
+ cause = CC_CAUSE_XFER_LOCAL;
+ } else if (data->reason == CC_REASON_CONF) {
+ cause = CC_CAUSE_CONF;
+ }
+
+ lsm_ui_call_state(evHold, line, lcb, cause);
+
+ ui_set_call_status(platform_get_phrase_index_str(CALL_INITIATE_HOLD),
+ line, lcb->ui_id);
+
+ config_get_value(CFGID_RING_SETTING_BUSY_POLICY,
+ &ringSettingBusyStationPolicy,
+ sizeof(ringSettingBusyStationPolicy));
+ if (ringSettingBusyStationPolicy) {
+ lsm_set_ringer(lcb, call_id, line, YES);
+ } else {
+ /*
+ * If the hold reason is internal this means the phone logic is placing
+ * a call on hold, not the user. Thus don't update the alerting for the
+ * hold state as the user should not hear the alerting pattern change
+ * as they did not place the call on hold. The phone places calls on hold
+ * in cases such as the phone has an active call, another call comes in
+ * for that line and the new call is answered. Therefore the phone places the
+ * active call on hold before answering the incoming call.
+ *
+ */
+ if (data->reason == CC_REASON_INTERNAL) {
+ lsm_set_ringer(lcb, call_id, line, NO);
+ } else {
+ lsm_set_ringer(lcb, call_id, line, YES);
+ }
+ }
+
+ vcmActivateWlan(FALSE);
+
+ return (CC_RC_SUCCESS);
+}
+
+
+/*
+ * lsm_hold_remote
+ *
+ * Move the phone into the Hold state.
+ *
+ * Function is used when the remote side initiated the hold.
+ */
+static cc_rcs_t
+lsm_hold_remote (lsm_lcb_t *lcb, cc_state_data_hold_t *data)
+{
+ static const char fname[] = "lsm_hold_remote";
+ callid_t call_id = lcb->call_id;
+ line_t line = lcb->line;
+ const char *prompt_status;
+ fsmdef_dcb_t *dcb;
+ fsmdef_media_t *media;
+
+ dcb = lcb->dcb;
+ if (dcb == NULL) {
+ return (CC_RC_ERROR);
+ }
+
+ /* close and re-open receive channel for all media entries */
+ GSMSDP_FOR_ALL_MEDIA(media, dcb) {
+ if (!GSMSDP_MEDIA_ENABLED(media)) {
+ /* this entry is not active */
+ continue;
+ }
+ if (media->direction_set &&
+ media->direction == SDP_DIRECTION_INACTIVE) {
+ lsm_close_rx(lcb, FALSE, media);
+ } else {
+ lsm_close_rx(lcb, TRUE, media);
+ }
+
+ /* reopen the receive channel if the direction is RECVONLY */
+ if (media->direction_set &&
+ media->direction == SDP_DIRECTION_RECVONLY) {
+ lsm_rx_start(lcb, fname, media);
+ }
+ /* close tx if media is not inactive or receive only */
+ if ((media->direction == SDP_DIRECTION_INACTIVE) ||
+ (media->direction == SDP_DIRECTION_RECVONLY)) {
+ lsm_close_tx(lcb, FALSE, media);
+ }
+ }
+
+ lsm_internal_update_call_info(lcb, dcb);
+
+ lsm_ui_call_state(evRemHold, line, lcb, CC_CAUSE_NORMAL);
+
+ prompt_status = ((lcb->state == LSM_S_CONNECTED) ?
+ platform_get_phrase_index_str(CALL_CONNECTED) :
+ platform_get_phrase_index_str(CALL_INITIATE_HOLD));
+ ui_set_call_status(prompt_status, line, lcb->ui_id);
+
+ lsm_set_ringer(lcb, call_id, line, YES);
+
+
+ return (CC_RC_SUCCESS);
+}
+
+
+static cc_rcs_t
+lsm_hold (lsm_lcb_t *lcb, cc_state_data_hold_t *data)
+{
+ cc_rcs_t cc_rc;
+
+ if (data == NULL) {
+ return (CC_RC_ERROR);
+ }
+
+ LSM_DEBUG(get_debug_string(LSM_DBG_INT1), lcb->call_id, lcb->line,
+ "lsm_hold", "local", data->local);
+
+ switch (data->local) {
+ case (TRUE):
+ cc_rc = lsm_hold_local(lcb, data);
+ break;
+
+ case (FALSE):
+ cc_rc = lsm_hold_remote(lcb, data);
+ break;
+
+ default:
+ cc_rc = CC_RC_ERROR;
+ break;
+ }
+ vcmEnableSidetone(NO);
+ return (cc_rc);
+}
+
+
+static cc_rcs_t
+lsm_resume_local (lsm_lcb_t *lcb, cc_state_data_resume_t *data)
+{
+ line_t line = lcb->line;
+ fsmdef_dcb_t *dcb;
+
+ lsm_change_state(lcb, __LINE__, LSM_S_HOLDING);
+
+ dcb = lcb->dcb;
+ if (dcb == NULL) {
+ return (CC_RC_ERROR);
+ }
+
+ ui_set_call_status(platform_get_phrase_index_str(CALL_CONNECTED),
+ line, lcb->ui_id);
+
+ return (CC_RC_SUCCESS);
+}
+
+
+static cc_rcs_t
+lsm_resume_remote (lsm_lcb_t *lcb, cc_state_data_resume_t *data)
+{
+ callid_t call_id = lcb->call_id;
+ line_t line = lcb->line;
+ const char *prompt_status;
+
+ if (lcb->dcb == NULL) {
+ return (CC_RC_ERROR);
+ }
+
+ lsm_update_media(lcb, cc_state_name(CC_STATE_RESUME));
+
+ prompt_status = ((lcb->state == LSM_S_CONNECTED) ?
+ platform_get_phrase_index_str(CALL_CONNECTED) :
+ platform_get_phrase_index_str(CALL_INITIATE_HOLD));
+ ui_set_call_status(prompt_status, line, lcb->ui_id);
+
+ lsm_set_ringer(lcb, call_id, line, YES);
+
+ return (CC_RC_SUCCESS);
+}
+
+
+static cc_rcs_t
+lsm_resume (lsm_lcb_t *lcb, cc_state_data_resume_t *data)
+{
+ cc_rcs_t cc_rc;
+
+ if (data == NULL) {
+ return (CC_RC_ERROR);
+ }
+
+ LSM_DEBUG(get_debug_string(LSM_DBG_INT1), lcb->call_id, lcb->line,
+ "lsm_resume", "local", data->local);
+
+ switch (data->local) {
+ case (TRUE):
+ cc_rc = lsm_resume_local(lcb, data);
+ break;
+
+ case (FALSE):
+ cc_rc = lsm_resume_remote(lcb, data);
+ break;
+
+ default:
+ cc_rc = CC_RC_ERROR;
+ break;
+ }
+
+ vcmActivateWlan(TRUE);
+
+ vcmEnableSidetone(YES);
+ return (cc_rc);
+}
+
+
+static cc_rcs_t
+lsm_onhook (lsm_lcb_t *lcb, cc_state_data_onhook_t *data)
+{
+ callid_t call_id = lcb->call_id;
+ line_t line = lcb->line;
+ fsmdef_dcb_t *dcb;
+ cc_causes_t cause;
+ int sdpmode = 0;
+
+ config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
+
+
+ dcb = lcb->dcb;
+ if (dcb == NULL) {
+ return (CC_RC_ERROR);
+ }
+
+ dp_int_onhook(line, call_id);
+
+ /* hard close receive and transmit channels for all media entries */
+ lsm_close_rx(lcb, FALSE, NULL);
+ lsm_close_tx(lcb, FALSE, NULL);
+
+ lsm_change_state(lcb, __LINE__, LSM_S_IDLE);
+
+ if (lsm_is_phone_inactive()) {
+ vcmEnableSidetone(NO);
+ }
+
+ ui_set_call_status(ui_get_idle_prompt_string(), line, lcb->ui_id);
+
+
+ (void) lsm_stop_tone(lcb, NULL);
+
+ if (!sdpmode) {
+ vcmControlRinger(VCM_RING_OFF, NO, NO, line, dcb->call_id);
+ }
+
+ lsm_set_ringer(lcb, call_id, line, YES);
+
+ cause = data->cause;
+ if (FSM_CHK_FLAGS(dcb->flags, FSMDEF_F_XFER_COMPLETE)) {
+ DEF_DEBUG(DEB_F_PREFIX"Transfer complete.\n", DEB_F_PREFIX_ARGS(LSM, "lsm_onhook"));
+ cause = CC_CAUSE_XFER_COMPLETE;
+ }
+ lsm_ui_call_state(evOnHook, line, lcb, cause);
+
+
+ lsm_free_lcb(lcb);
+
+ vcmActivateWlan(FALSE);
+
+ vcmRemoveBandwidth(lsm_get_ms_ui_call_handle(line, call_id, CC_NO_CALL_ID));
+
+ return (CC_RC_SUCCESS);
+}
+
+static cc_rcs_t
+lsm_call_failed (lsm_lcb_t *lcb, cc_state_data_call_failed_t *data)
+{
+ callid_t call_id = lcb->call_id;
+ line_t line = lcb->line;
+ vcm_tones_t tone;
+ lsm_states_t line_state;
+ const char *status = NULL;
+ call_events state;
+ boolean send_call_info = TRUE;
+ fsmdef_dcb_t *dcb;
+ boolean must_log = FALSE;
+
+ dcb = lcb->dcb;
+ if (dcb == NULL) {
+ return (CC_RC_ERROR);
+ }
+
+ /* For busy generated by UI-STATE in 183, do not manipulate the
+ * media port
+ */
+ if (data->cause != CC_CAUSE_UI_STATE_BUSY) {
+ /* hard close receive and transmit channels for all media entries */
+ lsm_close_rx(lcb, FALSE, NULL);
+ lsm_close_tx(lcb, FALSE, NULL);
+ }
+
+ switch (data->cause) {
+ case (CC_CAUSE_BUSY):
+ line_state = LSM_S_BUSY;
+ state = evBusy;
+ tone = VCM_LINE_BUSY_TONE;
+ status = platform_get_phrase_index_str(LINE_BUSY);
+ dp_int_update(line, call_id, data->caller_id.called_number);
+ send_call_info = FALSE;
+ break;
+
+ case (CC_CAUSE_UI_STATE_BUSY):
+ line_state = LSM_S_BUSY;
+ state = evBusy;
+ tone = VCM_LINE_BUSY_TONE;
+ dp_int_update(line, call_id, data->caller_id.called_number);
+ break;
+
+ case (CC_CAUSE_INVALID_NUMBER):
+ line_state = LSM_S_INVALID_NUMBER;
+ state = evReorder;
+ tone = VCM_REORDER_TONE;
+ send_call_info = FALSE;
+ break;
+
+ case (CC_CAUSE_CONGESTION):
+ case (CC_CAUSE_PAYLOAD_MISMATCH):
+ dp_int_update(line, call_id, data->caller_id.called_number);
+
+ /* FALLTHROUGH */
+ /*sa_ignore FALL_THROUGH*/
+ default:
+ send_call_info = FALSE;
+ line_state = LSM_S_CONGESTION;
+ state = evReorder;
+ tone = VCM_REORDER_TONE;
+ if ( (data->cause == CC_CAUSE_NO_USER_ANS)||
+ (data->cause == CC_TEMP_NOT_AVAILABLE) ) {
+ must_log = TRUE;
+ }
+ break;
+ }
+
+ lsm_change_state(lcb, __LINE__, line_state);
+
+ if (status) {
+ ui_set_call_status(status, line, lcb->ui_id);
+ }
+
+ if (state == evReorder && !must_log) {
+ ui_log_disposition(dcb->call_id, CC_CALL_LOG_DISP_IGNORE);
+ }
+
+ /* Send call info only if not error */
+ if (send_call_info == TRUE) {
+ ui_call_info(data->caller_id.calling_name,
+ data->caller_id.calling_number,
+ data->caller_id.alt_calling_number,
+ data->caller_id.display_calling_number,
+ data->caller_id.called_name,
+ data->caller_id.called_number,
+ data->caller_id.display_called_number,
+ data->caller_id.orig_called_name,
+ data->caller_id.orig_called_number,
+ data->caller_id.last_redirect_name,
+ data->caller_id.last_redirect_number,
+ (calltype_t)dcb->call_type,
+ line, lcb->ui_id,
+ dcb->caller_id.call_instance_id,
+ FSM_GET_SECURITY_STATUS(dcb),
+ FSM_GET_POLICY(dcb));
+ }
+
+ lsm_ui_call_state(state, line, lcb, CC_CAUSE_NORMAL);
+
+ /* Tone played in remote-cc play tone request, so don't start tone again
+ */
+ if ((data->cause != CC_CAUSE_UI_STATE_BUSY) && (data->cause != CC_CAUSE_REMOTE_DISCONN_REQ_PLAYTONE)) {
+ fsmdef_media_t *audio_media = gsmsdp_find_audio_media(dcb);
+
+ lsm_util_start_tone(tone, FALSE, lsm_get_ms_ui_call_handle(line, call_id, CC_NO_CALL_ID), dcb->group_id,
+ ((audio_media != NULL) ? audio_media->refid :
+ CC_NO_MEDIA_REF_ID),
+ VCM_PLAY_TONE_TO_EAR);
+ }
+
+ return (CC_RC_SUCCESS);
+}
+
+static void
+lsm_ringer (lsm_lcb_t *lcb, cc_action_data_ringer_t *data)
+{
+ vcm_ring_mode_t ringer;
+ line_t line = lcb->line;
+
+ ringer = (data->on == FALSE) ? (VCM_RING_OFF) : (VCM_FEATURE_RING);
+
+ LSM_DEBUG(DEB_F_PREFIX"CTI RING SETTING: line = %d, ringer Mode = %s,"
+ "Ring once = NO, alertInfo = NO\n", DEB_F_PREFIX_ARGS(LSM, "lsm_ringer"),
+ line, vm_alert_names[ringer]);
+
+ vcmControlRinger(ringer, NO, NO, line, lcb->call_id);
+}
+
+static cc_rcs_t
+lsm_dial_mode (lsm_lcb_t *lcb, cc_action_data_dial_mode_t *data)
+{
+ return (CC_RC_SUCCESS);
+}
+
+
+static cc_rcs_t
+lsm_mwi (lsm_lcb_t *lcb, callid_t call_id, line_t line,
+ cc_action_data_mwi_t *data)
+{
+ ui_set_mwi(line, data->on, data->type, data->newCount, data->oldCount, data->hpNewCount, data->hpOldCount);
+
+ return (CC_RC_SUCCESS);
+}
+
+
+/*
+ * Function: lsm_update_ui
+ *
+ * Parameters:
+ * call_id:
+ * line:
+ * data:
+ *
+ * Description: This function is used to hide the UI platform details from
+ * the FSMs. This function is provided to allow the FSMs
+ * to update the UI in certain cases.
+ *
+ * Returns: rc
+ *
+ */
+cc_rcs_t
+lsm_update_ui (lsm_lcb_t *lcb, cc_action_data_update_ui_t *data)
+{
+ callid_t call_id = lcb->call_id;
+ line_t line = lcb->line;
+ lsm_states_t instance_state;
+ call_events call_state = evMaxEvent;
+ fsmcnf_ccb_t *ccb;
+ fsmdef_dcb_t *dcb;
+ boolean update = FALSE;
+ boolean inbound;
+ cc_feature_data_call_info_t *call_info;
+ call_events original_call_event;
+ lsm_lcb_t *lcb_tmp;
+ const char *conf_str;//[] = {(char)0x80, (char)0x34, (char)0x00};
+
+ instance_state = lcb->state;
+
+ switch (data->action) {
+ case CC_UPDATE_CONF_ACTIVE:
+
+ switch (instance_state) {
+ case LSM_S_RINGOUT:
+ call_state = evRingOut;
+ break;
+
+ case LSM_S_CONNECTED:
+ default:
+ ccb = fsmcnf_get_ccb_by_call_id(call_id);
+ if ((ccb != NULL) && (ccb->active == TRUE)) {
+
+ conf_str = platform_get_phrase_index_str(UI_CONFERENCE);
+ lcb_tmp = lsm_get_lcb_by_call_id(ccb->cnf_call_id);
+ dcb = lcb_tmp->dcb;
+ ui_call_info(CALL_INFO_NONE,
+ CALL_INFO_NONE,
+ CALL_INFO_NONE,
+ 0,
+ conf_str,
+ CALL_INFO_NONE,
+ 0,
+ CALL_INFO_NONE,
+ CALL_INFO_NONE,
+ CALL_INFO_NONE,
+ CALL_INFO_NONE,
+ FSMDEF_CALL_TYPE_OUTGOING,
+ dcb->line, lcb_tmp->ui_id,
+ dcb->caller_id.call_instance_id,
+ FSM_GET_SECURITY_STATUS(dcb),
+ FSM_GET_POLICY(dcb));
+
+ call_state = evConference;
+
+ } else if (instance_state == LSM_S_CONNECTED) {
+
+ call_state = evConnected;
+
+ } else {
+
+ call_state = evRingOut;
+ }
+ break;
+ } /* switch (instance_state) { */
+
+ break;
+
+ case CC_UPDATE_CALLER_INFO:
+
+ /* For local conference, do not update the primary
+ * call bubbles call-info. Primary call is already
+ * displaying To conference in this case
+ * But dcb-> caller_id should be updated to
+ * refresh the UI when the call is dropped
+ */
+ ccb = fsmcnf_get_ccb_by_call_id(call_id);
+ if (ccb && (ccb->flags & LCL_CNF) &&
+ (ccb->cnf_call_id == call_id)) {
+ break;
+ }
+
+ call_info = &data->data.caller_info;
+ dcb = lcb->dcb;
+ if (dcb == NULL || call_info == NULL) {
+ return (CC_RC_ERROR);
+ }
+
+ inbound = dcb->inbound;
+ if (call_info->feature_flag & CC_ORIENTATION) {
+ inbound =
+ (call_info->orientation == CC_ORIENTATION_FROM) ? TRUE : FALSE;
+ update = TRUE;
+ }
+
+ if (call_info->feature_flag & CC_CALLER_ID) {
+ update = TRUE;
+ /*
+ * This "if" block, without the "&& inbound" condition, was put in by Serhad
+ * to fix CSCsm58054 and it results in CSCso98110. The "inbound" condition
+ * is added to narrow the scope of CSCsm58054's fix. Note that "inbound" here
+ * refers to the perceived orientation set in call info. So for example, in case
+ * of a 3-way conf, and phone is the last party to receive the call, is ringing
+ * and then be joined into a conference, direction would be outbound. The display
+ * would say "To Conference".
+ */
+ if ( (instance_state == LSM_S_RINGIN) && inbound ) {
+ cc_state_data_alerting_t alerting_data;
+
+ alerting_data.caller_id = dcb->caller_id;
+ lsm_update_inalert_status(line, lcb->ui_id, &alerting_data, TRUE);
+ }
+ }
+
+ if (call_info->feature_flag & CC_CALL_INSTANCE) {
+ update = TRUE;
+ }
+
+ if (call_info->feature_flag & CC_SECURITY) {
+ update = TRUE;
+ }
+
+ if (call_info->feature_flag & CC_POLICY) {
+ update = TRUE;
+ }
+
+ /*
+ * If we are going to spoof ring out, skip the explicit UI update.
+ * the far end alerting handling will update the UI. Do not
+ * update UI twice.
+ */
+ if (dcb->spoof_ringout_requested &&
+ !dcb->spoof_ringout_applied &&
+ lcb->state == LSM_S_CONNECTED) {
+ cc_state_data_far_end_alerting_t alerting_data;
+
+ alerting_data.caller_id = dcb->caller_id;
+ (void) lsm_far_end_alerting(lcb, &alerting_data);
+ dcb->spoof_ringout_applied = TRUE;
+ } else if (update && dcb->ui_update_required) {
+
+ calltype_t call_type;
+
+ if (dcb->call_type == FSMDEF_CALL_TYPE_FORWARD) {
+ call_type = (inbound) ? (calltype_t)dcb->call_type:FSMDEF_CALL_TYPE_OUTGOING;
+ } else {
+ if (inbound) {
+ call_type = FSMDEF_CALL_TYPE_INCOMING;
+ } else {
+ call_type = FSMDEF_CALL_TYPE_OUTGOING;
+ }
+ }
+
+ ui_call_info(dcb->caller_id.calling_name,
+ dcb->caller_id.calling_number,
+ dcb->caller_id.alt_calling_number,
+ dcb->caller_id.display_calling_number,
+ dcb->caller_id.called_name,
+ dcb->caller_id.called_number,
+ dcb->caller_id.display_called_number,
+ dcb->caller_id.orig_called_name,
+ dcb->caller_id.orig_called_number,
+ dcb->caller_id.last_redirect_name,
+ dcb->caller_id.last_redirect_number,
+ call_type,
+ line,
+ lcb->ui_id,
+ dcb->caller_id.call_instance_id,
+ FSM_GET_SECURITY_STATUS(dcb),
+ FSM_GET_POLICY(dcb));
+
+ dcb->ui_update_required = FALSE;
+
+ conf_str = platform_get_phrase_index_str(UI_CONFERENCE);
+ if(cpr_strncasecmp(dcb->caller_id.called_name, conf_str, strlen(conf_str)) == 0){
+ dcb->is_conf_call = TRUE;
+ } else {
+ dcb->is_conf_call = FALSE;
+ }
+ }
+
+ break;
+
+ case CC_UPDATE_SET_CALL_STATUS:
+ {
+ /* set call status line */
+ cc_set_call_status_data_t *call_status_p =
+ &data->data.set_call_status_parms;
+ ui_set_call_status(call_status_p->phrase_str_p, call_status_p->line,
+ lcb->ui_id);
+ break;
+ }
+ case CC_UPDATE_SET_NOTIFICATION:
+ {
+ /* set status line notification */
+ cc_set_notification_data_t *call_notification_p =
+ &data->data.set_notification_parms;
+ ui_set_notification(line, lcb->ui_id,
+ call_notification_p->phrase_str_p,
+ call_notification_p->timeout, FALSE,
+ (char)call_notification_p->priority);
+ break;
+ }
+ case CC_UPDATE_CLEAR_NOTIFICATION:
+ /* clear status line notification */
+ ui_clear_notification();
+ break;
+
+ case CC_UPDATE_SECURITY_STATUS:
+ /* update security status */
+ break;
+
+ case CC_UPDATE_XFER_PRIMARY:
+ call_state = evConnected;
+ break;
+
+ case CC_UPDATE_CALL_PRESERVATION:
+
+ /* Call is in preservation mode. Update UI so that only endcall softkey is available */
+ ui_call_in_preservation(line, lcb->ui_id);
+ break;
+
+ case CC_UPDATE_CALL_CONNECTED:
+ if (instance_state == LSM_S_CONNECTED) {
+ call_state = evConnected;
+ }
+ break;
+
+ case CC_UPDATE_CONF_RELEASE:
+ dcb = lcb->dcb;
+
+ if (instance_state == LSM_S_CONNECTED) {
+ call_state = evConnected;
+
+ } else if (instance_state == LSM_S_RINGOUT) {
+ call_state = evRingOut;
+ }
+
+ /*
+ * If we are going to spoof ring out, skip the explicit UI update.
+ * the far end alerting handling will update the UI. Do not
+ * update UI twice.
+ */
+ if (dcb->spoof_ringout_requested &&
+ !dcb->spoof_ringout_applied &&
+ lcb->state == LSM_S_CONNECTED) {
+ cc_state_data_far_end_alerting_t alerting_data;
+
+ alerting_data.caller_id = dcb->caller_id;
+ (void) lsm_far_end_alerting(lcb, &alerting_data);
+ dcb->spoof_ringout_applied = TRUE;
+
+ call_state = evRingOut;
+
+ } else {
+ calltype_t call_type;
+ if (dcb->orientation == CC_ORIENTATION_FROM) {
+ call_type = FSMDEF_CALL_TYPE_INCOMING;
+ } else if (dcb->orientation == CC_ORIENTATION_TO) {
+ call_type = FSMDEF_CALL_TYPE_OUTGOING;
+ } else {
+ call_type = (calltype_t)(dcb->call_type);
+ }
+ ui_call_info(dcb->caller_id.calling_name,
+ dcb->caller_id.calling_number,
+ dcb->caller_id.alt_calling_number,
+ dcb->caller_id.display_calling_number,
+ dcb->caller_id.called_name,
+ dcb->caller_id.called_number,
+ dcb->caller_id.display_called_number,
+ dcb->caller_id.orig_called_name,
+ dcb->caller_id.orig_called_number,
+ dcb->caller_id.last_redirect_name,
+ dcb->caller_id.last_redirect_number,
+ call_type,
+ line,
+ lcb->ui_id,
+ dcb->caller_id.call_instance_id,
+ FSM_GET_SECURITY_STATUS(dcb),
+ FSM_GET_POLICY(dcb));
+ }
+
+
+ break;
+
+ default:
+ break;
+ }
+
+ if (call_state != evMaxEvent) {
+ original_call_event = lcb->previous_call_event;
+
+ lsm_ui_call_state(call_state, line, lcb, CC_CAUSE_NORMAL);
+ if (original_call_event != call_state) {
+ /* Call state changed, take care of special event */
+ switch (call_state) {
+ case evConference:
+ break;
+
+ case evConnected:
+ case evWhisper:
+ ui_set_call_status(
+ platform_get_phrase_index_str(CALL_CONNECTED),
+ line, lcb->ui_id);
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ return (CC_RC_SUCCESS);
+}
+
+
+/*
+ * Function: lsm_update_placed_callinfo
+ *
+ * Description: this helps log dialed digits (as opposed to RPID provided
+ * value) into placed calls. This also decides whether to
+ * log called party name received in RPID.
+ *
+ * Parameters: dcb - pointer to default SM control block
+ *
+ * Returns: none
+ *
+ */
+#define CISCO_PLAR_STRING "x-cisco-serviceuri-offhook"
+void
+lsm_update_placed_callinfo (void *data)
+{
+ const char *tmp_called_number = NULL;
+ const char *called_name = NULL;
+ fsmdef_dcb_t *dcb = NULL;
+ lsm_lcb_t *lcb;
+ static const char fname[] = "lsm_update_placed_callinfo";
+ boolean has_called_number = FALSE;
+
+ LSM_DEBUG(DEB_F_PREFIX"Entering ...\n", DEB_F_PREFIX_ARGS(LSM, fname));
+ dcb = (fsmdef_dcb_t *) data;
+ lcb = lsm_get_lcb_by_call_id(dcb->call_id);
+ if (lcb == NULL) {
+ LSM_DEBUG(DEB_F_PREFIX"Exiting: lcb not found\n", DEB_F_PREFIX_ARGS(LSM, fname));
+ return;
+ }
+
+ if (dcb->caller_id.called_number != NULL &&
+ dcb->caller_id.called_number[0] != NUL) {
+ has_called_number = TRUE;
+ }
+
+
+ tmp_called_number = lsm_get_gdialed_digits();
+
+
+ /* if tmp_called_number is NULL or empty, return */
+ if (tmp_called_number == NULL || (*tmp_called_number) == NUL) {
+ LSM_DEBUG(DEB_L_C_F_PREFIX"Exiting : dialed digits is empty\n",
+ DEB_L_C_F_PREFIX_ARGS(LSM, lcb->line, lcb->call_id, fname));
+ return;
+ }
+
+ /*
+ * if tmp_called_number is same as what we receive in RPID,
+ * then get the called name from RPID if provided.
+ */
+ if (has_called_number) {
+ if (strcmp(tmp_called_number, CISCO_PLAR_STRING) == 0) {
+ tmp_called_number = dcb->caller_id.called_number;
+ }
+ /* if RPID number matches, dialed digits, use RPID name */
+ if (strcmp(dcb->caller_id.called_number, tmp_called_number) == 0) {
+ called_name = dcb->caller_id.called_name;
+ } else {
+ char tmp_str[STATUS_LINE_MAX_LEN];
+ platGetPhraseText(STR_INDEX_ANONYMOUS_SPACE, (char *)tmp_str, STATUS_LINE_MAX_LEN - 1);
+ if(strcmp(dcb->caller_id.called_number,tmp_str) == 0
+ && strcmp(dcb->caller_id.orig_rpid_number, tmp_called_number) == 0
+ && strcmp(dcb->caller_id.called_name, platform_get_phrase_index_str(UI_UNKNOWN)) != 0) {
+ called_name = dcb->caller_id.called_name;
+ }
+ }
+ }
+ ui_update_placed_call_info(lcb->line, lcb->call_id, called_name,
+ tmp_called_number);
+ LSM_DEBUG(DEB_L_C_F_PREFIX"Exiting: invoked ui_update_placed_call_info()\n",
+ DEB_L_C_F_PREFIX_ARGS(LSM, lcb->line, lcb->call_id, fname));
+}
+
+cc_int32_t
+lsm_show_cmd (cc_int32_t argc, const char *arv[])
+{
+ int i = 0;
+ lsm_lcb_t *lcb;
+
+ PR_ASSERT( i == 0 );
+ debugif_printf("\n------------------ LSM lcbs -------------------");
+ debugif_printf("\ni call_id line state lcb");
+ debugif_printf("\n-----------------------------------------------\n");
+
+ FSM_FOR_ALL_CBS(lcb, lsm_lcbs, LSM_MAX_LCBS) {
+ debugif_printf("%-2d %-7d %-4d %-16s 0x%8p\n",
+ i++, lcb->call_id, lcb->line,
+ lsm_state_name(lcb->state), lcb);
+
+ }
+
+ return (0);
+}
+
+void
+lsm_init_config (void)
+{
+ /*
+ * The silent period between call waiting bursts is now configurable
+ * for TNP phones. Store away the value for the callwaiting code to use.
+ * The config is in seconds, but CPR expects the duration in milliseconds
+ * thus multiply the config value by 1000. Non-TNP phones default to
+ * 10 seconds.
+ */
+ config_get_value(CFGID_CALL_WAITING_SILENT_PERIOD, &callWaitingDelay,
+ sizeof(callWaitingDelay));
+ callWaitingDelay = callWaitingDelay * 1000;
+}
+
+void
+lsm_init (void)
+{
+ static const char fname[] = "lsm_init";
+ lsm_lcb_t *lcb;
+ int i;
+
+ /*
+ * Init the lcbs.
+ */
+ lsm_lcbs = (lsm_lcb_t *) cpr_calloc(LSM_MAX_LCBS, sizeof(lsm_lcb_t));
+ if (lsm_lcbs == NULL) {
+ LSM_ERR_MSG(LSM_F_PREFIX"lsm_lcbs cpr_calloc returned NULL\n", fname);
+ return;
+ }
+
+ FSM_FOR_ALL_CBS(lcb, lsm_lcbs, LSM_MAX_LCBS) {
+ lsm_init_lcb(lcb);
+ }
+
+ /*
+ * Create tones and continous tone timer. The same call back function
+ * is utilized for each of these timers.
+ */
+ lsm_tmr_tones = cprCreateTimer("lsm_tmr_tones",
+ GSM_MULTIPART_TONES_TIMER,
+ TIMER_EXPIRATION, gsm_msg_queue);
+ lsm_continuous_tmr_tones = cprCreateTimer("lsm_continuous_tmr_tones",
+ GSM_CONTINUOUS_TONES_TIMER,
+ TIMER_EXPIRATION,
+ gsm_msg_queue);
+ lsm_tone_duration_tmr = cprCreateTimer("lsm_tone_duration_tmr",
+ GSM_TONE_DURATION_TIMER,
+ TIMER_EXPIRATION, gsm_msg_queue);
+ lsm_init_config();
+
+ for (i=0 ; ioffhook));
+#ifdef TEST
+ test_dial_calls(line, call_id, 500, "10011234");
+#endif
+ break;
+
+ case CC_STATE_DIALING:
+ result = lsm_dialing(lcb, &(data->dialing));
+ break;
+
+ case CC_STATE_DIALING_COMPLETED:
+ result = lsm_dialing_completed(lcb, &(data->dialing_completed));
+ break;
+
+ case CC_STATE_CALL_SENT:
+ result = lsm_call_sent(lcb, &(data->call_sent));
+ break;
+
+ case CC_STATE_FAR_END_PROCEEDING:
+ result = lsm_far_end_proceeding(lcb, &(data->far_end_proceeding));
+ break;
+
+ case CC_STATE_FAR_END_ALERTING:
+ result = lsm_far_end_alerting(lcb, &(data->far_end_alerting));
+ break;
+
+ case CC_STATE_CALL_RECEIVED:
+ result = lsm_call_received(lcb, &(data->call_received));
+ break;
+
+ case CC_STATE_ALERTING:
+ result = lsm_alerting(lcb, &(data->alerting));
+ break;
+
+ case CC_STATE_ANSWERED:
+ result = lsm_answered(lcb, &(data->answered));
+ break;
+
+ case CC_STATE_CONNECTED:
+ result = lsm_connected(lcb, &(data->connected));
+#ifdef TEST
+ test_disc_call(line, call_id);
+ test_line_offhook(line, cc_get_new_call_id());
+#endif
+ break;
+
+ case CC_STATE_HOLD:
+ result = lsm_hold(lcb, &(data->hold));
+ break;
+
+ case CC_STATE_HOLD_REVERT:
+ result = lsm_hold_reversion(lcb);
+ break;
+
+ case CC_STATE_RESUME:
+ result = lsm_resume(lcb, &(data->resume));
+ break;
+
+ case CC_STATE_ONHOOK:
+ result = lsm_onhook(lcb, &(data->onhook));
+ break;
+
+ case CC_STATE_CALL_FAILED:
+ result = lsm_call_failed(lcb, &(data->call_failed));
+ break;
+
+ default:
+ break;
+ }
+
+ if (result == CC_RC_ERROR) {
+ LSM_DEBUG(get_debug_string(LSM_DBG_CC_ERROR), call_id, line, fname,
+ state, data);
+ }
+
+ return;
+}
+
+static cc_rcs_t
+lsm_media (lsm_lcb_t *lcb, callid_t call_id, line_t line)
+{
+ fsmdef_dcb_t *dcb;
+
+ dcb = lcb->dcb;
+ if (dcb == NULL) {
+ return (CC_RC_ERROR);
+ }
+
+ if (!dcb->spoof_ringout_requested) {
+ lsm_update_media(lcb, "MEDIA");
+ vcmEnableSidetone(YES);
+ } else if (!dcb->spoof_ringout_applied &&
+ (lcb->state == LSM_S_CONNECTED)) {
+ cc_state_data_far_end_alerting_t alerting_data;
+
+ alerting_data.caller_id = dcb->caller_id;
+ (void) lsm_far_end_alerting(lcb, &alerting_data);
+ dcb->spoof_ringout_applied = TRUE;
+ }
+
+ return (CC_RC_SUCCESS);
+}
+
+/*
+ * Function: lsm_stop_media
+ *
+ * Parameters:
+ * lcb - pointer to lsm_lcb_t,
+ * call_id - gsm call id for the call in used.
+ * line - line_t for the line number (dn line).
+ * data - action data.
+ *
+ * Description:
+ * The function simply stops media (close Rx and Tx) and set the
+ * proper ringer.
+ *
+ * Returns: None.
+ */
+static void
+lsm_stop_media (lsm_lcb_t *lcb, callid_t call_id, line_t line,
+ cc_action_data_t *data)
+{
+ static const char fname[] = "lsm_stop_media";
+ fsmdef_dcb_t *dcb;
+ fsmdef_media_t *media;
+
+ dcb = lcb->dcb;
+ if (dcb == NULL) {
+ LSM_DEBUG(get_debug_string(DEBUG_INPUT_NULL), fname);
+ return;
+ }
+
+ /* hard close receive and transmit channels */
+ if ((data == NULL) ||
+ (data->stop_media.media_refid == CC_NO_MEDIA_REF_ID)) {
+ /* no data provided or no specific ref ID, defaul to all entries */
+ lsm_close_rx(lcb, FALSE, NULL);
+ lsm_close_tx(lcb, FALSE, NULL);
+ } else {
+ /* look up the media entry for the given reference ID */
+ media = gsmsdp_find_media_by_refid(dcb,
+ data->stop_media.media_refid);
+ if (media != NULL) {
+ lsm_close_rx(lcb, FALSE, media);
+ lsm_close_tx(lcb, FALSE, media);
+ } else {
+ /* no entry found */
+ LSM_DEBUG(DEB_L_C_F_PREFIX"no media with reference ID %d found\n",
+ DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, dcb->call_id, fname),
+ data->stop_media.media_refid);
+ return;
+ }
+ }
+ lsm_set_ringer(lcb, call_id, line, YES);
+}
+
+
+
+/*
+ * lsm_add_remote_stream
+ *
+ * Description:
+ * The function adds a remote stream to the media subsystem
+ *
+ * Parameters:
+ * [in] line - line
+ * [in] call_id - GSM call ID
+ * [in] media - media line to add as remote stream
+ * [out] pc_stream_id
+ * Returns: None
+ */
+void lsm_add_remote_stream (line_t line, callid_t call_id, fsmdef_media_t *media, int *pc_stream_id)
+{
+ static const char fname[] = "lsm_add_remote_stream";
+ fsmdef_dcb_t *dcb;
+ lsm_lcb_t *lcb;
+
+ lcb = lsm_get_lcb_by_call_id(call_id);
+ if (lcb != NULL) {
+ dcb = lcb->dcb;
+ if (dcb == NULL) {
+ LSM_ERR_MSG(get_debug_string(DEBUG_INPUT_NULL), fname);
+ return;
+ }
+
+ vcmCreateRemoteStream(media->cap_index, dcb->peerconnection,
+ pc_stream_id);
+
+ }
+}
+
+/*
+ * lsm_data_channel_negotiated
+ *
+ * Description:
+ * The function informs the API of a negotiated data channel m= line
+ *
+ * Parameters:
+ * [in] line - line
+ * [in] call_id - GSM call ID
+ * [in] media - media line to add as remote stream
+ * [out] pc_stream_id
+ * Returns: None
+ */
+void lsm_data_channel_negotiated (line_t line, callid_t call_id, fsmdef_media_t *media, int *pc_stream_id)
+{
+ static const char fname[] = "lsm_data_channel_negotiated";
+ fsmdef_dcb_t *dcb;
+ lsm_lcb_t *lcb;
+
+ lcb = lsm_get_lcb_by_call_id(call_id);
+ if (lcb) {
+ dcb = lcb->dcb;
+ if (dcb == NULL) {
+ LSM_ERR_MSG(get_debug_string(DEBUG_INPUT_NULL), fname);
+ return;
+ }
+
+ /*
+ * have access to media->streams, media->protocol, media->sctp_port
+ * vcmSetDataChannelParameters may need renaming TODO: jesup
+ */
+
+ vcmSetDataChannelParameters(dcb->peerconnection, media->streams, media->sctp_port, media->protocol);
+
+ }
+}
+
+/**
+ *
+ * Peform non call related action
+ *
+ * @param line_t line
+ * @param callid_t gsm_id
+ * @param action type of action
+ * @param cc_action_data_t line
+ *
+ * @return true if the action has been peformed, else false
+ *
+ * @pre (action == CC_ACTION_MWI_LAMP_ONLY || CC_ACTION_SET_LINE_RINGER ||
+ CC_ACTION_PLAY_BLF_ALERTING_TONE)
+ */
+static boolean
+cc_call_non_call_action (callid_t call_id, line_t line,
+ cc_actions_t action, cc_action_data_t *data)
+{
+ /* Certain requests are device based and does not contain any
+ * line number and call_id associated with it. So handle thoese
+ * requests here
+ */
+ switch (action) {
+
+ case CC_ACTION_MWI_LAMP_ONLY:
+ if (data != NULL) {
+ ui_change_mwi_lamp(data->mwi.on);
+ return(TRUE);
+ }
+ break;
+
+ case CC_ACTION_SET_LINE_RINGER:
+
+ if (data != NULL) {
+ return(TRUE);
+ }
+ break;
+
+ case CC_ACTION_PLAY_BLF_ALERTING_TONE:
+ lsm_play_tone(CC_FEATURE_BLF_ALERT_TONE);
+ return TRUE;
+
+ default:
+ break;
+ }
+
+ return(FALSE);
+}
+
+/*
+ * LSM API supports various actions such as play tone, stop tone,
+ * direct media operation etc.
+ *
+ * @param[in] call_id GSM call ID of an active call.
+ * @param[in] line line number of the line_t type.
+ * @param[in] action cc_actions_t for the desired action.
+ * @param[in] data cc_action_data_t data or parameters that may be
+ * required for certain action.
+ *
+ * @return cc_rcs_t status.
+ *
+ * @pre line not_eqs CC_NO_LINE
+ * @pre ((action equals CC_ACTION_PLAY_TONE) or
+ * (action equals CC_ACTION_STOP_TONE) or
+ * (action equals CC_ACTION_DIAL_MODE) or
+ * (action equals CC_ACTION_MWI) or
+ * (action equals CC_ACTION_OPEN_RCV) or
+ * (action equals CC_ACTION_UPDATE_UI) or
+ * (action equals CC_ACTION_RINGER))
+ */
+cc_rcs_t
+cc_call_action (callid_t call_id, line_t line, cc_actions_t action,
+ cc_action_data_t *data)
+{
+ static const char fname[] = "cc_call_action";
+ cc_rcs_t result = CC_RC_SUCCESS;
+ lsm_lcb_t *lcb;
+ fsmdef_dcb_t *dcb;
+ fsmdef_media_t *media;
+
+ LSM_DEBUG(get_debug_string(LSM_DBG_ENTRY), call_id, line,
+ cc_action_name(action));
+
+ /* perform non call related actions. lcb is not required
+ * for these actions
+ */
+ if (cc_call_non_call_action(call_id, line, action, data)) {
+ return (result);
+ }
+
+ lcb = lsm_get_lcb_by_call_id(call_id);
+
+ if ((lcb == NULL) && (action != CC_ACTION_MWI)) {
+ LSM_DEBUG(get_debug_string(DEBUG_INPUT_NULL), fname);
+ return (CC_RC_ERROR);
+ }
+
+ switch (action) {
+ case CC_ACTION_PLAY_TONE:
+ if (data != NULL) {
+ result = lsm_start_tone(lcb, &(data->tone));
+ } else {
+ result = CC_RC_ERROR;
+ }
+ break;
+
+ case CC_ACTION_STOP_TONE:
+ if (data != NULL) {
+ result = lsm_stop_tone(lcb, &(data->tone));
+ } else {
+ result = CC_RC_ERROR;
+ }
+ break;
+
+ case CC_ACTION_SPEAKER:
+ break;
+
+ case CC_ACTION_DIAL_MODE:
+ if (data != NULL) {
+ result = lsm_dial_mode(lcb, &(data->dial_mode));
+ } else {
+ result = CC_RC_ERROR;
+ }
+ break;
+
+ case CC_ACTION_MWI:
+ if (data != NULL) {
+ result = lsm_mwi(NULL, call_id, line, &(data->mwi));
+ } else {
+ result = CC_RC_ERROR;
+ }
+ break;
+
+ case CC_ACTION_OPEN_RCV:
+ if (data != NULL) {
+ result = lsm_open_rx(lcb, &(data->open_rcv), NULL);
+ } else {
+ result = CC_RC_ERROR;
+ }
+ break;
+
+ case CC_ACTION_UPDATE_UI:
+ if (data != NULL) {
+ result = lsm_update_ui(lcb, &(data->update_ui));
+ } else {
+ result = CC_RC_ERROR;
+ }
+ break;
+
+ case CC_ACTION_MEDIA:
+ result = lsm_media(lcb, call_id, line);
+ break;
+
+ case CC_ACTION_RINGER:
+ if (data != NULL) {
+ lsm_ringer(lcb, &(data->ringer));
+ }
+ break;
+
+ case CC_ACTION_STOP_MEDIA:
+ lsm_stop_media(lcb, call_id, line, data);
+ break;
+
+ case CC_ACTION_START_RCV:
+ /* start receiving */
+ dcb = lcb->dcb;
+ if (dcb == NULL) {
+ /* No call ID */
+ result = CC_RC_ERROR;
+ break;
+ }
+
+ GSMSDP_FOR_ALL_MEDIA(media, dcb) {
+ if (!GSMSDP_MEDIA_ENABLED(media)) {
+ /* this entry is not active */
+ continue;
+ }
+
+ /* only support starting all receive channels for now */
+ lsm_rx_start(lcb, fname, media);
+ }
+ break;
+
+ case CC_ACTION_ANSWER_PENDING:
+ FSM_SET_FLAGS(lcb->flags, LSM_FLAGS_ANSWER_PENDING);
+ break;
+
+ default:
+ break;
+ }
+
+
+ if (result == CC_RC_ERROR) {
+ LSM_DEBUG(get_debug_string(LSM_DBG_CC_ERROR), call_id, line, fname,
+ action, data);
+ }
+
+ return (result);
+}
+
+
+void
+lsm_ui_display_notify (const char *notify_str, unsigned long timeout)
+{
+ /*
+ * add 0 as (default) priority; it is don't care in legacy mode
+ */
+ ui_set_notification(CC_NO_LINE, CC_NO_CALL_ID,
+ (char *)notify_str, (int)timeout, FALSE,
+ DEF_NOTIFY_PRI);
+}
+
+void
+lsm_ui_display_status (const char *status_str, line_t line, callid_t call_id)
+{
+ lsm_lcb_t *lcb;
+
+ if (call_id == CC_NO_CALL_ID) {
+ /* Invalid call id */
+ return;
+ }
+ lcb = lsm_get_lcb_by_call_id(call_id);
+ if (lcb == NULL) {
+ return;
+ }
+
+ ui_set_call_status((char *) status_str, line, lcb->ui_id);
+}
+
+/**
+ * This function will display notification status line.
+ *
+ * @param[in] str_index - index into phrase dictionary
+ *
+ * @return none
+ */
+void lsm_ui_display_notify_str_index (int str_index)
+{
+ char tmp_str[STATUS_LINE_MAX_LEN];
+
+ if ((platGetPhraseText(str_index,
+ (char *)tmp_str,
+ (STATUS_LINE_MAX_LEN - 1))) == CPR_SUCCESS) {
+ lsm_ui_display_notify(tmp_str, NO_FREE_LINES_TIMEOUT);
+ }
+}
+
+/*
+ * Function: lsm_parse_displaystr
+ *
+ * Parameters:string to be parsed
+ *
+ * Description:Wrapper function for parsing string to be displayed
+ *
+ * Returns: Pointer to parsed number
+ *
+ */
+string_t
+lsm_parse_displaystr (string_t displaystr)
+{
+ return (sippmh_parse_displaystr(displaystr));
+}
+
+void
+lsm_speaker_mode (short mode)
+{
+ ui_set_speaker_mode((boolean)mode);
+}
+
+/*
+ * Function:lsm_update_active_tone
+ *
+ * Parameters:
+ * tone - tone type
+ * call_id - call identifier
+ *
+ * Description: Update dcb->active_tone if starting infinite duration tone.
+ *
+ * Returns:none
+ *
+ */
+void
+lsm_update_active_tone (vcm_tones_t tone, callid_t call_id)
+{
+ static const char fname[] = "lsm_update_active_tone";
+ fsmdef_dcb_t *dcb;
+
+ /* if tone is any of following then set active_tone in dcb b/c these
+ * tones have infinite duration and need to be stopped. Other tones
+ * only play for a finite/short duration so no need to stop them as
+ * they will stop automatically.
+ */
+ switch (tone) {
+ /* for all tones with infinite playing duration */
+ case VCM_INSIDE_DIAL_TONE:
+ case VCM_LINE_BUSY_TONE:
+ case VCM_ALERTING_TONE:
+ case VCM_STUTTER_TONE:
+ case VCM_REORDER_TONE:
+ case VCM_OUTSIDE_DIAL_TONE:
+ case VCM_PERMANENT_SIGNAL_TONE:
+ case VCM_RECORDERWARNING_TONE:
+ case VCM_MONITORWARNING_TONE:
+ dcb = fsmdef_get_dcb_by_call_id(call_id);
+
+ if (dcb == NULL) {
+ /* Possibibly the ui_id was passed in and the dcb is no longer existed.
+ * Try to retrieve the corresponding dcb.
+ */
+ dcb = fsmdef_get_dcb_by_call_id(lsm_get_callid_from_ui_id(call_id));
+ }
+
+ if (dcb != NULL) {
+ /* Ideally a call should not make a infinite tone start request
+ * (without making a stop request) while there is already one playing.
+ * However, DSP will start playing the new request tone by overriding
+ * the current one. Technically its okay. So, just printing a log msg.
+ */
+ if (dcb->active_tone != VCM_NO_TONE) {
+ LSM_DEBUG(DEB_L_C_F_PREFIX"Active Tone current = %d new = %d\n",
+ DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, call_id, fname),
+ dcb->active_tone, tone);
+ }
+ dcb->active_tone = tone;
+ }
+ break;
+
+ default:
+ /* do nothing */
+ break;
+ }
+}
+
+/*
+ * Function: lsm_is_tx_channel_opened
+ *
+ * Parameters: call_id
+ *
+ * Description: check to see tx channel is openned
+ *
+ * Returns: TRUE or FALSE
+ *
+ */
+boolean
+lsm_is_tx_channel_opened(callid_t call_id)
+{
+ fsmdef_dcb_t *dcb_p = fsmdef_get_dcb_by_call_id(call_id);
+ fsmdef_media_t *media = NULL;
+
+ if (dcb_p == NULL) {
+ return (FALSE);
+ }
+
+ /*
+ * search the all entries that has a valid media and matches
+ * SDP_MEDIA_AUDIO type.
+ */
+ GSMSDP_FOR_ALL_MEDIA(media, dcb_p) {
+ if (media->type == SDP_MEDIA_AUDIO) {
+ /* found a match */
+ if (media->xmit_chan)
+ return (TRUE);
+ }
+ }
+ return (FALSE);
+}
+
+/*
+ * Function:lsm_update_monrec_tone_action
+ *
+ * Parameters:
+ * tone - tone type
+ * call_id - call identifier
+ *
+ * Description: Update dcb->monrec_tone_action.
+ *
+ * Returns:none
+ *
+ */
+void
+lsm_update_monrec_tone_action (vcm_tones_t tone, callid_t call_id, uint16_t direction)
+{
+ static const char fname[] = "lsm_update_monrec_tone_action";
+ fsmdef_dcb_t *dcb;
+ boolean tx_opened = lsm_is_tx_channel_opened(call_id);
+
+ dcb = fsmdef_get_dcb_by_call_id(call_id);
+
+ if (dcb != NULL) {
+ switch(tone) {
+ case VCM_MONITORWARNING_TONE:
+ switch (dcb->monrec_tone_action) {
+ case FSMDEF_MRTONE_NO_ACTION:
+ if (!tx_opened) {
+ dcb->monrec_tone_action = FSMDEF_MRTONE_RESUME_MONITOR_TONE;
+ } else {
+ dcb->monrec_tone_action = FSMDEF_MRTONE_PLAYED_MONITOR_TONE;
+ }
+ break;
+
+ case FSMDEF_MRTONE_PLAYED_RECORDER_TONE:
+ dcb->monrec_tone_action = FSMDEF_MRTONE_PLAYED_BOTH_TONES;
+ break;
+
+ case FSMDEF_MRTONE_RESUME_RECORDER_TONE:
+ dcb->monrec_tone_action = FSMDEF_MRTONE_RESUME_BOTH_TONES;
+ break;
+
+ case FSMDEF_MRTONE_PLAYED_MONITOR_TONE:
+ case FSMDEF_MRTONE_PLAYED_BOTH_TONES:
+ case FSMDEF_MRTONE_RESUME_MONITOR_TONE:
+ case FSMDEF_MRTONE_RESUME_BOTH_TONES:
+ default:
+ DEF_DEBUG(DEB_F_PREFIX"Invalid action request... tone:%d monrec_tone_action:%d \n",
+ DEB_F_PREFIX_ARGS("RCC", fname), tone, dcb->monrec_tone_action);
+ break;
+ }
+ dcb->monitor_tone_direction = direction;
+ break;
+
+ case VCM_RECORDERWARNING_TONE:
+ switch (dcb->monrec_tone_action) {
+ case FSMDEF_MRTONE_NO_ACTION:
+ if (!tx_opened) {
+ dcb->monrec_tone_action = FSMDEF_MRTONE_RESUME_RECORDER_TONE;
+ } else {
+ dcb->monrec_tone_action = FSMDEF_MRTONE_PLAYED_RECORDER_TONE;
+ }
+ break;
+
+ case FSMDEF_MRTONE_PLAYED_MONITOR_TONE:
+ dcb->monrec_tone_action = FSMDEF_MRTONE_PLAYED_BOTH_TONES;
+ break;
+
+ case FSMDEF_MRTONE_RESUME_MONITOR_TONE:
+ dcb->monrec_tone_action = FSMDEF_MRTONE_RESUME_BOTH_TONES;
+ break;
+
+ case FSMDEF_MRTONE_PLAYED_RECORDER_TONE:
+ case FSMDEF_MRTONE_PLAYED_BOTH_TONES:
+ case FSMDEF_MRTONE_RESUME_RECORDER_TONE:
+ case FSMDEF_MRTONE_RESUME_BOTH_TONES:
+ default:
+ DEF_DEBUG(DEB_F_PREFIX"Invalid action request... tone:%d monrec_tone_action:%d \n",
+ DEB_F_PREFIX_ARGS("RCC", fname), tone, dcb->monrec_tone_action);
+ break;
+ }
+ dcb->recorder_tone_direction = direction;
+ break;
+
+ default:
+ break;
+ } /* end of switch */
+
+ LSM_DEBUG(DEB_L_C_F_PREFIX"Start request for tone: %d. Set monrec_tone_action: %d\n",
+ DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, call_id, fname),
+ tone, dcb->monrec_tone_action);
+
+ } /* end of if */
+}
+
+/*
+ * Function:lsm_downgrade_monrec_tone_action
+ *
+ * Parameters:
+ * tone - tone type
+ * call_id - call identifier
+ *
+ * Description: Update dcb->monrec_tone_action.
+ *
+ * Returns:none
+ *
+ */
+void
+lsm_downgrade_monrec_tone_action (vcm_tones_t tone, callid_t call_id)
+{
+ static const char fname[] = "lsm_downgrade_monrec_tone_action";
+ fsmdef_dcb_t *dcb;
+
+ dcb = fsmdef_get_dcb_by_call_id(call_id);
+
+ /* Need to downgrade the monrec_tone_action */
+
+ if (dcb != NULL) {
+ switch (tone){
+ case VCM_MONITORWARNING_TONE:
+ switch (dcb->monrec_tone_action) {
+ case FSMDEF_MRTONE_PLAYED_MONITOR_TONE:
+ case FSMDEF_MRTONE_RESUME_MONITOR_TONE:
+ dcb->monrec_tone_action = FSMDEF_MRTONE_NO_ACTION;
+ break;
+
+ case FSMDEF_MRTONE_RESUME_BOTH_TONES:
+ dcb->monrec_tone_action = FSMDEF_MRTONE_RESUME_RECORDER_TONE;
+ break;
+
+ case FSMDEF_MRTONE_PLAYED_BOTH_TONES:
+ dcb->monrec_tone_action = FSMDEF_MRTONE_PLAYED_RECORDER_TONE;
+ break;
+
+ case FSMDEF_MRTONE_NO_ACTION:
+ case FSMDEF_MRTONE_PLAYED_RECORDER_TONE:
+ case FSMDEF_MRTONE_RESUME_RECORDER_TONE:
+ default:
+ DEF_DEBUG(DEB_F_PREFIX"Invalid action request... tone:%d monrec_tone_action:%d \n",
+ DEB_F_PREFIX_ARGS("RCC", fname), tone, dcb->monrec_tone_action);
+ break;
+ }
+ dcb->monitor_tone_direction = VCM_PLAY_TONE_TO_EAR;
+ break;
+
+ case VCM_RECORDERWARNING_TONE:
+ switch (dcb->monrec_tone_action) {
+ case FSMDEF_MRTONE_PLAYED_RECORDER_TONE:
+ case FSMDEF_MRTONE_RESUME_RECORDER_TONE:
+ dcb->monrec_tone_action = FSMDEF_MRTONE_NO_ACTION;
+ break;
+
+ case FSMDEF_MRTONE_RESUME_BOTH_TONES:
+ dcb->monrec_tone_action = FSMDEF_MRTONE_RESUME_MONITOR_TONE;
+ break;
+
+ case FSMDEF_MRTONE_PLAYED_BOTH_TONES:
+ dcb->monrec_tone_action = FSMDEF_MRTONE_PLAYED_MONITOR_TONE;
+ break;
+
+ case FSMDEF_MRTONE_NO_ACTION:
+ case FSMDEF_MRTONE_PLAYED_MONITOR_TONE:
+ case FSMDEF_MRTONE_RESUME_MONITOR_TONE:
+ default:
+ DEF_DEBUG(DEB_F_PREFIX"Invalid action request... tone:%d monrec_tone_action:%d \n",
+ DEB_F_PREFIX_ARGS("RCC", fname), tone, dcb->monrec_tone_action);
+ break;
+ }
+ dcb->recorder_tone_direction = VCM_PLAY_TONE_TO_EAR;
+ break;
+
+ default:
+ break;
+ } /* end of switch */
+
+ LSM_DEBUG(DEB_L_C_F_PREFIX"Stop request for tone: %d Downgrade monrec_tone_action: %d \n",
+ DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, call_id, fname),
+ tone, dcb->monrec_tone_action);
+ } /* end of if */
+}
+
+/*
+ * Function: lsm_set_hold_ringback_status
+ *
+ * Parameters:
+ * callid_t - callid of the lcb
+ * ringback_status - status of call hold ringback
+ *
+ * Description: Function used to set the ringback status
+ *
+ * Returns:None
+ *
+ */
+void
+lsm_set_hold_ringback_status(callid_t call_id, boolean ringback_status)
+{
+ lsm_lcb_t *lcb;
+
+ FSM_FOR_ALL_CBS(lcb, lsm_lcbs, LSM_MAX_LCBS) {
+ if (lcb->call_id == call_id) {
+ LSM_DEBUG(DEB_F_PREFIX"Setting ringback to %d for lcb %d\n",
+ DEB_F_PREFIX_ARGS(LSM, "lsm_set_hold_ringback_status"), ringback_status, call_id);
+ lcb->enable_ringback = ringback_status;
+ break;
+ }
+ }
+}
+
+void lsm_play_tone (cc_features_t feature_id)
+{
+ int play_tone;
+
+ switch (feature_id) {
+ case CC_FEATURE_BLF_ALERT_TONE:
+ if (lsm_find_state(LSM_S_RINGIN) > CC_NO_CALL_ID) {
+ // No tone if we have calls in ringing state
+ return;
+ }
+
+ if (!lsm_callwaiting()) {
+ config_get_value(CFGID_BLF_ALERT_TONE_IDLE, &play_tone, sizeof(play_tone));
+ if (play_tone == 0) {
+ return;
+ }
+ lsm_util_tone_start_with_speaker_as_backup(VCM_CALL_WAITING_TONE, VCM_ALERT_INFO_OFF,
+ CC_NO_CALL_ID, CC_NO_GROUP_ID,
+ CC_NO_MEDIA_REF_ID, VCM_PLAY_TONE_TO_EAR);
+ } else {
+ config_get_value(CFGID_BLF_ALERT_TONE_BUSY, &play_tone, sizeof(play_tone));
+ if (play_tone == 0) {
+ return;
+ }
+ lsm_util_tone_start_with_speaker_as_backup(VCM_CALL_WAITING_TONE, VCM_ALERT_INFO_OFF,
+ CC_NO_CALL_ID, CC_NO_GROUP_ID,
+ CC_NO_MEDIA_REF_ID, VCM_PLAY_TONE_TO_EAR);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+/*
+ * lsm_update_inalert_status
+ *
+ * Description:
+ *
+ * TNP specific implementation of status line update for inalert state.
+ *
+ * Parameters:
+ *
+ * line_t line - Line facility of the call
+ * callid_t call_id - Call id of call whose state is being reported
+ * cc_state_data_alerting_t * data - alerting callinfo.
+ * boolean notify - whether the msg be displayed at notify level.
+ *
+ * Returns: None
+ */
+static void
+lsm_update_inalert_status (line_t line, callid_t call_id,
+ cc_state_data_alerting_t * data,
+ boolean notify)
+{
+ static const char fname[] = "lsm_update_inalert_status";
+ char disp_str[LSM_DISPLAY_STR_LEN];
+
+ // get localized tag index for From and append one space character
+ sstrncpy(disp_str, platform_get_phrase_index_str(UI_FROM),
+ sizeof(disp_str));
+
+ LSM_DEBUG(DEB_L_C_F_PREFIX"+++ calling number = %s\n",
+ DEB_L_C_F_PREFIX_ARGS(LSM, line, call_id, fname),
+ data->caller_id.calling_number);
+
+ // append calling number if present or localized tag for Unknown Number
+ // otherwise
+ if ((data->caller_id.calling_number) &&
+ (data->caller_id.calling_number[0] != '\0') &&
+ data->caller_id.display_calling_number) {
+
+ sstrncat(disp_str, data->caller_id.calling_number,
+ sizeof(disp_str) - strlen(disp_str));
+ } else {
+ sstrncat(disp_str, platform_get_phrase_index_str(UI_UNKNOWN),
+ sizeof(disp_str) - strlen(disp_str));
+ }
+
+ // we display (via notification) the "From ..." info for 10 seconds.
+ // Note that this will remain displayed for 10 sec even if the user
+ // answers the call or switches to another call. This happens because
+ // notification has higher priority than call status (e.g. connected).
+ // This is done to have parity with SCCP phone behavior.
+ if (notify == TRUE) {
+ ui_set_notification(line, call_id,
+ (char *)disp_str, (unsigned long)CALL_ALERT_TIMEOUT,
+ FALSE, FROM_NOTIFY_PRI);
+ }
+ // After the notification we wish to set the call status to From XXXX. Same as SCCP phone behavior
+ lsm_ui_display_status((char *)disp_str, line, call_id);
+
+ return;
+}
+
+
+
+/*
+ * lsm_set_cfwd_all_nonccm
+ * This function calls JNI API to set the CFA state and DN in non-ccm mode.
+ *
+ * @param[in] line - line on which to set the CFA
+ * @param[in] callfwd_dialstring: CFA DN (will be stored in flash)
+ *
+ * @return: None
+ */
+void
+lsm_set_cfwd_all_nonccm (line_t line, char *callfwd_dialstring)
+{
+ // call Java API
+ ui_cfwd_status(line, TRUE, callfwd_dialstring, TRUE);
+}
+
+/*
+ * lsm_set_cfwd_all_ccm
+ *
+ * Description:
+ * This function calls JNI API to set the CFA state and DN in ccm mode.
+ *
+ * Parameters:
+ * char * callfwd_dialstring: CFA DN (will NOT be stored in flash)
+ *
+ * Returns: None
+ */
+void
+lsm_set_cfwd_all_ccm (line_t line, char *callfwd_dialstring)
+{
+ // set locally maintained variable
+ cfwdall_state_in_ccm_mode[line] = TRUE;
+
+ // call Java API
+ ui_cfwd_status((line_t)line, TRUE, callfwd_dialstring, FALSE);
+}
+
+/*
+ * lsm_clear_cfwd_all_nonccm
+ * This function calls JNI API to clear the CFA state and DN in non-ccm mode.
+ *
+ * @param[in] line - line on which to clear the CFA
+ *
+ * @return: None
+ */
+void
+lsm_clear_cfwd_all_nonccm (line_t line)
+{
+ // call Java API
+ ui_cfwd_status(line, FALSE, "", TRUE);
+}
+
+
+/*
+ * lsm_clear_cfwd_all_ccm
+ *
+ * Description:
+ * This function calls JNI API to clear the CFA state and DN in ccm mode.
+ *
+ * Parameters: None
+ *
+ * Returns: None
+ */
+void
+lsm_clear_cfwd_all_ccm (line_t line)
+{
+ // clear locally maintained variable
+ cfwdall_state_in_ccm_mode[line] = FALSE;
+
+ // call Java API
+ ui_cfwd_status((line_t)line, FALSE, "", FALSE);
+}
+
+/*
+ * lsm_check_cfwd_all_nonccm
+ *
+ * Description:
+ * This function returns the CFA state in non-ccm mode.
+ *
+ * @param[in] line - line on which to check the CFA
+ *
+ * @return: TRUE (if CFA set) or FALSE (if CFA clear)
+ */
+int
+lsm_check_cfwd_all_nonccm (line_t line)
+{
+ char cfg_cfwd_url[MAX_URL_LENGTH];
+
+ cfg_cfwd_url[0] = '\0';
+
+ // get the callfwdall url value from the config/flash table
+ config_get_string(CFGID_LINE_CFWDALL+line-1, cfg_cfwd_url, MAX_URL_LENGTH);
+
+ // return appropriate value: TRUE if non-NULL and FALSE otherwise
+ if (cfg_cfwd_url[0]) {
+ return ((int) TRUE);
+ } else {
+ return ((int) FALSE);
+ }
+}
+
+/*
+ * lsm_check_cfwd_all_ccm
+ *
+ * Description:
+ * This function returns the CFA state in ccm mode.
+ *
+ * Parameters: None
+ *
+ * Returns: TRUE or FALSE
+ */
+int
+lsm_check_cfwd_all_ccm (line_t line)
+{
+ return ((int) cfwdall_state_in_ccm_mode[line]);
+}
+
+/*
+ * lsm_is_phone_forwarded
+ *
+ * Description:
+ * This function is called from SIP stack to check if received INVITE
+ * should be responded with 302 or not. In the CCM mode this function
+ * will always return NULL... that is process the INVITE as normal and
+ * DO NOT 302 it. In the non-CCM mode, if the cfwdall_url is non-NULL
+ * then it will form a proper string to use in 302 response; otherwise
+ * a NULL will be returned and the INVITE will be processed as normal.
+ * NOTE: most all code is reused from the legacy phone code.
+ *
+ * Parameters: line - line for which to check the CFA status
+ *
+ * Returns: NULL if forwarding is not set;
+ * string to use in 302 response if forwarding is set (non-CCM only)
+ */
+char *
+lsm_is_phone_forwarded (line_t line)
+{
+ static const char fname[] = "lsm_is_phone_forwarded";
+ char proxy_ipaddr_str[MAX_IPADDR_STR_LEN];
+ int port_number = 5060; // use this value only if none found
+ char *domain = NULL;
+ char *port = NULL;
+ cpr_ip_addr_t proxy_ipaddr;
+
+
+ LSM_DEBUG(DEB_F_PREFIX"called\n", DEB_F_PREFIX_ARGS(LSM, fname));
+
+ // check if running in CCM mode. if so, return NULL that is cfwdall
+ // not applicable
+ if (sip_regmgr_get_cc_mode(TEL_CCB_START) == REG_MODE_CCM) {
+ return (NULL);
+ }
+ // get stored callfwdall url value from the config/flash table
+
+ config_get_string(CFGID_LINE_CFWDALL+line-1, cfwdall_url, sizeof(cfwdall_url));
+
+ if (cfwdall_url[0]) {
+ // find domain and port
+ domain = strchr(cfwdall_url, '@');
+ if (!domain) {
+ (void) sipTransportGetServerAddress(&proxy_ipaddr,
+ 1, TEL_CCB_START);
+ if (proxy_ipaddr.type != CPR_IP_ADDR_INVALID) {
+ ipaddr2dotted(proxy_ipaddr_str, &proxy_ipaddr);
+ port_number = sipTransportGetServerPort(1, TEL_CCB_START);
+ }
+ } else {
+ port = strchr(domain + 1, ':');
+ }
+
+ // handle 3 cases
+ if (domain == NULL) {
+ /* case (1): no domain or port present
+ * We have proxy's dotted ip address format. So, not FQDN check.
+ * Append domain/ip-addr and port.
+ */
+ snprintf(cfwdall_url + strlen(cfwdall_url),
+ MAX_URL_LENGTH - strlen(cfwdall_url),
+ "@%s:%d", proxy_ipaddr_str, port_number);
+ } else if (port == NULL) {
+ /* case (2): domain present but no port
+ * Check if the domain is dotted IP address and add port
+ * only if dotted IP address is used
+ */
+ if (!str2ip((const char *) domain + 1, &proxy_ipaddr)) {
+ port_number = sipTransportGetServerPort(1, TEL_CCB_START);
+ snprintf(cfwdall_url + strlen(cfwdall_url),
+ MAX_URL_LENGTH - strlen(cfwdall_url),
+ ":%d", port_number);
+ }
+ } else {
+ /* case (3): both domain and port present
+ * Both domain and port exists, but strip the port if the
+ * domain is FQDN
+ */
+ memcpy(proxy_ipaddr_str, domain + 1, (port - domain - 1));
+ *(proxy_ipaddr_str + (port - domain - 1)) = '\0';
+ if (str2ip((const char *) proxy_ipaddr_str, &proxy_ipaddr) != 0) {
+ *port = '\0';
+ }
+ }
+ return ((char *)cfwdall_url);
+ } else {
+ return ((char *)NULL);
+ }
+}
+
+/*
+ * lsm_get_callid_from_ui_id()
+ *
+ * Description:
+ * The function gets the UI id from LSM's LCB for a given GSM call ID.
+ *
+ * Parameters:
+ * ui_id - UI ID.
+ *
+ * Returns: callid_t
+ */
+callid_t
+lsm_get_callid_from_ui_id (callid_t uid)
+{
+ lsm_lcb_t *lcb;
+ FSM_FOR_ALL_CBS(lcb, lsm_lcbs, LSM_MAX_LCBS) {
+ if (lcb->ui_id == uid) {
+ return lcb->call_id;
+ }
+ }
+ return (CC_NO_CALL_ID);
+}
+
+/*
+ * lsm_get_ui_id
+ *
+ * Description:
+ * The function gets the UI id from LSM's LCB for a given GSM call ID.
+ *
+ * Parameters:
+ * call_id - GSM call ID
+ * ui_id - UI ID.
+ *
+ * Returns: None
+ */
+callid_t
+lsm_get_ui_id (callid_t call_id)
+{
+ lsm_lcb_t *lcb;
+
+ lcb = lsm_get_lcb_by_call_id(call_id);
+ if (lcb != NULL) {
+ return (lcb->ui_id);
+ }
+ return (CC_NO_CALL_ID);
+}
+
+/*
+ * lsm_get_ms_ui_id
+ *
+ * Description:
+ * The function gets the UI id from LSM's LCB for a given GSM call ID. During
+ * certain features like barge ui_id is set to CC_NO_CALL_ID.
+ *
+ * Parameters:
+ * call_id - GSM call ID
+ * ui_id - UI ID.
+ *
+ * Returns: None
+ */
+cc_call_handle_t
+lsm_get_ms_ui_call_handle (line_t line, callid_t call_id, callid_t ui_id)
+{
+ callid_t lsm_ui_id;
+
+ if (ui_id != CC_NO_CALL_ID) {
+ return CREATE_CALL_HANDLE(line, ui_id);
+ }
+
+ /* If ui_id present use that */
+ lsm_ui_id = lsm_get_ui_id(call_id);
+
+ if (lsm_ui_id != CC_NO_CALL_ID) {
+ return CREATE_CALL_HANDLE(line, lsm_ui_id);
+ }
+
+ return CREATE_CALL_HANDLE(line, call_id);
+}
+/*
+ * lsm_set_ui_id
+ *
+ * Description:
+ * The function sets the UI id to LSM's LCB for a given GSM call ID.
+ *
+ * Parameters:
+ * call_id - GSM call ID
+ * ui_id - UI ID.
+ *
+ * Returns: None
+ */
+void
+lsm_set_ui_id (callid_t call_id, callid_t ui_id)
+{
+ lsm_lcb_t *lcb;
+
+ lcb = lsm_get_lcb_by_call_id(call_id);
+ if (lcb != NULL) {
+ lcb->ui_id = ui_id;
+ }
+}
+
+char *
+lsm_get_gdialed_digits (void)
+{
+ return (dp_get_gdialed_digits());
+}
+
+/*
+ * lsm_update_video_avail
+ *
+ * Description:
+ * The function updates session about the video availability
+ *
+ * Parameters:
+ * line - line
+ * call_id - GSM call ID
+ * dir - video avail dir
+ *
+ * Returns: None
+ */
+void lsm_update_video_avail (line_t line, callid_t call_id, int dir)
+{
+ static const char fname[] = "lsm_update_video_avail";
+ fsmdef_dcb_t *dcb;
+ lsm_lcb_t *lcb;
+
+ lcb = lsm_get_lcb_by_call_id(call_id);
+ if (lcb != NULL) {
+ dcb = lcb->dcb;
+ if (dcb == NULL) {
+ LSM_ERR_MSG(get_debug_string(DEBUG_INPUT_NULL), fname);
+ return;
+ }
+
+ dir &= ~CC_ATTRIB_CAST;
+
+
+ ui_update_video_avail (line, lcb->ui_id, dir);
+
+ lsm_update_dscp_value(dcb);
+ }
+}
+
+/*
+ * lsm_update_video_offered
+ *
+ * Description:
+ * The function updates session about the video availability
+ *
+ * Parameters:
+ * line - line
+ * call_id - GSM call ID
+ * dir - video avail dir
+ *
+ * Returns: None
+ */
+void lsm_update_video_offered (line_t line, callid_t call_id, int dir)
+{
+ lsm_lcb_t *lcb;
+
+ lcb = lsm_get_lcb_by_call_id(call_id);
+ if (lcb != NULL) {
+ ui_update_video_offered (line, lcb->ui_id, dir);
+ }
+}
+
+/*
+ * lsm_set_video_mute
+ *
+ * Description:
+ * The function sets the video mute state for the call
+ *
+ * Parameters:
+ * line - line
+ * call_id - This is the UI_ID coming from UI
+ * mute - mute state
+ *
+ * Returns: None
+ */
+void lsm_set_video_mute (callid_t call_id, int mute)
+{
+ lsm_lcb_t *lcb;
+ callid_t cid = lsm_get_callid_from_ui_id(call_id); // get GSM_ID from UI_ID
+
+ lcb = lsm_get_lcb_by_call_id(cid);
+ if (lcb != NULL) {
+ lcb->vid_mute = mute;
+ }
+}
+
+/*
+ * lsm_get_video_mute
+ *
+ * Description:
+ * The function gets the video mute state for the call
+ *
+ * Parameters:
+ * line - line
+ * call_id - GSM call ID
+ *
+ * Returns: t_video_mute
+ */
+int lsm_get_video_mute (callid_t call_id)
+{
+ lsm_lcb_t *lcb;
+
+ lcb = lsm_get_lcb_by_call_id(call_id);
+ if (lcb != NULL) {
+ return lcb->vid_mute;
+ }
+ return (-1);
+}
+
+
+/*
+ * lsm_set_video_window
+ *
+ * Description:
+ * The function sets the video window state for the call
+ *
+ * Parameters:
+ * call_id - This is the UI_ID coming from UI
+ * flags - video window flags
+ * x - video window x coordinate
+ * y - video window y coordinate
+ * h - video window height
+ * w - video window width
+ *
+ * Returns: None
+ */
+void lsm_set_video_window (callid_t call_id, int flags, int x, int y, int h, int w)
+{
+ lsm_lcb_t *lcb;
+ callid_t cid = lsm_get_callid_from_ui_id(call_id); // get GSM_ID from UI_ID
+
+ lcb = lsm_get_lcb_by_call_id(cid);
+ if (lcb != NULL) {
+ lcb->vid_flags = flags;
+ lcb->vid_x = x;
+ lcb->vid_y = y;
+ lcb->vid_h = h;
+ lcb->vid_w = w;
+ }
+}
+
+/*
+ * lsm_get_video_window
+ *
+ * Description:
+ * The function gets the video window for the call
+ *
+ * Parameters:
+ * call_id - GSM call ID
+ * *flags - video window flag
+ * *x - video window x coordinate
+ * *y - video window y coordinate
+ * *h - video window height
+ * *w - video window width
+ *
+ * Returns: void
+ */
+void lsm_get_video_window (callid_t call_id, int *flags, int *x, int *y, int *h, int *w)
+{
+ lsm_lcb_t *lcb;
+
+ lcb = lsm_get_lcb_by_call_id(call_id);
+ if (lcb != NULL) {
+ *flags = lcb->vid_flags;
+ *x = lcb->vid_x;
+ *y = lcb->vid_y;
+ *h = lcb->vid_h;
+ *w = lcb->vid_w;
+ }
+}
+
+/*
+ * lsm_is_kpml_subscribed
+ *
+ * Description:
+ * check if kpml is subscribed for this call
+ *
+ * Parameters:
+ * call_id - GSM call ID
+ *
+ * Returns: true/false
+ */
+boolean lsm_is_kpml_subscribed (callid_t call_id)
+{
+ lsm_lcb_t *lcb;
+
+ lcb = lsm_get_lcb_by_call_id(call_id);
+ if (lcb == NULL) {
+ return FALSE;
+ }
+ return kpml_is_subscribed(call_id, lcb->line);
+}
+
+/**
+ * A helper method to start the tone.
+ */
+static void lsm_util_start_tone(vcm_tones_t tone, short alert_info,
+ cc_call_handle_t call_handle, groupid_t group_id,
+ streamid_t stream_id, uint16_t direction) {
+
+ int sdpmode = 0;
+ static const char fname[] = "lsm_util_start_tone";
+ line_t line = GET_LINE_ID(call_handle);
+ callid_t call_id = GET_CALL_ID(call_handle);
+ DEF_DEBUG(DEB_F_PREFIX"Enter, line=%d, call_id=%d.\n",
+ DEB_F_PREFIX_ARGS(MED_API, fname), line, call_id);
+
+ sdpmode = 0;
+ config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
+ if (!sdpmode) {
+ vcmToneStart(tone, alert_info, call_handle, group_id, stream_id, direction);
+ }
+ /*
+ * Set delay value for multi-part tones and repeated tones.
+ * Currently the only multi-part tones are stutter and message
+ * waiting tones. The only repeated tones are call waiting and
+ * tone on hold tones. If the DSP ever supports stutter and
+ * message waiting tones, these tones can be removed from this
+ * switch statement.
+ */
+ switch (tone) {
+ case VCM_MSG_WAITING_TONE:
+ lsm_start_multipart_tone_timer(tone, MSG_WAITING_DELAY, call_id);
+ break;
+
+ case VCM_HOLD_TONE:
+ lsm_start_continuous_tone_timer(tone, TOH_DELAY, call_id);
+ break;
+
+ default:
+ break;
+ }
+
+ /*
+ * Update dcb->active_tone if start request
+ * is for an infinite duration tone.
+ */
+ lsm_update_active_tone(tone, call_id);
+}
+
+/*
+ * Plays a short tone. uses the open audio path.
+ * If no audio path is open, plays on speaker.
+ *
+ * @param[in] tone - tone type
+ * @param[in] alert_info - alertinfo header
+ * @param[in] call_id - call identifier
+ * @param[in] direction - network, speaker, both
+ *
+ * @return none
+ */
+void
+lsm_util_tone_start_with_speaker_as_backup (vcm_tones_t tone, short alert_info,
+ cc_call_handle_t call_handle, groupid_t group_id,
+ streamid_t stream_id, uint16_t direction) {
+ static const char *fname = "lsm_util_tone_start_with_speaker_as_backup";
+ line_t line = GET_LINE_ID(call_handle);
+ callid_t call_id = GET_CALL_ID(call_handle);
+ DEF_DEBUG(DEB_L_C_F_PREFIX"tone=%-2d: direction=%-2d\n",
+ DEB_L_C_F_PREFIX_ARGS(MED_API, line, call_id, fname),
+ tone, direction);
+
+ //vcmToneStart
+ vcmToneStart(tone, alert_info, call_handle, group_id, stream_id, direction);
+
+ /*
+ * Set delay value for multi-part tones and repeated tones.
+ * Currently the only multi-part tones are stutter and message
+ * waiting tones. The only repeated tones are call waiting and
+ * tone on hold tones. If the DSP ever supports stutter and
+ * message waiting tones, these tones can be removed from this
+ * switch statement.
+ */
+ switch (tone) {
+ case VCM_MSG_WAITING_TONE:
+ lsm_start_multipart_tone_timer(tone, MSG_WAITING_DELAY, call_id);
+ break;
+
+ case VCM_HOLD_TONE:
+ lsm_start_continuous_tone_timer(tone, TOH_DELAY, call_id);
+ break;
+
+ default:
+ break;
+ }
+
+ /*
+ * Update dcb->active_tone if start request
+ * is for an infinite duration tone.
+ */
+ lsm_update_active_tone(tone, call_id);
+
+}
diff --git a/libs/sipcc/core/gsm/media_cap_tbl.c b/libs/sipcc/core/gsm/media_cap_tbl.c
new file mode 100644
index 0000000000..46cce5e5b8
--- /dev/null
+++ b/libs/sipcc/core/gsm/media_cap_tbl.c
@@ -0,0 +1,158 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include
+#include "ccapi.h"
+#include "phone_debug.h"
+#include "cc_debug.h"
+#include "CCProvider.h"
+#include "ccapi_snapshot.h"
+
+/**
+ * global media cap table for interaction between what platform
+ * can do and the GSM-SDP module
+ * AUDIO_1 is used for audio cannot be turned off
+ * VIDEO_1 is used for video
+ */
+cc_media_cap_table_t g_media_table = {
+ 1,
+ {
+ {CC_AUDIO_1,SDP_MEDIA_AUDIO,TRUE,TRUE,SDP_DIRECTION_RECVONLY},
+ {CC_VIDEO_1,SDP_MEDIA_VIDEO,TRUE,TRUE,SDP_DIRECTION_RECVONLY},
+ {CC_DATACHANNEL_1,SDP_MEDIA_APPLICATION,FALSE,TRUE,SDP_DIRECTION_SENDRECV},
+ }
+};
+
+static boolean g_nativeVidSupported = FALSE;
+static boolean g_vidCapEnabled = FALSE;
+static boolean g_natve_txCap_enabled = FALSE;
+
+/**
+ * Simple method to trigger escalation and deescalation
+ * based on media capability changes
+ */
+void escalateDeescalate() {
+ g_media_table.id++;
+ if ( ccapp_get_state() != CC_INSERVICE ) {
+ VCM_DEBUG(MED_F_PREFIX"Ignoring video cap update\n", "escalateDeescalate");
+ return;
+ }
+
+ //post the event
+ cc_int_feature(CC_SRC_UI, CC_SRC_GSM, CC_NO_CALL_ID,
+ CC_NO_LINE, CC_FEATURE_UPD_MEDIA_CAP, NULL);
+}
+
+cc_boolean cc_media_isTxCapEnabled() {
+ return g_natve_txCap_enabled;
+}
+
+cc_boolean cc_media_isVideoCapEnabled() {
+ if ( g_nativeVidSupported ) {
+ return g_vidCapEnabled;
+ }
+ return FALSE;
+}
+
+/**
+ * API to update the local video cap in the table
+ * called when native video support or vidCap cfg changes
+ *
+ * This method looks at video cap in cfg & native vid support on platform
+ */
+static void updateVidCapTbl(){
+
+ if ( g_vidCapEnabled ) {
+ if ( g_media_table.cap[CC_VIDEO_1].enabled == FALSE ) {
+ // cfg is enabled but cap tbl is not
+ if ( g_nativeVidSupported ) {
+ // we can do native now enable cap
+ g_media_table.cap[CC_VIDEO_1].enabled = TRUE;
+ g_media_table.cap[CC_VIDEO_1].support_direction =
+ g_natve_txCap_enabled?SDP_DIRECTION_SENDRECV:SDP_DIRECTION_RECVONLY;
+ if ( g_natve_txCap_enabled == FALSE ) {
+
+ }
+ escalateDeescalate();
+ } else {
+
+ }
+ }
+ } else {
+ // disable vid cap
+ DEF_DEBUG(MED_F_PREFIX"video capability disabled \n", "updateVidCapTbl");
+
+ if ( g_media_table.cap[CC_VIDEO_1].enabled ) {
+ g_media_table.cap[CC_VIDEO_1].enabled = FALSE;
+ escalateDeescalate();
+ }
+ }
+}
+
+
+/**
+ * API to update video capability on the device
+ * expected to be called once in the beginning only
+ */
+void cc_media_update_native_video_support(boolean val) {
+ DEF_DEBUG(MED_F_PREFIX"Setting native video support val=%d\n", "cc_media_update_native_video_support", val);
+ g_nativeVidSupported = val;
+ updateVidCapTbl();
+}
+
+/**
+ *
+ * API to update video capability on the device based on config
+ */
+void cc_media_update_video_cap(boolean val) {
+ DEF_DEBUG(MED_F_PREFIX"Setting video cap val=%d\n", "cc_media_update_video_cap", val);
+ g_vidCapEnabled = val;
+ updateVidCapTbl();
+ if ( g_nativeVidSupported ) {
+ ccsnap_gen_deviceEvent(CCAPI_DEVICE_EV_VIDEO_CAP_ADMIN_CONFIG_CHANGED, CC_DEVICE_ID);
+ }
+}
+
+/**
+ *
+ * API to update video tx capability based on camera plugin events
+ */
+
+void cc_media_update_native_video_txcap(boolean enable) {
+
+ VCM_DEBUG(MED_F_PREFIX"Setting txcap val=%d\n", "cc_media_update_video_txcap", enable);
+
+ if ( g_natve_txCap_enabled == enable ) {
+ // nothing to do
+ return;
+ }
+
+ g_natve_txCap_enabled = enable;
+ ccsnap_gen_deviceEvent(CCAPI_DEVICE_EV_CAMERA_ADMIN_CONFIG_CHANGED, CC_DEVICE_ID);
+
+ if ( g_nativeVidSupported && g_vidCapEnabled ) {
+ // act on camera events only iof native video is enabled
+ if ( g_natve_txCap_enabled ) {
+
+ } else if (g_media_table.cap[CC_VIDEO_1].enabled) {
+
+ }
+
+ g_media_table.cap[CC_VIDEO_1].support_direction =
+ g_natve_txCap_enabled?SDP_DIRECTION_SENDRECV:SDP_DIRECTION_RECVONLY;
+
+ escalateDeescalate();
+ }
+}
+
+static cc_boolean vidAutoTxPref=FALSE;
+void cc_media_setVideoAutoTxPref(cc_boolean txPref){
+ vidAutoTxPref = txPref;
+}
+
+cc_boolean cc_media_getVideoAutoTxPref(){
+ return vidAutoTxPref;
+}
+
+
diff --git a/libs/sipcc/core/gsm/sm.c b/libs/sipcc/core/gsm/sm.c
new file mode 100755
index 0000000000..80ba7a2f58
--- /dev/null
+++ b/libs/sipcc/core/gsm/sm.c
@@ -0,0 +1,78 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "cpr_stdio.h"
+#include "sm.h"
+#include "gsm.h"
+#include "fsm.h"
+#include "text_strings.h"
+#include "ccapi.h"
+
+sm_rcs_t
+sm_process_event (sm_table_t *tbl, sm_event_t *event)
+{
+ static const char fname[] = "sm_process_event";
+ int state_id = event->state;
+ int event_id = event->event;
+ sm_rcs_t rc = SM_RC_ERROR;
+ fsm_fcb_t *fcb = (fsm_fcb_t *) event->data;
+ cc_feature_t *feat_msg = NULL;
+ line_t line_id;
+ fsm_types_t fsm_type;
+ callid_t call_id;
+ sm_function_t hdlr; /* cached handler in order to compute its addr once */
+
+ /*
+ * validate the state and event
+ * and that there is a valid function for this state-event pair.
+ */
+ if ((state_id > tbl->min_state) &&
+ (state_id < tbl->max_state) &&
+ (event_id > tbl->min_event) &&
+ (event_id < tbl->max_event)) {
+ rc = SM_RC_DEF_CONT;
+ /*
+ * Save some paramters for debuging, the event handler may
+ * free the fcb once returned.
+ */
+ fsm_type = fcb->fsm_type;
+ call_id = fcb->call_id;
+ if ((hdlr = tbl->table[tbl->max_event * state_id + event_id]) != NULL) {
+ FSM_DEBUG_SM(DEB_F_PREFIX"%s %-4d: 0x%08lx: sm entry: (%s:%s)\n",
+ DEB_F_PREFIX_ARGS(FSM, fname), fsm_type_name(fsm_type), call_id,
+ tbl->table[tbl->max_event * state_id + event_id],
+ fsm_state_name(fsm_type, state_id),
+ cc_msg_name((cc_msgs_t)(event_id)));
+
+ rc = hdlr(event);
+ }
+
+ if (rc != SM_RC_DEF_CONT) {
+ /* For event_id == CC_MSG_FEATURE then display the
+ * feature associated with it.
+ */
+ if (event_id == CC_MSG_FEATURE) {
+ feat_msg = (cc_feature_t *) event->msg;
+ }
+ line_id = ((cc_feature_t *) event->msg)->line;
+
+ DEF_DEBUG(DEB_L_C_F_PREFIX"%-5s :(%s:%s%s)\n",
+ DEB_L_C_F_PREFIX_ARGS(GSM, line_id, call_id, fname),
+ fsm_type_name(fsm_type),
+ fsm_state_name(fsm_type, state_id),
+ cc_msg_name((cc_msgs_t)(event_id)),
+ feat_msg ? cc_feature_name(feat_msg->feature_id):" ");
+ }
+ }
+ /*
+ * Invalid state-event pair.
+ */
+ else {
+ GSM_ERR_MSG(GSM_F_PREFIX"illegal state-event pair: (%d <-- %d)\n",
+ fname, state_id, event_id);
+ rc = SM_RC_ERROR;
+ }
+
+ return rc;
+}
diff --git a/libs/sipcc/core/gsm/subapi.c b/libs/sipcc/core/gsm/subapi.c
new file mode 100755
index 0000000000..1dee58fa1e
--- /dev/null
+++ b/libs/sipcc/core/gsm/subapi.c
@@ -0,0 +1,269 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "cpr_types.h"
+#include "cpr_stdio.h"
+#include "cpr_string.h"
+#include "cpr_memory.h"
+#include "cpr_stdlib.h"
+#include "ccapi.h"
+#include "ccsip_task.h"
+#include "debug.h"
+#include "phone_debug.h"
+#include "phntask.h"
+#include "phone.h"
+#include "text_strings.h"
+#include "string_lib.h"
+#include "gsm.h"
+#include "vcm.h"
+#include "subapi.h"
+#include "misc_apps_task.h"
+
+
+static void
+sub_print_msg (char *pData, int len)
+{
+ int ix;
+ int msg_id = *((int *)pData);
+
+ buginf("\nCCAPI: cc_msg= %s, 0x=", cc_msg_name((cc_msgs_t)msg_id));
+ for (ix = 0; ix < len; ix++) {
+ if ((ix % 8 == 0) && ix) {
+ buginf(" ");
+ }
+ if (ix % 24 == 0) {
+ buginf("\n");
+ }
+ buginf("%02x ", *pData++);
+ }
+ buginf("\n");
+}
+
+cc_rcs_t
+sub_send_msg (cprBuffer_t buf, uint32_t cmd, uint16_t len, cc_srcs_t dst_id)
+{
+ cpr_status_e rc;
+
+ CC_DEBUG_MSG sub_print_msg((char *)buf, len);
+
+ switch (dst_id) {
+ case CC_SRC_GSM:
+ rc = gsm_send_msg(cmd, buf, len);
+ if (rc == CPR_FAILURE) {
+ cpr_free(buf);
+ }
+ break;
+ case CC_SRC_SIP:
+ rc = SIPTaskSendMsg(cmd, buf, len, NULL);
+ if (rc == CPR_FAILURE) {
+ cpr_free(buf);
+ }
+ break;
+ case CC_SRC_MISC_APP:
+ rc = MiscAppTaskSendMsg(cmd, buf, len);
+ if (rc == CPR_FAILURE) {
+ cpr_free(buf);
+ }
+ break;
+ default:
+ rc = CPR_FAILURE;
+ break;
+ }
+
+ return (rc == CPR_SUCCESS) ? CC_RC_SUCCESS : CC_RC_ERROR;
+}
+
+cc_rcs_t
+sub_int_subnot_register (cc_srcs_t src_id, cc_srcs_t dst_id,
+ cc_subscriptions_t evt_pkg, void *callback_fun,
+ cc_srcs_t dest_task, int msg_id, void *term_callback,
+ int term_msg_id, long min_duration, long max_duration)
+{
+ sipspi_msg_t *pmsg;
+
+ pmsg = (sipspi_msg_t *) cc_get_msg_buf(sizeof(*pmsg));
+ if (!pmsg) {
+ return CC_RC_ERROR;
+ }
+
+ pmsg->msg.subs_reg.eventPackage = evt_pkg;
+ pmsg->msg.subs_reg.max_duration = max_duration;
+ pmsg->msg.subs_reg.min_duration = min_duration;
+ pmsg->msg.subs_reg.subsIndCallback = (ccsipSubsIndCallbackFn_t)
+ callback_fun;
+ pmsg->msg.subs_reg.subsIndCallbackMsgID = msg_id;
+ pmsg->msg.subs_reg.subsIndCallbackTask = dest_task;
+ pmsg->msg.subs_reg.subsTermCallback = (ccsipSubsTerminateCallbackFn_t)
+ term_callback;
+ pmsg->msg.subs_reg.subsTermCallbackMsgID = term_msg_id;
+
+ return sub_send_msg((cprBuffer_t)pmsg, SIPSPI_EV_CC_SUBSCRIBE_REGISTER,
+ sizeof(*pmsg), dst_id);
+}
+
+/*
+ * Function: sub_int_subscribe()
+ *
+ * Parameters: msg_p - pointer to sipspi_msg_t (input parameter)
+ *
+ * Description: posts SIPSPI_EV_CC_SUBSCRIBE to SIP task message queue.
+ *
+ * Returns: CC_RC_ERROR - failed to post msg.
+ * CC_RC_SUCCESS - successful posted msg.
+ */
+cc_rcs_t
+sub_int_subscribe (sipspi_msg_t *msg_p)
+{
+ sipspi_msg_t *pmsg;
+
+ pmsg = (sipspi_msg_t *) cc_get_msg_buf(sizeof(*pmsg));
+ if (!pmsg) {
+ return CC_RC_ERROR;
+ }
+
+ memcpy(pmsg, msg_p, sizeof(sipspi_msg_t));
+ return sub_send_msg((cprBuffer_t)pmsg, SIPSPI_EV_CC_SUBSCRIBE,
+ sizeof(*pmsg), CC_SRC_SIP);
+}
+
+
+cc_rcs_t
+sub_int_subscribe_ack (cc_srcs_t src_id, cc_srcs_t dst_id, sub_id_t sub_id,
+ uint16_t response_code, int duration)
+{
+ sipspi_msg_t *pmsg;
+
+ pmsg = (sipspi_msg_t *) cc_get_msg_buf(sizeof(*pmsg));
+ if (!pmsg) {
+ return CC_RC_ERROR;
+ }
+
+ pmsg->msg.subscribe_resp.response_code = response_code;
+ pmsg->msg.subscribe_resp.sub_id = sub_id;
+ pmsg->msg.subscribe_resp.duration = duration;
+
+ return sub_send_msg((cprBuffer_t)pmsg, SIPSPI_EV_CC_SUBSCRIBE_RESPONSE,
+ sizeof(*pmsg), dst_id);
+}
+
+
+cc_rcs_t
+sub_int_notify (cc_srcs_t src_id, cc_srcs_t dst_id, sub_id_t sub_id,
+ ccsipNotifyResultCallbackFn_t notifyResultCallback,
+ int subsNotResCallbackMsgID, ccsip_event_data_t * eventData,
+ subscriptionState subState)
+{
+ sipspi_msg_t *pmsg;
+
+ pmsg = (sipspi_msg_t *) cc_get_msg_buf(sizeof(*pmsg));
+ if (!pmsg) {
+ return CC_RC_ERROR;
+ }
+
+ pmsg->msg.notify.eventData = eventData;
+ pmsg->msg.notify.notifyResultCallback = notifyResultCallback;
+ pmsg->msg.notify.sub_id = sub_id;
+ pmsg->msg.notify.subsNotResCallbackMsgID = subsNotResCallbackMsgID;
+ pmsg->msg.notify.subState = subState;
+
+ return sub_send_msg((cprBuffer_t) pmsg, SIPSPI_EV_CC_NOTIFY,
+ sizeof(*pmsg), dst_id);
+}
+
+/*
+ * Function: sub_int_notify_ack()
+ *
+ * Parameters: sub_id - subcription id for sip stack to track the subscription.
+ * response_code - response code to be sent in response to NOTIFY.
+ * cseq : CSeq for which response is being sent.
+ *
+ * Description: posts SIPSPI_EV_CC_NOTIFY_RESPONSE to SIP task message queue.
+ *
+ * Returns: CC_RC_ERROR - failed to post msg.
+ * CC_RC_SUCCESS - successful posted msg.
+ */
+cc_rcs_t
+sub_int_notify_ack (sub_id_t sub_id, uint16_t response_code, uint32_t cseq)
+{
+ sipspi_msg_t *pmsg;
+
+ pmsg = (sipspi_msg_t *) cc_get_msg_buf(sizeof(*pmsg));
+ if (!pmsg) {
+ return CC_RC_ERROR;
+ }
+
+ pmsg->msg.notify_resp.sub_id = sub_id;
+ pmsg->msg.notify_resp.response_code = response_code;
+ pmsg->msg.notify_resp.cseq = cseq;
+
+ return sub_send_msg((cprBuffer_t)pmsg, SIPSPI_EV_CC_NOTIFY_RESPONSE,
+ sizeof(*pmsg), CC_SRC_SIP);
+}
+
+
+/*
+ * Function: sub_int_subscribe_term()
+ *
+ * Parameters: sub_id - subcription id for sip stack to track the subscription.
+ * immediate - boolean flag to indicate if the termination be immediate.
+ * request_id - request id significant for out going subscriptions
+ * event_package - event package type
+ *
+ * Description: posts SIPSPI_EV_CC_SUBSCRIPTION_TERMINATED to SIP task message queue.
+ *
+ * Returns: CC_RC_ERROR - failed to post msg.
+ * CC_RC_SUCCESS - successful posted msg.
+ */
+cc_rcs_t
+sub_int_subscribe_term (sub_id_t sub_id, boolean immediate, int request_id,
+ cc_subscriptions_t event_package)
+{
+ sipspi_msg_t *pmsg;
+
+ pmsg = (sipspi_msg_t *) cc_get_msg_buf(sizeof(*pmsg));
+ if (!pmsg) {
+ return CC_RC_ERROR;
+ }
+
+ pmsg->msg.subs_term.immediate = immediate;
+ pmsg->msg.subs_term.sub_id = sub_id;
+ pmsg->msg.subs_term.request_id = request_id;
+ pmsg->msg.subs_term.eventPackage = event_package;
+
+ return sub_send_msg((cprBuffer_t)pmsg, SIPSPI_EV_CC_SUBSCRIPTION_TERMINATED,
+ sizeof(*pmsg), CC_SRC_SIP);
+}
+
+cc_rcs_t
+sip_send_message (ccsip_sub_not_data_t * msg_data, cc_srcs_t dest_id, int msg_id)
+{
+ ccsip_sub_not_data_t *pmsg;
+
+ pmsg = (ccsip_sub_not_data_t *) cc_get_msg_buf(sizeof(*pmsg));
+
+ if (!pmsg) {
+ return CC_RC_ERROR;
+ }
+
+ memcpy(pmsg, msg_data, sizeof(*pmsg));
+
+ return sub_send_msg((cprBuffer_t)pmsg, msg_id, sizeof(*pmsg), dest_id);
+}
+
+
+cc_rcs_t
+app_send_message (void *msg_data, int msg_len, cc_srcs_t dest_id, int msg_id)
+{
+ void *pmsg;
+
+ pmsg = (void *) cc_get_msg_buf(msg_len);
+
+ if (!pmsg) {
+ return CC_RC_ERROR;
+ }
+
+ memcpy(pmsg, msg_data, msg_len);
+
+ return sub_send_msg((cprBuffer_t)pmsg, msg_id, (uint16_t)msg_len, dest_id);
+}
diff --git a/libs/sipcc/core/includes/CSFLog.h b/libs/sipcc/core/includes/CSFLog.h
new file mode 100644
index 0000000000..ea02257556
--- /dev/null
+++ b/libs/sipcc/core/includes/CSFLog.h
@@ -0,0 +1,46 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef CSFLOG_H
+#define CSFLOG_H
+
+#include
+
+typedef enum{
+ CSF_LOG_CRITICAL =1,
+ CSF_LOG_ERROR,
+ CSF_LOG_WARNING,
+ CSF_LOG_NOTICE,
+ CSF_LOG_INFO,
+ CSF_LOG_DEBUG
+} CSFLogLevel;
+
+
+
+#define CSFLogError(tag , format, ...) CSFLog( CSF_LOG_ERROR, __FILE__ , __LINE__ , tag , format , ## __VA_ARGS__ )
+#define CSFLogErrorV(tag , format, va_list_arg) CSFLogV(CSF_LOG_ERROR, __FILE__ , __LINE__ , tag , format , va_list_arg )
+#define CSFLogWarn(tag , format, ...) CSFLog( CSF_LOG_WARNING, __FILE__ , __LINE__ , tag , format , ## __VA_ARGS__ )
+#define CSFLogWarnV(tag , format, va_list_arg) CSFLogV(CSF_LOG_WARNING, __FILE__ , __LINE__ , tag , format , va_list_arg )
+#define CSFLogInfo(tag , format, ...) CSFLog( CSF_LOG_INFO, __FILE__ , __LINE__ , tag , format , ## __VA_ARGS__ )
+#define CSFLogInfoV(tag , format, va_list_arg) CSFLogV(CSF_LOG_INFO, __FILE__ , __LINE__ , tag , format , va_list_arg )
+#define CSFLogDebug(tag , format, ...) CSFLog(CSF_LOG_DEBUG, __FILE__ , __LINE__ , tag , format , ## __VA_ARGS__ )
+#define CSFLogDebugV(tag , format, va_list_arg) CSFLogV(CSF_LOG_DEBUG, __FILE__ , __LINE__ , tag , format , va_list_arg )
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+#if 0
+void CSFLog( CSFLogLevel priority, const char* sourceFile, int sourceLine, const char* tag , const char* format, ...);
+void CSFLogV( CSFLogLevel priority, const char* sourceFile, int sourceLine, const char* tag , const char* format, va_list args);
+#else
+#endif
+#define CSFLog(pri, file, line, tag, format, ...)
+#define CSFLogV(pri, file, line, tag, format, args)
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/libs/sipcc/core/includes/ccSession.h b/libs/sipcc/core/includes/ccSession.h
new file mode 100755
index 0000000000..398f4976a3
--- /dev/null
+++ b/libs/sipcc/core/includes/ccSession.h
@@ -0,0 +1,207 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _CCSESSION_H_
+#define _CCSESSION_H_
+
+#include "session.h"
+#include "sessuri.h"
+
+#define SID_TYPE_SHIFT 28
+#define SID_LINE_SHIFT 16
+
+#define GET_SESS_TYPE(x) ( (x & 0xF0000000) >> SID_TYPE_SHIFT )
+#define GET_LINEID(x) (line_t)( (x & 0xFFF0000) >> SID_LINE_SHIFT )
+#define GET_CALLID(x) (callid_t)(x & 0xFFFF)
+
+
+
+
+/**
+ * ccSessionProviderCmd
+ * CallControl Provider Management Interface
+ * Called by Application to issue cmds to sipStack
+ *
+ * @param data - command and data
+ * data->cmd - see Session Provider Commands in session.h
+ * data->cmdData.ccData.reason - reason for SHUTDOWN/UNREGISTER_ALL_LINES CMD
+ CC_CAUSE_NORMAL/CC_CAUSE_NONE
+ * data->cmdData.ccData.reason_info - Descriptive stringa "notused"
+ *
+ * @return none
+ *
+ */
+void ccSessionProviderCmd(sessionProvider_cmd_t *data);
+
+
+/**
+ * ccSessionProviderState
+ * Method to report provider state updates to Application
+ *
+ * @param state - indicates the Session Provider state CCApp_states_t
+ * @param data - ccProvider_state_t indicating
+ * data->stateData.ccData.mode - REGMODE CCM
+ * data->stateData.ccData.cause - FAILOVER/FALLBACK
+ *
+ * @return none
+ *
+ */
+void ccSessionProviderState(unsigned int state, ccProvider_state_t *data);
+
+
+/**
+ * ccSessionCmd
+ * Method to Handle session lifecycle command such as realize, start etc.
+ *
+ * @param sCmd - session liefcycle command
+ * sCmd->cmd - REQUEST CMD
+ * sCmd->sessID - session ID
+ *
+ * @return none
+ *
+ */
+
+void ccSessionCmd (sessionCmd_t *sCmd);
+
+
+/**
+ * ccCreateSession
+ *
+ * Called by Application to create a new session
+ *
+ * @param param - uri_t
+ * param->param.call_session_param.line_id - line on which to create the session
+ * @return ccSession_id_t - id of the session created
+ */
+
+session_id_t ccCreateSession(uri_t *param);
+
+/**
+ * ccCloseSession
+ *
+ * Called by Application to close a session
+ *
+ * @param sess_id - ID of the session to be closed
+ *
+ * @return 0 success -1 failure
+ *
+ */
+
+int ccCloseSession(session_id_t sess_id);
+
+/* Need to document IDs and data for the following 4 methods */
+
+/**
+ * ccInvokeFeature
+ *
+ * Called by Application to invoke feature on session
+ *
+ * @param featData - featID and Additional info if needed for the feature
+ *
+ * @return none
+ *
+ */
+
+void ccInvokeFeature(session_feature_t *featData);
+
+/**
+ * ccInvokeProviderFeature
+ *
+ * Called by Application to invoke device specific features
+ *
+ * @param featData - Additional info if needed for the feature
+ *
+ * @return none
+ *
+ */
+
+void ccInvokeProviderFeature(session_feature_t *featData);
+
+
+/**
+ * ccSessionUpdate
+ *
+ * Called by sipstack to update session state and data
+ *
+ * @param eventID - ID of the event updating the session data
+ * @param session_data - event specific data
+ *
+ * @return none
+ *
+ */
+
+void ccSessionUpdate(session_update_t *session);
+
+
+
+/**
+ * ccFeatureUpdate
+ *
+ * Called by sipstack to update feature state and data
+ *
+ * @param featureID - ID of the feature updated
+ * @param session_data - feature specific data
+ *
+ * @return none
+ *
+ */
+
+void ccFeatureUpdate(feature_update_t *session);
+
+/***** Internal APIs below this line ***************/
+
+/**
+ * ccCreateSession
+ *
+ * Called to create a CC session
+ *
+ * @param param - ccSession_create_param_t
+ * Contains the type of session and specific data
+ *
+ * @return ccSession_id_t - id of the session created
+ */
+session_id_t createSessionId(line_t line, callid_t call);
+
+void platform_sync_cfg_vers (char *cfg_ver, char *dp_ver, char *softkey_ver);
+/********************************************************************************/
+
+/* Misc getter/setter function to get set the following */
+
+#define PROPERTY_ID_MWI 1 // per line
+#define PROPERTY_ID_TIME 2 // unsigned long
+#define PROPERTY_ID_KPML 3
+#define PROPERTY_ID_REGREASON 4
+#define PROPERTY_ID_SPKR_HDST 5 1
+
+void setIntProperty(unsigned int id, int val);
+int getIntProperty(unsigned int id);
+void setStrProperty(unsigned int id, char * val);
+char * getStrProperty(unsigned int id);
+
+
+/* Preserved API's from TNP Platform */
+char *ccSetDP(const char *dp_file_name);
+// update_label_n_speed_dial method here
+void setPropertyCacheBoolean(int cfg_id, int bool_value);
+void setPropertyCacheInteger(int cfg_id, int int_value);
+void setPropertyCacheString(int cfg_id, const char *string_value);
+void setPropertyCacheByte(int cfg_id, char byte_value);
+void setPropertyCacheByteArray(int cfg_id, char *byte_value, int length);
+
+/* BLF */
+void ccBLFSubscribe(int request_id, int duration, const char *watcher,
+ const char *presentity, int app_id, int feature_mask);
+void ccBLFUnsubscribe(int request_id);
+void ccBLFUnsubscribeAll();
+void blf_notification(int request_id, int status, int app_id);
+
+
+/**********************************************************************
+
+MID_JPlatUi_ui_log_status_msg, Ask RCDN team if log is changing?
+
+**********************************************************************/
+
+#endif
+
diff --git a/libs/sipcc/core/includes/ccapi.h b/libs/sipcc/core/includes/ccapi.h
new file mode 100755
index 0000000000..011b57e8fb
--- /dev/null
+++ b/libs/sipcc/core/includes/ccapi.h
@@ -0,0 +1,1578 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _CCAPI_H_
+#define _CCAPI_H_
+
+//#include "prtypes.h"
+#include "cpr_types.h"
+#include "cpr_memory.h"
+#include "phone_types.h"
+#include "string_lib.h"
+#include "vcm.h"
+#include "sdp.h"
+#include "cc_constants.h"
+
+typedef unsigned int cc_security_e;
+typedef unsigned int cc_select_state_e;
+typedef unsigned int cc_call_type_e;
+typedef unsigned int cc_policy_e;
+typedef int cc_causes_t;
+#define CC_CALL_OUTGOMING CC_CALL_TYPE_OUTGOING
+#define CC_CALL_FORWARDED CC_CALL_TYPE_FORWARDED
+#define CC_CALL_NONE CC_CALL_TYPE_NONE
+#define CC_CALL_INCOMING CC_CALL_TYPE_INCOMING
+#define SDP_SIZE 4096 /* must increase this */
+#define CANDIDATE_SIZE 150
+#define MID_SIZE 150
+
+#include "sessionConstants.h"
+
+typedef int cc_features_t;
+typedef unsigned int softkey_events;
+typedef unsigned int cc_call_priority_e;
+extern cc_reg_state_t ccapp_get_state();
+
+/* Session FEATURES */
+/* please update cc_feature_names whenever this enum list is changed */
+
+typedef enum {
+ CC_FEATURE_MIN = -1L,
+ CC_FEATURE_NONE,
+ CC_FEATURE_HOLD = 1L,
+ CC_FEATURE_RESUME,
+ CC_FEATURE_OFFHOOK,
+ CC_FEATURE_NEW_CALL,
+ CC_FEATURE_REDIAL,
+ CC_FEATURE_ONHOOK,
+ CC_FEATURE_KEYPRESS,
+ CC_FEATURE_DIAL,
+ CC_FEATURE_XFER,
+ CC_FEATURE_CFWD_ALL,
+ CC_FEATURE_END_CALL,
+ CC_FEATURE_ANSWER,
+ CC_FEATURE_INFO,
+ CC_FEATURE_CONF,
+ CC_FEATURE_JOIN,
+ CC_FEATURE_DIRTRXFR,
+ CC_FEATURE_SELECT,
+ CC_FEATURE_SPEEDDIAL,
+ CC_FEATURE_SWAP,
+ CC_FEATURE_SPEEDDIAL_BLF,
+ CC_FEATURE_BLIND_XFER_WITH_DIALSTRING,
+ CC_FEATURE_BKSPACE,
+ CC_FEATURE_CANCEL,
+ CC_FEATURE_DIALSTR,
+ CC_FEATURE_UPD_SESSION_MEDIA_CAP,
+ /* Not used in the session API */
+ CC_FEATURE_MEDIA,
+ CC_FEATURE_UPDATE,
+ CC_FEATURE_CALLINFO,
+ CC_FEATURE_BLIND_XFER,
+ CC_FEATURE_NOTIFY,
+ CC_FEATURE_SUBSCRIBE,
+ CC_FEATURE_B2BCONF,
+ CC_FEATURE_B2B_JOIN,
+ CC_FEATURE_HOLD_REVERSION,
+ CC_FEATURE_BLF_ALERT_TONE,
+ CC_FEATURE_REQ_PEND_TIMER_EXP,
+ CC_FEATURE_NUMBER,
+ CC_FEATURE_URL,
+ CC_FEATURE_REDIRECT,
+ CC_FEATURE_RINGBACK_DELAY_TIMER_EXP,
+ CC_FEATURE_CALL_PRESERVATION,
+ CC_FEATURE_UPD_MEDIA_CAP,
+ CC_FEATURE_CAC_RESP_PASS,
+ CC_FEATURE_CAC_RESP_FAIL,
+ CC_FEATURE_FAST_PIC_UPD,
+ CC_FEATURE_UNDEFINED,
+ CC_FEATURE_CREATEOFFER,
+ CC_FEATURE_CREATEANSWER,
+ CC_FEATURE_SETLOCALDESC,
+ CC_FEATURE_SETREMOTEDESC,
+ CC_FEATURE_LOCALDESC,
+ CC_FEATURE_REMOTEDESC,
+ CC_FEATURE_SETPEERCONNECTION,
+ CC_FEATURE_ADDSTREAM,
+ CC_FEATURE_REMOVESTREAM,
+ CC_FEATURE_ADDICECANDIDATE,
+ CC_FEATURE_MAX
+} group_cc_feature_t;
+
+#define skNewCall CC_FEATURE_NEW_CALL
+#define skConfrn CC_FEATURE_CONF
+
+/* please update the following cc_feature_names whenever this feature list is changed */
+
+#ifdef __CC_FEATURE_STRINGS__
+static const char *cc_feature_names[] = {
+ "NONE",
+ "HOLD",
+ "RESUME",
+ "OFFHOOK",
+ "NEW_CALL",
+ "REDIAL",
+ "ONHOOK",
+ "KEYPRESS",
+ "DIAL",
+ "XFER",
+ "CFWD_ALL", //10
+ "END_CALL",
+ "ANSWER",
+ "INFO",
+ "CONF",
+ "JOIN",
+ "DIR_XFER",
+ "SELECT",
+ "SPEEDDIAL",
+ "SWAP",
+ "SDBLF", //45
+ "BLIND_XFER_WITH_DIALSTRING",
+ "BSPACE",
+ "CANCEL",
+ "DIALSTR",
+ "UPD_SESSION_MEDIA_CAP",
+ "NEW_MEDIA",
+ "UPDATE",
+ "CALLINFO",
+ "BLIND_XFER",
+ "NOTIFY",
+ "SUBSCRIBE",
+ "B2BCONF",
+ "B2BJOIN",
+ "HOLD_REVERSION", //jni_max + 10
+ "BLF_ALERT_TONE",
+ "REQPENDTMREXP",
+ "NUMBER",
+ "URL",
+ "REDIRECT", //jni_max + 20
+ "RINGBACKDELAYTMREXP",
+ "CALL_PRESERVATION",
+ "UPD_MEDIA_CAP",
+ "CAC PASSED",
+ "CAC FAILED",
+ "FAST_PIC_UPD",
+ "UNDEFINED",
+ "CREATEOFFER",
+ "CREATEANSWER",
+ "SETLOCALDESC",
+ "SETREMOTEDESC",
+ "LOCALDESC",
+ "REMOTEDESC",
+ "SETPEERCONNECTION",
+ "ADDSTREAM",
+ "REMOVESTREAM",
+ "ADDICECANDIDATE",
+ "MAX"
+};
+
+/* This checks at compile-time that the cc_feature_names list
+ * is the same size as the cc_group_feature_t enum
+ */
+//PR_STATIC_ASSERT(PR_ARRAY_SIZE(cc_feature_names) == CC_FEATURE_MAX + 1);
+
+#endif
+
+/*
+ * Constants
+ */
+#define CC_MAX_DIALSTRING_LEN (512)
+#define CC_MAX_MEDIA_TYPES (15)
+#define CC_MAX_MEDIA_CAP (4)
+#define CC_NO_CALL_ID (0)
+#define CC_NO_LINE (0)
+#define CC_NO_DATA (NULL)
+#define CC_NO_MEDIA_REF_ID (0)
+#define CC_MAX_REDIRECTS (1)
+#define CC_MAX_BODY_PARTS 3
+#define CC_NO_GROUP_ID (0)
+#define CC_NO_CALL_INST_ID (0)
+#define CC_SHORT_DIALSTRING_LEN (64)
+#define CC_CISCO_PLAR_STRING "x-cisco-serviceuri-offhook"
+#define CISCO_BLFPICKUP_STRING "x-cisco-serviceuri-blfpickup"
+#define JOIN_ACROSS_LINES_DISABLED 0
+#define CC_MAX_TRACKS 8 // query this figure
+#define CC_MAX_STREAMS 2 // TODO: expand signaling to handle more than one of each a/v.
+
+
+/*
+ *
+ * Support type definintions
+ *
+ */
+typedef enum cc_rcs_t_ {
+ CC_RC_MIN = -1,
+ CC_RC_SUCCESS,
+ CC_RC_ERROR,
+ CC_RC_MAX
+} cc_rcs_t;
+
+typedef enum cc_msgs_t_ {
+ CC_MSG_MIN = -1,
+ CC_MSG_SETUP,
+ CC_MSG_SETUP_ACK,
+ CC_MSG_PROCEEDING,
+ CC_MSG_ALERTING,
+ CC_MSG_CONNECTED,
+ CC_MSG_CONNECTED_ACK,
+ CC_MSG_RELEASE,
+ CC_MSG_RELEASE_COMPLETE,
+ CC_MSG_FEATURE,
+ CC_MSG_FEATURE_ACK,
+ CC_MSG_OFFHOOK,
+ CC_MSG_ONHOOK,
+ CC_MSG_LINE,
+ CC_MSG_DIGIT_BEGIN,
+ CC_MSG_DIGIT_END,
+ CC_MSG_DIALSTRING,
+ CC_MSG_MWI,
+ CC_MSG_AUDIT,
+ CC_MSG_CREATEOFFER,
+ CC_MSG_CREATEANSWER,
+ CC_MSG_SETLOCALDESC,
+ CC_MSG_SETREMOTEDESC,
+ CC_MSG_REMOTEDESC,
+ CC_MSG_LOCALDESC,
+ CC_MSG_SETPEERCONNECTION,
+ CC_MSG_ADDSTREAM,
+ CC_MSG_REMOVESTREAM,
+ CC_MSG_ADDCANDIDATE,
+ CC_MSG_AUDIT_ACK,
+ CC_MSG_OPTIONS,
+ CC_MSG_OPTIONS_ACK,
+ CC_MSG_SUBSCRIBE,
+ CC_MSG_NOTIFY,
+ CC_MSG_FAILOVER_FALLBACK,
+ CC_MSG_INFO,
+ /* update the following strings table if this is changed */
+ CC_MSG_MAX
+} cc_msgs_t;
+
+#ifdef __CC_MESSAGES_STRINGS__
+static const char *cc_msg_names[] = {
+ "SETUP",
+ "SETUP_ACK",
+ "PROCEEDING",
+ "ALERTING",
+ "CONNECTED",
+ "CONNECTED_ACK",
+ "RELEASE",
+ "RELEASE_COMPLETE",
+ "FEAT:",
+ "FEATURE_ACK",
+ "OFFHOOK",
+ "ONHOOK",
+ "LINE",
+ "DIGIT_BEGIN",
+ "DIGIT_END",
+ "DIALSTRING",
+ "MWI",
+ "AUDIT",
+ "CREATEOFFER",
+ "CREATEANSWER",
+ "SETLOCALDESC",
+ "SETREMOTEDESC",
+ "REMOTEDESC",
+ "LOCALDESC",
+ "SETPEERCONNECTION",
+ "ADDSTREAM",
+ "REMOVESTREAM",
+ "ADDCANDIDATE",
+ "AUDIT_ACK",
+ "OPTIONS",
+ "OPTIONS_ACK",
+ "SUBSCRIBE",
+ "NOTIFY",
+ "FAILOVER_FALLBACK",
+ "INFO",
+ "INVALID",
+};
+
+/* This checks at compile-time that the cc_msg_names list
+ * is the same size as the cc_msgs_t enum
+ */
+//PR_STATIC_ASSERT(PR_ARRAY_SIZE(cc_msg_names) == CC_MSG_MAX + 1);
+
+#endif //__CC_MESSAGES_STRINGS__
+
+typedef enum cc_srcs_t_ {
+ CC_SRC_MIN = -1,
+ CC_SRC_GSM,
+ CC_SRC_UI,
+ CC_SRC_SIP,
+ CC_SRC_MISC_APP,
+ CC_SRC_RCC,
+ CC_SRC_CCAPP,
+ CC_SRC_MAX
+} cc_srcs_t;
+
+
+typedef enum cc_transfer_mode_e_ {
+ CC_XFR_MODE_MIN = -1,
+ CC_XFR_MODE_NONE,
+ CC_XFR_MODE_TRANSFEROR,
+ CC_XFR_MODE_TRANSFEREE,
+ CC_XFR_MODE_TARGET,
+ CC_XFR_MODE_MAX
+} cc_transfer_mode_e;
+
+typedef enum cc_regmgr_rsp_type_e_ {
+ CC_FAILOVER_RSP=0,
+ CC_RSP_START =1,
+ CC_RSP_COMPLETE=2
+} cc_regmgr_rsp_type_e;
+
+typedef enum cc_regmgr_rsp_e_ {
+ CC_REG_FAILOVER_RSP,
+ CC_REG_FALLBACK_RSP
+} cc_regmgr_rsp_e;
+
+/*
+ * Identifies what was in the Alert-Info header
+ */
+typedef enum {
+ ALERTING_NONE, /* No alert-info header present */
+ ALERTING_OLD, /* Unrecognized pattern or an error, mimic old behavior */
+ ALERTING_TONE, /* Play tone */
+ ALERTING_RING /* Play ringing pattern */
+} cc_alerting_type;
+
+typedef enum {
+ CC_MONITOR_NONE = 0,
+ CC_MONITOR_SILENT = 1,
+ CC_MONITOR_COACHING = 2
+} monitor_mode_t;
+
+typedef enum {
+ CFWDALL_NONE = -1,
+ CFWDALL_CLEAR,
+ CFWDALL_SET
+} cfwdall_mode_t;
+
+/* Do not change enum values unless remote-cc xml has been changed */
+
+typedef enum {
+ CC_RING_DEFAULT = 0,
+ CC_RING_ENABLE = 1,
+ CC_RING_DISABLE = 2
+} cc_rcc_ring_mode_e;
+
+/* Do not change enum values unless remote-cc xml has been changed */
+
+typedef enum {
+ CC_SK_EVT_TYPE_DEF = 0,
+ CC_SK_EVT_TYPE_EXPLI = CC_SK_EVT_TYPE_DEF,
+ CC_SK_EVT_TYPE_IMPLI = 1
+} cc_rcc_skey_evt_type_e;
+
+/* media name with media capability table */
+typedef enum {
+ CC_AUDIO_1,
+ CC_VIDEO_1,
+ CC_DATACHANNEL_1,
+} cc_media_cap_name;
+
+typedef struct cc_sdp_addr_t_ {
+ cpr_ip_addr_t addr;
+ unsigned int port;
+} cc_sdp_addr_t;
+
+typedef struct cc_sdp_data_t_ {
+ cc_sdp_addr_t addr;
+ int media_types[CC_MAX_MEDIA_TYPES];
+ int32_t avt_payload_type;
+} cc_sdp_data_t;
+
+typedef struct cc_sdp_t_ {
+ sdp_t *src_sdp; /* pointer to source SDP */
+ sdp_t *dest_sdp; /* pointer to received SDP */
+} cc_sdp_t;
+
+typedef enum
+{
+ cc_disposition_unknown = 0,
+ cc_disposition_render,
+ cc_disposition_session,
+ cc_dispostion_icon,
+ cc_disposition_alert,
+ cc_disposition_precondition
+} cc_disposition_type_t;
+
+typedef struct
+{
+ cc_disposition_type_t disposition;
+ boolean required_handling;
+} cc_content_disposition_t;
+
+typedef enum
+{
+ cc_content_type_unknown = 0,
+ cc_content_type_SDP,
+ cc_content_type_sipfrag,
+ cc_content_type_CMXML
+} cc_content_type_t;
+
+typedef struct cc_msgbody_t_ {
+ cc_content_type_t content_type;
+ cc_content_disposition_t content_disposition;
+ uint32_t body_length;
+ char *body;
+ char *content_id;
+} cc_msgbody_t;
+
+typedef struct cc_msgbody_info_t_ {
+ uint32_t num_parts; /* number of body parts */
+ cc_content_type_t content_type; /* top level content type */
+ cc_msgbody_t parts[CC_MAX_BODY_PARTS]; /* parts */
+} cc_msgbody_info_t;
+
+/*
+ * Message definitions
+ */
+
+typedef enum cc_redirect_reasons_t {
+ CC_REDIRECT_REASON_MIN = -1,
+ CC_REDIRECT_REASON_NONE,
+ CC_REDIRECT_REASON_BUSY,
+ CC_REDIRECT_REASON_NOANSWER,
+ CC_REDIRECT_REASON_UNCONDITIONAL,
+ CC_REDIRECT_REASON_DEFLECTION,
+ CC_REDIRECT_REASON_UNAVAILABLE
+} cc_redirect_reasons_t;
+
+typedef struct cc_redirect_t_ {
+ int count;
+ struct {
+ char number[CC_MAX_DIALSTRING_LEN];
+ cc_redirect_reasons_t redirect_reason;
+ } redirects[CC_MAX_REDIRECTS];
+} cc_redirect_t;
+
+typedef enum {
+ CC_FEAT_NONE,
+ CC_FEAT_HOLD,
+ CC_FEAT_RESUME,
+ CC_FEAT_BARGE,
+ CC_FEAT_CBARGE,
+ CC_FEAT_REPLACE,
+ CC_FEAT_CALLINFO,
+ CC_FEAT_INIT_CALL,
+ CC_FEAT_MONITOR,
+ CC_FEAT_TOGGLE_TO_SILENT_MONITORING,
+ CC_FEAT_TOGGLE_TO_WHISPER_COACHING
+} cc_call_info_e;
+
+typedef enum {
+ CC_REASON_NONE,
+ CC_REASON_XFER,
+ CC_REASON_CONF,
+ CC_REASON_SWAP,
+ CC_REASON_RCC,
+ CC_REASON_INTERNAL,
+ CC_REASON_MONITOR_UPDATE
+} cc_hold_resume_reason_e;
+
+typedef enum {
+ CC_PURPOSE_NONE,
+ CC_PURPOSE_INFO,
+ CC_PURPOSE_ICON,
+ CC_PURPOSE_CARD
+} cc_purpose_e;
+
+typedef enum {
+ CC_ORIENTATION_NONE = CC_CALL_TYPE_NONE,
+ CC_ORIENTATION_FROM = CC_CALL_TYPE_INCOMING,
+ CC_ORIENTATION_TO = CC_CALL_TYPE_OUTGOING
+} cc_orientation_e;
+
+typedef enum {
+ CC_UI_STATE_NONE,
+ CC_UI_STATE_RINGOUT,
+ CC_UI_STATE_CONNECTED,
+ CC_UI_STATE_BUSY
+} cc_ui_state_e;
+
+typedef enum {
+ CC_REASON_NULL,
+ CC_REASON_ACTIVECALL_LIST
+} cc_onhook_reason_e;
+
+typedef enum {
+ CC_CALL_LOG_DISP_MISSED,
+ CC_CALL_LOG_DISP_RCVD,
+ CC_CALL_LOG_DISP_PLACED,
+ CC_CALL_LOG_DISP_UNKNWN,
+ CC_CALL_LOG_DISP_IGNORE
+} cc_call_logdisp_e;
+
+/*
+ * The cc_caller_id_t structure contains caller IDs fields.
+ * Sending these fields accross components needs special care.
+ * There are CCAPI API that provide access or transport these fields
+ * by the source or by the destination. Any new caller IDs added,
+ * please update the APIs in ccapi.c to support the new fields.
+ * See cc_cp_caller(), cc_mv_caller_id() and cc_free_caller_id() functions.
+ */
+// mostly overlap with sessionTypes.h:cc_callinfo_t
+typedef struct cc_caller_id_t_ {
+ string_t calling_name;
+ string_t calling_number;
+ string_t alt_calling_number;
+ boolean display_calling_number;
+ string_t called_name;
+ string_t called_number;
+ boolean display_called_number;
+ string_t orig_called_name;
+ string_t orig_called_number;
+ string_t last_redirect_name;
+ string_t last_redirect_number;
+ string_t orig_rpid_number;
+ cc_call_type_e call_type;
+ uint16_t call_instance_id;
+} cc_caller_id_t;
+
+/*
+ * The followings are definitions of bits in the feature_flag of the
+ * cc_feature_data_call_info_t strucure.
+ *
+ * The CC_DELAY_UI_UPDATE flag is not related to call information but
+ * it indicates that the call info event signaled by SIP stack
+ * to GSM that UI update can be delayed due to media manipulation
+ * event will follow. This allows GSM to defer UI update to after the
+ * media manipulation event.
+ */
+#define CC_SECURITY 1
+#define CC_ORIENTATION (1<<1)
+#define CC_UI_STATE (1<<2)
+#define CC_CALLER_ID (1<<3)
+#define CC_CALL_INSTANCE (1<<4)
+#define CC_DELAY_UI_UPDATE (1<<5)
+#define CC_POLICY (1<<6)
+
+typedef struct cc_feature_data_call_info_t_{
+ uint16_t feature_flag;
+ cc_security_e security;
+ cc_policy_e policy;
+ cc_orientation_e orientation;
+ cc_ui_state_e ui_state;
+ cc_caller_id_t caller_id;
+ cc_call_priority_e priority;
+ boolean swap; //Indicate if hold/resume is because of swap
+ boolean protect; //indicate if the call has to be protected
+ boolean dusting; //indicate if it is a dusting call
+ uint32_t callref;
+ char global_call_id[CC_GCID_LEN];
+} cc_feature_data_call_info_t;
+
+typedef struct cc_replace_info_t_ {
+ callid_t remote_call_id; /* remote call ID to replace */
+} cc_replace_info_t;
+
+typedef struct cc_join_info_t_ {
+ callid_t join_call_id;
+} cc_join_info_t;
+
+typedef struct cc_initcall_t {
+ char gcid[CC_GCID_LEN]; // Global call id used for CTI
+ monitor_mode_t monitor_mode;
+} cc_initcall_t;
+
+typedef union {
+ cc_initcall_t initcall;
+ cc_hold_resume_reason_e hold_resume_reason;
+ cc_feature_data_call_info_t call_info_feat_data;
+ cc_purpose_e purpose; // Used for Barge, CBARGE
+ cc_replace_info_t replace;
+ cc_join_info_t join;
+} cc_call_info_data_t;
+
+typedef struct {
+ cc_call_info_data_t data;
+ cc_call_info_e type;
+} cc_call_info_t;
+
+typedef enum cc_xfer_methods_t_ {
+ CC_XFER_METHOD_MIN = -1,
+ CC_XFER_METHOD_NONE,
+ CC_XFER_METHOD_BYE,
+ CC_XFER_METHOD_REFER,
+ CC_XFER_METHOD_DIRXFR,
+ CC_RCC_METHOD_REFER,
+ CC_XFER_METHOD_MAX
+} cc_xfer_methods_t;
+
+typedef enum cc_subscriptions_t_ {
+ CC_SUBSCRIPTIONS_MIN = -1,
+ CC_SUBSCRIPTIONS_NONE,
+ CC_SUBSCRIPTIONS_XFER,
+ CC_SUBSCRIPTIONS_DIALOG = CC_SUBSCRIPTIONS_DIALOG_EXT,
+ CC_SUBSCRIPTIONS_CONFIG,
+ CC_SUBSCRIPTIONS_KPML = CC_SUBSCRIPTIONS_KPML_EXT,
+ CC_SUBSCRIPTIONS_PRESENCE = CC_SUBSCRIPTIONS_PRESENCE_EXT,
+ CC_SUBSCRIPTIONS_REMOTECC = CC_SUBSCRIPTIONS_REMOTECC_EXT,
+ CC_SUBSCRIPTIONS_REMOTECC_OPTIONSIND = CC_SUBSCRIPTIONS_REMOTECC_OPTIONSIND_EXT,
+ CC_SUBSCRIPTIONS_CONFIGAPP = CC_SUBSCRIPTIONS_CONFIGAPP_EXT,
+ CC_SUBSCRIPTIONS_MEDIA_INFO = CC_SUBSCRIPTIONS_MEDIA_INFO_EXT,
+ CC_SUBSCRIPTIONS_MAX
+} cc_subscriptions_t;
+
+typedef struct cc_feature_data_newcall_t_ {
+ char dialstring[CC_MAX_DIALSTRING_LEN];
+ cc_causes_t cause;
+ cc_redirect_t redirect;
+ cc_replace_info_t replace;
+ cc_join_info_t join;
+ char global_call_id[CC_GCID_LEN];
+ callid_t prim_call_id; /* For internal new call event
+ * refer primary call's call_id
+ */
+ cc_hold_resume_reason_e hold_resume_reason; /* Reason for new consult call */
+} cc_feature_data_newcall_t;
+
+typedef struct cc_feature_data_xfer_t_ {
+ cc_causes_t cause;
+ char dialstring[CC_MAX_DIALSTRING_LEN];
+ char referred_by[CC_MAX_DIALSTRING_LEN];
+ cc_xfer_methods_t method;
+ callid_t target_call_id;
+ char global_call_id[CC_GCID_LEN];
+} cc_feature_data_xfer_t;
+
+typedef enum cc_app_type_t_ {
+ CC_APP_MIN = -1,
+ CC_APP_NONE,
+ CC_APP_CMXML,
+ CC_APP_REMOTECC,
+ CC_APP_MAX
+} cc_app_type_t;
+
+typedef struct cc_refer_body_t_ {
+ struct cc_refer_body_t_ *next;
+ char refer_body[200];
+ int refer_body_len;
+ cc_app_type_t app_type;
+} cc_refer_body_t;
+
+typedef struct cc_feature_data_ind_t__ {
+ cc_causes_t cause;
+ char to[CC_MAX_DIALSTRING_LEN];
+ char referred_by[CC_MAX_DIALSTRING_LEN];
+ char referred_to[CC_MAX_DIALSTRING_LEN];
+ cc_refer_body_t refer_body;
+} cc_feature_data_ind_t;
+
+typedef struct cc_feature_data_endcall_t_ {
+ cc_causes_t cause;
+ char dialstring[CC_MAX_DIALSTRING_LEN];
+} cc_feature_data_endcall_t;
+
+typedef struct cc_kfact_t {
+ char rxstats[CC_KFACTOR_STAT_LEN];
+ char txstats[CC_KFACTOR_STAT_LEN];
+} cc_kfact_t;
+
+typedef struct cc_feature_data_hold_t_ {
+ cc_msgbody_info_t msg_body;
+ cc_call_info_t call_info;
+ cc_kfact_t kfactor;
+} cc_feature_data_hold_t;
+
+typedef struct cc_feature_data_hold_reversion_t_ {
+ int alertInterval;
+} cc_feature_data_hold_reversion_t;
+
+typedef struct cc_feature_data_resume_t_ {
+ cc_causes_t cause;
+ cc_msgbody_info_t msg_body;
+ cc_call_info_t call_info;
+ cc_kfact_t kfactor;
+} cc_feature_data_resume_t;
+
+typedef struct cc_feature_data_redirect_t_ {
+ char redirect_number[CC_MAX_DIALSTRING_LEN];
+ cc_redirect_t redirect;
+} cc_feature_data_redirect_t;
+
+typedef struct cc_feature_data_subscribe_t_ {
+ cc_subscriptions_t event_package;
+ boolean subscribe;
+ char subscribe_uri[CC_MAX_DIALSTRING_LEN];
+ cc_srcs_t component;
+ int component_id;
+ int *callBack;
+} cc_feature_data_subscribe_t;
+
+typedef enum cc_dialog_lock_e_ {
+ CC_DIALOG_UNLOCKED, /* unlocked */
+ CC_DIALOG_LOCKED /* local selected or locked */
+} cc_dialog_lock_e;
+
+typedef struct cc_notify_data_config_t {
+ boolean config_state;
+} cc_notify_data_config_t;
+
+typedef struct cc_notify_data_kpml_t {
+ boolean kpml_state;
+} cc_notify_data_kpml_t;
+
+
+typedef struct cc_notify_data_rcc_t {
+ cc_features_t feature;
+ cc_select_state_e select;
+} cc_notify_data_rcc_t;
+
+
+typedef union cc_notify_data_t {
+ cc_notify_data_config_t config;
+ cc_notify_data_kpml_t kpml;
+ cc_notify_data_rcc_t rcc;
+} cc_notify_data_t;
+
+typedef struct cc_feature_data_notify_t_ {
+ cc_subscriptions_t subscription;
+ cc_xfer_methods_t method;
+ cc_causes_t cause;
+ // The refer data above should have been in a cc_notify_data_refer_t
+ int cause_code;
+ callid_t blind_xferror_gsm_id;
+ boolean final;
+ cc_notify_data_t data;
+} cc_feature_data_notify_t;
+
+typedef struct cc_feature_data_update_t_ {
+ cc_msgbody_info_t msg_body;
+} cc_feature_data_update_t;
+
+typedef struct cc_feature_data_b2bcnf_t_ {
+ cc_causes_t cause;
+ callid_t call_id;
+ callid_t target_call_id;
+ char global_call_id[CC_GCID_LEN];
+} cc_feature_data_b2bcnf_t;
+
+typedef struct cc_feature_data_record_t_ {
+ boolean subref_flag;
+} cc_feature_data_record_t;
+
+typedef struct cc_feature_data_select_t_ {
+ boolean select; /* TRUE when select, FALSE when unselect */
+} cc_feature_data_select_t;
+
+typedef struct cc_feature_data_b2b_join_t_ {
+ callid_t b2bjoin_callid;
+ callid_t b2bjoin_joincallid;
+} cc_feature_data_b2b_join_t;
+
+
+typedef struct cc_media_cap_t_ {
+ cc_media_cap_name name; /* media channel name designator */
+ sdp_media_e type; /* media type: audio, video etc */
+ boolean enabled; /* this media is enabled or disabled */
+ boolean support_security; /* security is supported */
+ sdp_direction_e support_direction;/* supported direction */
+ cc_media_stream_id_t pc_stream; /* The media stream in the PC */
+ cc_media_track_id_t pc_track; /* The track ID in the media stream */
+} cc_media_cap_t;
+
+typedef struct cc_media_cap_table_t_ {
+ uint32_t id;
+ cc_media_cap_t cap[CC_MAX_MEDIA_CAP];/* capability table. */
+} cc_media_cap_table_t;
+
+typedef struct cc_media_track_t_ {
+ unsigned int media_stream_track_id;
+ boolean video;
+} cc_media_track_t;
+
+typedef struct cc_media_remote_track_table_t_ {
+ uint32_t num_tracks;
+ uint32_t media_stream_id;
+ cc_media_track_t track[CC_MAX_TRACKS];
+} cc_media_remote_track_table_t;
+
+typedef struct cc_media_remote_stream_table_t_ {
+ cc_media_remote_track_table_t streams[CC_MAX_STREAMS];
+} cc_media_remote_stream_table_t;
+
+typedef struct cc_media_local_track_table_t_ {
+ uint32_t media_stream_id;
+ cc_media_track_t track[CC_MAX_TRACKS];
+} cc_media_local_track_table_t;
+
+typedef struct cc_feature_data_generic_t {
+ boolean subref_flag;
+ uint32_t eventid;
+} cc_feature_data_generic_t;
+
+typedef struct cc_feature_data_cnf_t_ {
+ cc_causes_t cause;
+ callid_t call_id;
+ callid_t target_call_id;
+} cc_feature_data_cnf_t;
+
+typedef struct cc_feature_data_cancel_t_ {
+ cc_rcc_skey_evt_type_e cause;
+ callid_t call_id;
+ callid_t target_call_id;
+} cc_feature_data_cancel_t;
+
+typedef struct cc_feature_data_pc_t_ {
+ char pc_handle[PC_HANDLE_SIZE];
+} cc_feature_data_pc_t;
+
+typedef struct cc_feature_data_track_t_ {
+ cc_media_stream_id_t stream_id;
+ cc_media_track_id_t track_id;
+ cc_media_type_t media_type;
+} cc_feature_data_track_t;
+
+
+typedef struct cc_feature_candidate_t_ {
+ uint16_t level;
+ char candidate[CANDIDATE_SIZE];
+ char mid[MID_SIZE];
+} cc_feature_candidate_t;
+
+typedef struct cc_feature_session_t_ {
+ unsigned int sessionid;
+ cc_boolean has_constraints;
+} cc_feature_session_t;
+
+
+typedef union cc_feature_data_t {
+ cc_feature_data_newcall_t newcall;
+ cc_feature_data_xfer_t xfer;
+ cc_feature_data_ind_t indication;
+ cc_feature_data_endcall_t endcall;
+ cc_feature_data_hold_t hold;
+ cc_feature_data_hold_reversion_t hold_reversion;
+ cc_feature_data_resume_t resume;
+ cc_feature_data_redirect_t redirect;
+ cc_feature_data_subscribe_t subscribe;
+ cc_feature_data_notify_t notify;
+ cc_feature_data_update_t update;
+ cc_feature_data_b2bcnf_t b2bconf;
+ cc_feature_data_call_info_t call_info;
+ cc_feature_data_record_t record;
+ cc_feature_data_select_t select;
+ cc_feature_data_b2b_join_t b2bjoin;
+ cc_feature_data_generic_t generic;
+ cc_feature_data_cnf_t cnf;
+ cc_feature_data_b2bcnf_t cancel;
+ cc_media_cap_t caps;
+ cc_feature_data_pc_t pc;
+ cc_feature_data_track_t track;
+ cc_feature_candidate_t candidate;
+ cc_feature_session_t session;
+} cc_feature_data_t;
+
+typedef struct cc_setup_t_ {
+ cc_msgs_t msg_id;
+ cc_srcs_t src_id;
+ callid_t call_id;
+ line_t line;
+ cc_alerting_type alert_info;
+ vcm_ring_mode_t alerting_ring;
+ vcm_tones_t alerting_tone;
+ cc_caller_id_t caller_id;
+ cc_redirect_t redirect;
+ cc_call_info_t call_info;
+ boolean replaces;
+ string_t recv_info_list;
+ cc_msgbody_info_t msg_body;
+} cc_setup_t;
+
+typedef struct cc_setup_ack_t_ {
+ cc_msgs_t msg_id;
+ cc_srcs_t src_id;
+ callid_t call_id;
+ line_t line;
+ cc_caller_id_t caller_id;
+ cc_msgbody_info_t msg_body;
+} cc_setup_ack_t;
+
+typedef struct cc_proceeding_t_ {
+ cc_msgs_t msg_id;
+ cc_srcs_t src_id;
+ callid_t call_id;
+ line_t line;
+ cc_caller_id_t caller_id;
+} cc_proceeding_t;
+
+typedef struct cc_alerting_t_ {
+ cc_msgs_t msg_id;
+ cc_srcs_t src_id;
+ callid_t call_id;
+ line_t line;
+ cc_caller_id_t caller_id;
+ cc_msgbody_info_t msg_body;
+ boolean inband;
+} cc_alerting_t;
+
+typedef struct cc_connected_t_ {
+ cc_msgs_t msg_id;
+ cc_srcs_t src_id;
+ callid_t call_id;
+ line_t line;
+ cc_caller_id_t caller_id;
+ string_t recv_info_list;
+ cc_msgbody_info_t msg_body;
+} cc_connected_t;
+
+typedef struct cc_connected_ack_t_ {
+ cc_msgs_t msg_id;
+ cc_srcs_t src_id;
+ callid_t call_id;
+ line_t line;
+ cc_caller_id_t caller_id;
+ cc_msgbody_info_t msg_body;
+} cc_connected_ack_t;
+
+typedef struct cc_release_t_ {
+ cc_msgs_t msg_id;
+ cc_srcs_t src_id;
+ callid_t call_id;
+ line_t line;
+ cc_causes_t cause;
+ char dialstring[CC_MAX_DIALSTRING_LEN];
+ cc_kfact_t kfactor;
+} cc_release_t;
+
+typedef struct cc_release_complete_t_ {
+ cc_msgs_t msg_id;
+ cc_srcs_t src_id;
+ callid_t call_id;
+ line_t line;
+ cc_causes_t cause;
+ cc_kfact_t kfactor;
+} cc_release_complete_t;
+
+typedef struct cc_feature_t_ {
+ cc_msgs_t msg_id;
+ cc_srcs_t src_id;
+ callid_t call_id;
+ line_t line;
+ cc_features_t feature_id;
+ cc_feature_data_t data;
+ boolean data_valid;
+ cc_jsep_action_t action;
+ char sdp[SDP_SIZE];
+} cc_feature_t;
+
+typedef struct cc_feature_ack_t_ {
+ cc_msgs_t msg_id;
+ cc_srcs_t src_id;
+ callid_t call_id;
+ line_t line;
+ cc_features_t feature_id;
+ cc_feature_data_t data;
+ boolean data_valid;
+ cc_causes_t cause;
+} cc_feature_ack_t;
+
+typedef struct cc_offhook_t_ {
+ cc_msgs_t msg_id;
+ cc_srcs_t src_id;
+ callid_t call_id;
+ line_t line;
+ char global_call_id[CC_GCID_LEN];
+ callid_t prim_call_id; /* For internal new call event
+ * refer primary call's call_id
+ */
+ cc_hold_resume_reason_e hold_resume_reason; /* Reason for new consult call */
+ monitor_mode_t monitor_mode;
+ cfwdall_mode_t cfwdall_mode;
+} cc_offhook_t;
+
+typedef struct cc_onhook_t_ {
+ cc_msgs_t msg_id;
+ cc_srcs_t src_id;
+ callid_t call_id;
+ line_t line;
+ boolean softkey;
+ callid_t prim_call_id; /* For internal new call event
+ * refer primary call's call_id
+ */
+ cc_hold_resume_reason_e hold_resume_reason; /* Reason for new consult call */
+ cc_onhook_reason_e active_list; /* onhook is because of active call
+ * press
+ */
+} cc_onhook_t;
+
+typedef struct cc_line_t_ {
+ cc_msgs_t msg_id;
+ cc_srcs_t src_id;
+ callid_t call_id;
+ line_t line;
+} cc_line_t;
+
+typedef struct cc_digit_begin_t_ {
+ cc_msgs_t msg_id;
+ cc_srcs_t src_id;
+ callid_t call_id;
+ line_t line;
+ int digit;
+} cc_digit_begin_t;
+
+typedef struct cc_digit_end_t_ {
+ cc_msgs_t msg_id;
+ cc_srcs_t src_id;
+ callid_t call_id;
+ line_t line;
+ int digit;
+} cc_digit_end_t;
+
+typedef struct cc_dialstring_t_ {
+ cc_msgs_t msg_id;
+ cc_srcs_t src_id;
+ callid_t call_id;
+ line_t line;
+ char dialstring[CC_MAX_DIALSTRING_LEN];
+ char g_call_id[CC_GCID_LEN];
+ monitor_mode_t monitor_mode;
+} cc_dialstring_t;
+
+// mostly overlap with sessionTypes.h:cc_mwi_status_t
+typedef struct cc_action_data_mwi_ {
+ boolean on;
+ int type;
+ int newCount;
+ int oldCount;
+ int hpNewCount;
+ int hpOldCount;
+} cc_action_data_mwi_t;
+
+typedef struct cc_mwi_t_ {
+ cc_msgs_t msg_id;
+ cc_srcs_t src_id;
+ callid_t call_id;
+ line_t line;
+ cc_action_data_mwi_t msgSummary;
+} cc_mwi_t;
+
+typedef struct cc_options_sdp_req_t_ {
+ cc_msgs_t msg_id;
+ cc_srcs_t src_id;
+ callid_t call_id;
+ line_t line;
+ void * pMessage;
+} cc_options_sdp_req_t;
+
+typedef struct cc_options_sdp_ack_t_ {
+ cc_msgs_t msg_id;
+ cc_srcs_t src_id;
+ callid_t call_id;
+ line_t line;
+ void * pMessage;
+ cc_msgbody_info_t msg_body;
+} cc_options_sdp_ack_t;
+
+typedef struct cc_audit_sdp_req_t_ {
+ cc_msgs_t msg_id;
+ cc_srcs_t src_id;
+ callid_t call_id;
+ line_t line;
+ boolean apply_ringout;
+} cc_audit_sdp_req_t;
+
+typedef struct cc_audit_sdp_ack_t_ {
+ cc_msgs_t msg_id;
+ cc_srcs_t src_id;
+ callid_t call_id;
+ line_t line;
+ cc_msgbody_info_t msg_body;
+} cc_audit_sdp_ack_t;
+
+typedef struct cc_feature_tmr_t_ {
+ callid_t call_id;
+ line_t line;
+ cc_features_t feature_id;
+} cc_feature_tmr_t;
+
+typedef struct cc_regmgr_t_ {
+ cc_msgs_t msg_id;
+ cc_srcs_t src_id;
+ int rsp_type;
+ cc_regmgr_rsp_e rsp_id;
+ boolean wait_flag;
+} cc_regmgr_t;
+
+// mostly overlap with sessionTypes.h:session_send_info_t
+typedef struct cc_info_t {
+ cc_msgs_t msg_id;
+ cc_srcs_t not_used; // why not share a common struct?? why cast everything to cc_setup_t??
+ callid_t call_id;
+ line_t line;
+ string_t info_package;
+ string_t content_type;
+ string_t message_body;
+} cc_info_t;
+
+typedef struct cc_msg_t_ {
+ union {
+ cc_setup_t setup;
+ cc_setup_ack_t setup_ack;
+ cc_proceeding_t proceeding;
+ cc_alerting_t alerting;
+ cc_connected_t connected;
+ cc_connected_ack_t connected_ack;
+ cc_release_t release;
+ cc_release_complete_t release_complete;
+ cc_feature_t feature;
+ cc_feature_ack_t feature_ack;
+ cc_offhook_t offhook;
+ cc_onhook_t onhook;
+ cc_line_t line;
+ cc_digit_begin_t digit_begin;
+ cc_digit_end_t digit_end;
+ cc_dialstring_t dialstring;
+ cc_mwi_t mwi;
+ cc_options_sdp_ack_t options_ack;
+ cc_audit_sdp_ack_t audit_ack;
+ cc_info_t info;
+ } msg;
+} cc_msg_t;
+
+
+callid_t cc_get_new_call_id(void);
+const char *cc_msg_name(cc_msgs_t id);
+const char *cc_src_name(cc_srcs_t id);
+const char *cc_cause_name(cc_causes_t id);
+const char *cc_feature_name(cc_features_t id);
+
+void cc_int_setup(cc_srcs_t src_id, cc_srcs_t dst_id, callid_t call_id,
+ line_t line, cc_caller_id_t *caller_id,
+ cc_alerting_type alert_info, vcm_ring_mode_t alerting_ring,
+ vcm_tones_t alerting_tone, cc_redirect_t *redirect,
+ cc_call_info_t *call_info_p, boolean replaces,
+ string_t recv_info_list, cc_msgbody_info_t *msg_body);
+
+void cc_int_setup_ack(cc_srcs_t src_id, cc_srcs_t dst_id, callid_t call_id,
+ line_t line, cc_caller_id_t *caller_id,
+ cc_msgbody_info_t *msg_body);
+
+void cc_int_proceeding(cc_srcs_t src_id, cc_srcs_t dst_id, callid_t call_id,
+ line_t line, cc_caller_id_t *caller_id);
+
+void cc_int_alerting(cc_srcs_t src_id, cc_srcs_t dst_id, callid_t call_id,
+ line_t line, cc_caller_id_t *caller_id,
+ cc_msgbody_info_t *msg_body, boolean inband);
+
+void cc_int_connected(cc_srcs_t src_id, cc_srcs_t dst_id, callid_t call_id,
+ line_t line, cc_caller_id_t *caller_id,
+ string_t recv_info_list, cc_msgbody_info_t *msg_body);
+
+void cc_int_connected_ack(cc_srcs_t src_id, cc_srcs_t dst_id, callid_t call_id,
+ line_t line, cc_caller_id_t *caller_id,
+ cc_msgbody_info_t *msg_body);
+
+void cc_int_release(cc_srcs_t src_id, cc_srcs_t dst_id, callid_t call_id,
+ line_t line, cc_causes_t cause, const char *dialstring,
+ cc_kfact_t *kfactor);
+
+void cc_int_release_complete(cc_srcs_t src_id, cc_srcs_t dst_id,
+ callid_t call_id, line_t line, cc_causes_t cause,
+ cc_kfact_t *kfactor);
+
+void cc_int_feature2(cc_msgs_t msg_id, cc_srcs_t src_id, cc_srcs_t dst_id,
+ callid_t call_id, line_t line, cc_features_t feature_id,
+ cc_feature_data_t *data);
+
+void cc_createoffer(cc_srcs_t src_id, cc_srcs_t dst_id, callid_t call_id,
+ line_t line, cc_features_t feature_id, cc_feature_data_t *data);
+
+void cc_createanswer (cc_srcs_t src_id, cc_srcs_t dst_id, callid_t call_id,
+ line_t line, cc_features_t feature_id, string_t sdp, cc_feature_data_t *data);
+
+void cc_setlocaldesc (cc_srcs_t src_id, cc_srcs_t dst_id, callid_t call_id, line_t line,
+ cc_features_t feature_id, cc_jsep_action_t action, string_t sdp, cc_feature_data_t *data);
+
+void cc_setremotedesc (cc_srcs_t src_id, cc_srcs_t dst_id, callid_t call_id, line_t line,
+ cc_features_t feature_id, cc_jsep_action_t action, string_t sdp, cc_feature_data_t *data);
+
+void cc_localdesc (cc_srcs_t src_id, cc_srcs_t dst_id, callid_t call_id, line_t line,
+ cc_features_t feature_id, cc_feature_data_t *data);
+
+void cc_remotedesc (cc_srcs_t src_id, cc_srcs_t dst_id, callid_t call_id, line_t line,
+ cc_features_t feature_id, cc_feature_data_t *data);
+
+void cc_int_feature_ack(cc_srcs_t src_id, cc_srcs_t dst_id, callid_t call_id,
+ line_t line, cc_features_t feature_id,
+ cc_feature_data_t *data, cc_causes_t cause);
+
+void cc_int_offhook(cc_srcs_t src_id, cc_srcs_t dst_id, callid_t prim_call_id,
+ cc_hold_resume_reason_e consult_reason, callid_t call_id,
+ line_t line, char *global_call_id,
+ monitor_mode_t monitor_mode,
+ cfwdall_mode_t cfwdall_mode);
+
+void cc_int_onhook(cc_srcs_t src_id, cc_srcs_t dst_id, callid_t prim_call_id,
+ cc_hold_resume_reason_e consult_reason, callid_t call_id,
+ line_t line, boolean softkey, cc_onhook_reason_e active_list);
+
+void cc_int_line(cc_srcs_t src_id, cc_srcs_t dst_id, callid_t call_id,
+ line_t line);
+
+void cc_int_digit_begin(cc_srcs_t src_id, cc_srcs_t dst_id, callid_t call_id,
+ line_t line, int digit);
+
+void cc_int_digit_end(cc_srcs_t src_id, cc_srcs_t dst_id, callid_t call_id,
+ line_t line, int digit);
+
+void cc_int_dialstring(cc_srcs_t src_id, cc_srcs_t dst_id, callid_t call_id,
+ line_t line, const char *dialstring,
+ const char *g_call_id, monitor_mode_t monitor_mode);
+
+void cc_int_mwi(cc_srcs_t src_id, cc_srcs_t dst_id, callid_t call_id,
+ line_t line, boolean on, int type, int newCount,
+ int oldCount, int hpNewCount, int hpOldCount);
+
+void cc_int_options_sdp_req(cc_srcs_t src_id, cc_srcs_t dst_id,
+ callid_t call_id, line_t line, void *pMessage);
+
+void cc_int_options_sdp_ack(cc_srcs_t src_id, cc_srcs_t dst_id,
+ callid_t call_id, line_t line, void *pMessage,
+ cc_msgbody_info_t *msg_body);
+
+void cc_int_audit_sdp_req(cc_srcs_t src_id, cc_srcs_t dst_id, callid_t call_id,
+ line_t line, boolean apply_ringout);
+
+void cc_int_audit_sdp_ack(cc_srcs_t src_id, cc_srcs_t dst_id, callid_t call_id,
+ line_t line, cc_msgbody_info_t *msg_body);
+
+void cc_int_info(cc_srcs_t src_id, cc_srcs_t dst_id, callid_t call_id,
+ line_t line, string_t info_package, string_t content_type,
+ string_t message_body);
+
+void cc_int_fail_fallback(cc_srcs_t src_id, cc_srcs_t dst_id, int rsp_type,
+ cc_regmgr_rsp_e rsp_id, boolean waited);
+#define cc_fail_fallback_sip(a, b, c, d) cc_int_fail_fallback(a, CC_SRC_SIP, b, c, d)
+#define cc_fail_fallback_gsm(a, b, c) cc_int_fail_fallback(a, CC_SRC_GSM, b, c, FALSE)
+
+#define cc_setup(a, b, c, d, e, f, g, h, i, j, k, l) cc_int_setup(a, CC_SRC_GSM, b, c, d, e, f, g, h, i, j, k, l)
+#define cc_setup_ack(a, b, c, d, e) \
+ cc_int_setup_ack(a, CC_SRC_GSM, b, c, d, e)
+#define cc_proceeding(a, b, c, d) cc_int_proceeding(a, CC_SRC_GSM, b, c, d)
+#define cc_alerting(a, b, c, d, e, f) \
+ cc_int_alerting(a, CC_SRC_GSM, b, c, d, e, f)
+#define cc_connected(a, b, c, d, e, f) \
+ cc_int_connected(a, CC_SRC_GSM, b, c, d, e, f)
+#define cc_connected_ack(a, b, c, d, e) \
+ cc_int_connected_ack(a, CC_SRC_GSM, b, c, d, e)
+#define cc_release(a, b, c, d, e, f) cc_int_release(a, CC_SRC_GSM, b, c, d, e, f)
+#define cc_release_complete(a, b, c, d, e) \
+ cc_int_release_complete(a, CC_SRC_GSM, b, c, d, e)
+#define cc_feature(a, b, c, d, e) cc_int_feature2(CC_MSG_FEATURE, a, CC_SRC_GSM, b, c, d, e)
+#define cc_int_feature(a, b, c, d, e, f) cc_int_feature2(CC_MSG_FEATURE, a, b, c, d, e, f)
+#define cc_feature_ack(a, b, c, d, e, f) \
+ cc_int_feature_ack(a, CC_SRC_GSM, b, c, d, e, f)
+#define cc_offhook(a, b, c) cc_int_offhook(a, CC_SRC_GSM, CC_NO_CALL_ID, CC_REASON_NONE, b, c, NULL, CC_MONITOR_NONE,CFWDALL_NONE)
+#define cc_offhook_ext(a, b, c, d, e) cc_int_offhook(a, CC_SRC_GSM, CC_NO_CALL_ID, CC_REASON_NONE, b, c, d, e,CFWDALL_NONE)
+#define cc_onhook(a, b, c, d) cc_int_onhook(a, CC_SRC_GSM, CC_NO_CALL_ID, CC_REASON_NONE, b, c, d, CC_REASON_NULL)
+#define cc_onhook_ext(a, b, c, d, e) cc_int_onhook(a, CC_SRC_GSM, CC_NO_CALL_ID, CC_REASON_NONE, b, c, d, e)
+#define cc_line(a, b, c) cc_int_line(a, CC_SRC_GSM, b, c)
+#define cc_digit_begin(a, b, c, d) cc_int_digit_begin(a, CC_SRC_GSM, b, c, d)
+#define cc_dialstring(a, b, c, d) cc_int_dialstring(a, CC_SRC_GSM, b, c, d, NULL, CC_MONITOR_NONE)
+#define cc_dialstring_ext(a, b, c, d, e, f) cc_int_dialstring(a, CC_SRC_GSM, b, c, d, e, f)
+#define cc_mwi(a, b, c, d, e, f, g, h, i) cc_int_mwi(a, CC_SRC_GSM, b, c, d, e, f, g, h, i )
+#define cc_options_sdp_req(a, b, c, d) cc_int_options_sdp_req(a, CC_SRC_GSM, b, c, d)
+#define cc_audit_sdp_req(a, b, c, d) cc_int_audit_sdp_req(a, CC_SRC_GSM, b, c, d)
+
+typedef enum cc_types_t_ {
+ CC_TYPE_INVALID,
+ CC_TYPE_CCM,
+ CC_TYPE_OTHER
+} cc_types_t;
+
+typedef enum cc_states_t_ {
+ CC_STATE_MIN = -1,
+ CC_STATE_OFFHOOK,
+ CC_STATE_DIALING,
+ CC_STATE_DIALING_COMPLETED,
+ CC_STATE_CALL_SENT,
+ CC_STATE_FAR_END_PROCEEDING,
+ CC_STATE_FAR_END_ALERTING,
+ CC_STATE_CALL_RECEIVED,
+ CC_STATE_ALERTING,
+ CC_STATE_ANSWERED,
+ CC_STATE_CONNECTED,
+ CC_STATE_HOLD,
+ CC_STATE_RESUME,
+ CC_STATE_ONHOOK,
+ CC_STATE_CALL_FAILED,
+ CC_STATE_HOLD_REVERT,
+ CC_STATE_UNKNOWN,
+ CC_STATE_MAX
+} cc_states_t;
+
+/* Update cc_action_names structure in lsm.c with the
+ * corresponding change for the following structure.
+ */
+typedef enum cc_actions_t_ {
+ CC_ACTION_MIN = -1,
+ CC_ACTION_SPEAKER,
+ CC_ACTION_DIAL_MODE,
+ CC_ACTION_MWI,
+ CC_ACTION_MWI_LAMP_ONLY,
+ CC_ACTION_OPEN_RCV,
+ CC_ACTION_UPDATE_UI,
+ CC_ACTION_MEDIA,
+ CC_ACTION_RINGER,
+ CC_ACTION_SET_LINE_RINGER,
+ CC_ACTION_PLAY_TONE,
+ CC_ACTION_STOP_TONE,
+ CC_ACTION_STOP_MEDIA,
+ CC_ACTION_START_RCV,
+ CC_ACTION_ANSWER_PENDING,
+ CC_ACTION_PLAY_BLF_ALERTING_TONE,
+ CC_ACTION_MAX
+} cc_actions_t;
+
+typedef enum cc_services_t_ {
+ CC_SERVICE_MIN = -1,
+ CC_SERVICE_MAX
+} cc_services_t;
+
+typedef enum cc_update_ui_actions_t_ {
+ CC_UPDATE_MIN = -1,
+ CC_UPDATE_CONF_ACTIVE,
+ CC_UPDATE_CONF_RELEASE,
+ CC_UPDATE_XFER_PRIMARY,
+ CC_UPDATE_CALLER_INFO,
+ CC_UPDATE_SECURITY_STATUS,
+ CC_UPDATE_SET_CALL_STATUS,
+ CC_UPDATE_CLEAR_CALL_STATUS,
+ CC_UPDATE_SET_NOTIFICATION,
+ CC_UPDATE_CLEAR_NOTIFICATION,
+ CC_UPDATE_CALL_PRESERVATION,
+ CC_UPDATE_CALL_CONNECTED,
+ CC_UPDATE_MAX
+} cc_update_ui_actions_t;
+
+typedef struct cc_state_data_offhook_t_ {
+ cc_caller_id_t caller_id;
+ int dial_mode;
+} cc_state_data_offhook_t;
+
+/*
+ * This structure is passed in CC_STATE_DIALING to lsm to indicate
+ * wether a dialtone needs to be played or not
+ * should the stutter dial tone be suppressed or not
+ */
+typedef struct cc_state_data_dialing_t_ {
+ boolean play_dt;
+ boolean suppress_stutter;
+} cc_state_data_dialing_t;
+
+typedef struct cc_state_data_dialing_completedt_ {
+ cc_caller_id_t caller_id;
+} cc_state_data_dialing_completed_t;
+
+typedef struct cc_state_data_call_sent_t_ {
+ cc_caller_id_t caller_id;
+} cc_state_data_call_sent_t;
+
+typedef struct cc_state_data_far_end_proceeding_t_ {
+ cc_caller_id_t caller_id;
+} cc_state_data_far_end_proceeding_t;
+
+typedef struct cc_state_data_far_end_alerting_t_ {
+ cc_caller_id_t caller_id;
+} cc_state_data_far_end_alerting_t;
+
+typedef struct cc_state_data_call_received_t_ {
+ cc_caller_id_t caller_id;
+} cc_state_data_call_received_t;
+
+typedef struct cc_state_data_alerting_t_ {
+ cc_caller_id_t caller_id;
+} cc_state_data_alerting_t;
+
+typedef struct cc_state_data_answered_t_ {
+ cc_caller_id_t caller_id;
+} cc_state_data_answered_t;
+
+typedef struct cc_state_data_connected_t_ {
+ cc_caller_id_t caller_id;
+} cc_state_data_connected_t;
+
+typedef struct cc_state_data_hold_t_ {
+ cc_caller_id_t caller_id;
+ boolean local;
+ cc_hold_resume_reason_e reason;
+} cc_state_data_hold_t;
+
+typedef struct cc_state_data_resume_t_ {
+ cc_caller_id_t caller_id;
+ boolean local;
+} cc_state_data_resume_t;
+
+typedef struct cc_state_data_onhook_t_ {
+ cc_caller_id_t caller_id;
+ boolean local;
+ cc_causes_t cause;
+} cc_state_data_onhook_t;
+
+typedef struct cc_state_data_call_failed_t_ {
+ cc_caller_id_t caller_id;
+ cc_causes_t cause;
+} cc_state_data_call_failed_t;
+
+typedef union cc_state_data_t_ {
+ cc_state_data_offhook_t offhook;
+ cc_state_data_dialing_t dialing;
+ cc_state_data_dialing_completed_t dialing_completed;
+ cc_state_data_call_sent_t call_sent;
+ cc_state_data_far_end_proceeding_t far_end_proceeding;
+ cc_state_data_far_end_alerting_t far_end_alerting;
+ cc_state_data_call_received_t call_received;
+ cc_state_data_alerting_t alerting;
+ cc_state_data_answered_t answered;
+ cc_state_data_connected_t connected;
+ cc_state_data_hold_t hold;
+ cc_state_data_resume_t resume;
+ cc_state_data_onhook_t onhook;
+ cc_state_data_call_failed_t call_failed;
+} cc_state_data_t;
+
+typedef struct cc_action_data_digit_begin_ {
+ int tone;
+} cc_action_data_digit_begin_t;
+
+typedef struct cc_action_data_tone_ {
+ vcm_tones_t tone;
+} cc_action_data_tone_t;
+
+typedef struct cc_action_data_speaker_ {
+ boolean on;
+} cc_action_data_speaker_t;
+
+typedef struct cc_action_data_dial_mode_ {
+ int mode;
+ int digit_cnt;
+} cc_action_data_dial_mode_t;
+
+/*
+typedef struct cc_action_data_mwi_ {
+ boolean on;
+ int32_t type;
+ int32_t newCount;
+ int32_t oldCount;
+ int32_t hpNewCount;
+ int32_t hpOldCount;
+} cc_action_data_mwi_t;
+*/
+
+typedef struct cc_action_data_open_rcv_ {
+ boolean is_multicast;
+ cpr_ip_addr_t listen_ip;
+ uint16_t port;
+ boolean rcv_chan;
+ boolean keep;
+ media_refid_t media_refid; /* the ID of the media to reference to */
+ sdp_media_e media_type;
+} cc_action_data_open_rcv_t;
+
+typedef struct cc_set_call_status_data_ {
+ char *phrase_str_p;
+ int timeout;
+ callid_t call_id;
+ line_t line;
+} cc_set_call_status_data_t;
+
+typedef struct cc_clear_call_status_data_ {
+ callid_t call_id;
+ line_t line;
+} cc_clear_call_status_data_t;
+
+// mostly overlap with sessionTypes.h:cc_notification_data_t
+typedef struct cc_set_notification_data_ {
+ char *phrase_str_p;
+ unsigned long timeout;
+ unsigned long priority;
+} cc_set_notification_data_t;
+
+typedef union cc_update_ui_data_ {
+ cc_feature_data_call_info_t caller_info;
+ cc_set_call_status_data_t set_call_status_parms;
+ cc_clear_call_status_data_t clear_call_status_parms;
+ cc_set_notification_data_t set_notification_parms;
+ string_t security_status;
+} cc_update_ui_data_t;
+
+typedef struct cc_action_data_update_ui_ {
+ cc_update_ui_actions_t action;
+ cc_update_ui_data_t data;
+} cc_action_data_update_ui_t;
+
+typedef struct cc_action_data_ringer_ {
+ boolean on;
+} cc_action_data_ringer_t;
+
+typedef struct cc_action_data_stop_media_ {
+ media_refid_t media_refid; /* the ID of the media to reference to */
+} cc_action_data_stop_media_t;
+
+typedef union cc_action_data_t_ {
+ cc_action_data_digit_begin_t digit_begin;
+ cc_action_data_tone_t tone;
+ cc_action_data_speaker_t speaker;
+ cc_action_data_dial_mode_t dial_mode;
+ cc_action_data_mwi_t mwi;
+ cc_action_data_open_rcv_t open_rcv;
+ cc_action_data_update_ui_t update_ui;
+ cc_action_data_ringer_t ringer;
+ cc_action_data_stop_media_t stop_media;
+} cc_action_data_t;
+
+typedef struct cc_service_data_get_facility_by_line_ {
+ line_t line;
+} cc_service_data_get_facility_by_line_t;
+
+typedef union cc_service_data_t_ {
+ cc_service_data_get_facility_by_line_t get_facility_by_line;
+} cc_service_data_t;
+
+
+typedef enum {
+ MEDIA_INTERFACE_UPDATE_NOT_REQUIRED,
+ MEDIA_INTERFACE_UPDATE_STARTED,
+ MEDIA_INTERFACE_UPDATE_IN_PROCESS
+} dock_undock_event_t;
+
+extern dock_undock_event_t g_dock_undock_event;
+
+void cc_call_state(callid_t call_id, line_t line, cc_states_t state,
+ cc_state_data_t *data);
+cc_rcs_t cc_call_action(callid_t call_id, line_t line, cc_actions_t action,
+ cc_action_data_t *data);
+cc_rcs_t cc_call_service(callid_t call_id, line_t line, cc_services_t service,
+ cc_service_data_t *data);
+void cc_call_attribute(callid_t call_id, line_t line, call_attr_t attr);
+void cc_init(void);
+void cc_free_msg_body_parts(cc_msgbody_info_t *msg_body);
+void cc_free_msg_data(cc_msg_t *msg);
+void cc_initialize_msg_body_parts_info(cc_msgbody_info_t *msg_body);
+void cc_mv_msg_body_parts(cc_msgbody_info_t *dst_msg,
+ cc_msgbody_info_t *src_msg);
+cc_rcs_t cc_cp_msg_body_parts(cc_msgbody_info_t *dst_msg,
+ cc_msgbody_info_t *src_msg);
+void cc_mv_caller_id(cc_caller_id_t *dst_caller, cc_caller_id_t *src_caller);
+ //function that will be invoked by modules external to gsm:
+
+int cc_is_cnf_call(callid_t call_id);
+cc_transfer_mode_e cc_is_xfr_call(callid_t call_id);
+
+extern cprBuffer_t cc_get_msg_buf(int min_size);
+extern const char *cc_feature_name(cc_features_t id);
+extern const char *cc_msg_name(cc_msgs_t id);
+extern const char *cc_cause_name(cc_causes_t id);
+extern void cc_media_update_native_video_support(boolean val);
+extern void cc_media_update_video_cap(boolean val);
+extern void cc_media_update_native_video_txcap(boolean val);
+extern cc_boolean cc_media_isTxCapEnabled();
+extern cc_boolean cc_media_isVideoCapEnabled();
+extern void cc_media_setVideoAutoTxPref(cc_boolean txPref);
+extern cc_boolean cc_media_getVideoAutoTxPref();
+#endif
diff --git a/libs/sipcc/core/includes/check_sync.h b/libs/sipcc/core/includes/check_sync.h
new file mode 100644
index 0000000000..c5dd8051df
--- /dev/null
+++ b/libs/sipcc/core/includes/check_sync.h
@@ -0,0 +1,46 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef CHECK_SYNC_H
+#define CHECK_SYNC_H
+
+#include "util_parse.h"
+
+typedef enum {
+ SYNCS_ANY,
+ SYNCS_GOT_VERSION,
+ SYNCS_GOT_VERSION_EQ,
+ SYNCS_GOT_SYNC,
+ SYNCS_GOT_SYNC_EQ,
+ SYNCS_GOT_GENERIC,
+ SYNCS_GOT_GENERIC_EQ
+} sync_states;
+
+typedef enum {
+ SYNCF_NONE,
+ SYNCF_MY,
+ SYNCF_WILD
+} SyncVersionFound_t;
+
+typedef struct {
+ char myVersion[MAX_LOAD_ID_STRING];
+ char resetSync[MAX_SYNC_LEN];
+ SyncVersionFound_t versionFound;
+} VersionSync_t;
+
+#define SYNCINFO_XML "syncinfo.xml"
+#define SYNC_BUF_SIZE 4096
+
+extern int CheckSync;
+extern int SyncInfoInProgress;
+extern char *SyncBuffer;
+
+int check_sync_get(void);
+void add_sync_info(char *version, char *sync, VersionSync_t *versionSync);
+int parse_sync_entry(char **parseptr, VersionSync_t *versionSync);
+int parse_sync_info(char *parseptr, VersionSync_t *versionSync);
+void process_sync_info(char *syncInfo);
+short handle_sync_message(short cmd, void *pData);
+
+#endif
diff --git a/libs/sipcc/core/includes/ci.h b/libs/sipcc/core/includes/ci.h
new file mode 100644
index 0000000000..e5d014cf4a
--- /dev/null
+++ b/libs/sipcc/core/includes/ci.h
@@ -0,0 +1,34 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _CI_INCLUDED_H
+#define _CI_INCLUDED_H
+
+#include "plat_api.h"
+#include "plat_debug.h"
+
+
+/* return codes for CI command processing */
+#define CI_OK (0)
+#define CI_ERROR (1)
+#define CI_INVALID (2)
+#define CI_AMBIGUOUS (3)
+
+/* flags for CI processing */
+#define CI_PROMPT (0x0001)
+
+/*
+ * Prototypes for public functions
+ */
+void ci_init();
+int ci_process_input(const char *str, char *wkspace, int wklen);
+int32_t ci_show_cmds(int32_t argc, const char *argv[]);
+ci_callback ci_set_interceptor(ci_callback func);
+
+int ci_err_too_few(void); /* "Too few arguments" */
+int ci_err_too_many(void); /* "Too many arguments" */
+int ci_err_inv_arg(void); /* "Invalid argument" */
+uint32_t ci_streval(const char *str);
+
+#endif /* _CI_INCLUDED_H */
diff --git a/libs/sipcc/core/includes/config.h b/libs/sipcc/core/includes/config.h
new file mode 100755
index 0000000000..bd149742dd
--- /dev/null
+++ b/libs/sipcc/core/includes/config.h
@@ -0,0 +1,195 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _CONFIG_H_
+#define _CONFIG_H_
+
+#include "cpr_types.h"
+#include "cpr_timers.h"
+#include "cfgfile_utils.h"
+#include "configmgr.h"
+#include "prot_configmgr.h"
+#include "phone.h"
+
+/*
+ * List of timers that the CFG task is responsible for.
+ * CPR will send a msg to the CFG task when these
+ * timers expire. CPR expects a timer id when the timer
+ * is created, this enum serves that purpose.
+ */
+typedef enum {
+ CFG_TFTP_RETRY_TIMER
+} cfgTimerList_t;
+
+#define MAX_REQ_FIELDS 20
+#define MAX_FIELD_NAME_SIZE 30
+#define MAX_FIELD_VALUE_SIZE 30
+#define MAX_FIELDDESC_STR (MAX_FIELD_VALUE_SIZE+2)
+#define MAX_TFTP_PATH_LEN 64
+
+/*
+ * Definition of bits used in pDHCPInfo->extFields.ext.appStatus (32bits).
+ * Please note that some of these flags correspond to status flags
+ * asserted by Little App. Please see little_app.c, and make sure these
+ * flags are kept consistent.
+ */
+
+#define APPSTATUS_UPGRADE_FAILED 0x80000000L
+
+/* maximum length of config file including comments */
+#define MAX_CFG_FILE_LENGTH 0x2000
+
+/* minimum length of a registrion in seconds */
+#define MIN_REGISTRATION_PERIOD 20
+
+#define BUF_TEST();
+
+typedef enum {
+ ERASE_PROGRAM,
+ ERASE_ONLY,
+ PROGRAM_ONLY
+} flash_mode_t;
+
+extern var_t prot_cfg_table[];
+extern cfg_rom_t *const prot_startup_config;
+extern cfg_rom_t *const prot_running_config;
+extern cfg_rom_t *const prot_temp_config;
+extern int config_commit(int);
+extern int prot_sanity_check_config_settings(void);
+extern boolean prot_option_allowed_in_cfg_file(const char *);
+extern void prot_shutdown(void);
+extern int prot_config_change_notify(int);
+extern void prot_disconnected(int);
+extern int FlashaProgram(uint16_t *Source, uint16_t *Dest, uint32_t Size,
+ flash_mode_t mode);
+
+extern uint16_t g_NewVlan;
+extern uint16_t g_NewRelease;
+extern uint16_t g_NewErase;
+extern char local_media_type_string[];
+extern char local_net_dev_type_string[];
+
+void CFGTftpTimeout(int /*cpr_timer_t*/ *tmr);
+int CFGProgramFlash(uint8_t *src, uint8_t *dst, uint32_t len);
+int CFGEraseFlash(uint8_t *src, uint8_t *dst, uint32_t len);
+int CFGEraseProgramFlash(uint8_t *src, uint8_t *dst, uint32_t len);
+int CFGChksum(uint8_t *ptr, uint32_t len, uint32_t *csum, int dspmode,
+ int cmpmode);
+int CFGGetUISettings(uint8_t *pData);
+int CFGSetUISettings(void);
+void CFGSetLockState(boolean);
+boolean CFGIsLocked(void);
+void cfg_set_running_config(void);
+void cfg_get_stored_prot_settings(void);
+void LoadTempConfigData(void);
+void config_handle_cdp(int);
+void cfg_sanity_check_media_range(void);
+void cfg_check_la_appStatus(unsigned long appStatus);
+void cfg_set_inhibitLoading(int yesno);
+int cfg_get_inhibitLoading(void);
+
+
+/////////////////////////////////////////////////////////////
+// Configuration Variables replacing CUCM config file
+//
+////
+//////
+
+static const int gStartMediaPort = 16384;
+static const int gStopMediaPort = 32766;
+static const boolean gCallerIdBlocking = FALSE;
+static const boolean gAnonblock = FALSE;
+static const char gPreferredCodec[] = "none";
+static const char gDtmfOutOfBand[] = "avt";
+static const int gDtmfAvtPayload = 101;
+static const int gDtmfDbLevel = 3;
+static const int gSipRetx = 10;
+static const int gSipInviteRetx = 6;
+static const int gTimerT1 = 500;
+static const int gTimerT2 = 4000;
+static const int gTimerInviteExpires = 180;
+static const int gTimerRegisterExpires = 3600;
+static const boolean gRegisterWithProxy = TRUE;
+static const char gBackupProxy[] = "USECALLMANAGER";
+static const int gBackupProxyPort = 5060;
+static const char gEmergencyProxy[] = "USECALLMANAGER";
+static const int gEmergencyProxyPort = 5060;
+static const char gOutboundProxy[] = "USECALLMANAGER";
+static const int gOutboundProxyPort = 5060;
+static const boolean gNatRecievedProcessing = FALSE;
+static const char gUserInfo[] = "None";
+static const boolean gRemotePartyID = TRUE;
+static const boolean gSemiAttendedTransfer = TRUE;
+static const int gCallHoldRingback = 2;
+static const boolean gStutterMsgWaiting = FALSE;
+static const char gCallForwardURI[] = "x-cisco-serviceuri-cfwdall";
+static const boolean gCallStats = TRUE;
+static const int gTimerRegisterDelta = 5;
+static const int gMaxRedirects = 70;
+static const boolean gRfc2543Hold = FALSE;
+static const boolean gLocalCfwdEnable = TRUE;
+static const int gConnectionMonitorDuration = 120;
+static const int gCallLogBlfEnabled = 3 & 0x1;
+static const boolean gRetainForwardInformation = FALSE;
+static const int gRemoteCcEnable = 1;
+static const int gTimerKeepAliveExpires = 120;
+static const int gTimerSubscribeExpires = 120;
+static const int gTimerSubscribeDelta = 5;
+static const int gKpml = 3;
+static const boolean gNatEnabled = FALSE;
+static const char gNatAddress[] = "";
+static const boolean gAnableVad = FALSE;
+static const boolean gAutoAnswerAltBehavior = FALSE;
+static const int gAutoAnswerTimer = 1;
+static const boolean gAutoAnswerOverride = TRUE;
+static const int gOffhookToFirstDigitTimer = 15000;
+static const int gSilentPeriodBetweenCallWaitingBursts = 10;
+static const int gRingSettingBusyStationPolicy = 0;
+static const int gBlfAudibleAlertSettingOfIdleStation = 0;
+static const int gBlfAudibleAlertSettingOfBusyStation = 0;
+static const int gJoinAcrossLines = 0;
+static const boolean gCnfJoinEnabled = TRUE;
+static const int gRollover = 0;
+static const boolean gTransferOnhookEnabled = FALSE;
+static const int gDscpForAudio = 184;
+static const int gDscpVideo = 136;
+static const int gT302Timer = 5000;
+static const int gLineIndex = 1;
+static const int gFeatureID = 9;
+static const char gProxy[] = "USECALLMANAGER";
+static const int gPort = 5060;
+static const char gDisplayName[] = "";
+static const char gMessagesNumber[] = "";
+static const boolean gCallerName = TRUE;
+static const boolean gCallerNumber = FALSE;
+static const boolean gRedirectedNumber = FALSE;
+static const boolean gDialedNumber = TRUE;
+static const unsigned char gMessageWaitingLampPolicy = 3;
+static const unsigned char gMessageWaitingAMWI = 1;
+static const unsigned char gRingSettingIdle = 4;
+static const unsigned char gRingSettingActive = 5;
+static const int gMaxNumCalls = 1;
+static const int gBusyTrigger = 1;
+static const unsigned char gAutoAnswerEnabled = 2 & 0x1;
+static const unsigned char gCallWaiting = 3 & 0x1;
+static const int gDeviceSecurityMode = 1;
+static const int gCcm2_sip_port = 5060;
+static const int gCcm3_sip_port = 5060;
+static const boolean gCcm1_isvalid = TRUE;
+static const int gDscpCallControl = 1;
+static const int gSpeakerEnabled = 1;
+static const char gExternalNumberMask[] = "";
+static const char gVersion[] = "0.1";
+static const boolean gRTCPMUX = FALSE;
+static const boolean gMAXAVBITRATE = FALSE; /* Following six are OPUS fmtp options */
+static const boolean gMAXCODEDAUDIOBW = FALSE;
+static const boolean gUSEDTX = FALSE;
+static const boolean gSTEREO = FALSE;
+static const boolean gUSEINBANDFEC = FALSE;
+static const boolean gCBR = FALSE;
+static const boolean gMAXPTIME = FALSE;
+static const int gSCTPPort = 5000;
+static const int gNumDataStreams = 16;
+
+#endif /* _CONFIG_H_ */
diff --git a/libs/sipcc/core/includes/configapp.h b/libs/sipcc/core/includes/configapp.h
new file mode 100644
index 0000000000..fae40922e5
--- /dev/null
+++ b/libs/sipcc/core/includes/configapp.h
@@ -0,0 +1,13 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef CONFIGAPP_H
+#define CONFIGAPP_H
+
+extern void configapp_init();
+extern void configapp_shutdown();
+extern void configapp_process_msg(uint32_t cmd, void *msg);
+
+#endif
+
diff --git a/libs/sipcc/core/includes/configmgr.h b/libs/sipcc/core/includes/configmgr.h
new file mode 100755
index 0000000000..3c0b4bee8a
--- /dev/null
+++ b/libs/sipcc/core/includes/configmgr.h
@@ -0,0 +1,62 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _CONFIGMGR_H_
+#define _CONFIGMGR_H_
+
+/*
+ * #defines for maximum length of the image names
+ * The MAX_LOAD_ID_LENGTH must be larger (or the same as)
+ * MAX_OLD_LOAD_ID_LENGTH or strange things may
+ * happen because they are used as indexes into
+ * arrays.
+ */
+#include "cpr_types.h"
+#define MAX_LOAD_ID_LENGTH 60
+#define MAX_LOAD_ID_STRING MAX_LOAD_ID_LENGTH + 1
+#define MAX_OLD_LOAD_ID_LENGTH 8
+#define MAX_OLD_LOAD_ID_STRING MAX_OLD_LOAD_ID_LENGTH + 1
+#define MAX_URL_LENGTH 128
+
+#define MAX_SYNC_LEN 33
+#define MAX_PHONE_LABEL 32
+
+/* Start of section for new "protocol-inspecific" calls */
+
+#define MAX_CONFIG_STRING_NAME 64
+#define DEFAULT_LINE 1
+
+#define YESSTR "YES"
+#define NOSTR "NO"
+#define IPOFZEROS "0.0.0.0"
+
+enum ACTIONATTR {
+ AA_IGNORE = 0,
+ AA_COMMIT = 1,
+ AA_RELOAD = 1 << 1,
+ AA_REGISTER = 1 << 2,
+ AA_FORCE = 1 << 3,
+ AA_RESET = 1 << 4,
+ AA_SETTINGS = 1 << 5,
+ AA_BU_REG = 1 << 6
+};
+
+/*********************************************************
+ *
+ * External Function Prototypes
+ *
+ *********************************************************/
+void config_get_string(int id, char *buffer, int buffer_len);
+void config_set_string(int id, char *buffer);
+void config_get_value(int id, void *buffer, int length);
+void config_set_value(int id, void *buffer, int length);
+
+void config_get_line_string(int id, char *buffer, int line, int buffer_len);
+void config_set_line_string(int id, char *buffer, int line);
+void config_get_line_value(int id, void *buffer, int length, int line);
+void config_set_line_value(int id, void *buffer, int length, int line);
+
+void config_init(void);
+
+#endif /* _CONFIGMGR_H_ */
diff --git a/libs/sipcc/core/includes/debug.h b/libs/sipcc/core/includes/debug.h
new file mode 100644
index 0000000000..19fd5e237b
--- /dev/null
+++ b/libs/sipcc/core/includes/debug.h
@@ -0,0 +1,108 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _DEBUG_INCLUDED_H /* allows multiple inclusion */
+#define _DEBUG_INCLUDED_H
+
+#include "cpr_types.h"
+#include "plat_api.h"
+#include "phone_debug.h"
+#include "CSFLog.h"
+#include
+
+typedef cc_int32_t (*debug_callback)(cc_int32_t argc, const char *argv[]);
+typedef cc_int32_t (*show_callback)(cc_int32_t argc, const char *argv[]);
+typedef cc_int32_t (*clear_callback)(cc_int32_t argc, const char *argv[]);
+
+typedef enum {
+ TEST_OPEN,
+ TEST_CLOSE,
+ TEST_KEY,
+ TEST_ONHOOK,
+ TEST_OFFHOOK,
+ TEST_SHOW,
+ TEST_HIDE,
+ TEST_PROFILE,
+ TEST_C3PO
+} test_command_t;
+
+
+typedef int32_t (*test_callback)(int32_t argc, const char *argv[],
+ test_command_t command);
+
+extern int32_t TestMode;
+extern int32_t TestShow;
+
+typedef enum {
+ DEBUG_ENTRY_TYPE_FLAG,
+ DEBUG_ENTRY_TYPE_DEBUG_FUNC,
+ DEBUG_ENTRY_TYPE_SHOW_FUNC
+} debug_entry_type_e;
+
+typedef struct {
+ const char *keyw;
+ union {
+ int32_t *flag;
+ debug_callback func;
+ show_callback show_func;
+ } u;
+ debug_entry_type_e type;
+ boolean show_tech;
+} debug_entry_t;
+
+typedef struct {
+ const char *keyw;
+ union {
+ int32_t *flag;
+ clear_callback func;
+ } u;
+} clear_entry_t;
+
+typedef struct {
+ const char *keyw;
+ const char *abrv;
+ const char *help;
+ boolean hidden;
+ union {
+ int32_t *flag;
+ test_callback func;
+ } u;
+ test_command_t command;
+} test_entry_t;
+
+
+typedef struct {
+ unsigned char flag;
+ unsigned char hookevent;
+ unsigned char keyevent; // keyevent and key will double as a timer value internally
+ unsigned char key;
+} testevent_t;
+
+// The next 4 defines are used as flag values to specify the event types in the queue.
+// Note that we cannot use the HOOKSCAN and KEYSCAN that are defined in phone.h, because
+// HOOKSCAN requires a full integer. In order to minimize space in the test event queue
+// we need short numbers.
+#define TEST_NONE 0
+#define TEST_KEYSCAN 1
+#define TEST_HOOKSCAN 2
+#define TEST_TIMER 0x80
+
+
+#define MAX_DEBUG_NAME 50
+#define MAX_SHOW_NAME 50
+#define MAX_CLEAR_NAME 50
+
+/*
+ * Prototypes for public functions
+ */
+void bind_test_keyword(const char *keyword, const char *abrv, boolean hidden,
+ test_callback func, test_command_t command,
+ const char *help);
+testevent_t TESTGetEvent(void);
+
+// Send debug output to CSFLog
+#define debugif_printf(format, ...) CSFLogDebug("debugif", format, ## __VA_ARGS__ )
+#define PR_ASSERT( test ) assert( test )
+
+#endif /* _DEBUG_INCLUDED_H */
diff --git a/libs/sipcc/core/includes/dialplan.h b/libs/sipcc/core/includes/dialplan.h
new file mode 100755
index 0000000000..ec1f93e610
--- /dev/null
+++ b/libs/sipcc/core/includes/dialplan.h
@@ -0,0 +1,111 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef DIALPLAN_H
+#define DIALPLAN_H
+
+#include
+#include "phone_types.h"
+
+#define DIALPLAN_MAX_SIZE 0x2000
+#define MAX_SUBTITUTIONS 5
+#define MAX_TONES 3
+#define MAX_TEMPLATE_LENGTH 196
+#define DIAL_ESCAPE '\\'
+#define MAX_DIALSTRING 256
+#define DIAL_TIMEOUT 10
+#define MAX_DP_VERSION_STAMP_LEN (64+1)
+extern char g_dp_version_stamp[MAX_DP_VERSION_STAMP_LEN];
+
+typedef enum {
+ DIAL_NOMATCH = 0,
+ DIAL_GIVETONE,
+ DIAL_WILDPATTERN,
+ DIAL_FULLPATTERN,
+ DIAL_FULLMATCH,
+ DIAL_IMMEDIATELY
+} DialMatchAction;
+
+/* Set enum values to match DialMatchAction */
+typedef enum {
+ DIALTONE_NOMATCH = 0,
+ DIALTONE_WILD = 2,
+ DIALTONE_FULL,
+ DIALTONE_EXACT
+} DialToneMatch;
+
+typedef enum {
+ UserUnspec,
+ UserPhone,
+ UserIP
+} UserMode;
+
+typedef enum {
+ RouteDefault, // Route using the default proxy
+ RouteEmergency, // Route using the emergency proxy
+ RouteFQDN // Route according to the FQDN in the entry
+} RouteMode;
+
+struct DialTemplate {
+ struct DialTemplate *next;
+ char *pattern;
+ line_t line;
+ char *rewrite;
+ int timeout;
+ UserMode userMode;
+ RouteMode routeMode;
+ int tones_defined;
+ vcm_tones_t tone[MAX_TONES];
+};
+
+struct StoredDialTemplate {
+ short size; // Size of header part of structure
+ short nextOffset; // total Number of bytes used in the entry
+ // A zero here is used as a last entry
+ int timeout;
+ line_t line;
+ UserMode userMode;
+ short pattern_offset; // Offset to the pattern string
+ short rewrite_offset; // Offset to the rewrite string
+ RouteMode routeMode;
+ int tones_defined;
+ vcm_tones_t tone[MAX_TONES];
+
+};
+
+typedef enum {
+ STATE_ANY,
+ STATE_GOT_MATCH,
+ STATE_GOT_MATCH_EQ,
+ STATE_GOT_LINE,
+ STATE_GOT_LINE_EQ,
+ STATE_GOT_TIMEOUT,
+ STATE_GOT_TIMEOUT_EQ,
+ STATE_GOT_USER,
+ STATE_GOT_USER_EQ,
+ STATE_GOT_REWRITE,
+ STATE_GOT_REWRITE_EQ,
+ STATE_GOT_ROUTE,
+ STATE_GOT_ROUTE_EQ,
+ STATE_GOT_TONE,
+ STATE_GOT_TONE_EQ,
+ STATE_START_TAG_COMPLETED, /* start tag parsing is complete when self-terminating () format is not used */
+ STATE_END_TAG_STARTED, /* end tag started when we see "" */
+ STATE_END_TAG_FOUND /* end tag is parsed */
+} ParseDialState;
+
+extern DialMatchAction MatchDialTemplate(const char *pattern,
+ const line_t line,
+ int *timeout,
+ char *rewrite, int rewritelen,
+ RouteMode *pRouteMode,
+ vcm_tones_t *pTone);
+void SaveDialTemplate(void);
+void RestoreDialPlan(void);
+void InitDialPlan(boolean);
+void FreeDialTemplates(void);
+extern short handle_dialplan(short, void *);
+extern boolean ParseDialTemplate(char *parseptr);
+
+#endif //DIALPLAN_H
diff --git a/libs/sipcc/core/includes/dialplanint.h b/libs/sipcc/core/includes/dialplanint.h
new file mode 100755
index 0000000000..bb0c4047fb
--- /dev/null
+++ b/libs/sipcc/core/includes/dialplanint.h
@@ -0,0 +1,93 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef DIALPLANINT_H
+#define DIALPLANINT_H
+
+#include "phone_types.h"
+#include "dialplan.h"
+
+#define BKSPACE_KEY 90
+#define DEFAULT_DIALTIMEOUT 30
+#define CISCO_PLAR_STRING "x-cisco-serviceuri-offhook"
+
+typedef struct timer_index_ {
+ line_t line;
+ callid_t call_id;
+} timer_index_t;
+
+typedef union timer_info_t_ {
+ void *whole;
+ timer_index_t index;
+} timer_info_t;
+
+/* dialplan interface data structure */
+typedef struct dp_int_t_ {
+ line_t line;
+ callid_t call_id;
+ char digit;
+ char digit_str[MAX_DIALSTRING];
+ boolean collect_more;
+ void *tmr_ptr;
+ char global_call_id[CC_GCID_LEN];
+ monitor_mode_t monitor_mode;
+} dp_int_t;
+
+typedef enum {
+ DP_NONE_TIMER,
+ DP_OFFHOOK_TIMER,
+ DP_INTERDIGIT_TIMER
+} dp_timer_type_e;
+
+typedef struct dp_data_t_ {
+ char gDialed[MAX_DIALSTRING];
+ char gReDialed[MAX_DIALSTRING];
+ line_t gRedialLine;
+ char empty_rewrite[MAX_DIALSTRING];
+
+ uint32_t offhook_timeout; /* timeout configured to wait after offhook */
+ void *dial_timer;
+ boolean gDialplanDone;
+ /* Indicates that local dialplan match has been completed */
+ boolean allow_proceed;
+ /* under certain conditions proceed has to be passed to
+ * UI even KPML is enabled. For example redial, which not
+ * collect more digits so freeze the screen by sending
+ * proceed to UI
+ */
+
+ line_t line; /* Line where which dialing is currently active */
+ callid_t call_id; /* call id of currently dialing call */
+ boolean url_dialing; /* Indicates dialing is url dialing */
+ timer_info_t timer_info;
+ dp_timer_type_e gTimerType;
+} dp_data_t;
+
+void dp_dial_timeout(void *);
+void dp_int_init_dialing_data(line_t line, callid_t call_id);
+void dp_int_update_key_string(line_t line, callid_t call_id, char *digits);
+void dp_int_store_digit_string(line_t line, callid_t call_id, char *digit_str);
+void dp_int_update_keypress(line_t line, callid_t call_id, unsigned char digit);
+void dp_int_dial_immediate(line_t line, callid_t call_id, boolean collect_more,
+ char *digit_str, char *g_call_id,
+ monitor_mode_t monitor_mode);
+void dp_int_do_redial(line_t line, callid_t call_id);
+void dp_int_onhook(line_t line, callid_t call_id);
+void dp_int_offhook(line_t line, callid_t call_id);
+void dp_int_update(line_t line, callid_t call_id, string_t called_num);
+int dp_init_template(const char *dp_file_name, int maxSize);
+void dp_int_cancel_offhook_timer(line_t line, callid_t call_id);
+
+
+boolean dp_offhook (line_t line, callid_t call_id);
+boolean dp_get_kpml_state(void);
+void dp_delete_last_digit(line_t line_id, callid_t call_id);
+void dp_store_digits(line_t line, callid_t call_id, unsigned char digit);
+char *dp_get_gdialed_digits(void);
+line_t dp_get_redial_line(void);
+void dp_reset(void);
+boolean dp_check_for_plar_line(line_t line);
+void dp_cancel_offhook_timer(void);
+
+#endif /* DIALPLANINT_H */
diff --git a/libs/sipcc/core/includes/digcalc.h b/libs/sipcc/core/includes/digcalc.h
new file mode 100644
index 0000000000..3665f9f922
--- /dev/null
+++ b/libs/sipcc/core/includes/digcalc.h
@@ -0,0 +1,42 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _DIGCALC_H_
+#define _DIGCALC_H_
+
+#define HASHLEN 16
+typedef char HASH[HASHLEN];
+#define HASHHEXLEN 32
+typedef char HASHHEX[HASHHEXLEN + 1];
+
+#define IN
+#define OUT
+
+/* calculate H(A1) as per HTTP Digest spec */
+void DigestCalcHA1(
+ IN char *pszAlg,
+ IN char *pszUserName,
+ IN char *pszRealm,
+ IN char *pszPassword,
+ IN char *pszNonce,
+ IN char *pszCNonce,
+ OUT HASHHEX SessionKey
+ );
+
+/* calculate request-digest/response-digest as per HTTP Digest spec */
+void DigestCalcResponse(
+ IN HASHHEX HA1, /* H(A1) */
+ IN char *pszNonce, /* nonce from server */
+ IN char *pszNonceCount, /* 8 hex digits */
+ IN char *pszCNonce, /* client nonce */
+ IN char *pszQop, /* qop-value: "", "auth", "auth-int" */
+ IN char *pszMethod, /* method from the request */
+ IN char *pszDigestUri, /* requested URL */
+ IN HASHHEX HEntity, /* H(entity body) if qop="auth-int" */
+ OUT HASHHEX Response /* request-digest or response-digest */
+ );
+
+void DigestString(char *string, HASHHEX response);
+
+#endif
diff --git a/libs/sipcc/core/includes/dns_utils.h b/libs/sipcc/core/includes/dns_utils.h
new file mode 100644
index 0000000000..51683bdf41
--- /dev/null
+++ b/libs/sipcc/core/includes/dns_utils.h
@@ -0,0 +1,77 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _DNS_UTILS_INCLUDED_H
+#define _DNS_UTILS_INCLUDED_H
+
+#include "dns_util.h"
+
+#define MAX_DNS_CON 10
+#define DNS_TO_CNT 400
+#define DNS_RSP_FLG 0x8000
+#define DNS_RSP_CODE 0xf
+
+#define DNS_HOST_TYPE 0x01
+#define DNS_CNAME_TYPE 0x05
+#define DNS_SRV_TYPE 0x21
+#define DNS_PTR_TYPE 0xc0
+
+#define DNS_IN_CLASS 1
+
+#define DNS_INUSE_FREE 0
+#define DNS_INUSE_WAIT 1
+#define DNS_INUSE_CACHED 2
+
+/* per suggestion RFC in about sanity checking */
+#define DNS_MIN_TTL (5*60) /* 5 minutes */
+#define DNS_MAX_TTL (24*60*60) /* 1 day */
+
+#define KAZOO_DNS_DEBUG 1
+
+#define DNS_OK 0
+#define DNS_ERR_NOBUF 1
+#define DNS_ERR_INUSE 2
+#define DNS_ERR_TIMEOUT 3
+#define DNS_ERR_NOHOST 4
+#define DNS_ERR_HOST_UNAVAIL 5
+#define DNS_ERR_BAD_DATA 6
+#define DNS_ERR_LINK_DOWN 7
+#define DNS_ENTRY_VALID 8
+#define DNS_ENTRY_INVALID 9
+#define DNS_ERR_TTL_EXPIRED 10
+
+#define DNS_MAX_SRV_REQ 20
+
+#define DNS_HNAME_PAD 10
+#define DOMAIN_NAME_LENGTH 256
+
+typedef struct rr_reply_rec_ {
+ uint8_t ordered;
+ uint32_t priority;
+ uint32_t weight;
+ uint32_t rweight;
+ uint32_t ttl;
+ uint32_t port;
+ uint32_t rcvd_order;
+ int8_t *name;
+} rr_reply_rec_t;
+
+typedef struct master_rr_list_ {
+ uint8_t valid;
+ uint16_t ref_count;
+ uint8_t num_recs;
+ int8_t domain_name[DOMAIN_NAME_LENGTH + 1];
+ rr_reply_rec_t **rr_recs_order;
+} master_rr_list_t;
+
+typedef struct call_rr_list_ {
+ uint8_t current_index;
+ uint8_t max_index;
+ uint8_t master_index;
+ int8_t *domain_name;
+ rr_reply_rec_t **rr_recs_order;
+} call_rr_list_t;
+
+
+#endif /* _DNS_UTILS_INCLUDED_H */
diff --git a/libs/sipcc/core/includes/dtmf.h b/libs/sipcc/core/includes/dtmf.h
new file mode 100644
index 0000000000..906bce88ed
--- /dev/null
+++ b/libs/sipcc/core/includes/dtmf.h
@@ -0,0 +1,27 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _DTMF_H_
+#define _DTMF_H_
+
+typedef enum _DTMFState {
+ DTMF_IDLE,
+ DTMF_START,
+ DTMF_CONT,
+ DTMF_END
+} DTMFState;
+
+typedef enum {
+ DTMF_OUTOFBAND_NONE = 0,
+ DTMF_OUTOFBAND_AVT,
+ DTMF_OUTOFBAND_AVT_ALWAYS
+} DtmfOutOfBandTransport_t;
+
+boolean RTPDtmfInbandGet(void);
+DtmfOutOfBandTransport_t RTPDtmfOutofbandGet(void);
+void RTPDtmfInbandSet(boolean val);
+void RTPDtmfOutofbandSet(uint16_t channel, DtmfOutOfBandTransport_t transport,
+ int payload_type);
+
+#endif
diff --git a/libs/sipcc/core/includes/embedded.h b/libs/sipcc/core/includes/embedded.h
new file mode 100644
index 0000000000..68a076b72c
--- /dev/null
+++ b/libs/sipcc/core/includes/embedded.h
@@ -0,0 +1,24 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef embedded_hpp
+#define embedded_hpp
+
+typedef signed char INT8;
+typedef signed short INT16;
+typedef signed int INT32;
+
+typedef unsigned char UINT8;
+typedef unsigned short UINT16;
+typedef unsigned int UINT32;
+
+typedef signed char int8;
+typedef signed short int16;
+typedef signed int int32;
+
+typedef unsigned char uint8;
+typedef unsigned short uint16;
+typedef unsigned int uint32;
+
+#endif
diff --git a/libs/sipcc/core/includes/intelpentiumtypes.h b/libs/sipcc/core/includes/intelpentiumtypes.h
new file mode 100644
index 0000000000..8e9955fadb
--- /dev/null
+++ b/libs/sipcc/core/includes/intelpentiumtypes.h
@@ -0,0 +1,19 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef IntelPentium_hpp
+#define IntelPentium_hpp
+
+typedef char INT8;
+typedef short INT16;
+typedef int INT32;
+
+typedef unsigned char UINT8;
+typedef unsigned short UINT16;
+typedef unsigned int UINT32;
+
+typedef float FLOAT32;
+typedef double FLOAT64;
+
+#endif
\ No newline at end of file
diff --git a/libs/sipcc/core/includes/kpml_common_util.h b/libs/sipcc/core/includes/kpml_common_util.h
new file mode 100755
index 0000000000..6238112432
--- /dev/null
+++ b/libs/sipcc/core/includes/kpml_common_util.h
@@ -0,0 +1,49 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef __KPML_COMMON_UTIL_H__
+#define __KPML_COMMON_UTIL_H__
+
+/* KPML status code for kpml decoder */
+typedef enum {
+ KPML_STATUS_OK,
+ KPML_ERROR_ENCODE,
+ KPML_ERROR_INVALID_ATTR,
+ KPML_ERROR_INVALID_ELEM,
+ KPML_ERROR_INVALID_VALUE,
+ KPML_ERROR_INTERNAL,
+ KPML_ERROR_MISSING_ATTR,
+ KPML_ERROR_MISSING_FIELD,
+ KPML_ERROR_NOMEM,
+ KPML_ERROR_XML_PARSER
+} kpml_status_type_t;
+
+
+/* single_digit_bitmask */
+#define REGEX_0 1
+#define REGEX_1 (1<<1)
+#define REGEX_2 (1<<2)
+#define REGEX_3 (1<<3)
+#define REGEX_4 (1<<4)
+#define REGEX_5 (1<<5)
+#define REGEX_6 (1<<6)
+#define REGEX_7 (1<<7)
+#define REGEX_8 (1<<8)
+#define REGEX_9 (1<<9)
+#define REGEX_STAR (1<<10)
+#define REGEX_POUND (1<<11)
+#define REGEX_A (1<<12)
+#define REGEX_B (1<<13)
+#define REGEX_C (1<<14)
+#define REGEX_D (1<<15)
+#define REGEX_PLUS (1<<16)
+
+#define REGEX_0_9 REGEX_0|REGEX_1|REGEX_2|REGEX_3|REGEX_4|REGEX_5|REGEX_6|REGEX_7|REGEX_8|REGEX_9
+
+#define KPML_DEFAULT_DTMF_REGEX "[x*#ABCD]"
+
+kpml_status_type_t kpml_parse_regex_str(char *regex_str,
+ kpml_regex_match_t *regex_match);
+
+#endif /* __KPML_COMMON_UTIL_H__ */
diff --git a/libs/sipcc/core/includes/kpmlmap.h b/libs/sipcc/core/includes/kpmlmap.h
new file mode 100755
index 0000000000..568895cbc3
--- /dev/null
+++ b/libs/sipcc/core/includes/kpmlmap.h
@@ -0,0 +1,177 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef KPMLMAP_H
+#define KPMLMAP_H
+
+#include "xml_parser_defines.h"
+#include "singly_link_list.h"
+#include "subapi.h"
+
+#define KPML_ESCAPE '\\'
+#define MAX_DIALSTRING 256
+#define DIAL_TIMEOUT 10
+#define MAX_KPML_TAG_STRING 32
+#define MAX_KPML_TEXT_STRING 16
+#define KPML_BUFFERS_NUM 100
+
+#define KPML_VER_STR "1.0"
+#define KPML_ENTER_STR "#"
+#define NUM_OF_REGX 1
+
+typedef enum {
+ KPML_NOMATCH = 0,
+ KPML_GIVETONE,
+ KPML_WILDPATTERN,
+ KPML_FULLPATTERN,
+ KPML_FULLMATCH,
+ KPML_IMMEDIATELY
+} kpml_match_action_e;
+
+typedef enum {
+ KPML_SUCCESS = 200,
+ KPML_USER_TERM_NOMATCH = 402,
+ KPML_TIMER_EXPIRE = 423,
+ KPML_NO_DIALOG = 481,
+ KPML_SUB_EXPIRE = 487,
+ KPML_BAD_EVENT = 489,
+ KPML_BAD_DOC = 501,
+ KPML_NO_PERSISTENT = 531,
+ KPML_NO_MULTIPLE = 532,
+ KPML_NO_MULITPLE_CALL_LEG = 533
+} kpml_resp_code_e;
+
+typedef enum {
+ KPML_NONE = 0x0,
+ KPML_SIGNAL_ONLY = 0x1,
+ KPML_DTMF_ONLY = 0x2,
+ KPML_BOTH = 0x3
+} kpml_config_e;
+
+#define KPML_SUCCESS_STR "OK"
+#define KPML_USER_TERM_NOMATCH_STR "No Match"
+#define KPML_TIMER_EXPIRE_STR "Timer Expired"
+#define KPML_SUB_EXPIRE_STR "Subscription Expired"
+#define KPML_ATTR_NOT_SUPPORTED_STR "Attribute not supported"
+#define KPML_TRYING_STR "Trying"
+
+
+typedef enum {
+ KPML_ONE_SHOT = 0,
+ KPML_PERSISTENT,
+ KPML_SINGLY_NOTIFY
+} kpml_sub_type_e;
+
+typedef enum {
+ KPML_NO_TIMER,
+ KPML_INTERDIGIT_TIMER,
+ KPML_CRITICAL_TIMER,
+ KPML_EXTRADIGIT_TIMER,
+ KPML_LONGDIGIT_TIMER
+} kpml_timer_e;
+
+typedef enum {
+ NO_SUB_DATA = 0,
+ SUB_DATA_FOUND = 1,
+ NOTIFY_SENT
+} kpml_state_e;
+
+typedef struct kpml_Q_digit_t_ {
+ char digits[MAX_DIALSTRING];
+ int dig_head;
+ int dig_tail;
+} kpml_Q_dig;
+
+typedef struct {
+ line_t line;
+ callid_t call_id;
+ void *timer;
+} kpml_key_t;
+
+typedef struct kpml_regex_match_s {
+ int num_digits;
+ union {
+ unsigned long single_digit_bitmask;
+ } u;
+} kpml_regex_match_t;
+
+typedef struct kpml_data_t_ {
+
+ line_t line;
+ callid_t call_id;
+ sub_id_t sub_id;
+
+ unsigned long sub_duration;
+ void *sub_timer;
+ kpml_key_t subtimer_key;
+
+ /* Hold regx received by SUB */
+ struct Regex regex[NUM_OF_REGX];
+
+ kpml_regex_match_t regex_match[NUM_OF_REGX];
+
+ /* If this is set then send out 402 response after # key */
+ boolean enterkey;
+
+ uint32_t kpml_id;
+
+ /* if this persistent */
+ kpml_sub_type_e persistent;
+ int flush;
+
+ /* timeout duration */
+ xml_unsigned32 inttimeout;
+ xml_unsigned32 crittimeout;
+ xml_unsigned32 extratimeout;
+
+ /* timer pointers for digits */
+ void *inter_digit_timer;
+ void *critical_timer;
+ void *extra_digit_timer;
+
+ kpml_key_t inttime_key;
+ kpml_key_t crittime_key;
+ kpml_key_t extratime_key;
+
+ xml_unsigned16 longhold;
+ xml_unsigned8 longrepeat;
+ xml_unsigned8 nopartial;
+
+ /* Store dialed digits */
+ char kpmlDialed[MAX_DIALSTRING];
+ boolean last_dig_bkspace;
+
+ char q_digits[MAX_DIALSTRING];
+ int dig_head;
+ int dig_tail;
+
+ boolean sub_reject; /* If this varilable is set reject
+ * the subscription. There are cases
+ * where INV has been sent out premeturaly
+ * If the B2BUA asks for more digit by
+ * subsctiption, then reject thoese
+ */
+
+ boolean pending_sub;
+
+ boolean enable_backspace;
+ /* Setting this variable will enable backspace
+ */
+
+} kpml_data_t;
+
+kpml_state_e kpml_update_dialed_digits(line_t line, callid_t call_id,
+ char digit);
+void kpml_flush_quarantine_buffer(line_t line, callid_t call_id);
+void kpml_sm_register(void);
+void kpml_quarantine_digits(line_t line, callid_t call_id, char digit);
+void kpml_init(void);
+void kpml_shutdown(void);
+void kpml_set_subscription_reject(line_t line, callid_t call_id);
+boolean kpml_get_state(void);
+void kpml_inter_digit_timer_callback(void *);
+void kpml_subscription_timer_callback(void *);
+boolean kpml_is_subscribed (callid_t call_id, line_t line);
+
+#endif //KPMLMAP_H
diff --git a/libs/sipcc/core/includes/md5.h b/libs/sipcc/core/includes/md5.h
new file mode 100644
index 0000000000..9a7381c12f
--- /dev/null
+++ b/libs/sipcc/core/includes/md5.h
@@ -0,0 +1,57 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+ * rights reserved.
+ *
+ * License to copy and use this software is granted provided that it
+ * is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+ * Algorithm" in all material mentioning or referencing this software
+ * or this function.
+ *
+ * License is also granted to make and use derivative works provided
+ * that such works are identified as "derived from the RSA Data
+ * Security, Inc. MD5 Message-Digest Algorithm" in all material
+ * mentioning or referencing the derived work.
+ *
+ * RSA Data Security, Inc. makes no representations concerning either
+ * the merchantability of this software or the suitability of this
+ * software for any particular purpose. It is provided "as is"
+ * without express or implied warranty of any kind.
+ *
+ * These notices must be retained in any copies of any part of this
+ * documentation and/or software.
+ */
+
+#ifndef _MD5_H
+#define _MD5_H
+
+/* delineate the cisco changes to the RSA supplied module */
+#define CISCO_MD5_MODS
+
+#if defined(CISCO_MD5_MODS)
+
+#define MD5_LEN 16
+
+#endif /* defined(CISCO_MD5_MODS) */
+
+/* MD5 context. */
+typedef struct {
+ unsigned long int state[4]; /* state (ABCD) */
+ unsigned long int count[2]; /* number of bits, modulo 2^64 (lsb first) */
+ unsigned char buffer[64]; /* input buffer */
+} MD5_CTX;
+
+void MD5Init(MD5_CTX *);
+void MD5Update(MD5_CTX *, unsigned char *, unsigned int);
+void MD5Final(unsigned char[16], MD5_CTX *);
+
+//#define MD5TESTSUITE 1
+#if defined(MD5TESTSUITE) /* only needed if running MD5 verfication tests */
+void MDString(char *string);
+void MDPrint(char *digest);
+void MDTestSuite(void);
+#endif
+
+#endif /* _MD5_H */
diff --git a/libs/sipcc/core/includes/memory.h b/libs/sipcc/core/includes/memory.h
new file mode 100755
index 0000000000..4a0fc35cef
--- /dev/null
+++ b/libs/sipcc/core/includes/memory.h
@@ -0,0 +1,35 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _MEMORY_H_
+#define _MEMORY_H_
+
+/*
+ * DESCRIPTION
+ * This module contains the functions which implement the dynamic memory
+ * management routines. The following assumptions/rules apply:
+ * 1) Packets are allocated a minimum of MIN_BLOCK + BLOCK_OVERHEAD bytes.
+ * 2) The size of the heap is set at link time, using the -heap flag
+ * The allocation and sizing of the heap is a cooperative effort
+ * involving the linker, this file, and "sysmem.c".
+ * 3) The heap can be reset at any time by calling the function "minit"
+ *
+ */
+
+
+/*
+ *--------------------DEPRECATED FILE-------------------------------
+ *
+ * As part of Skittles project this file is deprecated.
+ * DO NOT add anything to this file. use cpr_stdlib.h instead
+ * If you are doing SYNC merges _DO_ _NOT_ merge anything from parent
+ * This file is kept here because it comes from parent/grand parent branches
+ * and will not be removed from clearcase till Skittles collapses.
+ * [The fAQ on cc tools contains details of why ]
+ *
+ * If you have questions send email to skittles-dev
+ *---------------------------------------------------------------
+ */
+
+#endif
diff --git a/libs/sipcc/core/includes/misc_apps_task.h b/libs/sipcc/core/includes/misc_apps_task.h
new file mode 100644
index 0000000000..baa5214d93
--- /dev/null
+++ b/libs/sipcc/core/includes/misc_apps_task.h
@@ -0,0 +1,14 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef MISC_APP_TASK_H
+#define MISC_APP_TASK_H
+
+extern cprMsgQueue_t s_misc_msg_queue;
+
+extern cpr_status_e MiscAppTaskSendMsg(uint32_t cmd, cprBuffer_t buf,
+ uint16_t len);
+extern void MiscAppTask(void *arg);
+
+#endif /* MISC_APP_TASK_H */
diff --git a/libs/sipcc/core/includes/misc_util.h b/libs/sipcc/core/includes/misc_util.h
new file mode 100644
index 0000000000..fcd2e90f9f
--- /dev/null
+++ b/libs/sipcc/core/includes/misc_util.h
@@ -0,0 +1,9 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef __MISC_UTIL_H__
+#define __MISC_UTIL_H__
+unsigned long gmt_string_to_seconds(char *gmt_string, unsigned long *seconds);
+long diff_current_time(unsigned long t1, unsigned long *difference);
+#endif
diff --git a/libs/sipcc/core/includes/phntask.h b/libs/sipcc/core/includes/phntask.h
new file mode 100644
index 0000000000..24b5fceedb
--- /dev/null
+++ b/libs/sipcc/core/includes/phntask.h
@@ -0,0 +1,309 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef PHNTASK_H
+#define PHNTASK_H
+
+/* used for certain bugtraps */
+#define ERRid 0xE0
+#define ERR_1 0xE1
+#define ERR_2 0XE2
+#define ERR_3 0XE3
+#define ERR_4 0XE4
+#define ERR_5 0XE5
+
+/*
+ * SysHdr Network Command definitions (0x00 - 0x0F)
+ */
+#define RCV_CMD 0x00
+#define TRAP_CMD 0x01
+#define OPEN_CMD 0x02
+#define CLOSE_CMD 0x03
+#define HANG_CMD 0x04
+#define TO_CMD 0x05
+#define ISR_CMD 0x06
+#define ACK_CMD 0x07
+#define NACK_CMD 0x08
+#define PING_CMD 0x09
+#define JOIN_CMD 0x0A
+#define LEAVE_CMD 0x0B
+#define TO2_CMD 0x0C
+#define TO3_CMD 0x0D
+
+/*---------------------------------------------
+ * Message Definition
+ *
+ * original requirement is to get a unique id I guess
+ * for TNP we just get some unique numbers through enum
+ */
+
+enum {
+ /* CPR Messages */
+ TIMER_EXPIRATION,
+
+ /* DHCP Messages */
+ DHCP_UDP,
+ DHCP_TMR,
+ DHCP_TFTP,
+ DHCP_DHCP,
+ DHCP_TO,
+ DHCP_RESET_IP,
+ DHCP_DNS,
+ DHCP_CFG,
+ DHCP_CDP,
+ DHCP_RESTART,
+ DHCP_SOC,
+ DHCP_UI,
+
+ /* SNTP Messages */
+ SNTP_UDP,
+ SNTP_REQ,
+
+ /* TFTP Messages */
+ TFTP_PHN,
+ TFTP_CFG,
+ TFTP_DHCP,
+ TFTP_UDP,
+ TFTP_TO,
+
+ /* UDP Messages */
+ UDP_TFTP,
+ UDP_DHCP,
+ UDP_DNS,
+ UDP_RTP,
+ UDP_SNTP,
+
+ /* TCP Messages */
+ TCP_PHN,
+ TCP_PHN_OPEN,
+ TCP_PHN_CLOSE,
+ TCP_CFG,
+ TCP_CFG_OPEN,
+ TCP_CFG_CLOSE,
+ TCP_TO,
+ TCP_SOC,
+
+ /* HTTP Messages */
+ HTTP_RCV,
+
+ /* Socket Messages */
+ ICMP_DHCP,
+ ICMP_ARP,
+ ICMP_RTP,
+ SOC_ICMP,
+ SOC_IGMP,
+ SOC_ROUTE,
+ SOC_FRAG,
+ IGMP_PHN_JOIN,
+ IGMP_PHN_LEAVE,
+ IP_PHN,
+ SOC_ISR,
+ NET_CDP,
+
+ /* Phone Messages */
+ PHN_TCP,
+ PHN_CFG,
+ PHN_CFG_UI,
+ PHN_TFTP,
+ PHN_TICK_TO,
+ PHN_DSP,
+ PHN_REG,
+
+ PHN_DIS,
+
+ /* DNS Messages */
+ DNS_DHCP,
+ DNS_CFG,
+ DNS_CFG_URL,
+ DNS_UDP,
+ DNS_TO,
+
+
+ CFG_DNS,
+ CFG_TFTP,
+ CFG_TMR,
+ CFG_CDP_TMR,
+ CFG_UI,
+ CFG_NET_CFG,
+ CFG_FMW_CFG,
+ CFG_STA_CFG,
+ CFG_KAZOO_CFG,
+ CFG_ETH_MEDIA,
+ TCP_PHN_CFG_TCP_DONE,
+
+ NET_DNS,
+ CDP_C3PO,
+ CDP_TO_WAIT,
+ CDP_ETH,
+ CDP_TO_SYNC,
+ CDP_SEND,
+ CDP_CACHE_TO,
+ CDP_NET,
+ CDP_TRIG,
+ C3PO_ETH_MODE,
+
+ /* RTP Messages */
+ RTP_ISR,
+ RTP_UDP,
+
+ /* TTY Messages */
+ TTY_TTY,
+
+ /* SIP Task Messages */
+ SIP_UDP,
+ SIP_GSM,
+ SIP_REG_REQ,
+ SIP_REG_CANCEL,
+ SIP_REG_PHONE_IDLE,
+ SIP_REG_FALLBACK,
+ SIP_TMR_REG_ACK,
+ SIP_TMR_REG_EXPIRE,
+ SIP_TMR_REG_WAIT,
+ SIP_TMR_REG_RETRY,
+ SIP_TMR_REG_STABLE,
+ SIP_TMR_INV_LOCALEXPIRE,
+ SIP_TMR_INV_EXPIRE,
+ SIP_TMR_MSG_RETRY,
+ SIP_REG_CLEANUP,
+ CC_EVENT,
+ SIP_ICMP_UNREACHABLE,
+ SIP_TMR_SUPERVISION_DISCONNECT,
+ SIP_TMR_CALL_DISCONNECT,
+ SIP_TMR_MSG_RETRY_SUBNOT,
+ SIP_TMR_PERIODIC_SUBNOT,
+ SIP_TMR_GLARE_AVOIDANCE,
+ SIPSPI_EV_CC_SUBSCRIBE_REGISTER,
+ SIPSPI_EV_CC_SUBSCRIBE,
+ SIPSPI_EV_CC_SUBSCRIBE_RESPONSE,
+ SIPSPI_EV_CC_NOTIFY,
+ SIPSPI_EV_CC_NOTIFY_RESPONSE,
+ SIPSPI_EV_CC_SUBSCRIPTION_TERMINATED,
+ SIPSPI_EV_CC_PUBLISH_REQ,
+ REG_MGR_STATE_CHANGE,
+ SUB_MSG_KPML_TERMINATE,
+ SUB_MSG_KPML_SUBSCRIBE,
+ SUB_MSG_KPML_NOTIFY_ACK,
+ SUB_MSG_KPML_SUBSCRIBE_TIMER,
+ SUB_MSG_KPML_DIGIT_TIMER,
+ DP_MSG_INIT_DIALING,
+ DP_MSG_DIGIT_TIMER,
+ DP_MSG_DIGIT_STR,
+ DP_MSG_STORE_DIGIT,
+ DP_MSG_DIGIT,
+ DP_MSG_DIAL_IMMEDIATE,
+ DP_MSG_REDIAL,
+ DP_MSG_ONHOOK,
+ DP_MSG_OFFHOOK,
+ DP_MSG_CANCEL_OFFHOOK_TIMER,
+ DP_MSG_UPDATE,
+ SIP_TMR_STANDBY_KEEPALIVE,
+ SUB_MSG_PRESENCE_GET_STATE,
+ SUB_MSG_PRESENCE_TERM_REQ,
+ SUB_MSG_PRESENCE_TERM_REQ_ALL,
+ SUB_MSG_PRESENCE_SUBSCRIBE_RESP,
+ SUB_MSG_PRESENCE_NOTIFY,
+ SUB_MSG_PRESENCE_UNSOLICITED_NOTIFY,
+ SUB_MSG_PRESENCE_TERMINATE,
+ SUB_HANDLER_INITIALIZED,
+ SIP_TMR_DM_SHR_WAIT_DM_UPD_EVENT,
+ SIP_SHUTDOWN,
+ SIP_TMR_SHUTDOWN_PHASE2,
+ SIP_RESTART,
+ SUB_MSG_CONFIGAPP_SUBSCRIBE,
+ SUB_MSG_CONFIGAPP_TERMINATE,
+ SUB_MSG_CONFIGAPP_NOTIFY,
+ SUB_MSG_CONFIGAPP_NOTIFY_ACK,
+ SIP_REG_UPDATE,
+ SUB_MSG_FEATURE_SUBSCRIBE_RESP,
+ SUB_MSG_FEATURE_NOTIFY,
+ SUB_MSG_FEATURE_TERMINATE,
+ SUB_MSG_B2BCNF_SUBSCRIBE_RESP,
+ SUB_MSG_B2BCNF_NOTIFY,
+ SUB_MSG_B2BCNF_TERMINATE,
+ THREAD_UNLOAD,
+ DCSM_EV_READY,
+
+ /* GSM Messages */
+ GSM_RM,
+ GSM_FM,
+ GSM_GSM,
+ GSM_SIP,
+ FM_GSM
+};
+
+#define REG_CMD_PRINT(arg) \
+ (arg == SIP_REG_REQ ? "SIP_REG_REQ" : \
+ arg == SIP_REG_CANCEL ? "SIP_REG_CANCEL" : \
+ arg == SIP_REG_PHONE_IDLE ? "SIP_REG_PHONE_IDLE" : \
+ arg == SIP_REG_FALLBACK ? "SIP_REG_FALLBACK" : \
+ arg == SIP_TMR_REG_ACK ? "SIP_TMR_REG_ACK" : \
+ arg == SIP_TMR_REG_EXPIRE ? "SIP_TMR_REG_EXPIRE" : \
+ arg == SIP_TMR_REG_WAIT ? "SIP_TMR_REG_WAIT" : \
+ arg == SIP_TMR_REG_RETRY ? "SIP_TMR_REG_RETRY" : \
+ arg == SIP_TMR_REG_STABLE ? "SIP_TMR_REG_STABLE" : \
+ arg == SIP_REG_CLEANUP ? "SIP_REG_CLEANUP" : "")\
+
+
+
+#define TCP_USR_OPEN TCP_PHN_OPEN
+#define TCP_USR_CLOSE TCP_PHN_CLOSE
+#define TCP_USR TCP_PHN
+#define IGMP_USR_JOIN IGMP_PHN_JOIN
+#define IGMP_USR_LEAVE IGMP_PHN_LEAVE
+
+/*
+ * END INTER-TASK COMMANDS
+ *
+ */
+
+
+
+/*
+ * This is used by the config task to allow it to
+ * accept messages sent to it by the phone task.
+ */
+#define TFTP_USR TFTP_PHN
+
+
+/*
+ * Stack Definition
+ * Stacks need to be 32bit aligned.
+ */
+
+#define STKSZ 61440 //default stacksize rountable platform
+
+
+#if defined SIP_OS_LINUX
+
+#define NICE_STEP -4
+#define TIMER_THREAD_RELATIVE_PRIORITY 4*(NICE_STEP) /* -16 */
+/* redid priorities to adjust relative priority with EDT cannot
+ use NICE_STEP so using absolute numbers here */
+#define GSM_THREAD_RELATIVE_PRIORITY -14
+#define SIP_THREAD_RELATIVE_PRIORITY -14
+#define APP_THREAD_RELATIVE_PRIORITY -14
+#define CCPROVIDER_THREAD_RELATIVE_PRIORITY -14
+
+#elif defined SIP_OS_OSX
+
+#define NICE_STEP -4
+#define TIMER_THREAD_RELATIVE_PRIORITY 4*(NICE_STEP) /* -16 */
+#define GSM_THREAD_RELATIVE_PRIORITY 3*(NICE_STEP) /* -12 */
+#define SIP_THREAD_RELATIVE_PRIORITY 3*(NICE_STEP) /* -12 */
+#define APP_THREAD_RELATIVE_PRIORITY 3*(NICE_STEP) /* -12 */
+#define CCPROVIDER_THREAD_RELATIVE_PRIORITY 3*(NICE_STEP) /*-12 */
+
+#elif defined SIP_OS_WINDOWS
+
+#define TIMER_THREAD_RELATIVE_PRIORITY 0
+#define GSM_THREAD_RELATIVE_PRIORITY -1
+#define SIP_THREAD_RELATIVE_PRIORITY -1
+#define APP_THREAD_RELATIVE_PRIORITY -1
+#define CCPROVIDER_THREAD_RELATIVE_PRIORITY -1
+
+#endif
+
+extern int platThreadInit(char *threadName);
+
+#endif /* PHNTASK_H */
diff --git a/libs/sipcc/core/includes/phone.h b/libs/sipcc/core/includes/phone.h
new file mode 100644
index 0000000000..62fa07d75d
--- /dev/null
+++ b/libs/sipcc/core/includes/phone.h
@@ -0,0 +1,504 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef PHONE_H
+#define PHONE_H
+
+#include "text_strings.h"
+
+#include "sessionConstants.h"
+
+// define device reset types
+typedef enum {
+ DEVICE_RESET = CC_DEVICE_RESET,
+ DEVICE_RESTART = CC_DEVICE_RESTART,
+ ICMP_UNREACHABLE_RESET = CC_DEVICE_ICMP_UNREACHABLE
+} DeviceResetType;
+
+/*
+ * When not building IRX or attempting to emluate IRX
+ * define the irx_lst_blk structure
+ */
+typedef int32_t irx_lst_blk;
+#if defined SIP_OS_WINDOWS
+/*
+ * When attempting to emulate TNP, but use 79xx BTXML
+ * define the following
+ */
+typedef int32_t irx_tsk_blk;
+typedef int32_t irx_tmr_buf;
+
+#include "tnpphone.h"
+#endif
+
+
+#define APP_MAX_SIZE 0x60000L
+#define MAX_CTL_FILE_SIZE 0x8000L
+
+#define disableInt IRXDISAB
+#define enableInt IRXENAB
+#define intrOff IRXHRDDIS
+#define intrOn IRXHRDENA
+
+#define MAX_LINES_7940 2
+#define MAX_LINES_7960 6
+#define DSP_LOAD_ID_MAX 28
+#define OLD_DSP_LOAD_ID_MAX 8
+
+/*
+ * System timer tick (clock interrupt) specifications.
+ */
+#define TICKS_PER_SECOND 100 /* 10ms. per tick */
+#define SECONDS_TO_TICKS(SECS) ((SECS) * TICKS_PER_SECOND)
+#define TICKS_TO_SECONDS(TICKS) ((TICKS)/ TICKS_PER_SECOND)
+#define MILLISECONDS_TO_TICKS(MILLISECS) (((MILLISECS)*(TICKS_PER_SECOND))/1000)
+
+enum {
+ DSP_RST,
+ GPIO_A = 4,
+ GPIO_B,
+ GPIO_C,
+ GPIO_D,
+ gpioMax
+};
+
+typedef struct {
+ uint8_t loadid[256];
+ uint8_t apploadid[8];
+ uint32_t chksum; // file checksum
+ uint32_t applen; // file len
+ uint32_t appcmp; // compressed/uncompressed
+ uint32_t cmpchksum; // file checksum
+ uint32_t cmplen; // file len
+} LoadHdr;
+
+typedef struct {
+ uint8_t apploadid[DSP_LOAD_ID_MAX];
+ uint32_t chksum; // file checksum
+ uint32_t applen; // file len
+ uint32_t appcmp; // compressed/uncompressed
+ uint32_t cmpchksum; // file checksum
+ uint32_t cmplen; // file len
+
+} DSPLoadHdr;
+
+typedef struct {
+ uint8_t apploadid[OLD_DSP_LOAD_ID_MAX];
+ uint32_t chksum; // file checksum
+ uint32_t applen; // file len
+ uint32_t appcmp; // compressed/uncompressed
+ uint32_t cmpchksum; // file checksum
+ uint32_t cmplen; // file len
+
+} LegacyDSPLoadHdr;
+
+typedef struct {
+ uint16_t valid;
+ uint16_t notused[3];
+ uint16_t hw_ver_hi;
+ uint16_t hw_ver_low;
+ uint8_t mac[6];
+ int8_t model[20];
+ uint16_t feature_bits;
+ uint16_t ext;
+ uint16_t license[20];
+ int8_t serial_number[20];
+} MfgBlk;
+
+#define GPIO_IO_SEL_SHIFT 8
+
+#define GPIOA_LBK_ON 1
+#define GPIOA_MSG_LED 4
+#define GPIOA_SPKR_LED 5
+#define GPIOA_MUTE_LED 6
+#define GPIOA_HDST_LED 7
+#define GPIOA_IO_MASK ((1<<(GPIOA_LBK_ON+GPIO_IO_SEL_SHIFT))|\
+ (1<<(GPIOA_MSG_LED+GPIO_IO_SEL_SHIFT))|\
+ (1<<(GPIOA_SPKR_LED+GPIO_IO_SEL_SHIFT))|\
+ (1<<(GPIOA_MUTE_LED+GPIO_IO_SEL_SHIFT))|\
+ (1<<(GPIOA_HDST_LED+GPIO_IO_SEL_SHIFT)))
+
+#define GPIOD_HANDSET 0
+#define GPIOD_SPKER 1
+#define GPIOD_PHY_MDC 3
+#define GPIOD_PHY_MDIO 4
+#define GPIOD_IO_RST_HI 5
+#define GPIOD_IO_RST_LO 6
+#define GPIOD_IO_MASK 0xff00
+
+typedef volatile struct {
+ uint16_t reg;
+ uint16_t unused;
+} s_rbbreg;
+
+enum {
+ rbbTimeout,
+ rbbAPIWs,
+ rbbWbufEn,
+ rbbAccessFactor0,
+ rbbAccessFactor1,
+ rbbAccessFactor2,
+ rbbAccessFactor3,
+ rbbIntrSw,
+ rbbMax
+};
+
+extern s_rbbreg RBBReg[rbbMax];
+
+#define DCFG_PROGRAMMED 0x12300000L
+#define DCFG_FIXED_VLAN 0x00000001L
+#define DCFG_UI_SETTING 0x00000002L
+
+#define IF_MAX 1
+#define MAX_PORT 2
+enum { PORT_UP, PORT_DOWN };
+
+#define KA_TICKS 0 //Default to 10 seconds
+
+typedef struct {
+ uint32_t Active,
+ IP,
+ SSRC,
+ PktIn,
+ OctIn,
+ Delay,
+ Cycle,
+ Tick,
+ Time,
+ Mcast;
+ uint16_t Seq,
+ First;
+ int32_t Jitter,
+ Trans;
+} _s_talkers;
+
+#define TX_CONNECT 1
+#define RX_CONNECT 2
+
+//defined values for IfActive
+#define IF_2MPS 1L
+#define IF_10MPS 2L
+
+//Flag definitions for timer
+#define KEYSCAN 0x00000001L
+#define HOOKSCAN 0x00000002L
+#define TIMETICK 0x00000004L
+
+#define ON 1
+#define OFF 0
+#define TALK 2
+#define SIZEOF_UISET 16
+
+typedef struct {
+ uint8_t diag;
+ uint32_t status;
+ uint16_t vlan;
+ uint16_t vvlan;
+ uint16_t port;
+ uint16_t uiset[SIZEOF_UISET];
+ uint16_t vvlanAdmin;
+ uint16_t vvlanIP; //vvlan that our IP address was aquired on
+ uint8_t unused[2001]; //struct must remain 2046 in size
+} DeviceCfgBlk;
+
+
+// pulled from net_config.h
+#define MAX_NAME (64)
+#define BACKUP_SERVERS (7)
+#define MAX_DHCP_TFTP_FILE_NAME (128)
+#define DISKFULL 3 // file too large
+#define NOERR 8 // no error
+typedef struct
+{
+ int8_t tftp_file[40];
+ uint32_t status;
+ uint32_t control;
+ uint32_t appStatus;
+ uint32_t appControl;
+ uint32_t tftp_backup;
+} DHCPBlkExt;
+
+typedef struct
+{
+ uint32_t status; // This structure for sake of backward compatibility needs to
+ uint32_t my_ip_addr; // remain as is until you and I are deceased, stop paying taxes
+ uint32_t subnet_mask; // and all the 79xx phones are long gone. A strategy could be
+ uint32_t defaultgw; // developed to solve this and world hunger but heed this warning.
+ uint32_t dns_addr;
+ uint32_t tftp_addr;
+ uint8_t my_mac_addr[6];
+ int8_t domain_name[MAX_NAME];
+ int8_t my_name[MAX_NAME];
+ uint32_t dhcp_server;
+ uint32_t spare;
+ uint32_t dns_backup[BACKUP_SERVERS];
+ uint32_t gw_backup[BACKUP_SERVERS];
+ int8_t tftp_name[MAX_NAME];
+ union {
+ int8_t tftp_file[MAX_DHCP_TFTP_FILE_NAME];
+ DHCPBlkExt ext;
+ } extFields;
+} DHCPBlk;
+
+
+/*
+ * These structures are how the memory blocks are laid out
+ * Note that these are reflected in ASICAPP.CMD with:
+ *
+ * BOOT_MEM : org = 0x00000020 len = 0x00001FE0
+ * MFG_ROM : org = 0x00004000 len = 0x00002000
+ * CFG_ROM : org = 0x00006000 len = 0x00002000
+ * VER_MEM : org = 0x00008000 len = 0x00000004
+ * A1_ROM : org = 0x00010000 len = 0x00060000
+ * A2_ROM : org = 0x00070000 len = 0x00060000
+ * DSP_ROM : org = 0x000D0000 len = 0x00020000
+ * DIR_ROM : org = 0x000F0000 len = 0x00010000
+ */
+typedef struct {
+ DHCPBlk dhcp_blk; /* 0x00006000 - 0x0000619f len=0x01a0 */
+ DeviceCfgBlk device_cfg_blk; /* 0x000061a0 - 0x000069a3 len=0x0804 */
+
+// removing this area as we don't use it. Re-allocating this space
+// for use in the prot_cfg_area so we can store more config info.
+// int8_t skinny_cfg[0x065c]; /* 0x000069a4 - 0x00006fff len=0x065c */
+
+ int8_t prot_signature[0x0004]; /* 0x000069a4 - 0x000069a7 len=0x0004 */
+
+// int8_t prot_cfg_area[0x0ff8]; /* 0x00007004 - 0x00007ffb len=0x0ff8 */
+ int8_t prot_cfg_area[0x1654]; /* 0x000069a8 - 0x00007ffb len=0x1654 */
+
+ uint32_t prot_cfg_offset; /* 0x00007ffc - 0x00007fff len=0x0004 */
+} cfg_rom_t;
+
+typedef struct {
+ int8_t prot_signature[0x0004]; /* 0x000F0000 - 0x000F0003 len=0x0004 */
+ int8_t personal_dir[0xDFFC]; /* 0x000F0004 - 0x000FDFFF len=0xDFFC */
+ int8_t dial_signature[0x0004]; /* 0x000FE000 - 0x000FE003 len=0x0004 */
+ int8_t dial_plan[0x1FF0]; /* 0x000FE004 - 0x000FFFF3 len=0x1FF0 */
+ uint32_t unused_offset2; /* 0x000FFFF4 - 0x000FFFF7 len=0x0004 */
+ uint32_t dial_plan_offset; /* 0x000FFFF8 - 0x000FFFFB len=0x0004 */
+ uint32_t prot_dir_offset; /* 0x000FFFFC - 0x000FFFFF len=0x0004 */
+} dir_rom_t;
+#define DIR_CONFIG_SIGNATURE "DIR0"
+#define CONFIG_MAX (0x2000 - sizeof(DHCPBlk) - sizeof(DeviceCfgBlk))
+
+// These variables are declared in the ASIC.CMD file
+extern volatile uint32_t WDTimer;
+extern volatile uint16_t GPIO1[gpioMax];
+extern DHCPBlk DHCPInfo; // DHCP info stored in RAM
+extern LoadHdr Load; // load header of current app
+
+#ifdef _WIN32
+extern uint8_t LoadArea[0xFFFF];
+extern uint8_t BootHeader[9]; // Magic number 9 = MAX_OLD_LOAD_ID_STRING
+#else
+extern uint8_t LoadArea; // landing zone for app download
+extern int8_t BootHeader;
+#endif
+extern LoadHdr LoadHeader; // landing zone for app download
+extern DHCPBlk DHCPInfoRom; // DHCP info stored in ROM
+extern DHCPBlk DHCPInfoTemp; // DHCP info stored in ROM
+extern MfgBlk MfgInfo; // Manufacturing information
+extern LoadHdr App1Hdr; // Application 1 in ROM
+extern LoadHdr App2Hdr; // Application 2 in ROM
+extern uint8_t App1Rom; // Application 1 in ROM
+extern uint8_t App2Rom; // Application 2 in ROM
+extern DSPLoadHdr DspHeader;
+extern dir_rom_t DirStorage; // Actual personal directory stored in ROM
+extern uint32_t DcmpVer; // Version of Decompression Algorithm in boot
+extern uint16_t DCVerReg;
+//extern SysHdr *pCFGTftpReq;
+
+typedef struct {
+ int16_t displayContrast;
+ int16_t ringType;
+ int16_t handsetVolume;
+ int16_t headsetVolume;
+ int16_t speakerVolume;
+ int16_t ringVolume;
+ int16_t reserved[10];
+} t_SettingsDesc;
+
+extern int16_t SavePhoneSettings;
+
+// Phone states
+enum {
+ STATE_INIT_CFG,
+ STATE_CDP_CFG,
+ STATE_IP_CFG,
+ STATE_FILE_CFG,
+ STATE_CFG_UPDATE,
+ STATE_CONNECTING,
+ STATE_REGISTER,
+ STATE_REGISTER_REJ,
+ STATE_LOADID_REQ,
+ STATE_BOOT_DSP,
+ STATE_LOADING,
+ STATE_CONNECTED,
+ STATE_RESETTING,
+ STATE_IP_RELEASE,
+ STATE_DUP_IP,
+ STATE_DONE_LOADING,
+ STATE_UNPROVISIONED, /* KAZOO only */
+ maxPHNState
+};
+
+enum { CDP_CACHE_P0_CLEAR, CDP_CACHE_P1_CLEAR, CDP_CACHE_CLEAN };
+//enum { CDP_UNTRUSTED, CDP_TRUSTED, CDP_TRUST_NA = 255 };
+
+#define DC_NONE 0
+#define DC_C3PO 1
+#define DC_ETH 3
+#define DC_2MPS 7
+
+#define NO_TAGGING 4095
+#define NO_VID 4096
+
+/*
+ * Number of buffers in a pool.
+ */
+#define SYSBUF_CNT 50
+#define DSPBUF_CNT 30
+#define SIPTMRBUF_CNT 32
+#define SIPBUF_CNT MAX(MAX_TEL_LINES, 32)
+#define GSMBUF_CNT 32
+#define GUITMRBUF_CNT 5
+#define TCPBUF_CNT 6 // for use by telnet etc
+#define PKTBUF_TX_CNT 10
+#define ENET_RX_BUF_CNT 10
+#define PKTBUF_CNT (ENET_RX_BUF_CNT + PKTBUF_TX_CNT) //20
+
+/*
+ * Size of an indivdual buffer. CPR_MAX_MSG_SIZE
+ * declared in cpr_irx_ipc.h needs to be set to
+ * the largest value defined here.
+ */
+#define SYSBUF_SIZ 512
+#define GUITMRBUF_SIZ 32
+#define PKTBUF_SIZ 3072
+#define TCPBUF_SIZ 2560
+#define DSPBUF_SIZ 96
+#define GUIBUF_SIZ 512
+
+// Buffer Return Identifiers
+/*
+ * Since we now have this horrible mismash of CPR and IRX calls
+ * in the legacy phone, CPR has to have an unique buffer ID to
+ * place in the sys header of the buffers so when the application
+ * is done with them CPR will know not to call Main0RetBuffer. This
+ * value is not used in application code just #defined here to
+ * prevent it being used in the future.
+ */
+#define SYS_BUFFER 1 //System Buffer
+#define XMT_BUFFER 2 //Ether Transmit Packet Ram Buffer
+#define RCV_BUFFER 3 //Ether Receive Packet Ram Buffer
+#define TCP_BUFFER 4
+#define DSP_BUFFER 5
+#define GUITMR_BUFFER 6
+#define CPR_BUFFER 256
+
+extern uint16_t ResetPend;
+extern uint32_t gtick;
+extern uint16_t ResetTimer; // used to delay the bugtrap, 10mse ticks
+extern uint8_t LinkState[MAX_PORT];
+extern uint16_t LinkStatus[MAX_PORT];
+extern uint8_t CurrentLinkState[MAX_PORT];
+extern uint16_t CurrentMode[MAX_PORT];
+
+extern int16_t CallInProg;
+extern int32_t BugTrapped;
+
+extern MfgBlk *pMfgInfo;
+extern DeviceCfgBlk *pDeviceInfo, *pDeviceInfoRom;
+extern LoadHdr *pMyLoad, *pPriLoad, *pSecLoad;
+extern int8_t *pMyPlatform;
+extern int8_t *pMyPhoneModel;
+extern DSPLoadHdr *pMyDSPLoad;
+
+extern int32_t PhoneStim;
+extern int32_t PhoneHookStim;
+
+extern uint32_t IfActive;
+extern volatile uint16_t VVLan, DCDetect, C3PODetected;
+extern uint32_t MaxPort;
+
+extern uint32_t BCastMax;
+extern boolean Is7940;
+extern boolean Is79x0G;
+
+void PHNChangeState(uint16_t state);
+uint16_t PHNGetState(void);
+int32_t PHNStateToStringIndex(uint16_t PhoneState);
+void PHNSpeakerMode(uint16_t mode);
+void PHNMuteMode(uint16_t mode);
+void PHNHeadsetMode(uint16_t mode);
+void PHNRequestFile(int8_t *pName, uint8_t *pDest, int32_t maxSize);
+void PHNMessageLedMode(uint16_t mode);
+void PHNRingerLedMode(uint16_t mode);
+void phone_reset(DeviceResetType resetType);
+void platform_reset_req(DeviceResetType resetType);
+void platform_sync_cfg_vers(char *configVersionStamp,
+ char *dialplanVersionStamp, char *);
+int32_t phone_get_keypress_rand_seed(void);
+int16_t phone_call_in_progress(void);
+
+void tweak_watchdog(void);
+extern uint32_t set_wd_timeout(uint16_t new_time);
+extern void restore_wd_timeout(uint32_t prev_time);
+
+#define DEFAULT_WATCHDOG_TIME 8
+
+#define PROGRAM_HW_WATCHDOG_IN_MILLISECONDS(x); WDTimer = 0x00550000; \
+ WDTimer = 0x01AA0000 + ((x)); //Program the watchdog
+
+#define HIT_THE_WATCHDOG() tweak_watchdog()
+
+
+void BugInfoValidate(void);
+uint32_t BugInfoAbortPtr(void);
+
+
+int8_t *task2string(int32_t task_id);
+
+#define EXCEPTION_BUGCODE 0xdd //BugTrap Code:0xddxx for exceptions
+#define INITSTKSZ 500
+#define SVCSTKSZ 40 // interrupt off (svc) stack size
+
+
+/* SKITTLES moved syshdr for IPC from network.h. this will be the new home for
+ * SysHdr. it is used by all phone tasks and can not be plat specific.
+ */
+#define MISC_LN 8
+typedef struct
+{
+ void *Next;
+ uint32_t Cmd;
+ uint16_t RetID;
+ uint16_t Port;
+ uint16_t Len;
+ uint8_t *Data;
+ union {
+ void *UsrPtr;
+ uint32_t UsrInfo;
+ } Usr;
+ uint8_t Misc[MISC_LN];
+ // void *TempPtr;
+} phn_syshdr_t;
+
+/* SKITTLES The line below is only temporary till we
+ * change refernces to SysHdr.
+ */
+typedef phn_syshdr_t SysHdr;
+
+/* settings.c needs it */
+extern DHCPBlk *pDHCPInfoTemp;
+
+extern SysHdr *pCFGTftpReq;
+
+typedef struct {
+ char newcfgVerStamp[64];
+ char newdialplanVerStamp[64];
+} PhoneSyncCfgVer;
+
+#endif /* PHONE_H */
diff --git a/libs/sipcc/core/includes/phone_debug.h b/libs/sipcc/core/includes/phone_debug.h
new file mode 100644
index 0000000000..ce8f7ed3c5
--- /dev/null
+++ b/libs/sipcc/core/includes/phone_debug.h
@@ -0,0 +1,275 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _PHONE_DEBUG_H_
+#define _PHONE_DEBUG_H_
+
+#include "cpr_stdio.h"
+#include "cc_constants.h"
+
+extern cc_int32_t SipDebugMessage;
+extern cc_int32_t SipDebugState;
+extern cc_int32_t SipDebugTask;
+extern int32_t SipRelDevEnabled;
+extern cc_int32_t SipDebugRegState;
+extern int32_t SipDebugGenContactHeader;
+extern cc_int32_t SipDebugTrx;
+
+extern int32_t DebugPlatform;
+extern int32_t DebugSOCTask;
+extern int32_t DebugSNTP;
+extern int32_t DebugSNTPPacket;
+extern cc_int32_t TMRDebug;
+extern cc_int32_t GSMDebug;
+extern cc_int32_t FIMDebug;
+extern cc_int32_t LSMDebug;
+extern cc_int32_t VCMDebug;
+extern cc_int32_t PLATDebug;
+extern cc_int32_t CCEVENTDebug;
+extern cc_int32_t FSMDebugSM;
+extern int32_t CSMDebugSM;
+extern cc_int32_t CCDebug;
+extern cc_int32_t CCDebugMsg;
+extern cc_int32_t AuthDebug;
+extern int32_t DebugDTMFOutofBand;
+extern int32_t DebugFlash;
+
+extern int32_t StrlibDebug;
+extern cc_int32_t ConfigDebug;
+
+extern int32_t DebugMalloc;
+extern int32_t DebugMallocTable;
+extern int32_t SoftkeyDebug;
+extern int32_t arp_debug_flag;
+extern int32_t arp_debug_broadcast_flag;
+extern int32_t cdp_debug;
+extern int32_t timestamp_debug;
+extern int32_t cdp_debug;
+
+extern int32_t HTTPDebug;
+extern cc_int32_t KpmlDebug;
+extern cc_int32_t DpintDebug;
+extern cc_int32_t g_cacDebug;
+extern cc_int32_t g_blfDebug;
+extern int32_t Dpint32_tDebug;
+extern cc_int32_t TNPDebug;
+extern cc_int32_t g_configappDebug;
+extern cc_int32_t g_CCAppDebug;
+extern cc_int32_t g_CCLogDebug;
+extern cc_int32_t g_dcsmDebug;
+extern cc_int32_t g_DEFDebug;
+
+extern cc_int32_t g_NotifyCallDebug;
+extern cc_int32_t g_NotifyLineDebug;
+
+// ---------------- definitions based on bug_printf -----------------
+
+ // Now some level definitions for buf_printf
+#define BUG_BROADCAST 0 // can't be disabled
+#define BUG_EMERGENCY 1
+#define BUG_ALERT 2
+#define BUG_CRITICAL 3
+#define BUG_ERROR 4
+#define BUG_WARNING 5
+#define BUG_NOTICE 6
+#define BUG_INFO 7
+#define BUG_DEBUG 8 // debugs and such
+
+extern int32_t bug_printf(int32_t level, const char *_format, ...);
+extern int32_t nbuginf(const char *_format, ...);
+
+#define logMsg buginf
+
+/* SIP debug macros */
+#define CCSIP_DEBUG_MESSAGE if (SipDebugMessage) buginf
+#define CCSIP_DEBUG_MESSAGE_PKT if (SipDebugMessage) platform_print_sip_msg
+#define CCSIP_DEBUG_STATE if (SipDebugState) buginf
+#define CCSIP_DEBUG_TASK if (SipDebugTask) buginf
+#define CCSIP_DEBUG_REG_STATE if (SipDebugRegState) buginf
+#define CCSIP_DEBUG_TRX if (SipDebugTrx) buginf
+#define CCSIP_DEBUG_DM if (SipDebugDM) buginf
+
+/* Platform debug macros */
+#define PHN_DEBUG_SNTP if (DebugSNTP)
+#define PHN_DEBUG_SNTP_PACKET if (DebugSNTPPacket)
+
+/* TNP adapter debugs */
+#define TNP_DEBUG if (TNPDebug) buginf
+
+#define DEF_DISPLAY_BUF 128
+/*
+ * Only used in the IOS SIP Parser routines
+ */
+#define CCSIP_ERR_MSG err_msg
+#define CCSIP_DEBUG_ERROR err_msg
+#define CCSIP_ERR_DEBUG if (1)
+#define CCSIP_INFO_DEBUG if (1)
+
+#define TMR_DEBUG if (TMRDebug) buginf
+#define GSM_DEBUG if (GSMDebug) buginf
+#define FIM_DEBUG if (FIMDebug) buginf
+#define LSM_DEBUG if (LSMDebug) buginf
+#define CALL_EVENT if (CCEVENTDebug) buginf
+#define FSM_DEBUG_SM if (FSMDebugSM) buginf
+#define CSM_DEBUG_SM if (CSMDebugSM) buginf
+#define DEF_DEBUG if (g_DEFDebug) notice_msg
+
+#define CC_DEBUG if (CCDebug) buginf
+#define CC_DEBUG_MSG if (CCDebugMsg)
+#define AUTH_DEBUG if (AuthDebug) buginf
+#define ARP_DEBUG if (arp_debug_flag) buginf
+#define ARP_BCAST_DEBUG if (arp_debug_broadcast_flag) buginf
+#define CDP_DEBUG if (cdp_debug) buginf
+
+#define NOTIFY_CALL_DEBUG if (g_NotifyCallDebug) buginf
+#define NOTIFY_LINE_DEBUG if (g_NotifyLineDebug) buginf
+
+/* String library macro */
+#define CONFIG_DEBUG if (ConfigDebug) buginf
+#define FLASH_DEBUG if (DebugFlash) buginf
+#define KPML_DEBUG if (KpmlDebug) buginf
+#define CAC_DEBUG if (g_cacDebug) buginf
+#define DCSM_DEBUG if (g_dcsmDebug) buginf
+#define BLF_DEBUG if (g_blfDebug) buginf
+#define BLF_ERROR err_msg
+#define MISC_APP_DEBUG if (g_miscAppDebug) buginf
+#define DPINT_DEBUG if (DpintDebug) buginf
+#define CONFIGAPP_DEBUG if (g_configappDebug) buginf
+#define CCAPP_DEBUG if (g_CCAppDebug) buginf
+#define CCLOG_DEBUG if (g_CCLogDebug) buginf
+#define MSP_DEBUG if (VCMDebug) buginf
+#define CCAPP_ERROR err_msg
+#define MSP_ERROR err_msg
+#define CCAPP_ERROR err_msg
+#define TNP_ERR err_msg
+#define VCM_ERR err_msg
+#define DEF_ERROR err_msg
+#define DEF_ERR err_msg
+
+#define APP_NAME "SIPCC-"
+#define DEB_L_C_F_PREFIX APP_NAME"%s: %d/%d, %s: "
+#define DEB_L_C_F_PREFIX_ARGS(msg_name, line, call_id, func_name) \
+ msg_name, line, call_id, func_name
+#define DEB_F_PREFIX APP_NAME"%s: %s: "
+#define DEB_F_PREFIX_ARGS(msg_name, func_name) msg_name, func_name
+#define GSM_L_C_F_PREFIX "GSM : %d/%d : %s : " // requires 3 args: line_id, call_id, fname
+#define GSM_F_PREFIX "GSM : %s : " // requires 1 arg: fname
+#define GSM_DEBUG_ERROR err_msg
+#define LSM_L_C_F_PREFIX "LSM : %d/%d : %s : " // requires 3 args: line_id, call_id, fname
+#define LSM_F_PREFIX "LSM : %s : " // requires 1 arg: fname
+#define CCA_L_C_F_PREFIX "CCA : %d/%d : %s : " // requires 3 args: line_id, call_id, fname
+#define CCA_F_PREFIX "CCA : %s : " // requires 1 arg: fname
+#define MSP_F_PREFIX "SIPCC-MSP: %s: "
+#define DEB_NOTIFY_PREFIX "AUTO.%s:"
+
+#define MISC_F_PREFIX "MSC : %s : " // requires 1 arg: fname
+
+#define KPML_L_C_F_PREFIX "KPM : %d/%d : %s : " // requires 3 args: line_id, call_id, fname
+#define KPML_F_PREFIX "KPM : %s : " // requires 1 arg: fname
+#define KPML_ERROR err_msg
+#define CAC_ERROR err_msg
+#define DCSM_ERROR err_msg
+#define CONFIG_ERROR err_msg
+#define PLAT_ERROR err_msg
+
+#define CAC_L_C_F_PREFIX "CAC : %d/%d : %s : " // requires 3 args: line_id, call_id, fname
+#define CAC_F_PREFIX "CAC : %s : " // requires 1 arg: fname
+#define DCSM_L_C_F_PREFIX "DCSM : %d/%d : %s : " // requires 3 args: line_id, call_id, fname
+#define DCSM_F_PREFIX "DCSM : %s : " // requires 1 arg: fname
+#define CFG_F_PREFIX "CFG : %s : " // requires 1 arg: fname
+#define PLAT_COMMON_F_PREFIX "PLAT_COMMON : %s : " // requires 1 arg: fname
+#define MED_F_PREFIX "MED : %s : "
+#define MED_L_C_F_PREFIX "MED : %d/%d : %s : " // line/call/fname as arg
+
+
+/* Debug MSGNAMEs */
+#define CC_API "CC_API" // CCAPI debugs
+#define FSM "FSM" // FSM debugs
+#define GSM "GSM" // gsm related debugs
+#define DCSM "DCSM" // gsm related debugs
+#define SIP_STATE "SIP_STATE"
+#define SIP_EVT "SIP_EVT" // SIP events
+#define SIP_MSG_RECV "SIP_MSG_RECV"
+#define SIP_MSG_SEND "SIP_MSG_SEND"
+#define SIP_REG_STATE "SIP_REG_STATE"
+#define SIP_REG_FREE_FALLBACK "SIP_REG_FREE_FALLBACK"
+#define DP_API "DP_API" // dial plan
+#define KPML_INFO "KPML_INFO"
+#define BLF_INFO "BLF_INFO"// presence information
+#define MED_API "MED_API" // media api
+#define UI_API "UI_API"
+#define FIM "FIM" // FIM debugs
+#define LSM "LSM"
+#define SIP_AUTH "SIP_AUTH"
+#define TNP_INIT "TNP_INIT"
+#define TNP_BLF "TNP_BLF"
+#define RM "RM" // resource manager
+#define SIP_KA "SIP_KA" // SIP keepalive
+#define JNI "JNI"
+#define CONFIG_API "CONFIG_API" // config table API
+#define BLF "BLF"
+#define CONFIG_APP "CONFIG_APP"
+#define SIP_MSG_QUE "SIP_MSG_QUE" // SIP message queue
+#define SIP_TRANS "SIP_TRANS" // SIP transport
+#define HTTPISH "HTTPISH" // Network to structure translation
+#define SIP_MSG "SIP_MSG"
+#define SIP_TIMER "SIP_TIMER"
+#define SIP_ID "SIP_ID"
+#define SIP_FWD "SIP_FWD"
+#define SIP_NOTIFY "SIP_NOTIFY"
+#define SIP_TASK "SIP_TASK"
+#define SIP_IP_MATCH "SIP_IP_MATCH"
+#define SIP_SUB "SIP_SUB" // SIP subscription
+#define SIP_SDP "SIP_SDP"
+#define SIP_STORE "SIP_STORE"
+#define SIP_PUB "SIP_PUB" // SIP publish
+//#define SIP_UDP "SIP_UDP"
+#define SIP_TLS "SIP_TLS"
+//#define SIP_TCP "SIP_TCP"
+#define SIP_SDP "SIP_SDP"
+#define SIP_REP "SIP_REP" // SIP replace info
+#define SIP_PROXY "SIP_PROXY"
+#define SIP_CALL_STATUS "SIP_CALL_STATUS"
+#define SIP_ACK "SIP_ACK" // SIP invite response ack
+#define CPR "CPR"
+#define SIP_BRANCH "SIP_BRANCH"
+#define SIP_CTRL "SIP_CTRL"
+#define SIP_TRX "SIP_TRX" // SIP transaction
+#define SIP_ROUTE "SIP_ROUTE"
+#define SIP_CALL_ID "SIP_CALL_ID"
+#define SIP_CSEQ "SIP_CSEQ"
+#define SIP_TAG "SIP_TAG"
+#define SIP_RESP "SIP_RESP" // SIP response message
+#define SIP_REQ_URI "SIP_REQ_URI"
+#define SIP "SIP"
+#define SIP_REG "SIP_REG"
+#define SIP_CCM_RESTART "SIP_CCM_RESTART"
+#define SIP_CRED "SIP_CRED" // SIP registration credentials
+#define SIP_BUTTON "SIP_BUTTON"
+#define SIP_SUB_RESP "SIP_SUB_RESP" // SIP subscription response
+#define SIP_NOTIFY "SIP_NOTIFY"
+#define SIP_FALLBACK "SIP_FALLBACK"
+#define SIP_FAILOVER "SIP_FAILOVER"
+#define SIP_STANDBY "SIP_STANDBY"
+#define SIP_CC_CONN "SIP_CC_CONN" // SIP CC connections
+#define SIP_CONFIG "SIP_CONFIG"
+#define DIALPLAN "DIALPLAN"
+#define SIP_REQ_DIGEST "SIP_REQ_DIGEST"
+#define SIP_CC_INIT "SIP_CC_INIT"
+#define SIP_CC_PROV "SIP_CC_PROV" // CC Provider
+#define SIP_SES_HASH "SIP_SES_HASH" // session hash
+#define PLAT_API "PLAT_API" // platform API
+#define CHUNK "CHUNK"
+#define MISC_UTIL "MISC_UTIL"
+#define SIP_CC_SES "SIP_CC_SES" // CC session
+#define CAPF_UI "CAPF_UI"
+#define CC_API_NATIVE "CC_API_NATIVE"
+#define TANDUN_STUB "TANDUN_STUB"
+#define SIP_SOCK "SIP_SOCK"
+#define SIP_TCP_MSG "SIP_TCP_MSG"
+#define MS_PROVIDER "MSP"
+#define SIP_CONTENT_TYPE "SIP_CONTENT_TYPE"
+#define SIP_INFO_PACKAGE "SIP_INFO_PACKAGE"
+
+#endif
diff --git a/libs/sipcc/core/includes/phone_platform_constants.h b/libs/sipcc/core/includes/phone_platform_constants.h
new file mode 100755
index 0000000000..1c0aa6087a
--- /dev/null
+++ b/libs/sipcc/core/includes/phone_platform_constants.h
@@ -0,0 +1,210 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _PHONE_PLATFORM_CONSTANTS_H_
+#define _PHONE_PLATFORM_CONSTANTS_H_
+
+// Defines for the various phone models. Note that the device numbers
+// appearing after the model name are pre-determined when new phone models
+// are added and must correspond to the ones programmed into CCM
+#define SIP_FIRMWARE_VERSION "9.1.1"
+
+// Legacy
+#define PHONE_MODEL_NUMBER_7940 "8"
+#define PHONE_MODEL_NUMBER_7960 "7"
+#define LEGACY_MODEL_7940 "CP-7940G"
+#define LEGACY_MODEL_7960 "CP-7960G"
+#define CCSIP_SIP_7940_USER_AGENT "CP7940G"
+#define CCSIP_SIP_7960_USER_AGENT "CP7960G"
+
+// Communicator
+// Note: The Communicator will send its native device number of 30016
+// so that the CCM will recognize it as a CIPC. If talking to an older CCM
+// that expects the Communicator to register as a 7970, please define
+// _CIPC_7970_ in SIP project file
+#ifdef _CIPC_7970_
+#define PHONE_MODEL_NUMBER_COMMUNICATOR "30006"
+#else
+#define PHONE_MODEL_NUMBER_COMMUNICATOR "30016"
+#endif
+#define CCSIP_SIP_COMMUNICATOR_USER_AGENT "SIPIPCommunicator"
+
+// UC core
+#define PHONE_MODEL_NUMBER_UCCORE "358"
+#define CCSIP_SIP_UCCORE_USER_AGENT "SIPUCCore"
+
+// 8961
+#define PHONE_MODEL_NUMBER_8961 "540"
+#define RT_MODEL_8961 "CP-8961"
+#define CCSIP_SIP_8961_USER_AGENT "CP8961"
+
+// 9951
+#define PHONE_MODEL_NUMBER_9951 "537"
+#define RT_MODEL_9951 "CP-9951"
+#define CCSIP_SIP_9951_USER_AGENT "CP9951"
+
+// 9971
+#define PHONE_MODEL_NUMBER_9971 "493"
+#define RT_MODEL_9971 "CP-9971"
+#define CCSIP_SIP_9971_USER_AGENT "CP9971"
+
+// 7970
+#define PHONE_MODEL_NUMBER_7970 "30006"
+#define TNP_MODEL_7970 "CP-7970G"
+#define CCSIP_SIP_7970_USER_AGENT "CP7970G"
+
+// 7971
+#define PHONE_MODEL_NUMBER_7971 "119"
+#define TNP_MODEL_7971 "CP-7971G-GE"
+#define CCSIP_SIP_7971_USER_AGENT "CP7971G-GE"
+
+// 7911
+#define PHONE_MODEL_NUMBER_7911 "307"
+#define TNP_MODEL_7911 "CP-7911G"
+#define CCSIP_SIP_7911_USER_AGENT "CP7911G"
+
+// 7906
+#define PHONE_MODEL_NUMBER_7906 "369"
+#define TNP_MODEL_7906 "CP-7906G"
+#define CCSIP_SIP_7906_USER_AGENT "CP7906G"
+
+// 7931
+#define PHONE_MODEL_NUMBER_7931 "348"
+#define TNP_MODEL_7931 "CP-7931G"
+#define CCSIP_SIP_7931_USER_AGENT "CP7931G"
+
+// Maximum Lines on 794X models
+#define MAX_REG_LINES_794X 2
+
+// 7941
+#define PHONE_MODEL_NUMBER_7941 "115"
+#define TNP_MODEL_7941 "CP-7941G"
+#define CCSIP_SIP_7941_USER_AGENT "CP7941G"
+
+// 7941 GE
+#define PHONE_MODEL_NUMBER_7941GE "309"
+#define TNP_MODEL_7941GE "CP-7941G-GE"
+#define CCSIP_SIP_7941_GE_USER_AGENT "CP7941G-GE"
+
+// 7961
+#define PHONE_MODEL_NUMBER_7961 "30018"
+#define TNP_MODEL_7961 "CP-7961G"
+#define CCSIP_SIP_7961_USER_AGENT "CP7961G"
+
+// 7961 GE
+#define PHONE_MODEL_NUMBER_7961GE "308"
+#define TNP_MODEL_7961GE "CP-7961G-GE"
+#define CCSIP_SIP_7961_GE_USER_AGENT "CP7961G-GE"
+
+// 7942
+#define PHONE_MODEL_NUMBER_7942 "434"
+#define TNP_MODEL_7942 "CP-7942G"
+#define CCSIP_SIP_7942_USER_AGENT "CP7942G"
+
+// 7945
+#define PHONE_MODEL_NUMBER_7945 "435"
+#define TNP_MODEL_7945 "CP-7945G"
+#define CCSIP_SIP_7945_USER_AGENT "CP7945G"
+
+// 7962
+#define PHONE_MODEL_NUMBER_7962 "404"
+#define TNP_MODEL_7962 "CP-7962G"
+#define CCSIP_SIP_7962_USER_AGENT "CP7962G"
+
+// 7965
+#define PHONE_MODEL_NUMBER_7965 "436"
+#define TNP_MODEL_7965 "CP-7965G"
+#define CCSIP_SIP_7965_USER_AGENT "CP7965G"
+
+// 7975
+#define PHONE_MODEL_NUMBER_7975 "437"
+#define TNP_MODEL_7975 "CP-7975G"
+#define CCSIP_SIP_7975_USER_AGENT "CP7975G"
+
+// CSF
+#define PHONE_MODEL_NUMBER_CSF "503"
+#define CSF_MODEL "CSF"
+#define CCSIP_SIP_CSF_USER_AGENT "IKRAN"
+
+// CIUS
+#define PHONE_MODEL_NUMBER_CIUS "593"
+#define CIUS_MODEL "CP-CIUS"
+#define CCSIP_SIP_CIUS_USER_AGENT "CPCIUS"
+
+// SOUNDWAVE
+#define PHONE_MODEL_NUMBER_SOUNDWAVE "575"
+#define SOUNDWAVE_MODEL "SOUNDWAVE"
+#define CCSIP_SIP_SOUNDWAVE_USER_AGENT "SOUNDWAVE"
+
+
+
+
+#define MAX_SIDECAR_LINES 28 // Max number of lines supported on sidecars
+
+#define MAX_BKEM_LINES 48 // Max number of lines supported on BKEMs
+
+/****************************************************
+ * Start: definitions for vendor's phones
+ */
+//Definition for 6901
+#define PHONE_MODEL_NUMBER_6901 "547"
+#define RTLITE_MODEL_6901 "CP-6901"
+#define CCSIP_SIP_6901_USER_AGENT "CP6901"
+
+//Definitions for 6911
+#define PHONE_MODEL_NUMBER_6911 "548"
+#define RTLITE_MODEL_6911 "CP-6911"
+#define CCSIP_SIP_6911_USER_AGENT "CP6911"
+
+//Definition for 6921
+#define PHONE_MODEL_NUMBER_6921 "495"
+#define RTLITE_MODEL_6921 "CP-6921"
+#define CCSIP_SIP_6921_USER_AGENT "CP6921"
+
+//Definition for 6941
+#define PHONE_MODEL_NUMBER_6941 "496"
+#define RTLITE_MODEL_6941 "CP-6941"
+#define CCSIP_SIP_6941_USER_AGENT "CP6941"
+
+//Definition for 6945
+#define PHONE_MODEL_NUMBER_6945 "564"
+#define RTLITE_MODEL_6945 "CP-6945"
+#define CCSIP_SIP_6945_USER_AGENT "CP6945"
+
+//Definition for 6961
+#define PHONE_MODEL_NUMBER_6961 "497"
+#define RTLITE_MODEL_6961 "CP-6961"
+#define CCSIP_SIP_6961_USER_AGENT "CP6961"
+
+//Definition for 7937
+#define PHONE_MODEL_NUMBER_7937 "431"
+#define RTLITE_MODEL_7937 "7937G"
+#define CCSIP_SIP_7937_USER_AGENT "7937G"
+/**
+ * End of vendor's definition
+ ******************************************************/
+
+//Default set
+#define PHONE_MODEL_NUMBER "493"
+#define PHONE_MODEL "CP-9971"
+#define CCSIP_SIP_USER_AGENT "CP9971"
+
+#define MAX_PHONE_LINES 8
+#define MAX_REG_LINES 51
+#define MAX_CALLS 51
+#define MAX_CALLS_PER_LINE 51
+
+/*
+ * MAX_INSTANCES (call_instances) should equal to maximum number of calls
+ * allowed by the phone but MAX_CALLS is defined to be 1 more than the
+ * actual maximum capacity. Therefore define MAX_INSTANCES to MAX_CALLS -1
+ */
+#define MAX_INSTANCES (MAX_CALLS - 1) /* max number of instance ID */
+
+/* MAX_CONFIG_LINES - java side defined fixed number to 36 for non-Buckfast TNP
+ * models so use 36 in call cases. Changing this needs java side change
+ */
+#define MAX_CONFIG_LINES 51
+
+#endif
diff --git a/libs/sipcc/core/includes/phone_types.h b/libs/sipcc/core/includes/phone_types.h
new file mode 100644
index 0000000000..0b4f11f2f8
--- /dev/null
+++ b/libs/sipcc/core/includes/phone_types.h
@@ -0,0 +1,32 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _PHONE_TYPES_H_
+#define _PHONE_TYPES_H_
+
+#include "sessionConstants.h"
+#include "cc_constants.h"
+
+#define MAC_ADDRESS_LENGTH 6
+
+typedef cc_lineid_t line_t;
+typedef cc_callid_t callid_t;
+typedef cc_groupid_t groupid_t;
+typedef unsigned short calltype_t;
+typedef unsigned short media_refid_t;
+typedef cc_streamid_t streamid_t;
+typedef cc_mcapid_t mcapid_t;
+
+typedef enum {
+ NORMAL_CALL = CC_ATTR_NORMAL,
+ XFR_CONSULT = CC_ATTR_XFR_CONSULT,
+ CONF_CONSULT = CC_ATTR_CONF_CONSULT,
+ ATTR_BARGING = CC_ATTR_BARGING,
+ RIUHELD_LOCKED = CC_ATTR_RIUHELD_LOCKED,
+ LOCAL_CONF_CONSULT = CC_ATTR_LOCAL_CONF_CONSULT,
+ ATTR_MAX
+} call_attr_t;
+
+#define CC_GCID_LEN (129)
+#endif
diff --git a/libs/sipcc/core/includes/platform_api.h b/libs/sipcc/core/includes/platform_api.h
new file mode 100644
index 0000000000..f791e6743c
--- /dev/null
+++ b/libs/sipcc/core/includes/platform_api.h
@@ -0,0 +1,52 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _PLATFORM_API_H_
+#define _PLATFORM_API_H_
+
+#include "cpr_types.h"
+#include "cpr_socket.h"
+#include "ccsip_pmh.h"
+#include "plat_api.h"
+#include "sessionTypes.h"
+
+void platform_get_wired_mac_address(uint8_t *addr);
+void platform_get_active_mac_address(uint8_t *addr);
+void platform_get_ip_address(cpr_ip_addr_t *ip_addr);
+cpr_ip_mode_e platform_get_ip_address_mode(void);
+void platform_apply_config (char * configVersionStamp, char * dialplanVersionStamp, char * fcpVersionStamp, char * cucmResult, char * loadId, char * inactiveLoadId, char * loadServer, char * logServer, boolean ppid);
+
+/**
+ * Set ip address mode
+ * e.g.
+ */
+cpr_ip_mode_e platGetIpAddressMode();
+
+/**
+ * @brief Given a msg buffer, returns a pointer to the buffer's header
+ *
+ * The cprGetSysHeader function retrieves the system header buffer for the
+ * passed in message buffer.
+ *
+ * @param[in] buffer pointer to the buffer whose sysHdr to return
+ *
+ * @return Abstract pointer to the msg buffer's system header
+ * or #NULL if failure
+ */
+void *
+cprGetSysHeader (void *buffer);
+
+/**
+ * @brief Called when the application is done with this system header
+ *
+ * The cprReleaseSysHeader function returns the system header buffer to the
+ * system.
+ * @param[in] syshdr pointer to the sysHdr to be released
+ *
+ * @return none
+ */
+void
+cprReleaseSysHeader (void *syshdr);
+
+#endif
diff --git a/libs/sipcc/core/includes/pres_sub_not_handler.h b/libs/sipcc/core/includes/pres_sub_not_handler.h
new file mode 100644
index 0000000000..bc021a7763
--- /dev/null
+++ b/libs/sipcc/core/includes/pres_sub_not_handler.h
@@ -0,0 +1,20 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef PRES_SUB_NOT_HANDLER_H
+#define PRES_SUB_NOT_HANDLER_H
+
+#include "cpr_types.h"
+
+extern void pres_get_state(int request_id, int duration, const char *watcher,
+ const char *presentity, int app_id, int feature_mask);
+extern void pres_terminate_req(int request_id);
+extern void pres_terminate_req_all(void);
+extern void pres_process_msg_from_msgq(uint32_t cmd, void *msg_p);
+extern cpr_status_e pres_create_retry_after_timers(void);
+extern void pres_destroy_retry_after_timers(void);
+extern void pres_play_blf_audible_alert(void);
+extern void pres_sub_handler_initialized(void);
+
+#endif /* PRES_SUB_NOT_HANDLER_H */
diff --git a/libs/sipcc/core/includes/publish_int.h b/libs/sipcc/core/includes/publish_int.h
new file mode 100644
index 0000000000..c76b666000
--- /dev/null
+++ b/libs/sipcc/core/includes/publish_int.h
@@ -0,0 +1,70 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef PUBLISH_INT_H
+#define PUBLISH_INT_H
+
+#include "ccsip_subsmanager.h"
+#include "cpr_types.h"
+#include "ccsip_callinfo.h"
+
+
+typedef uint32_t pub_handle_t;
+#define NULL_PUBLISH_HANDLE 0 /* this is to indicate that handle is not assigned yet */
+
+
+typedef struct {
+ pub_handle_t pub_handle; // handle assigned by the SIP stack
+ pub_handle_t app_handle; // handle assigned by the Application
+ char ruri[MAX_URI_LENGTH]; // Address of the resource
+ char esc[MAX_URI_LENGTH]; // Event State Compositor
+ uint32_t expires; // suggested Expires in seconds
+ cc_subscriptions_t event_type; // EventType, for example, prescence
+ ccsip_event_data_t *event_data_p; // Event Data
+ cc_srcs_t callback_task; // CallBack Task ID
+ int resp_msg_id; //Response Msg ID
+} pub_req_t;
+
+typedef struct {
+ unsigned int resp_code; // response code
+ pub_handle_t pub_handle; // handle assigned by the SIP stack
+ pub_handle_t app_handle; // handle assigned by the Application
+} pub_rsp_t;
+
+extern
+void publish_init(pub_handle_t app_handle,
+ char *ruri,
+ char *esc,
+ unsigned int expires,
+ cc_subscriptions_t event_type,
+ ccsip_event_data_t *event_data_p,
+ cc_srcs_t callback_task,
+ int message_id
+ );
+
+extern
+void publish_update(pub_handle_t pub_handle,
+ cc_subscriptions_t event_type,
+ ccsip_event_data_t *event_data_p,
+ cc_srcs_t callback_task,
+ int message_id
+ );
+
+extern
+void publish_terminate(pub_handle_t pub_handle,
+ cc_subscriptions_t event_type,
+ cc_srcs_t callback_task,
+ int message_id
+ );
+
+extern
+cc_rcs_t publish_int_response(pub_rsp_t *pub_rsp_p,
+ cc_srcs_t callback_task,
+ int message_id
+ );
+
+#endif /*PUBLISH_INT_H*/
+
+
+
diff --git a/libs/sipcc/core/includes/rcc_int_types.h b/libs/sipcc/core/includes/rcc_int_types.h
new file mode 100755
index 0000000000..b55e00e6f0
--- /dev/null
+++ b/libs/sipcc/core/includes/rcc_int_types.h
@@ -0,0 +1,72 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _RCC_INT_TYPES_H_
+#define _RCC_INT_TYPES_H_
+
+#include "phone_types.h"
+#include "xml_parser_defines.h"
+#include "sll_lite.h"
+
+// The table below should be kept in sync with the enum type
+// in the RemoteCC XML
+typedef enum {
+ RCC_SOFTKEY_UNDEFINED = 0,
+ RCC_SOFTKEY_REDIAL = 1,
+ RCC_SOFTKEY_NEWCALL,
+ RCC_SOFTKEY_HOLD,
+ RCC_SOFTKEY_TRANSFER,
+ RCC_SOFTKEY_CFWDALL,
+ RCC_SOFTKEY_CFWDBUSY,
+ RCC_SOFTKEY_CFWDNOANS,
+ RCC_SOFTKEY_BACKSPACE,
+ RCC_SOFTKEY_ENDCALL,
+ RCC_SOFTKEY_RESUME,
+ RCC_SOFTKEY_ANSWER,
+ RCC_SOFTKEY_INFO,
+ RCC_SOFTKEY_CONFERENCE,
+ RCC_SOFTKEY_JOIN,
+ RCC_SOFTKEY_RMLASTCONF,
+ RCC_SOFTKEY_BARGE,
+ RCC_SOFTKEY_DIRECTXFER,
+ RCC_SOFTKEY_SELECT,
+ RCC_SOFTKEY_CBARGE,
+ RCC_SOFTKEY_DIV_ALL,
+ RCC_SOFTKEY_TRANSFERTOVM,
+ RCC_SOFTKEY_UNSELECT,
+ RCC_SOFTKEY_CANCEL,
+ RCC_SOFTKEY_CONFDETAILS,
+ RCC_IPMA_SKEY_TRANSFAS = 66,
+ RCC_IPMA_SKEY_INTRCPT = 67,
+ RCC_IPMA_SKEY_TRANSFVM = 68,
+ RCC_IPMA_SKEY_TRANSMG = 69,
+ RCC_IPMA_SKEY_SETWTCH = 70,
+} rcc_softkey_event_t;
+
+/*
+ * 400 - Invalid line handle
+ * 401 - Invalid calling address
+ * 402 - Invalid called address
+ * 403 - User data too large
+ * 404 - PassThrough data too large
+ * 405 - Cannot process request in current line state
+ */
+
+typedef enum {
+ RCC_ERR = -1,
+ RCC_NONE = 0,
+ RCC_TRYING = 100,
+ RCC_SUCCESS = 200,
+ RCC_SUCCESS_COMPLETE = 201,
+ RCC_COMPLETE = 300,
+ RCC_FAILED = 400,
+ RCC_INVALID_LINE = 401,
+ RCC_INVALID_CALLING_ADDR = 402,
+ RCC_INVALID_CALLED_ADDR = 403,
+ RCC_LARGE_DATA = 404,
+ RCC_PROCESS_REQ_FAILED = 405,
+ RCC_RESP_MAX
+} rcc_resp_code_e;
+
+#endif //_RCC_INT_TYPES_H_
diff --git a/libs/sipcc/core/includes/regexp.h b/libs/sipcc/core/includes/regexp.h
new file mode 100644
index 0000000000..99fb19b3df
--- /dev/null
+++ b/libs/sipcc/core/includes/regexp.h
@@ -0,0 +1,83 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef __REGEXP_H__
+#define __REGEXP_H__
+
+/*
+ * Definitions etc. for regexp(3) routines.
+ *
+ * Caveat: this is V8 regexp(3) [actually, a reimplementation thereof],
+ * not the System V one.
+ */
+#define NSUBEXP 10
+struct regexp_ {
+ char *startp[NSUBEXP];
+ char *endp[NSUBEXP];
+ char regflag; /* Flags used for pattern matching */
+ char regstart; /* Internal use only. */
+ char reganch; /* Internal use only. */
+ char regatom; /* Internal use only. */
+ char *regmust; /* Internal use only. */
+ int regmlen; /* Internal use only. */
+ char program[1]; /* Unwarranted chumminess with compiler. */
+};
+
+typedef struct regexp_ regexp;
+
+
+/*
+ * The first byte of the regexp internal "program" is actually this magic
+ * number; the start node begins in the second byte.
+ */
+#define MAGIC 0234
+
+/*
+ * The parameters for regflag
+ */
+#define REG_NOSUB 0x02 /* Don't do sub-string matches */
+
+/* Return Values from regexecstring()
+ */
+typedef enum {
+ REG_NO_MATCH = 0,
+ REG_MATCHED,
+ REG_MAYBE
+} regval;
+
+
+/***********************************************************************
+ *
+ * Externs and Prototypes
+ *
+ ***********************************************************************/
+
+/*
+ * regexp.c
+ */
+extern char *reg(int, int *);
+extern char *regatom(int *);
+extern char *regbranch(int *);
+extern char *regnode(char);
+extern char *regpiece(int *);
+extern char *regprop(char *);
+extern int regexec(regexp *, char *);
+extern int regmatch(char *);
+extern int regrepeat(char *);
+extern int regtry(regexp *, char *);
+extern regexp *regcomp(char *, char);
+extern void regc(char);
+extern void regdump(regexp *);
+extern void regerror(char *);
+extern void reginsert(char, char *);
+extern void regoptail(char *, char *);
+extern void regtail(char *, char *);
+extern regval regexecstring(regexp *, char *);
+
+/*
+ * regsub.c
+ */
+extern int regsub(regexp *, char *, char *, int);
+
+#endif /* __REGEXP_H__ */
diff --git a/libs/sipcc/core/includes/ringlist.h b/libs/sipcc/core/includes/ringlist.h
new file mode 100755
index 0000000000..71ac3bddc8
--- /dev/null
+++ b/libs/sipcc/core/includes/ringlist.h
@@ -0,0 +1,22 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef RINGLIST_H
+#define RINGLIST_H
+
+#define MAX_RINGS 56
+#define RING_LIST_BUFFER_SIZE (MAX_RINGS*64)
+
+extern uint16_t rng_get_num_ringers(void);
+extern int8_t *rng_get_ring_name(uint16_t);
+extern void rng_play_ring(uint16_t);
+extern void rng_set_ringer(void);
+extern boolean rng_select_ringer(uint16_t);
+extern uint16_t rng_get_selected_ringnum(void);
+extern int16_t handle_ringlist(int16_t, void *);
+extern void rng_request_ringlist(void);
+extern void rng_init(void);
+extern void rng_cancel_ring(void);
+
+#endif
diff --git a/libs/sipcc/core/includes/rtp_defs.h b/libs/sipcc/core/includes/rtp_defs.h
new file mode 100644
index 0000000000..b12f5fe9b6
--- /dev/null
+++ b/libs/sipcc/core/includes/rtp_defs.h
@@ -0,0 +1,123 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef RTP_DEFS_H
+#define RTP_DEFS_H
+
+#include "cpr_types.h"
+
+#define SAMPLES_TO_MILLISECONDS(SAMPLES) ((SAMPLES)>>3)
+#define MILLISECONDS_TO_SAMPLES(PERIOD) ((PERIOD)<<3)
+
+#define MAX_TX_RTP_PORTS 2
+#define MAX_FRAMES_PER_PACKET 6
+#define MAX_VOICE_FRAME_SIZE 320
+
+#define GSM_EFR_FRAME_SIZE 32
+#define GSM_FR_FRAME_SIZE 33
+#define G729_FRAME_SIZE 10
+#define G723_FRAME_SIZE63 24
+#define G723_FRAME_SIZE53 20
+#define G723_SID_FRAME_SIZE 4
+#define G729_SID_FRAME_SIZE 2
+
+#define GSM_SAMPLES_PER_FRAME 160
+#define G729_SAMPLES_PER_FRAME 80
+#define G723_SAMPLES_PER_FRAME 240
+#define LINEAR_16KHZ_SAMPLES_PER_FRAME 160 // 10 ms = 160 samples @ 16 kHz
+
+#define MAX_ARM_TO_DSP_CHANNEL 3
+#define MAX_DSP_TO_ARM_CHANNEL 2
+#define HALF_SIZE_DATA_INGRESS 240
+#define RX_MAX MAX_ARM_TO_DSP_CHANNEL
+
+#define OPEN_OK 0
+#define OPEN_ERROR_DUPLICATE -1
+
+#define ASSIGN_TX_CHANNEL (0x1)
+#define ASSIGN_RX_CHANNEL (0x2)
+#define CHANNEL_CLOSE_IN_PROGRESS (0x80000000)
+
+#define RTP_START_PORT 0x4000
+#define RTP_END_PORT 0x7FFE
+
+#define GET_DYN_PAYLOAD_TYPE_VALUE(a) ((a & 0XFF00) ? ((a & 0XFF00) >> 8) : a)
+#define SET_PAYLOAD_TYPE_WITH_DYNAMIC(a,b) ((a << 8) | b)
+
+
+//=============================================================================
+//
+// Enumeration Types
+//
+//-----------------------------------------------------------------------------
+enum RTP_PAYLOAD_TYPES
+{
+ G711_MULAW_PAYLOAD_TYPE = 0,
+ GSM_FR_PAYLOAD_TYPE = 3,
+ G723_PAYLOAD_TYPE = 4,
+ G711_ALAW_PAYLOAD_TYPE = 8,
+ LINEAR_8KHZ_PAYLOAD_TYPE = 12,
+ TYPE13_SID_PAYLOAD_TYPE = 13,
+ G729_PAYLOAD_TYPE = 18,
+ GSM_EFR_PAYLOAD_TYPE = 20,
+ LINEAR_16KHZ_PAYLOAD_TYPE = 25,
+ AVT_PAYLOAD_TYPE = 101,
+ MASK_PAYLOAD_TYPE = 0x7f
+};
+
+enum RTP_TRANSMIT_STATES
+{
+ RTP_TX_FRAME,
+ RTP_TX_START,
+ RTP_TX_NO_FRAME,
+ RTP_TX_END = RTP_TX_NO_FRAME,
+ RTP_TX_SID
+};
+
+enum RTP_RX_STATES
+{
+ RTP_RX_NORMAL,
+ RTP_RX_FLUSH_SOON,
+ RTP_RX_FLUSH_NOW
+};
+
+enum RTP_TALKERS_TYPES
+{
+ FIRST_TALKER = 0,
+ LAST_TALKER = RX_MAX - 1,
+ NO_TALKER
+};
+
+typedef enum
+{
+ RTP_INGRESS = 0,
+ RTP_EGRESS
+} t_RtpDirection;
+
+//=============================================================================
+//
+// Structure/Type definitions
+//
+//-----------------------------------------------------------------------------
+typedef uint16_t rtp_channel_t;
+
+/********************************/
+/* RTP Call Stats Descriptor */
+/* */
+/********************************/
+
+typedef struct
+{
+ int call_id;
+ unsigned long Rxduration;
+ unsigned long Rxpackets;
+ unsigned long Rxoctets;
+ unsigned long Rxlatepkts;
+ unsigned long Rxlostpkts;
+ unsigned long Txduration;
+ unsigned long Txpackets;
+ unsigned long Txoctets;
+} t_callstats;
+
+#endif
diff --git a/libs/sipcc/core/includes/scSession.h b/libs/sipcc/core/includes/scSession.h
new file mode 100755
index 0000000000..0525d1928b
--- /dev/null
+++ b/libs/sipcc/core/includes/scSession.h
@@ -0,0 +1,24 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "string_lib.h"
+#include "sessionConstants.h"
+#include "sessionTypes.h"
+
+/* CallControl Provider Management Interfaces */
+void scSessionProviderCmd(sessionProvider_cmd_t *data);
+
+/* CallControl Provider Management Updates */
+void scSessionProviderState(unsigned int state, scProvider_state_t *data);
+
+/* Session mgmt */
+session_id_t scCreateSession(session_create_param_t *param);
+void scCloseSession(session_id_t sess_id);
+void scInvokeFeature(session_feature_t *featData);
+
+/* Session Updates */
+void scSessionUpdate(session_update_t *session);
+void scFeatureUpdate(feature_update_t *data);
+
+
diff --git a/libs/sipcc/core/includes/session.h b/libs/sipcc/core/includes/session.h
new file mode 100755
index 0000000000..2b2390a262
--- /dev/null
+++ b/libs/sipcc/core/includes/session.h
@@ -0,0 +1,168 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _SESSION_H_
+#define _SESSION_H_
+
+#include "sessionConstants.h"
+#include "sessionTypes.h"
+#include "sessuri.h"
+
+/**
+ * sessionProviderCmd
+ * Session Provider Management Interfaces
+ * Called by Application to issue cmds to Session Provider
+ *
+ * @param data - sessionProvider_cmd_t
+ * Contains the command session provider type and provider specific data
+ *
+ * @return none
+ *
+ */
+void sessionProviderCmd(sessionProvider_cmd_t *);
+
+/**
+ * sessionProviderState
+ * Method to report session provider state updates to Application
+ *
+ * @param state - provider_state_t
+ * Contains the INS/OOS state along with provider specific data
+ *
+ * @return none
+ *
+ */
+void sessionProviderState(provider_state_t *state);
+
+/**
+ * createSession
+ *
+ * Called to create a session of requested type
+ *
+ * @param param - uri
+ * indicates type of session and specific params
+ *
+ * @return ccSession_id_t - id of the session created
+ */
+
+session_id_t createSession(uri_t uri_info);
+
+/**
+ * closeSession
+ *
+ * Called to close an existing session
+ *
+ * @param sess_id - session id of the session to be closed
+ *
+ * @return >=0 success, -1 failure
+ */
+
+int closeSession(session_id_t sess_id);
+
+/**
+ * sessionCmd
+ * Session Lifecycle Management Interfaces
+ * Called by Application to manage Session States
+ *
+ * @param data - sessionCmd_t
+ * Contains the command session type and session specific data
+ *
+ * @return none
+ *
+ */
+void sessionCmd(sessionCmd_t *sCmd);
+
+/**
+ * invokeFeature
+ *
+ * Called to invoke a feature on session or device
+ *
+ * @param feat - feature specific data along with its id
+ * @param featData - Additional info if needed for the feature
+ *
+ * @return none
+ *
+ */
+
+void invokeFeature(session_feature_t *feat);
+
+/**
+ * invokeProviderFeature
+ *
+ * Called to invoke a feature on session or device
+ *
+ * @param feat - feature specific data along with its id
+ * @param featData - Additional info if needed for the feature
+ *
+ * @return none
+ *
+ */
+
+void invokeProviderFeature(session_feature_t *feat);
+
+/**
+ * sessionUpdate
+ *
+ * Called by session provider to update session state and data
+ *
+ * @param session - session_update_t
+ * Contains session specific event state and data
+ *
+ * @return none
+ *
+ */
+void sessionUpdate(session_update_t *session);
+
+/**
+ * featureUpdate
+ *
+ * Called by session provider to update feature state and data
+ * not specific to a session
+ *
+ * @param feature - feature specific events and data
+ *
+ * @return none
+ *
+ */
+void featureUpdate(feature_update_t *feature);
+
+
+/**
+ * sessionMgmt
+ *
+ * Called to manage various misc. functions of the device
+ *
+ * @param sessMgmt - the data
+ *
+ * @return none
+ *
+ */
+void sessionMgmt (session_mgmt_t *sess_mgmt);
+
+/**
+ * sessionSendInfo
+ *
+ * Called to send an Info Package
+ *
+ * @param send_info - the session ID and the Info Package to be sent
+ *
+ * @return none
+ *
+ */
+void sessionSendInfo (session_send_info_t *send_info);
+
+/**
+ * sessionRcvdInfo
+ *
+ * Called to forward a received Info Package (either parsed or unparsed)
+ * to the Java side
+ *
+ * @param rcvd_info - the session ID and Info Package received
+ *
+ * @return none
+ *
+ */
+void sessionRcvdInfo (session_rcvd_info_t *rcvd_info);
+
+#endif
+
diff --git a/libs/sipcc/core/includes/sessionConstants.h b/libs/sipcc/core/includes/sessionConstants.h
new file mode 100755
index 0000000000..a094c3d867
--- /dev/null
+++ b/libs/sipcc/core/includes/sessionConstants.h
@@ -0,0 +1,364 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _SESSION_CONSTANTS_H_
+#define _SESSION_CONSTANTS_H_
+
+#include "cc_constants.h"
+
+typedef enum {
+ GROUP_TAG,
+ GROUP_SESSION_TYPE,
+ GROUP_CMD,
+ GROUP_STATE,
+ GROUP_CC_MODE,
+ GROUP_CC_REG_CAUSE,
+ GROUP_CC_FEATURE,
+ GROUP_DEVICE_FEATURE,
+ GROUP_RINGER_RESERVATION,
+ GROUP_CALL_STATE,
+ GROUP_CC_ATTR,
+ GROUP_CC_CALL_TYPE,
+ GROUP_CC_SECURITY,
+ GROUP_INFO_PKG_ID,
+ GROUP_CC_POLICY,
+ GROUP_UI_PRIVACY,
+ GROUP_SIP_BLF,
+ GROUP_SESSION_EVENT,
+ GROUP_CALL_EVENT,
+ GROUP_FILEPLAYER,
+ GROUP_MEDIA_EVENT,
+ GROUP_MEDIA_DIRECTION,
+ GROUP_PRIORITY,
+ GROUP_SESSION,
+ GROUP_CC_CAUSE
+} group_t;
+
+typedef enum {
+ TAG_LINE = 1L,
+ TAG_STATE,
+ TAG_CCM_ADDR,
+ TAG_STATUS,
+ TAG_LCLCFWD,
+ TAG_CFANUM,
+ TAG_COUNT,
+ TAG_INSTANCE,
+ TAG_TIMEOUT,
+ TAG_PRIORITY,
+ TAG_NOTPROG,
+ TAG_RESET_TYPE,
+ TAG_ATTR,
+ TAG_INST,
+ TAG_SECURITY,
+ TAG_CLD_NAME,
+ TAG_CLD_NUMB,
+ TAG_CLG_NAME,
+ TAG_CLG_NUMB,
+ TAG_PRIVACY,
+ TAG_FEAT_SET,
+ TAG_FEATURE,
+ TAG_PROMPT,
+ TAG_ORIG_NAME,
+ TAG_ORIG_NUMB,
+ TAG_REDIR_NAME,
+ TAG_REDIR_NUMB,
+ TAG_ALT_CLG,
+ TAG_DISP_CLG,
+ TAG_DISP_CLD,
+ TAG_CALL_TYPE,
+ TAG_MODE,
+ TAG_CAUSE,
+ TAG_CALL_SELECTED,
+ TAG_BUTTON_NUMB,
+ TAG_SPEED_DIAL,
+ TAG_LABEL,
+ TAG_GCID,
+ TAG_LOGDISP,
+ TAG_MWI_TYPE,
+ TAG_NEW_COUNT,
+ TAG_OLD_COUNT,
+ TAG_HP_NEW_COUNT,
+ TAG_HP_OLD_COUNT,
+ TAG_MEDIA_TYPE,
+ TAG_MEDIA_DIRECTION,
+ TAG_MEDIA_MODE,
+ TAG_DURATION,
+ TAG_SESSION_HANDLE,
+ TAG_MCAP_ID,
+ TAG_GROUP_ID,
+ TAG_STREAM_ID,
+ TAG_REF_COUNT,
+ TAG_SESSION_ID,
+ TAG_RECV_INFO_LIST,
+ TAG_INFO_PACKAGE,
+ TAG_CONTENT_TYPE,
+ TAG_MESSAGE_BODY,
+ TAG_POLICY,
+ TAG_CFG_VER,
+ TAG_DP_VER,
+ TAG_SK_VER,
+ TAG_METHOD,
+ TAG_SIS_VER_NAME,
+ TAG_SIS_VER_MAJOR,
+ TAG_SIS_VER_MINOR,
+ TAG_SIS_VER_ADDTNL
+} group_tag_t;
+
+
+/* Session types supported */
+/* SESSIONTYPE_* is encoded into the MSB of session_feature_t.session_id */
+// XXX TODO figure out how to decouple this from the Java side constant
+typedef enum {
+ SESSIONTYPE_CALLCONTROL = 1L,
+ SESSIONTYPE_RSTP,
+ SESSIONTYPE_RTP,
+ SESSIONTYPE_FILEPLAYER,
+ SESSIONTYPE_TONE,
+ SESSIONTYPE_CAPTURE
+} group_session_type_t;
+
+/* Session Provider Management Commands */
+typedef enum {
+ CMD_INIT = 1L,
+ CMD_INSERVICE,
+ CMD_RESTART,
+ CMD_SHUTDOWN,
+ CMD_UNLOAD,
+ CMD_PRE_INIT,
+ CMD_PRO_BASE,
+ CMD_UNREGISTER_ALL_LINES = 10L,
+ CMD_REGISTER_ALL_LINES,
+ CMD_BLF_INIT
+} group_cmd_t;
+
+/* Other provider specific cmds can be defined beginning with CMD_PRO_BASE */
+/* TBD from JNI */
+#define CC_CMD_UPDATELINES CMD_PRO_BASE
+
+/**
+ * Defines registration state
+ */
+typedef enum {
+ CC_CREATED_IDLE,
+ CC_OOS_FAILOVER,
+ CC_OOS_REGISTERING,
+ CC_OOS_AWAIT_CFG_SYNC,
+ CC_OOS_AWAIT_RESTART,
+ CC_INSERVICE,
+ CC_OOS_IDLE
+} cc_reg_state_t;
+
+/* Other provider specific cmds can be defined beginning with STATE_PRO_BASE */
+
+
+
+/* Device specific feature update IDs */
+typedef enum {
+ DEVICE_FEATURE_CFWD = 1L,
+ DEVICE_FEATURE_MWI,
+ DEVICE_FEATURE_MWILAMP,
+ DEVICE_FEATURE_MNC_REACHED,
+ DEVICE_SERVICE_CONTROL_REQ,
+ DEVICE_NOTIFICATION,
+ DEVICE_LABEL_N_SPEED,
+ DEVICE_REG_STATE,
+ DEVICE_CCM_CONN_STATUS,
+ DEVICE_CONDITIONAL_RESTART = 14L,
+ DEVICE_SYNC_CONFIG_VERSION,
+ DEVICE_ENABLE_VIDEO,
+ DEVICE_ENABLE_CAMERA,
+ DEVICE_FEATURE_BLF,
+ DEVICE_SUPPORTS_NATIVE_VIDEO
+} group_device_feature_t;
+
+/* Ringer Reservation feature update IDs */
+typedef enum {
+ RINGER_RESERVATION_CREATED = 100L,
+ RINGER_RESERVATION_UPDATE
+} group_ringer_reservation_t;
+
+/* Info Package */
+typedef enum {
+ INFO_PKG_ID_GENERIC_RAW = 0L
+} group_info_pkg_id_t;
+
+/* Session Events */
+typedef enum {
+ SESSION_CREATED = 1L,
+ SESSION_CLOSED
+} group_session_event_t;
+
+/* Call Session Events */
+typedef enum {
+ CALL_SESSION_CREATED = SESSION_CREATED,
+ CALL_SESSION_CLOSED = SESSION_CLOSED,
+ CALL_STATE = 3L,
+ CALL_NEWCALL,
+ CALL_INFORMATION,
+ CALL_ATTR,
+ CALL_SECURITY,
+ CALL_LOGDISP,
+ CALL_PLACED_INFO,
+ CALL_STATUS,
+ CALL_DELETE_LAST_DIGIT,
+ CALL_ENABLE_BKSP,
+ CALL_SELECT_FEATURE_SET,
+ CALL_SELECTED,
+ CALL_PRESERVATION_ACTIVE,
+ CALL_GCID,
+ CALL_FEATURE_CANCEL,
+ VIDEO_AVAIL = 20L,
+ CALL_RECV_INFO_LIST,
+ VIDEO_OFFERED,
+ RINGER_STATE,
+ CALL_CALLREF,
+ MEDIA_INTERFACE_UPDATE_BEGIN,
+ MEDIA_INTERFACE_UPDATE_SUCCESSFUL,
+ MEDIA_INTERFACE_UPDATE_FAIL,
+ CREATE_OFFER,
+ CREATE_ANSWER,
+ SET_LOCAL_DESC,
+ SET_REMOTE_DESC,
+ REMOTE_STREAM_ADD
+} group_call_event_t;
+
+/* File Player Session Events */
+typedef enum {
+ FILEPLAYER_PLAYED = 300L,
+ FILEPLAYER_ALLOCATED
+} group_fileplayer_t;
+
+typedef enum {
+ TONE_STARTED = 101L,
+ TONE_STOPPED,
+ MEDIA_INFO,
+ MEDIA_UPDATE
+} group_media_event_t;
+
+//#include "com_cisco_sessionapi_MediaDirection.h"
+typedef enum {
+ RX_DIRECTION = 0L,
+ TX_DIRECTION,
+ BI_DIRECTION
+} group_media_direction_t;
+
+typedef enum {
+ PROMPTSTATUS_PROMPT = 10L,
+ PROMPTSTATUS_HIGH = 11L,
+ PROMPTSTATUS_NORMAL = 15L,
+ PROMPTSTATUS_MEDIA_MANAGER = 16L,
+ PROMPTSTATUS_NOTIFICATION = 20L,
+ PROMPTSTATUS_STATUS = 30L,
+ PROMPTSTATUS_LOW = 31L,
+ SOFTKEYBAR_APPLICATION_MANAGER = 100L,
+ SOFTKEYBAR_MEDIA_MANAGER = 50L
+} group_priority_t;
+
+/* Session Features that can be invoked TBD should come from JNI */
+#define FEATURE_NONE 0
+#define FEATURE_VOLUME_CTRL 1
+#define FEATURE_PRO_BASE 0
+
+/* Call Priority TBD should come from JNI */
+#define CC_CALL_PRIORITY_NORMAL 0
+#define CC_CALL_PRIORITY_URGENT 1
+
+/* Session Commands TBD should come from JNI */
+typedef enum {
+ SESSION_REALIZE = 1,
+ SESSION_PREFETCH,
+ SESSION_START,
+ SESSION_STOP,
+ SESSION_DEALLOCATE,
+ SESSION_CLOSE,
+ SESSION_ALLOCATE
+} group_session_t;
+
+/*
+ * CC Provider specific constants.
+ * These do not come from JNI Files
+ */
+
+#include "phone_types.h"
+
+#define CC_ALL_LINES 255
+#define CC_SESSION_INVALID 0x01FFFFFF
+#define CC_MAX_GCID CC_GCID_LEN
+
+/* 1-9 * # A B C D are number 1 thru 16 */
+#define BKSP_KEY 90
+
+#ifdef __CC_CAUSE_STRINGS__
+static const char *cc_cause_names[] = {
+ "OK",
+ "ERR",
+ "UNASSIGNED_NUM",
+ "NO_RESOURCE",
+ "NO_ROUTE",
+ "NORMAL",
+ "BUSY",
+ "NO_USER_RESP",
+ "NO_USER_ANS",
+ "REJECT",
+ "INVALID_NUMBER",
+ "FACILITY_REJECTED",
+ "CALL_ID_IN_USE",
+ "XFER_LOCAL",
+ "XFER_REMOTE",
+ "XFER_BY_REMOTE",
+ "XFER_CONFERENCE",
+ "CONGESTION",
+ "ANONYMOUS",
+ "REDIRECT",
+ "PAYLOAD_MISMATCH",
+ "CONF",
+ "REPLACE",
+ "NO_REPLACE_CALL",
+ "NO_RESUME",
+ "NO_MEDIA",
+ "REQUEST_PENDING",
+ "INVALID_PARTICIPANT",
+ "NO_CONF_BRIDGE",
+ "MAX_PARTICIPANT",
+ "KEY_NOT_ACTIVE",
+ "TEMP_NOT_AVAILABLE",
+ "REMOTE_SERVER_ERROR",
+ "BARGE",
+ "CBARGE",
+ "NOT_FOUND",
+ "SECURITY_FAILURE",
+ "MONITOR",
+ "UI_STATE_BUSY",
+ "SIP_CAUSE_ANSWERED_ELSEWHERE",
+ "RETRIEVED",
+ "FORWARDED",
+ "ABANDONED",
+ "XFER_LOCAL_WITH_DIALSTRING",
+ "CAC_BW_OK",
+ "ONHOOK_FEAT_COMP",
+ "RESP_TIMEOUT",
+ "SERV_ERR_UNAVAIL",
+ "REMOTE_DISCONN_REQ_PLAYTONE",
+ "MAX_CAUSE"
+};
+#endif //__CC_CAUSE_STRINGS__
+
+#define MAX_SOFT_KEYS 16
+
+
+// eventually these should come from the Java side
+typedef enum {
+ SESSION_MGMT_APPLY_CONFIG,
+ SESSION_MGMT_SET_TIME,
+ SESSION_MGMT_GET_PHRASE_TEXT,
+ SESSION_MGMT_SET_UNREG_REASON,
+ SESSION_MGMT_GET_UNREG_REASON,
+ SESSION_MGMT_UPDATE_KPMLCONFIG,
+ SESSION_MGMT_GET_AUDIO_DEVICE_STATUS,
+ SESSION_MGMT_CHECK_SPEAKER_HEADSET_MODE,
+ SESSION_MGMT_LINE_HAS_MWI_ACTIVE,
+ SESSION_MGMT_EXECUTE_URI
+} session_mgmt_func_e;
+
+#endif
diff --git a/libs/sipcc/core/includes/sessionTypes.h b/libs/sipcc/core/includes/sessionTypes.h
new file mode 100755
index 0000000000..cc9b235516
--- /dev/null
+++ b/libs/sipcc/core/includes/sessionTypes.h
@@ -0,0 +1,427 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _SESSIONTYPES_H_
+#define _SESSIONTYPES_H_
+
+#include "string_lib.h"
+#include "sessionConstants.h"
+#include "ccsip_pmh.h"
+#include "cc_constants.h"
+#include "sip_ccm_transport.h"
+#include "plat_api.h"
+
+/*********************** SESSION ID *****************/
+typedef unsigned int session_id_t ;
+
+typedef struct {
+ unsigned int reason;
+ string_t reason_info;
+} ccSessionProvider_cmd_t;
+
+typedef struct {
+ string_t sis_ver_name ; //could be "cme" now.
+ unsigned int sis_ver_major;
+ unsigned int sis_ver_minor;
+ unsigned int sis_ver_addtnl;
+}sis_ver;
+
+typedef struct {
+ unsigned int cause;
+ unsigned int mode;
+ sis_ver sis_ver_info;
+} ccProvider_state_t;
+
+typedef struct {
+ line_t line_id;
+ string_t dial;
+} ccSession_create_param_t;
+
+typedef struct {
+ string_t info;
+ string_t info1;
+ unsigned int state;
+ cc_jsep_action_t action;
+ cc_media_stream_id_t stream_id;
+ cc_media_track_id_t track_id;
+ cc_media_type_t media_type;
+ cc_level_t level;
+ unsigned int sessionid;
+ cc_boolean has_constraints;
+} ccSession_feature_t;
+
+typedef struct {
+ int state;
+ int attr;
+ int inst;
+ line_t line_id;
+ int cause;
+ string_t sdp;
+ unsigned int media_stream_id;
+ unsigned int media_stream_track_id;
+} cc_call_state_data_t;
+/* CALL_SESSION_CREATED shall use the call_state as data*/
+
+typedef struct
+{
+ string_t cldNum;
+ string_t cldName;
+} cc_placed_call_info_t;
+
+typedef struct
+{
+ string_t clgName;
+ string_t clgNumber;
+ string_t altClgNumber;
+ boolean dispClgNumber;
+ string_t cldName;
+ string_t cldNumber;
+ boolean dispCldNumber;
+ string_t origCalledName;
+ string_t origCalledNumber;
+ string_t lastRedirectingName;
+ string_t lastRedirectingNumber;
+ unsigned short call_type;
+ unsigned short instance_id;
+ int security;
+ int policy;
+} cc_callinfo_t;
+
+typedef struct {
+ string_t featSet;
+ int featMask[MAX_SOFT_KEYS];
+} cc_featurekey_set_t;
+
+typedef struct {
+ cc_boolean start;
+ vcm_ring_mode_t mode;
+ cc_boolean once;
+} cc_ringer_state_t;
+
+/**
+ * Define call status to carry over timeout/priority that might be sent from CUCM.
+ * Note: if the values of timeout and priority are zero, then 2 second is the
+ * derfault value for the timeout. It's mostly the application based on UI
+ * design.
+ */
+typedef struct {
+ string_t status;
+ int timeout;
+ int priority;
+} cc_call_status_t;
+
+typedef struct
+{
+ union {
+ cc_call_state_data_t state_data;
+ cc_placed_call_info_t plcd_info;
+ cc_callinfo_t call_info;
+ cc_call_status_t status;
+ char gcid[CC_MAX_GCID];
+ int action;
+ int security;
+ cc_featurekey_set_t feat_set;
+ unsigned int target_sess_id;
+ unsigned int callref;
+ string_t recv_info_list;
+ cc_ringer_state_t ringer;
+ } data;
+} ccSession_update_t;
+
+typedef struct {
+ line_t line;
+ unsigned int info;
+} cc_line_data_t;
+
+typedef struct {
+ int state;
+ int info;
+} cc_feature_state_t;
+
+typedef struct {
+ cc_blf_state_t state;
+ int request_id;
+ int app_id;
+} cc_feature_blf_state_t;
+
+typedef struct {
+ int timeout;
+ boolean notifyProgress;
+ char priority;
+ string_t prompt;
+} cc_notification_data_t;
+
+typedef struct {
+ line_t line;
+ unsigned char button;
+ string_t speed;
+ string_t label;
+} cc_label_n_speed_t;
+
+typedef struct {
+ string_t cfg_ver;
+ string_t dp_ver;
+ string_t softkey_ver;
+} cc_cfg_version_t;
+
+typedef struct {
+ line_t line;
+ boolean isFwd;
+ boolean isLocal;
+ string_t cfa_num;
+} cc_cfwd_status_t;
+
+typedef struct {
+ string_t addr;
+ int status;
+} cc_ccm_conn_t;
+
+typedef struct {
+ line_t line;
+ boolean status;
+ int type;
+ int newCount;
+ int oldCount;
+ int hpNewCount;
+ int hpOldCount;
+} cc_mwi_status_t;
+
+typedef struct {
+ union {
+ cc_line_data_t line_info; // For line specific features
+ cc_feature_state_t state_data; // For device specific feature
+ cc_feature_blf_state_t blf_data; // For blf state updates.
+ cc_notification_data_t notification;
+ cc_label_n_speed_t cfg_lbl_n_spd;
+ cc_cfwd_status_t cfwd; // For CFWD ALL feature
+ cc_ccm_conn_t ccm_conn;
+ cc_mwi_status_t mwi_status;
+ unsigned int reset_type;
+ cc_cfg_version_t cfg_ver_data;
+ } data;
+} ccFeature_update_t;
+
+typedef struct {
+ int data;
+} ccSessionCmd_t;
+
+/*********************** STREAM SESSION TYPES *****************/
+
+typedef struct {
+ unsigned int reason;
+} scSessionProvider_cmd_t;
+
+typedef struct {
+ unsigned int mode;
+} scSession_state_t;
+
+typedef struct {
+ line_t line_id;
+} scSession_create_param_t;
+
+typedef struct {
+ string_t info;
+} scSession_feature_t;
+
+typedef struct {
+ string_t info;
+} scProvider_state_t;
+
+typedef struct {
+ int type;
+ int mcap_id;
+ int group_id;
+ int stream_id;
+ int call_id;
+ int direction;
+ int ref_count;
+ int session_handle;//session handle for ms rtp session
+} rtp_session_info;
+
+typedef struct {
+ int refcount;
+} rtp_session_update;
+
+typedef struct {
+ union {
+ int state;
+ rtp_session_info rtp_info;
+ rtp_session_update rtp_update;
+ } data;
+} scSession_update_t;
+
+typedef struct {
+ string_t info;
+} scFeature_update_t;
+
+typedef struct {
+ string_t info;
+} scSessionCmd_t;
+
+typedef struct {
+ int id;
+ int data;
+} rcFeature_update_t;
+
+/********************** SESSION TYPES ****************************/
+
+
+typedef struct {
+ unsigned int sessionType;
+ unsigned int cmd;
+ union {
+ ccSessionProvider_cmd_t ccData;
+ scSessionProvider_cmd_t scData;
+ } cmdData;
+} sessionProvider_cmd_t;
+
+typedef struct {
+ unsigned int sessionType;
+ unsigned int state;
+ union {
+ ccProvider_state_t ccData;
+ scProvider_state_t scData;
+ } stateData;
+} provider_state_t;
+
+typedef struct {
+ unsigned int sessionType;
+ string_t uri;
+ union {
+ ccSession_create_param_t ccData;
+ scSession_create_param_t scData;
+ } createData;
+} session_create_param_t;
+
+typedef struct {
+ unsigned int session_id;
+ unsigned int featureID;
+ union {
+ ccSession_feature_t ccData;
+ scSession_feature_t scData;
+ } featData;
+} session_feature_t;
+
+typedef struct {
+ unsigned int sessionID;
+ unsigned int eventID;
+ unsigned int sessType;
+ union {
+ ccSession_update_t ccSessionUpd;
+ scSession_update_t scSessionUpd;
+ } update;
+}session_update_t;
+
+typedef struct {
+ unsigned int sessID;
+ unsigned int cmd;
+ union {
+ ccSessionCmd_t ccCmd;
+ scSessionCmd_t scCmd;
+ } cmdData;
+}sessionCmd_t;
+
+
+typedef struct {
+ unsigned int sessionType;
+ unsigned int featureID;
+ union {
+ ccFeature_update_t ccFeatUpd;
+ scFeature_update_t scFeatUpd;
+ rcFeature_update_t rcFeatUpd;
+ } update;
+}feature_update_t;
+
+
+typedef struct {
+ string_t config_version_stamp;
+ string_t dialplan_version_stamp;
+ string_t fcp_version_stamp;
+ string_t cucm_result;
+ string_t load_id;
+ string_t inactive_load_id;
+ string_t load_server;
+ string_t log_server;
+ boolean ppid;
+} session_mgmt_config_t;
+
+typedef struct {
+ int result;
+} session_mgmt_apply_config_result_t;
+
+typedef struct {
+ long gmt_time;
+} session_mgmt_time_t;
+
+typedef struct {
+ int ret_val;
+ int ndx;
+ char *outstr;
+ uint32_t len;
+} session_mgmt_phrase_text_t;
+
+typedef struct {
+ int unreg_reason;
+} session_mgmt_unreg_reason_t;
+
+typedef struct {
+ int kpml_val;
+} session_mgmt_kpmlconfig_t;
+
+typedef struct {
+ int enabled;
+ plat_audio_device_t device_type;
+} session_mgmt_audio_device_status_t;
+
+typedef struct {
+ boolean enabled;
+} session_mgmt_speaker_headset_mode_t;
+
+typedef struct {
+ boolean ret_val;
+ line_t line;
+} session_mgmt_line_mwi_active_t;
+
+typedef struct {
+ string_t uri;
+} session_mgmt_uri_t;
+
+typedef struct {
+ session_mgmt_func_e func_id;
+ union {
+ session_mgmt_config_t config;
+ session_mgmt_apply_config_result_t apply_config_result;
+ session_mgmt_time_t time;
+ session_mgmt_phrase_text_t phrase_text;
+ session_mgmt_unreg_reason_t unreg_reason;
+ session_mgmt_kpmlconfig_t kpmlconfig;
+ session_mgmt_audio_device_status_t audio_device_status;
+ session_mgmt_speaker_headset_mode_t speaker_headset_mode;
+ session_mgmt_line_mwi_active_t line_mwi_active;
+ session_mgmt_uri_t uri;
+ } data;
+} session_mgmt_t;
+
+
+typedef struct {
+ string_t info_package;
+ string_t content_type;
+ string_t message_body;
+} info_generic_raw_t;
+
+typedef struct {
+ unsigned int sessionID;
+ info_generic_raw_t generic_raw;
+} session_send_info_t;
+
+typedef struct {
+ unsigned int sessionID;
+ int packageID;
+ union {
+ info_generic_raw_t generic_raw;
+ } info;
+} session_rcvd_info_t;
+
+#endif
+
diff --git a/libs/sipcc/core/includes/sessuri.h b/libs/sipcc/core/includes/sessuri.h
new file mode 100644
index 0000000000..8c5ffbf55a
--- /dev/null
+++ b/libs/sipcc/core/includes/sessuri.h
@@ -0,0 +1,171 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _SESSURI_H_
+#define _SESSURI_H_
+
+#define MAX_LEN_SCHEME_INFO 256
+#define MAX_STR_LEN_PARAM_TYPE 64
+#define MAX_STR_LEN_PARAM_VAL 64
+
+/*
+ * Scheme names
+ */
+#define SCHEME_SIP "sip"
+#define SCHEME_FILE "file"
+#define SCHEME_RTP "rtp"
+#define SCHEME_RTSP "rtsp"
+#define SCHEME_CAPTURE "capture"
+
+/**
+ *
+ * Different URI types.
+ *
+ */
+typedef enum {
+ SCHEME_NONE=0,
+ SIP_URI,
+ FILE_URI,
+ CAPTURE_URI,
+ RTP_URI,
+ RTSP_URI
+} scheme_e;
+
+/**
+ * parameter tags/names
+ *
+ */
+
+#define LINE_TAG "line"
+
+/**
+ * Definitions for file player session
+ */
+#define CADENCE_TAG "cadence"
+#define MEDIA_TYPE_TAG "media_type"
+#define LOOP_COUNT_TAG "loop_count"
+#define PRIORITY_TAG "priority"
+#define FILEPTYPE_TAG "type"
+
+/**
+ * Definitions for raw rtp session
+ */
+#define DIRECTION_TAG "direction"
+#define MULTICAST_TAG "mcast"
+#define PAYLOADTYPE_TAG "payloadtype"
+#define FRAMESIZE_TAG "framesize"
+#define VADENABLE_TAG "vad"
+#define PRECEDENCE_TAG "precedence"
+#define MIXINGMODE_TAG "mode"
+#define MIXINGPARTY_TAG "party"
+#define CHANNELTYPE_TAG "channeltype"
+#define LOCALADDRESS_TAG "localaddress"
+#define LOCALPORT_TAG "localport"
+#define ALGORITHM_TAG "algorithm"
+
+/**
+ * Param types required for various URIs.
+ *
+ */
+typedef enum {
+ LINE_PARAM=0,
+ MEDIA_TYPE_PARAM,
+ CADENCE_PARAM,
+ LOOP_COUNT_PARAM,
+ PRIORITY_PARAM,
+ MAX_QUERY_PARAM,
+ DIRECTION_PARAM,
+ MULTICAST_PARAM,
+ PAYLOADTYPE_PARAM,
+ FRAMESIZE_PARAM,
+ VADENABLE_PARAM,
+ PRECEDENCE_PARAM,
+ MIXINGMODE_PARAM,
+ MIXINGPARTY_PARAM,
+ CHANNELTYPE_PARAM,
+ LOCALADDRESS_PARAM,
+ LOCALPORT_PARAM,
+ ALGORITHM_PARAM,
+ FILETYPE_PARAM
+} param_e;
+
+typedef enum {
+ MEDIA_TYPE_AUDIO,
+ MEDIA_TYPE_VIDEO,
+ MEDIA_TYPE_AUDIO_VIDEO,
+} media_type_e;
+
+/**
+ * params related to call sessions.
+ *
+ */
+typedef struct {
+ int line_id;
+ media_type_e media_type;
+} call_session_param_t;
+
+/**
+ * params related to capture sessions.
+ *
+ */
+typedef struct {
+ media_type_e media_type;
+} capture_session_param_t;
+
+/**
+ *
+ * params related file sessions
+ */
+typedef struct {
+ int type;
+ int loop_count;
+ int cadence;
+ int priority;
+} file_session_param_t;
+
+typedef struct {
+ int direction;
+ int multicast;
+ int payloadtype;
+ int framesize;
+ int vadenable;
+ int precedence;
+ int mixingmode;
+ int mixingparty;
+ int channeltype;
+ int localaddress;
+ int localport;
+ int algorithm;
+} raw_rtp_session_param_t;
+
+/*
+ * generic param type
+ */
+typedef union params {
+ call_session_param_t call_session_param;
+ file_session_param_t file_session_param;
+ raw_rtp_session_param_t raw_session_param;
+ capture_session_param_t capture_session_param;
+} param_t;
+
+
+/*
+ * URI information. This is output of the Parser.
+ *
+ */
+typedef struct uri_s {
+ scheme_e scheme;
+ char scheme_specific[MAX_LEN_SCHEME_INFO];
+ union
+ {
+ call_session_param_t call_session_param;
+ file_session_param_t file_session_param;
+ raw_rtp_session_param_t raw_session_param;
+ }param;
+
+} uri_t;
+
+int parse_uri(const char *uri, uri_t *uri_info);
+
+#endif
diff --git a/libs/sipcc/core/includes/singly_link_list.h b/libs/sipcc/core/includes/singly_link_list.h
new file mode 100644
index 0000000000..a0046abc6d
--- /dev/null
+++ b/libs/sipcc/core/includes/singly_link_list.h
@@ -0,0 +1,117 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _SINGLY_LINK_LIST_H
+#define _SINGLY_LINK_LIST_H
+
+typedef enum {
+ SLL_MATCH_FOUND,
+ SLL_MATCH_NOT_FOUND
+} sll_match_e;
+
+/*
+ * type definition for find function pointer. The find function takes two arguments:
+ * 1. find_by_p - pointer to the key
+ * 2. data_p - pointer to the linked list node data.
+ */
+typedef sll_match_e(*sll_find_callback_t)(void *find_by_p, void *data_p);
+
+typedef void *sll_handle_t;
+
+typedef enum {
+ SLL_RET_SUCCESS,
+ SLL_RET_INVALID_ARGS,
+ SLL_RET_MALLOC_FAILURE,
+ SLL_RET_NODE_NOT_FOUND,
+ SLL_RET_LIST_NOT_EMPTY,
+ SLL_RET_OTHER_FAILURE
+} sll_return_e;
+
+/*
+ * sll_create(): creates a signly linked list control block and initializes it.
+ * Applications shall call this first before performing any singly
+ * linked list primitives, such as append, remove, find or destroy.
+ *
+ * Parameters: find_fp - function pointer which will be used to find the matching node.
+ *
+ * Returns: list handle or NULL if it can not create the list.
+ */
+extern sll_handle_t sll_create(sll_find_callback_t find_fp);
+
+/*
+ * sll_destroy(): if the list is empty, it frees the list.
+ * It is the responsibility of the applications to empty
+ * the list before destroying the list.
+ *
+ * Parameters: list_handle - handle to the list.
+ *
+ * Returns: SLL_RET_SUCCESS if it successfully destroys.
+ * SLL_RET_INVALID_ARGS if the arguments are invalid.
+ * SLL_RET_LIST_NOT_EMPTY if the list is not empty.
+ */
+extern sll_return_e sll_destroy(sll_handle_t list_handle);
+
+/*
+ * sll_append(): creates a list node and appends it to the list.
+ * Applications are responsible for memory management of the
+ * data that the node will point to.
+ *
+ * Parameters: list_handle - handle to the list.
+ * data_p - pointer to the data that the list node will point to.
+ *
+ * Returns: SLL_RET_SUCCESS if it successfully appends.
+ * SLL_RET_INVALID_ARGS if the arguments are invalid.
+ * SLL_RET_MALLOC_FAILURE if memory allocation fails.
+ */
+extern sll_return_e sll_append(sll_handle_t list_handle, void *data_p);
+
+/*
+ * sll_remove(): removes the node from the list and frees the node.
+ * Applications are responsible for memory management of the
+ * data that the node points to.
+ *
+ * Parameters: list_handle - handle to the list.
+ * data_p - pointer to the data that the list node points to.
+ *
+ * Returns: SLL_RET_SUCCESS if it successfully removes.
+ * SLL_RET_INVALID_ARGS if the arguments are invalid.
+ * SLL_RET_NODE_NOT_FOUND if the node is not found in the list.
+ */
+extern sll_return_e sll_remove(sll_handle_t list_handle, void *data_p);
+
+/*
+ * sll_find(): finds the matching node data using find_fp function.
+ *
+ * Parameters: list_handle - handle to the list.
+ * find_by_p - pointer to the opaque data that will be used by find_fp function.
+ *
+ * Returns: pointer to the data or NULL if it can not find.
+ */
+extern void *sll_find(sll_handle_t list_handle, void *find_by_p);
+
+/*
+ * sll_next(): returns pointer to the data in the next node to the node holding data_p.
+ * if data_p is NULL, then returns pointer to the data in the first node.
+ * Applications can use this primitive to walk through the list. Typically,
+ * it can be used to remove the individual nodes and to destroy the list
+ * before shutting down/resetting the application.
+ *
+ * Parameters: list_handle - handle to the list.
+ * data_p - pointer to the data that the list node points to.
+ *
+ * Returns: pointer to the data or NULL if it can not find.
+ */
+extern void *sll_next(sll_handle_t list_handle, void *data_p);
+
+/*
+ * sll_count(): returns the number of elements in the list.
+ * count of the linked list.
+ *
+ * Parameters: list_handle - handle to the list.
+ *
+ * Returns: returns the number of elements in the list.
+ */
+extern unsigned int sll_count(sll_handle_t list_handle);
+
+#endif
diff --git a/libs/sipcc/core/includes/sip_socket_api.h b/libs/sipcc/core/includes/sip_socket_api.h
new file mode 100755
index 0000000000..2969d7d8d0
--- /dev/null
+++ b/libs/sipcc/core/includes/sip_socket_api.h
@@ -0,0 +1,80 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef __SIP_SOCKET_API_H__
+#define __SIP_SOCKET_API_H__
+
+#include "cpr.h"
+#include "cpr_socket.h"
+
+/**
+ * sipSocketSend
+ *
+ * @brief The sipSocketSend() function is a wrapper used by the sipstack to send
+ * data over a socket. This function decides to use the secure versus unsecure
+ * connection based on the "secure" flag.
+ *
+ * @note - The implementation of both secure/non-secure is the same in RT/TNP
+ * products. It is different for the other vendors and hence we need this
+ * flexibility.
+ *
+ * @param[in] soc Specifies the socket created with cprSocket() to send
+ * @param[in] buf A pointer to the buffer of the message to send.
+ * @param[in] len Specifies the length in bytes of the message pointed to by the buffer argument.
+ * @param[in] flags - The options used for the send.
+ *
+ *
+ */
+ssize_t
+sipSocketSend (cpr_socket_t soc,
+ CONST void *buf,
+ size_t len,
+ int32_t flags,
+ boolean secure);
+
+/**
+ * sipSocketRecv
+ *
+ * @brief The sipSocketRecv() function is a wrapper used by the sipstack to send
+ * data over a socket. This function decides to use the secure versus unsecure
+ * connection based on the "secure" flag.
+ *
+ * @note - The implementation of both secure/non-secure is the same in RT/TNP
+ * products. It is different for the other vendors and hence we need this
+ * flexibility.
+ *
+ * @param[in] soc Specifies the socket created with cprSocket() to send
+ * @param[in] buf A pointer to the buffer of the message to send.
+ * @param[in] len Specifies the length in bytes of the message pointed to by the buffer argument.
+ * @param[in] flags - The options used for the recv.
+ */
+ssize_t
+sipSocketRecv (cpr_socket_t soc,
+ void * RESTRICT buf,
+ size_t len,
+ int32_t flags,
+ boolean secure);
+
+/**
+ * sipSocketClose
+ *
+ * @brief The sipSocketClose() function is a wrapper used by the sipstack to
+ * close a socket. This function decides to use the secure versus unsecure
+ * connection based on the "secure" flag.
+ *
+ * @note - The implementation of both secure/non-secure is the same in RT/TNP
+ * products. It is different for the other vendors and hence we need this
+ * flexibility.
+ *
+ * @param[in] soc - The socket that needs to be destroyed
+ *
+ * @return CPR_SUCCESS on success otherwise, CPR_FAILURE. cpr_errno needs to be set in this case.
+ *
+ * @note The possible error values this function should return are
+ * @li [CPR_EBADF] socket is not a valid socket descriptor.
+ */
+cpr_status_e
+sipSocketClose (cpr_socket_t soc,
+ boolean secure);
+#endif
diff --git a/libs/sipcc/core/includes/sntp.h b/libs/sipcc/core/includes/sntp.h
new file mode 100644
index 0000000000..93f53ea147
--- /dev/null
+++ b/libs/sipcc/core/includes/sntp.h
@@ -0,0 +1,92 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef SNTP_H
+#define SNTP_H
+
+#include
+#include
+#include
+#include
+
+#include
+// Begin system specific includes
+//#include
+#include
+#include
+#include
+#include
+#include
+#include
+// End system specific includes
+
+#define MAX_IPADDR_STR_LEN 48
+
+#define NTP_UTC_OFFSET (2208963600)
+#define PORT_NTP (123)
+#define MULTICAST_ADDR_NTP (0xE0000101L)
+#define BROADCAST_ADDR (0xFFFFFFFF)
+#define TIMEPORT (37)
+
+typedef enum { unicast, multicast, anycast, directed_broadcast } SNTP_Mode;
+
+typedef struct {
+ unsigned int precision:8;
+ unsigned int poll:8;
+ unsigned int stratum:8;
+ unsigned int mode:3;
+ unsigned int versionNumber:3;
+ unsigned int leapIndicator:2;
+} NTPHeader_s;
+
+typedef struct {
+ union {
+ NTPHeader_s header;
+ unsigned long rawheader;
+ } u;
+ unsigned long rootDelay;
+ unsigned long rootDispersion;
+ unsigned long referenceIdentifier;
+ unsigned long referenceTimestamp[2];
+ unsigned long originateTimestamp[2];
+ unsigned long receiveTimestamp[2];
+ unsigned long transmitTimestamp[2];
+ // Removed the following fields since they are version 4
+ // specific.
+ //unsigned long keyIdentifier;
+ //unsigned long messageDigest[4];
+} NTPStruct_s;
+
+typedef struct {
+ Socket *server_socket; // Socket to SNTP server
+ Socket *lsocket; // Local listening socket
+ Socket *bsocket; // Broadcast listening socket
+ Socket *msocket; // Multicast listening socket
+ char address[MAX_IPADDR_STR_LEN];
+ unsigned long sntp_server_addr;
+ SNTP_Mode mode;
+
+ unsigned long destinationTimestamp[2];
+ long roundtripDelay[2];
+ long timeOffset[2];
+ long time_zone;
+} SNTP_State;
+
+typedef union {
+ unsigned long NTPDataBuffer[17];
+ NTPStruct_s NTPData;
+} NTPPacket_u;
+
+void SNTPInit(void);
+void SNTPStop(void);
+int SNTPSend(void);
+void SNTPCallback(irx_tmr_buf *pTmrBlk);
+int SNTPRecv(SysHdr *pSm);
+long NTPSemanticCheck(const NTPStruct_s *ntpdata);
+void SNTPSecondUpdate(void);
+void printNTPStruct(const NTPStruct_s *ntpdata, const SNTP_State *state);
+long sntp_get_rand_seed(void);
+void SNTPDebugInit(void);
+
+#endif
diff --git a/libs/sipcc/core/includes/string_lib.h b/libs/sipcc/core/includes/string_lib.h
new file mode 100755
index 0000000000..1efb231c7d
--- /dev/null
+++ b/libs/sipcc/core/includes/string_lib.h
@@ -0,0 +1,56 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _STRING_LIB_INCLUDED_H /* allows multiple inclusion */
+#define _STRING_LIB_INCLUDED_H
+
+#include "cpr_types.h"
+
+#define LEN_UNKNOWN -1
+
+typedef struct string_block_t_
+{
+ struct string_block_t_ *next;
+ uint16_t refcount;
+ uint16_t length;
+ const char *fname;
+ int line;
+ short signature;
+ char data[1];
+} string_block_t;
+
+
+/*
+ * Prototypes for functions
+ */
+
+string_t strlib_malloc(const char *str, int length, const char *fname,
+ int line);
+string_t strlib_copy(string_t str);
+string_t strlib_update(string_t destination, const char *source,
+ const char *fname, int line);
+string_t strlib_append(string_t str, const char *toappend_str,
+ const char *fname, int line);
+string_t strlib_prepend(string_t str, const char *toprepend_str,
+ const char *fname, int line);
+void strlib_free(string_t str);
+char *strlib_open(string_t str, int length, const char *fname, int line);
+string_t strlib_close(char *str);
+string_t strlib_printf(const char *format, ...);
+string_t strlib_empty(void);
+void strlib_debug_init(void);
+long strlib_mem_used(void);
+int strlib_test_memory_is_string(void *mem);
+void strlib_init (void);
+
+#ifndef __STRINGLIB_INTERNAL__
+#define strlib_malloc(x,y) strlib_malloc(x,y,__FILE__,__LINE__)
+#define strlib_update(x,y) strlib_update(x,y,__FILE__,__LINE__)
+#define strlib_append(x,y) strlib_append(x,y,__FILE__,__LINE__)
+#define strlib_prepend(x,y) strlib_prepend(x,y,__FILE__,__LINE__)
+#define strlib_open(x,y) strlib_open(x,y,__FILE__,__LINE__)
+#endif
+
+
+#endif
diff --git a/libs/sipcc/core/includes/subapi.h b/libs/sipcc/core/includes/subapi.h
new file mode 100755
index 0000000000..367842732a
--- /dev/null
+++ b/libs/sipcc/core/includes/subapi.h
@@ -0,0 +1,43 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _SUBAPI_H_
+#define _SUBAPI_H_
+
+#include "ccsip_subsmanager.h"
+
+cc_rcs_t sub_int_subnot_register(cc_srcs_t src_id, cc_srcs_t dst_id,
+ cc_subscriptions_t evt_pkg, void *callback_fun,
+ cc_srcs_t dest_task, int msg_id,
+ void *term_callback, int term_msg_id,
+ long min_duration, long max_duration);
+
+cc_rcs_t sub_int_subscribe(sipspi_msg_t *msg_p);
+
+cc_rcs_t sub_int_subscribe_ack(cc_srcs_t src_id, cc_srcs_t dst_id,
+ sub_id_t sub_id, uint16_t response_code,
+ int duration);
+
+cc_rcs_t sub_int_notify(cc_srcs_t src_id, cc_srcs_t dst_id, sub_id_t sub_id,
+ ccsipNotifyResultCallbackFn_t notifyResultCallback,
+ int subsNotResCallbackMsgID,
+ ccsip_event_data_t *eventData,
+ subscriptionState subState);
+
+cc_rcs_t sub_int_notify_ack(sub_id_t sub_id, uint16_t response_code,
+ uint32_t cseq);
+
+cc_rcs_t sub_int_subscribe_term(sub_id_t sub_id, boolean immediate,
+ int request_id,
+ cc_subscriptions_t event_package);
+
+cc_rcs_t sip_send_message(ccsip_sub_not_data_t *msg_data,
+ cc_srcs_t dest_task, int msg_id);
+
+cc_rcs_t app_send_message(void *msg_data, int msg_len, cc_srcs_t dest_id,
+ int msg_id);
+extern cc_rcs_t
+sub_send_msg (cprBuffer_t buf, uint32_t cmd, uint16_t len, cc_srcs_t dst_id);
+
+#endif
diff --git a/libs/sipcc/core/includes/task.h b/libs/sipcc/core/includes/task.h
new file mode 100755
index 0000000000..6cbc937603
--- /dev/null
+++ b/libs/sipcc/core/includes/task.h
@@ -0,0 +1,28 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef TASK_H
+#define TASK_H
+
+/*
+ *--------------------DEPRECATED FILE-------------------------------
+ *
+ * As part of Skittles project this file is deprecated.
+ * DO NOT add anything to this file.
+ * The contents of this file are really platform specific and
+ * have moved to phntask.h under
+ * src-bcm-tnp/h/phntask.h for CNU phones.
+ * src-arm-79xx/phntask.h for IRX phones.
+ *
+ * If you are doing SYNC merges _DO_ _NOT_ merge anything from parent
+ * This file is kept here because it comes from parent/grand parent branches
+ * and will not be removed from clearcase till Skittles collapses.
+ * [The fAQ on cc tools contains details of why ]
+ *
+ * If you have questions send email to skittles-dev
+ *---------------------------------------------------------------
+ */
+#define SIP_TMR 0xffff //TODO CPR a temporary bogus number
+
+#endif /* TASK_H */
diff --git a/libs/sipcc/core/includes/time2.h b/libs/sipcc/core/includes/time2.h
new file mode 100644
index 0000000000..cc02ce7dbe
--- /dev/null
+++ b/libs/sipcc/core/includes/time2.h
@@ -0,0 +1,192 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef TIME2_H
+#define TIME2_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+// System specific includes
+
+// End system specific
+
+#define EPOCH_YEAR (1900)
+#define EPOCH_SECONDS (0x80000000)
+#define DAYS_PER_LEAP_YEAR (366)
+#define DAYS_PER_YEAR (365)
+#define DAYS_PER_WEEK (7)
+#define LEAP_FOUR_CENTURY (400)
+#define LEAP_CENTURY (100)
+#define LEAP_YEAR (4)
+// Calculated with 365.2425 days/year for the Gregorian calendar
+#define SECONDS_PER_GREGORIAN_YEAR (31556952)
+#define SECONDS_PER_YEAR (31536000)
+#define SECONDS_PER_LEAP_YEAR (31622400)
+#define SECONDS_PER_DAY (86400)
+#define SECONDS_PER_HOUR (3600)
+#define SECONDS_PER_MINUTE (60)
+#define MINUTES_PER_HOUR (60)
+#define HOURS_PER_DAY (24)
+#define MAX_WEEKS_PER_MONTH (6)
+#define MONTHS_PER_YEAR (12)
+
+#define STARTING_TIME (101 * SECONDS_PER_GREGORIAN_YEAR)
+
+//If 30 minutes have elapsed, clear time display
+#define SNTP_MAX_TIME_SINCE_UPDATE 30*60
+
+typedef enum {
+ SUNDAY = 0, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY
+} DAYS_NAMES_TO_NUMBER;
+
+typedef enum {
+ JANUARY = 0,
+ FEBRUARY,
+ MARCH,
+ APRIL,
+ MAY,
+ JUNE,
+ JULY,
+ AUGUST,
+ SEPTEMBER,
+ OCTOBER,
+ NOVEMBER,
+ DECEMBER
+} MONTH_NAMES_TO_NUMBER;
+
+typedef struct {
+ time_t time;
+ unsigned short millitm;
+ short timezone;
+ short dstflag;
+} timeb;
+
+typedef struct {
+ // Standard Gregorian calendar date
+ unsigned long year; // Range >= EPOCH_YEAR
+ unsigned long month; // Range 0-11, use MONTH_NAME_x for text
+ unsigned long day; // Range 1-31
+
+ // Standard 24 hour time format
+ unsigned long hour; // Range 0-23
+ unsigned long minute; // Range 0-59
+ unsigned long seconds; // Range 0-59
+
+ // Specifics about a year and the current date
+ unsigned long day_of_year; // Range 0-365
+ unsigned long day_of_january_first; // Range 0-6, use DAY_NAME_x for text
+ unsigned long day_of_week; // Range 0-6, use DAY_NAME_x for text
+ unsigned long week_of_year; // Range 1-53
+
+ // Variables that are associated with leap years and calculations
+ unsigned long leap_years; // Non negative integer
+ unsigned long leap_flag; // Range 0-1, boolean
+
+ // Time zone specifics set by user
+ long time_zone; // Timezone offset in seconds
+ unsigned long daylight_saving_offset; // Number of seconds to add (adjust) when DST starts
+ // e.g. daylight_saving_offset = 3600; // 1 hour
+ // when DST starts the code will add 1 hour to the GMT time and
+ // when DST stops it will stop adding 1 hour
+ unsigned long daylight_saving_start_month; // Range 0-11, use MONTH_NAME_x for text
+ unsigned long daylight_saving_start_day; // Range 1-31, if set to 0, only then will week of month is used
+ unsigned long daylight_saving_start_day_of_week; // Range 0-6, use DAY_NAME_x for text
+ unsigned long daylight_saving_start_week_of_month;// Range 0-6, First, second, etc. DAY_NAME of the month, zero denotes last week in month, e.g. day_of_week = 0, week_of_month = 1 => First Sunday of month
+ unsigned long daylight_saving_start_time; // Range 0-86399, number of seconds past midnight
+ unsigned long daylight_saving_stop_month; // Range 0-11, use MONTH_NAME_x for text
+ unsigned long daylight_saving_stop_day; // Range 1-31, if set to 0, only then will week of month is used
+ unsigned long daylight_saving_stop_day_of_week; // Range 0-6, use DAY_NAME_x for text
+ unsigned long daylight_saving_stop_week_of_month; // Range 0-6, First, second, etc. DAY_NAME of the month, zero denotes last week in month, e.g. day_of_week = 0, week_of_month = 1 => First Sunday of month
+ unsigned long daylight_saving_stop_time; // Range 0-86399, number of seconds past midnight
+ unsigned long daylight_saving_year_calc; // Non negative integer, non 0 means daylight saving start and stop second is calculated for given year
+ unsigned long daylight_saving_auto_adjust; // Range 0-1, boolean
+
+ // Time zone specifics set by make_date
+ unsigned long is_daylight_saving; // Range 0-1, boolean
+ unsigned long daylight_saving_start_second; // Second in the year that daylight saving starts
+ unsigned long daylight_saving_stop_second; // Second in the year that daylight saving stops
+} time2_s;
+
+typedef struct {
+ const char *TZ_NAME;
+ const long offset;
+} TZ_STRUCT;
+
+// Time date externs
+extern const char *const MONTH_NAMES_LONG[];
+extern const char *const MONTH_NAMES_SHORT[];
+extern const unsigned long DAYS_IN_MONTH[];
+extern const char *const DAY_NAMES_LONG[];
+extern const char *const DAY_NAMES_SHORT[];
+extern const char *const DAY_NAMES_ABBREV[];
+extern const TZ_STRUCT TZ_TABLE[];
+
+long make_date(unsigned long secondsPastEpoch, time2_s *timeStruct);
+const char *get_month_name_long(unsigned long month);
+const char *get_month_name_short(unsigned long month);
+const char *get_day_name_long(unsigned long day);
+const char *get_day_name_short(unsigned long day);
+const char *get_day_name_abrrev(unsigned long day);
+long get_leap_years(unsigned long year);
+unsigned long get_seconds_past_epoch(unsigned long nth, unsigned long day_name, unsigned long month, unsigned long year);
+long is_leap_year(unsigned long year);
+long range_check_time_struct(time2_s *ts);
+unsigned long date_to_seconds(const time2_s *ts);
+unsigned long time_to_seconds(const time2_s *ts);
+unsigned long date_time_to_seconds(const time2_s *ts);
+unsigned long get_local_time(void);
+void get_precise_local_time(unsigned long *local_time);
+long get_local_timezone(void);
+long get_local_dst_active(void);
+unsigned long time_to_short_string(const time2_s *ts, char *time_string);
+unsigned long gmt_string_to_seconds(char *gmt_string, unsigned long *seconds);
+unsigned long seconds_to_gmt_string(unsigned long seconds, char *gmt_string);
+unsigned long diff_time(unsigned long t1, unsigned long t2);
+
+// This function is similar to the strcmp function in the string.h library
+// It includes support for handling the NTP most significant bit rollover
+// If t1 < t2 cmp_time returns -1
+// If t1 == t2 cmp_time returns 0
+// If t1 > t2 cmp_time returns 1
+long cmp_time(unsigned long t1, unsigned long t2);
+
+long diff_current_time(unsigned long t1, unsigned long *difference);
+long parse_month(char *pString);
+long parse_day_of_week(char *pString);
+long parse_timezone(char *pString);
+long parse_time(char *pString);
+
+/*
+ * Formats ulMilliseconds into elasped time in the form of
+ * HRS:MIN:SEC for less than 24 hours and then
+ * DAY(S) HRS:MIN:SEC for greater than 24 hours
+*/
+void ascTimeDuration(unsigned long ulMilliseconds, char *ptimStr, int length);
+void ascFormatDate(time2_s *ts, char * pDateStr, int length);
+void ascFormatHrMinTime(time2_s *ts, char * pTimeStr, int length, char bFlashColon);
+void FormatDateTime(char * ptimeStr, int length);
+void FormatDebugTime(char *timeStr, int length,long ts);
+char *GetDateTimeString(void);
+
+// Called once a second to update the time. Returns true indicating
+// a roll-over indicating the display needs updated.
+// Once a minute we need to update the time/date display and
+// update the minute/hour/day etc.
+//
+int TimeOfDayUpdate(void);
+
+// Set the time of day clock
+void SetTimeOfDay(time2_s *time);
+
+// Blank "turn off" the display of time
+// called when there is a change to
+// the time keeping systems on the phone
+void ClearTimeDisplay(void);
+
+#endif
diff --git a/libs/sipcc/core/includes/timer.h b/libs/sipcc/core/includes/timer.h
new file mode 100755
index 0000000000..eb02e9e63f
--- /dev/null
+++ b/libs/sipcc/core/includes/timer.h
@@ -0,0 +1,49 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef MGCP_TIMER_H
+#define MGCP_TIMER_H
+
+#define TIMER_FREE 0x1 /* Indicates timer is free */
+#define TIMER_INITIALIZED 0x2 /* Indicates timer is initialized */
+#define TIMER_ACTIVE 0x4 /* Indicates timer is in list */
+
+/* Timer event structure */
+typedef struct timer_struct
+{
+ unsigned int expiration_time; /* Expiration time */
+ int interval; /* Timer period */
+ void *parameter1; /* Timer expiration callback param */
+ void *parameter2; /* Second timer expiration callback param */
+ void (*expiration_callback)
+ (void *timer, void *parameter1, void *parameter2); /* Expiry handler */
+ int flags; /* Debugging flags */
+ struct timer_struct *pred; /* List predecessor */
+ struct timer_struct *next; /* List successor */
+} timer_struct_type;
+
+extern unsigned long current_time(void);
+extern void timer_event_activate(timer_struct_type *timer);
+extern void *timer_event_allocate(void);
+extern void timer_event_cancel(timer_struct_type *timer);
+extern void timer_event_free(timer_struct_type *timer);
+extern void timer_event_initialize(timer_struct_type *timer,
+ int period,
+ void (*expiration)(void *timer_event,
+ void *param1,
+ void *param2),
+ void *param1, void *param2);
+extern void timer_event_process(void);
+extern void timer_event_system_init(void);
+extern boolean timer_expired(void);
+extern void platform_timer_tick(void);
+extern void platform_timer_init(void);
+
+#ifdef _WIN32
+extern void platform_timer_stop(void);
+#endif
+extern int timer_ms_to_ticks(int milliseconds);
+extern boolean is_timer_active(timer_struct_type *timer);
+
+#endif
diff --git a/libs/sipcc/core/includes/tnpphone.h b/libs/sipcc/core/includes/tnpphone.h
new file mode 100644
index 0000000000..80d4d62ac0
--- /dev/null
+++ b/libs/sipcc/core/includes/tnpphone.h
@@ -0,0 +1,65 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef TNPPHONE_H
+#define TNPPHONE_H
+
+#include "phone.h"
+
+
+#ifdef SIP_OS_WINDOWS
+
+
+#ifndef MAX_FILE_NAME
+#define MAX_FILE_NAME 256
+#endif
+
+/* Defined in net_config.h */
+typedef struct
+{
+ uint8_t fName[MAX_FILE_NAME]; // Name of file being transfered
+ uint32_t rcvLen;
+ uint32_t maxSize; // The maximum size of the file to be read
+ uint8_t *fDest; // The destination address for transfer
+ uint32_t fHost; // Foreign IP address
+ uint16_t rtCode;
+ uint8_t taskId;
+ irx_lst_blk *pTaskList;
+} TftpOpen; // TFTP Request
+
+#define CFG_PROGRAMMED 0x12300000L
+#define CFG_PROGRAM_TFTP 0x12200000L
+#define CFG_DHCP_DISABLE 0x00000001L
+#define CFG_DHCP_TIMEOUT 0x00000002L
+#define CFG_TFTP_TIMEOUT 0x00000004L
+#define CFG_TFTP_NTFOUND 0x00000008L
+#define CFG_TFTP_ACCESS 0x00000010L
+#define CFG_TFTP_ERR 0x00000020L
+#define CFG_DNS_ERROR 0x00000040L
+#define CFG_DNS_TIMEOUT 0x00000080L
+#define CFG_DNS_IP 0x00000100L
+#define CFG_VER_ERR 0x00000200L
+#define CFG_CKSUM_ERR 0x00000400L
+//#define CFG_TFTP_FILE 0x00000800L
+#define CFG_DFLT_GWY 0x00001000L
+#define CFG_DUP_IP 0x00002000L
+#define CFG_PATCHED 0x00004000L
+#define CFG_LINK_DOWN 0x00008000L
+#define CFG_FIXED_TFTP 0x00010000L
+#define CFG_PROG_ERR 0x00020000L
+#define CFG_BOOTP 0x00040000L
+#define CFG_DHCP_RELEASE 0x00080000L
+
+
+#ifndef ERROR
+#define ERROR (-1)
+#endif
+
+#ifndef PHONE_TICK_TO
+#define PHONE_TICK_TO 10
+#endif
+
+
+#endif
+#endif
diff --git a/libs/sipcc/core/includes/uart.h b/libs/sipcc/core/includes/uart.h
new file mode 100755
index 0000000000..30596cf4ea
--- /dev/null
+++ b/libs/sipcc/core/includes/uart.h
@@ -0,0 +1,119 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _UART_H_
+#define _UART_H_
+
+#include "cpr_types.h"
+
+
+/*
+ * Telecaster specific defines
+ */
+#define SYSCLOCK ((unsigned long)25000000) /* 25 MHZ */
+#define UART_BASE_ADDRESS (UART_16550_REGS *)0xFFFE4000
+
+/*
+ * 16550 register definition
+ */
+typedef struct {
+ volatile uint8_t dc; /* RBR/THR */
+ volatile uint8_t ier; /* Interrupt Enable Reg */
+ volatile uint8_t iir; /* Interrupt ID Reg */
+ volatile uint8_t lcr; /* Line Control Reg / FIFO Control Reg */
+ volatile uint8_t mcr; /* Modem Control Register */
+ volatile uint8_t lsr; /* Line Status Register */
+ volatile uint8_t msr; /* Modem Status Register */
+ volatile uint8_t scr; /* Scratch Register */
+} UART_16550_REGS;
+
+/*
+ * UART register bit symbols
+ */
+#define UART_IER_MASK 0xF0
+#define IER_RX_IE 0x01
+#define IER_TX_IE 0x02
+#define IER_LS_IE 0x04
+#define IER_MS_IE 0x08
+
+#define UART_IIR_RV 0x01
+#define IIR_IPEND 0x01
+#define IIR_MODEM_STAT 0x00
+#define IIR_TX_EMPTY 0x02
+#define IIR_RX_AVAIL 0x04
+#define IIR_RX_LINE_STAT 0x06
+#define IIR_CHAR_TIMOUT 0x0C
+
+#define UART_FCR_MASK 0x30
+#define FCR_FIFO_EN 0x01
+#define FCR_CLR_RXF 0x02
+#define FCR_CLR_TXF 0x04
+#define FCR_TRIGR_1BYT 0x00
+#define FCR_TRIGR_4BYT 0x40
+#define FCR_TRIGR_8BYT 0x80
+#define FCR_TRIGR_14BYT 0xC0
+
+#define LCR_CHR_LEN_5BIT 0x00
+#define LCR_CHR_LEN_6BIT 0x01
+#define LCR_CHR_LEN_7BIT 0x02
+#define LCR_CHR_LEN_8BIT 0x03
+#define LCR_STOP1 0x00
+#define LCR_STOP2 0x04
+#define LCR_PAR_EN 0x08
+#define LCR_PAR_ODD 0x10
+#define LCR_FIX_PAR 0x20
+#define LCR_BRK_CTL 0x40
+#define LCR_DLAB 0x80
+
+#define MCR_DTR 0x01
+#define MCR_RTS 0x02
+#define MCR_OUT1 0x04
+#define MCR_OUT2 0x08
+#define MCR_LPBK 0x10
+#define MCR_AUTO_FLW_EN 0x20
+
+#define UART_LSR_RV 0x60
+#define LSR_RX_AVAIL 0x01
+#define LSR_OVRUN 0x02
+#define LSR_PAR_ERR 0x04
+#define LSR_FRAM_ERR 0x08
+#define LSR_BRK_INT 0x10
+#define LSR_TX_EMPTY 0x20
+#define LSR_XMITR_EMPTY 0x40
+#define LSR_RX_FIFO_ERR 0x80
+
+#define UART_MSR_RV 0x00
+#define MSR_CTS_CHG 0x01
+#define MSR_DSR_CHG 0x02
+#define MSR_TERI 0x04
+#define MSR_CD_CHG 0x08
+#define MSR_CTS_IN 0x10
+#define MSR_DSR_IN 0x20
+#define MSR_RI_IN 0x40
+#define MSR_CD_IN 0x80
+
+
+#define DATAREADY 0x01
+#define XMITFIFOEMPTY 0x20
+
+
+#define RXLINESTATUS (3<<1)
+#define RXDATAAVAIL (2<<1)
+#define CHARTIMEOUT (6<<1)
+#define TXEMPTY (1<<1)
+#define MODEMSTATUS (0<<1)
+#define RXERRORS 0x8E
+#define DATAREADY 0x01
+#define XMITFIFOEMPTY 0x20
+
+
+#define TX_EMPTY 0x01
+
+//extern int uart_init(int speed, char *buf, int buf_size);
+extern int32_t uart_init();
+extern void uart_flush(int32_t dev);
+extern int32_t uart_outc(int8_t c, void *);
+extern int32_t uart_outs(int8_t *s, void *);
+
+#endif
diff --git a/libs/sipcc/core/includes/uiapi.h b/libs/sipcc/core/includes/uiapi.h
new file mode 100644
index 0000000000..6604264eb1
--- /dev/null
+++ b/libs/sipcc/core/includes/uiapi.h
@@ -0,0 +1,164 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _UIAPI_H_
+#define _UIAPI_H_
+
+#include "cpr_types.h"
+#include "phone_types.h"
+#include "string_lib.h"
+#include "vcm.h"
+#include "ccapi.h"
+
+#include "sessionConstants.h"
+typedef enum {
+ evMinEvent = 0,
+ evOffHook = OFFHOOK,
+ evOnHook = ONHOOK,
+ evRingOut = RINGOUT,
+ evRingIn = RINGIN,
+ evProceed = PROCEED,
+ evConnected = CONNECTED,
+ evHold = HOLD,
+ evRemHold = REMHOLD,
+ evResume = RESUME,
+ evBusy = BUSY,
+ evReorder = REORDER,
+ evConference = CONFERENCE,
+ evRemInUse = REMINUSE,
+ evCallPreservation = PRESERVATION,
+ evHoldRevert = HOLDREVERT,
+ evWhisper = WHISPER,
+ evWaitingForDigits = WAITINGFORDIGITS,
+ evCreateOffer = CREATEOFFER,
+ evCreateAnswer = CREATEANSWER,
+ evCreateOfferError = CREATEOFFERERROR,
+ evCreateAnswerError = CREATEANSWERERROR,
+ evSetLocalDesc = SETLOCALDESC,
+ evSetRemoteDesc = SETREMOTEDESC,
+ evSetLocalDescError = SETLOCALDESCERROR,
+ evSetRemoteDescError = SETREMOTEDESCERROR,
+ evOnRemoteStreamAdd = REMOTESTREAMADD,
+ evMaxEvent
+} call_events;
+
+#define MWI_STATUS_YES 1
+
+/* call operations : dialing, state change and info related */
+void ui_new_call(call_events event, line_t nLine, callid_t nCallID,
+ int call_attr, uint16_t call_instance_id, boolean dialed_digits);
+void ui_set_call_attr(line_t line_id, callid_t call_id, call_attr_t attr);
+void ui_call_info(string_t clgName, string_t clgNumber, string_t altClgNumber, boolean dispClgNumber,
+ string_t cldName, string_t cldNumber, boolean dispCldNumber,
+ string_t pOrigCalledNameStr, string_t pOrigCalledNumberStr,
+ string_t pLastRedirectingNameStr,
+ string_t pLastRedirectingNumberStr,
+ calltype_t call_type,
+ line_t line, callid_t call_id, uint16_t call_instance_id,
+ cc_security_e call_security, cc_policy_e call_policy);
+void ui_cc_capability(line_t line_id, callid_t call_id,
+ string_t recv_info_list);
+void ui_info_received(line_t line_id, callid_t call_id,
+ const char *info_package, const char *content_type,
+ const char *message_body);
+void ui_update_placed_call_info(line_t line, callid_t call_id, string_t cldName,
+ string_t cldNumber);
+void ui_log_disposition( callid_t nCallID, int logDisp);
+void ui_call_state(call_events event, line_t nLine, callid_t nCallID, cc_causes_t cause);
+void ui_set_local_hold(line_t line, callid_t call_id);
+void ui_delete_last_digit(line_t line_id, callid_t call_id);
+void ui_update_label_n_speeddial(line_t line, line_t button_no, string_t
+ speed_dial, string_t label);
+void ui_mnc_reached(line_t line, boolean mnc_reached);
+
+void ui_call_selected(line_t line_id, callid_t call_id, int selected);
+void ui_call_in_preservation(line_t line_id, callid_t call_id);
+void ui_update_call_security(line_t line, callid_t call_id,
+ cc_security_e call_security);
+void ui_update_conf_invoked(line_t line, callid_t call_id,
+ boolean invoked);
+void ui_terminate_feature(line_t line, callid_t call_id,
+ callid_t target_call_id);
+
+void ui_update_gcid(line_t line, callid_t call_id, char *gcid);
+void ui_update_callref(line_t line, callid_t call_id, unsigned int callref);
+
+/* status line related */
+void ui_set_call_status(string_t pString, line_t line, callid_t callID);
+char *ui_get_idle_prompt_string(void);
+void ui_set_idle_prompt_string(string_t pString, int prompt);
+void ui_set_notification(line_t line, callid_t callID,
+ char *promptString, int timeout,
+ boolean notifyProgress, char priority);
+void ui_clear_notification();
+
+/* softkey manipulation */
+void ui_control_feature(line_t line_id, callid_t call_id, int list[], int len, int enable);
+void ui_select_feature_key_set(line_t line_id, callid_t call_id, char *set_name,
+ int sk_list[], int len);
+void ui_control_featurekey_bksp(line_t line_id, callid_t call_id,
+ boolean enable);
+
+/* speaker */
+void ui_set_speaker_mode(boolean mode);
+
+/* mwi */
+void ui_set_mwi(line_t line, boolean status, int type, int newCount, int oldCount, int hpNewCount, int hpOldCount);
+void ui_change_mwi_lamp(int status);
+boolean ui_line_has_mwi_active(line_t line);
+
+/* call forward */
+void ui_cfwd_status(line_t line, boolean cfa, char *cfa_number,
+ boolean lcl_fwd);
+
+/* registration, stack init related */
+void ui_sip_config_done(void);
+void ui_set_sip_registration_state(line_t line, boolean registered);
+void ui_reg_all_failed(void);
+
+void ui_keypad_button(char *digitstr, int direction);
+
+void ui_offhook(line_t line, callid_t call_id);
+void ui_dial_call(line_t line, callid_t call_id, char *to,
+ char *global_call_id);
+int ui_dial_digits(line_t line, char *digitstr);
+int ui_dial_dtmf(line_t line, char *digitstr);
+void ui_answer_call(line_t line, callid_t call_id);
+void ui_disconnect_call(line_t line, callid_t call_id);
+int ui_xfer_setup(line_t line, callid_t call_id, char *to,
+ char *global_call_id, boolean media);
+void ui_xfer_complete(line_t line, callid_t call_id, callid_t consult_call_id);
+int ui_conf_setup(line_t line, callid_t call_id, char *to,
+ char *global_call_id);
+void ui_conf_complete(line_t line, callid_t call_id, callid_t consult_call_id);
+int ui_hold_call(line_t line, callid_t call_id);
+void ui_hold_retrieve_call(line_t line, callid_t call_id);
+void ui_cfwdall_req(unsigned int line);
+
+/* Test Interface */
+void ui_execute_uri(char *);
+
+/* Status Message Interface */
+void ui_log_status_msg(char *msg);
+
+void ui_init_ccm_conn_status(void);
+void ui_update_video_avail (line_t line, callid_t call_id, int avail);
+void ui_update_video_offered (line_t line, callid_t call_id, int dir);
+void ui_call_stop_ringer(line_t line, callid_t call_id);
+void ui_call_start_ringer(vcm_ring_mode_t ringMode, short once, line_t line, callid_t call_id);
+void ui_BLF_notification (int request_id, cc_blf_state_t blf_state, int app_id);
+void ui_update_media_interface_change(line_t line, callid_t call_id, group_call_event_t event);
+void ui_create_offer(call_events event, line_t nLine, callid_t nCallID,
+ uint16_t call_instance_id, char* sdp);
+void ui_create_answer(call_events event, line_t nLine, callid_t nCallID,
+ uint16_t call_instance_id, char* sdp);
+void ui_set_local_description(call_events event, line_t nLine, callid_t nCallID,
+ uint16_t call_instance_id, char* sdp, cc_int32_t status);
+void ui_set_remote_description(call_events event, line_t nLine, callid_t nCallID,
+ uint16_t call_instance_id, char* sdp, cc_int32_t status);
+void ui_on_remote_stream_added(call_events event, line_t nLine, callid_t nCallID,
+ uint16_t call_instance_id, cc_media_remote_track_table_t media_tracks);
+
+
+#endif
diff --git a/libs/sipcc/core/includes/upgrade.h b/libs/sipcc/core/includes/upgrade.h
new file mode 100644
index 0000000000..96f2bd987e
--- /dev/null
+++ b/libs/sipcc/core/includes/upgrade.h
@@ -0,0 +1,37 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _UPGRADE_INCLUDED_H
+#define _UPGRADE_INCLUDED_H
+
+#include "cpr_types.h"
+#include "phone.h"
+
+/*
+ * Telecaster has these extra 32 bytes of data
+ * in front of the load header. I have no idea what
+ * they are for, but having a structure makes it easier
+ * to deal with this as opposed to adding 0x20 to the
+ * address.
+ */
+typedef struct
+{
+ uint8_t vectors[0x20];
+ LoadHdr hdr;
+} BigLoadHdr;
+
+/*
+ * Prototypes for public functions
+ */
+void upgrade_bootup_init(void);
+int upgrade_done(int tftp_rc);
+void upgrade_start(const char *fname);
+void upgrade_memcpy(void *dst, const void *src, int len);
+int upgrade_check(const char *loadid);
+int upgrade_validate_app_image(const BigLoadHdr *load);
+int upgrade_validate_dsp_image(const DSPLoadHdr *dsp);
+void upgrade_erase_dir_storage(void);
+void upgrade_write_dir_storage(char *buffer, char *flash, int size);
+
+#endif /* _UPGRADE_INCLUDED_H */
diff --git a/libs/sipcc/core/includes/util_ios_queue.h b/libs/sipcc/core/includes/util_ios_queue.h
new file mode 100644
index 0000000000..98ad646c73
--- /dev/null
+++ b/libs/sipcc/core/includes/util_ios_queue.h
@@ -0,0 +1,59 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _UTIL_IOS_QUEUE_H
+#define _UTIL_IOS_QUEUE_H
+
+/*
+ * Define the queue data type and a basic enqueue structure
+ */
+
+typedef struct queuetype_ {
+ void *qhead; /* head of queue */
+ void *qtail; /* tail of queue */
+ int count; /* possible count */
+ int maximum; /* maximum entries */
+} queuetype;
+
+typedef queuetype *queue_ptr_t;
+
+typedef struct nexthelper_
+{
+ struct nexthelper_ *next;
+ unsigned char data[4];
+} queue_node, nexthelper, *node_ptr_t;
+
+typedef enum get_node_status_ {
+ GET_NODE_FAIL_EMPTY_LIST,
+ GET_NODE_FAIL_END_OF_LIST,
+ GET_NODE_SUCCESS
+} get_node_status;
+
+void queue_init(queuetype *q, int maximum);
+void *peekqueuehead(queuetype* q);
+
+/*Functions used by SIP */
+int queryqueuedepth(queuetype const *q);
+boolean checkqueue(queuetype *q, void *e);
+void *p_dequeue(queuetype *qptr);
+void p_enqueue(queuetype *qptr, void *eaddr);
+void p_requeue(queuetype *qptr, void *eaddr);
+void p_swapqueue(queuetype *qptr, void *enew, void *eold);
+void p_unqueue(queuetype *q, void *e);
+void p_unqueuenext(queuetype *q, void **prev);
+void enqueue(queuetype *qptr, void *eaddr);
+void *dequeue(queuetype *qptr);
+void unqueue(queuetype *q, void *e);
+void requeue(queuetype *qptr, void *eaddr);
+void *remqueue(queuetype *qptr, void *eaddr, void *paddr);
+void insqueue(queuetype *qptr, void *eaddr, void *paddr);
+boolean queueBLOCK(queuetype *qptr);
+boolean validqueue(queuetype *qptr, boolean print_message);
+
+boolean queue_create_init(queue_ptr_t *queue);
+void add_list(queue_ptr_t queue, node_ptr_t node);
+get_node_status get_node(queue_ptr_t queue, node_ptr_t *node);
+void queue_delete(queue_ptr_t queue);
+
+#endif
diff --git a/libs/sipcc/core/includes/util_parse.h b/libs/sipcc/core/includes/util_parse.h
new file mode 100644
index 0000000000..e3341124a2
--- /dev/null
+++ b/libs/sipcc/core/includes/util_parse.h
@@ -0,0 +1,12 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _UTIL_PARSE_H_
+#define _UTIL_PARSE_H_
+
+#include "xml_defs.h"
+
+XMLToken parse_xml_tokens(char **parseptr, char *value, int maxlen);
+
+#endif
diff --git a/libs/sipcc/core/includes/util_string.h b/libs/sipcc/core/includes/util_string.h
new file mode 100644
index 0000000000..04a53d9ecc
--- /dev/null
+++ b/libs/sipcc/core/includes/util_string.h
@@ -0,0 +1,28 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _UTIL_STRING_H_
+#define _UTIL_STRING_H_
+
+#include "cpr_types.h"
+#include "cpr_socket.h"
+
+#define EMPTY_STR ""
+#define EMPTY_STR_LEN 1
+
+boolean is_empty_str(char *str);
+void init_empty_str(char *str);
+
+void ipaddr2dotted(char *addr_str, cpr_ip_addr_t *addr);
+uint32_t dotted2ipaddr(const char *addr_str);
+int str2ip(const char *str, cpr_ip_addr_t *addr);
+void util_ntohl(cpr_ip_addr_t *ip_addr_out, cpr_ip_addr_t *ip_addr_in);
+boolean util_compare_ip(cpr_ip_addr_t *ip_add1, cpr_ip_addr_t *ip_addr2);
+void util_extract_ip(cpr_ip_addr_t *ip_addr, cpr_sockaddr_storage *from);
+uint16_t util_get_port(cpr_sockaddr_storage *sock_storage);
+void util_get_ip_using_mode(cpr_ip_addr_t *ip_addr, cpr_ip_mode_e ip_mode,
+ uint32_t ip4, char *ip6);
+boolean util_check_if_ip_valid(cpr_ip_addr_t *ip_addr);
+
+#endif
diff --git a/libs/sipcc/core/includes/www.h b/libs/sipcc/core/includes/www.h
new file mode 100644
index 0000000000..e5c40b01ea
--- /dev/null
+++ b/libs/sipcc/core/includes/www.h
@@ -0,0 +1,25 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _WWW_H_
+#define _WWW_H_
+
+#define MAXCHARSPERLINE 400
+
+typedef struct {
+ int soc;
+ unsigned char buf[MAXCHARSPERLINE];
+ unsigned char text[MAXCHARSPERLINE];
+ int idx, n, clen, send;
+} WWWRBuf;
+
+extern int Connect2WWW(char *hostName);
+extern int Connect2WWWIPPort(unsigned long nIPAddr, unsigned short nPort,
+ char *hostName);
+extern void wwwSend(WWWRBuf *wrb, char *fmt, ...);
+extern boolean www_proxy_used(int connection);
+extern boolean www_socket_open(int connection);
+extern void HTTP_Init_ConnTbl();
+
+#endif
diff --git a/libs/sipcc/core/includes/xml_defs.h b/libs/sipcc/core/includes/xml_defs.h
new file mode 100644
index 0000000000..b91558f30a
--- /dev/null
+++ b/libs/sipcc/core/includes/xml_defs.h
@@ -0,0 +1,51 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _XML_DEFS_H_
+#define _XML_DEFS_H_
+
+#include "cpr_types.h"
+
+#define TOK_MAX_LEN (24)
+
+#define TOK_NONE (0)
+#define TOK_PROC (1)
+#define TOK_ELEMENT (2)
+#define TOK_ATTRIBUTE (3)
+#define TOK_CONTENT (4)
+
+#define XML_START (1199)
+#define XML_END (1200)
+#define XML_CONTENT (1201)
+#define XML_ALL_CONTENT (1202)
+
+typedef struct XMLTokenStruc {
+ const int8_t strTok[TOK_MAX_LEN];
+ int16_t TokType;
+ void *pData; // This may be another XMLTable,
+ // or an array of valid attribute values.
+} XMLTokenStruc;
+
+typedef void (*XmlFunc)(int16_t, void *);
+
+typedef struct XMLTableStruc {
+ void (*xml_func)( int16_t TokID, void *pData );
+ uint8_t nNumTok;
+ const XMLTokenStruc *pTok;
+} XMLTableStruc;
+
+typedef enum {
+ TOK_ERR,
+ TOK_EOF, /* reached end of the input */
+ TOK_LBRACKET, /* "<" */
+ TOK_ENDLBRACKET, /* "" */
+ TOK_EMPTYBRACKET, /* "/>" */
+ TOK_RBRACKET, /* ">" */
+ TOK_EQ, /* "=" */
+ TOK_STR, /* string on the rhs of = */
+ TOK_KEYWORD, /* string on lhs of = */
+ TOK_CONTENT_STR
+} XMLToken;
+
+#endif
diff --git a/libs/sipcc/core/sdp/ccsdp.c b/libs/sipcc/core/sdp/ccsdp.c
new file mode 100644
index 0000000000..585a9549cd
--- /dev/null
+++ b/libs/sipcc/core/sdp/ccsdp.c
@@ -0,0 +1,326 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "sdp.h"
+#include "ccapi.h"
+
+
+const char* ccsdpAttrGetFmtpParamSets(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+ cc_sdp_t *sdpp = sdp_ptr;
+
+ if ( sdpp->dest_sdp == NULL ) {
+ return NULL;
+ }
+ return sdp_attr_get_fmtp_param_sets(sdpp->dest_sdp, level, cap_num, inst_num);
+}
+
+sdp_result_e ccsdpAttrGetFmtpPackMode(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u16 *val)
+{
+ cc_sdp_t *sdpp = sdp_ptr;
+
+ if ( sdpp->dest_sdp == NULL ) {
+ return SDP_INVALID_PARAMETER;
+ }
+ return sdp_attr_get_fmtp_pack_mode(sdpp->dest_sdp, level, cap_num, inst_num, val);
+}
+
+sdp_result_e ccsdpAttrGetFmtpLevelAsymmetryAllowed(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u16 *val)
+{
+ cc_sdp_t *sdpp = sdp_ptr;
+
+ if ( sdpp->dest_sdp == NULL ) {
+ return SDP_INVALID_PARAMETER;
+ }
+ return sdp_attr_get_fmtp_level_asymmetry_allowed(sdpp->dest_sdp, level, cap_num, inst_num, val);
+}
+
+const char* ccsdpAttrGetFmtpProfileLevelId (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+ cc_sdp_t *sdpp = sdp_ptr;
+
+ if ( sdpp->dest_sdp == NULL ) {
+ return NULL;
+ }
+ return sdp_attr_get_fmtp_profile_id(sdpp->dest_sdp, level, cap_num, inst_num);
+}
+
+
+
+sdp_result_e ccsdpAttrGetFmtpMaxMbps (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u32 *val)
+{
+ cc_sdp_t *sdpp = sdp_ptr;
+
+ if ( sdpp->dest_sdp == NULL ) {
+ return SDP_INVALID_PARAMETER;
+ }
+ return sdp_attr_get_fmtp_max_mbps(sdpp->dest_sdp, level, cap_num, inst_num, val);
+}
+
+sdp_result_e ccsdpAttrGetFmtpMaxFs (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u32 *val)
+{
+ cc_sdp_t *sdpp = sdp_ptr;
+
+ if ( sdpp->dest_sdp == NULL ) {
+ return SDP_INVALID_PARAMETER;
+ }
+ return sdp_attr_get_fmtp_max_fs(sdpp->dest_sdp, level, cap_num, inst_num, val);
+}
+
+sdp_result_e ccsdpAttrGetFmtpMaxCpb (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u32 *val)
+{
+ cc_sdp_t *sdpp = sdp_ptr;
+
+ if ( sdpp->dest_sdp == NULL ) {
+ return SDP_INVALID_PARAMETER;
+ }
+ return sdp_attr_get_fmtp_max_cpb(sdpp->dest_sdp, level, cap_num, inst_num, val);
+}
+
+sdp_result_e ccsdpAttrGetFmtpMaxBr (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u32* val)
+{
+ cc_sdp_t *sdpp = sdp_ptr;
+
+ if ( sdpp->dest_sdp == NULL ) {
+ return SDP_INVALID_PARAMETER;
+ }
+ return sdp_attr_get_fmtp_max_br(sdpp->dest_sdp, level, cap_num, inst_num, val);
+}
+
+int ccsdpGetBandwidthValue (void *sdp_ptr, u16 level, u16 inst_num)
+
+{
+ cc_sdp_t *sdpp = sdp_ptr;
+
+ if ( sdpp->dest_sdp == NULL ) {
+ return SDP_INVALID_PARAMETER;
+ }
+ return sdp_get_bw_value(sdpp->dest_sdp, level, inst_num);
+}
+
+sdp_result_e ccsdpAttrGetFmtpMaxDpb (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u32 *val)
+{
+ cc_sdp_t *sdpp = sdp_ptr;
+
+ if ( sdpp->dest_sdp == NULL ) {
+ return SDP_INVALID_PARAMETER;
+ }
+ return sdp_attr_get_fmtp_max_dpb(sdpp->dest_sdp, level, cap_num, inst_num, val);
+}
+
+sdp_result_e ccsdpAddNewAttr (void *sdp_ptr, u16 level, u8 cap_num,
+ sdp_attr_e attr_type, u16 *inst_num)
+{
+ cc_sdp_t *sdpp = sdp_ptr;
+
+ if ( sdpp->src_sdp == NULL ) {
+ return SDP_INVALID_PARAMETER;
+ }
+ return sdp_add_new_attr(sdpp->src_sdp, level, cap_num, attr_type, inst_num);
+}
+
+sdp_result_e ccsdpAttrSetFmtpPayloadType (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u16 payload_num)
+{
+ cc_sdp_t *sdpp = sdp_ptr;
+
+ if ( sdpp->src_sdp == NULL ) {
+ return SDP_INVALID_PARAMETER;
+ }
+ return sdp_attr_set_fmtp_payload_type(sdpp->src_sdp, level, cap_num, inst_num, payload_num);
+}
+
+
+sdp_result_e ccsdpAttrSetFmtpPackMode (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u16 pack_mode)
+{
+ cc_sdp_t *sdpp = sdp_ptr;
+
+ if ( sdpp->src_sdp == NULL ) {
+ return SDP_INVALID_PARAMETER;
+ }
+ return sdp_attr_set_fmtp_pack_mode(sdpp->src_sdp, level, cap_num, inst_num, pack_mode);
+}
+
+sdp_result_e ccsdpAttrSetFmtpLevelAsymmetryAllowed (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u16 asym_allowed)
+{
+ cc_sdp_t *sdpp = sdp_ptr;
+
+ if ( sdpp->src_sdp == NULL ) {
+ return SDP_INVALID_PARAMETER;
+ }
+ return sdp_attr_set_fmtp_level_asymmetry_allowed(sdpp->src_sdp, level, cap_num, inst_num, asym_allowed);
+}
+
+
+sdp_result_e ccsdpAttrSetFmtpProfileLevelId (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, const char *profile_level_id)
+{
+ cc_sdp_t *sdpp = sdp_ptr;
+
+ if ( sdpp->src_sdp == NULL ) {
+ return SDP_INVALID_PARAMETER;
+ }
+ return sdp_attr_set_fmtp_profile_level_id(sdpp->src_sdp, level, cap_num, inst_num, profile_level_id);
+}
+
+
+sdp_result_e ccsdpAttrSetFmtpParameterSets (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, const char *parameter_sets)
+{
+ cc_sdp_t *sdpp = sdp_ptr;
+
+ if ( sdpp->src_sdp == NULL ) {
+ return SDP_INVALID_PARAMETER;
+ }
+ return sdp_attr_set_fmtp_parameter_sets(sdpp->src_sdp, level, cap_num, inst_num, parameter_sets);
+}
+
+
+
+sdp_result_e ccsdpAttrSetFmtpMaxBr (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u32 max_br)
+{
+ cc_sdp_t *sdpp = sdp_ptr;
+
+ if ( sdpp->src_sdp == NULL ) {
+ return SDP_INVALID_PARAMETER;
+ }
+ return sdp_attr_set_fmtp_max_br(sdpp->src_sdp, level, cap_num, inst_num, max_br);
+}
+
+
+sdp_result_e ccsdpAttrSetFmtpMaxMbps (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u32 max_mbps)
+{
+ cc_sdp_t *sdpp = sdp_ptr;
+
+ if ( sdpp->src_sdp == NULL ) {
+ return SDP_INVALID_PARAMETER;
+ }
+ return sdp_attr_set_fmtp_max_mbps(sdpp->src_sdp, level, cap_num, inst_num, max_mbps);
+}
+
+sdp_result_e ccsdpAttrSetFmtpMaxFs (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u32 max_fs)
+{
+ cc_sdp_t *sdpp = sdp_ptr;
+
+ if ( sdpp->src_sdp == NULL ) {
+ return SDP_INVALID_PARAMETER;
+ }
+ return sdp_attr_set_fmtp_max_fs(sdpp->src_sdp, level, cap_num, inst_num, max_fs);
+}
+
+sdp_result_e ccsdpAttrSetFmtpMaxCpb (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u32 max_cpb)
+{
+ cc_sdp_t *sdpp = sdp_ptr;
+
+ if ( sdpp->src_sdp == NULL ) {
+ return SDP_INVALID_PARAMETER;
+ }
+ return sdp_attr_set_fmtp_max_cpb(sdpp->src_sdp, level, cap_num, inst_num, max_cpb);
+}
+
+sdp_result_e ccsdpAttrSetFmtpMaxDbp (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u32 max_dpb)
+{
+ cc_sdp_t *sdpp = sdp_ptr;
+
+ if ( sdpp->src_sdp == NULL ) {
+ return SDP_INVALID_PARAMETER;
+ }
+ return sdp_attr_set_fmtp_max_dpb(sdpp->src_sdp, level, cap_num, inst_num, max_dpb);
+}
+
+
+sdp_result_e ccsdpAttrSetFmtpQcif (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u16 qcif)
+{
+ cc_sdp_t *sdpp = sdp_ptr;
+
+ if ( sdpp->src_sdp == NULL ) {
+ return SDP_INVALID_PARAMETER;
+ }
+ return sdp_attr_set_fmtp_qcif(sdpp->src_sdp, level, cap_num, inst_num, qcif);
+}
+
+sdp_result_e ccsdpAttrSetFmtpSqcif (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u16 sqcif)
+{
+ cc_sdp_t *sdpp = sdp_ptr;
+
+ if ( sdpp->src_sdp == NULL ) {
+ return SDP_INVALID_PARAMETER;
+ }
+ return sdp_attr_set_fmtp_sqcif(sdpp->src_sdp, level, cap_num, inst_num, sqcif);
+}
+
+sdp_result_e ccsdpAddNewBandwidthLine (void *sdp_ptr, u16 level, sdp_bw_modifier_e bw_modifier, u16 *inst_num)
+{
+ cc_sdp_t *sdpp = sdp_ptr;
+
+ if ( sdpp->src_sdp == NULL ) {
+ return SDP_INVALID_PARAMETER;
+ }
+ return sdp_add_new_bw_line(sdpp->src_sdp, level, bw_modifier, inst_num);
+}
+
+
+sdp_result_e ccsdpSetBandwidth (void *sdp_ptr, u16 level, u16 inst_num,
+ sdp_bw_modifier_e bw_modifier, u32 bw_val)
+{
+ cc_sdp_t *sdpp = sdp_ptr;
+
+ if ( sdpp->src_sdp == NULL ) {
+ return SDP_INVALID_PARAMETER;
+ }
+ return sdp_set_bw(sdpp->src_sdp, level, inst_num, bw_modifier, bw_val);
+}
+
+const char * ccsdpCodecName(rtp_ptype ptype)
+{
+ switch (ptype)
+ {
+ case RTP_NONE: return "NONE";
+ case RTP_PCMU: return "PCMU";
+ case RTP_CELP: return "CELP";
+ case RTP_G726: return "G726";
+ case RTP_GSM: return "GSM";
+ case RTP_G723: return "G723";
+ case RTP_DVI4: return "DVI4";
+ case RTP_DVI4_II: return "DVI4_II";
+ case RTP_LPC: return "LPC";
+ case RTP_PCMA: return "PCMA";
+ case RTP_G722: return "G722";
+ case RTP_G728: return "G728";
+ case RTP_G729: return "G729";
+ case RTP_JPEG: return "JPEG";
+ case RTP_NV: return "NV";
+ case RTP_H261: return "H261";
+ case RTP_H264_P0: return "H264_P0";
+ case RTP_H264_P1: return "H264_P1";
+ case RTP_AVT: return "AVT";
+ case RTP_L16: return "L16";
+ case RTP_H263: return "H263";
+ case RTP_ILBC: return "iLBC";
+ case RTP_OPUS: return "OPUS";
+ case RTP_VP8: return "VP8";
+ case RTP_I420: return "I420";
+ /* case RTP_ISAC: return "ISAC"; */
+ }
+ return "UNKNOWN";
+}
+
diff --git a/libs/sipcc/core/sdp/sdp.h b/libs/sipcc/core/sdp/sdp.h
new file mode 100644
index 0000000000..a7ad11db6e
--- /dev/null
+++ b/libs/sipcc/core/sdp/sdp.h
@@ -0,0 +1,2010 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _SDP_H_
+#define _SDP_H_
+
+#include "cc_constants.h"
+#include "sdp_os_defs.h"
+#include "ccsdp.h"
+
+/* SDP Defines */
+
+/* The following defines are used to indicate params that are specified
+ * as the choose parameter or parameters that are invalid. These can
+ * be used where the value required is really a u16, but is represented
+ * by an int32.
+ */
+#define SDP_CHOOSE_PARAM (-1)
+#define SDP_SESSION_LEVEL 0xFFFF
+
+#define UNKNOWN_CRYPTO_SUITE "UNKNOWN_CRYPTO_SUITE"
+#define AES_CM_128_HMAC_SHA1_32 "AES_CM_128_HMAC_SHA1_32"
+#define AES_CM_128_HMAC_SHA1_80 "AES_CM_128_HMAC_SHA1_80"
+#define F8_128_HMAC_SHA1_80 "F8_128_HMAC_SHA1_80"
+
+/*
+ * SDP_SRTP_MAX_KEY_SIZE_BYTES
+ * Maximum size for a SRTP Master Key in bytes.
+ */
+#define SDP_SRTP_MAX_KEY_SIZE_BYTES 16
+/*
+ * SDP_SRTP_MAX_SALT_SIZE_BYTES
+ * Maximum size for a SRTP Master Salt in bytes.
+ */
+#define SDP_SRTP_MAX_SALT_SIZE_BYTES 14
+/*
+ * SDP_SRTP_MAX_MKI_SIZE_BYTES
+ * Maximum size for a SRTP Master Key Index in bytes.
+ */
+#define SDP_SRTP_MAX_MKI_SIZE_BYTES 4
+
+/* Max number of characters for Lifetime */
+#define SDP_SRTP_MAX_LIFETIME_BYTES 16
+
+#define SDP_SDESCRIPTIONS_KEY_SIZE_UNKNOWN 0
+#define SDP_SRTP_CRYPTO_SELECTION_FLAGS_UNKNOWN 0
+
+/*
+ * SRTP_CONTEXT_SET_*
+ * Set a SRTP Context field flag
+ */
+#define SDP_SRTP_ENCRYPT_MASK 0x00000001
+#define SDP_SRTP_AUTHENTICATE_MASK 0x00000002
+#define SDP_SRTCP_ENCRYPT_MASK 0x00000004
+#define SDP_SRTCP_SSRC_MASK 0x20000000
+#define SDP_SRTCP_ROC_MASK 0x10000000
+#define SDP_SRTCP_KDR_MASK 0x08000000
+#define SDP_SRTCP_KEY_MASK 0x80000000
+#define SDP_SRTCP_SALT_MASK 0x40000000
+
+#define SDP_SRTP_CONTEXT_SET_SSRC(cw) ((cw) |= SDP_SRTCP_SSRC_MASK)
+#define SDP_SRTP_CONTEXT_SET_ROC(cw) ((cw) |= SDP_SRTCP_ROC_MASK)
+#define SDP_SRTP_CONTEXT_SET_KDR(cw) ((cw) |= SDP_SRTCP_KDR_MASK)
+#define SDP_SRTP_CONTEXT_SET_MASTER_KEY(cw) ((cw) |= SDP_SRTCP_KEY_MASK)
+#define SDP_SRTP_CONTEXT_SET_MASTER_SALT(cw) ((cw) |= SDP_SRTCP_SALT_MASK)
+#define SDP_SRTP_CONTEXT_SET_ENCRYPT_AUTHENTICATE(cw) \
+ ((cw) |= (SDP_SRTP_ENCRYPT_MASK | SDP_SRTP_AUTHENTICATE_MASK | \
+ SDP_SRTCP_ENCRYPT_MASK))
+
+#define SDP_SRTP_CONTEXT_RESET_SSRC(cw) ((cw) &= ~(SDP_SRTCP_SSRC_MASK))
+#define SDP_SRTP_CONTEXT_RESET_ROC(cw) ((cw) &= ~(SDP_SRTCP_ROC_MASK))
+#define SDP_SRTP_CONTEXT_RESET_KDR(cw) ((cw) &= ~(SDP_SRTCP_KDR_MASK))
+#define SDP_CONTEXT_RESET_MASTER_KEY(cw) ((cw) &= ~(SDP_SRTCP_KEY_MASK))
+#define SDP_CONTEXT_RESET_MASTER_SALT(cw) ((cw) &= ~(SDP_SRTCP_SALT_MASK))
+
+/* SDP Enum Types */
+
+typedef enum {
+ SDP_DEBUG_TRACE,
+ SDP_DEBUG_WARNINGS,
+ SDP_DEBUG_ERRORS,
+ SDP_MAX_DEBUG_TYPES
+} sdp_debug_e;
+
+typedef enum {
+ SDP_CHOOSE_CONN_ADDR,
+ SDP_CHOOSE_PORTNUM,
+ SDP_MAX_CHOOSE_PARAMS
+} sdp_choose_param_e;
+
+
+/* Token Lines - these must be in the same order they should
+ * appear in an SDP.
+ */
+typedef enum {
+ SDP_TOKEN_V = 0,
+ SDP_TOKEN_O,
+ SDP_TOKEN_S,
+ SDP_TOKEN_I,
+ SDP_TOKEN_U,
+ SDP_TOKEN_E,
+ SDP_TOKEN_P,
+ SDP_TOKEN_C,
+ SDP_TOKEN_B,
+ SDP_TOKEN_T,
+ SDP_TOKEN_R,
+ SDP_TOKEN_Z,
+ SDP_TOKEN_K,
+ SDP_TOKEN_A,
+ SDP_TOKEN_M,
+ SDP_MAX_TOKENS
+} sdp_token_e;
+
+/* Media Types */
+typedef enum {
+ SDP_MEDIA_AUDIO = 0,
+ SDP_MEDIA_VIDEO,
+ SDP_MEDIA_APPLICATION,
+ SDP_MEDIA_DATA,
+ SDP_MEDIA_CONTROL,
+ SDP_MEDIA_NAS_RADIUS,
+ SDP_MEDIA_NAS_TACACS,
+ SDP_MEDIA_NAS_DIAMETER,
+ SDP_MEDIA_NAS_L2TP,
+ SDP_MEDIA_NAS_LOGIN,
+ SDP_MEDIA_NAS_NONE,
+ SDP_MEDIA_TEXT,
+ SDP_MEDIA_IMAGE,
+ SDP_MAX_MEDIA_TYPES,
+ SDP_MEDIA_UNSUPPORTED,
+ SDP_MEDIA_INVALID
+} sdp_media_e;
+
+
+/* Connection Network Type */
+typedef enum {
+ SDP_NT_INTERNET = 0, /* 0 -> IP - In SDP "IN" is defined */
+ /* to mean "Internet" */
+ SDP_NT_ATM, /* 1 -> ATM */
+ SDP_NT_FR, /* 2 -> FRAME RELAY */
+ SDP_NT_LOCAL, /* 3 -> local */
+ SDP_MAX_NETWORK_TYPES,
+ SDP_NT_UNSUPPORTED,
+ SDP_NT_INVALID
+} sdp_nettype_e;
+
+
+/* Address Type */
+typedef enum {
+ SDP_AT_IP4 = 0, /* 0 -> IP Version 4 (IP4) */
+ SDP_AT_IP6, /* 1 -> IP Version 6 (IP6) */
+ SDP_AT_NSAP, /* 2 -> 20 byte NSAP address */
+ SDP_AT_EPN, /* 3 -> 32 bytes of endpoint name */
+ SDP_AT_E164, /* 4 -> 15 digit decimal number addr */
+ SDP_AT_GWID, /* 5 -> Private gw id. ASCII string */
+ SDP_MAX_ADDR_TYPES,
+ SDP_AT_UNSUPPORTED,
+ SDP_AT_FQDN,
+ SDP_AT_INVALID
+} sdp_addrtype_e;
+
+
+/* Transport Types */
+
+#define SDP_MAX_PROFILES 3
+
+typedef enum {
+ SDP_TRANSPORT_RTPAVP = 0,
+ SDP_TRANSPORT_UDP,
+ SDP_TRANSPORT_UDPTL,
+ SDP_TRANSPORT_CES10,
+ SDP_TRANSPORT_LOCAL,
+ SDP_TRANSPORT_AAL2_ITU,
+ SDP_TRANSPORT_AAL2_ATMF,
+ SDP_TRANSPORT_AAL2_CUSTOM,
+ SDP_TRANSPORT_AAL1AVP,
+ SDP_TRANSPORT_UDPSPRT,
+ SDP_TRANSPORT_RTPSAVP,
+ SDP_TRANSPORT_TCP,
+ SDP_TRANSPORT_RTPSAVPF,
+ SDP_TRANSPORT_SCTPDTLS,
+ SDP_MAX_TRANSPORT_TYPES,
+ SDP_TRANSPORT_UNSUPPORTED,
+ SDP_TRANSPORT_INVALID
+} sdp_transport_e;
+
+
+/* Encryption KeyType */
+typedef enum {
+ SDP_ENCRYPT_CLEAR, /* 0 -> Key given in the clear */
+ SDP_ENCRYPT_BASE64, /* 1 -> Base64 encoded key */
+ SDP_ENCRYPT_URI, /* 2 -> Ptr to URI */
+ SDP_ENCRYPT_PROMPT, /* 3 -> No key included, prompt user */
+ SDP_MAX_ENCRYPT_TYPES,
+ SDP_ENCRYPT_UNSUPPORTED,
+ SDP_ENCRYPT_INVALID
+} sdp_encrypt_type_e;
+
+
+/* Known string payload types */
+typedef enum {
+ SDP_PAYLOAD_T38,
+ SDP_PAYLOAD_XTMR,
+ SDP_PAYLOAD_T120,
+ SDP_MAX_STRING_PAYLOAD_TYPES,
+ SDP_PAYLOAD_UNSUPPORTED,
+ SDP_PAYLOAD_INVALID
+} sdp_payload_e;
+
+
+/* Payload type indicator */
+typedef enum {
+ SDP_PAYLOAD_NUMERIC,
+ SDP_PAYLOAD_ENUM
+} sdp_payload_ind_e;
+
+
+/* Image payload types */
+typedef enum {
+ SDP_PORT_NUM_ONLY, /* or '$' */
+ SDP_PORT_NUM_COUNT, /* / */
+ SDP_PORT_VPI_VCI, /* / */
+ SDP_PORT_VCCI, /* */
+ SDP_PORT_NUM_VPI_VCI, /* // */
+ SDP_PORT_VCCI_CID, /* / or '$'/'$' */
+ SDP_PORT_NUM_VPI_VCI_CID, /* /// */
+ SDP_MAX_PORT_FORMAT_TYPES,
+ SDP_PORT_FORMAT_INVALID
+} sdp_port_format_e;
+
+
+/* Fmtp attribute format Types */
+typedef enum {
+ SDP_FMTP_NTE,
+ SDP_FMTP_CODEC_INFO,
+ SDP_FMTP_MODE,
+ SDP_FMTP_DATACHANNEL,
+ SDP_FMTP_UNKNOWN_TYPE,
+ SDP_FMTP_MAX_TYPE
+} sdp_fmtp_format_type_e;
+
+
+/* T.38 Rate Mgmt Types */
+typedef enum {
+ SDP_T38_LOCAL_TCF,
+ SDP_T38_TRANSFERRED_TCF,
+ SDP_T38_UNKNOWN_RATE,
+ SDP_T38_MAX_RATES
+} sdp_t38_ratemgmt_e;
+
+
+/* T.38 udp EC Types */
+typedef enum {
+ SDP_T38_UDP_REDUNDANCY,
+ SDP_T38_UDP_FEC,
+ SDP_T38_UDPEC_UNKNOWN,
+ SDP_T38_MAX_UDPEC
+} sdp_t38_udpec_e;
+
+/* Bitmaps for manipulating sdp_direction_e */
+typedef enum {
+ SDP_DIRECTION_FLAG_SEND=0x01,
+ SDP_DIRECTION_FLAG_RECV=0x02
+} sdp_direction_flag_e;
+
+/* Media flow direction */
+typedef enum {
+ SDP_DIRECTION_INACTIVE = 0,
+ SDP_DIRECTION_SENDONLY = SDP_DIRECTION_FLAG_SEND,
+ SDP_DIRECTION_RECVONLY = SDP_DIRECTION_FLAG_RECV,
+ SDP_DIRECTION_SENDRECV = SDP_DIRECTION_FLAG_SEND | SDP_DIRECTION_FLAG_RECV,
+ SDP_MAX_QOS_DIRECTIONS
+} sdp_direction_e;
+
+#define SDP_DIRECTION_PRINT(arg) \
+ (((sdp_direction_e)(arg)) == SDP_DIRECTION_INACTIVE ? "SDP_DIRECTION_INACTIVE " : \
+ ((sdp_direction_e)(arg)) == SDP_DIRECTION_SENDONLY ? "SDP_DIRECTION_SENDONLY": \
+ ((sdp_direction_e)(arg)) == SDP_DIRECTION_RECVONLY ? "SDP_DIRECTION_RECVONLY ": \
+ ((sdp_direction_e)(arg)) == SDP_DIRECTION_SENDRECV ? " SDP_DIRECTION_SENDRECV": "SDP_MAX_QOS_DIRECTIONS")
+
+
+/* QOS Strength tag */
+typedef enum {
+ SDP_QOS_STRENGTH_OPT,
+ SDP_QOS_STRENGTH_MAND,
+ SDP_QOS_STRENGTH_SUCC,
+ SDP_QOS_STRENGTH_FAIL,
+ SDP_QOS_STRENGTH_NONE,
+ SDP_MAX_QOS_STRENGTH,
+ SDP_QOS_STRENGTH_UNKNOWN
+} sdp_qos_strength_e;
+
+
+/* QOS direction */
+typedef enum {
+ SDP_QOS_DIR_SEND,
+ SDP_QOS_DIR_RECV,
+ SDP_QOS_DIR_SENDRECV,
+ SDP_QOS_DIR_NONE,
+ SDP_MAX_QOS_DIR,
+ SDP_QOS_DIR_UNKNOWN
+} sdp_qos_dir_e;
+
+/* QoS Status types */
+typedef enum {
+ SDP_QOS_LOCAL,
+ SDP_QOS_REMOTE,
+ SDP_QOS_E2E,
+ SDP_MAX_QOS_STATUS_TYPES,
+ SDP_QOS_STATUS_TYPE_UNKNOWN
+} sdp_qos_status_types_e;
+
+/* QoS Status types */
+typedef enum {
+ SDP_CURR_QOS_TYPE,
+ SDP_CURR_UNKNOWN_TYPE,
+ SDP_MAX_CURR_TYPES
+} sdp_curr_type_e;
+
+/* QoS Status types */
+typedef enum {
+ SDP_DES_QOS_TYPE,
+ SDP_DES_UNKNOWN_TYPE,
+ SDP_MAX_DES_TYPES
+} sdp_des_type_e;
+
+/* QoS Status types */
+typedef enum {
+ SDP_CONF_QOS_TYPE,
+ SDP_CONF_UNKNOWN_TYPE,
+ SDP_MAX_CONF_TYPES
+} sdp_conf_type_e;
+
+
+/* Named event range result values. */
+typedef enum {
+ SDP_NO_MATCH,
+ SDP_PARTIAL_MATCH,
+ SDP_FULL_MATCH
+} sdp_ne_res_e;
+
+/* Fmtp attribute parameters for audio/video codec information */
+typedef enum {
+
+ /* mainly for audio codecs */
+ SDP_ANNEX_A, /* 0 */
+ SDP_ANNEX_B,
+ SDP_BITRATE,
+
+ /* for video codecs */
+ SDP_QCIF,
+ SDP_CIF,
+ SDP_MAXBR,
+ SDP_SQCIF,
+ SDP_CIF4,
+ SDP_CIF16,
+ SDP_CUSTOM,
+ SDP_PAR,
+ SDP_CPCF,
+ SDP_BPP,
+ SDP_HRD,
+ SDP_PROFILE,
+ SDP_LEVEL,
+ SDP_INTERLACE,
+
+ /* H.264 related */
+ SDP_PROFILE_LEVEL_ID, /* 17 */
+ SDP_PARAMETER_SETS,
+ SDP_PACKETIZATION_MODE,
+ SDP_INTERLEAVING_DEPTH,
+ SDP_DEINT_BUF_REQ,
+ SDP_MAX_DON_DIFF,
+ SDP_INIT_BUF_TIME,
+
+ SDP_MAX_MBPS,
+ SDP_MAX_FS,
+ SDP_MAX_CPB,
+ SDP_MAX_DPB,
+ SDP_MAX_BR,
+ SDP_REDUNDANT_PIC_CAP,
+ SDP_DEINT_BUF_CAP,
+ SDP_MAX_RCMD_NALU_SIZE,
+
+ SDP_PARAMETER_ADD,
+
+ /* Annexes - begin */
+ /* Some require special handling as they don't have token=token format*/
+ SDP_ANNEX_D,
+ SDP_ANNEX_F,
+ SDP_ANNEX_I,
+ SDP_ANNEX_J,
+ SDP_ANNEX_T,
+
+ /* These annexes have token=token format */
+ SDP_ANNEX_K,
+ SDP_ANNEX_N,
+ SDP_ANNEX_P,
+
+ SDP_MODE,
+ SDP_LEVEL_ASYMMETRY_ALLOWED,
+ SDP_MAX_AVERAGE_BIT_RATE,
+ SDP_USED_TX,
+ SDP_STEREO,
+ SDP_USE_IN_BAND_FEC,
+ SDP_MAX_CODED_AUDIO_BW,
+ SDP_CBR,
+ SDP_STREAMS,
+ SDP_PROTOCOL,
+ SDP_MAX_FMTP_PARAM,
+ SDP_FMTP_PARAM_UNKNOWN
+} sdp_fmtp_codec_param_e;
+
+/* Fmtp attribute parameters values for
+ fmtp attribute parameters which convey codec
+ information */
+
+typedef enum {
+ SDP_YES,
+ SDP_NO,
+ SDP_MAX_FMTP_PARAM_VAL,
+ SDP_FMTP_PARAM_UNKNOWN_VAL
+} sdp_fmtp_codec_param_val_e;
+
+/* silenceSupp suppPref */
+typedef enum {
+ SDP_SILENCESUPP_PREF_STANDARD,
+ SDP_SILENCESUPP_PREF_CUSTOM,
+ SDP_SILENCESUPP_PREF_NULL, /* "-" */
+ SDP_MAX_SILENCESUPP_PREF,
+ SDP_SILENCESUPP_PREF_UNKNOWN
+} sdp_silencesupp_pref_e;
+
+/* silenceSupp sidUse */
+typedef enum {
+ SDP_SILENCESUPP_SIDUSE_NOSID,
+ SDP_SILENCESUPP_SIDUSE_FIXED,
+ SDP_SILENCESUPP_SIDUSE_SAMPLED,
+ SDP_SILENCESUPP_SIDUSE_NULL, /* "-" */
+ SDP_MAX_SILENCESUPP_SIDUSE,
+ SDP_SILENCESUPP_SIDUSE_UNKNOWN
+} sdp_silencesupp_siduse_e;
+
+typedef enum {
+ SDP_MEDIADIR_ROLE_PASSIVE,
+ SDP_MEDIADIR_ROLE_ACTIVE,
+ SDP_MEDIADIR_ROLE_BOTH,
+ SDP_MEDIADIR_ROLE_REUSE,
+ SDP_MEDIADIR_ROLE_UNKNOWN,
+ SDP_MAX_MEDIADIR_ROLES,
+ SDP_MEDIADIR_ROLE_UNSUPPORTED,
+ SDP_MEDIADIR_ROLE_INVALID
+} sdp_mediadir_role_e;
+
+typedef enum {
+ SDP_GROUP_ATTR_FID,
+ SDP_GROUP_ATTR_LS,
+ SDP_GROUP_ATTR_ANAT,
+ SDP_MAX_GROUP_ATTR_VAL,
+ SDP_GROUP_ATTR_UNSUPPORTED
+} sdp_group_attr_e;
+
+typedef enum {
+ SDP_SRC_FILTER_INCL,
+ SDP_SRC_FILTER_EXCL,
+ SDP_MAX_FILTER_MODE,
+ SDP_FILTER_MODE_NOT_PRESENT
+} sdp_src_filter_mode_e;
+
+typedef enum {
+ SDP_RTCP_UNICAST_MODE_REFLECTION,
+ SDP_RTCP_UNICAST_MODE_RSI,
+ SDP_RTCP_MAX_UNICAST_MODE,
+ SDP_RTCP_UNICAST_MODE_NOT_PRESENT
+} sdp_rtcp_unicast_mode_e;
+
+/*
+ * sdp_srtp_fec_order_t
+ * This type defines the order in which to perform FEC
+ * (Forward Error Correction) and SRTP Encryption/Authentication.
+ */
+typedef enum sdp_srtp_fec_order_t_ {
+ SDP_SRTP_THEN_FEC, /* upon sending perform SRTP then FEC */
+ SDP_FEC_THEN_SRTP, /* upon sending perform FEC then SRTP */
+ SDP_SRTP_FEC_SPLIT /* upon sending perform SRTP Encryption,
+ * then FEC, the SRTP Authentication */
+} sdp_srtp_fec_order_t;
+
+
+/*
+ * sdp_srtp_crypto_suite_t
+ * Enumeration of the crypto suites supported for MGCP SRTP
+ * package.
+ */
+typedef enum sdp_srtp_crypto_suite_t_ {
+ SDP_SRTP_UNKNOWN_CRYPTO_SUITE = 0,
+ SDP_SRTP_AES_CM_128_HMAC_SHA1_32,
+ SDP_SRTP_AES_CM_128_HMAC_SHA1_80,
+ SDP_SRTP_F8_128_HMAC_SHA1_80,
+ SDP_SRTP_MAX_NUM_CRYPTO_SUITES
+} sdp_srtp_crypto_suite_t;
+
+/*
+ * SDP SRTP crypto suite definition parameters
+ *
+ * SDP_SRTP__KEY_BYTES
+ * The size of a master key for in bytes.
+ *
+ * SDP_SRTP__SALT_BYTES
+ * The size of a master salt for in bytes.
+ */
+#define SDP_SRTP_AES_CM_128_HMAC_SHA1_32_KEY_BYTES 16
+#define SDP_SRTP_AES_CM_128_HMAC_SHA1_32_SALT_BYTES 14
+#define SDP_SRTP_AES_CM_128_HMAC_SHA1_80_KEY_BYTES 16
+#define SDP_SRTP_AES_CM_128_HMAC_SHA1_80_SALT_BYTES 14
+#define SDP_SRTP_F8_128_HMAC_SHA1_80_KEY_BYTES 16
+#define SDP_SRTP_F8_128_HMAC_SHA1_80_SALT_BYTES 14
+
+/* SDP Defines */
+
+#define SDP_MAX_STRING_LEN 256 /* Max len for SDP string */
+#define SDP_MAX_SHORT_STRING_LEN 12 /* Max len for a short SDP string */
+#define SDP_MAX_PAYLOAD_TYPES 23 /* Max payload types in m= line */
+#define SDP_TOKEN_LEN 2 /* Len of = */
+#define SDP_CURRENT_VERSION 0 /* Current default SDP version */
+#define SDP_MAX_PORT_PARAMS 4 /* Max m= port params - x/x/x/x */
+#define SDP_MIN_DYNAMIC_PAYLOAD 96 /* Min dynamic payload */
+#define SDP_MAX_DYNAMIC_PAYLOAD 127 /* Max dynamic payload */
+#define SDP_MIN_CIF_VALUE 1 /* applies to all QCIF,CIF,CIF4,CIF16,SQCIF */
+#define SDP_MAX_CIF_VALUE 32 /* applies to all QCIF,CIF,CIF4,CIF16,SQCIF */
+#define SDP_MAX_SRC_ADDR_LIST 1 /* Max source addrs for which filter applies */
+
+
+#define SDP_DEFAULT_PACKETIZATION_MODE_VALUE 0 /* max packetization mode for H.264 */
+#define SDP_MAX_PACKETIZATION_MODE_VALUE 2 /* max packetization mode for H.264 */
+
+#define SDP_MAX_LEVEL_ASYMMETRY_ALLOWED_VALUE 1 /* max level asymmetry allowed value for H.264 */
+#define SDP_DEFAULT_LEVEL_ASYMMETRY_ALLOWED_VALUE 1 /* default level asymmetry allowed value for H.264 */
+#define SDP_INVALID_LEVEL_ASYMMETRY_ALLOWED_VALUE 2 /* invalid value for level-asymmetry-allowed param for H.264 */
+
+
+/* Max number of stream ids that can be grouped together */
+#define SDP_MAX_GROUP_STREAM_ID 10
+
+
+#define SDP_MAGIC_NUM 0xabcdabcd
+
+#define SDP_UNSUPPORTED "Unsupported"
+#define SDP_MAX_LINE_LEN 256 /* Max len for SDP Line */
+
+#define SDP_MAX_PROFILE_VALUE 10
+#define SDP_MAX_LEVEL_VALUE 100
+#define SDP_MIN_PROFILE_LEVEL_VALUE 0
+#define SDP_MAX_TTL_VALUE 255
+#define SDP_MIN_MCAST_ADDR_HI_BIT_VAL 224
+#define SDP_MAX_MCAST_ADDR_HI_BIT_VAL 239
+
+/* SDP Enum Types */
+
+typedef enum {
+ SDP_ERR_INVALID_CONF_PTR,
+ SDP_ERR_INVALID_SDP_PTR,
+ SDP_ERR_INTERNAL,
+ SDP_MAX_ERR_TYPES
+} sdp_errmsg_e;
+
+/* SDP Structure Definitions */
+
+/* String names of varios tokens */
+typedef struct {
+ char *name;
+ u8 strlen;
+} sdp_namearray_t;
+
+/* c= line info */
+typedef struct {
+ sdp_nettype_e nettype;
+ sdp_addrtype_e addrtype;
+ char conn_addr[SDP_MAX_STRING_LEN+1];
+ tinybool is_multicast;
+ u16 ttl;
+ u16 num_of_addresses;
+} sdp_conn_t;
+
+/* t= line info */
+typedef struct sdp_timespec {
+ char start_time[SDP_MAX_STRING_LEN+1];
+ char stop_time[SDP_MAX_STRING_LEN+1];
+ struct sdp_timespec *next_p;
+} sdp_timespec_t;
+
+
+/* k= line info */
+typedef struct sdp_encryptspec {
+ sdp_encrypt_type_e encrypt_type;
+ char encrypt_key[SDP_MAX_STRING_LEN+1];
+} sdp_encryptspec_t;
+
+
+/* FMTP attribute deals with named events in the range of 0-255 as
+ * defined in RFC 2833 */
+#define SDP_MIN_NE_VALUE 0
+#define SDP_MAX_NE_VALUES 256
+#define SDP_NE_BITS_PER_WORD ( sizeof(u32) * 8 )
+#define SDP_NE_NUM_BMAP_WORDS ((SDP_MAX_NE_VALUES + SDP_NE_BITS_PER_WORD - 1)/SDP_NE_BITS_PER_WORD )
+#define SDP_NE_BIT_0 ( 0x00000001 )
+#define SDP_NE_ALL_BITS ( 0xFFFFFFFF )
+
+#define SDP_DEINT_BUF_REQ_FLAG 0x1
+#define SDP_INIT_BUF_TIME_FLAG 0x2
+#define SDP_MAX_RCMD_NALU_SIZE_FLAG 0x4
+#define SDP_DEINT_BUF_CAP_FLAG 0x8
+
+typedef struct sdp_fmtp {
+ u16 payload_num;
+ u32 maxval; /* maxval optimizes bmap search */
+ u32 bmap[ SDP_NE_NUM_BMAP_WORDS ];
+ sdp_fmtp_format_type_e fmtp_format; /* Gives the format type
+ for FMTP attribute*/
+ tinybool annexb_required;
+ tinybool annexa_required;
+
+ tinybool annexa;
+ tinybool annexb;
+ u32 bitrate;
+ u32 mode;
+
+ /* some OPUS specific fmtp params */
+ u32 maxaveragebitrate;
+ u16 usedtx;
+ u16 stereo;
+ u16 useinbandfec;
+ char maxcodedaudiobandwidth[SDP_MAX_STRING_LEN+1];
+ u16 cbr;
+
+ /* some Data Channel specific fmtp params */
+ u16 streams; /* Num streams per Data Channel */
+ char protocol[SDP_MAX_STRING_LEN+1];
+
+ /* BEGIN - All Video related FMTP parameters */
+ u16 qcif;
+ u16 cif;
+ u16 maxbr;
+ u16 sqcif;
+ u16 cif4;
+ u16 cif16;
+
+ u16 custom_x;
+ u16 custom_y;
+ u16 custom_mpi;
+ /* CUSTOM=360,240,4 implies X-AXIS=360, Y-AXIS=240; MPI=4 */
+ u16 par_width;
+ u16 par_height;
+ /* PAR=12:11 implies par_width=12, par_height=11 */
+
+ /* CPCF should be a float. IOS does not support float and so it is u16 */
+ /* For portable stack, CPCF should be defined as float and the parsing should
+ * be modified accordingly */
+ u16 cpcf;
+ u16 bpp;
+ u16 hrd;
+
+ int16 profile;
+ int16 level;
+ tinybool is_interlace;
+
+ /* some more H.264 specific fmtp params */
+ char profile_level_id[SDP_MAX_STRING_LEN+1];
+ char parameter_sets[SDP_MAX_STRING_LEN+1];
+ u16 packetization_mode;
+ u16 level_asymmetry_allowed;
+ u16 interleaving_depth;
+ u32 deint_buf_req;
+ u32 max_don_diff;
+ u32 init_buf_time;
+
+ u32 max_mbps;
+ u32 max_fs;
+ u32 max_cpb;
+ u32 max_dpb;
+ u32 max_br;
+ tinybool redundant_pic_cap;
+ u32 deint_buf_cap;
+ u32 max_rcmd_nalu_size;
+ tinybool parameter_add;
+
+ tinybool annex_d;
+
+ tinybool annex_f;
+ tinybool annex_i;
+ tinybool annex_j;
+ tinybool annex_t;
+
+ /* H.263 codec requires annex K,N and P to have values */
+ u16 annex_k_val;
+ u16 annex_n_val;
+
+ /* Annex P can take one or more values in the range 1-4 . e.g P=1,3 */
+ u16 annex_p_val_picture_resize; /* 1 = four; 2 = sixteenth */
+ u16 annex_p_val_warp; /* 3 = half; 4=sixteenth */
+
+ u8 flag;
+
+ /* END - All Video related FMTP parameters */
+
+} sdp_fmtp_t;
+
+/* a=qos|secure|X-pc-qos|X-qos info */
+typedef struct sdp_qos {
+ sdp_qos_strength_e strength;
+ sdp_qos_dir_e direction;
+ tinybool confirm;
+ sdp_qos_status_types_e status_type;
+} sdp_qos_t;
+
+/* a=curr:qos status_type direction */
+typedef struct sdp_curr {
+ sdp_curr_type_e type;
+ sdp_qos_status_types_e status_type;
+ sdp_qos_dir_e direction;
+} sdp_curr_t;
+
+/* a=des:qos strength status_type direction */
+typedef struct sdp_des {
+ sdp_des_type_e type;
+ sdp_qos_strength_e strength;
+ sdp_qos_status_types_e status_type;
+ sdp_qos_dir_e direction;
+} sdp_des_t;
+
+/* a=conf:qos status_type direction */
+typedef struct sdp_conf {
+ sdp_conf_type_e type;
+ sdp_qos_status_types_e status_type;
+ sdp_qos_dir_e direction;
+} sdp_conf_t;
+
+
+/* a=rtpmap or a=sprtmap info */
+typedef struct sdp_transport_map {
+ u16 payload_num;
+ char encname[SDP_MAX_STRING_LEN+1];
+ u32 clockrate;
+ u16 num_chan;
+} sdp_transport_map_t;
+
+
+/* a=rtr info */
+typedef struct sdp_rtr {
+ tinybool confirm;
+} sdp_rtr_t;
+
+/* a=subnet info */
+typedef struct sdp_subnet {
+ sdp_nettype_e nettype;
+ sdp_addrtype_e addrtype;
+ char addr[SDP_MAX_STRING_LEN+1];
+ int32 prefix;
+} sdp_subnet_t;
+
+
+/* a=X-pc-codec info */
+typedef struct sdp_pccodec {
+ u16 num_payloads;
+ ushort payload_type[SDP_MAX_PAYLOAD_TYPES];
+} sdp_pccodec_t;
+
+/* a=direction info */
+typedef struct sdp_comediadir {
+ sdp_mediadir_role_e role;
+ tinybool conn_info_present;
+ sdp_conn_t conn_info;
+ u32 src_port;
+} sdp_comediadir_t;
+
+
+
+/* a=silenceSupp info */
+typedef struct sdp_silencesupp {
+ tinybool enabled;
+ tinybool timer_null;
+ u16 timer;
+ sdp_silencesupp_pref_e pref;
+ sdp_silencesupp_siduse_e siduse;
+ tinybool fxnslevel_null;
+ u8 fxnslevel;
+} sdp_silencesupp_t;
+
+
+/*
+ * a=mptime info */
+/* Note that an interval value of zero corresponds to
+ * the "-" syntax on the a= line.
+ */
+typedef struct sdp_mptime {
+ u16 num_intervals;
+ ushort intervals[SDP_MAX_PAYLOAD_TYPES];
+} sdp_mptime_t;
+
+/*
+ * a=X-sidin:, a=X-sidout:< val> and a=X-confid:
+ * Stream Id,ConfID related attributes to be used for audio/video conferencing
+ *
+*/
+
+typedef struct sdp_stream_data {
+ char x_sidin[SDP_MAX_STRING_LEN+1];
+ char x_sidout[SDP_MAX_STRING_LEN+1];
+ char x_confid[SDP_MAX_STRING_LEN+1];
+ sdp_group_attr_e group_attr; /* FID or LS */
+ u16 num_group_id;
+ u16 group_id_arr[SDP_MAX_GROUP_STREAM_ID];
+} sdp_stream_data_t;
+
+/*
+ * a=source-filter:
+ * = ...
+ * One or more source addresses to apply filter, for one or more connection
+ * address in unicast/multicast environments
+ */
+typedef struct sdp_source_filter {
+ sdp_src_filter_mode_e mode;
+ sdp_nettype_e nettype;
+ sdp_addrtype_e addrtype;
+ char dest_addr[SDP_MAX_STRING_LEN+1];
+ u16 num_src_addr;
+ char src_list[SDP_MAX_SRC_ADDR_LIST+1][SDP_MAX_STRING_LEN+1];
+} sdp_source_filter_t;
+
+/*
+ * b=:
+ *
+*/
+typedef struct sdp_bw_data {
+ struct sdp_bw_data *next_p;
+ sdp_bw_modifier_e bw_modifier;
+ int bw_val;
+} sdp_bw_data_t;
+
+/*
+ * This structure houses a linked list of sdp_bw_data_t instances. Each
+ * sdp_bw_data_t instance represents one b= line.
+ */
+typedef struct sdp_bw {
+ u16 bw_data_count;
+ sdp_bw_data_t *bw_data_list;
+} sdp_bw_t;
+
+/* Media lines for AAL2 may have more than one transport type defined
+ * each with its own payload type list. These are referred to as
+ * profile types instead of transport types. This structure is used
+ * to handle these multiple profile types. Note: One additional profile
+ * field is needed because of the way parsing is done. This is not an
+ * error. */
+typedef struct sdp_media_profiles {
+ u16 num_profiles;
+ sdp_transport_e profile[SDP_MAX_PROFILES+1];
+ u16 num_payloads[SDP_MAX_PROFILES];
+ sdp_payload_ind_e payload_indicator[SDP_MAX_PROFILES][SDP_MAX_PAYLOAD_TYPES];
+ u16 payload_type[SDP_MAX_PROFILES][SDP_MAX_PAYLOAD_TYPES];
+} sdp_media_profiles_t;
+
+
+/*
+ * sdp_srtp_crypto_context_t
+ * This type is used to hold cryptographic context information.
+ *
+ */
+
+typedef struct sdp_srtp_crypto_context_t_ {
+ int32 tag;
+ unsigned long selection_flags;
+ sdp_srtp_crypto_suite_t suite;
+ unsigned char master_key[SDP_SRTP_MAX_KEY_SIZE_BYTES];
+ unsigned char master_salt[SDP_SRTP_MAX_SALT_SIZE_BYTES];
+ unsigned char master_key_size_bytes;
+ unsigned char master_salt_size_bytes;
+ unsigned long ssrc; /* not used */
+ unsigned long roc; /* not used */
+ unsigned long kdr; /* not used */
+ unsigned short seq; /* not used */
+ sdp_srtp_fec_order_t fec_order; /* not used */
+ unsigned char master_key_lifetime[SDP_SRTP_MAX_LIFETIME_BYTES];
+ unsigned char mki[SDP_SRTP_MAX_MKI_SIZE_BYTES];
+ u16 mki_size_bytes;
+ char* session_parameters;
+} sdp_srtp_crypto_context_t;
+
+
+/* m= line info and associated attribute list */
+/* Note: Most of the port parameter values are 16-bit values. We set
+ * the type to int32 so we can return either a 16-bit value or the
+ * choose value. */
+typedef struct sdp_mca {
+ sdp_media_e media;
+ sdp_conn_t conn;
+ sdp_transport_e transport;
+ sdp_port_format_e port_format;
+ int32 port;
+ int32 sctpport;
+ int32 num_ports;
+ int32 vpi;
+ u32 vci; /* VCI needs to be 32-bit */
+ int32 vcci;
+ int32 cid;
+ u16 num_payloads;
+ sdp_payload_ind_e payload_indicator[SDP_MAX_PAYLOAD_TYPES];
+ u16 payload_type[SDP_MAX_PAYLOAD_TYPES];
+ sdp_media_profiles_t *media_profiles_p;
+ tinybool sessinfo_found;
+ sdp_encryptspec_t encrypt;
+ sdp_bw_t bw;
+ sdp_attr_e media_direction; /* Either INACTIVE, SENDONLY,
+ RECVONLY, or SENDRECV */
+ u32 mid;
+ struct sdp_attr *media_attrs_p;
+ struct sdp_mca *next_p;
+} sdp_mca_t;
+
+
+/* generic a= line info */
+typedef struct sdp_attr {
+ sdp_attr_e type;
+ union {
+ tinybool boolean_val;
+ u32 u32_val;
+ char string_val[SDP_MAX_STRING_LEN+1];
+ char ice_attr[SDP_MAX_STRING_LEN+1];
+ sdp_fmtp_t fmtp;
+ sdp_qos_t qos;
+ sdp_curr_t curr;
+ sdp_des_t des;
+ sdp_conf_t conf;
+ sdp_transport_map_t transport_map; /* A rtpmap or sprtmap */
+ sdp_subnet_t subnet;
+ sdp_t38_ratemgmt_e t38ratemgmt;
+ sdp_t38_udpec_e t38udpec;
+ sdp_pccodec_t pccodec;
+ sdp_silencesupp_t silencesupp;
+ sdp_mca_t *cap_p; /* A X-CAP or CDSC attribute */
+ sdp_rtr_t rtr;
+ sdp_comediadir_t comediadir;
+ sdp_srtp_crypto_context_t srtp_context;
+ sdp_mptime_t mptime;
+ sdp_stream_data_t stream_data;
+ char unknown[SDP_MAX_STRING_LEN+1];
+ sdp_source_filter_t source_filter;
+ } attr;
+ struct sdp_attr *next_p;
+} sdp_attr_t;
+
+typedef struct sdp_srtp_crypto_suite_list_ {
+ sdp_srtp_crypto_suite_t crypto_suite_val;
+ char * crypto_suite_str;
+ unsigned char key_size_bytes;
+ unsigned char salt_size_bytes;
+} sdp_srtp_crypto_suite_list;
+
+/* Application configuration options */
+typedef struct sdp_conf_options {
+ u32 magic_num;
+ tinybool debug_flag[SDP_MAX_DEBUG_TYPES];
+ tinybool version_reqd;
+ tinybool owner_reqd;
+ tinybool session_name_reqd;
+ tinybool timespec_reqd;
+ tinybool media_supported[SDP_MAX_MEDIA_TYPES];
+ tinybool nettype_supported[SDP_MAX_NETWORK_TYPES];
+ tinybool addrtype_supported[SDP_MAX_ADDR_TYPES];
+ tinybool transport_supported[SDP_MAX_TRANSPORT_TYPES];
+ tinybool allow_choose[SDP_MAX_CHOOSE_PARAMS];
+ /* Statistics counts */
+ u32 num_builds;
+ u32 num_parses;
+ u32 num_not_sdp_desc;
+ u32 num_invalid_token_order;
+ u32 num_invalid_param;
+ u32 num_no_resource;
+ struct sdp_conf_options *next_p;
+} sdp_conf_options_t;
+
+
+/* Session level SDP info with pointers to media line info. */
+/* Elements here that can only be one of are included directly. Elements */
+/* that can be more than one are pointers. */
+typedef struct {
+ char peerconnection[PC_HANDLE_SIZE];
+ u32 magic_num;
+ sdp_conf_options_t *conf_p;
+ tinybool debug_flag[SDP_MAX_DEBUG_TYPES];
+ char debug_str[SDP_MAX_STRING_LEN+1];
+ u32 debug_id;
+ int32 version; /* version is really a u16 */
+ char owner_name[SDP_MAX_STRING_LEN+1];
+ char owner_sessid[SDP_MAX_STRING_LEN+1];
+ char owner_version[SDP_MAX_STRING_LEN+1];
+ sdp_nettype_e owner_network_type;
+ sdp_addrtype_e owner_addr_type;
+ char owner_addr[SDP_MAX_STRING_LEN+1];
+ char sessname[SDP_MAX_STRING_LEN+1];
+ tinybool sessinfo_found;
+ tinybool uri_found;
+ sdp_conn_t default_conn;
+ sdp_timespec_t *timespec_p;
+ sdp_encryptspec_t encrypt;
+ sdp_bw_t bw;
+ sdp_attr_t *sess_attrs_p;
+
+ /* Info to help with building capability attributes. */
+ u16 cur_cap_num;
+ sdp_mca_t *cur_cap_p;
+ /* Info to help parsing X-cpar attrs. */
+ u16 cap_valid;
+ u16 last_cap_inst;
+ /* Info to help building X-cpar/cpar attrs. */
+ sdp_attr_e last_cap_type;
+
+ /* MCA - Media, connection, and attributes */
+ sdp_mca_t *mca_p;
+ ushort mca_count;
+} sdp_t;
+
+
+/* Token processing table. */
+typedef struct {
+ char *name;
+ sdp_result_e (*parse_func)(sdp_t *sdp_p, u16 level, const char *ptr);
+ sdp_result_e (*build_func)(sdp_t *sdp_p, u16 level, flex_string *fs);
+} sdp_tokenarray_t;
+
+
+/* Attribute processing table. */
+typedef struct {
+ char *name;
+ u16 strlen;
+ sdp_result_e (*parse_func)(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr);
+ sdp_result_e (*build_func)(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs);
+} sdp_attrarray_t;
+
+
+/* Prototypes */
+
+/* sdp_config.c */
+extern void *sdp_init_config(void);
+extern void sdp_appl_debug(void *config_p, sdp_debug_e debug_type,
+ tinybool debug_flag);
+extern void sdp_require_version(void *config_p, tinybool version_required);
+extern void sdp_require_owner(void *config_p, tinybool owner_required);
+extern void sdp_require_session_name(void *config_p,
+ tinybool sess_name_required);
+extern void sdp_require_timespec(void *config_p, tinybool timespec_required);
+extern void sdp_media_supported(void *config_p, sdp_media_e media_type,
+ tinybool media_supported);
+extern void sdp_nettype_supported(void *config_p, sdp_nettype_e nettype,
+ tinybool nettype_supported);
+extern void sdp_addrtype_supported(void *config_p, sdp_addrtype_e addrtype,
+ tinybool addrtype_supported);
+extern void sdp_transport_supported(void *config_p, sdp_transport_e transport,
+ tinybool transport_supported);
+extern void sdp_allow_choose(void *config_p, sdp_choose_param_e param,
+ tinybool choose_allowed);
+
+/* sdp_main.c */
+extern sdp_t *sdp_init_description(const char *peerconnection, void *config_p);
+extern void sdp_debug(sdp_t *sdp_ptr, sdp_debug_e debug_type, tinybool debug_flag);
+extern void sdp_set_string_debug(sdp_t *sdp_ptr, const char *debug_str);
+extern sdp_result_e sdp_parse(sdp_t *sdp_ptr, char **bufp, u16 len);
+extern sdp_result_e sdp_build(sdp_t *sdp_ptr, flex_string *fs);
+extern sdp_t *sdp_copy(sdp_t *sdp_ptr);
+extern sdp_result_e sdp_free_description(sdp_t *sdp_ptr);
+extern void sdp_parse_error(const char *peerconnection, const char *format, ...);
+
+extern const char *sdp_get_result_name(sdp_result_e rc);
+
+
+/* sdp_access.c */
+extern tinybool sdp_version_valid(void *sdp_p);
+extern int32 sdp_get_version(void *sdp_p);
+extern sdp_result_e sdp_set_version(void *sdp_p, int32 version);
+
+extern tinybool sdp_owner_valid(void *sdp_p);
+extern const char *sdp_get_owner_username(void *sdp_p);
+extern const char *sdp_get_owner_sessionid(void *sdp_p);
+extern const char *sdp_get_owner_version(void *sdp_p);
+extern sdp_nettype_e sdp_get_owner_network_type(void *sdp_p);
+extern sdp_addrtype_e sdp_get_owner_address_type(void *sdp_p);
+extern const char *sdp_get_owner_address(void *sdp_p);
+extern sdp_result_e sdp_set_owner_username(void *sdp_p, const char *username);
+extern sdp_result_e sdp_set_owner_sessionid(void *sdp_p, const char *sessid);
+extern sdp_result_e sdp_set_owner_version(void *sdp_p, const char *version);
+extern sdp_result_e sdp_set_owner_network_type(void *sdp_p,
+ sdp_nettype_e network_type);
+extern sdp_result_e sdp_set_owner_address_type(void *sdp_p,
+ sdp_addrtype_e address_type);
+extern sdp_result_e sdp_set_owner_address(void *sdp_p, const char *address);
+
+extern tinybool sdp_session_name_valid(void *sdp_p);
+extern const char *sdp_get_session_name(void *sdp_p);
+extern sdp_result_e sdp_set_session_name(void *sdp_p, const char *sessname);
+
+extern tinybool sdp_timespec_valid(void *sdp_ptr);
+extern const char *sdp_get_time_start(void *sdp_ptr);
+extern const char *sdp_get_time_stop(void *sdp_ptr);
+sdp_result_e sdp_set_time_start(void *sdp_ptr, const char *start_time);
+sdp_result_e sdp_set_time_stop(void *sdp_ptr, const char *stop_time);
+
+extern tinybool sdp_encryption_valid(void *sdp_ptr, u16 level);
+extern sdp_encrypt_type_e sdp_get_encryption_method(void *sdp_ptr, u16 level);
+extern const char *sdp_get_encryption_key(void *sdp_ptr, u16 level);
+extern sdp_result_e sdp_set_encryption_method(void *sdp_ptr, u16 level,
+ sdp_encrypt_type_e method);
+extern sdp_result_e sdp_set_encryption_key(void *sdp_ptr, u16 level,
+ const char *key);
+
+extern tinybool sdp_connection_valid(void *sdp_p, u16 level);
+extern tinybool sdp_bw_line_exists(void *sdp_ptr, u16 level, u16 inst_num);
+extern tinybool sdp_bandwidth_valid(void *sdp_p, u16 level, u16 inst_num);
+extern sdp_nettype_e sdp_get_conn_nettype(void *sdp_p, u16 level);
+extern sdp_addrtype_e sdp_get_conn_addrtype(void *sdp_p, u16 level);
+extern const char *sdp_get_conn_address(void *sdp_p, u16 level);
+
+extern tinybool sdp_is_mcast_addr (void *sdp_ptr, u16 level);
+extern int32 sdp_get_mcast_ttl(void *sdp_ptr, u16 level);
+extern int32 sdp_get_mcast_num_of_addresses(void *sdp_ptr, u16 level);
+
+extern sdp_result_e sdp_set_conn_nettype(void *sdp_p, u16 level,
+ sdp_nettype_e nettype);
+extern sdp_result_e sdp_set_conn_addrtype(void *sdp_p, u16 level,
+ sdp_addrtype_e addrtype);
+extern sdp_result_e sdp_set_conn_address(void *sdp_p, u16 level,
+ const char *address);
+extern sdp_result_e sdp_set_mcast_addr_fields(void *sdp_ptr, u16 level,
+ u16 ttl, u16 num_addr);
+
+extern tinybool sdp_media_line_valid(void *sdp_ptr, u16 level);
+extern u16 sdp_get_num_media_lines(void *sdp_ptr);
+extern sdp_media_e sdp_get_media_type(void *sdp_ptr, u16 level);
+extern sdp_port_format_e sdp_get_media_port_format(void *sdp_ptr, u16 level);
+extern int32 sdp_get_media_portnum(void *sdp_ptr, u16 level);
+extern int32 sdp_get_media_portcount(void *sdp_ptr, u16 level);
+extern int32 sdp_get_media_vpi(void *sdp_ptr, u16 level);
+extern u32 sdp_get_media_vci(void *sdp_ptr, u16 level);
+extern int32 sdp_get_media_vcci(void *sdp_ptr, u16 level);
+extern int32 sdp_get_media_cid(void *sdp_ptr, u16 level);
+extern sdp_transport_e sdp_get_media_transport(void *sdp_ptr, u16 level);
+extern u16 sdp_get_media_num_profiles(void *sdp_ptr, u16 level);
+extern sdp_transport_e sdp_get_media_profile(void *sdp_ptr, u16 level,
+ u16 profile_num);
+extern u16 sdp_get_media_num_payload_types(void *sdp_ptr, u16 level);
+extern u16 sdp_get_media_profile_num_payload_types(void *sdp_ptr, u16 level,
+ u16 profile_num);
+extern u32 sdp_get_media_payload_type(void *sdp_ptr, u16 level,
+ u16 payload_num, sdp_payload_ind_e *indicator);
+extern u32 sdp_get_media_profile_payload_type(void *sdp_ptr, u16 level,
+ u16 prof_num, u16 payload_num, sdp_payload_ind_e *indicator);
+extern sdp_result_e sdp_insert_media_line(void *sdp_ptr, u16 level);
+extern void sdp_delete_media_line(void *sdp_ptr, u16 level);
+extern sdp_result_e sdp_set_media_type(void *sdp_ptr, u16 level,
+ sdp_media_e media);
+extern sdp_result_e sdp_set_media_port_format(void *sdp_ptr, u16 level,
+ sdp_port_format_e port_format);
+extern sdp_result_e sdp_set_media_portnum(void *sdp_ptr, u16 level,
+ int32 portnum, int32 sctpport);
+extern sdp_result_e sdp_set_media_portcount(void *sdp_ptr, u16 level,
+ int32 num_ports);
+extern sdp_result_e sdp_set_media_vpi(void *sdp_ptr, u16 level, int32 vpi);
+extern sdp_result_e sdp_set_media_vci(void *sdp_ptr, u16 level, u32 vci);
+extern sdp_result_e sdp_set_media_vcci(void *sdp_ptr, u16 level, int32 vcci);
+extern sdp_result_e sdp_set_media_cid(void *sdp_ptr, u16 level, int32 cid);
+extern sdp_result_e sdp_set_media_transport(void *sdp_ptr, u16 level,
+ sdp_transport_e transport);
+extern sdp_result_e sdp_add_media_profile(void *sdp_ptr, u16 level,
+ sdp_transport_e profile);
+extern sdp_result_e sdp_add_media_payload_type(void *sdp_ptr, u16 level,
+ u16 payload_type, sdp_payload_ind_e indicator);
+extern sdp_result_e sdp_add_media_profile_payload_type(void *sdp_ptr,
+ u16 level, u16 prof_num, u16 payload_type,
+ sdp_payload_ind_e indicator);
+
+/* sdp_attr_access.c */
+extern sdp_result_e sdp_add_new_attr(void *sdp_ptr, u16 level, u8 cap_num,
+ sdp_attr_e attr_type, u16 *inst_num);
+extern sdp_result_e sdp_copy_attr (void *src_sdp_ptr, void *dst_sdp_ptr,
+ u16 src_level, u16 dst_level,
+ u8 src_cap_num, u8 dst_cap_num,
+ sdp_attr_e src_attr_type, u16 src_inst_num);
+extern sdp_result_e sdp_copy_all_attrs(void *src_sdp_ptr, void *dst_sdp_ptr,
+ u16 src_level, u16 dst_level);
+extern sdp_result_e sdp_attr_num_instances(void *sdp_ptr, u16 level,
+ u8 cap_num, sdp_attr_e attr_type, u16 *num_attr_inst);
+extern sdp_result_e sdp_get_total_attrs(void *sdp_ptr, u16 level, u8 cap_num,
+ u16 *num_attrs);
+extern sdp_result_e sdp_get_attr_type(void *sdp_ptr, u16 level, u8 cap_num,
+ u16 attr_num, sdp_attr_e *attr_type, u16 *inst_num);
+extern sdp_result_e sdp_delete_attr(void *sdp_ptr, u16 level, u8 cap_num,
+ sdp_attr_e attr_type, u16 inst_num);
+extern sdp_result_e sdp_delete_all_attrs(void *sdp_ptr, u16 level, u8 cap_num);
+extern tinybool sdp_attr_valid(void *sdp_ptr, sdp_attr_e attr_type,
+ u16 level, u8 cap_num, u16 inst_num);
+extern const char *sdp_attr_get_simple_string(void *sdp_ptr,
+ sdp_attr_e attr_type, u16 level, u8 cap_num, u16 inst_num);
+extern sdp_result_e sdp_attr_set_simple_string(void *sdp_ptr,
+ sdp_attr_e attr_type, u16 level,
+ u8 cap_num, u16 inst_num, const char *string_parm);
+extern u32 sdp_attr_get_simple_u32(void *sdp_ptr, sdp_attr_e attr_type,
+ u16 level, u8 cap_num, u16 inst_num);
+extern sdp_result_e sdp_attr_set_simple_u32(void *sdp_ptr,
+ sdp_attr_e attr_type, u16 level,
+ u8 cap_num, u16 inst_num, u32 num_parm);
+extern tinybool sdp_attr_get_simple_boolean(void *sdp_ptr,
+ sdp_attr_e attr_type, u16 level, u8 cap_num, u16 inst_num);
+extern sdp_result_e sdp_attr_set_simple_boolean(void *sdp_ptr,
+ sdp_attr_e attr_type, u16 level, u8 cap_num,
+ u16 inst_num, u32 bool_parm);
+extern const char* sdp_attr_get_maxprate(void *sdp_ptr, u16 level,
+ u16 inst_num);
+extern sdp_result_e sdp_attr_set_maxprate(void *sdp_ptr, u16 level,
+ u16 inst_num, const char *string_parm);
+extern sdp_t38_ratemgmt_e sdp_attr_get_t38ratemgmt(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern sdp_result_e sdp_attr_set_t38ratemgmt(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ sdp_t38_ratemgmt_e t38ratemgmt);
+extern sdp_t38_udpec_e sdp_attr_get_t38udpec(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern sdp_result_e sdp_attr_set_t38udpec(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ sdp_t38_udpec_e t38udpec);
+extern sdp_direction_e sdp_get_media_direction(void *sdp_ptr, u16 level,
+ u8 cap_num);
+extern sdp_qos_strength_e sdp_attr_get_qos_strength(void *sdp_ptr, u16 level,
+ u8 cap_num, sdp_attr_e qos_attr, u16 inst_num);
+extern sdp_qos_status_types_e sdp_attr_get_qos_status_type (void *sdp_ptr, u16 level,
+ u8 cap_num, sdp_attr_e qos_attr, u16 inst_num);
+extern sdp_qos_dir_e sdp_attr_get_qos_direction(void *sdp_ptr, u16 level,
+ u8 cap_num, sdp_attr_e qos_attr, u16 inst_num);
+extern tinybool sdp_attr_get_qos_confirm(void *sdp_ptr, u16 level,
+ u8 cap_num, sdp_attr_e qos_attr, u16 inst_num);
+extern sdp_curr_type_e sdp_attr_get_curr_type (void *sdp_ptr, u16 level,
+ u8 cap_num, sdp_attr_e qos_attr, u16 inst_num);
+extern sdp_des_type_e sdp_attr_get_des_type (void *sdp_ptr, u16 level,
+ u8 cap_num, sdp_attr_e qos_attr, u16 inst_num);
+extern sdp_conf_type_e sdp_attr_get_conf_type (void *sdp_ptr, u16 level,
+ u8 cap_num, sdp_attr_e qos_attr, u16 inst_num);
+extern sdp_result_e sdp_attr_set_conf_type (void *sdp_ptr, u16 level,
+ u8 cap_num, sdp_attr_e qos_attr, u16 inst_num,
+ sdp_conf_type_e conf_type);
+extern sdp_result_e sdp_attr_set_des_type (void *sdp_ptr, u16 level,
+ u8 cap_num, sdp_attr_e qos_attr, u16 inst_num,
+ sdp_des_type_e des_type);
+extern sdp_result_e sdp_attr_set_curr_type (void *sdp_ptr, u16 level,
+ u8 cap_num, sdp_attr_e qos_attr, u16 inst_num,
+ sdp_curr_type_e curr_type);
+extern sdp_result_e sdp_attr_set_qos_strength(void *sdp_ptr, u16 level,
+ u8 cap_num, sdp_attr_e qos_attr, u16 inst_num,
+ sdp_qos_strength_e strength);
+extern sdp_result_e sdp_attr_set_qos_direction(void *sdp_ptr, u16 level,
+ u8 cap_num, sdp_attr_e qos_attr, u16 inst_num,
+ sdp_qos_dir_e direction);
+extern sdp_result_e sdp_attr_set_qos_status_type(void *sdp_ptr, u16 level,
+ u8 cap_num, sdp_attr_e qos_attr, u16 inst_num,
+ sdp_qos_status_types_e status_type);
+extern sdp_result_e sdp_attr_set_qos_confirm(void *sdp_ptr, u16 level,
+ u8 cap_num, sdp_attr_e qos_attr, u16 inst_num,
+ tinybool confirm);
+extern sdp_nettype_e sdp_attr_get_subnet_nettype(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern sdp_addrtype_e sdp_attr_get_subnet_addrtype(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern const char *sdp_attr_get_subnet_addr(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern int32 sdp_attr_get_subnet_prefix(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern sdp_result_e sdp_attr_set_subnet_nettype(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ sdp_nettype_e nettype);
+extern sdp_result_e sdp_attr_set_subnet_addrtype(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ sdp_addrtype_e addrtype);
+extern sdp_result_e sdp_attr_set_subnet_addr(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ const char *addr);
+extern sdp_result_e sdp_attr_set_subnet_prefix(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ int32 prefix);
+extern tinybool sdp_attr_rtpmap_payload_valid(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 *inst_num, u16 payload_type);
+extern u16 sdp_attr_get_rtpmap_payload_type(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern const char *sdp_attr_get_rtpmap_encname(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern u32 sdp_attr_get_rtpmap_clockrate(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern u16 sdp_attr_get_rtpmap_num_chan(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern sdp_result_e sdp_attr_set_rtpmap_payload_type(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u16 payload_num);
+extern sdp_result_e sdp_attr_set_rtpmap_encname(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, const char *encname);
+extern sdp_result_e sdp_attr_set_rtpmap_clockrate(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u32 clockrate);
+extern sdp_result_e sdp_attr_set_rtpmap_num_chan(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u16 num_chan);
+extern tinybool sdp_attr_sprtmap_payload_valid(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 *inst_num, u16 payload_type);
+extern u16 sdp_attr_get_sprtmap_payload_type(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern const char *sdp_attr_get_sprtmap_encname(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern u32 sdp_attr_get_sprtmap_clockrate(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern u16 sdp_attr_get_sprtmap_num_chan(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern sdp_result_e sdp_attr_set_sprtmap_payload_type(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u16 payload_num);
+extern sdp_result_e sdp_attr_set_sprtmap_encname(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, const char *encname);
+extern sdp_result_e sdp_attr_set_sprtmap_clockrate(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u16 clockrate);
+extern sdp_result_e sdp_attr_set_sprtmap_num_chan(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u16 num_chan);
+extern tinybool sdp_attr_fmtp_payload_valid(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 *inst_num, u16 payload_type);
+extern u16 sdp_attr_get_fmtp_payload_type(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern sdp_ne_res_e sdp_attr_fmtp_is_range_set(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u8 low_val, u8 high_val);
+extern tinybool sdp_attr_fmtp_valid(void *sdp_ptr, u16 level, u8 cap_num,
+ u16 inst_num, u16 appl_maxval, u32* evt_array);
+extern sdp_result_e sdp_attr_set_fmtp_payload_type(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u16 payload_num);
+extern sdp_result_e sdp_attr_get_fmtp_range(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u32 *bmap);
+extern sdp_result_e sdp_attr_set_fmtp_range(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u8 low_val, u8 high_val);
+extern sdp_result_e sdp_attr_set_fmtp_bitmap(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u32 *bmap, u32 maxval);
+extern sdp_result_e sdp_attr_clear_fmtp_range(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u8 low_val, u8 high_val);
+extern sdp_ne_res_e sdp_attr_compare_fmtp_ranges(void *src_sdp_ptr,
+ void *dst_sdp_ptr, u16 src_level, u16 dst_level,
+ u8 src_cap_num, u8 dst_cap_num, u16 src_inst_num,
+ u16 dst_inst_num);
+extern sdp_result_e sdp_attr_copy_fmtp_ranges(void *src_sdp_ptr,
+ void *dst_sdp_ptr, u16 src_level, u16 dst_level,
+ u8 src_cap_num, u8 dst_cap_num, u16 src_inst_num,
+ u16 dst_inst_num);
+extern sdp_result_e sdp_attr_set_fmtp_annexa (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ tinybool annexa);
+extern sdp_result_e sdp_attr_set_fmtp_mode(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u32 mode);
+extern u32 sdp_attr_get_fmtp_mode_for_payload_type (void *sdp_ptr, u16 level,
+ u8 cap_num, u32 payload_type);
+
+extern sdp_result_e sdp_attr_set_fmtp_annexb (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ tinybool annexb);
+
+extern sdp_result_e sdp_attr_set_fmtp_bitrate_type (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u32 bitrate);
+extern sdp_result_e sdp_attr_set_fmtp_cif (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u16 cif);
+extern sdp_result_e sdp_attr_set_fmtp_qcif (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u16 qcif);
+extern sdp_result_e sdp_attr_set_fmtp_sqcif (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u16 sqcif);
+extern sdp_result_e sdp_attr_set_fmtp_cif4 (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u16 cif4);
+extern sdp_result_e sdp_attr_set_fmtp_cif16 (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u16 cif16);
+extern sdp_result_e sdp_attr_set_fmtp_maxbr (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u16 maxbr);
+extern sdp_result_e sdp_attr_set_fmtp_max_average_bitrate (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u32 maxaveragebitrate);
+extern sdp_result_e sdp_attr_set_fmtp_usedtx (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ tinybool usedtx);
+extern sdp_result_e sdp_attr_set_fmtp_stereo (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ tinybool stereo);
+extern sdp_result_e sdp_attr_set_fmtp_useinbandfec (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ tinybool useinbandfec);
+extern sdp_result_e sdp_attr_set_fmtp_maxcodedaudiobandwidth (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ const char *maxcodedaudiobandwidth);
+extern sdp_result_e sdp_attr_set_fmtp_cbr (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ tinybool cbr);
+extern sdp_result_e sdp_attr_set_fmtp_custom (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u16 custom_x, u16 custom_y,
+ u16 custom_mpi);
+extern sdp_result_e sdp_attr_set_fmtp_par (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u16 par_width, u16 par_height);
+extern sdp_result_e sdp_attr_set_fmtp_bpp (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u16 bpp);
+extern sdp_result_e sdp_attr_set_fmtp_hrd (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u16 hrd);
+
+extern sdp_result_e sdp_attr_set_fmtp_h263_num_params (void *sdp_ptr,
+ int16 level,
+ u8 cap_num,
+ u16 inst_num,
+ int16 profile,
+ u16 h263_level,
+ tinybool interlace);
+
+extern sdp_result_e sdp_attr_set_fmtp_profile_level_id (void *sdp_ptr,
+ u16 level,
+ u8 cap_num,
+ u16 inst_num,
+ const char *prof_id);
+
+extern sdp_result_e sdp_attr_set_fmtp_parameter_sets (void *sdp_ptr,
+ u16 level,
+ u8 cap_num,
+ u16 inst_num,
+ const char *parameter_sets);
+
+extern sdp_result_e sdp_attr_set_fmtp_deint_buf_req (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u32 deint_buf_req);
+
+extern sdp_result_e sdp_attr_set_fmtp_init_buf_time (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u32 init_buf_time);
+
+extern sdp_result_e sdp_attr_set_fmtp_max_don_diff (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u32 max_don_diff);
+
+extern sdp_result_e sdp_attr_set_fmtp_interleaving_depth (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u16 interleaving_depth);
+
+extern sdp_result_e sdp_attr_set_fmtp_pack_mode (void *sdp_ptr,
+ u16 level,
+ u8 cap_num,
+ u16 inst_num,
+ u16 pack_mode);
+
+extern sdp_result_e sdp_attr_set_fmtp_level_asymmetry_allowed (void *sdp_ptr,
+ u16 level,
+ u8 cap_num,
+ u16 inst_num,
+ u16 level_asymmetry_allowed);
+
+extern sdp_result_e sdp_attr_set_fmtp_redundant_pic_cap (void *sdp_ptr,
+ u16 level,
+ u8 cap_num,
+ u16 inst_num,
+ tinybool redundant_pic_cap);
+
+extern sdp_result_e sdp_attr_set_fmtp_max_mbps (void *sdp_ptr,
+ u16 level,
+ u8 cap_num,
+ u16 inst_num,
+ u32 max_mbps);
+
+extern sdp_result_e sdp_attr_set_fmtp_max_fs (void *sdp_ptr,
+ u16 level,
+ u8 cap_num,
+ u16 inst_num,
+ u32 max_fs);
+
+extern sdp_result_e sdp_attr_set_fmtp_max_cpb (void *sdp_ptr,
+ u16 level,
+ u8 cap_num,
+ u16 inst_num,
+ u32 max_cpb);
+
+extern sdp_result_e sdp_attr_set_fmtp_max_dpb (void *sdp_ptr,
+ u16 level,
+ u8 cap_num,
+ u16 inst_num,
+ u32 max_dpb);
+
+extern sdp_result_e sdp_attr_set_fmtp_max_br (void *sdp_ptr,
+ u16 level,
+ u8 cap_num,
+ u16 inst_num,
+ u32 max_br);
+
+extern sdp_result_e sdp_attr_set_fmtp_max_rcmd_nalu_size (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u32 max_rcmd_nalu_size);
+
+extern sdp_result_e sdp_attr_set_fmtp_deint_buf_cap (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u32 deint_buf_cap);
+
+extern sdp_result_e sdp_attr_set_fmtp_h264_parameter_add (void *sdp_ptr,
+ u16 level,
+ u8 cap_num,
+ u16 inst_num,
+ tinybool parameter_add);
+
+extern sdp_result_e sdp_attr_set_fmtp_h261_annex_params (void *sdp_ptr,
+ u16 level,
+ u8 cap_num,
+ u16 inst_num,
+ tinybool annex_d);
+
+extern sdp_result_e sdp_attr_set_fmtp_h263_annex_params (void *sdp_ptr,
+ u16 level,
+ u8 cap_num,
+ u16 inst_num,
+ tinybool annex_f,
+ tinybool annex_i,
+ tinybool annex_j,
+ tinybool annex_t,
+ u16 annex_k_val,
+ u16 annex_n_val,
+ u16 annex_p_val_picture_resize,
+ u16 annex_p_val_warp);
+
+
+/* get routines */
+extern int32 sdp_attr_get_fmtp_bitrate_type (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+
+extern int32 sdp_attr_get_fmtp_cif (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern int32 sdp_attr_get_fmtp_qcif (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern int32 sdp_attr_get_fmtp_sqcif (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern int32 sdp_attr_get_fmtp_cif4 (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern int32 sdp_attr_get_fmtp_cif16 (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern int32 sdp_attr_get_fmtp_maxbr (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern sdp_result_e sdp_attr_get_fmtp_max_average_bitrate (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u32* val);
+extern sdp_result_e sdp_attr_get_fmtp_usedtx (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, tinybool* val);
+extern sdp_result_e sdp_attr_get_fmtp_stereo (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, tinybool* val);
+extern sdp_result_e sdp_attr_get_fmtp_useinbandfec (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, tinybool* val);
+extern char* sdp_attr_get_fmtp_maxcodedaudiobandwidth (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern sdp_result_e sdp_attr_get_fmtp_cbr (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, tinybool* val);
+extern sdp_result_e sdp_attr_set_fmtp_streams (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u32 streams);
+extern sdp_result_e sdp_attr_get_fmtp_streams (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u32* val);
+extern sdp_result_e sdp_attr_get_fmtp_data_channel_protocol (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, char* protocol);
+extern sdp_result_e sdp_attr_set_fmtp_data_channel_protocol (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ const char *protocol);
+extern int32 sdp_attr_get_fmtp_custom_x (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern int32 sdp_attr_get_fmtp_custom_y (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern int32 sdp_attr_get_fmtp_custom_mpi (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern int32 sdp_attr_get_fmtp_par_width (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern int32 sdp_attr_get_fmtp_par_height (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern int32 sdp_attr_get_fmtp_bpp (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern int32 sdp_attr_get_fmtp_hrd (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern int32 sdp_attr_get_fmtp_profile (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern int32 sdp_attr_get_fmtp_level (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern tinybool sdp_attr_get_fmtp_interlace (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern tinybool sdp_attr_get_fmtp_annex_d (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern tinybool sdp_attr_get_fmtp_annex_f (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern tinybool sdp_attr_get_fmtp_annex_i (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern tinybool sdp_attr_get_fmtp_annex_j (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern tinybool sdp_attr_get_fmtp_annex_t (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern int32 sdp_attr_get_fmtp_annex_k_val (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern int32 sdp_attr_get_fmtp_annex_n_val (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+
+extern int32 sdp_attr_get_fmtp_annex_p_picture_resize (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern int32 sdp_attr_get_fmtp_annex_p_warp (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+
+/* H.264 codec specific params */
+
+extern const char *sdp_attr_get_fmtp_profile_id(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern const char *sdp_attr_get_fmtp_param_sets(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern sdp_result_e sdp_attr_get_fmtp_pack_mode (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u16 *val);
+
+extern sdp_result_e sdp_attr_get_fmtp_level_asymmetry_allowed (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u16 *val);
+
+extern sdp_result_e sdp_attr_get_fmtp_interleaving_depth (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u16 *val);
+extern sdp_result_e sdp_attr_get_fmtp_max_don_diff (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u32 *val);
+
+/* The following four H.264 parameters that require special handling as
+ * the values range from 0 - 4294967295
+ */
+extern sdp_result_e sdp_attr_get_fmtp_deint_buf_req (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u32 *val);
+extern sdp_result_e sdp_attr_get_fmtp_deint_buf_cap (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u32 *val);
+extern sdp_result_e sdp_attr_get_fmtp_init_buf_time (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u32 *val);
+extern sdp_result_e sdp_attr_get_fmtp_max_rcmd_nalu_size (void *sdp_ptr,
+ u16 level, u8 cap_num,
+ u16 inst_num, u32 *val);
+
+
+extern sdp_result_e sdp_attr_get_fmtp_max_mbps (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u32 *val);
+extern sdp_result_e sdp_attr_get_fmtp_max_fs (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u32 *val);
+extern sdp_result_e sdp_attr_get_fmtp_max_cpb (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u32 *val);
+extern sdp_result_e sdp_attr_get_fmtp_max_dpb (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u32 *val);
+extern sdp_result_e sdp_attr_get_fmtp_max_br (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u32 *val);
+extern tinybool sdp_attr_fmtp_is_redundant_pic_cap (void *sdp_ptr, u16 level,
+ u8 cap_num,
+ u16 inst_num);
+extern tinybool sdp_attr_fmtp_is_parameter_add (void *sdp_ptr, u16 level,
+ u8 cap_num,
+ u16 inst_num);
+extern tinybool sdp_attr_fmtp_is_annexa_set (void *sdp_ptr, u16 level,
+ u8 cap_num,
+ u16 inst_num);
+
+extern tinybool sdp_attr_fmtp_is_annexb_set (void *sdp_ptr, u16 level,
+ u8 cap_num,
+ u16 inst_num);
+
+extern sdp_fmtp_format_type_e sdp_attr_fmtp_get_fmtp_format (void *sdp_ptr, u16 level, u8 cap_num,
+ u16 inst_num);
+
+extern u16 sdp_attr_get_pccodec_num_payload_types(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern u16 sdp_attr_get_pccodec_payload_type(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u16 payload_num);
+extern sdp_result_e sdp_attr_add_pccodec_payload_type(void *sdp_ptr,
+ u16 level, u8 cap_num,
+ u16 inst_num, u16 payload_type);
+extern u16 sdp_attr_get_xcap_first_cap_num(void *sdp_ptr, u16 level,
+ u16 inst_num);
+extern sdp_media_e sdp_attr_get_xcap_media_type(void *sdp_ptr, u16 level,
+ u16 inst_num);
+extern sdp_transport_e sdp_attr_get_xcap_transport_type(void *sdp_ptr,
+ u16 level, u16 inst_num);
+extern u16 sdp_attr_get_xcap_num_payload_types(void *sdp_ptr, u16 level,
+ u16 inst_num);
+extern u16 sdp_attr_get_xcap_payload_type(void *sdp_ptr, u16 level,
+ u16 inst_num, u16 payload_num,
+ sdp_payload_ind_e *indicator);
+extern sdp_result_e sdp_attr_set_xcap_media_type(void *sdp_ptr, u16 level,
+ u16 inst_num, sdp_media_e media);
+extern sdp_result_e sdp_attr_set_xcap_transport_type(void *sdp_ptr, u16 level,
+ u16 inst_num, sdp_transport_e transport);
+extern sdp_result_e sdp_attr_add_xcap_payload_type(void *sdp_ptr, u16 level,
+ u16 inst_num, u16 payload_type,
+ sdp_payload_ind_e indicator);
+extern u16 sdp_attr_get_cdsc_first_cap_num(void *sdp_ptr, u16 level,
+ u16 inst_num);
+extern sdp_media_e sdp_attr_get_cdsc_media_type(void *sdp_ptr, u16 level,
+ u16 inst_num);
+extern sdp_transport_e sdp_attr_get_cdsc_transport_type(void *sdp_ptr,
+ u16 level, u16 inst_num);
+extern u16 sdp_attr_get_cdsc_num_payload_types(void *sdp_ptr, u16 level,
+ u16 inst_num);
+extern u16 sdp_attr_get_cdsc_payload_type(void *sdp_ptr, u16 level,
+ u16 inst_num, u16 payload_num,
+ sdp_payload_ind_e *indicator);
+extern sdp_result_e sdp_attr_set_cdsc_media_type(void *sdp_ptr, u16 level,
+ u16 inst_num, sdp_media_e media);
+extern sdp_result_e sdp_attr_set_cdsc_transport_type(void *sdp_ptr, u16 level,
+ u16 inst_num, sdp_transport_e transport);
+extern sdp_result_e sdp_attr_add_cdsc_payload_type(void *sdp_ptr, u16 level,
+ u16 inst_num, u16 payload_type,
+ sdp_payload_ind_e indicator);
+extern tinybool sdp_media_dynamic_payload_valid (void *sdp_ptr, u16 payload_type,
+ u16 m_line);
+
+extern sdp_result_e sdp_attr_set_rtr_confirm (void *, u16 , \
+ u8 ,u16 ,tinybool );
+extern tinybool sdp_attr_get_rtr_confirm (void *, u16, u8, u16);
+
+extern tinybool sdp_attr_get_silencesupp_enabled(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern u16 sdp_attr_get_silencesupp_timer(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ tinybool *null_ind);
+extern sdp_silencesupp_pref_e sdp_attr_get_silencesupp_pref(void *sdp_ptr,
+ u16 level,
+ u8 cap_num,
+ u16 inst_num);
+extern sdp_silencesupp_siduse_e sdp_attr_get_silencesupp_siduse(void *sdp_ptr,
+ u16 level,
+ u8 cap_num,
+ u16 inst_num);
+extern u8 sdp_attr_get_silencesupp_fxnslevel(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ tinybool *null_ind);
+extern sdp_result_e sdp_attr_set_silencesupp_enabled(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ tinybool enable);
+extern sdp_result_e sdp_attr_set_silencesupp_timer(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u16 value,
+ tinybool null_ind);
+extern sdp_result_e sdp_attr_set_silencesupp_pref(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ sdp_silencesupp_pref_e pref);
+extern sdp_result_e sdp_attr_set_silencesupp_siduse(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ sdp_silencesupp_siduse_e siduse);
+extern sdp_result_e sdp_attr_set_silencesupp_fxnslevel(void *sdp_ptr,
+ u16 level,
+ u8 cap_num,
+ u16 inst_num,
+ u16 value,
+ tinybool null_ind);
+
+extern sdp_mediadir_role_e sdp_attr_get_comediadir_role(void *sdp_ptr,
+ u16 level, u8 cap_num,
+ u16 inst_num);
+extern sdp_result_e sdp_attr_set_comediadir_role(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ sdp_mediadir_role_e role);
+
+extern sdp_result_e sdp_delete_all_media_direction_attrs (void *sdp_ptr,
+ u16 level);
+
+extern u16 sdp_attr_get_mptime_num_intervals(
+ void *sdp_ptr, u16 level, u8 cap_num, u16 inst_num);
+extern u16 sdp_attr_get_mptime_interval(
+ void *sdp_ptr, u16 level, u8 cap_num, u16 inst_num, u16 interval_num);
+extern sdp_result_e sdp_attr_add_mptime_interval(
+ void *sdp_ptr, u16 level, u8 cap_num, u16 inst_num, u16 interval);
+
+
+extern sdp_result_e sdp_delete_bw_line (void *sdp_ptr, u16 level, u16 inst_num);
+extern sdp_result_e sdp_copy_all_bw_lines(void *src_sdp_ptr, void *dst_sdp_ptr,
+ u16 src_level, u16 dst_level);
+extern sdp_bw_modifier_e sdp_get_bw_modifier(void *sdp_ptr, u16 level,
+ u16 inst_num);
+extern int32 sdp_get_bw_value(void *sdp_ptr, u16 level, u16 inst_num);
+extern int32 sdp_get_num_bw_lines (void *sdp_ptr, u16 level);
+
+extern sdp_result_e sdp_add_new_bw_line(void *sdp_ptr, u16 level,
+ sdp_bw_modifier_e bw_modifier, u16 *inst_num);
+extern sdp_result_e sdp_set_bw(void *sdp_ptr, u16 level, u16 inst_num,
+ sdp_bw_modifier_e value, u32 bw_val);
+
+extern sdp_group_attr_e sdp_get_group_attr(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern sdp_result_e sdp_set_group_attr(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ sdp_group_attr_e value);
+
+extern const char* sdp_attr_get_x_sidout (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+
+extern sdp_result_e sdp_attr_set_x_sidout (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ const char *sidout);
+
+extern const char* sdp_attr_get_x_sidin (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+
+extern sdp_result_e sdp_attr_set_x_sidin (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ const char *sidin);
+
+extern const char* sdp_attr_get_x_confid (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+
+extern sdp_result_e sdp_attr_set_x_confid (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ const char *confid);
+
+extern sdp_result_e sdp_attr_set_ice_candidate(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, const char *ice_candidate);
+
+extern u16 sdp_get_group_num_id(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern sdp_result_e sdp_set_group_num_id(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u16 group_num_id);
+
+extern int32 sdp_get_group_id(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u16 id_num);
+extern sdp_result_e sdp_set_group_id (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u16 group_id);
+
+
+extern int32 sdp_get_mid_value(void *sdp_ptr, u16 level);
+extern sdp_result_e sdp_set_mid_value(void *sdp_ptr, u16 level, u32 mid_val);
+
+extern sdp_result_e sdp_set_source_filter(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ sdp_src_filter_mode_e mode,
+ sdp_nettype_e nettype,
+ sdp_addrtype_e addrtype,
+ const char *dest_addr,
+ const char *src_addr);
+extern sdp_result_e sdp_include_new_filter_src_addr(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ const char *src_addr);
+extern sdp_src_filter_mode_e sdp_get_source_filter_mode(void *sdp_ptr,
+ u16 level, u8 cap_num,
+ u16 inst_num);
+extern sdp_result_e sdp_get_filter_destination_attributes(void *sdp_ptr,
+ u16 level, u8 cap_num,
+ u16 inst_num,
+ sdp_nettype_e *nettype,
+ sdp_addrtype_e *addrtype,
+ char *dest_addr);
+extern int32 sdp_get_filter_source_address_count(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num);
+extern sdp_result_e sdp_get_filter_source_address (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u16 src_addr_id,
+ char *src_addr);
+
+extern sdp_result_e sdp_set_rtcp_unicast_mode(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ sdp_rtcp_unicast_mode_e mode);
+extern sdp_rtcp_unicast_mode_e sdp_get_rtcp_unicast_mode(void *sdp_ptr,
+ u16 level, u8 cap_num,
+ u16 inst_num);
+
+void sdp_crypto_debug(char *buffer, ulong length_bytes);
+char * sdp_debug_msg_filter(char *buffer, ulong length_bytes);
+
+extern int32
+sdp_attr_get_sdescriptions_tag(void *sdp_ptr,
+ u16 level,
+ u8 cap_num,
+ u16 inst_num);
+
+extern sdp_srtp_crypto_suite_t
+sdp_attr_get_sdescriptions_crypto_suite(void *sdp_ptr,
+ u16 level,
+ u8 cap_num,
+ u16 inst_num);
+
+extern const char*
+sdp_attr_get_sdescriptions_key(void *sdp_ptr,
+ u16 level,
+ u8 cap_num,
+ u16 inst_num);
+
+extern const char*
+sdp_attr_get_sdescriptions_salt(void *sdp_ptr,
+ u16 level,
+ u8 cap_num,
+ u16 inst_num);
+
+extern const char*
+sdp_attr_get_sdescriptions_lifetime(void *sdp_ptr,
+ u16 level,
+ u8 cap_num,
+ u16 inst_num);
+
+extern sdp_result_e
+sdp_attr_get_sdescriptions_mki(void *sdp_ptr,
+ u16 level,
+ u8 cap_num,
+ u16 inst_num,
+ const char **mki_value,
+ u16 *mki_length);
+
+extern const char*
+sdp_attr_get_sdescriptions_session_params(void *sdp_ptr,
+ u16 level,
+ u8 cap_num,
+ u16 inst_num);
+
+extern unsigned char
+sdp_attr_get_sdescriptions_key_size(void *sdp_ptr,
+ u16 level,
+ u8 cap_num,
+ u16 inst_num);
+
+extern unsigned char
+sdp_attr_get_sdescriptions_salt_size(void *sdp_ptr,
+ u16 level,
+ u8 cap_num,
+ u16 inst_num);
+
+extern unsigned long
+sdp_attr_get_srtp_crypto_selection_flags(void *sdp_ptr,
+ u16 level,
+ u8 cap_num,
+ u16 inst_num);
+
+extern sdp_result_e
+sdp_attr_set_sdescriptions_tag(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ int32 tag_num);
+
+extern sdp_result_e
+sdp_attr_set_sdescriptions_crypto_suite(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ sdp_srtp_crypto_suite_t crypto_suite);
+
+extern sdp_result_e
+sdp_attr_set_sdescriptions_key(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ char *key);
+
+extern sdp_result_e
+sdp_attr_set_sdescriptions_salt(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ char *salt);
+
+extern sdp_result_e
+sdp_attr_set_sdescriptions_lifetime(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ char *lifetime);
+
+extern sdp_result_e
+sdp_attr_set_sdescriptions_mki(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ char *mki_value,
+ u16 mki_length);
+
+extern sdp_result_e
+sdp_attr_set_sdescriptions_key_size(void *sdp_ptr,
+ u16 level,
+ u8 cap_num,
+ u16 inst_num,
+ unsigned char key_size);
+
+extern sdp_result_e
+sdp_attr_set_sdescriptions_salt_size(void *sdp_ptr,
+ u16 level,
+ u8 cap_num,
+ u16 inst_num,
+ unsigned char salt_size);
+
+sdp_result_e
+sdp_attr_get_ice_attribute (void *sdp_ptr, u16 level,
+ u8 cap_num, sdp_attr_e sdp_attr, u16 inst_num,
+ char **out);
+sdp_result_e
+sdp_attr_set_ice_attribute(void *sdp_ptr, u16 level,
+ u8 cap_num, sdp_attr_e sdp_attr, u16 inst_num, const char *ice_attrib);
+
+sdp_result_e
+sdp_attr_get_rtcp_mux_attribute (void *sdp_ptr, u16 level,
+ u8 cap_num, sdp_attr_e sdp_attr, u16 inst_num,
+ tinybool *rtcp_mux);
+
+sdp_result_e
+sdp_attr_set_rtcp_mux_attribute(void *sdp_ptr, u16 level,
+ u8 cap_num, sdp_attr_e sdp_attr, u16 inst_num, const tinybool rtcp_mux);
+
+sdp_result_e
+sdp_attr_get_dtls_fingerprint_attribute (void *sdp_ptr, u16 level,
+ u8 cap_num, sdp_attr_e sdp_attr, u16 inst_num,
+ char **out);
+
+sdp_result_e
+sdp_attr_set_dtls_fingerprint_attribute(void *sdp_ptr, u16 level,
+ u8 cap_num, sdp_attr_e sdp_attr, u16 inst_num, const char *dtls_fingerprint);
+
+#endif /* _SDP_H_ */
diff --git a/libs/sipcc/core/sdp/sdp_access.c b/libs/sipcc/core/sdp/sdp_access.c
new file mode 100644
index 0000000000..76251a51f2
--- /dev/null
+++ b/libs/sipcc/core/sdp/sdp_access.c
@@ -0,0 +1,2847 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "sdp_os_defs.h"
+#include "sdp.h"
+#include "sdp_private.h"
+#include "ccsip_sdp.h"
+#include "rtp_defs.h"
+#include "CSFLog.h"
+
+//static const char* logTag = "sdp_access";
+
+/* Function: sdp_find_media_level
+ * Description: Find and return a pointer to the specified media level,
+ * if it exists.
+ * Note: This is not an API for the application but an internal
+ * routine used by the SDP library.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The media level to find.
+ * Returns: Pointer to the media level or NULL if not found.
+ */
+sdp_mca_t *sdp_find_media_level (sdp_t *sdp_p, u16 level)
+{
+ int i;
+ sdp_mca_t *mca_p = NULL;
+
+ if ((level >= 1) && (level <= sdp_p->mca_count)) {
+ for (i=1, mca_p = sdp_p->mca_p;
+ ((i < level) && (mca_p != NULL));
+ mca_p = mca_p->next_p, i++) {
+
+ /*sa_ignore EMPTYLOOP*/
+ ; /* Do nothing. */
+ }
+ }
+
+ return (mca_p);
+}
+
+/* Function: sdp_version_valid
+ * Description: Returns true or false depending on whether the version
+ * set for this SDP is valid. Currently the only valid
+ * version is 0.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * Returns: TRUE or FALSE.
+ */
+tinybool sdp_version_valid (void *sdp_ptr)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (FALSE);
+ }
+
+ if (sdp_p->version == SDP_INVALID_VALUE) {
+ return (FALSE);
+ } else {
+ return (TRUE);
+ }
+}
+
+/* Function: sdp_get_version
+ * Description: Returns the version value set for the given SDP.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * Returns: Version value.
+ */
+int32 sdp_get_version (void *sdp_ptr)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (0);
+ }
+
+ return (sdp_p->version);
+}
+
+/* Function: sdp_set_version
+ * Description: Sets the value of the version parameter for the v= version
+ * token line.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * version Version to set.
+ * Returns: SDP_SUCCESS
+ */
+sdp_result_e sdp_set_version (void *sdp_ptr, int32 version)
+{
+ sdp_t *sdp_p = (sdp_t*)sdp_ptr;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ sdp_p->version = version;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_owner_valid
+ * Description: Returns true or false depending on whether the owner
+ * token line has been defined for this SDP.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * Returns: TRUE or FALSE.
+ */
+tinybool sdp_owner_valid (void *sdp_ptr)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (FALSE);
+ }
+
+ if ((sdp_p->owner_name[0] == '\0') ||
+ (sdp_p->owner_network_type == SDP_NT_INVALID) ||
+ (sdp_p->owner_addr_type == SDP_AT_INVALID) ||
+ (sdp_p->owner_addr[0] == '\0')) {
+ return (FALSE);
+ } else {
+ return (TRUE);
+ }
+}
+
+/* Function: sdp_get_owner_username
+ * Description: Returns a pointer to the value of the username parameter
+ * from the o= owner token line. Value is returned as a
+ * const ptr and so cannot be modified by the application.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * Returns: Version value.
+ */
+const char *sdp_get_owner_username (void *sdp_ptr)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (NULL);
+ }
+
+ return (sdp_p->owner_name);
+}
+
+/* Function: sdp_get_owner_sessionid
+ * Description: Returns the session id parameter from the o= owner token
+ * line. Because the value may be larger than 32 bits, this
+ * parameter is returned as a string, though has been verified
+ * to be numeric. Value is returned as a const ptr and so
+ * cannot be modified by the application.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * Returns: Ptr to owner session id or NULL.
+ */
+const char *sdp_get_owner_sessionid (void *sdp_ptr)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (NULL);
+ }
+
+ return (sdp_p->owner_sessid);
+}
+
+/* Function: sdp_get_owner_version
+ * Description: Returns the version parameter from the o= owner token
+ * line. Because the value may be larger than 32 bits, this
+ * parameter is returned as a string, though has been verified
+ * to be numeric. Value is returned as a const ptr and so
+ * cannot be modified by the application.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * Returns: Ptr to owner version or NULL.
+ */
+const char *sdp_get_owner_version (void *sdp_ptr)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (NULL);
+ }
+
+ return (sdp_p->owner_version);
+}
+
+/* Function: sdp_get_owner_network_type
+ * Description: Returns the network type parameter from the o= owner token
+ * line. If network type has not been set SDP_NT_INVALID will
+ * be returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * Returns: Network type or SDP_NT_INVALID.
+ */
+sdp_nettype_e sdp_get_owner_network_type (void *sdp_ptr)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_NT_INVALID);
+ }
+
+ return (sdp_p->owner_network_type);
+}
+
+/* Function: sdp_get_owner_address_type
+ * Description: Returns the address type parameter from the o= owner token
+ * line. If address type has not been set SDP_AT_INVALID will
+ * be returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * Returns: Address type or SDP_AT_INVALID.
+ */
+sdp_addrtype_e sdp_get_owner_address_type (void *sdp_ptr)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_AT_INVALID);
+ }
+
+ return (sdp_p->owner_addr_type);
+}
+
+/* Function: sdp_get_owner_address
+ * Description: Returns the address parameter from the o= owner token
+ * line. Value is returned as a const ptr and so
+ * cannot be modified by the application.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * Returns: Ptr to address or NULL.
+ */
+const char *sdp_get_owner_address (void *sdp_ptr)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (NULL);
+ }
+
+ return (sdp_p->owner_addr);
+}
+
+/* Function: sdp_set_owner_username
+ * Description: Sets the value of the username parameter for the o= owner
+ * token line. The string is copied into the SDP structure
+ * so application memory will not be referenced by the SDP lib.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * username Ptr to the username string.
+ * Returns: SDP_SUCCESS
+ */
+sdp_result_e sdp_set_owner_username (void *sdp_ptr, const char *username)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ sstrncpy(sdp_p->owner_name, username, sizeof(sdp_p->owner_name));
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_set_owner_username
+ * Description: Sets the value of the session id parameter for the o= owner
+ * token line. The string is copied into the SDP structure
+ * so application memory will not be referenced by the SDP lib.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * sessionid Ptr to the sessionid string.
+ * Returns: SDP_SUCCESS
+ */
+sdp_result_e sdp_set_owner_sessionid (void *sdp_ptr, const char *sessionid)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ sstrncpy(sdp_p->owner_sessid, sessionid, sizeof(sdp_p->owner_sessid));
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_set_owner_version
+ * Description: Sets the value of the version parameter for the o= owner
+ * token line. The string is copied into the SDP structure
+ * so application memory will not be referenced by the SDP lib.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * version Ptr to the version string.
+ * Returns: SDP_SUCCESS
+ */
+sdp_result_e sdp_set_owner_version (void *sdp_ptr, const char *version)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ sstrncpy(sdp_p->owner_version, version, sizeof(sdp_p->owner_version));
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_set_owner_network_type
+ * Description: Sets the value of the network type parameter for the o= owner
+ * token line.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * network_type Network type for the owner line.
+ * Returns: SDP_SUCCESS
+ */
+sdp_result_e sdp_set_owner_network_type (void *sdp_ptr,
+ sdp_nettype_e network_type)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ sdp_p->owner_network_type = network_type;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_set_owner_address_type
+ * Description: Sets the value of the address type parameter for the o= owner
+ * token line.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * address_type Address type for the owner line.
+ * Returns: SDP_SUCCESS
+ */
+sdp_result_e sdp_set_owner_address_type (void *sdp_ptr,
+ sdp_addrtype_e address_type)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ sdp_p->owner_addr_type = address_type;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_set_owner_address
+ * Description: Sets the value of the address parameter for the o= owner
+ * token line. The string is copied into the SDP structure
+ * so application memory will not be referenced by the SDP lib.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * version Ptr to the version string.
+ * Returns: SDP_SUCCESS
+ */
+sdp_result_e sdp_set_owner_address (void *sdp_ptr, const char *address)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ sstrncpy(sdp_p->owner_addr, address, sizeof(sdp_p->owner_addr));
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_session_name_valid
+ * Description: Returns true or false depending on whether the session name
+ * s= token line has been defined for this SDP.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * Returns: TRUE or FALSE.
+ */
+tinybool sdp_session_name_valid (void *sdp_ptr)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (FALSE);
+ }
+
+ if (sdp_p->sessname[0] == '\0') {
+ return (FALSE);
+ } else {
+ return (TRUE);
+ }
+}
+
+/* Function: sdp_get_session_name
+ * Description: Returns the session name parameter from the s= session
+ * name token line. Value is returned as a const ptr and so
+ * cannot be modified by the application.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * Returns: Ptr to session name or NULL.
+ */
+const char *sdp_get_session_name (void *sdp_ptr)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (NULL);
+ }
+
+ return (sdp_p->sessname);
+}
+
+/* Function: sdp_set_session_name
+ * Description: Sets the value of the session name parameter for the s=
+ * session name token line. The string is copied into the
+ * SDP structure so application memory will not be
+ * referenced by the SDP lib.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * sessname Ptr to the session name string.
+ * Returns: SDP_SUCCESS
+ */
+sdp_result_e sdp_set_session_name (void *sdp_ptr, const char *sessname)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ sstrncpy(sdp_p->sessname, sessname, sizeof(sdp_p->sessname));
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_timespec_valid
+ * Description: Returns true or false depending on whether the timespec t=
+ * token line has been defined for this SDP.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * Returns: TRUE or FALSE.
+ */
+tinybool sdp_timespec_valid (void *sdp_ptr)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (FALSE);
+ }
+
+ if ((sdp_p->timespec_p == NULL) ||
+ (sdp_p->timespec_p->start_time == '\0') ||
+ (sdp_p->timespec_p->stop_time == '\0')) {
+ return (FALSE);
+ } else {
+ return (TRUE);
+ }
+}
+
+/* Function: sdp_get_time_start
+ * Description: Returns the start time parameter from the t= timespec token
+ * line. Because the value may be larger than 32 bits, this
+ * parameter is returned as a string, though has been verified
+ * to be numeric. Value is returned as a const ptr and so
+ * cannot be modified by the application.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * Returns: Ptr to start time or NULL.
+ */
+const char *sdp_get_time_start (void *sdp_ptr)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (NULL);
+ }
+
+ if (sdp_p->timespec_p != NULL) {
+ return (sdp_p->timespec_p->start_time);
+ } else {
+ return (NULL);
+ }
+}
+
+/* Function: sdp_get_time_stop
+ * Description: Returns the stop time parameter from the t= timespec token
+ * line. Because the value may be larger than 32 bits, this
+ * parameter is returned as a string, though has been verified
+ * to be numeric. Value is returned as a const ptr and so
+ * cannot be modified by the application.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * Returns: Ptr to stop time or NULL.
+ */
+const char *sdp_get_time_stop (void *sdp_ptr)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (NULL);
+ }
+
+ if (sdp_p->timespec_p != NULL) {
+ return (sdp_p->timespec_p->stop_time);
+ } else {
+ return (NULL);
+ }
+}
+
+/* Function: sdp_set_time_start
+ * Description: Sets the value of the start time parameter for the t=
+ * timespec token line. The string is copied into the
+ * SDP structure so application memory will not be
+ * referenced by the SDP lib.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * start_time Ptr to the start time string.
+ * Returns: SDP_SUCCESS
+ */
+sdp_result_e sdp_set_time_start (void *sdp_ptr, const char *start_time)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ if (sdp_p->timespec_p == NULL) {
+ sdp_p->timespec_p = (sdp_timespec_t *)SDP_MALLOC(sizeof(sdp_timespec_t));
+ if (sdp_p->timespec_p == NULL) {
+ sdp_p->conf_p->num_no_resource++;
+ return (SDP_NO_RESOURCE);
+ }
+ sdp_p->timespec_p->start_time[0] = '\0';
+ sdp_p->timespec_p->stop_time[0] = '\0';
+ }
+ sstrncpy(sdp_p->timespec_p->start_time, start_time,
+ sizeof(sdp_p->timespec_p->start_time));
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_set_time_stop
+ * Description: Sets the value of the stop time parameter for the t=
+ * timespec token line. The string is copied into the
+ * SDP structure so application memory will not be
+ * referenced by the SDP lib.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * stop_time Ptr to the stop time string.
+ * Returns: SDP_SUCCESS
+ */
+sdp_result_e sdp_set_time_stop (void *sdp_ptr, const char *stop_time)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ if (sdp_p->timespec_p == NULL) {
+ sdp_p->timespec_p = (sdp_timespec_t *)SDP_MALLOC(sizeof(sdp_timespec_t));
+ if (sdp_p->timespec_p == NULL) {
+ sdp_p->conf_p->num_no_resource++;
+ return (SDP_NO_RESOURCE);
+ }
+ sdp_p->timespec_p->start_time[0] = '\0';
+ sdp_p->timespec_p->stop_time[0] = '\0';
+ }
+ sstrncpy(sdp_p->timespec_p->stop_time, stop_time,
+ sizeof(sdp_p->timespec_p->stop_time));
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_encryption_valid
+ * Description: Returns true or false depending on whether the encryption k=
+ * token line has been defined for this SDP at the given level.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the k= line. Will be
+ * either SDP_SESSION_LEVEL or 1-n specifying a
+ * media line level.
+ * Returns: TRUE or FALSE.
+ */
+tinybool sdp_encryption_valid (void *sdp_ptr, u16 level)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_encryptspec_t *encrypt_p;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (FALSE);
+ }
+
+ if (level == SDP_SESSION_LEVEL) {
+ encrypt_p = &(sdp_p->encrypt);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (FALSE);
+ }
+ encrypt_p = &(mca_p->encrypt);
+ }
+
+ if ((encrypt_p->encrypt_type == SDP_ENCRYPT_INVALID) ||
+ ((encrypt_p->encrypt_type != SDP_ENCRYPT_PROMPT) &&
+ (encrypt_p->encrypt_key[0] == '\0'))) {
+ return (FALSE);
+ } else {
+ return (TRUE);
+ }
+}
+
+/* Function: sdp_get_encryption_method
+ * Description: Returns the encryption method parameter from the k=
+ * encryption token line. If encryption method has not been
+ * set SDP_ENCRYPT_INVALID will be returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the c= line. Will be
+ * either SDP_SESSION_LEVEL or 1-n specifying a
+ * media line level.
+ * Returns: Encryption method or SDP_ENCRYPT_INVALID.
+ */
+sdp_encrypt_type_e sdp_get_encryption_method (void *sdp_ptr, u16 level)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_encryptspec_t *encrypt_p;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_ENCRYPT_INVALID);
+ }
+
+ if (level == SDP_SESSION_LEVEL) {
+ encrypt_p = &(sdp_p->encrypt);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (SDP_ENCRYPT_INVALID);
+ }
+ encrypt_p = &(mca_p->encrypt);
+ }
+
+ return (encrypt_p->encrypt_type);
+}
+
+/* Function: sdp_get_encryption_key
+ * Description: Returns a pointer to the encryption key parameter
+ * from the k= encryption token line. Value is returned as a
+ * const ptr and so cannot be modified by the application.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the c= line. Will be
+ * either SDP_SESSION_LEVEL or 1-n specifying a
+ * media line level.
+ * Returns: Ptr to encryption key or NULL.
+ */
+const char *sdp_get_encryption_key (void *sdp_ptr, u16 level)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_encryptspec_t *encrypt_p;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (NULL);
+ }
+
+ if (level == SDP_SESSION_LEVEL) {
+ encrypt_p = &(sdp_p->encrypt);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (NULL);
+ }
+ encrypt_p = &(mca_p->encrypt);
+ }
+
+ return (encrypt_p->encrypt_key);
+}
+
+/* Function: sdp_set_encryption_method
+ * Description: Sets the value of the encryption method param for the k=
+ * encryption token line.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the k= line. Will be
+ * either SDP_SESSION_LEVEL or 1-n specifying a
+ * media line level.
+ * type The encryption type.
+ * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER
+ */
+sdp_result_e sdp_set_encryption_method (void *sdp_ptr, u16 level,
+ sdp_encrypt_type_e type)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_encryptspec_t *encrypt_p;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ if (level == SDP_SESSION_LEVEL) {
+ encrypt_p = &(sdp_p->encrypt);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ encrypt_p = &(mca_p->encrypt);
+ }
+
+ encrypt_p->encrypt_type = type;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_set_encryption_key
+ * Description: Sets the value of the encryption key parameter for the k=
+ * encryption token line. The string is copied into the
+ * SDP structure so application memory will not be
+ * referenced by the SDP lib.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the k= line. Will be
+ * either SDP_SESSION_LEVEL or 1-n specifying a
+ * media line level.
+ * key Ptr to the encryption key string.
+ * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER
+ */
+sdp_result_e sdp_set_encryption_key (void *sdp_ptr, u16 level, const char *key)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_encryptspec_t *encrypt_p;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ if (level == SDP_SESSION_LEVEL) {
+ encrypt_p = &(sdp_p->encrypt);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ encrypt_p = &(mca_p->encrypt);
+ }
+
+ sstrncpy(encrypt_p->encrypt_key, key, sizeof(encrypt_p->encrypt_key));
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_connection_valid
+ * Description: Returns true or false depending on whether the connection c=
+ * token line has been defined for this SDP at the given level.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the c= line. Will be
+ * either SDP_SESSION_LEVEL or 1-n specifying a
+ * media line level.
+ * Returns: TRUE or FALSE.
+ */
+tinybool sdp_connection_valid (void *sdp_ptr, u16 level)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_conn_t *conn_p;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (FALSE);
+ }
+
+ if (level == SDP_SESSION_LEVEL) {
+ conn_p = &(sdp_p->default_conn);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (FALSE);
+ }
+ conn_p = &(mca_p->conn);
+ }
+
+ /*if network type is ATM . then allow c= line without address type
+ * and address . This is a special case to cover PVC
+ */
+ if (conn_p->nettype == SDP_NT_ATM &&
+ conn_p->addrtype == SDP_AT_INVALID) {
+ return TRUE;
+ }
+
+ if ((conn_p->nettype >= SDP_MAX_NETWORK_TYPES) ||
+ (conn_p->addrtype >= SDP_MAX_ADDR_TYPES) ||
+ (conn_p->conn_addr[0] == '\0')) {
+ return (FALSE);
+ } else {
+ return (TRUE);
+ }
+}
+
+/* Function: sdp_bandwidth_valid
+ * Description: Returns true or false depending on whether the bandwidth b=
+ * token line has been defined for this SDP at the given level.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the c= line. Will be
+ * either SDP_SESSION_LEVEL or 1-n specifying a
+ * media line level.
+ * inst_num instance number of bw line at that level. The first
+ * instance has a inst_num of 1 and so on.
+ * Returns: TRUE or FALSE.
+ */
+tinybool sdp_bandwidth_valid (void *sdp_ptr, u16 level, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_bw_data_t *bw_data_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return FALSE;
+ }
+
+ bw_data_p = sdp_find_bw_line(sdp_p, level, inst_num);
+ if (bw_data_p != NULL) {
+ if ((bw_data_p->bw_modifier < SDP_BW_MODIFIER_AS) ||
+ (bw_data_p->bw_modifier >= SDP_MAX_BW_MODIFIER_VAL)) {
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+ } else {
+ return FALSE;
+ }
+}
+
+/*
+ * sdp_bw_line_exists
+ *
+ * Description: This api retruns true if there exists a bw line at the
+ * instance and level specified.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the c= line. Will be
+ * either SDP_SESSION_LEVEL or 1-n specifying a
+ * media line level.
+ * inst_num instance number of bw line at that level. The first
+ * instance has a inst_num of 1 and so on.
+ * Returns: TRUE or FALSE
+ */
+tinybool sdp_bw_line_exists (void *sdp_ptr, u16 level, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_bw_data_t *bw_data_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return FALSE;
+ }
+
+ bw_data_p = sdp_find_bw_line(sdp_p, level, inst_num);
+ if (bw_data_p != NULL) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/* Function: sdp_get_conn_nettype
+ * Description: Returns the network type parameter from the c=
+ * connection token line. If network type has not been
+ * set SDP_NT_INVALID will be returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the c= line. Will be
+ * either SDP_SESSION_LEVEL or 1-n specifying a
+ * media line level.
+ * Returns: Network type or SDP_NT_INVALID.
+ */
+sdp_nettype_e sdp_get_conn_nettype (void *sdp_ptr, u16 level)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_conn_t *conn_p;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_NT_INVALID);
+ }
+
+ if (level == SDP_SESSION_LEVEL) {
+ conn_p = &(sdp_p->default_conn);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (SDP_NT_INVALID);
+ }
+ conn_p = &(mca_p->conn);
+ }
+
+ return (conn_p->nettype);
+}
+
+/* Function: sdp_get_conn_addrtype
+ * Description: Returns the address type parameter from the c=
+ * connection token line. If address type has not been
+ * set SDP_AT_INVALID will be returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the c= line. Will be
+ * either SDP_SESSION_LEVEL or 1-n specifying a
+ * media line level.
+ * Returns: Address type or SDP_AT_INVALID.
+ */
+sdp_addrtype_e sdp_get_conn_addrtype (void *sdp_ptr, u16 level)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_conn_t *conn_p;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_AT_INVALID);
+ }
+
+ if (level == SDP_SESSION_LEVEL) {
+ conn_p = &(sdp_p->default_conn);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (SDP_AT_INVALID);
+ }
+ conn_p = &(mca_p->conn);
+ }
+
+ return (conn_p->addrtype);
+}
+
+/* Function: sdp_get_conn_address
+ * Description: Returns a pointer to the address parameter
+ * from the c= connection token line. Value is returned as a
+ * const ptr and so cannot be modified by the application.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the c= line. Will be
+ * either SDP_SESSION_LEVEL or 1-n specifying a
+ * media line level.
+ * Returns: Ptr to address or NULL.
+ */
+const char *sdp_get_conn_address (void *sdp_ptr, u16 level)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_conn_t *conn_p;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (NULL);
+ }
+
+ if (level == SDP_SESSION_LEVEL) {
+ conn_p = &(sdp_p->default_conn);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (NULL);
+ }
+ conn_p = &(mca_p->conn);
+ }
+
+ return (conn_p->conn_addr);
+}
+
+/* Function: sdp_is_mcast_addr
+ * Description: Returns a boolean to indicate if the addr is multicast in
+ * the c=line.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the c= line. Will be
+ * either SDP_SESSION_LEVEL or 1-n specifying a
+ * media line level.
+ * Returns: TRUE if the addr is multicast, FALSE if not.
+ */
+
+tinybool sdp_is_mcast_addr (void *sdp_ptr, u16 level)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_conn_t *conn_p;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (FALSE);
+ }
+
+ if (level == SDP_SESSION_LEVEL) {
+ conn_p = &(sdp_p->default_conn);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p != NULL) {
+ conn_p = &(mca_p->conn);
+ } else {
+ return (FALSE);
+ }
+ }
+
+ if ((conn_p) && (conn_p->is_multicast)) {
+ return (TRUE);
+ } else {
+ return (FALSE);
+ }
+}
+
+/* Function: sdp_get_mcast_ttl
+ * Description: Get the time to live(ttl) value for the multicast address
+ * if present.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the c= line. Will be
+ * either SDP_SESSION_LEVEL or 1-n specifying a
+ * media line level.
+ * Returns: Multicast address - Time to live (ttl) value
+ */
+
+int32 sdp_get_mcast_ttl (void *sdp_ptr, u16 level)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_conn_t *conn_p;
+ sdp_mca_t *mca_p;
+ u16 ttl=0;
+
+ if (sdp_verify_sdp_ptr(sdp_p) != FALSE) {
+ if (level == SDP_SESSION_LEVEL) {
+ conn_p = &(sdp_p->default_conn);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p != NULL) {
+ conn_p = &(mca_p->conn);
+ } else {
+ return SDP_INVALID_VALUE;
+ }
+ }
+ } else {
+ return SDP_INVALID_VALUE;
+ }
+
+ if (conn_p) {
+ ttl = conn_p->ttl;
+ }
+ return ttl;
+}
+
+/* Function: sdp_get_mcast_num_of_addresses
+ * Description: Get the number of addresses value for the multicast address
+ * if present.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the c= line. Will be
+ * either SDP_SESSION_LEVEL or 1-n specifying a
+ * media line level.
+ * Returns: Multicast address - number of addresses value
+ */
+
+int32 sdp_get_mcast_num_of_addresses (void *sdp_ptr, u16 level)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_conn_t *conn_p;
+ sdp_mca_t *mca_p;
+ u16 num_addr = 0;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_VALUE);
+ } else {
+ if (level == SDP_SESSION_LEVEL) {
+ conn_p = &(sdp_p->default_conn);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p != NULL) {
+ conn_p = &(mca_p->conn);
+ } else {
+ return (SDP_INVALID_VALUE);
+ }
+ }
+ }
+
+ if (conn_p) {
+ num_addr = conn_p->num_of_addresses;
+ }
+ return num_addr;
+}
+/* Function: sdp_set_conn_nettype
+ * Description: Sets the value of the network type parameter for the c=
+ * connection token line.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * nettype Network type for the connection line.
+ * level The level to check for the c= line. Will be
+ * either SDP_SESSION_LEVEL or 1-n specifying a
+ * media line level.
+ * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER
+ */
+sdp_result_e sdp_set_conn_nettype (void *sdp_ptr, u16 level,
+ sdp_nettype_e nettype)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_conn_t *conn_p;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ if (level == SDP_SESSION_LEVEL) {
+ conn_p = &(sdp_p->default_conn);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ conn_p = &(mca_p->conn);
+ }
+
+ conn_p->nettype = nettype;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_set_conn_addrtype
+ * Description: Sets the value of the address type parameter for the c=
+ * connection token line.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * addrtype Address type for the connection line.
+ * level The level to check for the c= line. Will be
+ * either SDP_SESSION_LEVEL or 1-n specifying a
+ * media line level.
+ * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER
+ */
+sdp_result_e sdp_set_conn_addrtype (void *sdp_ptr, u16 level,
+ sdp_addrtype_e addrtype)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_conn_t *conn_p;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ if (level == SDP_SESSION_LEVEL) {
+ conn_p = &(sdp_p->default_conn);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ conn_p = &(mca_p->conn);
+ }
+
+ conn_p->addrtype = addrtype;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_set_conn_address
+ * Description: Sets the value of the address parameter for the c=
+ * connection token line. The string is copied into the
+ * SDP structure so application memory will not be
+ * referenced by the SDP lib.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the c= line. Will be
+ * either SDP_SESSION_LEVEL or 1-n specifying a
+ * media line level.
+ * address Ptr to the address string.
+ * Returns: SDP_SUCCESS
+ */
+sdp_result_e sdp_set_conn_address (void *sdp_ptr, u16 level,
+ const char *address)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_conn_t *conn_p;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ if (level == SDP_SESSION_LEVEL) {
+ conn_p = &(sdp_p->default_conn);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ conn_p = &(mca_p->conn);
+ }
+
+ sstrncpy(conn_p->conn_addr, address, sizeof(conn_p->conn_addr));
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_set_mcast_addr_fields
+ * Description: Sets the value of the ttl and num of addresses for
+ * a multicast address.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the c= line. Will be
+ * either SDP_SESSION_LEVEL or 1-n specifying a
+ * media line level.
+ * ttl Time to live (ttl) value.
+ * num_of_addresses number of addresses
+ .
+ * Returns: SDP_SUCCESS
+ */
+sdp_result_e sdp_set_mcast_addr_fields(void *sdp_ptr, u16 level,
+ u16 ttl, u16 num_of_addresses)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_conn_t *conn_p;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ if (level == SDP_SESSION_LEVEL) {
+ conn_p = &(sdp_p->default_conn);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ conn_p = &(mca_p->conn);
+ }
+
+ if (conn_p) {
+ conn_p->is_multicast = TRUE;
+ if ((conn_p->ttl >0) && (conn_p->ttl <= SDP_MAX_TTL_VALUE)) {
+ conn_p->ttl = ttl;
+ }
+ conn_p->num_of_addresses = num_of_addresses;
+ } else {
+ return (SDP_FAILURE);
+ }
+ return (SDP_SUCCESS);
+}
+
+
+/* Function: sdp_media_line_valid
+ * Description: Returns true or false depending on whether the specified
+ * media line m= has been defined for this SDP. The
+ * SDP_SESSION_LEVEL level is not valid for this check since,
+ * by definition, this is a media level.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the c= line. Will be
+ * 1-n specifying a media line level.
+ * Returns: TRUE or FALSE.
+ */
+tinybool sdp_media_line_valid (void *sdp_ptr, u16 level)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (FALSE);
+ }
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (FALSE);
+ }
+
+ /* Validate params for this media line */
+ if ((mca_p->media >= SDP_MAX_MEDIA_TYPES) ||
+ (mca_p->port_format >= SDP_MAX_PORT_FORMAT_TYPES) ||
+ (mca_p->transport >= SDP_MAX_TRANSPORT_TYPES) ||
+ (mca_p->num_payloads == 0)) {
+ return (FALSE);
+ } else {
+ return (TRUE);
+ }
+}
+
+/* Function: sdp_get_num_media_lines
+ * Description: Returns the number of media lines associated with the SDP.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * Returns: Number of media lines.
+ */
+u16 sdp_get_num_media_lines (void *sdp_ptr)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (0);
+ }
+
+ return (sdp_p->mca_count);
+}
+
+/* Function: sdp_get_media_type
+ * Description: Returns the media type parameter from the m=
+ * media token line. If media type has not been
+ * set SDP_MEDIA_INVALID will be returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to of the m= media line. Will be 1-n.
+ * Returns: Media type or SDP_MEDIA_INVALID.
+ */
+sdp_media_e sdp_get_media_type (void *sdp_ptr, u16 level)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_MEDIA_INVALID);
+ }
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (SDP_MEDIA_INVALID);
+ }
+
+ return (mca_p->media);
+}
+
+/* Function: sdp_get_media_port_format
+ * Description: Returns the port format type associated with the m=
+ * media token line. If port format type has not been
+ * set SDP_PORT_FORMAT_INVALID will be returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to of the m= media line. Will be 1-n.
+ * Returns: Port format type or SDP_PORT_FORMAT_INVALID.
+ */
+sdp_port_format_e sdp_get_media_port_format (void *sdp_ptr, u16 level)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_PORT_FORMAT_INVALID);
+ }
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (SDP_PORT_FORMAT_INVALID);
+ }
+
+ return (mca_p->port_format);
+}
+
+/* Function: sdp_get_media_portnum
+ * Description: Returns the port number associated with the m=
+ * media token line. If port number has not been
+ * set SDP_INVALID_VALUE will be returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to of the m= media line. Will be 1-n.
+ * Returns: Port number or SDP_INVALID_VALUE.
+ */
+int32 sdp_get_media_portnum (void *sdp_ptr, u16 level)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_VALUE);
+ }
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (SDP_INVALID_VALUE);
+ }
+
+ /* Make sure port number is valid for the specified format. */
+ if ((mca_p->port_format != SDP_PORT_NUM_ONLY) &&
+ (mca_p->port_format != SDP_PORT_NUM_COUNT) &&
+ (mca_p->port_format != SDP_PORT_NUM_VPI_VCI) &&
+ (mca_p->port_format != SDP_PORT_NUM_VPI_VCI_CID)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Port num not valid for media line %u",
+ sdp_p->debug_str, level);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ }
+
+ return (mca_p->port);
+}
+
+/* Function: sdp_get_media_portcount
+ * Description: Returns the port count associated with the m=
+ * media token line. If port count has not been
+ * set SDP_INVALID_VALUE will be returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to of the m= media line. Will be 1-n.
+ * Returns: Port count or SDP_INVALID_VALUE.
+ */
+int32 sdp_get_media_portcount (void *sdp_ptr, u16 level)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_VALUE);
+ }
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (SDP_INVALID_VALUE);
+ }
+
+ /* Make sure port number is valid for the specified format. */
+ if (mca_p->port_format != SDP_PORT_NUM_COUNT) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Port count not valid for media line %u",
+ sdp_p->debug_str, level);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ }
+
+ return (mca_p->num_ports);
+}
+
+/* Function: sdp_get_media_vpi
+ * Description: Returns the VPI parameter associated with the m=
+ * media token line. If VPI has not been set
+ * SDP_INVALID_VALUE will be returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to of the m= media line. Will be 1-n.
+ * Returns: VPI or SDP_INVALID_VALUE.
+ */
+int32 sdp_get_media_vpi (void *sdp_ptr, u16 level)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_VALUE);
+ }
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (SDP_INVALID_VALUE);
+ }
+
+ /* Make sure port number is valid for the specified format. */
+ if ((mca_p->port_format != SDP_PORT_VPI_VCI) &&
+ (mca_p->port_format != SDP_PORT_NUM_VPI_VCI) &&
+ (mca_p->port_format != SDP_PORT_NUM_VPI_VCI_CID)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s VPI not valid for media line %u",
+ sdp_p->debug_str, level);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ }
+
+ return (mca_p->vpi);
+}
+
+/* Function: sdp_get_media_vci
+ * Description: Returns the VCI parameter associated with the m=
+ * media token line. If VCI has not been set
+ * SDP_INVALID_VALUE will be returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to of the m= media line. Will be 1-n.
+ * Returns: VCI or zero.
+ */
+u32 sdp_get_media_vci (void *sdp_ptr, u16 level)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (0);
+ }
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (0);
+ }
+
+ /* Make sure port number is valid for the specified format. */
+ if ((mca_p->port_format != SDP_PORT_VPI_VCI) &&
+ (mca_p->port_format != SDP_PORT_NUM_VPI_VCI) &&
+ (mca_p->port_format != SDP_PORT_NUM_VPI_VCI_CID)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s VCI not valid for media line %u",
+ sdp_p->debug_str, level);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ }
+
+ return (mca_p->vci);
+}
+
+/* Function: sdp_get_media_vcci
+ * Description: Returns the VCCI parameter associated with the m=
+ * media token line. If VCCI has not been set
+ * SDP_INVALID_VALUE will be returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to of the m= media line. Will be 1-n.
+ * Returns: VCCI or SDP_INVALID_VALUE.
+ */
+int32 sdp_get_media_vcci (void *sdp_ptr, u16 level)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_VALUE);
+ }
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (SDP_INVALID_VALUE);
+ }
+
+ /* Make sure port number is valid for the specified format. */
+ if ((mca_p->port_format != SDP_PORT_VCCI) &&
+ (mca_p->port_format != SDP_PORT_VCCI_CID)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s VCCI not valid for media line %u",
+ sdp_p->debug_str, level);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ }
+
+ return (mca_p->vcci);
+}
+
+/* Function: sdp_get_media_cid
+ * Description: Returns the CID parameter associated with the m=
+ * media token line. If CID has not been set
+ * SDP_INVALID_VALUE will be returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to of the m= media line. Will be 1-n.
+ * Returns: CID or SDP_INVALID_VALUE.
+ */
+int32 sdp_get_media_cid (void *sdp_ptr, u16 level)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_VALUE);
+ }
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (SDP_INVALID_VALUE);
+ }
+
+ /* Make sure port number is valid for the specified format. */
+ if ((mca_p->port_format != SDP_PORT_VCCI_CID) &&
+ (mca_p->port_format != SDP_PORT_NUM_VPI_VCI_CID)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s CID not valid for media line %u",
+ sdp_p->debug_str, level);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ }
+
+ return (mca_p->cid);
+}
+
+/* Function: sdp_get_media_transport
+ * Description: Returns the transport type parameter associated with the m=
+ * media token line. If transport type has not been set
+ * SDP_TRANSPORT_INVALID will be returned. If the transport
+ * type is one of the AAL2 variants, the profile routines below
+ * should be used to access multiple profile types and payload
+ * lists per m= line.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to of the m= media line. Will be 1-n.
+ * Returns: CID or SDP_TRANSPORT_INVALID.
+ */
+sdp_transport_e sdp_get_media_transport (void *sdp_ptr, u16 level)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_TRANSPORT_INVALID);
+ }
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (SDP_TRANSPORT_INVALID);
+ }
+
+ return (mca_p->transport);
+}
+
+/* Function: sdp_get_media_num_profiles
+ * Description: Returns the number of profiles associated with the m=
+ * media token line. If the media line is invalid, zero will
+ * be returned. Application must validate the media line
+ * before using this routine. Multiple profile types per
+ * media line is currently only used for AAL2. If the appl
+ * detects that the transport type is one of the AAL2 types,
+ * it should use these profile access routines to access the
+ * profile types and payload list for each.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to of the m= media line. Will be 1-n.
+ * Returns: Number of profiles or zero.
+ */
+u16 sdp_get_media_num_profiles (void *sdp_ptr, u16 level)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (0);
+ }
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (0);
+ }
+
+ if (mca_p->media_profiles_p == NULL) {
+ return (0);
+ } else {
+ return (mca_p->media_profiles_p->num_profiles);
+ }
+}
+
+/* Function: sdp_get_media_profile
+ * Description: Returns the specified profile type associated with the m=
+ * media token line. If the media line or profile number is
+ * invalid, SDP_TRANSPORT_INVALID will be returned.
+ * Applications must validate the media line before using this
+ * routine.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to of the m= media line. Will be 1-n.
+ * profile_num The specific profile type number to be retrieved.
+ * Returns: The profile type or SDP_TRANSPORT_INVALID.
+ */
+sdp_transport_e sdp_get_media_profile (void *sdp_ptr, u16 level,
+ u16 profile_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_TRANSPORT_INVALID);
+ }
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (SDP_TRANSPORT_INVALID);
+ }
+
+ if ((profile_num < 1) ||
+ (profile_num > mca_p->media_profiles_p->num_profiles)) {
+ return (SDP_TRANSPORT_INVALID);
+ } else {
+ return (mca_p->media_profiles_p->profile[profile_num-1]);
+ }
+}
+
+/* Function: sdp_get_media_num_payload_types
+ * Description: Returns the number of payload types associated with the m=
+ * media token line. If the media line is invalid, zero will
+ * be returned. Application must validate the media line
+ * before using this routine.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to of the m= media line. Will be 1-n.
+ * Returns: Number of payload types or zero.
+ */
+u16 sdp_get_media_num_payload_types (void *sdp_ptr, u16 level)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (0);
+ }
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (0);
+ }
+
+ return (mca_p->num_payloads);
+}
+
+/* Function: sdp_get_media_profile_num_payload_types
+ * Description: Returns the number of payload types associated with the
+ * specified profile on the m= media token line. If the
+ * media line or profile number is invalid, zero will
+ * be returned. Application must validate the media line
+ * and profile before using this routine.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to of the m= media line. Will be 1-n.
+ * profile_num The specific profile number. Will be 1-n.
+ * Returns: Number of payload types or zero.
+ */
+u16 sdp_get_media_profile_num_payload_types (void *sdp_ptr, u16 level,
+ u16 profile_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (0);
+ }
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (0);
+ }
+
+ if ((profile_num < 1) ||
+ (profile_num > mca_p->media_profiles_p->num_profiles)) {
+ return (0);
+ } else {
+ return (mca_p->media_profiles_p->num_payloads[profile_num-1]);
+ }
+}
+
+/* Function: sdp_get_media_payload_type
+ * Description: Returns the payload type of the specified payload for the m=
+ * media token line. If the media line or payload number is
+ * invalid, zero will be returned. Application must validate
+ * the media line before using this routine.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to of the m= media line. Will be 1-n.
+ * payload_num Number of the payload type to retrieve. The
+ * range is (1 - max num payloads).
+ * indicator Returns the type of payload returned, either
+ * NUMERIC or ENUM.
+ * Returns: Payload type or zero.
+ */
+u32 sdp_get_media_payload_type (void *sdp_ptr, u16 level, u16 payload_num,
+ sdp_payload_ind_e *indicator)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_mca_t *mca_p;
+ uint16_t num_a_lines = 0;
+ int i;
+ uint16_t ptype;
+ uint16_t pack_mode = 0; /*default 0, if remote did not provide any */
+ const char *encname = NULL;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (0);
+ }
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (0);
+ }
+
+ if ((payload_num < 1) || (payload_num > mca_p->num_payloads)) {
+ return (0);
+ }
+
+ *indicator = mca_p->payload_indicator[payload_num-1];
+ if ((mca_p->payload_type[payload_num-1] >= SDP_MIN_DYNAMIC_PAYLOAD) &&
+ (mca_p->payload_type[payload_num-1] <= SDP_MAX_DYNAMIC_PAYLOAD)) {
+ /*
+ * Get number of RTPMAP attributes for the AUDIO line
+ */
+ (void) sdp_attr_num_instances(sdp_p, level, 0, SDP_ATTR_RTPMAP,
+ &num_a_lines);
+ /*
+ * Loop through AUDIO media line RTPMAP attributes.
+ * NET dynamic payload type will be returned.
+ */
+ for (i = 0; i < num_a_lines; i++) {
+ ptype = sdp_attr_get_rtpmap_payload_type(sdp_p, level, 0,
+ (uint16_t) (i + 1));
+ if (ptype == mca_p->payload_type[payload_num-1] ) {
+ encname = sdp_attr_get_rtpmap_encname(sdp_p, level, 0,
+ (uint16_t) (i + 1));
+ if (encname) {
+ if (cpr_strcasecmp(encname, SIPSDP_ATTR_ENCNAME_ILBC) == 0) {
+ return (SET_PAYLOAD_TYPE_WITH_DYNAMIC(ptype, RTP_ILBC));
+ }
+ if (cpr_strcasecmp(encname, SIPSDP_ATTR_ENCNAME_L16_256K) == 0) {
+ return (SET_PAYLOAD_TYPE_WITH_DYNAMIC(ptype, RTP_L16));
+ }
+ if (cpr_strcasecmp(encname, SIPSDP_ATTR_ENCNAME_ISAC) == 0) {
+ return (SET_PAYLOAD_TYPE_WITH_DYNAMIC(ptype, RTP_ISAC));
+ }
+ if (cpr_strcasecmp(encname, SIPSDP_ATTR_ENCNAME_OPUS) == 0) {
+ return (SET_PAYLOAD_TYPE_WITH_DYNAMIC(ptype, RTP_OPUS));
+ }
+ if (cpr_strcasecmp(encname, SIPSDP_ATTR_ENCNAME_H264) == 0) {
+ sdp_attr_get_fmtp_pack_mode(sdp_p, level, 0, (uint16_t) (i + 1), &pack_mode);
+ if (pack_mode == SDP_DEFAULT_PACKETIZATION_MODE_VALUE) {
+ return (SET_PAYLOAD_TYPE_WITH_DYNAMIC(ptype, RTP_H264_P0));
+ } else {
+ return (SET_PAYLOAD_TYPE_WITH_DYNAMIC(ptype, RTP_H264_P1));
+ }
+ }
+ if (cpr_strcasecmp(encname, SIPSDP_ATTR_ENCNAME_VP8) == 0) {
+ return (SET_PAYLOAD_TYPE_WITH_DYNAMIC(ptype, RTP_VP8));
+ }
+ }
+ }
+ }
+ }
+ return (mca_p->payload_type[payload_num-1]);
+}
+
+/* Function: sdp_get_media_profile_payload_type
+ * Description: Returns the payload type of the specified payload for the m=
+ * media token line. If the media line or payload number is
+ * invalid, zero will be returned. Application must validate
+ * the media line before using this routine.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to of the m= media line. Will be 1-n.
+ * payload_num Number of the payload type to retrieve. The
+ * range is (1 - max num payloads).
+ * indicator Returns the type of payload returned, either
+ * NUMERIC or ENUM.
+ * Returns: Payload type or zero.
+ */
+u32 sdp_get_media_profile_payload_type (void *sdp_ptr, u16 level, u16 prof_num,
+ u16 payload_num,
+ sdp_payload_ind_e *indicator)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_mca_t *mca_p;
+ sdp_media_profiles_t *prof_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (0);
+ }
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (0);
+ }
+
+ prof_p = mca_p->media_profiles_p;
+ if ((prof_num < 1) ||
+ (prof_num > prof_p->num_profiles)) {
+ return (0);
+ }
+
+ if ((payload_num < 1) ||
+ (payload_num > prof_p->num_payloads[prof_num-1])) {
+ return (0);
+ }
+
+ *indicator = prof_p->payload_indicator[prof_num-1][payload_num-1];
+ return (prof_p->payload_type[prof_num-1][payload_num-1]);
+}
+
+/* Function: sdp_insert_media_line
+ * Description: Insert a new media line at the level specified for the
+ * given SDP.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The new media level to insert. Will be 1-n.
+ * Returns: SDP_SUCCESS, SDP_NO_RESOURCE, or SDP_INVALID_PARAMETER
+ */
+sdp_result_e sdp_insert_media_line (void *sdp_ptr, u16 level)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_mca_t *mca_p;
+ sdp_mca_t *new_mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ if ((level < 1) || (level > (sdp_p->mca_count+1))) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Invalid media line (%u) to insert, max is "
+ "(%u).", sdp_p->debug_str, level, sdp_p->mca_count);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Allocate resource for new media stream. */
+ new_mca_p = sdp_alloc_mca();
+ if (new_mca_p == NULL) {
+ sdp_p->conf_p->num_no_resource++;
+ return (SDP_NO_RESOURCE);
+ }
+
+ if (level == 1) {
+ /* We're inserting the first media line */
+ new_mca_p->next_p = sdp_p->mca_p;
+ sdp_p->mca_p = new_mca_p;
+ } else {
+ /* Find the pointer to the media stream just prior to where
+ * we want to insert the new stream.
+ */
+ mca_p = sdp_find_media_level(sdp_p, (u16)(level-1));
+ if (mca_p == NULL) {
+ SDP_FREE(new_mca_p);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ new_mca_p->next_p = mca_p->next_p;
+ mca_p->next_p = new_mca_p;
+ }
+
+ sdp_p->mca_count++;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_delete_media_line
+ * Description: Delete the media line at the level specified for the
+ * given SDP.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The media level to delete. Will be 1-n.
+ * Returns: SDP_SUCCESS, SDP_NO_RESOURCE, or SDP_INVALID_PARAMETER
+ */
+void sdp_delete_media_line (void *sdp_ptr, u16 level)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_mca_t *mca_p;
+ sdp_mca_t *prev_mca_p = NULL;
+ sdp_attr_t *attr_p;
+ sdp_attr_t *next_attr_p;
+ sdp_bw_t *bw_p;
+ sdp_bw_data_t *bw_data_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return;
+ }
+
+ /* If we're not deleting media line 1, then we need a pointer
+ * to the previous media line so we can relink. */
+ if (level == 1) {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ } else {
+ prev_mca_p = sdp_find_media_level(sdp_p, (u16)(level-1));
+ if (prev_mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return;
+ }
+ mca_p = prev_mca_p->next_p;
+ }
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return;
+ }
+
+ /* Delete all attributes from this level. */
+ for (attr_p = mca_p->media_attrs_p; attr_p != NULL;) {
+ next_attr_p = attr_p->next_p;
+ sdp_free_attr(attr_p);
+ attr_p = next_attr_p;
+ }
+
+ /* Delete bw line */
+ bw_p = &(mca_p->bw);
+ bw_data_p = bw_p->bw_data_list;
+ while (bw_data_p != NULL) {
+ bw_p->bw_data_list = bw_data_p->next_p;
+ SDP_FREE(bw_data_p);
+ bw_data_p = bw_p->bw_data_list;
+ }
+
+ /* Now relink the media levels and delete the specified one. */
+ if (prev_mca_p == NULL) {
+ sdp_p->mca_p = mca_p->next_p;
+ } else {
+ prev_mca_p->next_p = mca_p->next_p;
+ }
+ SDP_FREE(mca_p);
+ sdp_p->mca_count--;
+ return;
+}
+
+/* Function: sdp_set_media_type
+ * Description: Sets the value of the media type parameter for the m=
+ * media token line.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The media level to set the param. Will be 1-n.
+ * media Media type for the media line.
+ * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER
+ */
+sdp_result_e sdp_set_media_type (void *sdp_ptr, u16 level, sdp_media_e media)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ mca_p->media = media;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_set_media_port_format
+ * Description: Sets the value of the port format parameter for the m=
+ * media token line. Note that this parameter must be set
+ * before any of the port type specific parameters. If a
+ * parameter is not valid according to the port format
+ * specified, an attempt to set the parameter will fail.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The media level to set the param. Will be 1-n.
+ * port_format Media type for the media line.
+ * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER
+ */
+sdp_result_e sdp_set_media_port_format (void *sdp_ptr, u16 level,
+ sdp_port_format_e port_format)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ mca_p->port_format = port_format;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_set_media_portnum
+ * Description: Sets the value of the port number parameter for the m=
+ * media token line. If the port number is not valid with the
+ * port format specified for the media line, this call will
+ * fail.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The media level to set the param. Will be 1-n.
+ * portnum Port number to set.
+ * sctpport sctp port for application m= line
+ * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER
+ */
+sdp_result_e sdp_set_media_portnum (void *sdp_ptr, u16 level, int32 portnum, int32 sctp_port)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ mca_p->port = portnum;
+ mca_p->sctpport = sctp_port;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_set_media_portcount
+ * Description: Sets the value of the port count parameter for the m=
+ * media token line. If the port count is not valid with the
+ * port format specified for the media line, this call will
+ * fail.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The media level to set the param. Will be 1-n.
+ * num_ports Port count to set.
+ * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER
+ */
+sdp_result_e sdp_set_media_portcount (void *sdp_ptr, u16 level,
+ int32 num_ports)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ mca_p->num_ports = num_ports;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_set_media_vpi
+ * Description: Sets the value of the VPI parameter for the m=
+ * media token line. If the VPI is not valid with the
+ * port format specified for the media line, this call will
+ * fail.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The media level to set the param. Will be 1-n.
+ * vpi The VPI value to set.
+ * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER
+ */
+sdp_result_e sdp_set_media_vpi (void *sdp_ptr, u16 level, int32 vpi)
+{
+ sdp_t *sdp_p = (sdp_t*)sdp_ptr;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ mca_p->vpi = vpi;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_set_media_vci
+ * Description: Sets the value of the VCI parameter for the m=
+ * media token line. If the VCI is not valid with the
+ * port format specified for the media line, this call will
+ * fail.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The media level to set the param. Will be 1-n.
+ * vci The VCI value to set.
+ * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER
+ */
+sdp_result_e sdp_set_media_vci (void *sdp_ptr, u16 level, u32 vci)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ mca_p->vci = vci;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_set_media_vcci
+ * Description: Sets the value of the VCCI parameter for the m=
+ * media token line. If the VCCI is not valid with the
+ * port format specified for the media line, this call will
+ * fail.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The media level to set the param. Will be 1-n.
+ * vcci The VCCI value to set.
+ * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER
+ */
+sdp_result_e sdp_set_media_vcci (void *sdp_ptr, u16 level, int32 vcci)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ mca_p->vcci = vcci;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_set_media_cid
+ * Description: Sets the value of the CID parameter for the m=
+ * media token line. If the CID is not valid with the
+ * port format specified for the media line, this call will
+ * fail.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The media level to set the param. Will be 1-n.
+ * cid The CID value to set.
+ * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER
+ */
+sdp_result_e sdp_set_media_cid (void *sdp_ptr, u16 level, int32 cid)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ mca_p->cid = cid;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_set_media_transport
+ * Description: Sets the value of the transport type parameter for the m=
+ * media token line.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The media level to set the param. Will be 1-n.
+ * transport The transport type to set.
+ * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER
+ */
+sdp_result_e sdp_set_media_transport (void *sdp_ptr, u16 level,
+ sdp_transport_e transport)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ mca_p->transport = transport;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_add_media_profile
+ * Description: Add a new profile type for the m= media token line. This is
+ * used for AAL2 transport/profile types where more than one can
+ * be specified per media line. All other transport types should
+ * use the other transport access routines rather than this.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The media level to add the param. Will be 1-n.
+ * profile The profile type to add.
+ * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER
+ */
+sdp_result_e sdp_add_media_profile (void *sdp_ptr, u16 level,
+ sdp_transport_e profile)
+{
+ u16 prof_num;
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (mca_p->media_profiles_p == NULL) {
+ mca_p->media_profiles_p = (sdp_media_profiles_t *) \
+ SDP_MALLOC(sizeof(sdp_media_profiles_t));
+ if (mca_p->media_profiles_p == NULL) {
+ sdp_p->conf_p->num_no_resource++;
+ return (SDP_NO_RESOURCE);
+ } else {
+ mca_p->media_profiles_p->num_profiles = 0;
+ /* Set the transport type to this first profile type. */
+ mca_p->transport = profile;
+ }
+ }
+
+ if (mca_p->media_profiles_p->num_profiles >= SDP_MAX_PROFILES) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Max number of media profiles already specified"
+ " for media level %u", sdp_p->debug_str, level);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ prof_num = mca_p->media_profiles_p->num_profiles++;
+ mca_p->media_profiles_p->profile[prof_num] = profile;
+ mca_p->media_profiles_p->num_payloads[prof_num] = 0;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_add_media_payload_type
+ * Description: Add a new payload type for the media line at the level
+ * specified. The new payload type will be added at the end
+ * of the payload type list.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The media level to add the payload. Will be 1-n.
+ * payload_type The new payload type.
+ * indicator Defines the type of payload returned, either
+ * NUMERIC or ENUM.
+ * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER
+ */
+sdp_result_e sdp_add_media_payload_type (void *sdp_ptr, u16 level,
+ u16 payload_type,
+ sdp_payload_ind_e indicator)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (mca_p->num_payloads == SDP_MAX_PAYLOAD_TYPES) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Max number of payload types already defined "
+ "for media line %u", sdp_p->debug_str, level);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ mca_p->payload_indicator[mca_p->num_payloads] = indicator;
+ mca_p->payload_type[mca_p->num_payloads++] = payload_type;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_add_media_profile_payload_type
+ * Description: Add a new payload type for the media line at the level
+ * specified. The new payload type will be added at the end
+ * of the payload type list.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The media level to add the payload. Will be 1-n.
+ * prof_num The profile number to add the payload type.
+ * payload_type The new payload type.
+ * indicator Defines the type of payload returned, either
+ * NUMERIC or ENUM.
+ * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER
+ */
+sdp_result_e sdp_add_media_profile_payload_type (void *sdp_ptr, u16 level,
+ u16 prof_num, u16 payload_type,
+ sdp_payload_ind_e indicator)
+{
+ u16 num_payloads;
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if ((prof_num < 1) ||
+ (prof_num > mca_p->media_profiles_p->num_profiles)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Invalid profile number (%u) for set profile "
+ " payload type", sdp_p->debug_str, level);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (mca_p->media_profiles_p->num_payloads[prof_num-1] ==
+ SDP_MAX_PAYLOAD_TYPES) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Max number of profile payload types already "
+ "defined profile %u on media line %u",
+ sdp_p->debug_str, prof_num, level);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Get the current num payloads for this profile, and inc the number
+ * of payloads at the same time. Then store the new payload type. */
+ num_payloads = mca_p->media_profiles_p->num_payloads[prof_num-1]++;
+ mca_p->media_profiles_p->payload_indicator[prof_num-1][num_payloads] =
+ indicator;
+ mca_p->media_profiles_p->payload_type[prof_num-1][num_payloads] =
+ payload_type;
+ return (SDP_SUCCESS);
+}
+
+/*
+ * sdp_find_bw_line
+ *
+ * This helper function locates a specific bw line instance given the
+ * sdp, the level and the instance number of the bw line.
+ *
+ * Returns: Pointer to the sdp_bw_data_t instance, or NULL.
+ */
+sdp_bw_data_t* sdp_find_bw_line (void *sdp_ptr, u16 level, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_bw_t *bw_p;
+ sdp_bw_data_t *bw_data_p;
+ sdp_mca_t *mca_p;
+ int bw_attr_count=0;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (NULL);
+ }
+
+ if (level == SDP_SESSION_LEVEL) {
+ bw_p = &(sdp_p->bw);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (NULL);
+ }
+ bw_p = &(mca_p->bw);
+ }
+
+ for (bw_data_p = bw_p->bw_data_list;
+ bw_data_p != NULL;
+ bw_data_p = bw_data_p->next_p) {
+ bw_attr_count++;
+ if (bw_attr_count == inst_num) {
+ return bw_data_p;
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * sdp_copy_all_bw_lines
+ *
+ * Appends all the bw lines from the specified level of the orig sdp to the
+ * specified level of the dst sdp.
+ *
+ * Parameters: src_sdp_ptr The source SDP handle.
+ * dst_sdp_ptr The dest SDP handle.
+ * src_level The level in the src sdp from where to get the
+ * attributes.
+ * dst_level The level in the dst sdp where to put the
+ * attributes.
+ * Returns: SDP_SUCCESS Attributes were successfully copied.
+ */
+sdp_result_e sdp_copy_all_bw_lines (void *src_sdp_ptr, void *dst_sdp_ptr,
+ u16 src_level, u16 dst_level)
+{
+ sdp_t *src_sdp_p = (sdp_t *)src_sdp_ptr;
+ sdp_t *dst_sdp_p = (sdp_t *)dst_sdp_ptr;
+ sdp_bw_data_t *orig_bw_data_p;
+ sdp_bw_data_t *new_bw_data_p;
+ sdp_bw_data_t *bw_data_p;
+ sdp_bw_t *src_bw_p;
+ sdp_bw_t *dst_bw_p;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(src_sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ if (sdp_verify_sdp_ptr(dst_sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ /* Find src bw list */
+ if (src_level == SDP_SESSION_LEVEL) {
+ src_bw_p = &(src_sdp_p->bw);
+ } else {
+ mca_p = sdp_find_media_level(src_sdp_p, src_level);
+ if (mca_p == NULL) {
+ if (src_sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Invalid src media level (%u) for copy all "
+ "attrs ", src_sdp_p->debug_str, src_level);
+ }
+ return (SDP_INVALID_PARAMETER);
+ }
+ src_bw_p = &(mca_p->bw);
+ }
+
+ /* Find dst bw list */
+ if (dst_level == SDP_SESSION_LEVEL) {
+ dst_bw_p = &(dst_sdp_p->bw);
+ } else {
+ mca_p = sdp_find_media_level(dst_sdp_p, dst_level);
+ if (mca_p == NULL) {
+ if (src_sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Invalid dst media level (%u) for copy all "
+ "attrs ", src_sdp_p->debug_str, dst_level);
+ }
+ return (SDP_INVALID_PARAMETER);
+ }
+ dst_bw_p = &(mca_p->bw);
+ }
+
+ orig_bw_data_p = src_bw_p->bw_data_list;
+ while (orig_bw_data_p) {
+ /* For ever bw line in the src, allocate a new one for the dst */
+ new_bw_data_p = (sdp_bw_data_t*)SDP_MALLOC(sizeof(sdp_bw_data_t));
+ if (new_bw_data_p == NULL) {
+ return (SDP_NO_RESOURCE);
+ }
+ new_bw_data_p->next_p = NULL;
+ new_bw_data_p->bw_modifier = orig_bw_data_p->bw_modifier;
+ new_bw_data_p->bw_val = orig_bw_data_p->bw_val;
+
+ /*
+ * Enqueue the sdp_bw_data_t instance at the end of the list of
+ * sdp_bw_data_t instances.
+ */
+ if (dst_bw_p->bw_data_list == NULL) {
+ dst_bw_p->bw_data_list = new_bw_data_p;
+ } else {
+ for (bw_data_p = dst_bw_p->bw_data_list;
+ bw_data_p->next_p != NULL;
+ bw_data_p = bw_data_p->next_p) {
+
+ /*sa_ignore EMPTYLOOP*/
+ ; /* Do nothing. */
+ }
+
+ bw_data_p->next_p = new_bw_data_p;
+ }
+ dst_bw_p->bw_data_count++;
+
+ orig_bw_data_p = orig_bw_data_p->next_p;
+ }
+
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_get_bw_modifier
+ * Description: Returns the bandwidth modifier parameter from the b=
+ * line. If no bw modifier has been set ,
+ * SDP_BW_MODIFIER_UNSUPPORTED will be returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level from which to get the bw modifier.
+ * inst_num instance number of bw line at that level. The first
+ * instance has a inst_num of 1 and so on.
+ * Returns: Valid modifer value or SDP_BW_MODIFIER_UNSUPPORTED.
+ */
+sdp_bw_modifier_e sdp_get_bw_modifier (void *sdp_ptr, u16 level, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_bw_data_t *bw_data_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_BW_MODIFIER_UNSUPPORTED);
+ }
+
+ bw_data_p = sdp_find_bw_line(sdp_p, level, inst_num);
+
+ if (bw_data_p) {
+ return (bw_data_p->bw_modifier);
+ } else {
+ return (SDP_BW_MODIFIER_UNSUPPORTED);
+ }
+}
+
+/* Function: sdp_get_bw_value
+ * Description: Returns the bandwidth value parameter from the b=
+ * line.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level from which to get the bw value.
+ * inst_num instance number of bw line at the level. The first
+ * instance has a inst_num of 1 and so on.
+ * Returns: A valid numerical bw value or SDP_INVALID_VALUE.
+ */
+int32 sdp_get_bw_value (void *sdp_ptr, u16 level, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_bw_data_t *bw_data_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_VALUE);
+ }
+
+ bw_data_p = sdp_find_bw_line(sdp_p, level, inst_num);
+
+ if (bw_data_p) {
+ return (bw_data_p->bw_val);
+ } else {
+ return (SDP_INVALID_VALUE);
+ }
+}
+
+/*
+ * sdp_get_num_bw_lines
+ *
+ * Returns the number of bw lines are present at a given level.
+ *
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level at which the count of bw lines is required
+ *
+ * Returns: A valid count or SDP_INVALID_VALUE
+ */
+int32 sdp_get_num_bw_lines (void *sdp_ptr, u16 level)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_bw_t *bw_p;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_VALUE);
+ }
+
+ if (level == SDP_SESSION_LEVEL) {
+ bw_p = &(sdp_p->bw);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ }
+ bw_p = &(mca_p->bw);
+ }
+
+ return (bw_p->bw_data_count);
+}
+
+/*
+ * sdp_add_new_bw_line
+ *
+ * To specify bandwidth parameters at any level, a bw line must first be
+ * added at that level using this function. After this addition, you can set
+ * the properties of the added bw line by using sdp_set_bw().
+ *
+ * Note carefully though, that since there can be multiple instances of bw
+ * lines at any level, you must specify the instance number when setting
+ * or getting the properties of a bw line at any level.
+ *
+ * This function returns within the inst_num variable, the instance number
+ * of the created bw_line at that level. The instance number is 1-based.
+ * For example:
+ * v=0 #Session Level
+ * o=mhandley 2890844526 2890842807 IN IP4 126.16.64.4
+ * s=SDP Seminar
+ * c=IN IP4 10.1.0.2
+ * t=0 0
+ * b=AS:60 # instance number 1
+ * b=TIAS:50780 # instance number 2
+ * m=audio 1234 RTP/AVP 0 101 102 # 1st Media level
+ * b=AS:12 # instance number 1
+ * b=TIAS:8480 # instance number 2
+ * m=audio 1234 RTP/AVP 0 101 102 # 2nd Media level
+ * b=AS:20 # instance number 1
+ *
+ * Parameters:
+ * sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to create the bw line.
+ * bw_modifier The Type of bandwidth, CT, AS or TIAS.
+ * *inst_num This memory is set with the instance number of the newly
+ * created bw line instance.
+ */
+sdp_result_e sdp_add_new_bw_line (void *sdp_ptr, u16 level, sdp_bw_modifier_e bw_modifier, u16 *inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_bw_t *bw_p;
+ sdp_mca_t *mca_p;
+ sdp_bw_data_t *new_bw_data_p;
+ sdp_bw_data_t *bw_data_p = NULL;
+
+ *inst_num = 0;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ if (level == SDP_SESSION_LEVEL) {
+ bw_p = &(sdp_p->bw);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ bw_p = &(mca_p->bw);
+ }
+
+ //see if a bw line already exist for this bw_modifier.
+ for(bw_data_p = bw_p->bw_data_list; bw_data_p != NULL; bw_data_p = bw_data_p->next_p) {
+ ++(*inst_num);
+ if (bw_data_p->bw_modifier == bw_modifier) {
+ return (SDP_SUCCESS);
+ }
+ }
+
+ /*
+ * Allocate a new sdp_bw_data_t instance and set it's values from the
+ * input parameters.
+ */
+ new_bw_data_p = (sdp_bw_data_t*)SDP_MALLOC(sizeof(sdp_bw_data_t));
+ if (new_bw_data_p == NULL) {
+ sdp_p->conf_p->num_no_resource++;
+ return (SDP_NO_RESOURCE);
+ }
+ new_bw_data_p->next_p = NULL;
+ new_bw_data_p->bw_modifier = SDP_BW_MODIFIER_UNSUPPORTED;
+ new_bw_data_p->bw_val = 0;
+
+ /*
+ * Enqueue the sdp_bw_data_t instance at the end of the list of
+ * sdp_bw_data_t instances.
+ */
+ if (bw_p->bw_data_list == NULL) {
+ bw_p->bw_data_list = new_bw_data_p;
+ } else {
+ for (bw_data_p = bw_p->bw_data_list;
+ bw_data_p->next_p != NULL;
+ bw_data_p = bw_data_p->next_p) {
+
+ /*sa_ignore EMPTYLOOP*/
+ ; /* Do nothing. */
+ }
+
+ bw_data_p->next_p = new_bw_data_p;
+ }
+ *inst_num = ++bw_p->bw_data_count;
+
+ return (SDP_SUCCESS);
+}
+
+/*
+ * sdp_delete_bw_line
+ *
+ * Deletes the bw line instance at the specified level.
+ *
+ * sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to delete the bw line.
+ * inst_num The instance of the bw line to delete.
+ */
+sdp_result_e sdp_delete_bw_line (void *sdp_ptr, u16 level, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_bw_t *bw_p;
+ sdp_mca_t *mca_p;
+ sdp_bw_data_t *bw_data_p = NULL;
+ sdp_bw_data_t *prev_bw_data_p = NULL;
+ int bw_data_count = 0;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ if (level == SDP_SESSION_LEVEL) {
+ bw_p = &(sdp_p->bw);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ bw_p = &(mca_p->bw);
+ }
+
+ bw_data_p = bw_p->bw_data_list;
+ while (bw_data_p != NULL) {
+ bw_data_count++;
+ if (bw_data_count == inst_num) {
+ break;
+ }
+
+ prev_bw_data_p = bw_data_p;
+ bw_data_p = bw_data_p->next_p;
+ }
+
+ if (bw_data_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s bw line instance %d not found.",
+ sdp_p->debug_str, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (prev_bw_data_p == NULL) {
+ bw_p->bw_data_list = bw_data_p->next_p;
+ } else {
+ prev_bw_data_p->next_p = bw_data_p->next_p;
+ }
+ bw_p->bw_data_count--;
+
+ SDP_FREE(bw_data_p);
+ return (SDP_SUCCESS);
+}
+
+/*
+ * sdp_set_bw
+ *
+ * Once a bandwidth line is added under a level, this function can be used to
+ * set the properties of that bandwidth line.
+ *
+ * Parameters:
+ * sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to at which the bw line resides.
+ * inst_num The instance number of the bw line that is to be set.
+ * bw_modifier The Type of bandwidth, CT, AS or TIAS.
+ * bw_val Numerical bandwidth value.
+ *
+ * NOTE: Before calling this function to set the bw line, the bw line must
+ * be added using sdp_add_new_bw_line at the required level.
+ */
+sdp_result_e sdp_set_bw (void *sdp_ptr, u16 level, u16 inst_num,
+ sdp_bw_modifier_e bw_modifier, u32 bw_val)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_bw_data_t *bw_data_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ if ((bw_modifier < SDP_BW_MODIFIER_AS) ||
+ (bw_modifier >= SDP_MAX_BW_MODIFIER_VAL)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Invalid bw modifier type: %d.",
+ sdp_p->debug_str, bw_modifier);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ bw_data_p = sdp_find_bw_line(sdp_p, level, inst_num);
+ if (bw_data_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s The %u instance of a b= line was not found at level %u.",
+ sdp_p->debug_str, inst_num, level);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ bw_data_p->bw_modifier = bw_modifier;
+ bw_data_p->bw_val = bw_val;
+
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_get_mid_value
+ * Description: Returns the mid value parameter from the a= mid: line.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level SDP_MEDIA_LEVEL
+ * Returns: mid value.
+ */
+int32 sdp_get_mid_value (void *sdp_ptr, u16 level)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_VALUE);
+ }
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ }
+ return (mca_p->mid);
+}
+
+/* Function: sdp_set_mid_value
+ * Description: Sets the value of the mid value for the
+ * a= mid: line.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level SDP_MEDIA_LEVEL
+ * mid_val mid value .
+ * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER
+*/
+sdp_result_e sdp_set_mid_value (void *sdp_ptr, u16 level, u32 mid_val)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ mca_p->mid = mid_val;
+ return (SDP_SUCCESS);
+}
diff --git a/libs/sipcc/core/sdp/sdp_attr.c b/libs/sipcc/core/sdp/sdp_attr.c
new file mode 100644
index 0000000000..6d794a2427
--- /dev/null
+++ b/libs/sipcc/core/sdp/sdp_attr.c
@@ -0,0 +1,4755 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include
+#include
+
+#include "plstr.h"
+#include "sdp_os_defs.h"
+#include "sdp.h"
+#include "sdp_private.h"
+#include "sdp_base64.h"
+//#include "mozilla/Assertions.h"
+#include "CSFLog.h"
+
+//static const char* logTag = "sdp_attr";
+
+/*
+ * Macro for sdp_build_attr_fmtp
+ * Adds name-value pair where value is char*
+ */
+#define FMTP_BUILD_STRING(condition, name, value) \
+ if ((condition)) { \
+ sdp_append_name_and_string(fs, (name), (value), semicolon); \
+ semicolon = TRUE; \
+ }
+
+/*
+ * Macro for sdp_build_attr_fmtp
+ * Adds name-value pair where value is unsigned
+ */
+#define FMTP_BUILD_UNSIGNED(condition, name, value) \
+ if ((condition)) { \
+ sdp_append_name_and_unsigned(fs, (name), (value), semicolon); \
+ semicolon = TRUE; \
+ }
+
+/*
+ * Macro for sdp_build_attr_fmtp
+ * Adds flag string on condition
+ */
+#define FMTP_BUILD_FLAG(condition, name) \
+ if ((condition)) { \
+ if (semicolon) { \
+ flex_string_append(fs, ";"); \
+ } \
+ flex_string_append(fs, name); \
+ semicolon = TRUE; \
+ }
+
+/*
+ * Helper function for adding nv-pair where value is string.
+ */
+static void sdp_append_name_and_string(flex_string *fs,
+ const char *name,
+ const char *value,
+ tinybool semicolon)
+{
+ flex_string_sprintf(fs, "%s%s=%s",
+ semicolon ? ";" : "",
+ name,
+ value);
+}
+
+/*
+ * Helper function for adding nv-pair where value is unsigned.
+ */
+static void sdp_append_name_and_unsigned(flex_string *fs,
+ const char *name,
+ unsigned int value,
+ tinybool semicolon)
+{
+ flex_string_sprintf(fs, "%s%s=%u",
+ semicolon ? ";" : "",
+ name,
+ value);
+}
+
+/* Function: sdp_parse_attribute
+ * Description: Figure out the type of attribute and call the appropriate
+ * parsing routine. If parsing errors are encountered,
+ * warnings will be printed and the attribute will be ignored.
+ * Unrecognized/invalid attributes do not cause overall parsing
+ * errors. All errors detected are noted as warnings.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * ptr Pointer to the attribute string to parse.
+ */
+sdp_result_e sdp_parse_attribute (sdp_t *sdp_p, u16 level, const char *ptr)
+{
+ int i;
+ u8 xcpar_flag = FALSE;
+ sdp_result_e result;
+ sdp_mca_t *mca_p=NULL;
+ sdp_attr_t *attr_p;
+ sdp_attr_t *next_attr_p;
+ sdp_attr_t *prev_attr_p = NULL;
+ char tmp[SDP_MAX_STRING_LEN];
+
+ /* Validate the level */
+ if (level != SDP_SESSION_LEVEL) {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (SDP_FAILURE);
+ }
+ }
+
+ /* Find the attribute type. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), ": \t", &result);
+ if (ptr == NULL) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s No attribute type specified, parse failed.", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ if (ptr[0] == ':') {
+ /* Skip the ':' char for parsing attribute parameters. */
+ ptr++;
+ }
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s No attribute type specified, parse failed.", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = (sdp_attr_t *)SDP_MALLOC(sizeof(sdp_attr_t));
+ if (attr_p == NULL) {
+ sdp_p->conf_p->num_no_resource++;
+ return (SDP_NO_RESOURCE);
+ }
+ attr_p->type = SDP_ATTR_INVALID;
+ attr_p->next_p = NULL;
+ for (i=0; i < SDP_MAX_ATTR_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_attr[i].name, sdp_attr[i].strlen) == 0) {
+ attr_p->type = (sdp_attr_e)i;
+ break;
+ }
+ }
+ if (attr_p->type == SDP_ATTR_INVALID) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: Unrecognized attribute (%s) ",
+ sdp_p->debug_str, tmp);
+ sdp_free_attr(attr_p);
+ return (SDP_SUCCESS);
+ }
+
+ /* If this is an X-cpar or cpar attribute, set the flag. The attribute
+ * type will be changed by the parse. */
+ if ((attr_p->type == SDP_ATTR_X_CPAR) ||
+ (attr_p->type == SDP_ATTR_CPAR)) {
+ xcpar_flag = TRUE;
+ }
+
+ /* Parse the attribute. */
+ result = sdp_attr[attr_p->type].parse_func(sdp_p, attr_p, ptr);
+ if (result != SDP_SUCCESS) {
+ sdp_free_attr(attr_p);
+ /* Return success so the parse won't fail. We don't want to
+ * fail on errors with attributes but just ignore them.
+ */
+ return (SDP_SUCCESS);
+ }
+
+ /* If this was an X-cpar/cpar attribute, it was hooked into the X-cap/cdsc
+ * structure, so we're finished.
+ */
+ if (xcpar_flag == TRUE) {
+ return (result);
+ }
+
+ /* Add the attribute in the appropriate place. */
+ if (level == SDP_SESSION_LEVEL) {
+ for (next_attr_p = sdp_p->sess_attrs_p; next_attr_p != NULL;
+ prev_attr_p = next_attr_p,
+ next_attr_p = next_attr_p->next_p) {
+ ; /* Empty for */
+ }
+ if (prev_attr_p == NULL) {
+ sdp_p->sess_attrs_p = attr_p;
+ } else {
+ prev_attr_p->next_p = attr_p;
+ }
+ } else {
+ for (next_attr_p = mca_p->media_attrs_p; next_attr_p != NULL;
+ prev_attr_p = next_attr_p,
+ next_attr_p = next_attr_p->next_p) {
+ ; /* Empty for */
+ }
+ if (prev_attr_p == NULL) {
+ mca_p->media_attrs_p = attr_p;
+ } else {
+ prev_attr_p->next_p = attr_p;
+ }
+ }
+
+ return (result);
+}
+
+/* Build all of the attributes defined for the specified level. */
+sdp_result_e sdp_build_attribute (sdp_t *sdp_p, u16 level, flex_string *fs)
+{
+ sdp_attr_t *attr_p;
+ sdp_mca_t *mca_p=NULL;
+ sdp_result_e result;
+
+ if (level == SDP_SESSION_LEVEL) {
+ attr_p = sdp_p->sess_attrs_p;
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (SDP_FAILURE);
+ }
+ attr_p = mca_p->media_attrs_p;
+ }
+ /* Re-initialize the current capability number for this new level. */
+ sdp_p->cur_cap_num = 1;
+
+ /* Build all of the attributes for this level. Note that if there
+ * is a problem building an attribute, we don't fail but just ignore it.*/
+ while (attr_p != NULL) {
+ if (attr_p->type >= SDP_MAX_ATTR_TYPES) {
+ if (sdp_p->debug_flag[SDP_DEBUG_WARNINGS]) {
+ CSFLogDebug(logTag, "%s Invalid attribute type to build (%u)",
+ sdp_p->debug_str, attr_p->type);
+ }
+ } else {
+ result = sdp_attr[attr_p->type].build_func(sdp_p, attr_p, fs);
+
+ if (result != SDP_SUCCESS) {
+ CSFLogError(logTag, "%s error building attribute %d", __FUNCTION__, result);
+ return result;
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Built a=%s attribute line", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type));
+ }
+ }
+ attr_p = attr_p->next_p;
+ }
+
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_parse_attr_simple_string (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ sdp_result_e result;
+
+ ptr = sdp_getnextstrtok(ptr, attr_p->attr.string_val,
+ sizeof(attr_p->attr.string_val), " \t", &result);
+
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No string token found for %s attribute",
+ sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, %s", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type),
+ attr_p->attr.string_val);
+ }
+ return (SDP_SUCCESS);
+ }
+}
+
+sdp_result_e sdp_build_attr_simple_string (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ flex_string_sprintf(fs, "a=%s:%s\r\n", sdp_attr[attr_p->type].name,
+ attr_p->attr.string_val);
+
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_parse_attr_simple_u32 (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ sdp_result_e result;
+
+ attr_p->attr.u32_val = sdp_getnextnumtok(ptr, &ptr, " \t", &result);
+
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: Numeric token for %s attribute not found",
+ sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, %lu", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type), attr_p->attr.u32_val);
+ }
+ return (SDP_SUCCESS);
+ }
+}
+
+sdp_result_e sdp_build_attr_simple_u32 (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ flex_string_sprintf(fs, "a=%s:%u\r\n", sdp_attr[attr_p->type].name,
+ attr_p->attr.u32_val);
+
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_parse_attr_simple_bool (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ sdp_result_e result;
+
+ if (sdp_getnextnumtok(ptr, &ptr, " \t", &result) == 0) {
+ attr_p->attr.boolean_val = FALSE;
+ } else {
+ attr_p->attr.boolean_val= TRUE;
+ }
+
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: Boolean token for %s attribute not found",
+ sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ if (attr_p->attr.boolean_val) {
+ SDP_PRINT("%s Parsed a=%s, boolean is TRUE", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type));
+ } else {
+ SDP_PRINT("%s Parsed a=%s, boolean is FALSE", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type));
+ }
+ }
+ return (SDP_SUCCESS);
+ }
+}
+
+sdp_result_e sdp_build_attr_simple_bool (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ flex_string_sprintf(fs, "a=%s:%s\r\n", sdp_attr[attr_p->type].name,
+ attr_p->attr.boolean_val ? "1" : "0");
+
+ return SDP_SUCCESS;
+}
+
+/*
+ * sdp_parse_attr_maxprate
+ *
+ * This function parses maxprate attribute lines. The ABNF for this a=
+ * line is:
+ * max-p-rate-def = "a" "=" "maxprate" ":" packet-rate CRLF
+ * packet-rate = 1*DIGIT ["." 1*DIGIT]
+ *
+ * Returns:
+ * SDP_INVALID_PARAMETER - If we are unable to parse the string OR if
+ * packet-rate is not in the right format as per
+ * the ABNF.
+ *
+ * SDP_SUCCESS - If we are able to successfully parse the a= line.
+ */
+sdp_result_e sdp_parse_attr_maxprate (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ sdp_result_e result;
+
+ ptr = sdp_getnextstrtok(ptr, attr_p->attr.string_val,
+ sizeof(attr_p->attr.string_val), " \t", &result);
+
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No string token found for %s attribute",
+ sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ if (!sdp_validate_maxprate(attr_p->attr.string_val)) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s is not a valid maxprate value.",
+ attr_p->attr.string_val);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, %s", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type),
+ attr_p->attr.string_val);
+ }
+ return (SDP_SUCCESS);
+ }
+}
+
+/*
+ * sdp_attr_fmtp_no_value
+ * Helper function for sending the warning when a parameter value is
+ * missing.
+ *
+ */
+static void sdp_attr_fmtp_no_value(sdp_t *sdp, char *param_name)
+{
+ sdp_parse_error(sdp->peerconnection,
+ "%s Warning: No %s value specified for fmtp attribute",
+ sdp->debug_str, param_name);
+ sdp->conf_p->num_invalid_param++;
+}
+
+/*
+ * sdp_attr_fmtp_invalid_value
+ * Helper function for sending the warning when a parameter value is
+ * incorrect.
+ *
+ */
+
+static void sdp_attr_fmtp_invalid_value(sdp_t *sdp, char *param_name,
+ char* param_value)
+{
+ sdp_parse_error(sdp->peerconnection,
+ "%s Warning: Invalid %s: %s specified for fmtp attribute",
+ sdp->debug_str, param_name, param_value);
+ sdp->conf_p->num_invalid_param++;
+}
+
+/* Note: The fmtp attribute formats currently handled are:
+ * fmtp: ,...
+ * fmtp: [annexa=yes/no] [annexb=yes/no] [bitrate=]
+ * [QCIF =] [CIF =] [MaxBR = ] one or more
+ * Other FMTP params as per H.263, H.263+, H.264 codec support.
+ * Note -"value" is a numeric value > 0 and each event is a
+ * single number or a range separated by a '-'.
+ * Example: fmtp:101 1,3-15,20
+ * Video codecs have annexes that can be listed in the following legal formats:
+ * a) a=fmtp:34 param1=token;D;I;J;K=1;N=2;P=1,3
+ * b) a=fmtp:34 param1=token;D;I;J;K=1;N=2;P=1,3;T
+ * c) a=fmtp:34 param1=token;D;I;J
+ *
+ */
+
+sdp_result_e sdp_parse_attr_fmtp (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ u16 i;
+ u32 mapword;
+ u32 bmap;
+ u8 low_val;
+ u8 high_val;
+ const char *ptr2;
+ const char *fmtp_ptr;
+ sdp_result_e result1 = SDP_SUCCESS;
+ sdp_result_e result2 = SDP_SUCCESS;
+ tinybool done = FALSE;
+ tinybool codec_info_found = FALSE;
+ sdp_fmtp_t *fmtp_p;
+ char tmp[SDP_MAX_STRING_LEN];
+ char *src_ptr;
+ char *temp_ptr = NULL;
+ tinybool flag=FALSE;
+ char *tok=NULL;
+ char *temp=NULL;
+ u16 custom_x=0;
+ u16 custom_y=0;
+ u16 custom_mpi=0;
+ u16 par_height=0;
+ u16 par_width=0;
+ u16 cpcf=0;
+ u16 iter=0;
+
+ ulong l_val = 0;
+ char* strtok_state;
+ unsigned long strtoul_result;
+ char* strtoul_end;
+
+ /* Find the payload type number. */
+ attr_p->attr.fmtp.payload_num = (u16)sdp_getnextnumtok(ptr, &ptr,
+ " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "payload type");
+ return SDP_INVALID_PARAMETER;
+ }
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_UNKNOWN_TYPE;
+ fmtp_p->parameter_add = TRUE;
+ fmtp_p->flag = 0;
+
+ /*
+ * set default value of packetization mode and level-asymmetry-allowed. If
+ * remote sdp does not specify any value for these two parameters, then the
+ * default value will be assumed for remote sdp. If remote sdp does specify
+ * any value for these parameters, then default value will be overridden.
+ */
+ fmtp_p->packetization_mode = 0;
+ fmtp_p->level_asymmetry_allowed = SDP_DEFAULT_LEVEL_ASYMMETRY_ALLOWED_VALUE;
+
+ /* BEGIN - a typical macro fn to replace '/' with ';' from fmtp line*/
+ /* This ugly replacement of '/' with ';' is only done because
+ * econf/MS client sends in this wierd /illegal format.
+ * fmtp parameters MUST be separated by ';'
+ */
+ temp_ptr = cpr_strdup(ptr);
+ if (temp_ptr == NULL) {
+ return (SDP_FAILURE);
+ }
+ fmtp_ptr = src_ptr = temp_ptr;
+ while (flag == FALSE) {
+ if (*src_ptr == '\n') {
+ flag = TRUE;
+ break;
+ }
+ if (*src_ptr == '/') {
+ *src_ptr =';' ;
+ }
+ src_ptr++;
+ }
+ /* END */
+ /* Once we move to RFC compliant video codec implementations, the above
+ * patch should be removed */
+ while (!done) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "= \t", &result1);
+ if (result1 == SDP_SUCCESS) {
+ if (cpr_strncasecmp(tmp, sdp_fmtp_codec_param[1].name,
+ sdp_fmtp_codec_param[1].strlen) == 0) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "annexb");
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ tok = tmp;
+ tok++;
+ if (cpr_strncasecmp(tok,sdp_fmtp_codec_param_val[0].name,
+ sdp_fmtp_codec_param_val[0].strlen) == 0) {
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->annexb_required = TRUE;
+ fmtp_p->annexb = TRUE;
+ } else if (cpr_strncasecmp(tok,sdp_fmtp_codec_param_val[1].name,
+ sdp_fmtp_codec_param_val[1].strlen) == 0) {
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->annexb_required = TRUE;
+ fmtp_p->annexb = FALSE;
+ } else {
+ sdp_attr_fmtp_invalid_value(sdp_p, "annexb", tok);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp, sdp_fmtp_codec_param[0].name,
+ sdp_fmtp_codec_param[0].strlen) == 0) {
+
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "annexa");
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ tok = tmp;
+ tok++;
+ if (cpr_strncasecmp(tok,sdp_fmtp_codec_param_val[0].name,
+ sdp_fmtp_codec_param_val[0].strlen) == 0) {
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->annexa = TRUE;
+ fmtp_p->annexa_required = TRUE;
+ } else if (cpr_strncasecmp(tok,sdp_fmtp_codec_param_val[1].name,
+ sdp_fmtp_codec_param_val[1].strlen) == 0) {
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->annexa = FALSE;
+ fmtp_p->annexa_required = TRUE;
+ } else {
+ sdp_attr_fmtp_invalid_value(sdp_p, "annexa", tok);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[2].name,
+ sdp_fmtp_codec_param[2].strlen) == 0) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "bitrate");
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ tok = tmp;
+ tok++;
+
+ errno = 0;
+ strtoul_result = strtoul(tok, &strtoul_end, 10);
+
+ if (errno || tok == strtoul_end || strtoul_result == 0 || strtoul_result > UINT_MAX) {
+ sdp_attr_fmtp_invalid_value(sdp_p, "bitrate", tok);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->bitrate = (u32) strtoul_result;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[41].name,
+ sdp_fmtp_codec_param[41].strlen) == 0) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "mode");
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ tok = tmp;
+ tok++;
+
+ errno = 0;
+ strtoul_result = strtoul(tok, &strtoul_end, 10);
+
+ if (errno || tok == strtoul_end || strtoul_result > UINT_MAX) {
+ sdp_attr_fmtp_invalid_value(sdp_p, "mode", tok);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+
+ fmtp_p->fmtp_format = SDP_FMTP_MODE;
+ fmtp_p->mode = (u32) strtoul_result;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[3].name,
+ sdp_fmtp_codec_param[3].strlen) == 0) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "qcif");
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ tok = tmp;
+ tok++;
+
+ errno = 0;
+ strtoul_result = strtoul(tok, &strtoul_end, 10);
+
+ if (errno || tok == strtoul_end ||
+ strtoul_result < SDP_MIN_CIF_VALUE || strtoul_result > SDP_MAX_CIF_VALUE) {
+ sdp_attr_fmtp_invalid_value(sdp_p, "qcif", tok);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->qcif = (u16) strtoul_result;
+ codec_info_found = TRUE;
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[4].name,
+ sdp_fmtp_codec_param[4].strlen) == 0) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "cif");
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ tok = tmp;
+ tok++;
+
+ errno = 0;
+ strtoul_result = strtoul(tok, &strtoul_end, 10);
+
+ if (errno || tok == strtoul_end ||
+ strtoul_result < SDP_MIN_CIF_VALUE || strtoul_result > SDP_MAX_CIF_VALUE) {
+ sdp_attr_fmtp_invalid_value(sdp_p, "cif", tok);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->cif = (u16) strtoul_result;
+ codec_info_found = TRUE;
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[5].name,
+ sdp_fmtp_codec_param[5].strlen) == 0) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "maxbr");
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ tok = tmp;
+ tok++;
+
+ errno = 0;
+ strtoul_result = strtoul(tok, &strtoul_end, 10);
+
+ if (errno || tok == strtoul_end ||
+ strtoul_result == 0 || strtoul_result > USHRT_MAX) {
+ sdp_attr_fmtp_invalid_value(sdp_p, "maxbr", tok);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->maxbr = (u16) strtoul_result;
+ codec_info_found = TRUE;
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[6].name,
+ sdp_fmtp_codec_param[6].strlen) == 0) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "sqcif");
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ tok = tmp;
+ tok++;
+
+ errno = 0;
+ strtoul_result = strtoul(tok, &strtoul_end, 10);
+
+ if (errno || tok == strtoul_end ||
+ strtoul_result < SDP_MIN_CIF_VALUE || strtoul_result > SDP_MAX_CIF_VALUE) {
+ sdp_attr_fmtp_invalid_value(sdp_p, "sqcif", tok);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->sqcif = (u16) strtoul_result;
+ codec_info_found = TRUE;
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[7].name,
+ sdp_fmtp_codec_param[7].strlen) == 0) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "cif4");
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ tok = tmp;
+ tok++;
+
+ errno = 0;
+ strtoul_result = strtoul(tok, &strtoul_end, 10);
+
+ if (errno || tok == strtoul_end ||
+ strtoul_result < SDP_MIN_CIF_VALUE || strtoul_result > SDP_MAX_CIF_VALUE) {
+ sdp_attr_fmtp_invalid_value(sdp_p, "cif4", tok);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->cif4 = (u16) strtoul_result;
+ codec_info_found = TRUE;
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[8].name,
+ sdp_fmtp_codec_param[8].strlen) == 0) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "cif16");
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ tok = tmp;
+ tok++;
+
+ errno = 0;
+ strtoul_result = strtoul(tok, &strtoul_end, 10);
+
+ if (errno || tok == strtoul_end ||
+ strtoul_result < SDP_MIN_CIF_VALUE || strtoul_result > SDP_MAX_CIF_VALUE) {
+ sdp_attr_fmtp_invalid_value(sdp_p, "cif16", tok);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->cif16 = (u16) strtoul_result;
+ codec_info_found = TRUE;
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[9].name,
+ sdp_fmtp_codec_param[9].strlen) == 0) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "custom");
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ tok = tmp;
+ tok++; temp=PL_strtok_r(tok, ",", &strtok_state);
+ iter++;
+ if (temp) {
+ iter=1;
+ while (temp != NULL) {
+ errno = 0;
+ strtoul_result = strtoul(temp, &strtoul_end, 10);
+
+ if (errno || temp == strtoul_end || strtoul_result > USHRT_MAX){
+ custom_x = custom_y = custom_mpi = 0;
+ break;
+ }
+
+ if (iter == 1)
+ custom_x = (u16) strtoul_result;
+ if (iter == 2)
+ custom_y = (u16) strtoul_result;
+ if (iter == 3)
+ custom_mpi = (u16) strtoul_result;
+
+ temp=PL_strtok_r(NULL, ",", &strtok_state);
+ iter++;
+ }
+ }
+
+ /* custom x,y and mpi values from tmp */
+ if (!custom_x || !custom_y || !custom_mpi) {
+ sdp_attr_fmtp_invalid_value(sdp_p, "x/y/MPI", temp);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->custom_x = custom_x;
+ fmtp_p->custom_y = custom_y;
+ fmtp_p->custom_mpi = custom_mpi;
+ codec_info_found = TRUE;
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[10].name,
+ sdp_fmtp_codec_param[10].strlen) == 0) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "par");
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ tok = tmp;
+ tok++; temp=PL_strtok_r(tok, ":", &strtok_state);
+ if (temp) {
+ iter=1;
+ /* get par width and par height for the aspect ratio */
+ while (temp != NULL) {
+ errno = 0;
+ strtoul_result = strtoul(temp, &strtoul_end, 10);
+
+ if (errno || temp == strtoul_end || strtoul_result > USHRT_MAX) {
+ par_width = par_height = 0;
+ break;
+ }
+
+ if (iter == 1)
+ par_width = (u16) strtoul_result;
+ else
+ par_height = (u16) strtoul_result;
+
+ temp=PL_strtok_r(NULL, ",", &strtok_state);
+ iter++;
+ }
+ }
+ if (!par_width || !par_height) {
+ sdp_attr_fmtp_invalid_value(sdp_p, "par_width or par_height", temp);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->par_width = par_width;
+ fmtp_p->par_height = par_height;
+ codec_info_found = TRUE;
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[11].name,
+ sdp_fmtp_codec_param[11].strlen) == 0) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "cpcf");
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ tok = tmp;
+ tok++; temp=PL_strtok_r(tok, ".", &strtok_state);
+ if ( temp != NULL ) {
+ errno = 0;
+ strtoul_result = strtoul(temp, &strtoul_end, 10);
+
+ if (errno || temp == strtoul_end || strtoul_result > USHRT_MAX) {
+ cpcf = 0;
+ } else {
+ cpcf = (u16) strtoul_result;
+ }
+ }
+
+ if (!cpcf) {
+ sdp_attr_fmtp_invalid_value(sdp_p, "cpcf", tok);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->cpcf = cpcf;
+ codec_info_found = TRUE;
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[12].name,
+ sdp_fmtp_codec_param[12].strlen) == 0) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "bpp");
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ tok = tmp;
+ tok++;
+
+ errno = 0;
+ strtoul_result = strtoul(tok, &strtoul_end, 10);
+
+ if (errno || tok == strtoul_end || strtoul_result == 0 || strtoul_result > USHRT_MAX) {
+ sdp_attr_fmtp_invalid_value(sdp_p, "bpp", tok);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->bpp = (u16) strtoul_result;
+ codec_info_found = TRUE;
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[13].name,
+ sdp_fmtp_codec_param[13].strlen) == 0) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "hrd");
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ tok = tmp;
+ tok++;
+
+ errno = 0;
+ strtoul_result = strtoul(tok, &strtoul_end, 10);
+
+ if (errno || tok == strtoul_end || strtoul_result == 0 || strtoul_result > USHRT_MAX) {
+ sdp_attr_fmtp_invalid_value(sdp_p, "hrd", tok);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->hrd = (u16) strtoul_result;
+ codec_info_found = TRUE;
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[14].name,
+ sdp_fmtp_codec_param[14].strlen) == 0) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "profile");
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ tok = tmp;
+ tok++;
+
+ errno = 0;
+ strtoul_result = strtoul(tok, &strtoul_end, 10);
+
+ if (errno || tok == strtoul_end ||
+ strtoul_result > SDP_MAX_PROFILE_VALUE) {
+ sdp_attr_fmtp_invalid_value(sdp_p, "profile", tok);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->profile = (short) strtoul_result;
+ codec_info_found = TRUE;
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[15].name,
+ sdp_fmtp_codec_param[15].strlen) == 0) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "level");
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ tok = tmp;
+ tok++;
+
+ errno = 0;
+ strtoul_result = strtoul(tok, &strtoul_end, 10);
+
+ if (errno || tok == strtoul_end ||
+ strtoul_result > SDP_MAX_LEVEL_VALUE) {
+ sdp_attr_fmtp_invalid_value(sdp_p, "level", tok);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->level = (short) strtoul_result;
+ codec_info_found = TRUE;
+ } if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[16].name,
+ sdp_fmtp_codec_param[16].strlen) == 0) {
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->is_interlace = TRUE;
+ codec_info_found = TRUE;
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[17].name,
+ sdp_fmtp_codec_param[17].strlen) == 0) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "profile_level_id");
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ tok = tmp;
+ tok++;
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ sstrncpy(fmtp_p->profile_level_id , tok, sizeof(fmtp_p->profile_level_id));
+ codec_info_found = TRUE;
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[18].name,
+ sdp_fmtp_codec_param[18].strlen) == 0) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "parameter_sets");
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ tok = tmp;
+ tok++;
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ sstrncpy(fmtp_p->parameter_sets , tok, sizeof(fmtp_p->parameter_sets));
+ codec_info_found = TRUE;
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[19].name,
+ sdp_fmtp_codec_param[19].strlen) == 0) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "packetization_mode");
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ tok = tmp;
+ tok++;
+
+ errno = 0;
+ strtoul_result = strtoul(tok, &strtoul_end, 10);
+
+ if (errno || tok == strtoul_end || strtoul_result > 2) {
+ sdp_attr_fmtp_invalid_value(sdp_p, "packetization_mode", tok);
+ sdp_p->conf_p->num_invalid_param++;
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->packetization_mode = (int16) strtoul_result;
+ codec_info_found = TRUE;
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[20].name,
+ sdp_fmtp_codec_param[20].strlen) == 0) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "interleaving_depth");
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ tok = tmp;
+ tok++;
+
+ errno = 0;
+ strtoul_result = strtoul(tok, &strtoul_end, 10);
+
+ if (errno || tok == strtoul_end || strtoul_result == 0 || strtoul_result > USHRT_MAX) {
+ sdp_attr_fmtp_invalid_value(sdp_p, "interleaving_depth", tok);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->interleaving_depth = (u16) strtoul_result;
+ codec_info_found = TRUE;
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[21].name,
+ sdp_fmtp_codec_param[21].strlen) == 0) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "deint_buf");
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ tok = tmp;
+ tok++;
+ if (sdp_checkrange(sdp_p, tok, &l_val) == TRUE) {
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->deint_buf_req = (u32) l_val;
+ fmtp_p->flag |= SDP_DEINT_BUF_REQ_FLAG;
+ codec_info_found = TRUE;
+ } else {
+ sdp_attr_fmtp_invalid_value(sdp_p, "deint_buf_req", tok);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[22].name,
+ sdp_fmtp_codec_param[22].strlen) == 0) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "max_don_diff");
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ tok = tmp;
+ tok++;
+
+ errno = 0;
+ strtoul_result = strtoul(tok, &strtoul_end, 10);
+
+ if (errno || tok == strtoul_end || strtoul_result == 0 || strtoul_result > UINT_MAX) {
+ sdp_attr_fmtp_invalid_value(sdp_p, "max_don_diff", tok);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->max_don_diff = (u32) strtoul_result;
+ codec_info_found = TRUE;
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[23].name,
+ sdp_fmtp_codec_param[23].strlen) == 0) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "init_buf_time");
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ tok = tmp;
+ tok++;
+ if (sdp_checkrange(sdp_p, tok, &l_val) == TRUE) {
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->init_buf_time = (u32) l_val;
+ fmtp_p->flag |= SDP_INIT_BUF_TIME_FLAG;
+ codec_info_found = TRUE;
+ } else {
+ sdp_attr_fmtp_invalid_value(sdp_p, "init_buf_time", tok);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[24].name,
+ sdp_fmtp_codec_param[24].strlen) == 0) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "max_mbps");
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ tok = tmp;
+ tok++;
+
+ errno = 0;
+ strtoul_result = strtoul(tok, &strtoul_end, 10);
+
+ if (errno || tok == strtoul_end || strtoul_result == 0 || strtoul_result > UINT_MAX) {
+ sdp_attr_fmtp_invalid_value(sdp_p, "max_mbps", tok);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->max_mbps = (u32) strtoul_result;
+ codec_info_found = TRUE;
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[25].name,
+ sdp_fmtp_codec_param[25].strlen) == 0) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "max_fs");
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ tok = tmp;
+ tok++;
+
+ errno = 0;
+ strtoul_result = strtoul(tok, &strtoul_end, 10);
+
+ if (errno || tok == strtoul_end || strtoul_result == 0 || strtoul_result > UINT_MAX) {
+ sdp_attr_fmtp_invalid_value(sdp_p, "max_fs", tok);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->max_fs = (u32) strtoul_result;
+ codec_info_found = TRUE;
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[26].name,
+ sdp_fmtp_codec_param[26].strlen) == 0) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "max_cbp");
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ tok = tmp;
+ tok++;
+
+ errno = 0;
+ strtoul_result = strtoul(tok, &strtoul_end, 10);
+
+ if (errno || tok == strtoul_end || strtoul_result == 0 || strtoul_result > UINT_MAX) {
+ sdp_attr_fmtp_invalid_value(sdp_p, "max_cpb", tok);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->max_cpb = (u32) strtoul_result;
+ codec_info_found = TRUE;
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[27].name,
+ sdp_fmtp_codec_param[27].strlen) == 0) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "max_dpb");
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ tok = tmp;
+ tok++;
+
+ errno = 0;
+ strtoul_result = strtoul(tok, &strtoul_end, 10);
+
+ if (errno || tok == strtoul_end || strtoul_result == 0 || strtoul_result > UINT_MAX) {
+ sdp_attr_fmtp_invalid_value(sdp_p, "max_dpb", tok);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->max_dpb = (u32) strtoul_result;
+ codec_info_found = TRUE;
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[28].name,
+ sdp_fmtp_codec_param[28].strlen) == 0) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "max_br");
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ tok = tmp;
+ tok++;
+
+ errno = 0;
+ strtoul_result = strtoul(tok, &strtoul_end, 10);
+
+ if (errno || tok == strtoul_end || strtoul_result == 0 || strtoul_result > UINT_MAX) {
+ sdp_attr_fmtp_invalid_value(sdp_p, "max_br", tok);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->max_br = (u32) strtoul_result;
+ codec_info_found = TRUE;
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[29].name,
+ sdp_fmtp_codec_param[29].strlen) == 0) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "redundant_pic_cap");
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ tok = tmp;
+ tok++;
+
+ errno = 0;
+ strtoul_result = strtoul(tok, &strtoul_end, 10);
+
+ if (!errno && tok != strtoul_end && strtoul_result == 1) {
+ fmtp_p->redundant_pic_cap = TRUE;
+ } else {
+ fmtp_p->redundant_pic_cap = FALSE;
+ }
+
+ codec_info_found = TRUE;
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[30].name,
+ sdp_fmtp_codec_param[30].strlen) == 0) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "deint_buf_cap");
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ tok = tmp;
+ tok++;
+ if (sdp_checkrange(sdp_p, tok, &l_val) == TRUE) {
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->deint_buf_cap = (u32) l_val;
+ fmtp_p->flag |= SDP_DEINT_BUF_CAP_FLAG;
+ codec_info_found = TRUE;
+ } else {
+ sdp_attr_fmtp_invalid_value(sdp_p, "deint_buf_cap", tok);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[31].name,
+ sdp_fmtp_codec_param[31].strlen) == 0) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "max_rcmd_nalu_size");
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ tok = tmp;
+ tok++;
+ if (sdp_checkrange(sdp_p, tok, &l_val) == TRUE) {
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->max_rcmd_nalu_size = (u32) l_val;
+ fmtp_p->flag |= SDP_MAX_RCMD_NALU_SIZE_FLAG;
+ codec_info_found = TRUE;
+ } else {
+ sdp_attr_fmtp_invalid_value(sdp_p, "max_rcmd_nalu_size", tok);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[32].name,
+ sdp_fmtp_codec_param[32].strlen) == 0) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "parameter_add");
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ tok = tmp;
+ tok++;
+
+ errno = 0;
+ strtoul_result = strtoul(tok, &strtoul_end, 10);
+
+ if (errno || tok == strtoul_end || strtoul_result > 1) {
+ sdp_attr_fmtp_invalid_value(sdp_p, "parameter_add", tok);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+
+ if (strtoul_result == 1) {
+ fmtp_p->parameter_add = TRUE;
+ } else {
+ fmtp_p->parameter_add = FALSE;
+ }
+
+ codec_info_found = TRUE;
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[33].name,
+ sdp_fmtp_codec_param[33].strlen) == 0) {
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->annex_d = TRUE;
+ codec_info_found = TRUE;
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[34].name,
+ sdp_fmtp_codec_param[34].strlen) == 0) {
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->annex_f = TRUE;
+ codec_info_found = TRUE;
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[35].name,
+ sdp_fmtp_codec_param[35].strlen) == 0) {
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->annex_i = TRUE;
+ codec_info_found = TRUE;
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[36].name,
+ sdp_fmtp_codec_param[36].strlen) == 0) {
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->annex_j = TRUE;
+ codec_info_found = TRUE;
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[37].name,
+ sdp_fmtp_codec_param[36].strlen) == 0) {
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->annex_t = TRUE;
+ codec_info_found = TRUE;
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[38].name,
+ sdp_fmtp_codec_param[38].strlen) == 0) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "annex_k");
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ tok = tmp;
+ tok++;
+
+ errno = 0;
+ strtoul_result = strtoul(tok, &strtoul_end, 10);
+
+ if (errno || tok == strtoul_end || strtoul_result == 0 || strtoul_result > USHRT_MAX) {
+ sdp_attr_fmtp_invalid_value(sdp_p, "annex_k", tok);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->annex_k_val = (u16) strtoul_result;
+ codec_info_found = TRUE;
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[39].name,
+ sdp_fmtp_codec_param[39].strlen) == 0) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "annex_n");
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ tok = tmp;
+ tok++;
+
+ errno = 0;
+ strtoul_result = strtoul(tok, &strtoul_end, 10);
+
+ if (errno || tok == strtoul_end || strtoul_result == 0 || strtoul_result > USHRT_MAX) {
+ sdp_attr_fmtp_invalid_value(sdp_p, "annex_n", tok);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->annex_n_val = (u16) strtoul_result;
+ codec_info_found = TRUE;
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[40].name,
+ sdp_fmtp_codec_param[40].strlen) == 0) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "annex_p");
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ fmtp_p->annex_p_val_picture_resize = 0;
+ fmtp_p->annex_p_val_warp = 0;
+ tok = tmp;
+ tok++; temp=PL_strtok_r(tok, ",", &strtok_state);
+ if (temp) {
+ iter=1;
+ while (temp != NULL) {
+ errno = 0;
+ strtoul_result = strtoul(temp, &strtoul_end, 10);
+
+ if (errno || temp == strtoul_end || strtoul_result > USHRT_MAX) {
+ break;
+ }
+
+ if (iter == 1)
+ fmtp_p->annex_p_val_picture_resize = (u16) strtoul_result;
+ else if (iter == 2)
+ fmtp_p->annex_p_val_warp = (u16) strtoul_result;
+
+ temp=PL_strtok_r(NULL, ",", &strtok_state);
+ iter++;
+ }
+ }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ codec_info_found = TRUE;
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[42].name,
+ sdp_fmtp_codec_param[42].strlen) == 0) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "level_asymmetry_allowed");
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ tok = tmp;
+ tok++;
+
+ errno = 0;
+ strtoul_result = strtoul(tok, &strtoul_end, 10);
+
+ if (errno || tok == strtoul_end || strtoul_result > SDP_MAX_LEVEL_ASYMMETRY_ALLOWED_VALUE) {
+ sdp_attr_fmtp_invalid_value(sdp_p, "level_asymmetry_allowed", tok);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->level_asymmetry_allowed = (int) strtoul_result;
+ codec_info_found = TRUE;
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[43].name,
+ sdp_fmtp_codec_param[43].strlen) == 0) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "maxaveragebitrate");
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ tok = tmp;
+ tok++;
+ errno = 0;
+ strtoul_result = strtoul(tok, &strtoul_end, 10);
+
+ if (errno || tok == strtoul_end || strtoul_result == 0 || strtoul_result > UINT_MAX) {
+ sdp_attr_fmtp_invalid_value(sdp_p, "maxaveragebitrate", tok);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->maxaveragebitrate = (u32) strtoul_result;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[44].name,
+ sdp_fmtp_codec_param[44].strlen) == 0) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "usedtx");
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ tok = tmp;
+ tok++;
+ errno = 0;
+ strtoul_result = strtoul(tok, &strtoul_end, 10);
+
+ if (errno || tok == strtoul_end || strtoul_result > 1) {
+ sdp_attr_fmtp_invalid_value(sdp_p, "usedtx", tok);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->usedtx = (u16) strtoul_result;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[45].name,
+ sdp_fmtp_codec_param[45].strlen) == 0) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "stereo");
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ tok = tmp;
+ tok++;
+ errno = 0;
+
+ strtoul_result = strtoul(tok, &strtoul_end, 10);
+
+ if (errno || tok == strtoul_end || strtoul_result > 1) {
+ sdp_attr_fmtp_invalid_value(sdp_p, "stereo", tok);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->stereo = (u16) strtoul_result;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[46].name,
+ sdp_fmtp_codec_param[46].strlen) == 0) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "useinbandfec");
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ tok = tmp;
+ tok++;
+ errno = 0;
+
+ strtoul_result = strtoul(tok, &strtoul_end, 10);
+
+ if (errno || tok == strtoul_end || strtoul_result > 1) {
+ sdp_attr_fmtp_invalid_value(sdp_p, "useinbandfec", tok);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->useinbandfec = (u16) strtoul_result;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[47].name,
+ sdp_fmtp_codec_param[47].strlen) == 0) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "maxcodedaudiobandwidth");
+ sdp_p->conf_p->num_invalid_param++;
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ tok = tmp;
+ tok++;
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ sstrncpy(fmtp_p->maxcodedaudiobandwidth , tok, sizeof(fmtp_p->maxcodedaudiobandwidth));
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[48].name,
+ sdp_fmtp_codec_param[48].strlen) == 0) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "cbr");
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ tok = tmp;
+ tok++;
+ errno = 0;
+
+ strtoul_result = strtoul(tok, &strtoul_end, 10);
+
+ if (errno || tok == strtoul_end || strtoul_result > 1) {
+ sdp_attr_fmtp_invalid_value(sdp_p, "cbr", tok);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->cbr = (u16) strtoul_result;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[49].name,
+ sdp_fmtp_codec_param[49].strlen) == 0) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "streams");
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ tok = tmp;
+ tok++;
+ errno = 0;
+
+ strtoul_result = strtoul(tok, &strtoul_end, 10);
+
+ if (errno || tok == strtoul_end || strtoul_result > INT_MAX) {
+ sdp_attr_fmtp_invalid_value(sdp_p, "streams", tok);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+
+ fmtp_p->fmtp_format = SDP_FMTP_DATACHANNEL;
+ fmtp_p->streams = (int) strtoul_result;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[50].name,
+ sdp_fmtp_codec_param[50].strlen) == 0) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "protocol");
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ tok = tmp;
+ tok++;
+ fmtp_p->fmtp_format = SDP_FMTP_DATACHANNEL;
+ sstrncpy(fmtp_p->protocol , tok, sizeof(fmtp_p->protocol));
+ codec_info_found = TRUE;
+
+ } else if (fmtp_ptr != NULL && *fmtp_ptr == '\n') {
+ temp=PL_strtok_r(tmp, ";", &strtok_state);
+ if (temp) {
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Annexes are possibly there for this fmtp %s tmp: %s line\n",
+ sdp_p->debug_str, fmtp_ptr, tmp);
+ }
+ while (temp != NULL) {
+ if (strchr(temp, 'D') !=NULL) {
+ attr_p->attr.fmtp.annex_d = TRUE;
+ }
+ if (strchr(temp, 'F') !=NULL) {
+ attr_p->attr.fmtp.annex_f = TRUE;
+ }
+ if (strchr(temp, 'I') !=NULL) {
+ attr_p->attr.fmtp.annex_i = TRUE;
+ }
+ if (strchr(temp, 'J') !=NULL) {
+ attr_p->attr.fmtp.annex_j = TRUE;
+ }
+ if (strchr(temp, 'T') !=NULL) {
+ attr_p->attr.fmtp.annex_t = TRUE;
+ }
+ temp=PL_strtok_r(NULL, ";", &strtok_state);
+ }
+ } /* if (temp) */
+ done = TRUE;
+ }
+ fmtp_ptr++;
+ } else {
+ done = TRUE;
+ }
+ } /* while - done loop*/
+
+ if (codec_info_found) {
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, payload type %u, bitrate %lu, mode %u QCIF = %u, CIF = %u, MAXBR= %u, SQCIF=%u, CIF4= %u, CIF16=%u, CUSTOM=%u,%u,%u , PAR=%u:%u,CPCF=%u, BPP=%u, HRD=%u \n",
+ sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type),
+ attr_p->attr.fmtp.payload_num,
+ attr_p->attr.fmtp.bitrate,
+ attr_p->attr.fmtp.mode,
+ attr_p->attr.fmtp.qcif,
+ attr_p->attr.fmtp.cif,
+ attr_p->attr.fmtp.maxbr,
+ attr_p->attr.fmtp.sqcif,
+ attr_p->attr.fmtp.cif4,
+ attr_p->attr.fmtp.cif16,
+ attr_p->attr.fmtp.custom_x,attr_p->attr.fmtp.custom_y,
+ attr_p->attr.fmtp.custom_mpi,
+ attr_p->attr.fmtp.par_width,
+ attr_p->attr.fmtp.par_height,
+ attr_p->attr.fmtp.cpcf,
+ attr_p->attr.fmtp.bpp,
+ attr_p->attr.fmtp.hrd
+ );
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, payload type %u,PROFILE=%u,LEVEL=%u, INTERLACE - %s",
+ sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type),
+ attr_p->attr.fmtp.payload_num,
+ attr_p->attr.fmtp.profile,
+ attr_p->attr.fmtp.level,
+ attr_p->attr.fmtp.is_interlace ? "YES":"NO");
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed H.264 attributes: profile-level-id=%s, parameter-sets=%s, packetization-mode=%d level-asymmetry-allowed=%d interleaving-depth=%d deint-buf-req=%lu max-don-diff=%lu, init_buf-time=%lu\n",
+ sdp_p->debug_str,
+ attr_p->attr.fmtp.profile_level_id,
+ attr_p->attr.fmtp.parameter_sets,
+ attr_p->attr.fmtp.packetization_mode,
+ attr_p->attr.fmtp.level_asymmetry_allowed,
+ attr_p->attr.fmtp.interleaving_depth,
+ attr_p->attr.fmtp.deint_buf_req,
+ attr_p->attr.fmtp.max_don_diff,
+ attr_p->attr.fmtp.init_buf_time
+ );
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("\n%s Parsed H.264 opt attributes: max-mbps=%lu, max-fs=%lu, max-cpb=%lu max-dpb=%lu max-br=%lu redundant-pic-cap=%d, deint-buf-cap=%lu, max-rcmd-nalu-size=%lu , parameter-add=%d\n",
+ sdp_p->debug_str,
+ attr_p->attr.fmtp.max_mbps,
+ attr_p->attr.fmtp.max_fs,
+ attr_p->attr.fmtp.max_cpb,
+ attr_p->attr.fmtp.max_dpb,
+ attr_p->attr.fmtp.max_br,
+ attr_p->attr.fmtp.redundant_pic_cap,
+ attr_p->attr.fmtp.deint_buf_cap,
+ attr_p->attr.fmtp.max_rcmd_nalu_size,
+ attr_p->attr.fmtp.parameter_add);
+
+ }
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed annexes are : D=%d F=%d I=%d J=%d T=%d, K=%d N=%d P=%d,%d\n",
+ sdp_p->debug_str,
+ attr_p->attr.fmtp.annex_d,
+ attr_p->attr.fmtp.annex_f, attr_p->attr.fmtp.annex_i,
+ attr_p->attr.fmtp.annex_j, attr_p->attr.fmtp.annex_t,
+ attr_p->attr.fmtp.annex_k_val,
+ attr_p->attr.fmtp.annex_n_val,
+ attr_p->attr.fmtp.annex_p_val_picture_resize,
+ attr_p->attr.fmtp.annex_p_val_warp);
+
+ }
+ SDP_FREE(temp_ptr);
+ return (SDP_SUCCESS);
+ } else {
+ done = FALSE;
+ fmtp_ptr = src_ptr;
+ tmp[0] = '\0';
+ }
+
+ for (i=0; !done; i++) {
+ fmtp_p->fmtp_format = SDP_FMTP_NTE;
+ /* Look for comma separated events */
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), ", \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ done = TRUE;
+ continue;
+ }
+ /* Now look for '-' separated range */
+ ptr2 = tmp;
+ low_val = (u8)sdp_getnextnumtok(ptr2, (const char **)&ptr2,
+ "- \t", &result1);
+ if (*ptr2 == '-') {
+ high_val = (u8)sdp_getnextnumtok(ptr2, (const char **)&ptr2,
+ "- \t", &result2);
+ } else {
+ high_val = low_val;
+ }
+
+ if ((result1 != SDP_SUCCESS) || (result2 != SDP_SUCCESS)) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: Invalid named events specified for fmtp attribute.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ SDP_FREE(temp_ptr);
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ for (i = low_val; i <= high_val; i++) {
+ mapword = i/SDP_NE_BITS_PER_WORD;
+ bmap = SDP_NE_BIT_0 << (i%32);
+ fmtp_p->bmap[mapword] |= bmap;
+ }
+ if (high_val > fmtp_p->maxval) {
+ fmtp_p->maxval = high_val;
+ }
+ }
+
+ if (fmtp_p->maxval == 0) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No named events specified for fmtp attribute.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ SDP_FREE(temp_ptr);
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, payload type %u, ", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type),
+ attr_p->attr.fmtp.payload_num);
+ }
+ SDP_FREE(temp_ptr);
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_attr_fmtp (sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs)
+{
+ u16 event_id;
+ u32 mask;
+ u32 mapword;
+ u8 min = 0;
+ u8 max = 0;
+ tinybool range_start = FALSE;
+ tinybool range_end = FALSE;
+ tinybool semicolon = FALSE;
+ sdp_fmtp_t *fmtp_p;
+
+ flex_string_sprintf(fs, "a=%s:%u ",
+ sdp_attr[attr_p->type].name,
+ attr_p->attr.fmtp.payload_num);
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ switch (fmtp_p->fmtp_format) {
+ case SDP_FMTP_MODE:
+ sdp_append_name_and_unsigned(fs, "mode", fmtp_p->mode, FALSE);
+ break;
+
+ case SDP_FMTP_CODEC_INFO:
+ FMTP_BUILD_UNSIGNED(fmtp_p->bitrate > 0, "bitrate", fmtp_p->bitrate)
+
+ FMTP_BUILD_STRING(fmtp_p->annexa_required,
+ "annexa", (fmtp_p->annexa ? "yes" : "no"))
+
+ FMTP_BUILD_STRING(fmtp_p->annexb_required,
+ "annexb", (fmtp_p->annexa ? "yes" : "no"))
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->qcif > 0, "QCIF", fmtp_p->qcif)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->cif > 0, "CIF", fmtp_p->cif)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->maxbr > 0, "MAXBR", fmtp_p->maxbr)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->sqcif > 0, "SQCIF", fmtp_p->sqcif)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->cif4 > 0, "CIF4", fmtp_p->cif4)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->cif16 > 0, "CIF16", fmtp_p->cif16)
+
+ if ((fmtp_p->custom_x > 0) && (fmtp_p->custom_y > 0) &&
+ (fmtp_p->custom_mpi > 0)) {
+ flex_string_sprintf(fs, "%sCUSTOM=%u,%u,%u",
+ semicolon ? ";" : "",
+ fmtp_p->custom_x,
+ fmtp_p->custom_y,
+ fmtp_p->custom_mpi);
+
+ semicolon = TRUE;
+ }
+
+ if ((fmtp_p->par_height > 0) && (fmtp_p->par_width > 0)) {
+ flex_string_sprintf(fs, "%sPAR=%u:%u",
+ semicolon ? ";" : "",
+ fmtp_p->par_width,
+ fmtp_p->par_width);
+
+ semicolon = TRUE;
+ }
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->cpcf > 0, "CPCF", fmtp_p->cpcf)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->bpp > 0, "BPP", fmtp_p->bpp)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->hrd > 0, "HRD", fmtp_p->hrd)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->profile >= 0, "PROFILE", fmtp_p->profile)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->level >= 0, "LEVEL", fmtp_p->level)
+
+ FMTP_BUILD_FLAG(fmtp_p->is_interlace, "INTERLACE")
+
+ FMTP_BUILD_FLAG(fmtp_p->annex_d, "D")
+
+ FMTP_BUILD_FLAG(fmtp_p->annex_f, "F")
+
+ FMTP_BUILD_FLAG(fmtp_p->annex_i, "I")
+
+ FMTP_BUILD_FLAG(fmtp_p->annex_j, "J")
+
+ FMTP_BUILD_FLAG(fmtp_p->annex_t, "T")
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->annex_k_val > 0,
+ "K", fmtp_p->annex_k_val)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->annex_n_val > 0,
+ "N", fmtp_p->annex_n_val)
+
+ if ((fmtp_p->annex_p_val_picture_resize > 0) &&
+ (fmtp_p->annex_p_val_warp > 0)) {
+ flex_string_sprintf(fs, "%sP=%d:%d",
+ semicolon ? ";" : "",
+ fmtp_p->annex_p_val_picture_resize,
+ fmtp_p->annex_p_val_warp);
+
+ semicolon = TRUE;
+ }
+
+ FMTP_BUILD_STRING(strlen(fmtp_p->profile_level_id) > 0,
+ "profile-level-id", fmtp_p->profile_level_id)
+
+ FMTP_BUILD_STRING(strlen(fmtp_p->parameter_sets) > 0,
+ "sprop-parameter-sets", fmtp_p->parameter_sets)
+
+ FMTP_BUILD_UNSIGNED(
+ fmtp_p->packetization_mode < SDP_MAX_PACKETIZATION_MODE_VALUE,
+ "packetization-mode", fmtp_p->packetization_mode)
+
+ FMTP_BUILD_UNSIGNED(
+ fmtp_p->level_asymmetry_allowed <=
+ SDP_MAX_LEVEL_ASYMMETRY_ALLOWED_VALUE,
+ "level-asymmetry-allowed", fmtp_p->level_asymmetry_allowed)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->interleaving_depth > 0,
+ "sprop-interleaving-depth", fmtp_p->interleaving_depth)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->flag & SDP_DEINT_BUF_REQ_FLAG,
+ "sprop-deint-buf-req", fmtp_p->deint_buf_req)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->max_don_diff > 0,
+ "sprop-max-don-diff", fmtp_p->max_don_diff)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->flag & SDP_INIT_BUF_TIME_FLAG,
+ "sprop-init-buf-time", fmtp_p->init_buf_time)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->max_mbps > 0,
+ "max-mbps", fmtp_p->max_mbps)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->max_fs > 0, "max-fs", fmtp_p->max_fs)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->max_cpb > 0, "max-cpb", fmtp_p->max_cpb)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->max_dpb > 0, "max-dpb", fmtp_p->max_dpb)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->max_br > 0, "max-br", fmtp_p->max_br)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->redundant_pic_cap > 0,
+ "redundant-pic-cap", fmtp_p->redundant_pic_cap)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->flag & SDP_DEINT_BUF_CAP_FLAG,
+ "deint-buf-cap", fmtp_p->deint_buf_cap)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->flag & SDP_MAX_RCMD_NALU_SIZE_FLAG,
+ "max-rcmd-naFMTP_BUILD_FLlu-size", fmtp_p->max_rcmd_nalu_size)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->parameter_add > 0,
+ "parameter-add", fmtp_p->parameter_add)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->maxaveragebitrate > 0,
+ "maxaveragebitrate", fmtp_p->maxaveragebitrate)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->usedtx <= 1, "usedtx", fmtp_p->usedtx)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->stereo <= 1, "stereo", fmtp_p->stereo)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->useinbandfec <= 1,
+ "useinbandfec", fmtp_p->useinbandfec)
+
+ FMTP_BUILD_STRING(strlen(fmtp_p->maxcodedaudiobandwidth) > 0,
+ "maxcodedaudiobandwidth", fmtp_p->maxcodedaudiobandwidth)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->cbr <= 1, "cbr", fmtp_p->cbr)
+
+ break;
+
+ case SDP_FMTP_DATACHANNEL:
+ FMTP_BUILD_STRING(strlen(fmtp_p->protocol) > 0,
+ "protocol", fmtp_p->protocol)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->streams > 0, "streams", fmtp_p->streams)
+
+ break;
+
+ case SDP_FMTP_NTE:
+ default:
+ break;
+ }
+
+ for(event_id = 0, mapword = 0, mask = SDP_NE_BIT_0;
+ event_id <= fmtp_p->maxval;
+ event_id++, mapword = event_id/SDP_NE_BITS_PER_WORD ) {
+
+ if (event_id % SDP_NE_BITS_PER_WORD) {
+ mask <<= 1;
+ } else {
+ /* crossed a bitmap word boundary */
+ mask = SDP_NE_BIT_0;
+ if (!range_start && !range_end && !fmtp_p->bmap[mapword]) {
+ /* no events in this word, skip to the last event id
+ * in this bitmap word. */
+ event_id += SDP_NE_BITS_PER_WORD - 1;
+ continue;
+ }
+ }
+
+ if (fmtp_p->bmap[mapword] & mask) {
+ if (!range_start) {
+ range_start = TRUE;
+ min = max = (u8)event_id;
+ } else {
+ max = (u8)event_id;
+ }
+ range_end = (max == fmtp_p->maxval);
+ } else {
+ /* If we were in the middle of a range, then we've hit the
+ * end. If we weren't, there is no end to hit. */
+ range_end = range_start;
+ }
+
+ /* If this is the end of the range, print it to the string. */
+ if (range_end) {
+ range_start = range_end = FALSE;
+
+ flex_string_sprintf(fs, "%u", min);
+
+ if (min != max) {
+ flex_string_sprintf(fs, "-%u", max);
+ }
+
+ if (max != fmtp_p->maxval) {
+ flex_string_append(fs, ",");
+ }
+ }
+ }
+
+ flex_string_append(fs, "\r\n");
+
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_parse_attr_direction (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ /* No parameters to parse. */
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type));
+ }
+
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_attr_direction (sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs)
+{
+ flex_string_sprintf(fs, "a=%s\r\n", sdp_get_attr_name(attr_p->type));
+
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_parse_attr_qos (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ int i;
+ sdp_result_e result;
+ char tmp[SDP_MAX_STRING_LEN];
+
+ /* Find the strength tag. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No qos strength tag specified.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p->attr.qos.strength = SDP_QOS_STRENGTH_UNKNOWN;
+ for (i=0; i < SDP_MAX_QOS_STRENGTH; i++) {
+ if (cpr_strncasecmp(tmp, sdp_qos_strength[i].name,
+ sdp_qos_strength[i].strlen) == 0) {
+ attr_p->attr.qos.strength = (sdp_qos_strength_e)i;
+ }
+ }
+ if (attr_p->attr.qos.strength == SDP_QOS_STRENGTH_UNKNOWN) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: QOS strength tag unrecognized (%s)",
+ sdp_p->debug_str, tmp);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Find the qos direction. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No qos direction specified.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p->attr.qos.direction = SDP_QOS_DIR_UNKNOWN;
+ for (i=0; i < SDP_MAX_QOS_DIR; i++) {
+ if (cpr_strncasecmp(tmp, sdp_qos_direction[i].name,
+ sdp_qos_direction[i].strlen) == 0) {
+ attr_p->attr.qos.direction = (sdp_qos_dir_e)i;
+ }
+ }
+ if (attr_p->attr.qos.direction == SDP_QOS_DIR_UNKNOWN) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: QOS direction unrecognized (%s)",
+ sdp_p->debug_str, tmp);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* See if confirm was specified. Defaults to FALSE. */
+ attr_p->attr.qos.confirm = FALSE;
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result == SDP_SUCCESS) {
+ if (cpr_strncasecmp(tmp, "confirm", sizeof("confirm")) == 0) {
+ attr_p->attr.qos.confirm = TRUE;
+ }
+ if (attr_p->attr.qos.confirm == FALSE) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: QOS confirm parameter invalid (%s)",
+ sdp_p->debug_str, tmp);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, strength %s, direction %s, confirm %s",
+ sdp_p->debug_str, sdp_get_attr_name(attr_p->type),
+ sdp_get_qos_strength_name(attr_p->attr.qos.strength),
+ sdp_get_qos_direction_name(attr_p->attr.qos.direction),
+ (attr_p->attr.qos.confirm ? "set" : "not set"));
+ }
+
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_attr_qos (sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs)
+{
+ flex_string_sprintf(fs, "a=%s:%s %s%s\r\n", sdp_attr[attr_p->type].name,
+ sdp_get_qos_strength_name(attr_p->attr.qos.strength),
+ sdp_get_qos_direction_name(attr_p->attr.qos.direction),
+ attr_p->attr.qos.confirm ? " confirm" : "");
+
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_parse_attr_curr (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ int i;
+ sdp_result_e result;
+ char tmp[SDP_MAX_STRING_LEN];
+
+ /* Find the curr type tag. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No curr attr type specified.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p->attr.curr.type = SDP_CURR_UNKNOWN_TYPE;
+ for (i=0; i < SDP_MAX_CURR_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_curr_type[i].name,
+ sdp_curr_type[i].strlen) == 0) {
+ attr_p->attr.curr.type = (sdp_curr_type_e)i;
+ }
+ }
+
+ if (attr_p->attr.curr.type != SDP_CURR_QOS_TYPE) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: Unknown curr type.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Check qos status type */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No curr attr type specified.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p->attr.curr.status_type = SDP_QOS_STATUS_TYPE_UNKNOWN;
+ for (i=0; i < SDP_MAX_QOS_STATUS_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_qos_status_type[i].name,
+ sdp_qos_status_type[i].strlen) == 0) {
+ attr_p->attr.curr.status_type = (sdp_qos_status_types_e)i;
+ }
+ }
+
+
+ /* Find the qos direction. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No qos direction specified.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p->attr.curr.direction = SDP_QOS_DIR_UNKNOWN;
+ for (i=0; i < SDP_MAX_QOS_DIR; i++) {
+ if (cpr_strncasecmp(tmp, sdp_qos_direction[i].name,
+ sdp_qos_direction[i].strlen) == 0) {
+ attr_p->attr.curr.direction = (sdp_qos_dir_e)i;
+ }
+ }
+ if (attr_p->attr.curr.direction == SDP_QOS_DIR_UNKNOWN) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: QOS direction unrecognized (%s)",
+ sdp_p->debug_str, tmp);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, type %s status type %s, direction %s",
+ sdp_p->debug_str, sdp_get_attr_name(attr_p->type),
+ sdp_get_curr_type_name(attr_p->attr.curr.type),
+ sdp_get_qos_status_type_name(attr_p->attr.curr.status_type),
+ sdp_get_qos_direction_name(attr_p->attr.curr.direction));
+ }
+
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_attr_curr (sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs)
+{
+ flex_string_sprintf(fs, "a=%s:%s %s %s\r\n",
+ sdp_attr[attr_p->type].name,
+ sdp_get_curr_type_name(attr_p->attr.curr.type),
+ sdp_get_qos_status_type_name(attr_p->attr.curr.status_type),
+ sdp_get_qos_direction_name(attr_p->attr.curr.direction));
+
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_parse_attr_des (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ int i;
+ sdp_result_e result;
+ char tmp[SDP_MAX_STRING_LEN];
+
+ /* Find the curr type tag. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No des attr type specified.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p->attr.des.type = SDP_DES_UNKNOWN_TYPE;
+ for (i=0; i < SDP_MAX_CURR_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_des_type[i].name,
+ sdp_des_type[i].strlen) == 0) {
+ attr_p->attr.des.type = (sdp_des_type_e)i;
+ }
+ }
+
+ if (attr_p->attr.des.type != SDP_DES_QOS_TYPE) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: Unknown conf type.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Find the strength tag. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No qos strength tag specified.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p->attr.des.strength = SDP_QOS_STRENGTH_UNKNOWN;
+ for (i=0; i < SDP_MAX_QOS_STRENGTH; i++) {
+ if (cpr_strncasecmp(tmp, sdp_qos_strength[i].name,
+ sdp_qos_strength[i].strlen) == 0) {
+ attr_p->attr.des.strength = (sdp_qos_strength_e)i;
+ }
+ }
+ if (attr_p->attr.des.strength == SDP_QOS_STRENGTH_UNKNOWN) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: QOS strength tag unrecognized (%s)",
+ sdp_p->debug_str, tmp);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Check qos status type */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No des attr type specified.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p->attr.des.status_type = SDP_QOS_STATUS_TYPE_UNKNOWN;
+ for (i=0; i < SDP_MAX_QOS_STATUS_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_qos_status_type[i].name,
+ sdp_qos_status_type[i].strlen) == 0) {
+ attr_p->attr.des.status_type = (sdp_qos_status_types_e)i;
+ }
+ }
+
+
+ /* Find the qos direction. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No qos direction specified.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p->attr.des.direction = SDP_QOS_DIR_UNKNOWN;
+ for (i=0; i < SDP_MAX_QOS_DIR; i++) {
+ if (cpr_strncasecmp(tmp, sdp_qos_direction[i].name,
+ sdp_qos_direction[i].strlen) == 0) {
+ attr_p->attr.des.direction = (sdp_qos_dir_e)i;
+ }
+ }
+ if (attr_p->attr.des.direction == SDP_QOS_DIR_UNKNOWN) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: QOS direction unrecognized (%s)",
+ sdp_p->debug_str, tmp);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, type %s strength %s status type %s, direction %s",
+ sdp_p->debug_str, sdp_get_attr_name(attr_p->type),
+ sdp_get_des_type_name(attr_p->attr.des.type),
+ sdp_get_qos_strength_name(attr_p->attr.qos.strength),
+ sdp_get_qos_status_type_name(attr_p->attr.des.status_type),
+ sdp_get_qos_direction_name(attr_p->attr.des.direction));
+ }
+
+ return (SDP_SUCCESS);
+}
+
+
+sdp_result_e sdp_build_attr_des (sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs)
+{
+ flex_string_sprintf(fs, "a=%s:%s %s %s %s\r\n",
+ sdp_attr[attr_p->type].name,
+ sdp_get_curr_type_name((sdp_curr_type_e)attr_p->attr.des.type),
+ sdp_get_qos_strength_name(attr_p->attr.des.strength),
+ sdp_get_qos_status_type_name(attr_p->attr.des.status_type),
+ sdp_get_qos_direction_name(attr_p->attr.des.direction));
+
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_parse_attr_conf (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ int i;
+ sdp_result_e result;
+ char tmp[SDP_MAX_STRING_LEN];
+
+ /* Find the curr type tag. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No conf attr type specified.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p->attr.conf.type = SDP_CONF_UNKNOWN_TYPE;
+ for (i=0; i < SDP_MAX_CURR_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_conf_type[i].name,
+ sdp_conf_type[i].strlen) == 0) {
+ attr_p->attr.conf.type = (sdp_conf_type_e)i;
+ }
+ }
+
+ if (attr_p->attr.conf.type != SDP_CONF_QOS_TYPE) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: Unknown conf type.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Check qos status type */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No conf attr type specified.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p->attr.conf.status_type = SDP_QOS_STATUS_TYPE_UNKNOWN;
+ for (i=0; i < SDP_MAX_QOS_STATUS_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_qos_status_type[i].name,
+ sdp_qos_status_type[i].strlen) == 0) {
+ attr_p->attr.conf.status_type = (sdp_qos_status_types_e)i;
+ }
+ }
+
+
+ /* Find the qos direction. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No qos direction specified.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p->attr.conf.direction = SDP_QOS_DIR_UNKNOWN;
+ for (i=0; i < SDP_MAX_QOS_DIR; i++) {
+ if (cpr_strncasecmp(tmp, sdp_qos_direction[i].name,
+ sdp_qos_direction[i].strlen) == 0) {
+ attr_p->attr.conf.direction = (sdp_qos_dir_e)i;
+ }
+ }
+ if (attr_p->attr.conf.direction == SDP_QOS_DIR_UNKNOWN) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: QOS direction unrecognized (%s)",
+ sdp_p->debug_str, tmp);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, type %s status type %s, direction %s",
+ sdp_p->debug_str, sdp_get_attr_name(attr_p->type),
+ sdp_get_conf_type_name(attr_p->attr.conf.type),
+ sdp_get_qos_status_type_name(attr_p->attr.conf.status_type),
+ sdp_get_qos_direction_name(attr_p->attr.conf.direction));
+ }
+
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_attr_conf (sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs)
+{
+ flex_string_sprintf(fs, "a=%s:%s %s %s\r\n",
+ sdp_attr[attr_p->type].name,
+ sdp_get_conf_type_name(attr_p->attr.conf.type),
+ sdp_get_qos_status_type_name(attr_p->attr.conf.status_type),
+ sdp_get_qos_direction_name(attr_p->attr.conf.direction));
+
+ return SDP_SUCCESS;
+}
+
+/*
+ * Parse a rtpmap or a sprtmap. Both formats use the same structure
+ * the only difference being the keyword "rtpmap" vs "sprtmap". The
+ * rtpmap field in the sdp_attr_t is used to store both mappings.
+ */
+sdp_result_e sdp_parse_attr_transport_map (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ sdp_result_e result;
+
+ attr_p->attr.transport_map.payload_num = 0;
+ attr_p->attr.transport_map.encname[0] = '\0';
+ attr_p->attr.transport_map.clockrate = 0;
+ attr_p->attr.transport_map.num_chan = 1;
+
+ /* Find the payload type number. */
+ attr_p->attr.transport_map.payload_num =
+ (u16)sdp_getnextnumtok(ptr, &ptr, " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: Invalid payload type specified for %s attribute.",
+ sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Find the encoding name. */
+ ptr = sdp_getnextstrtok(ptr, attr_p->attr.transport_map.encname,
+ sizeof(attr_p->attr.transport_map.encname), "/ \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No encoding name specified in %s attribute.",
+ sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Find the clockrate. */
+ attr_p->attr.transport_map.clockrate =
+ sdp_getnextnumtok(ptr, &ptr, "/ \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No clockrate specified for "
+ "%s attribute, set to default of 8000.",
+ sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
+ attr_p->attr.transport_map.clockrate = 8000;
+ }
+
+ /* Find the number of channels, if specified. This is optional. */
+ if (*ptr == '/') {
+ /* If a '/' exists, expect something valid beyond it. */
+ attr_p->attr.transport_map.num_chan =
+ (u16)sdp_getnextnumtok(ptr, &ptr, "/ \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: Invalid number of channels parameter"
+ " for rtpmap attribute.", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, payload type %u, encoding name %s, "
+ "clockrate %lu", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type),
+ attr_p->attr.transport_map.payload_num,
+ attr_p->attr.transport_map.encname,
+ attr_p->attr.transport_map.clockrate);
+ if (attr_p->attr.transport_map.num_chan != 1) {
+ SDP_PRINT("/%u", attr_p->attr.transport_map.num_chan);
+ }
+ }
+
+ return (SDP_SUCCESS);
+}
+
+/*
+ * Build a rtpmap or a sprtmap. Both formats use the same structure
+ * the only difference being the keyword "rtpmap" vs "sprtmap". The
+ * rtpmap field in the sdp_attr_t is used for both mappings.
+ */
+sdp_result_e sdp_build_attr_transport_map (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ if (attr_p->attr.transport_map.num_chan == 1) {
+ flex_string_sprintf(fs, "a=%s:%u %s/%u\r\n",
+ sdp_attr[attr_p->type].name,
+ attr_p->attr.transport_map.payload_num,
+ attr_p->attr.transport_map.encname,
+ attr_p->attr.transport_map.clockrate);
+ } else {
+ flex_string_sprintf(fs, "a=%s:%u %s/%u/%u\r\n",
+ sdp_attr[attr_p->type].name,
+ attr_p->attr.transport_map.payload_num,
+ attr_p->attr.transport_map.encname,
+ attr_p->attr.transport_map.clockrate,
+ attr_p->attr.transport_map.num_chan);
+ }
+
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_parse_attr_subnet (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ int i;
+ char *slash_ptr;
+ sdp_result_e result;
+ tinybool type_found = FALSE;
+ char tmp[SDP_MAX_STRING_LEN];
+
+ /* Find the subnet network type. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No network type specified in subnet attribute.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p->attr.subnet.nettype = SDP_NT_UNSUPPORTED;
+ for (i=0; i < SDP_MAX_NETWORK_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_nettype[i].name,
+ sdp_nettype[i].strlen) == 0) {
+ type_found = TRUE;
+ }
+ if (type_found == TRUE) {
+ if (sdp_p->conf_p->nettype_supported[i] == TRUE) {
+ attr_p->attr.subnet.nettype = (sdp_nettype_e)i;
+ }
+ type_found = FALSE;
+ }
+ }
+ if (attr_p->attr.subnet.nettype == SDP_NT_UNSUPPORTED) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: Subnet network type unsupported (%s).",
+ sdp_p->debug_str, tmp);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Find the subnet address type. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No address type specified in subnet attribute.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p->attr.subnet.addrtype = SDP_AT_UNSUPPORTED;
+ for (i=0; i < SDP_MAX_ADDR_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_addrtype[i].name,
+ sdp_addrtype[i].strlen) == 0) {
+ type_found = TRUE;
+ }
+ if (type_found == TRUE) {
+ if (sdp_p->conf_p->addrtype_supported[i] == TRUE) {
+ attr_p->attr.subnet.addrtype = (sdp_addrtype_e)i;
+ }
+ type_found = FALSE;
+ }
+ }
+ if (attr_p->attr.subnet.addrtype == SDP_AT_UNSUPPORTED) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: Subnet address type unsupported (%s).",
+ sdp_p->debug_str, tmp);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Find the subnet address. */
+ ptr = sdp_getnextstrtok(ptr, attr_p->attr.subnet.addr,
+ sizeof(attr_p->attr.subnet.addr), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No subnet address specified in "
+ "subnet attribute.", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ slash_ptr = sdp_findchar(attr_p->attr.subnet.addr, "/");
+ if (*slash_ptr == '/') {
+ *slash_ptr++ = '\0';
+ /* If the '/' exists, expect a valid prefix to follow. */
+ attr_p->attr.subnet.prefix = sdp_getnextnumtok(slash_ptr,
+ (const char **)&slash_ptr,
+ " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: Invalid subnet prefix specified in "
+ "subnet attribute.", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ } else {
+ attr_p->attr.subnet.prefix = SDP_INVALID_VALUE;
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, network %s, addr type %s, address %s ",
+ sdp_p->debug_str, sdp_get_attr_name(attr_p->type),
+ sdp_get_network_name(attr_p->attr.subnet.nettype),
+ sdp_get_address_name(attr_p->attr.subnet.addrtype),
+ attr_p->attr.subnet.addr);
+ if (attr_p->attr.subnet.prefix != SDP_INVALID_VALUE) {
+ SDP_PRINT("/%u", (ushort)attr_p->attr.subnet.prefix);
+ }
+ }
+
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_attr_subnet (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ if (attr_p->attr.subnet.prefix == SDP_INVALID_VALUE) {
+ flex_string_sprintf(fs, "a=%s:%s %s %s\r\n",
+ sdp_attr[attr_p->type].name,
+ sdp_get_network_name(attr_p->attr.subnet.nettype),
+ sdp_get_address_name(attr_p->attr.subnet.addrtype),
+ attr_p->attr.subnet.addr);
+ } else {
+ flex_string_sprintf(fs, "a=%s:%s %s %s/%u\r\n",
+ sdp_attr[attr_p->type].name,
+ sdp_get_network_name(attr_p->attr.subnet.nettype),
+ sdp_get_address_name(attr_p->attr.subnet.addrtype),
+ attr_p->attr.subnet.addr,
+ (ushort)attr_p->attr.subnet.prefix);
+ }
+
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_parse_attr_t38_ratemgmt (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ int i;
+ sdp_result_e result;
+ char tmp[SDP_MAX_STRING_LEN];
+
+ /* Find the rate mgmt. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No t38 rate management specified.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p->attr.t38ratemgmt = SDP_T38_UNKNOWN_RATE;
+ for (i=0; i < SDP_T38_MAX_RATES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_t38_rate[i].name,
+ sdp_t38_rate[i].strlen) == 0) {
+ attr_p->attr.t38ratemgmt = (sdp_t38_ratemgmt_e)i;
+ }
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, rate %s", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type),
+ sdp_get_t38_ratemgmt_name(attr_p->attr.t38ratemgmt));
+ }
+
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_attr_t38_ratemgmt (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ flex_string_sprintf(fs, "a=%s:%s\r\n",
+ sdp_attr[attr_p->type].name,
+ sdp_get_t38_ratemgmt_name(attr_p->attr.t38ratemgmt));
+
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_parse_attr_t38_udpec (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ int i;
+ sdp_result_e result;
+ char tmp[SDP_MAX_STRING_LEN];
+
+ /* Find the udpec. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No t38 udpEC specified.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p->attr.t38udpec = SDP_T38_UDPEC_UNKNOWN;
+ for (i=0; i < SDP_T38_MAX_UDPEC; i++) {
+ if (cpr_strncasecmp(tmp, sdp_t38_udpec[i].name,
+ sdp_t38_udpec[i].strlen) == 0) {
+ attr_p->attr.t38udpec = (sdp_t38_udpec_e)i;
+ }
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, udpec %s", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type),
+ sdp_get_t38_udpec_name(attr_p->attr.t38udpec));
+ }
+
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_attr_t38_udpec (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ flex_string_sprintf(fs, "a=%s:%s\r\n",
+ sdp_attr[attr_p->type].name,
+ sdp_get_t38_udpec_name(attr_p->attr.t38udpec));
+
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_parse_attr_pc_codec (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ u16 i;
+ sdp_result_e result;
+
+ for (i=0; i < SDP_MAX_PAYLOAD_TYPES; i++) {
+ attr_p->attr.pccodec.payload_type[i] = (ushort)sdp_getnextnumtok(ptr, &ptr,
+ " \t", &result);
+ if (result != SDP_SUCCESS) {
+ break;
+ }
+ attr_p->attr.pccodec.num_payloads++;
+ }
+
+ if (attr_p->attr.pccodec.num_payloads == 0) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No payloads specified for %s attr.",
+ sdp_p->debug_str, sdp_attr[attr_p->type].name);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, num payloads %u, payloads: ",
+ sdp_p->debug_str, sdp_get_attr_name(attr_p->type),
+ attr_p->attr.pccodec.num_payloads);
+ for (i=0; i < attr_p->attr.pccodec.num_payloads; i++) {
+ SDP_PRINT("%u ", attr_p->attr.pccodec.payload_type[i]);
+ }
+ }
+
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_attr_pc_codec (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ int i;
+
+ flex_string_sprintf(fs, "a=%s: ", sdp_attr[attr_p->type].name);
+
+ for (i=0; i < attr_p->attr.pccodec.num_payloads; i++) {
+ flex_string_sprintf(fs, "%u ", attr_p->attr.pccodec.payload_type[i]);
+ }
+
+ flex_string_append(fs, "\r\n");
+
+ return SDP_SUCCESS;
+}
+
+
+sdp_result_e sdp_parse_attr_cap (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ u16 i;
+ sdp_result_e result;
+ sdp_mca_t *cap_p;
+ char tmp[SDP_MAX_STRING_LEN];
+
+ /* Set the capability pointer to NULL for now in case we encounter
+ * an error in parsing.
+ */
+ attr_p->attr.cap_p = NULL;
+ /* Set the capability valid flag to FALSE in case we encounter an
+ * error. If we do, we don't want to process any X-cpar/cpar attributes
+ * from this point until we process the next valid X-cap/cdsc attr. */
+ sdp_p->cap_valid = FALSE;
+
+ /* Allocate resource for new capability. Note that the capability
+ * uses the same structure used for media lines.
+ */
+ cap_p = sdp_alloc_mca();
+ if (cap_p == NULL) {
+ sdp_p->conf_p->num_no_resource++;
+ return (SDP_NO_RESOURCE);
+ }
+
+ /* Find the capability number. We don't need to store this since we
+ * calculate it for ourselves as we need to. But it must be specified. */
+ (void)sdp_getnextnumtok(ptr, &ptr, "/ \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: Capability not specified for %s, "
+ "unable to parse.", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type));
+ SDP_FREE(cap_p);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Find the media type. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s No media type specified for %s attribute, "
+ "unable to parse.",
+ sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
+ SDP_FREE(cap_p);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ cap_p->media = SDP_MEDIA_UNSUPPORTED;
+ for (i=0; i < SDP_MAX_MEDIA_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_media[i].name, sdp_media[i].strlen) == 0) {
+ cap_p->media = (sdp_media_e)i;
+ break;
+ }
+ }
+ if (cap_p->media == SDP_MEDIA_UNSUPPORTED) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: Media type unsupported (%s).",
+ sdp_p->debug_str, tmp);
+ SDP_FREE(cap_p);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Find the transport protocol type. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s No transport protocol type specified, "
+ "unable to parse.", sdp_p->debug_str);
+ SDP_FREE(cap_p);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ cap_p->transport = SDP_TRANSPORT_UNSUPPORTED;
+ for (i=0; i < SDP_MAX_TRANSPORT_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_transport[i].name,
+ sdp_transport[i].strlen) == 0) {
+ cap_p->transport = (sdp_transport_e)i;
+ break;
+ }
+ }
+ if (cap_p->transport == SDP_TRANSPORT_UNSUPPORTED) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: Transport protocol type unsupported (%s).",
+ sdp_p->debug_str, tmp);
+ SDP_FREE(cap_p);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Find payload formats. AAL2 X-cap lines allow multiple
+ * transport/profile types per line, so these are handled differently.
+ */
+ if ((cap_p->transport == SDP_TRANSPORT_AAL2_ITU) ||
+ (cap_p->transport == SDP_TRANSPORT_AAL2_ATMF) ||
+ (cap_p->transport == SDP_TRANSPORT_AAL2_CUSTOM)) {
+ /* Capability processing is not currently defined for AAL2 types
+ * with multiple profiles. We don't process. */
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: AAL2 profiles unsupported with "
+ "%s attributes.", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type));
+ SDP_FREE(cap_p);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ /* Transport is a non-AAL2 type. Parse payloads normally. */
+ sdp_parse_payload_types(sdp_p, cap_p, ptr);
+ if (cap_p->num_payloads == 0) {
+ SDP_FREE(cap_p);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ }
+
+ attr_p->attr.cap_p = cap_p;
+ /*
+ * This capability attr is valid. We can now handle X-cpar or
+ * cpar attrs.
+ */
+ sdp_p->cap_valid = TRUE;
+ sdp_p->last_cap_inst++;
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed %s media type %s, Transport %s, "
+ "Num payloads %u", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type),
+ sdp_get_media_name(cap_p->media),
+ sdp_get_transport_name(cap_p->transport),
+ cap_p->num_payloads);
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_attr_cap (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ u16 i, j;
+ sdp_mca_t *cap_p;
+ sdp_media_profiles_t *profile_p;
+
+ /* Get a pointer to the capability structure. */
+ cap_p = attr_p->attr.cap_p;
+
+ if (cap_p == NULL) {
+ CSFLogError(logTag, "%s Invalid %s attribute, unable to build.",
+ sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
+ sdp_p->conf_p->num_invalid_param++;
+ /* Return success so build won't fail. */
+ return (SDP_SUCCESS);
+ }
+
+ /* Validate params for this capability line */
+ if ((cap_p->media >= SDP_MAX_MEDIA_TYPES) ||
+ (cap_p->transport >= SDP_MAX_TRANSPORT_TYPES)) {
+ CSFLogDebug(logTag, logTag, "%s Media or transport type invalid for %s "
+ "attribute, unable to build.", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type));
+ sdp_p->conf_p->num_invalid_param++;
+ /* Return success so build won't fail. */
+ return (SDP_SUCCESS);
+ }
+
+ flex_string_sprintf(fs, "a=%s: %u %s ", sdp_attr[attr_p->type].name,
+ sdp_p->cur_cap_num, sdp_get_media_name(cap_p->media));
+
+ /* If the X-cap line has AAL2 profiles, build them differently. */
+ if ((cap_p->transport == SDP_TRANSPORT_AAL2_ITU) ||
+ (cap_p->transport == SDP_TRANSPORT_AAL2_ATMF) ||
+ (cap_p->transport == SDP_TRANSPORT_AAL2_CUSTOM)) {
+ profile_p = cap_p->media_profiles_p;
+ for (i=0; i < profile_p->num_profiles; i++) {
+ flex_string_sprintf(fs, "%s",
+ sdp_get_transport_name(profile_p->profile[i]));
+
+ for (j=0; j < profile_p->num_payloads[i]; j++) {
+ flex_string_sprintf(fs, " %u",
+ profile_p->payload_type[i][j]);
+ }
+ flex_string_append(fs, " ");
+ }
+
+ flex_string_append(fs, "\r\n");
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Built m= media line", sdp_p->debug_str);
+ }
+ return SDP_SUCCESS;
+ }
+
+ /* Build the transport name */
+ flex_string_sprintf(fs, "%s", sdp_get_transport_name(cap_p->transport));
+
+ /* Build the format lists */
+ for (i=0; i < cap_p->num_payloads; i++) {
+ if (cap_p->payload_indicator[i] == SDP_PAYLOAD_ENUM) {
+ flex_string_sprintf(fs, " %s",
+ sdp_get_payload_name((sdp_payload_e)cap_p->payload_type[i]));
+ } else {
+ flex_string_sprintf(fs, " %u", cap_p->payload_type[i]);
+ }
+ }
+
+ flex_string_append(fs, "\r\n");
+
+ /* Increment the current capability number for the next X-cap/cdsc attr. */
+ sdp_p->cur_cap_num += cap_p->num_payloads;
+ sdp_p->last_cap_type = attr_p->type;
+
+ /* Build any X-cpar/cpar attributes associated with this X-cap/cdsc line. */
+ return sdp_build_attr_cpar(sdp_p, cap_p->media_attrs_p, fs);
+}
+
+
+sdp_result_e sdp_parse_attr_cpar (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ u16 i;
+ sdp_result_e result;
+ sdp_mca_t *cap_p;
+ sdp_attr_t *cap_attr_p = NULL;
+ sdp_attr_t *prev_attr_p;
+ char tmp[SDP_MAX_STRING_LEN];
+
+ /* Make sure we've processed a valid X-cap/cdsc attr prior to this and
+ * if so, get the cap pointer. */
+ if (sdp_p->cap_valid == TRUE) {
+ sdp_attr_e cap_type;
+
+ if (attr_p->type == SDP_ATTR_CPAR) {
+ cap_type = SDP_ATTR_CDSC;
+ } else {
+ /* Default to X-CAP for everything else */
+ cap_type = SDP_ATTR_X_CAP;
+ }
+
+ if (sdp_p->mca_count == 0) {
+ cap_attr_p = sdp_find_attr(sdp_p, SDP_SESSION_LEVEL, 0,
+ cap_type, sdp_p->last_cap_inst);
+ } else {
+ cap_attr_p = sdp_find_attr(sdp_p, sdp_p->mca_count, 0,
+ cap_type, sdp_p->last_cap_inst);
+ }
+ }
+ if ((cap_attr_p == NULL) || (cap_attr_p->attr.cap_p == NULL)) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: %s attribute specified with no "
+ "prior %s attribute", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type),
+ (attr_p->type == SDP_ATTR_CPAR)?
+ (sdp_get_attr_name(SDP_ATTR_CDSC)) :
+ (sdp_get_attr_name(SDP_ATTR_X_CAP)) );
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /*
+ * Ensure there is no mixed syntax like CDSC followed by X-CPAR
+ * or X-CAP followed by CPAR.
+ */
+ if (((cap_attr_p->type == SDP_ATTR_CDSC) &&
+ (attr_p->type == SDP_ATTR_X_CPAR)) ||
+ ( (cap_attr_p->type == SDP_ATTR_X_CAP) &&
+ (attr_p->type == SDP_ATTR_CPAR)) ) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: %s attribute inconsistent with "
+ "prior %s attribute", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type),
+ sdp_get_attr_name(cap_attr_p->type));
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ cap_p = cap_attr_p->attr.cap_p;
+
+ /* a= is the only token we handle in an X-cpar/cpar attribute. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), "= \t", &result);
+
+ if ((result != SDP_SUCCESS) || (tmp[0] != 'a') || (tmp[1] != '\0')) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: Invalid token type (%s) in %s "
+ "attribute, unable to parse", sdp_p->debug_str, tmp,
+ sdp_get_attr_name(attr_p->type));
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ /*sa_ignore NO_NULL_CHK
+ *{ptr is valid since the pointer was checked earlier and the
+ * function would have exited if NULL.}
+ */
+ if (*ptr == '=') {
+ ptr++;
+ }
+
+ /* Find the attribute type. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), ": \t", &result);
+ /*sa_ignore NO_NULL_CHK
+ *{ptr is valid since the pointer was checked earlier and the
+ * function would have exited if NULL.}
+ */
+ if (ptr[0] == ':') {
+ /* Skip the ':' char for parsing attribute parameters. */
+ ptr++;
+ }
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s No attribute type specified for %s attribute, unable to parse.",
+ sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type));
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Reset the type of the attribute from X-cpar/cpar to whatever the
+ * specified type is. */
+ attr_p->type = SDP_ATTR_INVALID;
+ attr_p->next_p = NULL;
+ for (i=0; i < SDP_MAX_ATTR_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_attr[i].name, sdp_attr[i].strlen) == 0) {
+ attr_p->type = (sdp_attr_e)i;
+ }
+ }
+ if (attr_p->type == SDP_ATTR_INVALID) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: Unrecognized attribute (%s) for %s attribute, unable to parse.",
+ sdp_p->debug_str, tmp,
+ sdp_get_attr_name(attr_p->type));
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* We don't allow recursion with the capability attributes. */
+ if ((attr_p->type == SDP_ATTR_X_SQN) ||
+ (attr_p->type == SDP_ATTR_X_CAP) ||
+ (attr_p->type == SDP_ATTR_X_CPAR) ||
+ (attr_p->type == SDP_ATTR_SQN) ||
+ (attr_p->type == SDP_ATTR_CDSC) ||
+ (attr_p->type == SDP_ATTR_CPAR)) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: Invalid attribute (%s) for %s"
+ " attribute, unable to parse.", sdp_p->debug_str, tmp,
+ sdp_get_attr_name(attr_p->type));
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Parse the attribute. */
+ result = sdp_attr[attr_p->type].parse_func(sdp_p, attr_p, ptr);
+ if (result != SDP_SUCCESS) {
+ return (result);
+ }
+
+ /* Hook the attribute into the capability structure. */
+ if (cap_p->media_attrs_p == NULL) {
+ cap_p->media_attrs_p = attr_p;
+ } else {
+ for (prev_attr_p = cap_p->media_attrs_p;
+ prev_attr_p->next_p != NULL;
+ prev_attr_p = prev_attr_p->next_p) {
+ ; /* Empty for */
+ }
+ prev_attr_p->next_p = attr_p;
+ }
+
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_attr_cpar (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ sdp_result_e result;
+ const char *cpar_name;
+
+ /* Determine whether to use cpar or X-cpar */
+ if (sdp_p->last_cap_type == SDP_ATTR_CDSC) {
+ cpar_name = sdp_get_attr_name(SDP_ATTR_CPAR);
+ } else {
+ /*
+ * Default to X-CPAR if anything else. This is the backward
+ * compatible value.
+ */
+ cpar_name = sdp_get_attr_name(SDP_ATTR_X_CPAR);
+ }
+
+ while (attr_p != NULL) {
+ if (attr_p->type >= SDP_MAX_ATTR_TYPES) {
+ CSFLogDebug(logTag, "%s Invalid attribute type to build (%u)",
+ sdp_p->debug_str, attr_p->type);
+ } else {
+ flex_string_sprintf(fs, "a=%s: ", cpar_name);
+
+ result = sdp_attr[attr_p->type].build_func(sdp_p, attr_p, fs);
+
+ if (result == SDP_SUCCESS) {
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Built %s a=%s attribute line",
+ sdp_p->debug_str, cpar_name,
+ sdp_get_attr_name(attr_p->type));
+ }
+ }
+ }
+ attr_p = attr_p->next_p;
+ }
+
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_parse_attr_rtr (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ sdp_result_e result;
+ char tmp[SDP_MAX_STRING_LEN];
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsing a=%s, %s", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type),
+ tmp);
+ }
+ /*Default confirm to FALSE. */
+ attr_p->attr.rtr.confirm = FALSE;
+
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS){ // No confirm tag specified is not an error
+ return (SDP_SUCCESS);
+ } else {
+ /* See if confirm was specified. Defaults to FALSE. */
+ if (cpr_strncasecmp(tmp, "confirm", sizeof("confirm")) == 0) {
+ attr_p->attr.rtr.confirm = TRUE;
+ }
+ if (attr_p->attr.rtr.confirm == FALSE) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: RTR confirm parameter invalid (%s)",
+ sdp_p->debug_str, tmp);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, %s", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type),
+ tmp);
+ }
+ return (SDP_SUCCESS);
+ }
+}
+
+sdp_result_e sdp_build_attr_rtr (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ flex_string_sprintf(fs, "a=%s%s\r\n",
+ sdp_attr[attr_p->type].name,
+ attr_p->attr.rtr.confirm ? ":confirm" : "");
+
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_parse_attr_comediadir (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ int i;
+ sdp_result_e result;
+ tinybool type_found = FALSE;
+ char tmp[SDP_MAX_STRING_LEN];
+
+ attr_p->attr.comediadir.role = SDP_MEDIADIR_ROLE_PASSIVE;
+ attr_p->attr.comediadir.conn_info_present = FALSE;
+ attr_p->attr.comediadir.conn_info.nettype = SDP_NT_INVALID;
+ attr_p->attr.comediadir.src_port = 0;
+
+ /* Find the media direction role. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), ": \t", &result);
+
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No role parameter specified for "
+ "comediadir attribute.", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p->attr.comediadir.role = SDP_MEDIADIR_ROLE_UNSUPPORTED;
+ for (i=0; i < SDP_MAX_MEDIADIR_ROLES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_mediadir_role[i].name,
+ sdp_mediadir_role[i].strlen) == 0) {
+ type_found = TRUE;
+ attr_p->attr.comediadir.role = (sdp_mediadir_role_e)i;
+ break;
+ }
+ }
+ if (attr_p->attr.comediadir.role == SDP_MEDIADIR_ROLE_UNSUPPORTED) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: Invalid role type specified for "
+ "comediadir attribute (%s).", sdp_p->debug_str, tmp);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* If the role is passive, we don't expect any more params. */
+ if (attr_p->attr.comediadir.role == SDP_MEDIADIR_ROLE_PASSIVE) {
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, passive",
+ sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
+ }
+ return (SDP_SUCCESS);
+ }
+
+ /* Find the connection information if present */
+ /* parse to get the nettype */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No network type specified in comediadir "
+ "attribute.", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_SUCCESS); /* as the optional parameters are not there */
+ }
+ attr_p->attr.comediadir.conn_info.nettype = SDP_NT_UNSUPPORTED;
+ for (i=0; i < SDP_MAX_NETWORK_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_nettype[i].name,
+ sdp_nettype[i].strlen) == 0) {
+ type_found = TRUE;
+ }
+ if (type_found == TRUE) {
+ if (sdp_p->conf_p->nettype_supported[i] == TRUE) {
+ attr_p->attr.comediadir.conn_info.nettype = (sdp_nettype_e)i;
+ }
+ type_found = FALSE;
+ }
+ }
+ if (attr_p->attr.comediadir.conn_info.nettype == SDP_NT_UNSUPPORTED) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: ConnInfo in Comediadir: network type "
+ "unsupported (%s).", sdp_p->debug_str, tmp);
+ sdp_p->conf_p->num_invalid_param++;
+ }
+
+ /* Find the comedia address type. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No address type specified in comediadir"
+ " attribute.", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ }
+ attr_p->attr.comediadir.conn_info.addrtype = SDP_AT_UNSUPPORTED;
+ for (i=0; i < SDP_MAX_ADDR_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_addrtype[i].name,
+ sdp_addrtype[i].strlen) == 0) {
+ type_found = TRUE;
+ }
+ if (type_found == TRUE) {
+ if (sdp_p->conf_p->addrtype_supported[i] == TRUE) {
+ attr_p->attr.comediadir.conn_info.addrtype = (sdp_addrtype_e)i;
+ }
+ type_found = FALSE;
+ }
+ }
+ if (attr_p->attr.comediadir.conn_info.addrtype == SDP_AT_UNSUPPORTED) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: Conninfo address type unsupported "
+ "(%s).", sdp_p->debug_str, tmp);
+ sdp_p->conf_p->num_invalid_param++;
+ }
+
+ /* Find the conninfo address. */
+ ptr = sdp_getnextstrtok(ptr, attr_p->attr.comediadir.conn_info.conn_addr,
+ sizeof(attr_p->attr.comediadir.conn_info.conn_addr), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No conninfo address specified in "
+ "comediadir attribute.", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ }
+
+ /* Find the src port info , if any */
+ attr_p->attr.comediadir.src_port = sdp_getnextnumtok(ptr, &ptr, " \t",
+ &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No src port specified in "
+ "comediadir attribute.", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, network %s, addr type %s, address %s "
+ "srcport %u ",
+ sdp_p->debug_str, sdp_get_attr_name(attr_p->type),
+ sdp_get_network_name(attr_p->attr.comediadir.conn_info.nettype),
+ sdp_get_address_name(attr_p->attr.comediadir.conn_info.addrtype),
+ attr_p->attr.comediadir.conn_info.conn_addr,
+ (unsigned int)attr_p->attr.comediadir.src_port);
+ }
+
+ if (sdp_p->conf_p->num_invalid_param > 0) {
+ return (SDP_INVALID_PARAMETER);
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e
+sdp_build_attr_comediadir (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ flex_string_sprintf(fs, "a=%s:%s\r\n",
+ sdp_attr[attr_p->type].name,
+ sdp_get_mediadir_role_name(attr_p->attr.comediadir.role));
+
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_parse_attr_silencesupp (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ int i;
+ sdp_result_e result;
+ char tmp[SDP_MAX_STRING_LEN];
+
+ /* Find silenceSuppEnable */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s No silenceSupp enable value specified, parse failed.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (cpr_strncasecmp(tmp, "on", sizeof("on")) == 0) {
+ attr_p->attr.silencesupp.enabled = TRUE;
+ } else if (cpr_strncasecmp(tmp, "off", sizeof("off")) == 0) {
+ attr_p->attr.silencesupp.enabled = FALSE;
+ } else if (cpr_strncasecmp(tmp, "-", sizeof("-")) == 0) {
+ attr_p->attr.silencesupp.enabled = FALSE;
+ } else {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: silenceSuppEnable parameter invalid (%s)",
+ sdp_p->debug_str, tmp);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Find silenceTimer -- u16 or "-" */
+
+ attr_p->attr.silencesupp.timer =
+ (u16)sdp_getnextnumtok_or_null(ptr, &ptr, " \t",
+ &attr_p->attr.silencesupp.timer_null,
+ &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: Invalid timer value specified for "
+ "silenceSupp attribute.", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Find suppPref */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No silenceSupp pref specified.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p->attr.silencesupp.pref = SDP_SILENCESUPP_PREF_UNKNOWN;
+ for (i=0; i < SDP_MAX_SILENCESUPP_PREF; i++) {
+ if (cpr_strncasecmp(tmp, sdp_silencesupp_pref[i].name,
+ sdp_silencesupp_pref[i].strlen) == 0) {
+ attr_p->attr.silencesupp.pref = (sdp_silencesupp_pref_e)i;
+ }
+ }
+ if (attr_p->attr.silencesupp.pref == SDP_SILENCESUPP_PREF_UNKNOWN) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: silenceSupp pref unrecognized (%s)",
+ sdp_p->debug_str, tmp);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Find sidUse */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No silenceSupp sidUse specified.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p->attr.silencesupp.siduse = SDP_SILENCESUPP_SIDUSE_UNKNOWN;
+ for (i=0; i < SDP_MAX_SILENCESUPP_SIDUSE; i++) {
+ if (cpr_strncasecmp(tmp, sdp_silencesupp_siduse[i].name,
+ sdp_silencesupp_siduse[i].strlen) == 0) {
+ attr_p->attr.silencesupp.siduse = (sdp_silencesupp_siduse_e)i;
+ }
+ }
+ if (attr_p->attr.silencesupp.siduse == SDP_SILENCESUPP_SIDUSE_UNKNOWN) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: silenceSupp sidUse unrecognized (%s)",
+ sdp_p->debug_str, tmp);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Find fxnslevel -- u8 or "-" */
+ attr_p->attr.silencesupp.fxnslevel =
+ (u8)sdp_getnextnumtok_or_null(ptr, &ptr, " \t",
+ &attr_p->attr.silencesupp.fxnslevel_null,
+ &result);
+
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: Invalid fxnslevel value specified for "
+ "silenceSupp attribute.", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, enabled %s",
+ sdp_p->debug_str, sdp_get_attr_name(attr_p->type),
+ (attr_p->attr.silencesupp.enabled ? "on" : "off"));
+ if (attr_p->attr.silencesupp.timer_null) {
+ SDP_PRINT(" timer=-");
+ } else {
+ SDP_PRINT(" timer=%u,", attr_p->attr.silencesupp.timer);
+ }
+ SDP_PRINT(" pref=%s, siduse=%s,",
+ sdp_get_silencesupp_pref_name(attr_p->attr.silencesupp.pref),
+ sdp_get_silencesupp_siduse_name(
+ attr_p->attr.silencesupp.siduse));
+ if (attr_p->attr.silencesupp.fxnslevel_null) {
+ SDP_PRINT(" fxnslevel=-");
+ } else {
+ SDP_PRINT(" fxnslevel=%u,", attr_p->attr.silencesupp.fxnslevel);
+ }
+ }
+
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_attr_silencesupp (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ char temp_timer_string[11];
+ char temp_fxnslevel_string[11];
+
+ if (attr_p->attr.silencesupp.timer_null) {
+ snprintf(temp_timer_string, sizeof(temp_timer_string), "-");
+ } else {
+ snprintf(temp_timer_string, sizeof(temp_timer_string), "%u", attr_p->attr.silencesupp.timer);
+ }
+
+ if (attr_p->attr.silencesupp.fxnslevel_null) {
+ snprintf(temp_fxnslevel_string, sizeof(temp_fxnslevel_string), "-");
+ } else {
+ snprintf(temp_fxnslevel_string, sizeof(temp_fxnslevel_string), "%u", attr_p->attr.silencesupp.fxnslevel);
+ }
+
+ flex_string_sprintf(fs, "a=%s:%s %s %s %s %s\r\n",
+ sdp_attr[attr_p->type].name,
+ (attr_p->attr.silencesupp.enabled ? "on" : "off"),
+ temp_timer_string,
+ sdp_get_silencesupp_pref_name(attr_p->attr.silencesupp.pref),
+ sdp_get_silencesupp_siduse_name(attr_p->attr.silencesupp.siduse),
+ temp_fxnslevel_string);
+
+ return SDP_SUCCESS;
+}
+
+/*
+ * sdp_parse_context_crypto_suite
+ *
+ * This routine parses the crypto suite pointed to by str, stores the crypto suite value into the
+ * srtp context suite component of the LocalConnectionOptions pointed to by lco_node_ptr and stores
+ * pointer to the next crypto parameter in tmp_ptr
+ */
+tinybool sdp_parse_context_crypto_suite(char * str, sdp_attr_t *attr_p, sdp_t *sdp_p) {
+ /*
+ * Three crypto_suites are defined: (Notice no SPACE between "crypto:" and the
+ * AES_CM_128_HMAC_SHA1_80
+ * AES_CM_128_HMAC_SHA1_32
+ * F8_128_HMAC_SHA1_80
+ */
+
+ int i;
+
+ /* Check crypto suites */
+ for(i=0; iattr.srtp_context.suite = sdp_srtp_crypto_suite_array[i].crypto_suite_val;
+ attr_p->attr.srtp_context.master_key_size_bytes =
+ sdp_srtp_crypto_suite_array[i].key_size_bytes;
+ attr_p->attr.srtp_context.master_salt_size_bytes =
+ sdp_srtp_crypto_suite_array[i].salt_size_bytes;
+ return TRUE; /* There is a succesful match so exit */
+ }
+ }
+ /* couldn't find a matching crypto suite */
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s No Matching crypto suite for SRTP Context(%s)-'X-crypto:v1' expected",
+ sdp_p->debug_str, str);
+
+ return FALSE;
+}
+
+
+sdp_result_e sdp_build_attr_srtpcontext (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+#define MAX_BASE64_ENCODE_SIZE_BYTES 60
+ int output_len = MAX_BASE64_ENCODE_SIZE_BYTES;
+ int key_size = attr_p->attr.srtp_context.master_key_size_bytes;
+ int salt_size = attr_p->attr.srtp_context.master_salt_size_bytes;
+ unsigned char base64_encoded_data[MAX_BASE64_ENCODE_SIZE_BYTES];
+ unsigned char base64_encoded_input[MAX_BASE64_ENCODE_SIZE_BYTES];
+ base64_result_t status;
+
+ output_len = MAX_BASE64_ENCODE_SIZE_BYTES;
+
+ /* Append master and salt keys */
+ bcopy(attr_p->attr.srtp_context.master_key, base64_encoded_input,
+ key_size );
+ bcopy(attr_p->attr.srtp_context.master_salt,
+ base64_encoded_input + key_size, salt_size );
+
+ if ((status = base64_encode(base64_encoded_input, key_size + salt_size,
+ base64_encoded_data, &output_len)) != BASE64_SUCCESS) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Error: Failure to Base64 Encoded data (%s) ",
+ sdp_p->debug_str, BASE64_RESULT_TO_STRING(status));
+ }
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ *(base64_encoded_data + output_len) = '\0';
+
+ flex_string_sprintf(fs, "a=%s:%s inline:%s||\r\n",
+ sdp_attr[attr_p->type].name,
+ sdp_srtp_context_crypto_suite[attr_p->attr.srtp_context.suite].name,
+ base64_encoded_data);
+
+ return SDP_SUCCESS;
+}
+
+/*
+ * sdp_parse_attr_mptime
+ * This function parses the a=mptime sdp line. This parameter consists of
+ * one or more numbers or hyphens ("-"). The first parameter must be a
+ * number. The number of parameters must match the number of formats specified
+ * on the m= line. This function is liberal in that it does not match against
+ * the m= line or require a number for the first parameter.
+ */
+sdp_result_e sdp_parse_attr_mptime (
+ sdp_t *sdp_p,
+ sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ u16 i; /* loop counter for parameters */
+ sdp_result_e result; /* value returned by this function */
+ tinybool null_ind; /* true if a parameter is "-" */
+
+ /*
+ * Scan the input line up to the maximum number of parameters supported.
+ * Look for numbers or hyphens and store the resulting values. Hyphens
+ * are stored as zeros.
+ */
+ for (i=0; iattr.mptime.intervals[i] =
+ (ushort)sdp_getnextnumtok_or_null(ptr,&ptr," \t",&null_ind,&result);
+ if (result != SDP_SUCCESS) {
+ break;
+ }
+ attr_p->attr.mptime.num_intervals++;
+ }
+
+ /*
+ * At least one parameter must be supplied. If not, return an error
+ * and optionally log the failure.
+ */
+ if (attr_p->attr.mptime.num_intervals == 0) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No intervals specified for %s attr.",
+ sdp_p->debug_str, sdp_attr[attr_p->type].name);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /*
+ * Here is some debugging code that helps us track what data
+ * is received and parsed.
+ */
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, num intervals %u, intervals: ",
+ sdp_p->debug_str, sdp_get_attr_name(attr_p->type),
+ attr_p->attr.mptime.num_intervals);
+ for (i=0; i < attr_p->attr.mptime.num_intervals; i++) {
+ SDP_PRINT("%u ", attr_p->attr.mptime.intervals[i]);
+ }
+ }
+
+ return SDP_SUCCESS;
+}
+
+/*
+ * sdp_build_attr_mptime
+ * This function builds the a=mptime sdp line. It reads the selected attribute
+ * from the sdp structure. Parameters with a value of zero are replaced by
+ * hyphens.
+ */
+sdp_result_e sdp_build_attr_mptime (
+ sdp_t *sdp_p,
+ sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ int i;
+
+ flex_string_sprintf(fs, "a=%s:", sdp_attr[attr_p->type].name);
+
+ /*
+ * Run the list of mptime parameter values and write each one
+ * to the sdp line. Replace zeros with hyphens.
+ */
+ for (i=0; i < attr_p->attr.mptime.num_intervals; i++) {
+ if (i > 0) {
+ flex_string_append(fs, " ");
+ }
+
+ if (attr_p->attr.mptime.intervals[i] == 0) {
+ flex_string_append(fs, "-");
+ } else {
+ flex_string_sprintf(fs, "%u", attr_p->attr.mptime.intervals[i]);
+ }
+ }
+
+ flex_string_append(fs, "\r\n");
+
+ return SDP_SUCCESS;
+}
+
+
+
+sdp_result_e sdp_parse_attr_x_sidin (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ sdp_result_e result;
+ attr_p->attr.stream_data.x_sidin[0] = '\0';
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsing a=%s", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type));
+ }
+
+ /* Find the X-sidin value */
+ ptr = sdp_getnextstrtok(ptr, attr_p->attr.stream_data.x_sidin,
+ sizeof(attr_p->attr.stream_data.x_sidin), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No Stream Id incoming specified for X-sidin attribute.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, %s", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type),
+ attr_p->attr.stream_data.x_sidin);
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_attr_x_sidin (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ flex_string_sprintf(fs, "a=%s:%s\r\n",
+ sdp_attr[attr_p->type].name,
+ attr_p->attr.stream_data.x_sidin);
+
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_parse_attr_x_sidout (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ sdp_result_e result;
+ attr_p->attr.stream_data.x_sidout[0] = '\0';
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsing a=%s", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type));
+ }
+
+ /* Find the X-sidout value */
+ ptr = sdp_getnextstrtok(ptr, attr_p->attr.stream_data.x_sidout,
+ sizeof(attr_p->attr.stream_data.x_sidout), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No Stream Id outgoing specified for X-sidout attribute.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, %s", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type),
+ attr_p->attr.stream_data.x_sidout);
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_attr_x_sidout (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ flex_string_sprintf(fs, "a=%s:%s\r\n",
+ sdp_attr[attr_p->type].name,
+ attr_p->attr.stream_data.x_sidout);
+
+ return SDP_SUCCESS;
+}
+
+
+sdp_result_e sdp_parse_attr_x_confid (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ sdp_result_e result;
+ attr_p->attr.stream_data.x_confid[0] = '\0';
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsing a=%s", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type));
+ }
+
+ /* Find the X-confid value */
+ ptr = sdp_getnextstrtok(ptr, attr_p->attr.stream_data.x_confid,
+ sizeof(attr_p->attr.stream_data.x_confid), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No Conf Id incoming specified for "
+ "X-confid attribute.", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, %s", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type),
+ attr_p->attr.stream_data.x_confid);
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_attr_x_confid (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ if (strlen(attr_p->attr.stream_data.x_confid) <= 0) {
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s X-confid value is not set. Cannot build a=X-confid line\n",
+ sdp_p->debug_str);
+ }
+
+ return SDP_INVALID_PARAMETER;
+ }
+
+ flex_string_sprintf(fs, "a=%s:%s\r\n",
+ sdp_attr[attr_p->type].name,
+ attr_p->attr.stream_data.x_confid);
+
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_parse_attr_group (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ sdp_result_e result;
+ char tmp[10];
+ int i=0;
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsing a=%s", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type));
+ }
+
+ /* Find the a=group: < id2> ... values */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No group attribute value specified for "
+ "a=group line", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p->attr.stream_data.group_attr = SDP_GROUP_ATTR_UNSUPPORTED;
+ for (i=0; i < SDP_MAX_GROUP_ATTR_VAL; i++) {
+ if (cpr_strncasecmp(tmp, sdp_group_attr_val[i].name,
+ sdp_group_attr_val[i].strlen) == 0) {
+ attr_p->attr.stream_data.group_attr = (sdp_group_attr_e)i;
+ break;
+ }
+ }
+
+ if (attr_p->attr.stream_data.group_attr == SDP_GROUP_ATTR_UNSUPPORTED) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: Group attribute type unsupported (%s).",
+ sdp_p->debug_str, tmp);
+ }
+
+
+ /*
+ * Scan the input line up after group: to the maximum number
+ * of id available.
+ */
+ attr_p->attr.stream_data.num_group_id =0;
+
+ for (i=0; iattr.stream_data.group_id_arr[i] =
+ (u16)sdp_getnextnumtok(ptr,&ptr," \t", &result);
+ if (result != SDP_SUCCESS) {
+ break;
+ }
+ attr_p->attr.stream_data.num_group_id++;
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s:%s\n", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type),
+ sdp_get_group_attr_name (attr_p->attr.stream_data.group_attr));
+ for (i=0; i < attr_p->attr.stream_data.num_group_id; i++) {
+ SDP_PRINT("%s Parsed group line id : %d\n", sdp_p->debug_str,
+ attr_p->attr.stream_data.group_id_arr[i]);
+ }
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_attr_group (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ int i;
+
+ flex_string_sprintf(fs, "a=%s:%s",
+ sdp_attr[attr_p->type].name,
+ sdp_get_group_attr_name(attr_p->attr.stream_data.group_attr));
+
+ for (i=0; i < attr_p->attr.stream_data.num_group_id; i++) {
+ if (attr_p->attr.stream_data.group_id_arr[i] > 0) {
+ flex_string_sprintf(fs, " %u",
+ attr_p->attr.stream_data.group_id_arr[i]);
+ }
+ }
+
+ flex_string_append(fs, "\r\n");
+
+ return SDP_SUCCESS;
+}
+
+/* Parse the source-filter attribute
+ * "a=source-filter:"
+ * = ...
+ */
+sdp_result_e sdp_parse_attr_source_filter (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ int i;
+ sdp_result_e result;
+ char tmp[SDP_MAX_STRING_LEN];
+
+ attr_p->attr.source_filter.mode = SDP_FILTER_MODE_NOT_PRESENT;
+ attr_p->attr.source_filter.nettype = SDP_NT_UNSUPPORTED;
+ attr_p->attr.source_filter.addrtype = SDP_AT_UNSUPPORTED;
+ attr_p->attr.source_filter.dest_addr[0] = '\0';
+ attr_p->attr.source_filter.num_src_addr = 0;
+
+ /* Find the filter mode */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No src filter attribute value specified for "
+ "a=source-filter line", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ for (i = 0; i < SDP_MAX_FILTER_MODE; i++) {
+ if (cpr_strncasecmp(tmp, sdp_src_filter_mode_val[i].name,
+ sdp_src_filter_mode_val[i].strlen) == 0) {
+ attr_p->attr.source_filter.mode = (sdp_src_filter_mode_e)i;
+ break;
+ }
+ }
+ if (attr_p->attr.source_filter.mode == SDP_FILTER_MODE_NOT_PRESENT) {
+ /* No point continuing */
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: Invalid src filter mode for a=source-filter "
+ "line", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Find the network type */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ for (i = 0; i < SDP_MAX_NETWORK_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_nettype[i].name,
+ sdp_nettype[i].strlen) == 0) {
+ if (sdp_p->conf_p->nettype_supported[i] == TRUE) {
+ attr_p->attr.source_filter.nettype = (sdp_nettype_e)i;
+ }
+ }
+ }
+ if (attr_p->attr.source_filter.nettype == SDP_NT_UNSUPPORTED) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: Network type unsupported "
+ "(%s) for a=source-filter", sdp_p->debug_str, tmp);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Find the address type */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ for (i = 0; i < SDP_MAX_ADDR_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_addrtype[i].name,
+ sdp_addrtype[i].strlen) == 0) {
+ if (sdp_p->conf_p->addrtype_supported[i] == TRUE) {
+ attr_p->attr.source_filter.addrtype = (sdp_addrtype_e)i;
+ }
+ }
+ }
+ if (attr_p->attr.source_filter.addrtype == SDP_AT_UNSUPPORTED) {
+ if (strncmp(tmp, "*", 1) == 0) {
+ attr_p->attr.source_filter.addrtype = SDP_AT_FQDN;
+ } else {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: Address type unsupported "
+ "(%s) for a=source-filter", sdp_p->debug_str, tmp);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ }
+
+ /* Find the destination addr */
+ ptr = sdp_getnextstrtok(ptr, attr_p->attr.source_filter.dest_addr,
+ sizeof(attr_p->attr.source_filter.dest_addr), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s No filter destination address specified for "
+ "a=source-filter", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Find the list of source address to apply the filter */
+ for (i = 0; i < SDP_MAX_SRC_ADDR_LIST; i++) {
+ ptr = sdp_getnextstrtok(ptr, attr_p->attr.source_filter.src_list[i],
+ sizeof(attr_p->attr.source_filter.src_list[i]), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ break;
+ }
+ attr_p->attr.source_filter.num_src_addr++;
+ }
+ if (attr_p->attr.source_filter.num_src_addr == 0) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No source list provided "
+ "for a=source-filter", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_source_filter (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ int i;
+
+ flex_string_sprintf(fs, "a=%s:%s %s %s %s",
+ sdp_get_attr_name(attr_p->type),
+ sdp_get_src_filter_mode_name(attr_p->attr.source_filter.mode),
+ sdp_get_network_name(attr_p->attr.source_filter.nettype),
+ sdp_get_address_name(attr_p->attr.source_filter.addrtype),
+ attr_p->attr.source_filter.dest_addr);
+
+ for (i = 0; i < attr_p->attr.source_filter.num_src_addr; i++) {
+ flex_string_append(fs, " ");
+ flex_string_append(fs, attr_p->attr.source_filter.src_list[i]);
+ }
+
+ flex_string_append(fs, "\r\n");
+
+ return SDP_SUCCESS;
+}
+
+/* Parse the rtcp-unicast attribute
+ * "a=rtcp-unicast:"
+ */
+sdp_result_e sdp_parse_attr_rtcp_unicast (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ sdp_result_e result;
+ u32 i;
+ char tmp[SDP_MAX_STRING_LEN];
+
+ attr_p->attr.u32_val = SDP_RTCP_UNICAST_MODE_NOT_PRESENT;
+
+ memset(tmp, 0, sizeof(tmp));
+
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No rtcp unicast mode specified for "
+ "a=rtcp-unicast line", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ for (i = 0; i < SDP_RTCP_MAX_UNICAST_MODE; i++) {
+ if (cpr_strncasecmp(tmp, sdp_rtcp_unicast_mode_val[i].name,
+ sdp_rtcp_unicast_mode_val[i].strlen) == 0) {
+ attr_p->attr.u32_val = i;
+ break;
+ }
+ }
+ if (attr_p->attr.u32_val == SDP_RTCP_UNICAST_MODE_NOT_PRESENT) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: Invalid rtcp unicast mode for "
+ "a=rtcp-unicast line", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_attr_rtcp_unicast (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ if (attr_p->attr.u32_val >= SDP_RTCP_MAX_UNICAST_MODE) {
+ return SDP_INVALID_PARAMETER;
+ }
+
+ flex_string_sprintf(fs, "a=%s:%s\r\n",
+ sdp_get_attr_name(attr_p->type),
+ sdp_get_rtcp_unicast_mode_name((sdp_rtcp_unicast_mode_e)attr_p->attr.u32_val));
+
+ return SDP_SUCCESS;
+}
+
+
+/*
+ * store_sdescriptions_mki_or_lifetime
+ *
+ * Verifies the syntax of the MKI or lifetime parameter and stores
+ * it in the sdescriptions attribute struct.
+ *
+ * Inputs:
+ * buf - pointer to MKI or lifetime string assumes string is null
+ * terminated.
+ * attr_p - pointer to attribute struct
+ *
+ * Outputs:
+ * Return TRUE all is good otherwise FALSE for error.
+ */
+
+tinybool
+store_sdescriptions_mki_or_lifetime (char *buf, sdp_attr_t *attr_p)
+{
+
+ tinybool result;
+ u16 mkiLen;
+ char mkiValue[SDP_SRTP_MAX_MKI_SIZE_BYTES];
+
+ /* MKI has a colon */
+ if (strstr(buf, ":")) {
+ result = verify_sdescriptions_mki(buf, mkiValue, &mkiLen);
+ if (result) {
+ attr_p->attr.srtp_context.mki_size_bytes = mkiLen;
+ sstrncpy((char*)attr_p->attr.srtp_context.mki, mkiValue,
+ SDP_SRTP_MAX_MKI_SIZE_BYTES);
+ }
+
+ } else {
+ result = verify_sdescriptions_lifetime(buf);
+ if (result) {
+ sstrncpy((char*)attr_p->attr.srtp_context.master_key_lifetime, buf,
+ SDP_SRTP_MAX_LIFETIME_BYTES);
+ }
+ }
+
+ return result;
+
+}
+
+/*
+ * sdp_parse_sdescriptions_key_param
+ *
+ * This routine parses the srtp key-params pointed to by str.
+ *
+ * key-params = ":"
+ * key-method = "inline" / key-method-ext [note V9 only supports 'inline']
+ * key-info = srtp-key-info
+ * srtp-key-info = key-salt ["|" lifetime] ["|" mki]
+ * key-salt = 1*(base64) ; binary key and salt values
+ * ; concatenated together, and then
+ * ; base64 encoded [section 6.8 of
+ * ; RFC2046]
+ *
+ * lifetime = ["2^"] 1*(DIGIT)
+ * mki = mki-value ":" mki-length
+ * mki-value = 1*DIGIT
+ * mki-length = 1*3DIGIT ; range 1..128.
+ *
+ * Inputs: str - pointer to beginning of key-params and assumes
+ * null terminated string.
+ */
+
+
+tinybool
+sdp_parse_sdescriptions_key_param (const char *str, sdp_attr_t *attr_p,
+ sdp_t *sdp_p)
+{
+ char buf[SDP_MAX_STRING_LEN],
+ base64decodeData[SDP_MAX_STRING_LEN];
+ const char *ptr;
+ sdp_result_e result = SDP_SUCCESS;
+ tinybool keyFound = FALSE;
+ int len,
+ keySize,
+ saltSize;
+ base64_result_t status;
+
+ ptr = str;
+ if (cpr_strncasecmp(ptr, "inline:", 7) != 0) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Could not find keyword inline", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return FALSE;
+ }
+
+ /* advance pass the inline key word */
+ ptr = ptr + 7;
+ ptr = sdp_getnextstrtok(ptr, buf, sizeof(buf), "|", &result);
+ while (result == SDP_SUCCESS) {
+ /* the fist time this loop executes, the key is gotten */
+ if (keyFound == FALSE) {
+ keyFound = TRUE;
+ len = SDP_MAX_STRING_LEN;
+ /* The key is base64 encoded composed of the master key concatenated with the
+ * master salt.
+ */
+ status = base64_decode((unsigned char *)buf, strlen(buf),
+ (unsigned char *)base64decodeData, &len);
+
+ if (status != BASE64_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s key-salt error decoding buffer: %s",
+ sdp_p->debug_str, BASE64_RESULT_TO_STRING(status));
+ return FALSE;
+ }
+
+ keySize = attr_p->attr.srtp_context.master_key_size_bytes;
+ saltSize = attr_p->attr.srtp_context.master_salt_size_bytes;
+
+ if (len != keySize + saltSize) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s key-salt size doesn't match: (%d, %d, %d)",
+ sdp_p->debug_str, len, keySize, saltSize);
+ return(FALSE);
+ }
+
+ bcopy(base64decodeData, attr_p->attr.srtp_context.master_key, keySize);
+
+ bcopy(base64decodeData + keySize,
+ attr_p->attr.srtp_context.master_salt, saltSize);
+
+ /* Used only for MGCP */
+ SDP_SRTP_CONTEXT_SET_MASTER_KEY
+ (attr_p->attr.srtp_context.selection_flags);
+ SDP_SRTP_CONTEXT_SET_MASTER_SALT
+ (attr_p->attr.srtp_context.selection_flags);
+
+ } else if (store_sdescriptions_mki_or_lifetime(buf, attr_p) == FALSE) {
+ return FALSE;
+ }
+
+ /* if we haven't reached the end of line, get the next token */
+ ptr = sdp_getnextstrtok(ptr, buf, sizeof(buf), "|", &result);
+ }
+
+ /* if we didn't find the key, error out */
+ if (keyFound == FALSE) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Could not find sdescriptions key", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return FALSE;
+ }
+
+ return TRUE;
+
+}
+
+/*
+ * sdp_build_attr_sdescriptions
+ *
+ * Builds a=crypto line for attribute type SDP_ATTR_SDESCRIPTIONS.
+ *
+ * a=crypto:tag 1*WSP crypto-suite 1*WSP key-params
+ *
+ * Where key-params = inline: ["|"lifetime] ["|" MKI:length]
+ * The key and salt is base64 encoded and lifetime and MKI/length are optional.
+ */
+
+sdp_result_e
+sdp_build_attr_sdescriptions (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+
+ unsigned char base64_encoded_data[MAX_BASE64_STRING_LEN];
+ unsigned char base64_encoded_input[MAX_BASE64_STRING_LEN];
+ int keySize,
+ saltSize,
+ outputLen;
+ base64_result_t status;
+
+ keySize = attr_p->attr.srtp_context.master_key_size_bytes;
+ saltSize = attr_p->attr.srtp_context.master_salt_size_bytes;
+
+ /* concatenate the master key + salt then base64 encode it */
+ bcopy(attr_p->attr.srtp_context.master_key,
+ base64_encoded_input, keySize);
+
+ bcopy(attr_p->attr.srtp_context.master_salt,
+ base64_encoded_input + keySize, saltSize);
+
+ outputLen = MAX_BASE64_STRING_LEN;
+ status = base64_encode(base64_encoded_input, keySize + saltSize,
+ base64_encoded_data, &outputLen);
+
+ if (status != BASE64_SUCCESS) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Error: Failure to Base64 Encoded data (%s) ",
+ sdp_p->debug_str, BASE64_RESULT_TO_STRING(status));
+ }
+ return (SDP_INVALID_PARAMETER);
+
+ }
+
+ base64_encoded_data[outputLen] = 0;
+
+ /* lifetime and MKI parameters are optional. Only inlcude them if
+ * they were set.
+ */
+
+
+ if (attr_p->attr.srtp_context.master_key_lifetime[0] != 0 &&
+ attr_p->attr.srtp_context.mki[0] != 0) {
+ flex_string_sprintf(fs, "a=%s:%d %s inline:%s|%s|%s:%d\r\n",
+ sdp_attr[attr_p->type].name,
+ attr_p->attr.srtp_context.tag,
+ sdp_srtp_context_crypto_suite[attr_p->attr.srtp_context.suite].name,
+ base64_encoded_data,
+ attr_p->attr.srtp_context.master_key_lifetime,
+ attr_p->attr.srtp_context.mki,
+ attr_p->attr.srtp_context.mki_size_bytes);
+
+ return SDP_SUCCESS;
+ }
+
+ /* if we get here, either lifetime is populated and mki and is not or mki is populated
+ * and lifetime is not or neither is populated
+ */
+
+ if (attr_p->attr.srtp_context.master_key_lifetime[0] != 0) {
+ flex_string_sprintf(fs, "a=%s:%d %s inline:%s|%s\r\n",
+ sdp_attr[attr_p->type].name,
+ attr_p->attr.srtp_context.tag,
+ sdp_srtp_context_crypto_suite[attr_p->attr.srtp_context.suite].name,
+ base64_encoded_data,
+ attr_p->attr.srtp_context.master_key_lifetime);
+
+ } else if (attr_p->attr.srtp_context.mki[0] != 0) {
+ flex_string_sprintf(fs, "a=%s:%d %s inline:%s|%s:%d\r\n",
+ sdp_attr[attr_p->type].name,
+ attr_p->attr.srtp_context.tag,
+ sdp_srtp_context_crypto_suite[attr_p->attr.srtp_context.suite].name,
+ base64_encoded_data,
+ attr_p->attr.srtp_context.mki,
+ attr_p->attr.srtp_context.mki_size_bytes);
+
+ } else {
+ flex_string_sprintf(fs, "a=%s:%d %s inline:%s\r\n",
+ sdp_attr[attr_p->type].name,
+ attr_p->attr.srtp_context.tag,
+ sdp_srtp_context_crypto_suite[attr_p->attr.srtp_context.suite].name,
+ base64_encoded_data);
+
+ }
+
+ return SDP_SUCCESS;
+
+}
+
+
+/*
+ * sdp_parse_attr_srtp
+ *
+ * Parses Session Description for Protocol Security Descriptions
+ * version 2 or version 9. Grammar is of the form:
+ *
+ * a=crypto: []
+ *
+ * Note session-params is not supported and will not be parsed.
+ * Version 2 does not contain a tag.
+ *
+ * Inputs:
+ * sdp_p - pointer to sdp handle
+ * attr_p - pointer to attribute structure
+ * ptr - pointer to string to be parsed
+ * vtype - version type
+ */
+
+sdp_result_e
+sdp_parse_attr_srtp (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr, sdp_attr_e vtype)
+{
+
+ char tmp[SDP_MAX_STRING_LEN];
+ sdp_result_e result = SDP_FAILURE;
+ int k = 0;
+
+ /* initialize only the optional parameters */
+ attr_p->attr.srtp_context.master_key_lifetime[0] = 0;
+ attr_p->attr.srtp_context.mki[0] = 0;
+
+ /* used only for MGCP */
+ SDP_SRTP_CONTEXT_SET_ENCRYPT_AUTHENTICATE
+ (attr_p->attr.srtp_context.selection_flags);
+
+ /* get the tag only if we are version 9 */
+ if (vtype == SDP_ATTR_SDESCRIPTIONS) {
+ attr_p->attr.srtp_context.tag =
+ sdp_getnextnumtok(ptr, &ptr, " \t", &result);
+
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Could not find sdescriptions tag",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+
+ }
+ }
+
+ /* get the crypto suite */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Could not find sdescriptions crypto suite", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (!sdp_parse_context_crypto_suite(tmp, attr_p, sdp_p)) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Unsupported crypto suite", sdp_p->debug_str);
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Could not find sdescriptions key params", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (!sdp_parse_sdescriptions_key_param(tmp, attr_p, sdp_p)) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Failed to parse key-params", sdp_p->debug_str);
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* if there are session parameters, scan the session parameters
+ * into tmp until we reach end of line. Currently the sdp parser
+ * does not parse session parameters but if they are present,
+ * we store them for the application.
+ */
+ /*sa_ignore NO_NULL_CHK
+ *{ptr is valid since the pointer was checked earlier and the
+ * function would have exited if NULL.}
+ */
+ while (*ptr && *ptr != '\n' && *ptr != '\r' && k < SDP_MAX_STRING_LEN) {
+ tmp[k++] = *ptr++;
+ }
+
+ if ((k) && (k < SDP_MAX_STRING_LEN)) {
+ tmp[k] = 0;
+ attr_p->attr.srtp_context.session_parameters = cpr_strdup(tmp);
+ }
+
+ return SDP_SUCCESS;
+
+}
+
+/* Parses crypto attribute based on the sdescriptions version
+ * 9 grammar.
+ *
+ */
+
+sdp_result_e
+sdp_parse_attr_sdescriptions (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+
+ return sdp_parse_attr_srtp(sdp_p, attr_p, ptr,
+ SDP_ATTR_SDESCRIPTIONS);
+
+}
+
+/* Parses X-crypto attribute based on the sdescriptions version
+ * 2 grammar.
+ *
+ */
+
+sdp_result_e sdp_parse_attr_srtpcontext (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+
+ return sdp_parse_attr_srtp(sdp_p, attr_p, ptr,
+ SDP_ATTR_SRTP_CONTEXT);
+}
+
+
+sdp_result_e sdp_build_attr_ice_attr (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs) {
+ flex_string_sprintf(fs, "a=%s\r\n", attr_p->attr.ice_attr);
+
+ return SDP_SUCCESS;
+}
+
+
+sdp_result_e sdp_parse_attr_ice_attr (sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr) {
+ sdp_result_e result;
+ char tmp[SDP_MAX_STRING_LEN];
+
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), "\r\n", &result);
+ if (result != SDP_SUCCESS){
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: problem parsing ice attribute ", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* We need the attr= here. This is pretty gross. */
+ snprintf(attr_p->attr.ice_attr, sizeof(attr_p->attr.ice_attr),
+ "%s:%s", sdp_get_attr_name(attr_p->type), tmp);
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, %s", sdp_p->debug_str, sdp_get_attr_name(attr_p->type), tmp);
+ }
+ return (SDP_SUCCESS);
+}
+
+
+sdp_result_e sdp_parse_attr_fingerprint_attr (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ sdp_result_e result;
+
+ ptr = sdp_getnextstrtok(ptr, attr_p->attr.string_val, sizeof(attr_p->attr.string_val), "\r\n", &result);
+
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No string token found for %s attribute",
+ sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, %s", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type),
+ attr_p->attr.string_val);
+ }
+ return (SDP_SUCCESS);
+ }
+}
+
+sdp_result_e sdp_build_attr_rtcp_mux_attr (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs) {
+ flex_string_append(fs, "a=rtcp-mux\r\n");
+
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_parse_attr_rtcp_mux_attr (sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr) {
+ attr_p->attr.boolean_val = TRUE;
+
+ return (SDP_SUCCESS);
+}
diff --git a/libs/sipcc/core/sdp/sdp_attr_access.c b/libs/sipcc/core/sdp/sdp_attr_access.c
new file mode 100644
index 0000000000..cda2e6b051
--- /dev/null
+++ b/libs/sipcc/core/sdp/sdp_attr_access.c
@@ -0,0 +1,11872 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "sdp_os_defs.h"
+#include "sdp.h"
+#include "sdp_private.h"
+#include "CSFLog.h"
+
+//static const char* logTag = "sdp_attr_access";
+
+/* Attribute access routines are all defined by the following parameters.
+ *
+ * sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level the attribute is defined. Can be either
+ * SDP_SESSION_LEVEL or 0-n specifying a media line level.
+ * inst_num The instance number of the attribute. Multiple instances
+ * of a particular attribute may exist at each level and so
+ * the inst_num determines the particular attribute at that
+ * level that should be accessed. Note that this is the
+ * instance number of the specified type of attribute, not the
+ * overall attribute number at the level. Also note that the
+ * instance number is 1-based. For example:
+ * v=0
+ * o=mhandley 2890844526 2890842807 IN IP4 126.16.64.4
+ * s=SDP Seminar
+ * c=IN IP4 10.1.0.2
+ * t=0 0
+ * m=audio 1234 RTP/AVP 0 101 102
+ * a=foo 1
+ * a=foo 2
+ * a=bar 1 # This is instance 1 of attribute bar.
+ * a=foo 3 # This is instance 3 of attribute foo.
+ * cap_num Almost all of the attributes may be defined as X-cpar
+ * parameters (with the exception of X-sqn, X-cap, and X-cpar).
+ * If the cap_num is set to zero, then the attribute is not
+ * an X-cpar parameter attribute. If the cap_num is any other
+ * value, it specifies the capability number that the X-cpar
+ * attribute is specified for.
+ */
+
+/* Attribute handling:
+ *
+ * There are two basic types of attributes handled by the SDP library,
+ * those defined by a= token lines, and those embedded with a=X-cpar lines.
+ * The handling for each of these is described here.
+ *
+ * Simple (non X-cpar attributes):
+ *
+ * Attributes not embedded in a=X-cpar lines are referenced by level and
+ * instance number. For these attributes the capability number is always
+ * set to zero.
+ *
+ * An application will typically process these attributes in one of two ways.
+ * With the first method, the application can determine the total number
+ * of attributes defined at a given level and process them one at a time.
+ * For each attribute, the application will query the library to find out
+ * what type of attribute it is and which instance within that type. The
+ * application can then process this particular attribute referencing it
+ * by level and instance number.
+ *
+ * A second method of processing attributes is for applications to determine
+ * each type of attribute they are interested in, query the SDP library to
+ * find out how many of that type of attribute exist at a given level, and
+ * process each one at a time.
+ *
+ * X-cpar attribute processing:
+ *
+ * X-cpar attributes can contain embedded attributes. They are associated
+ * with X-cap attribute lines. An example of X-cap and X-cpar attributes
+ * found in an SDP is as follows:
+ *
+ * v=0
+ * o=- 25678 753849 IN IP4 128.96.41.1
+ * s=-
+ * t=0 0
+ * c=IN IP4 10.1.0.2
+ * m=audio 3456 RTP/AVP 18 96
+ * a=rtpmap:96 telephone-event/8000
+ * a=fmtp:96 0-15,32-35
+ * a=X-sqn: 0
+ * a=X-cap: 1 audio RTP/AVP 0 18 96 97
+ * a=X-cpar: a=fmtp:96 0-16,32-35
+ * a=X-cpar: a=rtpmap:97 X-NSE/8000
+ * a=X-cpar: a=fmtp:97 195-197
+ * a=X-cap: 5 image udptl t38
+ * a=X-cap: 6 application udp X-tmr
+ * a=X-cap: 7 audio RTP/AVP 100 101
+ * a=X-cpar: a=rtpmap:100 g.711/8000
+ * a=X-cpar: a=rtpmap:101 g.729/8000
+ *
+ * X-cap attributes can be defined at the SESSION_LEVEL or any media level.
+ * An X-cap attr is defined by the level and instance number just like
+ * other attributes. In the example above, X-cap attrs are defined at
+ * media level 1 and there are four instances at that level.
+ *
+ * The X-cpar attributes can also be referenced by level and instance number.
+ * However, the embedded attribute within an X-cpar attribute must be
+ * referenced by level, instance number, and capability number. This is
+ * because the X-cpar attribute is associated with a particular X-cap/
+ * capability.
+ * For all attributes that are not embedded within an X-cpar attribute, the
+ * cap_num should be referenced as zero. But for X-cpar attributes, the
+ * cap_num is specified to be one of the capability numbers of the previous
+ * X-cap line. The number of capabilities specified in an X-cap line is
+ * equal to the number of payloads. Thus, in this example, the first X-cap
+ * attr instance specifies capabilities 1-4, the second specifies capability
+ * 5, the third capability 6, and the fourth capabilities 7-8.
+ *
+ * X-cpar attributes can be processed with methods similar to the two
+ * previously mentioned. For each X-cap attribute, the application can
+ * use one of two methods to process the X-cpar attributes. First, it
+ * can query the total number of X-cpar attributes associated with a
+ * given X-cap attribute. The X-cap attribute is here defined by a level
+ * and a capability number. In the example above, the total number of
+ * attributes defined is as follows:
+ * level 1, cap_num 1 - total attrs: 3
+ * level 1, cap_num 5 - total attrs: 0
+ * level 1, cap_num 6 - total attrs: 0
+ * level 1, cap_num 7 - total attrs: 2
+ *
+ * Note that if the application queried the number of attributes for
+ * cap_num 2, 3, or 4, it would also return 3 attrs, and for cap_num
+ * 8 the library would return 2.
+ *
+ * Once the application determines the total number of attributes for
+ * that capability, it can again query the embedded attribute type and
+ * instance. For example, sdp_get_attr_type would return the following:
+ * level 1, cap_num 1, attr 1 -> attr type fmtp, instance 1
+ * level 1, cap_num 1, attr 2 -> attr type rtpmap, instance 1
+ * level 1, cap_num 1, attr 3 -> attr type fmtp, instance 2
+ * level 1, cap_num 7, attr 1 -> attr type rtpmap, instance 1
+ * level 1, cap_num 7, attr 2 -> attr type rtpmap, instance 2
+ *
+ * The individual embedded attributes can then be accessed by level,
+ * cap_num, and instance number.
+ *
+ * With the second method for handling X-cpar attributes, the application
+ * determines the types of attributes it is interested in. It can then
+ * query the SDP library to determine the number of attributes of that
+ * type found for that level and cap_num, and then process each one at
+ * a time. e.g., calling sdp_attr_num_instances would give:
+ * level 1, cap_num 1, attr_type fmtp -> two instances
+ * level 1, cap_num 1, attr_type rtpmap -> one instance
+ * level 1, cap_num 7, attr_type fmtp -> zero instances
+ * level 1, cap_num 7, attr_type rtpmap -> two instances
+ */
+
+
+/* Function: sdp_add_new_attr
+ * Description: Add a new attribute of the specified type at the given
+ * level and capability level or base attribute if cap_num
+ * is zero.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * attr_type The type of attribute to add.
+ * inst_num Pointer to a u16 in which to return the instance
+ * number of the newly added attribute.
+ * Returns: SDP_SUCCESS Attribute was added successfully.
+ * SDP_NO_RESOURCE No memory avail for new attribute.
+ * SDP_INVALID_PARAMETER Specified media line is not defined.
+ */
+sdp_result_e sdp_add_new_attr (void *sdp_ptr, u16 level, u8 cap_num,
+ sdp_attr_e attr_type, u16 *inst_num)
+{
+ u16 i;
+ sdp_mca_t *mca_p;
+ sdp_mca_t *cap_p;
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_attr_t *new_attr_p;
+ sdp_attr_t *prev_attr_p=NULL;
+ sdp_fmtp_t *fmtp_p;
+ sdp_comediadir_t *comediadir_p;
+
+ *inst_num = 0;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ if ((cap_num != 0) &&
+ ((attr_type == SDP_ATTR_X_CAP) || (attr_type == SDP_ATTR_X_CPAR) ||
+ (attr_type == SDP_ATTR_X_SQN) || (attr_type == SDP_ATTR_CDSC) ||
+ (attr_type == SDP_ATTR_CPAR) || (attr_type == SDP_ATTR_SQN))) {
+ if (sdp_p->debug_flag[SDP_DEBUG_WARNINGS]) {
+ CSFLogDebug(logTag, "%s Warning: Invalid attribute type for X-cpar/cdsc "
+ "parameter.", sdp_p->debug_str);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Some attributes are valid only under media level */
+ if (level == SDP_SESSION_LEVEL) {
+ switch (attr_type) {
+ case SDP_ATTR_RTCP:
+ case SDP_ATTR_LABEL:
+ return (SDP_INVALID_MEDIA_LEVEL);
+
+ default:
+ break;
+ }
+ }
+
+ new_attr_p = (sdp_attr_t *)SDP_MALLOC(sizeof(sdp_attr_t));
+ if (new_attr_p == NULL) {
+ sdp_p->conf_p->num_no_resource++;
+ return (SDP_NO_RESOURCE);
+ }
+
+ new_attr_p->type = attr_type;
+ new_attr_p->next_p = NULL;
+
+ /* Initialize the new attribute structure */
+ if ((new_attr_p->type == SDP_ATTR_X_CAP) ||
+ (new_attr_p->type == SDP_ATTR_CDSC)) {
+ new_attr_p->attr.cap_p = (sdp_mca_t *)SDP_MALLOC(sizeof(sdp_mca_t));
+ if (new_attr_p->attr.cap_p == NULL) {
+ sdp_free_attr(new_attr_p);
+ sdp_p->conf_p->num_no_resource++;
+ return (SDP_NO_RESOURCE);
+ }
+ } else if (new_attr_p->type == SDP_ATTR_FMTP) {
+ fmtp_p = &(new_attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_UNKNOWN_TYPE;
+ // set to invalid value
+ fmtp_p->packetization_mode = 0xff;
+ fmtp_p->level_asymmetry_allowed = SDP_INVALID_LEVEL_ASYMMETRY_ALLOWED_VALUE;
+ fmtp_p->annexb_required = FALSE;
+ fmtp_p->annexa_required = FALSE;
+ fmtp_p->maxval = 0;
+ fmtp_p->bitrate = 0;
+ fmtp_p->cif = 0;
+ fmtp_p->qcif = 0;
+ fmtp_p->profile = SDP_INVALID_VALUE;
+ fmtp_p->level = SDP_INVALID_VALUE;
+ fmtp_p->parameter_add = TRUE;
+ for (i=0; i < SDP_NE_NUM_BMAP_WORDS; i++) {
+ fmtp_p->bmap[i] = 0;
+ }
+ } else if ((new_attr_p->type == SDP_ATTR_RTPMAP) ||
+ (new_attr_p->type == SDP_ATTR_SPRTMAP)) {
+ new_attr_p->attr.transport_map.num_chan = 1;
+ } else if (new_attr_p->type == SDP_ATTR_DIRECTION) {
+ comediadir_p = &(new_attr_p->attr.comediadir);
+ comediadir_p->role = SDP_MEDIADIR_ROLE_PASSIVE;
+ comediadir_p->conn_info_present = FALSE;
+ } else if (new_attr_p->type == SDP_ATTR_MPTIME) {
+ sdp_mptime_t *mptime = &(new_attr_p->attr.mptime);
+ mptime->num_intervals = 0;
+ }
+
+ if (cap_num == 0) {
+ /* Add a new attribute. */
+ if (level == SDP_SESSION_LEVEL) {
+ if (sdp_p->sess_attrs_p == NULL) {
+ sdp_p->sess_attrs_p = new_attr_p;
+ } else {
+ for (attr_p = sdp_p->sess_attrs_p;
+ attr_p != NULL;
+ prev_attr_p = attr_p, attr_p = attr_p->next_p) {
+ /* Count the num instances of this type. */
+ if (attr_p->type == attr_type) {
+ (*inst_num)++;
+ }
+ }
+ prev_attr_p->next_p = new_attr_p;
+ }
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_free_attr(new_attr_p);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ if (mca_p->media_attrs_p == NULL) {
+ mca_p->media_attrs_p = new_attr_p;
+ } else {
+ for (attr_p = mca_p->media_attrs_p;
+ attr_p != NULL;
+ prev_attr_p = attr_p, attr_p = attr_p->next_p) {
+ /* Count the num instances of this type. */
+ if (attr_p->type == attr_type) {
+ (*inst_num)++;
+ }
+ }
+ prev_attr_p->next_p = new_attr_p;
+ }
+ }
+ } else {
+ /* Add a new capability attribute - find the capability attr. */
+ attr_p = sdp_find_capability(sdp_p, level, cap_num);
+ if (attr_p == NULL) {
+ sdp_free_attr(new_attr_p);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ cap_p = attr_p->attr.cap_p;
+ if (cap_p->media_attrs_p == NULL) {
+ cap_p->media_attrs_p = new_attr_p;
+ } else {
+ for (attr_p = cap_p->media_attrs_p;
+ attr_p != NULL;
+ prev_attr_p = attr_p, attr_p = attr_p->next_p) {
+ /* Count the num instances of this type. */
+ if (attr_p->type == attr_type) {
+ (*inst_num)++;
+ }
+ }
+ prev_attr_p->next_p = new_attr_p;
+ }
+ }
+
+ /* Increment the instance num for the attr just added. */
+ (*inst_num)++;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_copy_attr_fields
+ * Description: Copy the fields of an attribute based on attr type.
+ * This is an INTERNAL SDP routine only. It will not copy
+ * X-Cap, X-Cpar, CDSC, or CPAR attrs.
+ * Parameters: src_attr_p Ptr to the source attribute.
+ * dst_attr_p Ptr to the dst attribute.
+ * Returns: Nothing.
+ */
+void sdp_copy_attr_fields (sdp_attr_t *src_attr_p, sdp_attr_t *dst_attr_p)
+{
+ u16 i;
+
+ /* Copy over all the attribute information. */
+ dst_attr_p->type = src_attr_p->type;
+ dst_attr_p->next_p = NULL;
+
+ switch (src_attr_p->type) {
+
+ case SDP_ATTR_BEARER:
+ case SDP_ATTR_CALLED:
+ case SDP_ATTR_CONN_TYPE:
+ case SDP_ATTR_DIALED:
+ case SDP_ATTR_DIALING:
+ case SDP_ATTR_FRAMING:
+ case SDP_ATTR_MAXPRATE:
+ case SDP_ATTR_LABEL:
+ sstrncpy(dst_attr_p->attr.string_val, src_attr_p->attr.string_val,
+ SDP_MAX_STRING_LEN+1);
+ break;
+
+ case SDP_ATTR_EECID:
+ case SDP_ATTR_PTIME:
+ case SDP_ATTR_T38_VERSION:
+ case SDP_ATTR_T38_MAXBITRATE:
+ case SDP_ATTR_T38_MAXBUFFER:
+ case SDP_ATTR_T38_MAXDGRAM:
+ case SDP_ATTR_X_SQN:
+ case SDP_ATTR_TC1_PAYLOAD_BYTES:
+ case SDP_ATTR_TC1_WINDOW_SIZE:
+ case SDP_ATTR_TC2_PAYLOAD_BYTES:
+ case SDP_ATTR_TC2_WINDOW_SIZE:
+ case SDP_ATTR_RTCP:
+ case SDP_ATTR_MID:
+ case SDP_ATTR_RTCP_UNICAST:
+ dst_attr_p->attr.u32_val = src_attr_p->attr.u32_val;
+ break;
+
+ case SDP_ATTR_T38_FILLBITREMOVAL:
+ case SDP_ATTR_T38_TRANSCODINGMMR:
+ case SDP_ATTR_T38_TRANSCODINGJBIG:
+ case SDP_ATTR_TMRGWXID:
+ dst_attr_p->attr.boolean_val = src_attr_p->attr.boolean_val;
+ break;
+
+ case SDP_ATTR_QOS:
+ case SDP_ATTR_SECURE:
+ case SDP_ATTR_X_PC_QOS:
+ case SDP_ATTR_X_QOS:
+ dst_attr_p->attr.qos.strength = src_attr_p->attr.qos.strength;
+ dst_attr_p->attr.qos.direction = src_attr_p->attr.qos.direction;
+ dst_attr_p->attr.qos.confirm = src_attr_p->attr.qos.confirm;
+ break;
+
+ case SDP_ATTR_CURR:
+ dst_attr_p->attr.curr.type = src_attr_p->attr.curr.type;
+ dst_attr_p->attr.curr.direction = src_attr_p->attr.curr.direction;
+ dst_attr_p->attr.curr.status_type = src_attr_p->attr.curr.status_type;
+ break;
+ case SDP_ATTR_DES:
+ dst_attr_p->attr.des.type = src_attr_p->attr.des.type;
+ dst_attr_p->attr.des.direction = src_attr_p->attr.des.direction;
+ dst_attr_p->attr.des.status_type = src_attr_p->attr.des.status_type;
+ dst_attr_p->attr.des.strength = src_attr_p->attr.des.strength;
+ break;
+
+
+ case SDP_ATTR_CONF:
+ dst_attr_p->attr.conf.type = src_attr_p->attr.conf.type;
+ dst_attr_p->attr.conf.direction = src_attr_p->attr.conf.direction;
+ dst_attr_p->attr.conf.status_type = src_attr_p->attr.conf.status_type;
+ break;
+
+ case SDP_ATTR_INACTIVE:
+ case SDP_ATTR_RECVONLY:
+ case SDP_ATTR_SENDONLY:
+ case SDP_ATTR_SENDRECV:
+ /* These attrs have no parameters. */
+ break;
+
+ case SDP_ATTR_FMTP:
+ dst_attr_p->attr.fmtp.payload_num = src_attr_p->attr.fmtp.payload_num;
+ dst_attr_p->attr.fmtp.maxval = src_attr_p->attr.fmtp.maxval;
+ dst_attr_p->attr.fmtp.bitrate = src_attr_p->attr.fmtp.bitrate;
+ dst_attr_p->attr.fmtp.annexa = src_attr_p->attr.fmtp.annexa;
+ dst_attr_p->attr.fmtp.annexb = src_attr_p->attr.fmtp.annexb;
+ dst_attr_p->attr.fmtp.qcif = src_attr_p->attr.fmtp.qcif;
+ dst_attr_p->attr.fmtp.cif = src_attr_p->attr.fmtp.cif;
+ dst_attr_p->attr.fmtp.sqcif = src_attr_p->attr.fmtp.sqcif;
+ dst_attr_p->attr.fmtp.cif4 = src_attr_p->attr.fmtp.cif4;
+ dst_attr_p->attr.fmtp.cif16 = src_attr_p->attr.fmtp.cif16;
+ dst_attr_p->attr.fmtp.maxbr = src_attr_p->attr.fmtp.maxbr;
+ dst_attr_p->attr.fmtp.custom_x = src_attr_p->attr.fmtp.custom_x;
+ dst_attr_p->attr.fmtp.custom_y = src_attr_p->attr.fmtp.custom_y;
+ dst_attr_p->attr.fmtp.custom_mpi = src_attr_p->attr.fmtp.custom_mpi;
+ dst_attr_p->attr.fmtp.par_width = src_attr_p->attr.fmtp.par_width;
+ dst_attr_p->attr.fmtp.par_height = src_attr_p->attr.fmtp.par_height;
+ dst_attr_p->attr.fmtp.cpcf = src_attr_p->attr.fmtp.cpcf;
+ dst_attr_p->attr.fmtp.bpp = src_attr_p->attr.fmtp.bpp;
+ dst_attr_p->attr.fmtp.hrd = src_attr_p->attr.fmtp.hrd;
+
+ dst_attr_p->attr.fmtp.profile = src_attr_p->attr.fmtp.profile;
+ dst_attr_p->attr.fmtp.level = src_attr_p->attr.fmtp.level;
+ dst_attr_p->attr.fmtp.is_interlace = src_attr_p->attr.fmtp.is_interlace;
+
+ sstrncpy(dst_attr_p->attr.fmtp.profile_level_id,
+ src_attr_p->attr.fmtp.profile_level_id,
+ SDP_MAX_STRING_LEN+1);
+ sstrncpy(dst_attr_p->attr.fmtp.parameter_sets,
+ src_attr_p->attr.fmtp.parameter_sets,
+ SDP_MAX_STRING_LEN+1);
+ dst_attr_p->attr.fmtp.deint_buf_req =
+ src_attr_p->attr.fmtp.deint_buf_req;
+ dst_attr_p->attr.fmtp.max_don_diff =
+ src_attr_p->attr.fmtp.max_don_diff;
+ dst_attr_p->attr.fmtp.init_buf_time =
+ src_attr_p->attr.fmtp.init_buf_time;
+ dst_attr_p->attr.fmtp.packetization_mode =
+ src_attr_p->attr.fmtp.packetization_mode;
+ dst_attr_p->attr.fmtp.flag =
+ src_attr_p->attr.fmtp.flag;
+
+ dst_attr_p->attr.fmtp.max_mbps = src_attr_p->attr.fmtp.max_mbps;
+ dst_attr_p->attr.fmtp.max_fs = src_attr_p->attr.fmtp.max_fs;
+ dst_attr_p->attr.fmtp.max_cpb = src_attr_p->attr.fmtp.max_cpb;
+ dst_attr_p->attr.fmtp.max_dpb = src_attr_p->attr.fmtp.max_dpb;
+ dst_attr_p->attr.fmtp.max_br = src_attr_p->attr.fmtp.max_br;
+ dst_attr_p->attr.fmtp.redundant_pic_cap =
+ src_attr_p->attr.fmtp.redundant_pic_cap;
+ dst_attr_p->attr.fmtp.deint_buf_cap =
+ src_attr_p->attr.fmtp.deint_buf_cap;
+ dst_attr_p->attr.fmtp.max_rcmd_nalu_size =
+ src_attr_p->attr.fmtp.max_rcmd_nalu_size;
+ dst_attr_p->attr.fmtp.interleaving_depth =
+ src_attr_p->attr.fmtp.interleaving_depth;
+ dst_attr_p->attr.fmtp.parameter_add =
+ src_attr_p->attr.fmtp.parameter_add;
+
+ dst_attr_p->attr.fmtp.annex_d = src_attr_p->attr.fmtp.annex_d;
+ dst_attr_p->attr.fmtp.annex_f = src_attr_p->attr.fmtp.annex_f;
+ dst_attr_p->attr.fmtp.annex_i = src_attr_p->attr.fmtp.annex_i;
+ dst_attr_p->attr.fmtp.annex_j = src_attr_p->attr.fmtp.annex_j;
+ dst_attr_p->attr.fmtp.annex_t = src_attr_p->attr.fmtp.annex_t;
+ dst_attr_p->attr.fmtp.annex_k_val = src_attr_p->attr.fmtp.annex_k_val;
+ dst_attr_p->attr.fmtp.annex_n_val = src_attr_p->attr.fmtp.annex_n_val;
+ dst_attr_p->attr.fmtp.annex_p_val_picture_resize =
+ src_attr_p->attr.fmtp.annex_p_val_picture_resize;
+ dst_attr_p->attr.fmtp.annex_p_val_warp =
+ src_attr_p->attr.fmtp.annex_p_val_warp;
+
+ dst_attr_p->attr.fmtp.annexb_required =
+ src_attr_p->attr.fmtp.annexb_required;
+ dst_attr_p->attr.fmtp.annexa_required =
+ src_attr_p->attr.fmtp.annexa_required;
+ dst_attr_p->attr.fmtp.fmtp_format
+ = src_attr_p->attr.fmtp.fmtp_format;
+
+ for (i=0; i < SDP_NE_NUM_BMAP_WORDS; i++) {
+ dst_attr_p->attr.fmtp.bmap[i] = src_attr_p->attr.fmtp.bmap[i];
+ }
+ break;
+
+ case SDP_ATTR_RTPMAP:
+ dst_attr_p->attr.transport_map.payload_num =
+ src_attr_p->attr.transport_map.payload_num;
+ dst_attr_p->attr.transport_map.clockrate =
+ src_attr_p->attr.transport_map.clockrate;
+ dst_attr_p->attr.transport_map.num_chan =
+ src_attr_p->attr.transport_map.num_chan;
+ sstrncpy(dst_attr_p->attr.transport_map.encname,
+ src_attr_p->attr.transport_map.encname,
+ SDP_MAX_STRING_LEN+1);
+ break;
+
+ case SDP_ATTR_SUBNET:
+ dst_attr_p->attr.subnet.nettype = src_attr_p->attr.subnet.nettype;
+ dst_attr_p->attr.subnet.addrtype = src_attr_p->attr.subnet.addrtype;
+ dst_attr_p->attr.subnet.prefix = src_attr_p->attr.subnet.prefix;
+ sstrncpy(dst_attr_p->attr.subnet.addr, src_attr_p->attr.subnet.addr,
+ SDP_MAX_STRING_LEN+1);
+ break;
+
+ case SDP_ATTR_T38_RATEMGMT:
+ dst_attr_p->attr.t38ratemgmt = src_attr_p->attr.t38ratemgmt;
+ break;
+
+ case SDP_ATTR_T38_UDPEC:
+ dst_attr_p->attr.t38udpec = src_attr_p->attr.t38udpec;
+ break;
+
+ case SDP_ATTR_X_PC_CODEC:
+ dst_attr_p->attr.pccodec.num_payloads =
+ src_attr_p->attr.pccodec.num_payloads;
+ for (i=0; i < src_attr_p->attr.pccodec.num_payloads; i++) {
+ dst_attr_p->attr.pccodec.payload_type[i] =
+ src_attr_p->attr.pccodec.payload_type[i];
+ }
+ break;
+
+ case SDP_ATTR_DIRECTION:
+
+ dst_attr_p->attr.comediadir.role =
+ src_attr_p->attr.comediadir.role;
+
+ if (src_attr_p->attr.comediadir.conn_info.nettype) {
+ dst_attr_p->attr.comediadir.conn_info_present = TRUE;
+ dst_attr_p->attr.comediadir.conn_info.nettype =
+ src_attr_p->attr.comediadir.conn_info.nettype;
+ dst_attr_p->attr.comediadir.conn_info.addrtype =
+ src_attr_p->attr.comediadir.conn_info.addrtype;
+ sstrncpy(dst_attr_p->attr.comediadir.conn_info.conn_addr,
+ src_attr_p->attr.comediadir.conn_info.conn_addr,
+ SDP_MAX_STRING_LEN+1);
+ dst_attr_p->attr.comediadir.src_port =
+ src_attr_p->attr.comediadir.src_port;
+ }
+ break;
+
+ case SDP_ATTR_SILENCESUPP:
+ dst_attr_p->attr.silencesupp.enabled =
+ src_attr_p->attr.silencesupp.enabled;
+ dst_attr_p->attr.silencesupp.timer_null =
+ src_attr_p->attr.silencesupp.timer_null;
+ dst_attr_p->attr.silencesupp.timer =
+ src_attr_p->attr.silencesupp.timer;
+ dst_attr_p->attr.silencesupp.pref =
+ src_attr_p->attr.silencesupp.pref;
+ dst_attr_p->attr.silencesupp.siduse =
+ src_attr_p->attr.silencesupp.siduse;
+ dst_attr_p->attr.silencesupp.fxnslevel_null =
+ src_attr_p->attr.silencesupp.fxnslevel_null;
+ dst_attr_p->attr.silencesupp.fxnslevel =
+ src_attr_p->attr.silencesupp.fxnslevel;
+ break;
+
+ case SDP_ATTR_RTR:
+ dst_attr_p->attr.rtr.confirm = src_attr_p->attr.rtr.confirm;
+ break;
+
+ case SDP_ATTR_X_SIDIN:
+ case SDP_ATTR_X_SIDOUT:
+ case SDP_ATTR_X_CONFID:
+ sstrncpy(dst_attr_p->attr.stream_data.x_sidin,
+ src_attr_p->attr.stream_data.x_sidin,SDP_MAX_STRING_LEN+1);
+ sstrncpy(dst_attr_p->attr.stream_data.x_sidout,
+ src_attr_p->attr.stream_data.x_sidout,SDP_MAX_STRING_LEN+1);
+ sstrncpy(dst_attr_p->attr.stream_data.x_confid,
+ src_attr_p->attr.stream_data.x_confid,SDP_MAX_STRING_LEN+1);
+ break;
+
+ case SDP_ATTR_GROUP:
+ dst_attr_p->attr.stream_data.group_attr =
+ src_attr_p->attr.stream_data.group_attr;
+ dst_attr_p->attr.stream_data.num_group_id =
+ src_attr_p->attr.stream_data.num_group_id;
+
+ for (i=0; i < src_attr_p->attr.stream_data.num_group_id; i++) {
+ dst_attr_p->attr.stream_data.group_id_arr[i] =
+ src_attr_p->attr.stream_data.group_id_arr[i];
+ }
+ break;
+
+ case SDP_ATTR_SOURCE_FILTER:
+ dst_attr_p->attr.source_filter.mode =
+ src_attr_p->attr.source_filter.mode;
+ dst_attr_p->attr.source_filter.nettype =
+ src_attr_p->attr.source_filter.nettype;
+ dst_attr_p->attr.source_filter.addrtype =
+ src_attr_p->attr.source_filter.addrtype;
+ sstrncpy(dst_attr_p->attr.source_filter.dest_addr,
+ src_attr_p->attr.source_filter.dest_addr,
+ SDP_MAX_STRING_LEN+1);
+ for (i=0; iattr.source_filter.num_src_addr; ++i) {
+ sstrncpy(dst_attr_p->attr.source_filter.src_list[i],
+ src_attr_p->attr.source_filter.src_list[i],
+ SDP_MAX_STRING_LEN+1);
+ }
+ dst_attr_p->attr.source_filter.num_src_addr =
+ src_attr_p->attr.source_filter.num_src_addr;
+ break;
+
+ case SDP_ATTR_SRTP_CONTEXT:
+ case SDP_ATTR_SDESCRIPTIONS:
+ /* Tag parameter is not valid for version 2 sdescriptions */
+ if (src_attr_p->type == SDP_ATTR_SDESCRIPTIONS) {
+ dst_attr_p->attr.srtp_context.tag =
+ src_attr_p->attr.srtp_context.tag;
+ }
+
+ dst_attr_p->attr.srtp_context.selection_flags =
+ src_attr_p->attr.srtp_context.selection_flags;
+
+ dst_attr_p->attr.srtp_context.suite = src_attr_p->attr.srtp_context.suite;
+
+ dst_attr_p->attr.srtp_context.master_key_size_bytes =
+ src_attr_p->attr.srtp_context.master_key_size_bytes;
+
+ dst_attr_p->attr.srtp_context.master_salt_size_bytes =
+ src_attr_p->attr.srtp_context.master_salt_size_bytes;
+
+ bcopy(src_attr_p->attr.srtp_context.master_key,
+ dst_attr_p->attr.srtp_context.master_key,
+ SDP_SRTP_MAX_KEY_SIZE_BYTES);
+
+ bcopy(src_attr_p->attr.srtp_context.master_salt,
+ dst_attr_p->attr.srtp_context.master_salt,
+ SDP_SRTP_MAX_SALT_SIZE_BYTES);
+
+
+ sstrncpy((char*)dst_attr_p->attr.srtp_context.master_key_lifetime,
+ (char*)src_attr_p->attr.srtp_context.master_key_lifetime,
+ SDP_SRTP_MAX_LIFETIME_BYTES);
+
+ sstrncpy((char*)dst_attr_p->attr.srtp_context.mki,
+ (char*)src_attr_p->attr.srtp_context.mki,
+ SDP_SRTP_MAX_MKI_SIZE_BYTES);
+
+ dst_attr_p->attr.srtp_context.mki_size_bytes =
+ src_attr_p->attr.srtp_context.mki_size_bytes;
+
+ if (src_attr_p->attr.srtp_context.session_parameters) {
+ dst_attr_p->attr.srtp_context.session_parameters =
+ cpr_strdup(src_attr_p->attr.srtp_context.session_parameters);
+ }
+
+ break;
+
+ default:
+ break;
+ }
+
+ return;
+}
+
+/* Function: sdp_copy_attr
+ * Description: Copy an attribute from one SDP/level to another. A new
+ * attribute is automatically added to the end of the attr
+ * list at the dst SDP/level and all parameter values are
+ * copied.
+ * Description: Add a new attribute of the specified type at the given
+ * level and capability level or base attribute if cap_num
+ * is zero.
+ * Parameters: src_sdp_ptr The source SDP handle.
+ * dst_sdp_ptr The dest SDP handle.
+ * src_level The level of the source attribute.
+ * dst_level The level of the source attribute.
+ * src_cap_num The src capability number associated with the
+ * attribute if any.
+ * dst_cap_num The dst capability number associated with the
+ * attribute if any. Note that src and dst
+ * cap_num must both be zero or both be non-zero.
+ * src_attr_type The type of source attribute. This cannot
+ * be SDP_ATTR_X_CAP or SDP_ATTR_X_CPAR.
+ * src_inst_num The instance number of the source attr.
+ * Returns: SDP_SUCCESS Attribute was successfully copied.
+ */
+sdp_result_e sdp_copy_attr (void *src_sdp_ptr, void *dst_sdp_ptr,
+ u16 src_level, u16 dst_level,
+ u8 src_cap_num, u8 dst_cap_num,
+ sdp_attr_e src_attr_type, u16 src_inst_num)
+{
+ u16 i;
+ sdp_mca_t *mca_p;
+ sdp_mca_t *cap_p;
+ sdp_t *src_sdp_p = (sdp_t *)src_sdp_ptr;
+ sdp_t *dst_sdp_p = (sdp_t *)dst_sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_attr_t *new_attr_p;
+ sdp_attr_t *prev_attr_p;
+ sdp_attr_t *src_attr_p;
+
+ if (sdp_verify_sdp_ptr(src_sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ /* Make sure if one is a capability attribute, then both are. */
+ if (((src_cap_num == 0) && (dst_cap_num != 0)) ||
+ ((src_cap_num != 0) && (dst_cap_num == 0))) {
+ src_sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Cannot copy X_CAP/CDSC attributes directly using this routine.
+ * You also can't copy X_CPAR/CPAR attributes by specifying them directly,
+ * but you can copy them by giving the corresponding cap_num. */
+ if ((src_attr_type == SDP_ATTR_X_CAP) ||
+ (src_attr_type == SDP_ATTR_X_CPAR) ||
+ (src_attr_type == SDP_ATTR_CDSC) ||
+ (src_attr_type == SDP_ATTR_CPAR)) {
+ src_sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ src_attr_p = sdp_find_attr(src_sdp_p, src_level, src_cap_num,
+ src_attr_type, src_inst_num);
+ if (src_attr_p == NULL) {
+ if (src_sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Error: Source attribute for copy not found.",
+ src_sdp_p->debug_str);
+ }
+ src_sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ new_attr_p = (sdp_attr_t *)SDP_MALLOC(sizeof(sdp_attr_t));
+ if (new_attr_p == NULL) {
+ src_sdp_p->conf_p->num_no_resource++;
+ return (SDP_NO_RESOURCE);
+ }
+
+ /* Copy over all the attribute information. */
+ new_attr_p->type = src_attr_type;
+ new_attr_p->next_p = NULL;
+
+ switch (src_attr_type) {
+
+ case SDP_ATTR_BEARER:
+ case SDP_ATTR_CALLED:
+ case SDP_ATTR_CONN_TYPE:
+ case SDP_ATTR_DIALED:
+ case SDP_ATTR_DIALING:
+ case SDP_ATTR_FRAMING:
+ case SDP_ATTR_MAXPRATE:
+ case SDP_ATTR_LABEL:
+ sstrncpy(new_attr_p->attr.string_val, src_attr_p->attr.string_val,
+ SDP_MAX_STRING_LEN+1);
+ break;
+
+ case SDP_ATTR_EECID:
+ case SDP_ATTR_PTIME:
+ case SDP_ATTR_T38_VERSION:
+ case SDP_ATTR_T38_MAXBITRATE:
+ case SDP_ATTR_T38_MAXBUFFER:
+ case SDP_ATTR_T38_MAXDGRAM:
+ case SDP_ATTR_X_SQN:
+ case SDP_ATTR_TC1_PAYLOAD_BYTES:
+ case SDP_ATTR_TC1_WINDOW_SIZE:
+ case SDP_ATTR_TC2_PAYLOAD_BYTES:
+ case SDP_ATTR_TC2_WINDOW_SIZE:
+ case SDP_ATTR_RTCP:
+ case SDP_ATTR_MID:
+ case SDP_ATTR_RTCP_UNICAST:
+ new_attr_p->attr.u32_val = src_attr_p->attr.u32_val;
+ break;
+
+ case SDP_ATTR_T38_FILLBITREMOVAL:
+ case SDP_ATTR_T38_TRANSCODINGMMR:
+ case SDP_ATTR_T38_TRANSCODINGJBIG:
+ case SDP_ATTR_TMRGWXID:
+ new_attr_p->attr.boolean_val = src_attr_p->attr.boolean_val;
+ break;
+
+ case SDP_ATTR_QOS:
+ case SDP_ATTR_SECURE:
+ case SDP_ATTR_X_PC_QOS:
+ case SDP_ATTR_X_QOS:
+ new_attr_p->attr.qos.strength = src_attr_p->attr.qos.strength;
+ new_attr_p->attr.qos.direction = src_attr_p->attr.qos.direction;
+ new_attr_p->attr.qos.confirm = src_attr_p->attr.qos.confirm;
+ break;
+
+ case SDP_ATTR_CURR:
+ new_attr_p->attr.curr.type = src_attr_p->attr.curr.type;
+ new_attr_p->attr.curr.direction = src_attr_p->attr.curr.direction;
+ new_attr_p->attr.curr.status_type = src_attr_p->attr.curr.status_type;
+ break;
+ case SDP_ATTR_DES:
+ new_attr_p->attr.des.type = src_attr_p->attr.des.type;
+ new_attr_p->attr.des.direction = src_attr_p->attr.des.direction;
+ new_attr_p->attr.des.status_type = src_attr_p->attr.des.status_type;
+ new_attr_p->attr.des.strength = src_attr_p->attr.des.strength;
+ break;
+
+ case SDP_ATTR_CONF:
+ new_attr_p->attr.conf.type = src_attr_p->attr.conf.type;
+ new_attr_p->attr.conf.direction = src_attr_p->attr.conf.direction;
+ new_attr_p->attr.conf.status_type = src_attr_p->attr.conf.status_type;
+ break;
+
+ case SDP_ATTR_INACTIVE:
+ case SDP_ATTR_RECVONLY:
+ case SDP_ATTR_SENDONLY:
+ case SDP_ATTR_SENDRECV:
+ /* These attrs have no parameters. */
+ break;
+
+ case SDP_ATTR_FMTP:
+ new_attr_p->attr.fmtp.payload_num = src_attr_p->attr.fmtp.payload_num;
+ new_attr_p->attr.fmtp.maxval = src_attr_p->attr.fmtp.maxval;
+ new_attr_p->attr.fmtp.bitrate = src_attr_p->attr.fmtp.bitrate;
+ new_attr_p->attr.fmtp.annexa = src_attr_p->attr.fmtp.annexa;
+ new_attr_p->attr.fmtp.annexb = src_attr_p->attr.fmtp.annexb;
+ new_attr_p->attr.fmtp.cif = src_attr_p->attr.fmtp.cif;
+ new_attr_p->attr.fmtp.qcif = src_attr_p->attr.fmtp.qcif;
+ new_attr_p->attr.fmtp.sqcif = src_attr_p->attr.fmtp.qcif;
+ new_attr_p->attr.fmtp.cif4 = src_attr_p->attr.fmtp.cif4;
+ new_attr_p->attr.fmtp.cif16 = src_attr_p->attr.fmtp.cif16;
+ new_attr_p->attr.fmtp.maxbr = src_attr_p->attr.fmtp.maxbr;
+ new_attr_p->attr.fmtp.custom_x = src_attr_p->attr.fmtp.custom_x;
+ new_attr_p->attr.fmtp.custom_y = src_attr_p->attr.fmtp.custom_y;
+ new_attr_p->attr.fmtp.custom_mpi = src_attr_p->attr.fmtp.custom_mpi;
+ new_attr_p->attr.fmtp.par_width = src_attr_p->attr.fmtp.par_width;
+ new_attr_p->attr.fmtp.par_height = src_attr_p->attr.fmtp.par_height;
+ new_attr_p->attr.fmtp.cpcf = src_attr_p->attr.fmtp.cpcf;
+ new_attr_p->attr.fmtp.bpp = src_attr_p->attr.fmtp.bpp;
+ new_attr_p->attr.fmtp.hrd = src_attr_p->attr.fmtp.hrd;
+ new_attr_p->attr.fmtp.profile = src_attr_p->attr.fmtp.profile;
+ new_attr_p->attr.fmtp.level = src_attr_p->attr.fmtp.level;
+ new_attr_p->attr.fmtp.is_interlace = src_attr_p->attr.fmtp.is_interlace;
+
+ sstrncpy(new_attr_p->attr.fmtp.profile_level_id,
+ src_attr_p->attr.fmtp.profile_level_id,
+ SDP_MAX_STRING_LEN+1);
+ sstrncpy(new_attr_p->attr.fmtp.parameter_sets,
+ src_attr_p->attr.fmtp.parameter_sets,
+ SDP_MAX_STRING_LEN+1);
+ new_attr_p->attr.fmtp.deint_buf_req =
+ src_attr_p->attr.fmtp.deint_buf_req;
+ new_attr_p->attr.fmtp.max_don_diff =
+ src_attr_p->attr.fmtp.max_don_diff;
+ new_attr_p->attr.fmtp.init_buf_time =
+ src_attr_p->attr.fmtp.init_buf_time;
+ new_attr_p->attr.fmtp.packetization_mode =
+ src_attr_p->attr.fmtp.packetization_mode;
+ new_attr_p->attr.fmtp.flag =
+ src_attr_p->attr.fmtp.flag;
+
+ new_attr_p->attr.fmtp.max_mbps = src_attr_p->attr.fmtp.max_mbps;
+ new_attr_p->attr.fmtp.max_fs = src_attr_p->attr.fmtp.max_fs;
+ new_attr_p->attr.fmtp.max_cpb = src_attr_p->attr.fmtp.max_cpb;
+ new_attr_p->attr.fmtp.max_dpb = src_attr_p->attr.fmtp.max_dpb;
+ new_attr_p->attr.fmtp.max_br = src_attr_p->attr.fmtp.max_br;
+ new_attr_p->attr.fmtp.redundant_pic_cap =
+ src_attr_p->attr.fmtp.redundant_pic_cap;
+ new_attr_p->attr.fmtp.deint_buf_cap =
+ src_attr_p->attr.fmtp.deint_buf_cap;
+ new_attr_p->attr.fmtp.max_rcmd_nalu_size =
+ src_attr_p->attr.fmtp.max_rcmd_nalu_size;
+ new_attr_p->attr.fmtp.interleaving_depth =
+ src_attr_p->attr.fmtp.interleaving_depth;
+ new_attr_p->attr.fmtp.parameter_add =
+ src_attr_p->attr.fmtp.parameter_add;
+
+ new_attr_p->attr.fmtp.annex_d = src_attr_p->attr.fmtp.annex_d;
+ new_attr_p->attr.fmtp.annex_f = src_attr_p->attr.fmtp.annex_f;
+ new_attr_p->attr.fmtp.annex_i = src_attr_p->attr.fmtp.annex_i;
+ new_attr_p->attr.fmtp.annex_j = src_attr_p->attr.fmtp.annex_j;
+ new_attr_p->attr.fmtp.annex_t = src_attr_p->attr.fmtp.annex_t;
+ new_attr_p->attr.fmtp.annex_k_val = src_attr_p->attr.fmtp.annex_k_val;
+ new_attr_p->attr.fmtp.annex_n_val = src_attr_p->attr.fmtp.annex_n_val;
+ new_attr_p->attr.fmtp.annex_p_val_picture_resize =
+ src_attr_p->attr.fmtp.annex_p_val_picture_resize;
+ new_attr_p->attr.fmtp.annex_p_val_warp =
+ src_attr_p->attr.fmtp.annex_p_val_warp;
+
+ new_attr_p->attr.fmtp.annexb_required =
+ src_attr_p->attr.fmtp.annexb_required;
+ new_attr_p->attr.fmtp.annexa_required =
+ src_attr_p->attr.fmtp.annexa_required;
+ new_attr_p->attr.fmtp.fmtp_format
+ = src_attr_p->attr.fmtp.fmtp_format;
+
+ for (i=0; i < SDP_NE_NUM_BMAP_WORDS; i++) {
+ new_attr_p->attr.fmtp.bmap[i] = src_attr_p->attr.fmtp.bmap[i];
+ }
+ break;
+
+ case SDP_ATTR_RTPMAP:
+ new_attr_p->attr.transport_map.payload_num =
+ src_attr_p->attr.transport_map.payload_num;
+ new_attr_p->attr.transport_map.clockrate =
+ src_attr_p->attr.transport_map.clockrate;
+ new_attr_p->attr.transport_map.num_chan =
+ src_attr_p->attr.transport_map.num_chan;
+ sstrncpy(new_attr_p->attr.transport_map.encname,
+ src_attr_p->attr.transport_map.encname,
+ SDP_MAX_STRING_LEN+1);
+ break;
+
+ case SDP_ATTR_SUBNET:
+ new_attr_p->attr.subnet.nettype = src_attr_p->attr.subnet.nettype;
+ new_attr_p->attr.subnet.addrtype = src_attr_p->attr.subnet.addrtype;
+ new_attr_p->attr.subnet.prefix = src_attr_p->attr.subnet.prefix;
+ sstrncpy(new_attr_p->attr.subnet.addr, src_attr_p->attr.subnet.addr,
+ SDP_MAX_STRING_LEN+1);
+ break;
+
+ case SDP_ATTR_T38_RATEMGMT:
+ new_attr_p->attr.t38ratemgmt = src_attr_p->attr.t38ratemgmt;
+ break;
+
+ case SDP_ATTR_T38_UDPEC:
+ new_attr_p->attr.t38udpec = src_attr_p->attr.t38udpec;
+ break;
+
+ case SDP_ATTR_X_PC_CODEC:
+ new_attr_p->attr.pccodec.num_payloads =
+ src_attr_p->attr.pccodec.num_payloads;
+ for (i=0; i < src_attr_p->attr.pccodec.num_payloads; i++) {
+ new_attr_p->attr.pccodec.payload_type[i] =
+ src_attr_p->attr.pccodec.payload_type[i];
+ }
+ break;
+
+ case SDP_ATTR_DIRECTION:
+
+ new_attr_p->attr.comediadir.role =
+ src_attr_p->attr.comediadir.role;
+
+ if (src_attr_p->attr.comediadir.conn_info.nettype) {
+ new_attr_p->attr.comediadir.conn_info_present = TRUE;
+ new_attr_p->attr.comediadir.conn_info.nettype =
+ src_attr_p->attr.comediadir.conn_info.nettype;
+ new_attr_p->attr.comediadir.conn_info.addrtype =
+ src_attr_p->attr.comediadir.conn_info.addrtype;
+ sstrncpy(new_attr_p->attr.comediadir.conn_info.conn_addr,
+ src_attr_p->attr.comediadir.conn_info.conn_addr,
+ SDP_MAX_STRING_LEN+1);
+ new_attr_p->attr.comediadir.src_port =
+ src_attr_p->attr.comediadir.src_port;
+ }
+ break;
+
+
+ case SDP_ATTR_SILENCESUPP:
+ new_attr_p->attr.silencesupp.enabled =
+ src_attr_p->attr.silencesupp.enabled;
+ new_attr_p->attr.silencesupp.timer_null =
+ src_attr_p->attr.silencesupp.timer_null;
+ new_attr_p->attr.silencesupp.timer =
+ src_attr_p->attr.silencesupp.timer;
+ new_attr_p->attr.silencesupp.pref =
+ src_attr_p->attr.silencesupp.pref;
+ new_attr_p->attr.silencesupp.siduse =
+ src_attr_p->attr.silencesupp.siduse;
+ new_attr_p->attr.silencesupp.fxnslevel_null =
+ src_attr_p->attr.silencesupp.fxnslevel_null;
+ new_attr_p->attr.silencesupp.fxnslevel =
+ src_attr_p->attr.silencesupp.fxnslevel;
+ break;
+
+ case SDP_ATTR_MPTIME:
+ new_attr_p->attr.mptime.num_intervals =
+ src_attr_p->attr.mptime.num_intervals;
+ for (i=0; i < src_attr_p->attr.mptime.num_intervals; i++) {
+ new_attr_p->attr.mptime.intervals[i] =
+ src_attr_p->attr.mptime.intervals[i];
+ }
+ break;
+
+ case SDP_ATTR_X_SIDIN:
+ case SDP_ATTR_X_SIDOUT:
+ case SDP_ATTR_X_CONFID:
+ sstrncpy(new_attr_p->attr.stream_data.x_sidin,
+ src_attr_p->attr.stream_data.x_sidin,SDP_MAX_STRING_LEN+1);
+ sstrncpy(new_attr_p->attr.stream_data.x_sidout,
+ src_attr_p->attr.stream_data.x_sidout,SDP_MAX_STRING_LEN+1);
+ sstrncpy(new_attr_p->attr.stream_data.x_confid,
+ src_attr_p->attr.stream_data.x_confid,SDP_MAX_STRING_LEN+1);
+ break;
+
+ case SDP_ATTR_GROUP:
+ new_attr_p->attr.stream_data.group_attr =
+ src_attr_p->attr.stream_data.group_attr;
+ new_attr_p->attr.stream_data.num_group_id =
+ src_attr_p->attr.stream_data.num_group_id;
+
+ for (i=0; i < src_attr_p->attr.stream_data.num_group_id; i++) {
+ new_attr_p->attr.stream_data.group_id_arr[i] =
+ src_attr_p->attr.stream_data.group_id_arr[i];
+ }
+ break;
+
+ case SDP_ATTR_SOURCE_FILTER:
+ new_attr_p->attr.source_filter.mode =
+ src_attr_p->attr.source_filter.mode;
+ new_attr_p->attr.source_filter.nettype =
+ src_attr_p->attr.source_filter.nettype;
+ new_attr_p->attr.source_filter.addrtype =
+ src_attr_p->attr.source_filter.addrtype;
+ sstrncpy(new_attr_p->attr.source_filter.dest_addr,
+ src_attr_p->attr.source_filter.dest_addr,
+ SDP_MAX_STRING_LEN+1);
+ for (i=0; iattr.source_filter.num_src_addr; ++i) {
+ sstrncpy(new_attr_p->attr.source_filter.src_list[i],
+ src_attr_p->attr.source_filter.src_list[i],
+ SDP_MAX_STRING_LEN+1);
+ }
+ new_attr_p->attr.source_filter.num_src_addr =
+ src_attr_p->attr.source_filter.num_src_addr;
+ break;
+
+ case SDP_ATTR_SRTP_CONTEXT:
+ case SDP_ATTR_SDESCRIPTIONS:
+ /* Tag parameter is only valid for version 9 sdescriptions */
+ if (src_attr_type == SDP_ATTR_SDESCRIPTIONS) {
+ new_attr_p->attr.srtp_context.tag =
+ src_attr_p->attr.srtp_context.tag;
+ }
+
+ new_attr_p->attr.srtp_context.suite =
+ src_attr_p->attr.srtp_context.suite;
+
+ new_attr_p->attr.srtp_context.selection_flags =
+ src_attr_p->attr.srtp_context.selection_flags;
+
+ new_attr_p->attr.srtp_context.master_key_size_bytes =
+ src_attr_p->attr.srtp_context.master_key_size_bytes;
+
+ new_attr_p->attr.srtp_context.master_salt_size_bytes =
+ src_attr_p->attr.srtp_context.master_salt_size_bytes;
+
+ bcopy(src_attr_p->attr.srtp_context.master_key,
+ new_attr_p->attr.srtp_context.master_key,
+ SDP_SRTP_MAX_KEY_SIZE_BYTES);
+
+ bcopy(src_attr_p->attr.srtp_context.master_salt,
+ new_attr_p->attr.srtp_context.master_salt,
+ SDP_SRTP_MAX_SALT_SIZE_BYTES);
+
+
+ sstrncpy((char*)new_attr_p->attr.srtp_context.master_key_lifetime,
+ (char*)src_attr_p->attr.srtp_context.master_key_lifetime,
+ SDP_SRTP_MAX_LIFETIME_BYTES);
+
+ sstrncpy((char*)new_attr_p->attr.srtp_context.mki,
+ (char*)src_attr_p->attr.srtp_context.mki,
+ SDP_SRTP_MAX_MKI_SIZE_BYTES);
+
+ new_attr_p->attr.srtp_context.mki_size_bytes =
+ src_attr_p->attr.srtp_context.mki_size_bytes;
+
+ if (src_attr_p->attr.srtp_context.session_parameters) {
+ new_attr_p->attr.srtp_context.session_parameters =
+ cpr_strdup(src_attr_p->attr.srtp_context.session_parameters);
+ }
+
+ break;
+
+ default:
+ break;
+ }
+
+ if (src_cap_num == 0) {
+ if (dst_level == SDP_SESSION_LEVEL) {
+ if (dst_sdp_p->sess_attrs_p == NULL) {
+ dst_sdp_p->sess_attrs_p = new_attr_p;
+ } else {
+ for (prev_attr_p = dst_sdp_p->sess_attrs_p;
+ prev_attr_p->next_p != NULL;
+ prev_attr_p = prev_attr_p->next_p) {
+ ; /* Empty for */
+ }
+ prev_attr_p->next_p = new_attr_p;
+ }
+ } else {
+ mca_p = sdp_find_media_level(dst_sdp_p, dst_level);
+ if (mca_p == NULL) {
+ sdp_free_attr(new_attr_p);
+ src_sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ if (mca_p->media_attrs_p == NULL) {
+ mca_p->media_attrs_p = new_attr_p;
+ } else {
+ for (prev_attr_p = mca_p->media_attrs_p;
+ prev_attr_p->next_p != NULL;
+ prev_attr_p = prev_attr_p->next_p) {
+ ; /* Empty for */
+ }
+ prev_attr_p->next_p = new_attr_p;
+ }
+ }
+ } else {
+ /* Add a new capability attribute - find the capability attr. */
+ attr_p = sdp_find_capability(dst_sdp_p, dst_level, dst_cap_num);
+ if (attr_p == NULL) {
+ sdp_free_attr(new_attr_p);
+ src_sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ cap_p = attr_p->attr.cap_p;
+ if (cap_p->media_attrs_p == NULL) {
+ cap_p->media_attrs_p = new_attr_p;
+ } else {
+ for (prev_attr_p = cap_p->media_attrs_p;
+ prev_attr_p->next_p != NULL;
+ prev_attr_p = prev_attr_p->next_p) {
+ ; /* Empty for */
+ }
+ prev_attr_p->next_p = new_attr_p;
+ }
+ }
+
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_copy_all_attrs
+ * Description: Copy all attributes from one SDP/level to another.
+ * Parameters: src_sdp_ptr The source SDP handle.
+ * dst_sdp_ptr The dest SDP handle.
+ * src_level The level of the source attributes.
+ * dst_level The level of the source attributes.
+ * Returns: SDP_SUCCESS Attributes were successfully copied.
+ */
+sdp_result_e sdp_copy_all_attrs (void *src_sdp_ptr, void *dst_sdp_ptr,
+ u16 src_level, u16 dst_level)
+{
+ int i;
+ sdp_mca_t *mca_p = NULL;
+ sdp_t *src_sdp_p = (sdp_t *)src_sdp_ptr;
+ sdp_t *dst_sdp_p = (sdp_t *)dst_sdp_ptr;
+ sdp_mca_t *src_cap_p;
+ sdp_mca_t *dst_cap_p;
+ sdp_attr_t *src_attr_p;
+ sdp_attr_t *dst_attr_p;
+ sdp_attr_t *new_attr_p;
+ sdp_attr_t *src_cap_attr_p;
+ sdp_attr_t *dst_cap_attr_p;
+ sdp_attr_t *new_cap_attr_p;
+
+ if (sdp_verify_sdp_ptr(src_sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ if (sdp_verify_sdp_ptr(dst_sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ /* Find src attribute list. */
+ if (src_level == SDP_SESSION_LEVEL) {
+ src_attr_p = src_sdp_p->sess_attrs_p;
+ } else {
+ mca_p = sdp_find_media_level(src_sdp_p, src_level);
+ if (mca_p == NULL) {
+ if (src_sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Invalid src media level (%u) for copy all "
+ "attrs ", src_sdp_p->debug_str, src_level);
+ }
+ return (SDP_INVALID_PARAMETER);
+ }
+ src_attr_p = mca_p->media_attrs_p;
+ }
+
+ /* Find dst attribute list. */
+ if (dst_level == SDP_SESSION_LEVEL) {
+ dst_attr_p = dst_sdp_p->sess_attrs_p;
+ } else {
+ mca_p = sdp_find_media_level(dst_sdp_p, dst_level);
+ if (mca_p == NULL) {
+ if (src_sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Invalid dst media level (%u) for copy all "
+ "attrs ", src_sdp_p->debug_str, dst_level);
+ }
+ return (SDP_INVALID_PARAMETER);
+ }
+ dst_attr_p = mca_p->media_attrs_p;
+ }
+
+ /* Now find the end of the dst attr list. This is where we will
+ * add new attributes. */
+ while ((dst_attr_p != NULL) && (dst_attr_p->next_p != NULL)) {
+ dst_attr_p = dst_attr_p->next_p;
+ }
+
+ /* For each src attribute, allocate a new dst attr and copy the info */
+ while (src_attr_p != NULL) {
+
+ /* Allocate the new attr. */
+ new_attr_p = (sdp_attr_t *)SDP_MALLOC(sizeof(sdp_attr_t));
+ if (new_attr_p == NULL) {
+ src_sdp_p->conf_p->num_no_resource++;
+ return (SDP_NO_RESOURCE);
+ }
+
+ if ((src_attr_p->type != SDP_ATTR_X_CAP) &&
+ (src_attr_p->type != SDP_ATTR_CDSC)) {
+ /* Simple attr type - copy over all the attr info. */
+ sdp_copy_attr_fields(src_attr_p, new_attr_p);
+ } else {
+ /* X-cap/cdsc attrs must be handled differently. Allocate an
+ * mca structure and copy over any X-cpar/cdsc attrs. */
+
+ new_attr_p->attr.cap_p =
+ (sdp_mca_t *)SDP_MALLOC(sizeof(sdp_mca_t));
+ if (new_attr_p->attr.cap_p == NULL) {
+ sdp_free_attr(new_attr_p);
+ return (SDP_NO_RESOURCE);
+ }
+
+ new_attr_p->type = src_attr_p->type;
+
+ src_cap_p = src_attr_p->attr.cap_p;
+ dst_cap_p = new_attr_p->attr.cap_p;
+
+ dst_cap_p->media = src_cap_p->media;
+ dst_cap_p->conn.nettype = src_cap_p->conn.nettype;
+ dst_cap_p->conn.addrtype = src_cap_p->conn.addrtype;
+ sstrncpy(dst_cap_p->conn.conn_addr, src_cap_p->conn.conn_addr,
+ SDP_MAX_LINE_LEN+1);
+ dst_cap_p->transport = src_cap_p->transport;
+ dst_cap_p->port_format = src_cap_p->port_format;
+ dst_cap_p->port = src_cap_p->port;
+ dst_cap_p->num_ports = src_cap_p->num_ports;
+ dst_cap_p->vpi = src_cap_p->vpi;
+ dst_cap_p->vci = src_cap_p->vci;
+ dst_cap_p->vcci = src_cap_p->vcci;
+ dst_cap_p->cid = src_cap_p->cid;
+ dst_cap_p->num_payloads = src_cap_p->num_payloads;
+ dst_cap_p->mid = src_cap_p->mid;
+
+ for (i=0; i < SDP_MAX_PAYLOAD_TYPES; i++) {
+ new_attr_p->attr.cap_p->payload_indicator[i] =
+ src_attr_p->attr.cap_p->payload_indicator[i];
+ new_attr_p->attr.cap_p->payload_type[i] =
+ src_attr_p->attr.cap_p->payload_type[i];
+ }
+
+ src_cap_attr_p = src_attr_p->attr.cap_p->media_attrs_p;
+ dst_cap_attr_p = NULL;
+
+ /* Copy all of the X-cpar/cpar attrs from the src. */
+ while (src_cap_attr_p != NULL) {
+
+ new_cap_attr_p = (sdp_attr_t *)SDP_MALLOC(sizeof(sdp_attr_t));
+ if (new_cap_attr_p == NULL) {
+ sdp_free_attr (new_attr_p);
+ return (SDP_NO_RESOURCE);
+ }
+
+ /* Copy X-cpar/cpar attribute info. */
+ sdp_copy_attr_fields(src_cap_attr_p, new_cap_attr_p);
+
+ /* Now add the new X-cpar/cpar attr in the right place. */
+ if (dst_cap_attr_p == NULL) {
+ new_attr_p->attr.cap_p->media_attrs_p = new_cap_attr_p;
+ dst_cap_attr_p = new_cap_attr_p;
+ } else {
+ dst_cap_attr_p->next_p = new_cap_attr_p;
+ dst_cap_attr_p = new_cap_attr_p;
+ }
+
+ /* Move to the next X-cpar/cpar attr. */
+ src_cap_attr_p = src_cap_attr_p->next_p;
+ }
+
+ }
+
+ /* New add the new base attr at the correct place. */
+ if (dst_attr_p == NULL) {
+ if (dst_level == SDP_SESSION_LEVEL) {
+ dst_sdp_p->sess_attrs_p = new_attr_p;
+ dst_attr_p = dst_sdp_p->sess_attrs_p;
+ } else {
+ mca_p->media_attrs_p = new_attr_p;
+ dst_attr_p = mca_p->media_attrs_p;
+ }
+ } else {
+ dst_attr_p->next_p = new_attr_p;
+ dst_attr_p = dst_attr_p->next_p;
+ }
+
+ /* Now move on to the next src attr. */
+ src_attr_p = src_attr_p->next_p;
+ }
+
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_attr_num_instances
+ * Description: Get the number of attributes of the specified type at
+ * the given level and capability level.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * attr_type The type of attribute to add.
+ * num_attr_inst Pointer to a u16 in which to return the
+ * number of attributes.
+ * Returns: SDP_SUCCESS Attribute was added successfully.
+ * SDP_INVALID_PARAMETER Specified media line is not defined.
+ */
+sdp_result_e sdp_attr_num_instances (void *sdp_ptr, u16 level, u8 cap_num,
+ sdp_attr_e attr_type, u16 *num_attr_inst)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_result_e rc;
+ static char fname[] = "attr_num_instances";
+
+ *num_attr_inst = 0;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ rc = sdp_find_attr_list(sdp_p, level, cap_num, &attr_p, fname);
+ if (rc == SDP_SUCCESS) {
+ /* Found the attr list. Count the number of attrs of the given
+ * type at this level. */
+ for (; attr_p != NULL; attr_p = attr_p->next_p) {
+ if (attr_p->type == attr_type) {
+ (*num_attr_inst)++;
+ }
+ }
+
+ }
+
+ return (rc);
+}
+
+
+/* Function: sdp_get_total_attrs
+ * Description: Get the total number of attributes at the given level and
+ * capability level.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * num_attrs Pointer to a u16 in which to return the
+ * number of attributes.
+ * Returns: SDP_SUCCESS Attribute was added successfully.
+ * SDP_INVALID_PARAMETER Specified media line is not defined.
+ */
+sdp_result_e sdp_get_total_attrs (void *sdp_ptr, u16 level, u8 cap_num,
+ u16 *num_attrs)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_result_e rc;
+ static char fname[] = "get_total_attrs";
+
+ *num_attrs = 0;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ rc = sdp_find_attr_list(sdp_p, level, cap_num, &attr_p, fname);
+ if (rc == SDP_SUCCESS) {
+ /* Found the attr list. Count the total number of attrs
+ * at this level. */
+ for (; attr_p != NULL; attr_p = attr_p->next_p) {
+ (*num_attrs)++;
+ }
+
+ }
+
+ return (rc);
+}
+
+
+/* Function: sdp_get_attr_type
+ * Description: Given an overall attribute number at a specified level, i.e.,
+ * attr number is not specific to the type of attribute, return
+ * the attribute type and the instance number of that particular
+ * type of attribute.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * attr_num Attribute number to retrieve. This is an overall
+ * attribute number over all attrs at this level.
+ * Range is (1 - max attrs at this level).
+ * Returns: SDP_SUCCESS Attribute was added successfully.
+ * SDP_INVALID_PARAMETER Specified media line is not defined.
+ */
+sdp_result_e sdp_get_attr_type (void *sdp_ptr, u16 level, u8 cap_num,
+ u16 attr_num, sdp_attr_e *attr_type, u16 *inst_num)
+{
+ int i;
+ u16 attr_total_count=0;
+ u16 attr_count[SDP_MAX_ATTR_TYPES];
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_result_e rc;
+ static char fname[] = "get_attr_type";
+
+ *attr_type = SDP_ATTR_INVALID;
+ *inst_num = 0;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ if (attr_num < 1) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s %s, invalid attr num specified (%u) at level %u",
+ sdp_p->debug_str, fname, attr_num, level);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ for (i=0; i < SDP_MAX_ATTR_TYPES; i++) {
+ attr_count[i] = 0;
+ }
+
+ rc = sdp_find_attr_list(sdp_p, level, cap_num, &attr_p, fname);
+ if (rc == SDP_SUCCESS) {
+ /* Found the attr list. Now find the particular attribute
+ * at the given level. */
+ for (; attr_p != NULL; attr_p = attr_p->next_p) {
+ attr_count[attr_p->type]++;
+ if (++attr_total_count == attr_num) {
+ *attr_type = attr_p->type;
+ *inst_num = attr_count[attr_p->type];
+ break;
+ }
+ }
+
+ }
+
+ return (rc);
+}
+
+
+/* Internal routine to free the memory associated with an attribute.
+ * Certain attributes allocate additional memory. Free this and then
+ * free the attribute itself.
+ * Note that this routine may be called at any point (i.e., may be
+ * called due to a failure case) and so the additional memory
+ * associated with an attribute may or may not have been already
+ * allocated. This routine should check this carefully.
+ */
+void sdp_free_attr (sdp_attr_t *attr_p)
+{
+ sdp_mca_t *cap_p;
+ sdp_attr_t *cpar_p;
+ sdp_attr_t *next_cpar_p;
+
+ /* If this is an X-cap/cdsc attr, free the cap_p structure and
+ * all X-cpar/cpar attributes. */
+ if ((attr_p->type == SDP_ATTR_X_CAP) ||
+ (attr_p->type == SDP_ATTR_CDSC)) {
+ cap_p = attr_p->attr.cap_p;
+ if (cap_p != NULL) {
+ for (cpar_p = cap_p->media_attrs_p; cpar_p != NULL;) {
+ next_cpar_p = cpar_p->next_p;
+ sdp_free_attr(cpar_p);
+ cpar_p = next_cpar_p;
+ }
+ SDP_FREE(cap_p);
+ }
+ } else if ((attr_p->type == SDP_ATTR_SDESCRIPTIONS) ||
+ (attr_p->type == SDP_ATTR_SRTP_CONTEXT)) {
+ SDP_FREE(attr_p->attr.srtp_context.session_parameters);
+ }
+
+ /* Now free the actual attribute memory. */
+ SDP_FREE(attr_p);
+
+}
+
+
+/* Function: sdp_delete_attr
+ * Description: Delete the specified attribute from the SDP structure.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * attr_type The type of attribute to delete.
+ * inst_num The instance num of the attribute to delete.
+ * Returns: SDP_SUCCESS Attribute was deleted successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_delete_attr (void *sdp_ptr, u16 level, u8 cap_num,
+ sdp_attr_e attr_type, u16 inst_num)
+{
+ u16 attr_count=0;
+ sdp_mca_t *mca_p;
+ sdp_mca_t *cap_p;
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_attr_t *prev_attr_p = NULL;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ if (cap_num == 0) {
+ /* Find and delete the specified instance. */
+ if (level == SDP_SESSION_LEVEL) {
+ for (attr_p = sdp_p->sess_attrs_p; attr_p != NULL;
+ prev_attr_p = attr_p, attr_p = attr_p->next_p) {
+ if (attr_p->type == attr_type) {
+ attr_count++;
+ if (attr_count == inst_num) {
+ break;
+ }
+ }
+ }
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Delete attribute (%s) instance %d not "
+ "found.", sdp_p->debug_str,
+ sdp_get_attr_name(attr_type), inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ if (prev_attr_p == NULL) {
+ sdp_p->sess_attrs_p = attr_p->next_p;
+ } else {
+ prev_attr_p->next_p = attr_p->next_p;
+ }
+ sdp_free_attr(attr_p);
+ } else { /* Attr is at a media level */
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ for (attr_p = mca_p->media_attrs_p; attr_p != NULL;
+ prev_attr_p = attr_p, attr_p = attr_p->next_p) {
+ if (attr_p->type == attr_type) {
+ attr_count++;
+ if (attr_count == inst_num) {
+ break;
+ }
+ }
+ }
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Delete attribute (%s) instance %d "
+ "not found.", sdp_p->debug_str,
+ sdp_get_attr_name(attr_type), inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ if (prev_attr_p == NULL) {
+ mca_p->media_attrs_p = attr_p->next_p;
+ } else {
+ prev_attr_p->next_p = attr_p->next_p;
+ }
+ sdp_free_attr(attr_p);
+ } /* Attr is at a media level */
+ } else {
+ /* Attr is a capability X-cpar/cpar attribute, find the capability. */
+ attr_p = sdp_find_capability(sdp_p, level, cap_num);
+ if (attr_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ cap_p = attr_p->attr.cap_p;
+ /* Now find the specific attribute to delete. */
+ for (attr_p = cap_p->media_attrs_p; attr_p != NULL;
+ prev_attr_p = attr_p, attr_p = attr_p->next_p) {
+ if (attr_p->type == attr_type) {
+ attr_count++;
+ if (attr_count == inst_num) {
+ break;
+ }
+ }
+ }
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Delete X-cpar/cpar attribute (%s) cap_num %u, "
+ "instance %d not found.", sdp_p->debug_str,
+ sdp_get_attr_name(attr_type), cap_num, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ if (prev_attr_p == NULL) {
+ cap_p->media_attrs_p = attr_p->next_p;
+ } else {
+ prev_attr_p->next_p = attr_p->next_p;
+ }
+ sdp_free_attr(attr_p);
+ }
+
+ return (SDP_SUCCESS);
+}
+
+
+/* Function: sdp_delete_all_attrs
+ * Description: Delete all attributes at the specified level from
+ * the SDP structure.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * Returns: SDP_SUCCESS Attributes were deleted successfully.
+ */
+sdp_result_e sdp_delete_all_attrs (void *sdp_ptr, u16 level, u8 cap_num)
+{
+ sdp_mca_t *mca_p;
+ sdp_mca_t *cap_p;
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_attr_t *next_attr_p = NULL;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ if (cap_num == 0) {
+ if (level == SDP_SESSION_LEVEL) {
+ attr_p = sdp_p->sess_attrs_p;
+ while (attr_p != NULL) {
+ next_attr_p = attr_p->next_p;
+ sdp_free_attr(attr_p);
+ attr_p = next_attr_p;
+ }
+ sdp_p->sess_attrs_p = NULL;
+ } else { /* Attr is at a media level */
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p = mca_p->media_attrs_p;
+ while (attr_p != NULL) {
+ next_attr_p = attr_p->next_p;
+ sdp_free_attr(attr_p);
+ attr_p = next_attr_p;
+ }
+ mca_p->media_attrs_p = NULL;
+ }
+ } else {
+ /* Attr is a capability X-cpar/cpar attribute, find the capability. */
+ attr_p = sdp_find_capability(sdp_p, level, cap_num);
+ if (attr_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ cap_p = attr_p->attr.cap_p;
+ /* Now find the specific attribute to delete. */
+ attr_p = cap_p->media_attrs_p;
+ while (attr_p != NULL) {
+ next_attr_p = attr_p->next_p;
+ sdp_free_attr(attr_p);
+ attr_p = next_attr_p;
+ }
+ cap_p->media_attrs_p = NULL;
+ }
+
+ return (SDP_SUCCESS);
+}
+
+
+/* Function: sdp_find_attr_list
+ * Description: Find the attribute list for the specified level and cap_num.
+ * Note: This is not an API for the application but an internal
+ * routine used by the SDP library.
+ * Parameters: sdp_p Pointer to the SDP to search.
+ * level The level to check for the attribute list.
+ * cap_num The capability number associated with the
+ * attribute list. If none, should be zero.
+ * attr_p Pointer to the attr list pointer. Will be
+ * filled in on return if successful.
+ * fname String function name calling this routine.
+ * Use for printing debug.
+ * Returns: SDP_SUCCESS
+ * SDP_INVALID_MEDIA_LEVEL
+ * SDP_INVALID_CAPABILITY
+ * SDP_FAILURE
+ */
+sdp_result_e sdp_find_attr_list (sdp_t *sdp_p, u16 level, u8 cap_num,
+ sdp_attr_t **attr_p, char *fname)
+{
+ sdp_mca_t *mca_p;
+ sdp_mca_t *cap_p;
+ sdp_attr_t *cap_attr_p;
+
+ /* Initialize the attr pointer. */
+ *attr_p = NULL;
+
+ if (cap_num == 0) {
+ /* Find attribute list at the specified level. */
+ if (level == SDP_SESSION_LEVEL) {
+ *attr_p = sdp_p->sess_attrs_p;
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ *attr_p = mca_p->media_attrs_p;
+ }
+ } else {
+ /* Find the attr list for the capability specified. */
+ cap_attr_p = sdp_find_capability(sdp_p, level, cap_num);
+ if (cap_attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s %s, invalid capability %u at "
+ "level %u specified.", sdp_p->debug_str, fname,
+ cap_num, level);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_CAPABILITY);
+ }
+ cap_p = cap_attr_p->attr.cap_p;
+ *attr_p = cap_p->media_attrs_p;
+ }
+
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_find_attr
+ * Description: Find the specified attribute in an SDP structure.
+ * Note: This is not an API for the application but an internal
+ * routine used by the SDP library.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * attr_type The type of attribute to find.
+ * inst_num The instance num of the attribute to delete.
+ * Range should be (1 - max num insts of this
+ * particular type of attribute at this level).
+ * Returns: Pointer to the attribute or NULL if not found.
+ */
+sdp_attr_t *sdp_find_attr (sdp_t *sdp_p, u16 level, u8 cap_num,
+ sdp_attr_e attr_type, u16 inst_num)
+{
+ u16 attr_count=0;
+ sdp_mca_t *mca_p;
+ sdp_mca_t *cap_p;
+ sdp_attr_t *attr_p;
+
+ if (inst_num < 1) {
+ return (NULL);
+ }
+
+ if (cap_num == 0) {
+ if (level == SDP_SESSION_LEVEL) {
+ for (attr_p = sdp_p->sess_attrs_p; attr_p != NULL;
+ attr_p = attr_p->next_p) {
+ if (attr_p->type == attr_type) {
+ attr_count++;
+ if (attr_count == inst_num) {
+ return (attr_p);
+ }
+ }
+ }
+ } else { /* Attr is at a media level */
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (NULL);
+ }
+ for (attr_p = mca_p->media_attrs_p; attr_p != NULL;
+ attr_p = attr_p->next_p) {
+ if (attr_p->type == attr_type) {
+ attr_count++;
+ if (attr_count == inst_num) {
+ return (attr_p);
+ }
+ }
+ }
+ } /* Attr is at a media level */
+ } else {
+ /* Attr is a capability X-cpar/cpar attribute. */
+ attr_p = sdp_find_capability(sdp_p, level, cap_num);
+ if (attr_p == NULL) {
+ return (NULL);
+ }
+ cap_p = attr_p->attr.cap_p;
+ /* Now find the specific attribute. */
+ for (attr_p = cap_p->media_attrs_p; attr_p != NULL;
+ attr_p = attr_p->next_p) {
+ if (attr_p->type == attr_type) {
+ attr_count++;
+ if (attr_count == inst_num) {
+ return (attr_p);
+ }
+ }
+ }
+ }
+
+ return (NULL);
+}
+
+/* Function: sdp_find_capability
+ * Description: Find the specified capability attribute in an SDP structure.
+ * Note: This is not an API for the application but an internal
+ * routine used by the SDP library.
+ * Parameters: sdp_p The SDP handle.
+ * level The level to check for the capability.
+ * cap_num The capability number to locate.
+ * Returns: Pointer to the capability attribute or NULL if not found.
+ */
+sdp_attr_t *sdp_find_capability (sdp_t *sdp_p, u16 level, u8 cap_num)
+{
+ u8 cur_cap_num=0;
+ sdp_mca_t *mca_p;
+ sdp_mca_t *cap_p;
+ sdp_attr_t *attr_p;
+
+ if (level == SDP_SESSION_LEVEL) {
+ for (attr_p = sdp_p->sess_attrs_p; attr_p != NULL;
+ attr_p = attr_p->next_p) {
+ if ((attr_p->type == SDP_ATTR_X_CAP) ||
+ (attr_p->type == SDP_ATTR_CDSC)) {
+ cap_p = attr_p->attr.cap_p;
+ cur_cap_num += cap_p->num_payloads;
+ if (cap_num <= cur_cap_num) {
+ /* This is the right capability */
+ return (attr_p);
+ }
+ }
+ }
+ } else { /* Capability is at a media level */
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (NULL);
+ }
+ for (attr_p = mca_p->media_attrs_p; attr_p != NULL;
+ attr_p = attr_p->next_p) {
+ if ((attr_p->type == SDP_ATTR_X_CAP) ||
+ (attr_p->type == SDP_ATTR_CDSC)) {
+ cap_p = attr_p->attr.cap_p;
+ cur_cap_num += cap_p->num_payloads;
+ if (cap_num <= cur_cap_num) {
+ /* This is the right capability */
+ return (attr_p);
+ }
+ }
+ }
+ }
+
+ /* We didn't find the specified capability. */
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Unable to find specified capability (level %u, "
+ "cap_num %u).", sdp_p->debug_str, level, cap_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (NULL);
+}
+
+/* Function: sdp_attr_valid(void *sdp_ptr)
+ * Description: Returns true or false depending on whether the specified
+ * instance of the given attribute has been defined at the
+ * given level.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * attr_type The attribute type to validate.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: TRUE or FALSE.
+ */
+tinybool sdp_attr_valid (void *sdp_ptr, sdp_attr_e attr_type, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (FALSE);
+ }
+
+ if (sdp_find_attr(sdp_p, level, cap_num, attr_type, inst_num) == NULL) {
+ return (FALSE);
+ } else {
+ return (TRUE);
+ }
+}
+
+/* Function: sdp_attr_get_simple_string
+ * Description: Returns a pointer to a string attribute parameter. This
+ * routine can only be called for attributes that have just
+ * one string parameter. The value is returned as a const
+ * ptr and so cannot be modified by the application. If the
+ * given attribute is not defined, NULL will be returned.
+ * Attributes with a simple string parameter currently include:
+ * bearer, called, connection_type, dialed, dialing, direction
+ * and framing.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * attr_type The simple string attribute type.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Pointer to the parameter value.
+ */
+const char *sdp_attr_get_simple_string (void *sdp_ptr, sdp_attr_e attr_type,
+ u16 level, u8 cap_num, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (NULL);
+ }
+
+ if ((attr_type != SDP_ATTR_BEARER) &&
+ (attr_type != SDP_ATTR_CALLED) &&
+ (attr_type != SDP_ATTR_CONN_TYPE) &&
+ (attr_type != SDP_ATTR_DIALED) &&
+ (attr_type != SDP_ATTR_DIALING) &&
+ (attr_type != SDP_ATTR_FRAMING) &&
+ (attr_type != SDP_ATTR_X_SIDIN) &&
+ (attr_type != SDP_ATTR_X_SIDOUT)&&
+ (attr_type != SDP_ATTR_X_CONFID) &&
+ (attr_type != SDP_ATTR_LABEL)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Attribute type is not a simple string (%s)",
+ sdp_p->debug_str, sdp_get_attr_name(attr_type));
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (NULL);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, attr_type, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Attribute %s, level %u instance %u not found.",
+ sdp_p->debug_str, sdp_get_attr_name(attr_type),
+ level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (NULL);
+ } else {
+ return (attr_p->attr.string_val);
+ }
+}
+
+/* Function: sdp_attr_set_simple_string
+ * Description: Sets the value of a string attribute parameter. This
+ * routine can only be called for attributes that have just
+ * one string parameter. The string is copied into the SDP
+ * structure so application memory will not be referenced by
+ * the SDP library.
+ * Attributes with a simple string parameter currently include:
+ * bearer, called, connection_type, dialed, dialing, and
+ * framing.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * attr_type The simple string attribute type.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * string_parm Ptr to new string value.
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_simple_string (void *sdp_ptr, sdp_attr_e attr_type,
+ u16 level, u8 cap_num,
+ u16 inst_num, const char *string_parm)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ if ((attr_type != SDP_ATTR_BEARER) &&
+ (attr_type != SDP_ATTR_CALLED) &&
+ (attr_type != SDP_ATTR_CONN_TYPE) &&
+ (attr_type != SDP_ATTR_DIALED) &&
+ (attr_type != SDP_ATTR_DIALING) &&
+ (attr_type != SDP_ATTR_FRAMING) &&
+ (attr_type != SDP_ATTR_X_SIDIN) &&
+ (attr_type != SDP_ATTR_X_SIDOUT)&&
+ (attr_type != SDP_ATTR_X_CONFID) &&
+ (attr_type != SDP_ATTR_LABEL)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Attribute type is not a simple string (%s)",
+ sdp_p->debug_str, sdp_get_attr_name(attr_type));
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, attr_type, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Attribute %s, level %u instance %u not found.",
+ sdp_p->debug_str, sdp_get_attr_name(attr_type),
+ level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ sstrncpy(attr_p->attr.string_val, string_parm,
+ sizeof(attr_p->attr.string_val));
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_get_simple_u32
+ * Description: Returns an unsigned 32-bit attribute parameter. This
+ * routine can only be called for attributes that have just
+ * one u32 parameter. If the given attribute is not defined,
+ * zero will be returned. There is no way for the application
+ * to determine if zero is the actual value or the attribute
+ * wasn't defined, so the application must use the
+ * sdp_attr_valid function to determine this.
+ * Attributes with a simple u32 parameter currently include:
+ * eecid, ptime, T38FaxVersion, T38maxBitRate, T38FaxMaxBuffer,
+ * T38FaxMaxDatagram, X-sqn, TC1PayloadBytes, TC1WindowSize,
+ * TC2PayloadBytes, TC2WindowSize, rtcp.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * attr_type The simple u32 attribute type.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: u32 parameter value.
+ */
+u32 sdp_attr_get_simple_u32 (void *sdp_ptr, sdp_attr_e attr_type, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (0);
+ }
+
+ if ((attr_type != SDP_ATTR_EECID) &&
+ (attr_type != SDP_ATTR_PTIME) &&
+ (attr_type != SDP_ATTR_MAXPTIME) &&
+ (attr_type != SDP_ATTR_T38_VERSION) &&
+ (attr_type != SDP_ATTR_T38_MAXBITRATE) &&
+ (attr_type != SDP_ATTR_T38_MAXBUFFER) &&
+ (attr_type != SDP_ATTR_T38_MAXDGRAM) &&
+ (attr_type != SDP_ATTR_X_SQN) &&
+ (attr_type != SDP_ATTR_TC1_PAYLOAD_BYTES) &&
+ (attr_type != SDP_ATTR_TC1_WINDOW_SIZE) &&
+ (attr_type != SDP_ATTR_TC2_PAYLOAD_BYTES) &&
+ (attr_type != SDP_ATTR_TC2_WINDOW_SIZE) &&
+ (attr_type != SDP_ATTR_RTCP) &&
+ (attr_type != SDP_ATTR_MID) &&
+ (attr_type != SDP_ATTR_FRAMERATE)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Attribute type is not a simple u32 (%s)",
+ sdp_p->debug_str, sdp_get_attr_name(attr_type));
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, attr_type, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Attribute %s, level %u instance %u not found.",
+ sdp_p->debug_str, sdp_get_attr_name(attr_type),
+ level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ return (attr_p->attr.u32_val);
+ }
+}
+
+/* Function: sdp_attr_set_simple_u32
+ * Description: Sets the value of an unsigned 32-bit attribute parameter.
+ * This routine can only be called for attributes that have just
+ * one u32 parameter.
+ * Attributes with a simple u32 parameter currently include:
+ * eecid, ptime, T38FaxVersion, T38maxBitRate, T38FaxMaxBuffer,
+ * T38FaxMaxDatagram, X-sqn, TC1PayloadBytes, TC1WindowSize,
+ * TC2PayloadBytes, TC2WindowSize, rtcp.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * attr_type The simple u32 attribute type.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * num_parm New u32 parameter.
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_simple_u32 (void *sdp_ptr, sdp_attr_e attr_type,
+ u16 level, u8 cap_num, u16 inst_num, u32 num_parm)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ if ((attr_type != SDP_ATTR_EECID) &&
+ (attr_type != SDP_ATTR_PTIME) &&
+ (attr_type != SDP_ATTR_MAXPTIME) &&
+ (attr_type != SDP_ATTR_T38_VERSION) &&
+ (attr_type != SDP_ATTR_T38_MAXBITRATE) &&
+ (attr_type != SDP_ATTR_T38_MAXBUFFER) &&
+ (attr_type != SDP_ATTR_T38_MAXDGRAM) &&
+ (attr_type != SDP_ATTR_X_SQN) &&
+ (attr_type != SDP_ATTR_TC1_PAYLOAD_BYTES) &&
+ (attr_type != SDP_ATTR_TC1_WINDOW_SIZE) &&
+ (attr_type != SDP_ATTR_TC2_PAYLOAD_BYTES) &&
+ (attr_type != SDP_ATTR_TC2_WINDOW_SIZE) &&
+ (attr_type != SDP_ATTR_RTCP) &&
+ (attr_type != SDP_ATTR_MID) &&
+ (attr_type != SDP_ATTR_FRAMERATE)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Attribute type is not a simple u32 (%s)",
+ sdp_p->debug_str, sdp_get_attr_name(attr_type));
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, attr_type, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Attribute %s, level %u instance %u not found.",
+ sdp_p->debug_str, sdp_get_attr_name(attr_type),
+ level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ attr_p->attr.u32_val = num_parm;
+ return (SDP_SUCCESS);
+ }
+}
+
+
+/* Function: sdp_attr_get_simple_boolean
+ * Description: Returns a boolean attribute parameter. This
+ * routine can only be called for attributes that have just
+ * one boolean parameter. If the given attribute is not defined,
+ * FALSE will be returned. There is no way for the application
+ * to determine if FALSE is the actual value or the attribute
+ * wasn't defined, so the application must use the
+ * sdp_attr_valid function to determine this.
+ * Attributes with a simple boolean parameter currently include:
+ * T38FaxFillBitRemoval, T38FaxTranscodingMMR,
+ * T38FaxTranscodingJBIG, and TMRGwXid.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * attr_type The simple boolean attribute type.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Boolean value.
+ */
+tinybool sdp_attr_get_simple_boolean (void *sdp_ptr, sdp_attr_e attr_type,
+ u16 level, u8 cap_num, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (FALSE);
+ }
+
+ if ((attr_type != SDP_ATTR_T38_FILLBITREMOVAL) &&
+ (attr_type != SDP_ATTR_T38_TRANSCODINGMMR) &&
+ (attr_type != SDP_ATTR_T38_TRANSCODINGJBIG) &&
+ (attr_type != SDP_ATTR_TMRGWXID)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Attribute type is not a simple boolean (%s)",
+ sdp_p->debug_str, sdp_get_attr_name(attr_type));
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (FALSE);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, attr_type, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Attribute %s, level %u instance %u not found.",
+ sdp_p->debug_str, sdp_get_attr_name(attr_type),
+ level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (FALSE);
+ } else {
+ return (attr_p->attr.boolean_val);
+ }
+}
+
+/* Function: sdp_attr_set_simple_boolean
+ * Description: Sets the value of a boolean attribute parameter.
+ * This routine can only be called for attributes that have just
+ * one boolean parameter.
+ * Attributes with a simple boolean parameter currently include:
+ * T38FaxFillBitRemoval, T38FaxTranscodingMMR,
+ * T38FaxTranscodingJBIG, and TMRGwXid.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * attr_type The simple boolean attribute type.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * bool_parm New boolean parameter.
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_simple_boolean (void *sdp_ptr, sdp_attr_e attr_type,
+ u16 level, u8 cap_num,
+ u16 inst_num, u32 bool_parm)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ if ((attr_type != SDP_ATTR_T38_FILLBITREMOVAL) &&
+ (attr_type != SDP_ATTR_T38_TRANSCODINGMMR) &&
+ (attr_type != SDP_ATTR_T38_TRANSCODINGJBIG) &&
+ (attr_type != SDP_ATTR_TMRGWXID)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Attribute type is not a simple boolean (%s)",
+ sdp_p->debug_str, sdp_get_attr_name(attr_type));
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, attr_type, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Attribute %s, level %u instance %u not found.",
+ sdp_p->debug_str, sdp_get_attr_name(attr_type),
+ level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ attr_p->attr.boolean_val = (tinybool)bool_parm;
+ return (SDP_SUCCESS);
+ }
+}
+
+/*
+ * sdp_attr_get_maxprate
+ *
+ * This function is used by the application layer to get the packet-rate
+ * within the maxprate attribute.
+ *
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * inst_num The attribute instance number to set.
+ *
+ * Returns a pointer to a constant char array that stores the packet-rate,
+ * OR null if the attribute does not exist.
+ */
+const char*
+sdp_attr_get_maxprate (void *sdp_ptr, u16 level, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (NULL);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_MAXPRATE, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Attribute %s, level %u instance %u not found.",
+ sdp_p->debug_str, sdp_get_attr_name(SDP_ATTR_MAXPRATE),
+ level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (NULL);
+ } else {
+ return (attr_p->attr.string_val);
+ }
+}
+
+/*
+ * sdp_attr_set_maxprate
+ *
+ * This function is used by the application layer to set the packet rate of
+ * the maxprate attribute line appropriately. The maxprate attribute is
+ * defined as follows:
+ *
+ * max-p-rate-def = "a" "=" "maxprate" ":" packet-rate CRLF
+ * packet-rate = 1*DIGIT ["." 1*DIGIT]
+ *
+ *
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * inst_num The attribute instance number to set.
+ * string_parm A string that contains the value of packet-rate
+ * that needs to be advertised.
+ *
+ * Note that we use a string to set the packet-rate, so the application layer
+ * must format a string, as per the packet-rate format and pass it to this
+ * function.
+ *
+ * The decision to use a string to communicate the packet-rate was
+ * made because some operating systems do not support floating point
+ * operations.
+ *
+ * Returns:
+ * SDP_INVALID_SDP_PTR - If an invalid sdp handle is passed in.
+ * SDP_INVALID_PARAMETER - If the maxprate attribute is not defined at the
+ * specified level OR if the packet-rate is not
+ * formatted correctly in string_parm.
+ * SDP_SUCCESS - If we are successfully able to set the maxprate attribute.
+ */
+sdp_result_e
+sdp_attr_set_maxprate (void *sdp_ptr, u16 level, u16 inst_num,
+ const char *string_parm)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_MAXPRATE, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Attribute %s, level %u instance %u not found.",
+ sdp_p->debug_str, sdp_get_attr_name(SDP_ATTR_MAXPRATE),
+ level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ if (!sdp_validate_maxprate(string_parm)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s is not a valid maxprate value.", string_parm);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ sstrncpy(attr_p->attr.string_val, string_parm,
+ sizeof(attr_p->attr.string_val));
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_get_t38ratemgmt
+ * Description: Returns the value of the t38ratemgmt attribute
+ * parameter specified for the given attribute. If the given
+ * attribute is not defined, SDP_T38_UNKNOWN_RATE is returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Ratemgmt value.
+ */
+sdp_t38_ratemgmt_e sdp_attr_get_t38ratemgmt (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_T38_UNKNOWN_RATE);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_T38_RATEMGMT, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s t38ratemgmt attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_T38_UNKNOWN_RATE);
+ } else {
+ return (attr_p->attr.t38ratemgmt);
+ }
+}
+
+/* Function: sdp_attr_set_t38ratemgmt
+ * Description: Sets the value of the t38ratemgmt attribute parameter
+ * for the given attribute.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * t38ratemgmt New t38ratemgmt parameter.
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_t38ratemgmt (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ sdp_t38_ratemgmt_e t38ratemgmt)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_T38_RATEMGMT, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s t38ratemgmt attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ attr_p->attr.t38ratemgmt = t38ratemgmt;
+ return (SDP_SUCCESS);
+ }
+}
+
+
+/* Function: sdp_attr_get_t38udpec
+ * Description: Returns the value of the t38udpec attribute
+ * parameter specified for the given attribute. If the given
+ * attribute is not defined, SDP_T38_UDPEC_UNKNOWN is returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: UDP EC value.
+ */
+sdp_t38_udpec_e sdp_attr_get_t38udpec (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_T38_UDPEC_UNKNOWN);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_T38_UDPEC, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s t38udpec attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_T38_UDPEC_UNKNOWN);
+ } else {
+ return (attr_p->attr.t38udpec);
+ }
+}
+
+/* Function: sdp_attr_set_t38udpec
+ * Description: Sets the value of the t38ratemgmt attribute parameter
+ * for the given attribute.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * t38udpec New t38udpec parameter.
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_t38udpec (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ sdp_t38_udpec_e t38udpec)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_T38_UDPEC, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s t38udpec attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ attr_p->attr.t38udpec = t38udpec;
+ return (SDP_SUCCESS);
+ }
+}
+
+
+/* Function: sdp_get_media_direction
+ * Description: Determines the direction defined for a given level. The
+ * direction will be inactive, sendonly, recvonly, or sendrecv
+ * as determined by the last of these attributes specified at
+ * the given level. If none of these attributes are specified,
+ * the direction will be sendrecv by default.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * Returns: An SDP direction enum value.
+ */
+sdp_direction_e sdp_get_media_direction (void *sdp_ptr, u16 level,
+ u8 cap_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_mca_t *mca_p;
+ sdp_attr_t *attr_p;
+ sdp_direction_e direction = SDP_DIRECTION_SENDRECV;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (direction);
+ }
+
+ if (cap_num == 0) {
+ /* Find the pointer to the attr list for this level. */
+ if (level == SDP_SESSION_LEVEL) {
+ attr_p = sdp_p->sess_attrs_p;
+ } else { /* Attr is at a media level */
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (direction);
+ }
+ attr_p = mca_p->media_attrs_p;
+ }
+
+ /* Scan for direction oriented attributes. Last one wins. */
+ for (; attr_p != NULL; attr_p = attr_p->next_p) {
+ if (attr_p->type == SDP_ATTR_INACTIVE) {
+ direction = SDP_DIRECTION_INACTIVE;
+ } else if (attr_p->type == SDP_ATTR_SENDONLY) {
+ direction = SDP_DIRECTION_SENDONLY;
+ } else if (attr_p->type == SDP_ATTR_RECVONLY) {
+ direction = SDP_DIRECTION_RECVONLY;
+ } else if (attr_p->type == SDP_ATTR_SENDRECV) {
+ direction = SDP_DIRECTION_SENDRECV;
+ }
+ }
+ } else {
+ if (sdp_p->debug_flag[SDP_DEBUG_WARNINGS]) {
+ CSFLogDebug(logTag, "%s Warning: Invalid cap_num for media direction.",
+ sdp_p->debug_str);
+ }
+ }
+
+ return (direction);
+}
+
+/*
+ * sdp_delete_all_media_direction_attrs
+ *
+ * Deletes all the media direction attributes from a given SDP level.
+ * Media direction attributes include:
+ * a=sendonly
+ * a=recvonly
+ * a=sendrecv
+ * a=inactive
+ *
+ * This function can be used in conjunction with sdp_add_new_attr, to ensure
+ * that there is only one direction attribute per level.
+ * It can also be used to delete all attributes when the client wants to
+ * advertise the default direction, i.e. a=sendrecv.
+ */
+sdp_result_e sdp_delete_all_media_direction_attrs (void *sdp_ptr, u16 level)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_mca_t *mca_p;
+ sdp_attr_t *attr_p;
+ sdp_attr_t *prev_attr_p = NULL;
+ sdp_attr_t *tmp_attr_p = NULL;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ /* Find the pointer to the attr list for this level. */
+ if (level == SDP_SESSION_LEVEL) {
+ attr_p = sdp_p->sess_attrs_p;
+ while (attr_p != NULL) {
+ if ((attr_p->type == SDP_ATTR_INACTIVE) ||
+ (attr_p->type == SDP_ATTR_SENDONLY) ||
+ (attr_p->type == SDP_ATTR_RECVONLY) ||
+ (attr_p->type == SDP_ATTR_SENDRECV)) {
+
+ tmp_attr_p = attr_p;
+
+ if (prev_attr_p == NULL) {
+ sdp_p->sess_attrs_p = attr_p->next_p;
+ } else {
+ prev_attr_p->next_p = attr_p->next_p;
+ }
+ attr_p = attr_p->next_p;
+
+ sdp_free_attr(tmp_attr_p);
+ } else {
+ prev_attr_p = attr_p;
+ attr_p = attr_p->next_p;
+ }
+ }
+ } else { /* Attr is at a media level */
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (SDP_INVALID_MEDIA_LEVEL);
+ }
+
+ attr_p = mca_p->media_attrs_p;
+ while (attr_p != NULL) {
+ if ((attr_p->type == SDP_ATTR_INACTIVE) ||
+ (attr_p->type == SDP_ATTR_SENDONLY) ||
+ (attr_p->type == SDP_ATTR_RECVONLY) ||
+ (attr_p->type == SDP_ATTR_SENDRECV)) {
+
+ tmp_attr_p = attr_p;
+
+ if (prev_attr_p == NULL) {
+ mca_p->media_attrs_p = attr_p->next_p;
+ } else {
+ prev_attr_p->next_p = attr_p->next_p;
+ }
+ attr_p = attr_p->next_p;
+
+ sdp_free_attr(tmp_attr_p);
+ } else {
+ prev_attr_p = attr_p;
+ attr_p = attr_p->next_p;
+ }
+ }
+ }
+
+ return (SDP_SUCCESS);
+}
+
+/* Since there are four different attribute names which all have the same
+ * qos parameters, all of these attributes are accessed through this same
+ * set of APIs. To distinguish between specific attributes, the application
+ * must also pass the attribute type. The attribute must be one of:
+ * SDP_ATTR_QOS, SDP_ATTR_SECURE, SDP_ATTR_X_PC_QOS, and SDP_ATTR_X_QOS.
+ */
+tinybool sdp_validate_qos_attr (sdp_attr_e qos_attr)
+{
+ if ((qos_attr == SDP_ATTR_QOS) ||
+ (qos_attr == SDP_ATTR_SECURE) ||
+ (qos_attr == SDP_ATTR_X_PC_QOS) ||
+ (qos_attr == SDP_ATTR_X_QOS) ||
+ (qos_attr == SDP_ATTR_CURR) ||
+ (qos_attr == SDP_ATTR_DES) ||
+ (qos_attr == SDP_ATTR_CONF)){
+ return (TRUE);
+ } else {
+ return (FALSE);
+ }
+}
+
+/* Function: sdp_attr_get_qos_strength
+ * Description: Returns the value of the qos attribute strength
+ * parameter specified for the given attribute. If the given
+ * attribute is not defined, SDP_QOS_STRENGTH_UNKNOWN is
+ * returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * qos_attr The specific type of qos attribute. May be
+ * qos, secure, X-pc-qos, or X-qos.
+ * inst_num The attribute instance number to check.
+ * Returns: Qos strength value.
+ */
+sdp_qos_strength_e sdp_attr_get_qos_strength (void *sdp_ptr, u16 level,
+ u8 cap_num, sdp_attr_e qos_attr, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_QOS_STRENGTH_UNKNOWN);
+ }
+
+ if (sdp_validate_qos_attr(qos_attr) == FALSE) {
+ if (sdp_p->debug_flag[SDP_DEBUG_WARNINGS]) {
+ CSFLogDebug(logTag, "%s Warning: Invalid QOS attribute specified for"
+ "get qos strength.", sdp_p->debug_str);
+ }
+ return (SDP_QOS_STRENGTH_UNKNOWN);
+ }
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, qos_attr, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s %s attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str,
+ sdp_get_attr_name(qos_attr), level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_QOS_STRENGTH_UNKNOWN);
+ } else {
+ switch (qos_attr) {
+ case SDP_ATTR_QOS:
+ return (attr_p->attr.qos.strength);
+ case SDP_ATTR_DES:
+ return (attr_p->attr.des.strength);
+ default:
+ return SDP_QOS_STRENGTH_UNKNOWN;
+
+ }
+ }
+}
+
+/* Function: sdp_attr_get_qos_direction
+ * Description: Returns the value of the qos attribute direction
+ * parameter specified for the given attribute. If the given
+ * attribute is not defined, SDP_QOS_DIR_UNKNOWN is
+ * returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * qos_attr The specific type of qos attribute. May be
+ * qos, secure, X-pc-qos, or X-qos.
+ * inst_num The attribute instance number to check.
+ * Returns: Qos direction value.
+ */
+sdp_qos_dir_e sdp_attr_get_qos_direction (void *sdp_ptr, u16 level,
+ u8 cap_num, sdp_attr_e qos_attr, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_QOS_DIR_UNKNOWN);
+ }
+
+ if (sdp_validate_qos_attr(qos_attr) == FALSE) {
+ if (sdp_p->debug_flag[SDP_DEBUG_WARNINGS]) {
+ CSFLogDebug(logTag, "%s Warning: Invalid QOS attribute specified "
+ "for get qos direction.", sdp_p->debug_str);
+ }
+ return (SDP_QOS_DIR_UNKNOWN);
+ }
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, qos_attr, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s %s attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str,
+ sdp_get_attr_name(qos_attr), level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_QOS_DIR_UNKNOWN);
+ } else {
+ switch (qos_attr) {
+ case SDP_ATTR_QOS:
+ return (attr_p->attr.qos.direction);
+ case SDP_ATTR_CURR:
+ return (attr_p->attr.curr.direction);
+ case SDP_ATTR_DES:
+ return (attr_p->attr.des.direction);
+ case SDP_ATTR_CONF:
+ return (attr_p->attr.conf.direction);
+ default:
+ return SDP_QOS_DIR_UNKNOWN;
+
+ }
+ }
+}
+
+/* Function: sdp_attr_get_qos_status_type
+ * Description: Returns the value of the qos attribute status_type
+ * parameter specified for the given attribute. If the given
+ * attribute is not defined, SDP_QOS_STATUS_TYPE_UNKNOWN is
+ * returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * qos_attr The specific type of qos attribute. May be
+ * qos, secure, X-pc-qos, or X-qos.
+ * inst_num The attribute instance number to check.
+ * Returns: Qos direction value.
+ */
+sdp_qos_status_types_e sdp_attr_get_qos_status_type (void *sdp_ptr, u16 level,
+ u8 cap_num, sdp_attr_e qos_attr, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_QOS_STATUS_TYPE_UNKNOWN);
+ }
+
+ if (sdp_validate_qos_attr(qos_attr) == FALSE) {
+ if (sdp_p->debug_flag[SDP_DEBUG_WARNINGS]) {
+ CSFLogDebug(logTag, "%s Warning: Invalid QOS attribute specified "
+ "for get qos status_type.", sdp_p->debug_str);
+ }
+ return (SDP_QOS_STATUS_TYPE_UNKNOWN);
+ }
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, qos_attr, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s %s attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str,
+ sdp_get_attr_name(qos_attr), level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_QOS_STATUS_TYPE_UNKNOWN);
+ } else {
+ switch (qos_attr) {
+ case SDP_ATTR_CURR:
+ return (attr_p->attr.curr.status_type);
+ case SDP_ATTR_DES:
+ return (attr_p->attr.des.status_type);
+ case SDP_ATTR_CONF:
+ return (attr_p->attr.conf.status_type);
+ default:
+ return SDP_QOS_STATUS_TYPE_UNKNOWN;
+
+ }
+ }
+}
+
+/* Function: sdp_attr_get_qos_confirm
+ * Description: Returns the value of the qos attribute confirm
+ * parameter specified for the given attribute. Returns TRUE if
+ * the confirm parameter is specified.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * qos_attr The specific type of qos attribute. May be
+ * qos, secure, X-pc-qos, or X-qos.
+ * inst_num The attribute instance number to check.
+ * Returns: Boolean value.
+ */
+tinybool sdp_attr_get_qos_confirm (void *sdp_ptr, u16 level,
+ u8 cap_num, sdp_attr_e qos_attr, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (FALSE);
+ }
+
+ if (sdp_validate_qos_attr(qos_attr) == FALSE) {
+ if (sdp_p->debug_flag[SDP_DEBUG_WARNINGS]) {
+ CSFLogDebug(logTag, "%s Warning: Invalid QOS attribute specified "
+ "for get qos confirm.", sdp_p->debug_str);
+ }
+ return (FALSE);
+ }
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, qos_attr, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s %s attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str,
+ sdp_get_attr_name(qos_attr), level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (FALSE);
+ } else {
+ return (attr_p->attr.qos.confirm);
+ }
+}
+
+/* Function: sdp_attr_set_qos_strength
+ * Description: Sets the qos strength value for the specified qos attribute.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * qos_attr The specific type of qos attribute. May be
+ * qos, secure, X-pc-qos, or X-qos.
+ * inst_num The attribute instance number to check.
+ * strength New qos strength parameter.
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_qos_strength (void *sdp_ptr, u16 level, u8 cap_num,
+ sdp_attr_e qos_attr, u16 inst_num,
+ sdp_qos_strength_e strength)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ if (sdp_validate_qos_attr(qos_attr) == FALSE) {
+ if (sdp_p->debug_flag[SDP_DEBUG_WARNINGS]) {
+ CSFLogDebug(logTag, "%s Warning: Invalid QOS attribute specified "
+ "for set qos strength.", sdp_p->debug_str);
+ }
+ return (SDP_FAILURE);
+ }
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, qos_attr, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s %s attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str,
+ sdp_get_attr_name(qos_attr), level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ switch (qos_attr) {
+ case SDP_ATTR_QOS:
+ attr_p->attr.qos.strength = strength;
+ return (SDP_SUCCESS);
+ case SDP_ATTR_DES:
+ attr_p->attr.des.strength = strength;
+ return (SDP_SUCCESS);
+ default:
+ return (SDP_FAILURE);
+
+ }
+ }
+}
+
+/* Function: sdp_attr_get_curr_type
+ * Description: Returns the value of the curr attribute status_type
+ * parameter specified for the given attribute. If the given
+ * attribute is not defined, SDP_CURR_UNKNOWN_TYPE is
+ * returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * qos_attr The specific type of qos attribute. May be
+ * qos, secure, X-pc-qos, or X-qos.
+ * inst_num The attribute instance number to check.
+ * Returns: Curr type value.
+ */
+sdp_curr_type_e sdp_attr_get_curr_type (void *sdp_ptr, u16 level,
+ u8 cap_num, sdp_attr_e qos_attr, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_CURR_UNKNOWN_TYPE);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, qos_attr, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s %s attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str,
+ sdp_get_attr_name(qos_attr), level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_CURR_UNKNOWN_TYPE);
+ } else {
+ return (attr_p->attr.curr.type);
+ }
+}
+
+/* Function: sdp_attr_get_des_type
+ * Description: Returns the value of the des attribute status_type
+ * parameter specified for the given attribute. If the given
+ * attribute is not defined, SDP_DES_UNKNOWN_TYPE is
+ * returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * qos_attr The specific type of qos attribute. May be
+ * qos, secure, X-pc-qos, or X-qos.
+ * inst_num The attribute instance number to check.
+ * Returns: DES type value.
+ */
+sdp_des_type_e sdp_attr_get_des_type (void *sdp_ptr, u16 level,
+ u8 cap_num, sdp_attr_e qos_attr, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_DES_UNKNOWN_TYPE);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, qos_attr, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s %s attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str,
+ sdp_get_attr_name(qos_attr), level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_DES_UNKNOWN_TYPE);
+ } else {
+ return (attr_p->attr.des.type);
+ }
+}
+
+/* Function: sdp_attr_get_conf_type
+ * Description: Returns the value of the des attribute status_type
+ * parameter specified for the given attribute. If the given
+ * attribute is not defined, SDP_CONF_UNKNOWN_TYPE is
+ * returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * qos_attr The specific type of qos attribute. May be
+ * qos, secure, X-pc-qos, or X-qos.
+ * inst_num The attribute instance number to check.
+ * Returns: CONF type value.
+ */
+sdp_conf_type_e sdp_attr_get_conf_type (void *sdp_ptr, u16 level,
+ u8 cap_num, sdp_attr_e qos_attr, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_CONF_UNKNOWN_TYPE);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, qos_attr, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s %s attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str,
+ sdp_get_attr_name(qos_attr), level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_CONF_UNKNOWN_TYPE);
+ } else {
+ return (attr_p->attr.conf.type);
+ }
+}
+
+/* Function: sdp_attr_set_curr_type
+ * Description: Returns the value of the curr attribute status_type
+ * parameter specified for the given attribute. If the given
+ * attribute is not defined, SDP_CURR_UNKNOWN_TYPE is
+ * returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * qos_attr The specific type of qos attribute. May be
+ * qos, secure, X-pc-qos, or X-qos.
+ * inst_num The attribute instance number to check.
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_curr_type (void *sdp_ptr, u16 level,
+ u8 cap_num, sdp_attr_e qos_attr, u16 inst_num,
+ sdp_curr_type_e curr_type)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ if (sdp_validate_qos_attr(qos_attr) == FALSE) {
+ if (sdp_p->debug_flag[SDP_DEBUG_WARNINGS]) {
+ CSFLogDebug(logTag, "%s Warning: Invalid curr attribute specified "
+ "for set curr type.", sdp_p->debug_str);
+ }
+ return (SDP_FAILURE);
+ }
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, qos_attr, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s %s attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str,
+ sdp_get_attr_name(qos_attr), level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ attr_p->attr.curr.type = curr_type;
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_set_des_type
+ * Description: Sets the value of the des attribute type
+ * parameter specified for the given attribute. If the given
+ * attribute is not defined, SDP_DES_UNKNOWN_TYPE is
+ * returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * qos_attr The specific type of qos attribute. May be
+ * qos, secure, X-pc-qos, or X-qos.
+ * inst_num The attribute instance number to check.
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_des_type (void *sdp_ptr, u16 level,
+ u8 cap_num, sdp_attr_e qos_attr, u16 inst_num,
+ sdp_des_type_e des_type)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ if (sdp_validate_qos_attr(qos_attr) == FALSE) {
+ if (sdp_p->debug_flag[SDP_DEBUG_WARNINGS]) {
+ CSFLogDebug(logTag, "%s Warning: Invalid des attribute specified "
+ "for set des type.", sdp_p->debug_str);
+ }
+ return (SDP_FAILURE);
+ }
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, qos_attr, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s %s attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str,
+ sdp_get_attr_name(qos_attr), level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ attr_p->attr.des.type = des_type;
+ return (SDP_SUCCESS);
+ }
+}
+
+
+/* Function: sdp_attr_set_conf_type
+ * Description: Sets the value of the conf attribute type
+ * parameter specified for the given attribute. If the given
+ * attribute is not defined, SDP_CONF_UNKNOWN_TYPE is
+ * returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * qos_attr The specific type of qos attribute. May be
+ * qos, secure, X-pc-qos, or X-qos.
+ * inst_num The attribute instance number to check.
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_conf_type (void *sdp_ptr, u16 level,
+ u8 cap_num, sdp_attr_e qos_attr, u16 inst_num,
+ sdp_conf_type_e conf_type)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ if (sdp_validate_qos_attr(qos_attr) == FALSE) {
+ if (sdp_p->debug_flag[SDP_DEBUG_WARNINGS]) {
+ CSFLogDebug(logTag, "%s Warning: Invalid conf attribute specified "
+ "for set conf type.", sdp_p->debug_str);
+ }
+ return (SDP_FAILURE);
+ }
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, qos_attr, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s %s attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str,
+ sdp_get_attr_name(qos_attr), level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ attr_p->attr.conf.type = conf_type;
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_set_qos_direction
+ * Description: Sets the qos direction value for the specified qos attribute.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * qos_attr The specific type of qos attribute. May be
+ * qos, secure, X-pc-qos, or X-qos.
+ * inst_num The attribute instance number to check.
+ * direction New qos direction parameter.
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_qos_direction (void *sdp_ptr, u16 level, u8 cap_num,
+ sdp_attr_e qos_attr, u16 inst_num,
+ sdp_qos_dir_e direction)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ if (sdp_validate_qos_attr(qos_attr) == FALSE) {
+ if (sdp_p->debug_flag[SDP_DEBUG_WARNINGS]) {
+ CSFLogDebug(logTag, "%s Warning: Invalid QOS attribute specified "
+ "for set qos direction.", sdp_p->debug_str);
+ }
+ return (SDP_FAILURE);
+ }
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, qos_attr, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s %s attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str,
+ sdp_get_attr_name(qos_attr), level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ switch (qos_attr) {
+ case SDP_ATTR_QOS:
+ attr_p->attr.qos.direction = direction;
+ return (SDP_SUCCESS);
+ case SDP_ATTR_CURR:
+ attr_p->attr.curr.direction = direction;
+ return (SDP_SUCCESS);
+ case SDP_ATTR_DES:
+ attr_p->attr.des.direction = direction;
+ return (SDP_SUCCESS);
+ case SDP_ATTR_CONF:
+ attr_p->attr.conf.direction = direction;
+ return (SDP_SUCCESS);
+ default:
+ return (SDP_FAILURE);
+
+ }
+ }
+}
+
+/* Function: sdp_attr_set_qos_status_type
+ * Description: Sets the qos status_type value for the specified qos attribute.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * qos_attr The specific type of qos attribute. May be
+ * qos, secure, X-pc-qos, or X-qos.
+ * inst_num The attribute instance number to check.
+ * direction New qos direction parameter.
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_qos_status_type (void *sdp_ptr, u16 level, u8 cap_num,
+ sdp_attr_e qos_attr, u16 inst_num,
+ sdp_qos_status_types_e status_type)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ if (sdp_validate_qos_attr(qos_attr) == FALSE) {
+ if (sdp_p->debug_flag[SDP_DEBUG_WARNINGS]) {
+ CSFLogDebug(logTag, "%s Warning: Invalid QOS attribute specified "
+ "for set qos status_type.", sdp_p->debug_str);
+ }
+ return (SDP_FAILURE);
+ }
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, qos_attr, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s %s attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str,
+ sdp_get_attr_name(qos_attr), level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ switch (qos_attr) {
+ case SDP_ATTR_CURR:
+ attr_p->attr.curr.status_type = status_type;
+ return (SDP_SUCCESS);
+ case SDP_ATTR_DES:
+ attr_p->attr.des.status_type = status_type;
+ return (SDP_SUCCESS);
+ case SDP_ATTR_CONF:
+ attr_p->attr.conf.status_type = status_type;
+ return (SDP_SUCCESS);
+ default:
+ return (SDP_FAILURE);
+
+ }
+ }
+}
+
+/* Function: sdp_attr_set_qos_confirm
+ * Description: Sets the qos confirm value for the specified qos attribute.
+ * If this parameter is TRUE, the confirm parameter will be
+ * specified when the SDP description is built.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * qos_attr The specific type of qos attribute. May be
+ * qos, secure, X-pc-qos, or X-qos.
+ * inst_num The attribute instance number to check.
+ * confirm New qos confirm parameter.
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_qos_confirm (void *sdp_ptr, u16 level, u8 cap_num,
+ sdp_attr_e qos_attr, u16 inst_num,
+ tinybool qos_confirm)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ if (sdp_validate_qos_attr(qos_attr) == FALSE) {
+ if (sdp_p->debug_flag[SDP_DEBUG_WARNINGS]) {
+ CSFLogDebug(logTag, "%s Warning: Invalid QOS attribute specified "
+ "for set qos confirm.", sdp_p->debug_str);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, qos_attr, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s %s attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str,
+ sdp_get_attr_name(qos_attr), level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ attr_p->attr.qos.confirm = qos_confirm;
+ return (SDP_SUCCESS);
+ }
+}
+
+
+/* Function: sdp_attr_get_subnet_nettype
+ * Description: Returns the value of the subnet attribute network type
+ * parameter specified for the given attribute. If the given
+ * attribute is not defined, SDP_NT_INVALID is returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Nettype value.
+ */
+sdp_nettype_e sdp_attr_get_subnet_nettype (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_NT_INVALID);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SUBNET, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Subnet attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_NT_INVALID);
+ } else {
+ return (attr_p->attr.subnet.nettype);
+ }
+}
+
+/* Function: sdp_attr_get_subnet_addrtype
+ * Description: Returns the value of the subnet attribute address type
+ * parameter specified for the given attribute. If the given
+ * attribute is not defined, SDP_AT_INVALID is returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Addrtype value.
+ */
+sdp_addrtype_e sdp_attr_get_subnet_addrtype (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_AT_INVALID);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SUBNET, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Subnet attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_AT_INVALID);
+ } else {
+ return (attr_p->attr.subnet.addrtype);
+ }
+}
+
+/* Function: sdp_attr_get_subnet_addr
+ * Description: Returns the value of the subnet attribute address
+ * parameter specified for the given attribute. If the given
+ * attribute is not defined, NULL is returned. Value is
+ * returned as a const ptr and so cannot be modified by the
+ * application.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Pointer to address or NULL.
+ */
+const char *sdp_attr_get_subnet_addr (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (NULL);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SUBNET, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Subnet attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (NULL);
+ } else {
+ return (attr_p->attr.subnet.addr);
+ }
+}
+
+/* Function: sdp_attr_get_subnet_prefix
+ * Description: Returns the value of the subnet attribute prefix
+ * parameter specified for the given attribute. If the given
+ * attribute is not defined, SDP_INVALID_PARAM is returned.
+ * Note that this is value is defined to be (-2) and is
+ * different from the return code SDP_INVALID_PARAMETER.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Prefix value or SDP_INVALID_PARAM.
+ */
+int32 sdp_attr_get_subnet_prefix (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_VALUE);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SUBNET, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Subnet attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ } else {
+ return (attr_p->attr.subnet.prefix);
+ }
+}
+
+/* Function: sdp_attr_set_subnet_nettype
+ * Description: Sets the value of the subnet attribute nettype parameter
+ * for the given attribute.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * nettype The network type for the attribute.
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_subnet_nettype (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ sdp_nettype_e nettype)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SUBNET, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Subnet attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ attr_p->attr.subnet.nettype = nettype;
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_set_subnet_addrtype
+ * Description: Sets the value of the subnet attribute addrtype parameter
+ * for the given attribute.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * addrtype The address type for the attribute.
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_subnet_addrtype (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ sdp_addrtype_e sdp_addrtype)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SUBNET, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Subnet attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ attr_p->attr.subnet.addrtype = sdp_addrtype;
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_set_subnet_addr
+ * Description: Sets the value of the subnet attribute addr parameter
+ * for the given attribute. The address is copied into the
+ * SDP structure so application memory will not be
+ * referenced by the SDP lib.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * addr Ptr to the address string for the attribute.
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_subnet_addr (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ const char *addr)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SUBNET, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Subnet attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ sstrncpy(attr_p->attr.subnet.addr, addr,
+ sizeof(attr_p->attr.subnet.addr)) ;
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_set_subnet_prefix
+ * Description: Sets the value of the subnet attribute prefix parameter
+ * for the given attribute.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * prefix Prefix value for the attribute.
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_subnet_prefix (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ int32 prefix)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SUBNET, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Subnet attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ attr_p->attr.subnet.prefix = prefix;
+ return (SDP_SUCCESS);
+ }
+}
+
+
+/* Function: sdp_attr_rtpmap_payload_valid
+ * Description: Returns true or false depending on whether an rtpmap
+ * attribute was specified with the given payload value
+ * at the given level. If it was, the instance number of
+ * that attribute is returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number of the attribute
+ * found is returned via this param.
+ * Returns: TRUE or FALSE.
+ */
+tinybool sdp_attr_rtpmap_payload_valid (void *sdp_ptr, u16 level, u8 cap_num,
+ u16 *inst_num, u16 payload_type)
+{
+ u16 i;
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ u16 num_instances;
+
+ *inst_num = 0;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (FALSE);
+ }
+
+ if (sdp_attr_num_instances(sdp_ptr, level, cap_num,
+ SDP_ATTR_RTPMAP, &num_instances) != SDP_SUCCESS) {
+ return (FALSE);
+ }
+
+ for (i=1; i <= num_instances; i++) {
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_RTPMAP, i);
+ if ((attr_p != NULL) &&
+ (attr_p->attr.transport_map.payload_num == payload_type)) {
+ *inst_num = i;
+ return (TRUE);
+ }
+ }
+
+ return (FALSE);
+}
+
+/* Function: sdp_attr_get_rtpmap_payload_type
+ * Description: Returns the value of the rtpmap attribute payload type
+ * parameter specified for the given attribute. If the given
+ * attribute is not defined, zero is returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Payload type value.
+ */
+u16 sdp_attr_get_rtpmap_payload_type (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (0);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_RTPMAP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s rtpmap attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ return (attr_p->attr.transport_map.payload_num);
+ }
+}
+
+/* Function: sdp_attr_get_rtpmap_encname
+ * Description: Returns a pointer to the value of the encoding name
+ * parameter specified for the given attribute. Value is
+ * returned as a const ptr and so cannot be modified by the
+ * application. If the given attribute is not defined, NULL
+ * will be returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Codec value or SDP_CODEC_INVALID.
+ */
+const char *sdp_attr_get_rtpmap_encname (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (NULL);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_RTPMAP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s rtpmap attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (NULL);
+ } else {
+ return (attr_p->attr.transport_map.encname);
+ }
+}
+
+/* Function: sdp_attr_get_rtpmap_clockrate
+ * Description: Returns the value of the rtpmap attribute clockrate
+ * parameter specified for the given attribute. If the given
+ * attribute is not defined, zero is returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Clockrate value.
+ */
+u32 sdp_attr_get_rtpmap_clockrate (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (0);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_RTPMAP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s rtpmap attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ return (attr_p->attr.transport_map.clockrate);
+ }
+}
+
+/* Function: sdp_attr_get_rtpmap_num_chan
+ * Description: Returns the value of the rtpmap attribute num_chan
+ * parameter specified for the given attribute. If the given
+ * attribute is not defined, zero is returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Number of channels param or zero.
+ */
+u16 sdp_attr_get_rtpmap_num_chan (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (0);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_RTPMAP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s rtpmap attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ return (attr_p->attr.transport_map.num_chan);
+ }
+}
+
+/* Function: sdp_attr_set_rtpmap_payload_type
+ * Description: Sets the value of the rtpmap attribute payload type parameter
+ * for the given attribute.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * payload_num New payload type value.
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_rtpmap_payload_type (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u16 payload_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_RTPMAP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s rtpmap attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ attr_p->attr.transport_map.payload_num = payload_num;
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_set_rtpmap_encname
+ * Description: Sets the value of the rtpmap attribute encname parameter
+ * for the given attribute. String is copied into SDP memory.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * encname Ptr to string encoding name.
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_rtpmap_encname (void *sdp_ptr, u16 level, u8 cap_num,
+ u16 inst_num, const char *encname)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_RTPMAP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s rtpmap attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ if (encname) {
+ sstrncpy(attr_p->attr.transport_map.encname, encname,
+ sizeof(attr_p->attr.transport_map.encname));
+ }
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_get_ice_attribute
+ * Description: Returns the value of an ice attribute at a given level
+ *
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * ice_attrib Returns an ice attrib string
+ * Returns:
+ * SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_SDP_PTR SDP pointer invalid
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+
+sdp_result_e sdp_attr_get_ice_attribute (void *sdp_ptr, u16 level,
+ u8 cap_num, sdp_attr_e sdp_attr, u16 inst_num,
+ char **out)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, sdp_attr, inst_num);
+ if (attr_p != NULL) {
+ *out = attr_p->attr.ice_attr;
+ return (SDP_SUCCESS);
+ } else {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s ice attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ return (SDP_FAILURE);
+}
+
+/* Function: sdp_attr_set_ice_attribute
+ * Description: Sets the value of an ice attribute parameter
+ * String is copied into SDP memory.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to set the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * ice_attrib ice attribute string to set
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_ice_attribute(void *sdp_ptr, u16 level,
+ u8 cap_num, sdp_attr_e sdp_attr, u16 inst_num, const char *ice_attrib)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, sdp_attr, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s ice attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (!ice_attrib) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ sstrncpy(attr_p->attr.ice_attr, ice_attrib, sizeof(attr_p->attr.ice_attr));
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_attr_get_rtcp_mux_attribute
+ * Description: Returns the value of an rtcp-mux attribute at a given level
+ *
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * rtcp_mux Returns an rtcp-mux attrib bool
+ * Returns:
+ * SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_SDP_PTR SDP pointer invalid
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_get_rtcp_mux_attribute (void *sdp_ptr, u16 level,
+ u8 cap_num, sdp_attr_e sdp_attr, u16 inst_num,
+ tinybool *rtcp_mux)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, sdp_attr, inst_num);
+ if (attr_p != NULL) {
+ *rtcp_mux = attr_p->attr.boolean_val;
+ return (SDP_SUCCESS);
+ } else {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s rtcp-mux attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ return (SDP_FAILURE);
+}
+
+/* Function: sdp_attr_set_rtcp_mux_attribute
+ * Description: Sets the value of an rtcp_mux attribute parameter
+ * String is copied into SDP memory.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to set the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * rtcp_mux rtcp-mux attribute bool to set
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_rtcp_mux_attribute(void *sdp_ptr, u16 level,
+ u8 cap_num, sdp_attr_e sdp_attr, u16 inst_num, const tinybool rtcp_mux)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, sdp_attr, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s rtcp-mux attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p->attr.boolean_val = rtcp_mux;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_attr_get_dtls_fingerprint_attribute
+ * Description: Returns the value of dtls fingerprint attribute at a given level
+ *
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * dtls_fingerprint Returns an dtls fingerprint attrib string
+ * Returns:
+ * SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_SDP_PTR SDP pointer invalid
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_get_dtls_fingerprint_attribute (void *sdp_ptr, u16 level,
+ u8 cap_num, sdp_attr_e sdp_attr, u16 inst_num,
+ char **out)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, sdp_attr, inst_num);
+ if (attr_p != NULL) {
+ *out = attr_p->attr.string_val;
+ return (SDP_SUCCESS);
+ } else {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s dtls fingerprint attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ return (SDP_FAILURE);
+}
+
+/* Function: sdp_attr_set_dtls_fingerprint_attribute
+ * Description: Sets the value of a dtls fingerprint attribute parameter
+ * String is copied into SDP memory.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to set the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * dtls_fingerprint fingerprint attribute string to set
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_dtls_fingerprint_attribute(void *sdp_ptr, u16 level,
+ u8 cap_num, sdp_attr_e sdp_attr, u16 inst_num, const char *dtls_fingerprint)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, sdp_attr, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s dtls fingerprint attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (!dtls_fingerprint) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ sstrncpy(attr_p->attr.string_val, dtls_fingerprint, sizeof(attr_p->attr.string_val));
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_attr_set_rtpmap_clockrate
+ * Description: Sets the value of the rtpmap attribute clockrate parameter
+ * for the given attribute.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * clockrate New clockrate value.
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_rtpmap_clockrate (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u32 clockrate)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_RTPMAP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s rtpmap attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ attr_p->attr.transport_map.clockrate = clockrate;
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_set_rtpmap_num_chan
+ * Description: Sets the value of the rtpmap attribute num_chan parameter
+ * for the given attribute.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * num_chan New number of channels value.
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_rtpmap_num_chan (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u16 num_chan)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_RTPMAP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s rtpmap attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ attr_p->attr.transport_map.num_chan = num_chan;
+ return (SDP_SUCCESS);
+ }
+}
+
+
+/* Function: sdp_attr_sprtmap_payload_valid
+ * Description: Returns true or false depending on whether an sprtmap
+ * attribute was specified with the given payload value
+ * at the given level. If it was, the instance number of
+ * that attribute is returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number of the attribute
+ * found is returned via this param.
+ * Returns: TRUE or FALSE.
+ */
+tinybool sdp_attr_sprtmap_payload_valid (void *sdp_ptr, u16 level, u8 cap_num,
+ u16 *inst_num, u16 payload_type)
+{
+ u16 i;
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ u16 num_instances;
+
+ *inst_num = 0;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (FALSE);
+ }
+
+ if (sdp_attr_num_instances(sdp_ptr, level, cap_num,
+ SDP_ATTR_SPRTMAP, &num_instances) != SDP_SUCCESS) {
+ return (FALSE);
+ }
+
+ for (i=1; i <= num_instances; i++) {
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_SPRTMAP, i);
+ if ((attr_p != NULL) &&
+ (attr_p->attr.transport_map.payload_num == payload_type)) {
+ *inst_num = i;
+ return (TRUE);
+ }
+ }
+
+ return (FALSE);
+}
+
+/* Function: sdp_attr_get_sprtmap_payload_type
+ * Description: Returns the value of the sprtmap attribute payload type
+ * parameter specified for the given attribute. If the given
+ * attribute is not defined, zero is returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Payload type value.
+ */
+u16 sdp_attr_get_sprtmap_payload_type (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (0);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_SPRTMAP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s sprtmap attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ return (attr_p->attr.transport_map.payload_num);
+ }
+}
+
+/* Function: sdp_attr_get_sprtmap_encname
+ * Description: Returns a pointer to the value of the encoding name
+ * parameter specified for the given attribute. Value is
+ * returned as a const ptr and so cannot be modified by the
+ * application. If the given attribute is not defined, NULL
+ * will be returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Codec value or SDP_CODEC_INVALID.
+ */
+const char *sdp_attr_get_sprtmap_encname (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (NULL);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_SPRTMAP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s sprtmap attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (NULL);
+ } else {
+ return (attr_p->attr.transport_map.encname);
+ }
+}
+
+/* Function: sdp_attr_get_sprtmap_clockrate
+ * Description: Returns the value of the sprtmap attribute clockrate
+ * parameter specified for the given attribute. If the given
+ * attribute is not defined, zero is returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Clockrate value.
+ */
+u32 sdp_attr_get_sprtmap_clockrate (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (0);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_SPRTMAP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s sprtmap attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ return (attr_p->attr.transport_map.clockrate);
+ }
+}
+
+/* Function: sdp_attr_get_sprtmap_num_chan
+ * Description: Returns the value of the sprtmap attribute num_chan
+ * parameter specified for the given attribute. If the given
+ * attribute is not defined, zero is returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Number of channels param or zero.
+ */
+u16 sdp_attr_get_sprtmap_num_chan (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (0);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_SPRTMAP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s sprtmap attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ return (attr_p->attr.transport_map.num_chan);
+ }
+}
+
+/* Function: sdp_attr_set_sprtmap_payload_type
+ * Description: Sets the value of the sprtmap attribute payload type parameter
+ * for the given attribute.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * payload_num New payload type value.
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_sprtmap_payload_type (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u16 payload_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_SPRTMAP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s sprtmap attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ attr_p->attr.transport_map.payload_num = payload_num;
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_set_sprtmap_encname
+ * Description: Sets the value of the sprtmap attribute encname parameter
+ * for the given attribute. String is copied into SDP memory.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * encname Ptr to string encoding name.
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_sprtmap_encname (void *sdp_ptr, u16 level, u8 cap_num,
+ u16 inst_num, const char *encname)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_SPRTMAP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s sprtmap attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ sstrncpy(attr_p->attr.transport_map.encname, encname,
+ sizeof(attr_p->attr.transport_map.encname));
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_set_sprtmap_clockrate
+ * Description: Sets the value of the sprtmap attribute clockrate parameter
+ * for the given attribute.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * clockrate New clockrate value.
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_sprtmap_clockrate (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u16 clockrate)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_SPRTMAP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s sprtmap attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ attr_p->attr.transport_map.clockrate = clockrate;
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_set_sprtmap_num_chan
+ * Description: Sets the value of the sprtmap attribute num_chan parameter
+ * for the given attribute.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * num_chan New number of channels value.
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_sprtmap_num_chan (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u16 num_chan)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_SPRTMAP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s sprtmap attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ attr_p->attr.transport_map.num_chan = num_chan;
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Note: The fmtp attribute formats currently handled are:
+ * fmtp: ,...
+ * fmtp: [annexa=yes/no] [annexb=yes/no] [bitrate=]
+ * where "value" is a numeric value > 0
+ * where each event is a single number or a range separated
+ * by a '-'.
+ * Example: fmtp:101 1,3-15,20
+ */
+
+/* Function: tinybool sdp_attr_fmtp_valid(void *sdp_ptr)
+ * Description: Returns true or false depending on whether an fmtp
+ * attribute was specified with the given payload value
+ * at the given level. If it was, the instance number of
+ * that attribute is returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: TRUE or FALSE.
+ */
+tinybool sdp_attr_fmtp_payload_valid (void *sdp_ptr, u16 level, u8 cap_num,
+ u16 *inst_num, u16 payload_type)
+{
+ u16 i;
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ u16 num_instances;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (FALSE);
+ }
+
+ if (sdp_attr_num_instances(sdp_ptr, level, cap_num,
+ SDP_ATTR_FMTP, &num_instances) != SDP_SUCCESS) {
+ return (FALSE);
+ }
+
+ for (i=1; i <= num_instances; i++) {
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, i);
+ if ((attr_p != NULL) &&
+ (attr_p->attr.fmtp.payload_num == payload_type)) {
+ *inst_num = i;
+ return (TRUE);
+ }
+ }
+
+ return (FALSE);
+}
+
+/* Function: sdp_attr_get_fmtp_payload_type
+ * Description: Returns the value of the fmtp attribute payload type
+ * parameter specified for the given attribute. If the given
+ * attribute is not defined, zero is returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Payload type value.
+ */
+u16 sdp_attr_get_fmtp_payload_type (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (0);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ return (attr_p->attr.fmtp.payload_num);
+ }
+}
+
+
+/* Function: sdp_attr_fmtp_is_range_set
+ * Description: Determines if a range of events is set in an fmtp attribute.
+ * The overall range for events is 0-255.
+ * This will return either FULL_MATCH, PARTIAL_MATCH, or NO_MATCH
+ * depending on whether all, some, or none of the specified
+ * events are defined. If the given attribute is not defined,
+ * NO_MATCH will be returned. It is up to the appl to verify
+ * the validity of the attribute before calling this routine.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * low_val Low value of the range. Range is 0-255.
+ * high_val High value of the range.
+ * Returns: SDP_FULL_MATCH, SDP_PARTIAL_MATCH, SDP_NO_MATCH
+ */
+sdp_ne_res_e sdp_attr_fmtp_is_range_set (void *sdp_ptr, u16 level, u8 cap_num,
+ u16 inst_num, u8 low_val, u8 high_val)
+{
+ u16 i;
+ u32 mapword;
+ u32 bmap;
+ u32 num_vals = 0;
+ u32 num_vals_set = 0;
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_NO_MATCH);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_NO_MATCH);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ for (i = low_val; i <= high_val; i++) {
+ num_vals++;
+ mapword = i/SDP_NE_BITS_PER_WORD;
+ bmap = SDP_NE_BIT_0 << (i%32);
+ if (fmtp_p->bmap[ mapword ] & bmap) {
+ num_vals_set++;
+ }
+ }
+
+ if (num_vals == num_vals_set) {
+ return (SDP_FULL_MATCH);
+ } else if (num_vals_set == 0) {
+ return (SDP_NO_MATCH);
+ } else {
+ return (SDP_PARTIAL_MATCH);
+ }
+}
+
+/* Function: sdp_attr_fmtp_valid
+ * Description: Determines the validity of the events in the fmtp.
+ * The overall range for events is 0-255.
+ * The user passes an event list with valid events supported by Appl.
+ * This routine will do a simple AND comparison and report the result.
+ *
+ * This will return TRUE if ftmp events are valid, and FALSE otherwise.
+ * It is up to the appl to verify the validity of the attribute
+ * before calling this routine.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * appl_maxval Max event value supported by Appl. Range is 0-255.
+ * evt_array Bitmap containing events supported by application.
+ * Returns: TRUE, FALSE
+ */
+tinybool
+sdp_attr_fmtp_valid(void *sdp_ptr, u16 level, u8 cap_num,
+ u16 inst_num, u16 appl_maxval, u32* evt_array)
+{
+ u16 i;
+ u32 mapword;
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return FALSE;
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return FALSE;
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+
+ /* Do quick test. If application max value is lower than fmtp's then error */
+ if (fmtp_p->maxval > appl_maxval)
+ return FALSE;
+
+ /* Ok, events are within range. Now check that only
+ * allowed events have been received
+ */
+ mapword = appl_maxval/SDP_NE_BITS_PER_WORD;
+ for (i=0; ibmap[i] & ~(evt_array[i])) {
+ /* Remote SDP is requesting events not supported by Application */
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+/* Function: sdp_attr_set_fmtp_payload_type
+ * Description: Sets the value of the fmtp attribute payload type parameter
+ * for the given attribute.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * payload_type New payload type value.
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_fmtp_payload_type (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u16 payload_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ attr_p->attr.fmtp.payload_num = payload_num;
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_set_fmtp_bitmap
+ * Description: Set a range of named events for an fmtp attribute.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * bmap The 8 word data array holding the bitmap
+ * Returns: SDP_SUCCESS
+ */
+sdp_result_e sdp_attr_set_fmtp_bitmap(void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u32 *bmap, u32 maxval)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->maxval = maxval;
+ memcpy(fmtp_p->bmap, bmap, SDP_NE_NUM_BMAP_WORDS * sizeof(u32) );
+
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_attr_get_fmtp_range
+ * Description: Get a range of named events for an fmtp attribute.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * bmap The 8 word data array holding the bitmap
+ * Returns: SDP_SUCCESS
+ */
+sdp_result_e sdp_attr_get_fmtp_range (void *sdp_ptr, u16 level, u8 cap_num,
+ u16 inst_num, u32 *bmap)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ memcpy(bmap, fmtp_p->bmap, SDP_NE_NUM_BMAP_WORDS * sizeof(u32) );
+
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_attr_set_fmtp_range
+ * Description: Set a range of named events for an fmtp attribute. The low
+ * value specified must be <= the high value.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * low_val The low value of the range. Range is 0-255.
+ * high_val The high value of the range. May be == low.
+ * Returns: SDP_SUCCESS
+ */
+sdp_result_e sdp_attr_set_fmtp_range (void *sdp_ptr, u16 level, u8 cap_num,
+ u16 inst_num, u8 low_val, u8 high_val)
+{
+ u16 i;
+ u32 mapword;
+ u32 bmap;
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ for (i = low_val; i <= high_val; i++) {
+ mapword = i/SDP_NE_BITS_PER_WORD;
+ bmap = SDP_NE_BIT_0 << (i%32);
+ fmtp_p->bmap[ mapword ] |= bmap;
+ }
+ if (high_val > fmtp_p->maxval) {
+ fmtp_p->maxval = high_val;
+ }
+ fmtp_p->fmtp_format = SDP_FMTP_NTE;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_attr_clear_fmtp_range
+ * Description: Clear a range of named events for an fmtp attribute. The low
+ * value specified must be <= the high value.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * low_val The low value of the range. Range is 0-255
+ * high_val The high value of the range. May be == low.
+ * Returns: SDP_SUCCESS
+ */
+sdp_result_e sdp_attr_clear_fmtp_range (void *sdp_ptr, u16 level, u8 cap_num,
+ u16 inst_num, u8 low_val, u8 high_val)
+{
+ u16 i;
+ u32 mapword;
+ u32 bmap;
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ for (i = low_val; i <= high_val; i++) {
+ mapword = i/SDP_NE_BITS_PER_WORD;
+ bmap = SDP_NE_BIT_0 << (i%32);
+ fmtp_p->bmap[ mapword ] &= ~bmap;
+ }
+ if (high_val > fmtp_p->maxval) {
+ fmtp_p->maxval = high_val;
+ }
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_attr_compare_fmtp_ranges
+ * Description: Compare the named events set of two fmtp attributes. If all
+ * events are the same (either set or not), FULL_MATCH will be
+ * returned. If no events match, NO_MATCH will be returned.
+ * Otherwise PARTIAL_MATCH will be returned. If either attr is
+ * invalid, NO_MATCH will be returned.
+ * Parameters: src_sdp_ptr The SDP handle returned by sdp_init_description.
+ * dst_sdp_ptr The SDP handle returned by sdp_init_description.
+ * src_level The level of the src fmtp attribute.
+ * dst_level The level to the dst fmtp attribute.
+ * src_cap_num The capability number of the src attr.
+ * dst_cap_num The capability number of the dst attr.
+ * src_inst_numh The attribute instance of the src attr.
+ * dst_inst_numh The attribute instance of the dst attr.
+ * Returns: SDP_FULL_MATCH, SDP_PARTIAL_MATCH, SDP_NO_MATCH.
+ */
+sdp_ne_res_e sdp_attr_compare_fmtp_ranges (void *src_sdp_ptr,void *dst_sdp_ptr,
+ u16 src_level, u16 dst_level,
+ u8 src_cap_num, u8 dst_cap_num,
+ u16 src_inst_num, u16 dst_inst_num)
+{
+ u16 i,j;
+ u32 bmap;
+ u32 num_vals_match = 0;
+ sdp_t *src_sdp_p = (sdp_t *)src_sdp_ptr;
+ sdp_t *dst_sdp_p = (sdp_t *)dst_sdp_ptr;
+ sdp_attr_t *src_attr_p;
+ sdp_attr_t *dst_attr_p;
+ sdp_fmtp_t *src_fmtp_p;
+ sdp_fmtp_t *dst_fmtp_p;
+
+ if ((sdp_verify_sdp_ptr(src_sdp_p) == FALSE) ||
+ (sdp_verify_sdp_ptr(dst_sdp_p) == FALSE)) {
+ return (SDP_NO_MATCH);
+ }
+
+ src_attr_p = sdp_find_attr(src_sdp_p, src_level, src_cap_num,
+ SDP_ATTR_FMTP, src_inst_num);
+ dst_attr_p = sdp_find_attr(dst_sdp_p, dst_level, dst_cap_num,
+ SDP_ATTR_FMTP, dst_inst_num);
+ if ((src_attr_p == NULL) || (dst_attr_p == NULL)) {
+ if (src_sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s source or destination fmtp attribute for "
+ "compare not found.", src_sdp_p->debug_str);
+ }
+ src_sdp_p->conf_p->num_invalid_param++;
+ return (SDP_NO_MATCH);
+ }
+
+ src_fmtp_p = &(src_attr_p->attr.fmtp);
+ dst_fmtp_p = &(dst_attr_p->attr.fmtp);
+ for (i = 0; i < SDP_NE_NUM_BMAP_WORDS; i++) {
+ for (j = 0; j < SDP_NE_BITS_PER_WORD; j++) {
+ bmap = SDP_NE_BIT_0 << j;
+ if ((src_fmtp_p->bmap[i] & bmap) && (dst_fmtp_p->bmap[i] & bmap)) {
+ num_vals_match++;
+ } else if ((!(src_fmtp_p->bmap[i] & bmap)) &&
+ (!(dst_fmtp_p->bmap[i] & bmap))) {
+ num_vals_match++;
+ }
+ }
+ }
+
+ if (num_vals_match == (SDP_NE_NUM_BMAP_WORDS * SDP_NE_BITS_PER_WORD)) {
+ return (SDP_FULL_MATCH);
+ } else if (num_vals_match == 0) {
+ return (SDP_NO_MATCH);
+ } else {
+ return (SDP_PARTIAL_MATCH);
+ }
+}
+
+/* Function: sdp_attr_copy_fmtp_ranges
+ * Description: Copy the named events set for one fmtp attribute to another.
+ * Parameters: src_sdp_ptr The SDP handle returned by sdp_init_description.
+ * dst_sdp_ptr The SDP handle returned by sdp_init_description.
+ * src_level The level of the src fmtp attribute.
+ * dst_level The level to the dst fmtp attribute.
+ * src_cap_num The capability number of the src attr.
+ * dst_cap_num The capability number of the dst attr.
+ * src_inst_numh The attribute instance of the src attr.
+ * dst_inst_numh The attribute instance of the dst attr.
+ * Returns: SDP_SUCCESS
+ */
+sdp_result_e sdp_attr_copy_fmtp_ranges (void *src_sdp_ptr, void *dst_sdp_ptr,
+ u16 src_level, u16 dst_level,
+ u8 src_cap_num, u8 dst_cap_num,
+ u16 src_inst_num, u16 dst_inst_num)
+{
+ u16 i;
+ sdp_t *src_sdp_p = (sdp_t *)src_sdp_ptr;
+ sdp_t *dst_sdp_p = (sdp_t *)dst_sdp_ptr;
+ sdp_attr_t *src_attr_p;
+ sdp_attr_t *dst_attr_p;
+ sdp_fmtp_t *src_fmtp_p;
+ sdp_fmtp_t *dst_fmtp_p;
+
+ if ((sdp_verify_sdp_ptr(src_sdp_p) == FALSE) ||
+ (sdp_verify_sdp_ptr(dst_sdp_p) == FALSE)) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ src_attr_p = sdp_find_attr(src_sdp_p, src_level, src_cap_num,
+ SDP_ATTR_FMTP, src_inst_num);
+ dst_attr_p = sdp_find_attr(dst_sdp_p, dst_level, dst_cap_num,
+ SDP_ATTR_FMTP, dst_inst_num);
+ if ((src_attr_p == NULL) || (dst_attr_p == NULL)) {
+ if (src_sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s source or destination fmtp attribute for "
+ "copy not found.", src_sdp_p->debug_str);
+ }
+ src_sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ src_fmtp_p = &(src_attr_p->attr.fmtp);
+ dst_fmtp_p = &(dst_attr_p->attr.fmtp);
+ dst_fmtp_p->maxval = src_fmtp_p->maxval;
+ for (i = 0; i < SDP_NE_NUM_BMAP_WORDS; i++) {
+ dst_fmtp_p->bmap[i] = src_fmtp_p->bmap[i];
+ }
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_attr_set_fmtp_annexa
+ * Description: Sets the value of the fmtp attribute annexa type parameter
+ * for the given attribute.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * annexa It is either yes or no.
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_fmtp_annexa (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ tinybool annexa)
+{
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->annexa_required = TRUE;
+ fmtp_p->annexa = annexa;
+
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_attr_set_fmtp_annexb
+ * Description: Sets the value of the fmtp attribute annexb type parameter
+ * for the given attribute.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * annexb It is either yes or no.
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_fmtp_annexb (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ tinybool annexb)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->annexb_required = TRUE;
+ fmtp_p->annexb = annexb;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_attr_get_fmtp_mode
+ * Description: Gets the value of the fmtp attribute mode parameter
+ * for the given attribute.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * payload_type payload type.
+ * Returns: mode value
+ */
+u32 sdp_attr_get_fmtp_mode_for_payload_type (void *sdp_ptr, u16 level,
+ u8 cap_num, u32 payload_type)
+{
+ u16 num_a_lines = 0;
+ int i;
+ sdp_t *sdp_p = sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (0);
+ }
+ /*
+ * Get number of FMTP attributes for the AUDIO line
+ */
+ (void) sdp_attr_num_instances(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ &num_a_lines);
+ for (i = 0; i < num_a_lines; i++) {
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, (uint16_t) (i + 1));
+ if ((attr_p != NULL) &&
+ (attr_p->attr.fmtp.payload_num == (u16)payload_type)) {
+ if (attr_p->attr.fmtp.fmtp_format == SDP_FMTP_MODE) {
+ return attr_p->attr.fmtp.mode;
+ }
+ }
+ }
+ return 0;
+}
+
+/* Function: sdp_attr_set_fmtp_mode
+ * Description: Sets the value of the fmtp attribute mode type parameter
+ * for the given attribute.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * mode in milli seconds
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_fmtp_mode (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u32 mode)
+{
+ sdp_t *sdp_p = sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_MODE;
+ fmtp_p->mode = mode;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_attr_set_fmtp_bitrate_type
+ * Description: Sets the value of the fmtp attribute bitrate type parameter
+ * for the given attribute.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * bitrate Sets the bitrate value.
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_fmtp_bitrate_type (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u32 bitrate)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+ if (bitrate <= 0) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->bitrate = bitrate;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_attr_set_fmtp_cif
+ * Description: Sets the value of the fmtp attribute cif parameter
+ * for the given attribute.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * cif Sets the CIF value for a video codec
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_fmtp_cif (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u16 cif)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+ if ((cif < SDP_MIN_CIF_VALUE) || ( cif > SDP_MAX_CIF_VALUE)) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->cif = cif;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_attr_set_fmtp_qcif
+ * Description: Sets the value of the fmtp attribute qcif parameter
+ * for the given attribute.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * qcif Sets the QCIF value for a video codec
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_fmtp_qcif (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u16 qcif)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+ if ((qcif < SDP_MIN_CIF_VALUE) || ( qcif > SDP_MAX_CIF_VALUE)) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->qcif = qcif;
+ return (SDP_SUCCESS);
+}
+/* Function: sdp_attr_set_fmtp_sqcif
+ * Description: Sets the value of the fmtp attribute sqcif parameter
+ * for the given attribute.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * sqcif Sets the SQCIF value for a video codec
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_fmtp_sqcif (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u16 sqcif)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+ if ((sqcif < SDP_MIN_CIF_VALUE) || (sqcif > SDP_MAX_CIF_VALUE)) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->sqcif = sqcif;
+ return (SDP_SUCCESS);
+}
+
+
+/* Function: sdp_attr_set_fmtp_cif4
+ * Description: Sets the value of the fmtp attribute cif4 parameter
+ * for the given attribute.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * sqcif Sets the cif4 value for a video codec
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_fmtp_cif4 (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u16 cif4)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+ if ((cif4 < SDP_MIN_CIF_VALUE) || (cif4 > SDP_MAX_CIF_VALUE)) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->cif4 = cif4;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_attr_set_fmtp_cif16
+ * Description: Sets the value of the fmtp attribute cif16 parameter
+ * for the given attribute.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * cif16 Sets the cif16 value for a video codec
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_fmtp_cif16 (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u16 cif16)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+ if ((cif16 < SDP_MIN_CIF_VALUE) || (cif16 > SDP_MAX_CIF_VALUE)) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->cif16 = cif16;
+ return (SDP_SUCCESS);
+}
+
+
+/* Function: sdp_attr_set_fmtp_maxbr
+ * Description: Sets the value of the fmtp attribute maxbr parameter
+ * for the given attribute.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * MAXBR Sets the MAXBR value for a video codec
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+*/
+
+sdp_result_e sdp_attr_set_fmtp_maxbr (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u16 maxbr)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+ if (maxbr <= 0) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->maxbr = maxbr;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_attr_set_fmtp_custom
+ * Description: Sets the value of the fmtp attribute custom parameter
+ * for the given attribute.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * CUSTOM Sets the CUSTOM value for a video codec
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+*/
+
+sdp_result_e sdp_attr_set_fmtp_custom (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u16 custom_x, u16 custom_y, u16 custom_mpi)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+ if ((custom_x <= 0) || (custom_y <= 0) || (custom_mpi <= 0)) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->custom_x = custom_x;
+ fmtp_p->custom_y = custom_y;
+ fmtp_p->custom_mpi = custom_mpi;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_attr_set_fmtp_par
+ * Description: Sets the value of the fmtp attribute PAR parameter
+ * for the given attribute.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * PAR Sets the PAR width/height value
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+*/
+
+sdp_result_e sdp_attr_set_fmtp_par (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u16 par_width, u16 par_height)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+ if ((par_width <= 0) || (par_height <= 0)) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->par_width = par_width;
+ fmtp_p->par_height = par_height;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_attr_set_fmtp_cpcf
+ * Description: Sets the value of the fmtp attribute CPCF parameter
+ * for the given attribute.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * CPCF Sets the CPCF value
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+*/
+
+sdp_result_e sdp_attr_set_fmtp_cpcf (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u16 cpcf)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+ if (cpcf <= 0) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->cpcf = cpcf;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_attr_set_fmtp_bpp
+ * Description: Sets the value of the fmtp attribute BPP parameter
+ * for the given attribute.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * BPP Sets the BPP value
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+*/
+
+sdp_result_e sdp_attr_set_fmtp_bpp (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u16 bpp)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+ if (bpp <= 0) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->bpp = bpp;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_attr_set_fmtp_hrd
+ * Description: Sets the value of the fmtp attribute HRD parameter
+ * for the given attribute.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * HRD Sets the HRD value
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+
+sdp_result_e sdp_attr_set_fmtp_hrd (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u16 hrd)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+ if (hrd <= 0) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->hrd = hrd;
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_attr_set_fmtp_h263_num_params (void *sdp_ptr, int16 level,
+ u8 cap_num, u16 inst_num,
+ int16 profile,
+ u16 h263_level,
+ tinybool interlace)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+
+ if ((profile >= SDP_MIN_PROFILE_LEVEL_VALUE) &&
+ (profile <= SDP_MAX_PROFILE_VALUE)) {
+ fmtp_p->profile = profile;
+ }
+
+ if ((level >= SDP_MIN_PROFILE_LEVEL_VALUE) &&
+ (level <= SDP_MAX_LEVEL_VALUE)) {
+ fmtp_p->level = h263_level;
+ }
+
+ if (interlace) {
+ fmtp_p->is_interlace = TRUE;
+ } else {
+ fmtp_p->is_interlace = FALSE;
+ }
+
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_attr_set_fmtp_profile_level_id (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ const char *profile_level_id)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ if (profile_level_id) {
+ sstrncpy(fmtp_p->profile_level_id, profile_level_id,
+ SDP_MAX_STRING_LEN+1);
+ }
+
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_attr_set_fmtp_parameter_sets (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ const char *parameter_sets)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ if (parameter_sets) {
+ sstrncpy(fmtp_p->parameter_sets, parameter_sets, SDP_MAX_STRING_LEN+1);
+ }
+
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_attr_set_fmtp_pack_mode (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u16 pack_mode)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+ if (pack_mode > SDP_MAX_PACKETIZATION_MODE_VALUE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->packetization_mode = pack_mode;
+
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_attr_set_fmtp_level_asymmetry_allowed (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u16 asym_allowed)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->level_asymmetry_allowed = asym_allowed;
+
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_attr_set_fmtp_deint_buf_req (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u32 deint_buf_req)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->deint_buf_req = deint_buf_req;
+ fmtp_p->flag |= SDP_DEINT_BUF_REQ_FLAG;
+
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_attr_set_fmtp_init_buf_time (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u32 init_buf_time)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->init_buf_time = init_buf_time;
+ fmtp_p->flag |= SDP_INIT_BUF_TIME_FLAG;
+
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_attr_set_fmtp_max_don_diff (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u32 max_don_diff)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->max_don_diff = max_don_diff;
+
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_attr_set_fmtp_interleaving_depth (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u16 interleaving_depth)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->interleaving_depth = interleaving_depth;
+
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_attr_set_fmtp_redundant_pic_cap (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ tinybool redundant_pic_cap)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+
+ if (redundant_pic_cap > 1) {
+ return (SDP_FAILURE);
+ } else {
+ fmtp_p->redundant_pic_cap = redundant_pic_cap;
+ return (SDP_SUCCESS);
+ }
+}
+
+sdp_result_e sdp_attr_set_fmtp_max_mbps (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u32 max_mbps)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+
+ if (max_mbps > 0) {
+ fmtp_p->max_mbps = max_mbps;
+ return (SDP_SUCCESS);
+ } else {
+ return (SDP_FAILURE);
+ }
+}
+
+sdp_result_e sdp_attr_set_fmtp_max_fs (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u32 max_fs)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+
+ if (max_fs > 0) {
+ fmtp_p->max_fs = max_fs;
+ return (SDP_SUCCESS);
+ } else {
+ return (SDP_FAILURE);
+ }
+}
+
+sdp_result_e sdp_attr_set_fmtp_max_br (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u32 max_br)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+
+ if (max_br > 0) {
+ fmtp_p->max_br = max_br;
+ return (SDP_SUCCESS);
+ } else {
+ return (SDP_FAILURE);
+ }
+}
+
+sdp_result_e sdp_attr_set_fmtp_max_average_bitrate (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u32 maxaveragebitrate)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+
+ if (maxaveragebitrate > 0) {
+ fmtp_p->maxaveragebitrate = maxaveragebitrate;
+ return (SDP_SUCCESS);
+ } else {
+ return (SDP_FAILURE);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_max_average_bitrate
+ * Description: Gets the value of the fmtp attribute- maxaveragebitrate parameter for the OPUS codec
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: max-br value.
+ */
+
+sdp_result_e sdp_attr_get_fmtp_max_average_bitrate (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u32* val)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, 1);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ *val = attr_p->attr.fmtp.maxaveragebitrate;
+ return (SDP_SUCCESS);
+ }
+}
+
+
+sdp_result_e sdp_attr_set_fmtp_usedtx (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ tinybool usedtx)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+
+ if (usedtx == TRUE) {
+ fmtp_p->usedtx = 1;
+ } else {
+ fmtp_p->usedtx = 0;
+ }
+
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_attr_get_fmtp_usedtx
+ * Description: Gets the value of the fmtp attribute- usedtx parameter for the OPUS codec
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: usedtx value.
+ */
+
+sdp_result_e sdp_attr_get_fmtp_usedtx (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, tinybool* val)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ *val = (tinybool)attr_p->attr.fmtp.usedtx;
+ return (SDP_SUCCESS);
+ }
+}
+
+sdp_result_e sdp_attr_set_fmtp_stereo (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ tinybool stereo)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+
+ if (stereo == TRUE) {
+ fmtp_p->stereo = 1;
+ } else {
+ fmtp_p->stereo = 0;
+ }
+
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_attr_get_fmtp_usedtx
+ * Description: Gets the value of the fmtp attribute- usedtx parameter for the OPUS codec
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: stereo value.
+ */
+
+sdp_result_e sdp_attr_get_fmtp_stereo (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, tinybool* val)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ *val = (tinybool)attr_p->attr.fmtp.stereo;
+ return (SDP_SUCCESS);
+ }
+}
+
+sdp_result_e sdp_attr_set_fmtp_useinbandfec (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ tinybool useinbandfec)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+
+ if (useinbandfec == TRUE) {
+ fmtp_p->useinbandfec = 1;
+ } else {
+ fmtp_p->useinbandfec = 0;
+ }
+
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_attr_get_fmtp_useinbandfec
+ * Description: Gets the value of the fmtp attribute useinbandfec parameter for the OPUS codec
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: useinbandfec value.
+ */
+
+sdp_result_e sdp_attr_get_fmtp_useinbandfec (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, tinybool* val)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ *val = (tinybool)attr_p->attr.fmtp.useinbandfec;
+ return (SDP_SUCCESS);
+ }
+}
+
+sdp_result_e sdp_attr_set_fmtp_maxcodedaudiobandwidth (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ const char *maxcodedaudiobandwidth)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ if (maxcodedaudiobandwidth) {
+ sstrncpy(fmtp_p->maxcodedaudiobandwidth, maxcodedaudiobandwidth,
+ SDP_MAX_STRING_LEN+1);
+ }
+
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_attr_get_fmtp_maxcodedaudiobandwidth
+ * Description: Gets the value of the fmtp attribute maxcodedaudiobandwidth parameter for OPUS codec
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: maxcodedaudiobandwidth value.
+ */
+char* sdp_attr_get_fmtp_maxcodedaudiobandwidth (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (0);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ return (attr_p->attr.fmtp.maxcodedaudiobandwidth);
+ }
+}
+
+sdp_result_e sdp_attr_set_fmtp_cbr (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ tinybool cbr)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+
+ if (cbr == TRUE) {
+ fmtp_p->cbr = 1;
+ } else {
+ fmtp_p->cbr = 0;
+ }
+
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_attr_get_fmtp_cbr
+ * Description: Gets the value of the fmtp attribute cbr parameter for the OPUS codec
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: cbr value.
+ */
+
+sdp_result_e sdp_attr_get_fmtp_cbr (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, tinybool* val)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ *val = (tinybool)attr_p->attr.fmtp.cbr;
+ return (SDP_SUCCESS);
+ }
+}
+
+sdp_result_e sdp_attr_get_fmtp_streams (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u32* val)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (!attr_p) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ *val = attr_p->attr.fmtp.streams;
+ return (SDP_SUCCESS);
+ }
+}
+
+sdp_result_e sdp_attr_set_fmtp_streams (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u32 streams)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (!attr_p) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_DATACHANNEL;
+
+ if (streams > 0) {
+ fmtp_p->streams = streams;
+ return (SDP_SUCCESS);
+ } else {
+ return (SDP_FAILURE);
+ }
+}
+
+sdp_result_e sdp_attr_set_fmtp_data_channel_protocol (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ const char *protocol)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (!attr_p) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_DATACHANNEL;
+ if (protocol) {
+ sstrncpy(fmtp_p->protocol, protocol,
+ SDP_MAX_STRING_LEN+1);
+ }
+
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_attr_get_fmtp_data_channel_protocol (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, char* protocol)
+{
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (!attr_p) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ sstrncpy(protocol, attr_p->attr.fmtp.protocol, SDP_MAX_STRING_LEN+1);
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_attr_set_fmtp_max_cpb (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u32 max_cpb)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+
+ if (max_cpb > 0) {
+ fmtp_p->max_cpb = max_cpb;
+ return (SDP_SUCCESS);
+ } else {
+ return (SDP_FAILURE);
+ }
+}
+
+sdp_result_e sdp_attr_set_fmtp_max_dpb (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u32 max_dpb)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+
+ if (max_dpb > 0) {
+ fmtp_p->max_dpb = max_dpb;
+ return (SDP_SUCCESS);
+ } else {
+ return (SDP_FAILURE);
+ }
+}
+
+sdp_result_e sdp_attr_set_fmtp_max_rcmd_nalu_size (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u32 max_rcmd_nalu_size)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->max_rcmd_nalu_size = max_rcmd_nalu_size;
+ fmtp_p->flag |= SDP_MAX_RCMD_NALU_SIZE_FLAG;
+
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_attr_set_fmtp_deint_buf_cap (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u32 deint_buf_cap)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->deint_buf_cap = deint_buf_cap;
+ fmtp_p->flag |= SDP_DEINT_BUF_CAP_FLAG;
+
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_attr_set_fmtp_h264_parameter_add (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ tinybool parameter_add)
+{
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->parameter_add = parameter_add;
+
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_attr_set_fmtp_h261_annex_params (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ tinybool annex_d) {
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+
+ fmtp_p->annex_d = annex_d;
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_attr_set_fmtp_h263_annex_params (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ tinybool annex_f,
+ tinybool annex_i,
+ tinybool annex_j,
+ tinybool annex_t,
+ u16 annex_k_val,
+ u16 annex_n_val,
+ u16 annex_p_val_picture_resize,
+ u16 annex_p_val_warp)
+
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+
+ fmtp_p->annex_f = annex_f;
+ fmtp_p->annex_i = annex_i;
+ fmtp_p->annex_j = annex_j;
+ fmtp_p->annex_t = annex_t;
+
+ fmtp_p->annex_k_val = annex_k_val;
+ fmtp_p->annex_n_val = annex_n_val;
+
+ fmtp_p->annex_p_val_picture_resize = annex_p_val_picture_resize;
+ fmtp_p->annex_p_val_warp = annex_p_val_warp;
+
+ return (SDP_SUCCESS);
+}
+
+
+
+/* Function: sdp_attr_fmtp_is_annexb_set
+ * Description: Gives the value of the fmtp attribute annexb type parameter
+ * for the given attribute.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ *
+ *
+ * Returns: TRUE or FALSE.
+ */
+tinybool sdp_attr_fmtp_is_annexb_set (void *sdp_ptr, u16 level, u8 cap_num,
+ u16 inst_num)
+{
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (FALSE);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (FALSE);
+ } else {
+ return (attr_p->attr.fmtp.annexb);
+ }
+}
+
+/* Function: sdp_attr_fmtp_is_annexa_set
+ * Description: Gives the value of the fmtp attribute annexa type parameter
+ * for the given attribute.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ *
+ *
+ * Returns: TRUE or FALSE.
+ */
+tinybool sdp_attr_fmtp_is_annexa_set (void *sdp_ptr, u16 level, u8 cap_num,
+ u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (FALSE);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (FALSE);
+ } else {
+ return (attr_p->attr.fmtp.annexa);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_bitrate_type
+ * Description: Gets the value of the fmtp attribute bitrate type parameter
+ * for the given attribute.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Bitrate type value.
+ */
+int32 sdp_attr_get_fmtp_bitrate_type (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_VALUE);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ } else {
+ return (attr_p->attr.fmtp.bitrate);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_qcif
+ * Description: Gets the value of the fmtp attribute QCIF type parameter
+ * for a given Video codec.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: QCIF value.
+ */
+int32 sdp_attr_get_fmtp_qcif (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_VALUE);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ } else {
+ return (attr_p->attr.fmtp.qcif);
+ }
+}
+/* Function: sdp_attr_get_fmtp_cif
+ * Description: Gets the value of the fmtp attribute CIF type parameter
+ * for a given Video codec.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: CIF value.
+ */
+int32 sdp_attr_get_fmtp_cif (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_VALUE);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ } else {
+ return (attr_p->attr.fmtp.cif);
+ }
+}
+
+
+/* Function: sdp_attr_get_fmtp_sqcif
+ * Description: Gets the value of the fmtp attribute sqcif type parameter
+ * for a given Video codec.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: sqcif value.
+ */
+int32 sdp_attr_get_fmtp_sqcif (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_VALUE);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ } else {
+ return (attr_p->attr.fmtp.sqcif);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_cif4
+ * Description: Gets the value of the fmtp attribute CIF4 type parameter
+ * for a given Video codec.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: CIF4 value.
+ */
+int32 sdp_attr_get_fmtp_cif4 (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_VALUE);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ } else {
+ return (attr_p->attr.fmtp.cif4);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_cif16
+ * Description: Gets the value of the fmtp attribute CIF16 type parameter
+ * for a given Video codec.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: CIF16 value.
+ */
+
+int32 sdp_attr_get_fmtp_cif16 (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_VALUE);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ } else {
+ return (attr_p->attr.fmtp.cif16);
+ }
+}
+
+
+/* Function: sdp_attr_get_fmtp_maxbr
+ * Description: Gets the value of the fmtp attribute MAXBR type parameter
+ * for a given Video codec.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: MAXBR value.
+ */
+int32 sdp_attr_get_fmtp_maxbr (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_VALUE);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ } else {
+ return (attr_p->attr.fmtp.maxbr);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_custom_x
+ * Description: Gets the value of the fmtp attribute CUSTOM type parameter
+ * for a given Video codec.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: CUSTOM x value.
+ */
+
+int32 sdp_attr_get_fmtp_custom_x (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_VALUE);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ } else {
+ return (attr_p->attr.fmtp.custom_x);
+ }
+}
+/* Function: sdp_attr_get_fmtp_custom_y
+ * Description: Gets the value of the fmtp attribute custom_y type parameter
+ * for a given Video codec.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: CUSTOM Y-AXIS value.
+ */
+
+int32 sdp_attr_get_fmtp_custom_y (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_VALUE);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ } else {
+ return (attr_p->attr.fmtp.custom_y);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_custom_mpi
+ * Description: Gets the value of the fmtp attribute CUSTOM type parameter
+ * for a given Video codec.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: CUSTOM MPI value.
+ */
+
+int32 sdp_attr_get_fmtp_custom_mpi (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_VALUE);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ } else {
+ return (attr_p->attr.fmtp.custom_mpi);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_par_width
+ * Description: Gets the value of the fmtp attribute PAR (width) parameter
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: PAR - width value.
+ */
+int32 sdp_attr_get_fmtp_par_width (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_VALUE);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ } else {
+ return (attr_p->attr.fmtp.par_width);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_par_height
+ * Description: Gets the value of the fmtp attribute PAR (height) parameter
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: PAR - height value.
+ */
+int32 sdp_attr_get_fmtp_par_height (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_VALUE);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ } else {
+ return (attr_p->attr.fmtp.par_height);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_cpcf
+ * Description: Gets the value of the fmtp attribute- CPCF parameter
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: CPCF value.
+ */
+int32 sdp_attr_get_fmtp_cpcf (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_VALUE);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ } else {
+ return (attr_p->attr.fmtp.cpcf);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_bpp
+ * Description: Gets the value of the fmtp attribute- BPP parameter
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: BPP value.
+ */
+int32 sdp_attr_get_fmtp_bpp (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_VALUE);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ } else {
+ return (attr_p->attr.fmtp.bpp);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_hrd
+ * Description: Gets the value of the fmtp attribute- HRD parameter
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: HRD value.
+ */
+int32 sdp_attr_get_fmtp_hrd (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_VALUE);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ } else {
+ return (attr_p->attr.fmtp.hrd);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_profile
+ * Description: Gets the value of the fmtp attribute- PROFILE parameter
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: PROFILE value.
+ */
+int32 sdp_attr_get_fmtp_profile (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_VALUE);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ } else {
+ return (attr_p->attr.fmtp.profile);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_level
+ * Description: Gets the value of the fmtp attribute- LEVEL parameter
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: LEVEL value.
+ */
+int32 sdp_attr_get_fmtp_level (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_VALUE);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ } else {
+ return (attr_p->attr.fmtp.level);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_interlace
+ * Description: Checks if INTERLACE parameter is set.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: TRUE if INTERLACE is present and FALSE if INTERLACE is absent.
+ */
+tinybool sdp_attr_get_fmtp_interlace (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return FALSE;
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return FALSE;
+ } else {
+ return (attr_p->attr.fmtp.is_interlace);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_pack_mode
+ * Description: Gets the value of the fmtp attribute- packetization-mode parameter for H.264 codec
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: packetization-mode value in the range 0 - 2.
+ */
+
+sdp_result_e sdp_attr_get_fmtp_pack_mode (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u16 *val)
+{
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ *val = attr_p->attr.fmtp.packetization_mode;
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_level_asymmetry_allowed
+ * Description: Gets the value of the fmtp attribute- level-asymmetry-allowed parameter for H.264 codec
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: level asymmetry allowed value (0 or 1).
+ */
+
+sdp_result_e sdp_attr_get_fmtp_level_asymmetry_allowed (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u16 *val)
+{
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ *val = attr_p->attr.fmtp.level_asymmetry_allowed;
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_profile_id
+ * Description: Gets the value of the fmtp attribute- profile-level-id parameter for H.264 codec
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: profile-level-id value.
+ */
+const char* sdp_attr_get_fmtp_profile_id (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (0);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ return (attr_p->attr.fmtp.profile_level_id);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_param_sets
+ * Description: Gets the value of the fmtp attribute- parameter-sets parameter for H.264 codec
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: parameter-sets value.
+ */
+const char* sdp_attr_get_fmtp_param_sets (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (0);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ return (attr_p->attr.fmtp.parameter_sets);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_interleaving_depth
+ * Description: Gets the value of the fmtp attribute- interleaving_depth parameter for H.264 codec
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: interleaving_depth value
+ */
+
+sdp_result_e sdp_attr_get_fmtp_interleaving_depth (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u16* val)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ *val = attr_p->attr.fmtp.interleaving_depth;
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_deint_buf_req
+ * Description: Gets the value of the fmtp attribute- deint-buf-req parameter for H.264 codec
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: deint-buf-req value.
+ */
+
+sdp_result_e sdp_attr_get_fmtp_deint_buf_req (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u32 *val)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ if (attr_p->attr.fmtp.flag & SDP_DEINT_BUF_REQ_FLAG) {
+ *val = attr_p->attr.fmtp.deint_buf_req;
+ return (SDP_SUCCESS);
+ } else {
+ return (SDP_FAILURE);
+ }
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_max_don_diff
+ * Description: Gets the value of the fmtp attribute- max-don-diff parameter for H.264 codec
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: max-don-diff value.
+ */
+sdp_result_e sdp_attr_get_fmtp_max_don_diff (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u32 *val)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ *val = attr_p->attr.fmtp.max_don_diff;
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_init_buf_time
+ * Description: Gets the value of the fmtp attribute- init-buf-time parameter for H.264 codec
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: init-buf-time value.
+ */
+sdp_result_e sdp_attr_get_fmtp_init_buf_time (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u32 *val)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ if (attr_p->attr.fmtp.flag & SDP_INIT_BUF_TIME_FLAG) {
+ *val = attr_p->attr.fmtp.init_buf_time;
+ return (SDP_SUCCESS);
+ } else {
+ return (SDP_FAILURE);
+ }
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_max_mbps
+ * Description: Gets the value of the fmtp attribute- max-mbps parameter for H.264 codec
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: max-mbps value.
+ */
+
+sdp_result_e sdp_attr_get_fmtp_max_mbps (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u32 *val)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ *val = attr_p->attr.fmtp.max_mbps;
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_max_fs
+ * Description: Gets the value of the fmtp attribute- max-fs parameter for H.264 codec
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: max-fs value.
+ */
+
+sdp_result_e sdp_attr_get_fmtp_max_fs (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u32 *val)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ *val = attr_p->attr.fmtp.max_fs;
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_max_cpb
+ * Description: Gets the value of the fmtp attribute- max-cpb parameter for H.264 codec
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: max-cpb value.
+ */
+
+sdp_result_e sdp_attr_get_fmtp_max_cpb (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u32 *val)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ *val = attr_p->attr.fmtp.max_cpb;
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_max_dpb
+ * Description: Gets the value of the fmtp attribute- max-dpb parameter for H.264 codec
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: max-dpb value.
+ */
+
+sdp_result_e sdp_attr_get_fmtp_max_dpb (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u32 *val)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ *val = attr_p->attr.fmtp.max_dpb;
+ return (SDP_SUCCESS);
+ }
+}
+
+
+/* Function: sdp_attr_get_fmtp_max_br
+ * Description: Gets the value of the fmtp attribute- max-br parameter for H.264 codec
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: max-br value.
+ */
+
+sdp_result_e sdp_attr_get_fmtp_max_br (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u32* val)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ *val = attr_p->attr.fmtp.max_br;
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_fmtp_is_redundant_pic_cap
+ * Description: Gets the value of the fmtp attribute- redundant_pic_cap parameter for H.264 codec
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: redundant-pic-cap value.
+ */
+tinybool sdp_attr_fmtp_is_redundant_pic_cap (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (FALSE);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (FALSE);
+ } else {
+ return (attr_p->attr.fmtp.redundant_pic_cap);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_deint_buf_cap
+ * Description: Gets the value of the fmtp attribute- deint-buf-cap parameter for H.264 codec
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: deint-buf-cap value.
+ */
+
+sdp_result_e sdp_attr_get_fmtp_deint_buf_cap (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u32 *val)
+{
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ if (attr_p->attr.fmtp.flag & SDP_DEINT_BUF_CAP_FLAG) {
+ *val = attr_p->attr.fmtp.deint_buf_cap;
+ return (SDP_SUCCESS);
+ } else {
+ return (SDP_FAILURE);
+ }
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_max_rcmd_nalu_size
+ * Description: Gets the value of the fmtp attribute- max-rcmd-nalu-size parameter for H.264 codec
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: max-rcmd-nalu-size value.
+ */
+sdp_result_e sdp_attr_get_fmtp_max_rcmd_nalu_size (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u32 *val)
+{
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ if (attr_p->attr.fmtp.flag & SDP_MAX_RCMD_NALU_SIZE_FLAG) {
+ *val = attr_p->attr.fmtp.max_rcmd_nalu_size;
+ return (SDP_SUCCESS);
+ } else {
+ return (SDP_FAILURE);
+ }
+ }
+}
+
+/* Function: sdp_attr_fmtp_is_parameter_add
+ * Description: Gets the value of the fmtp attribute- parameter-add for H.264 codec
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: TRUE/FALSE ( parameter-add is boolean)
+ */
+tinybool sdp_attr_fmtp_is_parameter_add (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (FALSE);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (FALSE);
+ } else {
+ return (attr_p->attr.fmtp.parameter_add);
+ }
+}
+
+/****** Following functions are get routines for Annex values
+ * For each Annex support, the get routine will return the boolean TRUE/FALSE
+ * Some Annexures for Video codecs have values defined . In those cases,
+ * (e.g Annex K, P ) , the return values are not boolean.
+ *
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Annex value
+ */
+
+tinybool sdp_attr_get_fmtp_annex_d (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (FALSE);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (FALSE);
+ } else {
+ return (attr_p->attr.fmtp.annex_d);
+ }
+}
+
+tinybool sdp_attr_get_fmtp_annex_f (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (FALSE);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (FALSE);
+ } else {
+ return (attr_p->attr.fmtp.annex_f);
+ }
+}
+
+tinybool sdp_attr_get_fmtp_annex_i (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (FALSE);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (FALSE);
+ } else {
+ return (attr_p->attr.fmtp.annex_i);
+ }
+}
+
+tinybool sdp_attr_get_fmtp_annex_j (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (FALSE);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (FALSE);
+ } else {
+ return (attr_p->attr.fmtp.annex_j);
+ }
+}
+
+tinybool sdp_attr_get_fmtp_annex_t (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (FALSE);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (FALSE);
+ } else {
+ return (attr_p->attr.fmtp.annex_t);
+ }
+}
+
+int32 sdp_attr_get_fmtp_annex_k_val (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_VALUE);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ } else {
+ return (attr_p->attr.fmtp.annex_k_val);
+ }
+}
+
+int32 sdp_attr_get_fmtp_annex_n_val (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_VALUE);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ } else {
+ return (attr_p->attr.fmtp.annex_n_val);
+ }
+}
+
+int32 sdp_attr_get_fmtp_annex_p_picture_resize (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_VALUE);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ } else {
+ return (attr_p->attr.fmtp.annex_p_val_picture_resize);
+ }
+}
+
+int32 sdp_attr_get_fmtp_annex_p_warp (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_VALUE);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ } else {
+ return (attr_p->attr.fmtp.annex_p_val_warp);
+ }
+}
+
+/* Function: sdp_attr_fmtp_get_fmtp_format
+ * Description: Gives the value of the fmtp attribute fmtp_format
+ * type parameter
+ * for the given attribute.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ *
+ *
+ * Returns: Enum type sdp_fmtp_format_type_e
+ */
+sdp_fmtp_format_type_e sdp_attr_fmtp_get_fmtp_format (void *sdp_ptr,
+ u16 level, u8 cap_num,
+ u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_FMTP_UNKNOWN_TYPE);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_FMTP_UNKNOWN_TYPE);
+ } else {
+ return (attr_p->attr.fmtp.fmtp_format);
+ }
+}
+
+/* Function: sdp_attr_get_pccodec_num_payload_types
+ * Description: Returns the number of payload types specified for the
+ * given X-pc-codec attribute. If the given attribute is not
+ * defined, zero is returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Number of payload types.
+ */
+u16 sdp_attr_get_pccodec_num_payload_types (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (0);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_X_PC_CODEC,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s X-pc-codec attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ return (attr_p->attr.pccodec.num_payloads);
+ }
+}
+
+/* Function: sdp_attr_get_pccodec_payload_type
+ * Description: Returns the value of the specified payload type for the
+ * given X-pc-codec attribute. If the given attribute is not
+ * defined, zero is returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * payload_num The payload number to get. Range is (1 -
+ * max num payloads).
+ * Returns: Payload type.
+ */
+u16 sdp_attr_get_pccodec_payload_type (void *sdp_ptr, u16 level, u8 cap_num,
+ u16 inst_num, u16 payload_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (0);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_X_PC_CODEC,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s X-pc-codec attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ if ((payload_num < 1) ||
+ (payload_num > attr_p->attr.pccodec.num_payloads)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s X-pc-codec attribute, level %u instance %u, "
+ "invalid payload number %u requested.",
+ sdp_p->debug_str, level, inst_num, payload_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ return (attr_p->attr.pccodec.payload_type[payload_num-1]);
+ }
+ }
+}
+
+/* Function: sdp_attr_add_pccodec_payload_type
+ * Description: Add a new value to the list of payload types specified for
+ * the given X-pc-codec attribute. The payload type will be
+ * added to the end of the list so these values should be added
+ * in the order they will be displayed within the attribute.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * payload_type The payload type to add.
+ * Returns: SDP_SUCCESS Payload type was added successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_add_pccodec_payload_type (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u16 payload_type)
+{
+ u16 payload_num;
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_X_PC_CODEC,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s X-pc-codec attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ payload_num = attr_p->attr.pccodec.num_payloads++;
+ attr_p->attr.pccodec.payload_type[payload_num] = payload_type;
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_get_xcap_first_cap_num
+ * Description: Gets the first capability number valid for the specified
+ * X-cap attribute instance. If the capability is not
+ * defined, zero is returned.
+ * Note: cap_num is not specified. It must be zero.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the capability.
+ * inst_num The X-cap instance number to check.
+ * Returns: Capability number or zero.
+ */
+u16 sdp_attr_get_xcap_first_cap_num (void *sdp_ptr, u16 level, u16 inst_num)
+{
+ u16 cap_num=1;
+ u16 attr_count=0;
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (0);
+ }
+
+ if (level == SDP_SESSION_LEVEL) {
+ for (attr_p = sdp_p->sess_attrs_p; attr_p != NULL;
+ attr_p = attr_p->next_p) {
+ if (attr_p->type == SDP_ATTR_X_CAP) {
+ attr_count++;
+ if (attr_count == inst_num) {
+ return (cap_num);
+ } else {
+ cap_num += attr_p->attr.cap_p->num_payloads;
+ }
+ }
+ }
+ } else { /* Capability is at a media level */
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ }
+ for (attr_p = mca_p->media_attrs_p; attr_p != NULL;
+ attr_p = attr_p->next_p) {
+ if (attr_p->type == SDP_ATTR_X_CAP) {
+ attr_count++;
+ if (attr_count == inst_num) {
+ return (cap_num);
+ } else {
+ cap_num += attr_p->attr.cap_p->num_payloads;
+ }
+ }
+ }
+ } /* Attr is at a media level */
+
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s X-cap attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+}
+
+/* Function: sdp_attr_get_xcap_media_type
+ * Description: Returns the media type specified for the given X-cap
+ * attribute. If the given attribute is not defined,
+ * SDP_MEDIA_INVALID is returned.
+ * Note: cap_num is not specified. It must be zero.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * inst_num The attribute instance number to check.
+ * Returns: Media type or SDP_MEDIA_INVALID.
+ */
+sdp_media_e sdp_attr_get_xcap_media_type (void *sdp_ptr, u16 level,
+ u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_mca_t *cap_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_MEDIA_INVALID);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_X_CAP, inst_num);
+ if ((attr_p == NULL) || (attr_p->attr.cap_p == NULL)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s X-cap attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_MEDIA_INVALID);
+ } else {
+ cap_p = attr_p->attr.cap_p;
+ return (cap_p->media);
+ }
+}
+
+/* Function: sdp_attr_get_xcap_transport_type
+ * Description: Returns the transport type specified for the given X-cap
+ * attribute. If the given attribute is not defined,
+ * SDP_TRANSPORT_INVALID is returned.
+ * Note: cap_num is not specified. It must be zero.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * inst_num The attribute instance number to check.
+ * Returns: Media type or SDP_TRANSPORT_INVALID.
+ */
+sdp_transport_e sdp_attr_get_xcap_transport_type (void *sdp_ptr, u16 level,
+ u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_mca_t *cap_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_TRANSPORT_INVALID);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_X_CAP,
+ inst_num);
+ if ((attr_p == NULL) || (attr_p->attr.cap_p == NULL)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s X-cap attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_TRANSPORT_INVALID);
+ } else {
+ cap_p = attr_p->attr.cap_p;
+ return (cap_p->transport);
+ }
+}
+
+/* Function: sdp_attr_get_xcap_num_payload_types
+ * Description: Returns the number of payload types associated with the
+ * specified X-cap attribute. If the attribute is invalid,
+ * zero will be returned. Application must validate the
+ * attribute line before using this routine.
+ * Note: cap_num is not specified. It must be zero.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Number of payload types or zero.
+ */
+u16 sdp_attr_get_xcap_num_payload_types (void *sdp_ptr, u16 level,
+ u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_mca_t *cap_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (0);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_X_CAP, inst_num);
+ if ((attr_p == NULL) || (attr_p->attr.cap_p == NULL)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s X-cap attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ cap_p = attr_p->attr.cap_p;
+ return (cap_p->num_payloads);
+ }
+}
+
+/* Function: sdp_attr_get_xcap_payload_type
+ * Description: Returns the payload type of the specified payload for the
+ * X-cap attribute line. If the attr line or payload number is
+ * invalid, zero will be returned. Application must validate
+ * the X-cap attr before using this routine.
+ * Note: cap_num is not specified. It must be zero.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * inst_num The attribute instance number to check.
+ * payload_num The payload number to retrieve. Range is
+ * (1 - max num payloads).
+ * Returns: Payload type or zero.
+ */
+u16 sdp_attr_get_xcap_payload_type (void *sdp_ptr, u16 level,
+ u16 inst_num, u16 payload_num,
+ sdp_payload_ind_e *indicator)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_mca_t *cap_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (0);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_X_CAP, inst_num);
+ if ((attr_p == NULL) || (attr_p->attr.cap_p == NULL)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s X-cap attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ cap_p = attr_p->attr.cap_p;
+ if ((payload_num < 1) ||
+ (payload_num > cap_p->num_payloads)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s X-cap attribute, level %u instance %u, "
+ "payload num %u invalid.", sdp_p->debug_str,
+ level, inst_num, payload_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ *indicator = cap_p->payload_indicator[payload_num-1];
+ return (cap_p->payload_type[payload_num-1]);
+ }
+ }
+}
+
+
+/* Function: sdp_attr_set_xcap_media_type
+ * Description: Sets the value of the media type parameter for the X-cap
+ * attribute line.
+ * Note: cap_num is not specified. It must be zero.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * inst_num The attribute instance number to check.
+ * media Media type for the X-cap attribute.
+ * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER
+ */
+sdp_result_e sdp_attr_set_xcap_media_type (void *sdp_ptr, u16 level,
+ u16 inst_num, sdp_media_e media)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_mca_t *cap_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_X_CAP, inst_num);
+ if ((attr_p == NULL) || (attr_p->attr.cap_p == NULL)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s X-cap attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ cap_p = attr_p->attr.cap_p;
+ cap_p->media = media;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_attr_set_xcap_transport_type
+ * Description: Sets the value of the transport type parameter for the X-cap
+ * attribute line.
+ * Note: cap_num is not specified. It must be zero.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * inst_num The attribute instance number to check.
+ * transport Transport type for the X-cap attribute.
+ * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER
+ */
+sdp_result_e sdp_attr_set_xcap_transport_type(void *sdp_ptr, u16 level,
+ u16 inst_num,
+ sdp_transport_e transport)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_mca_t *cap_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_X_CAP, inst_num);
+ if ((attr_p == NULL) || (attr_p->attr.cap_p == NULL)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s X-cap attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ cap_p = attr_p->attr.cap_p;
+ cap_p->transport = transport;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_attr_add_xcap_payload_type
+ * Description: Add a new payload type for the X-cap attribute line
+ * specified. The new payload type will be added at the end
+ * of the payload type list.
+ * Note: cap_num is not specified. It must be zero.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * inst_num The attribute instance number to check.
+ * payload_type The new payload type.
+ * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER
+ */
+sdp_result_e sdp_attr_add_xcap_payload_type(void *sdp_ptr, u16 level,
+ u16 inst_num, u16 payload_type,
+ sdp_payload_ind_e indicator)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_mca_t *cap_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_X_CAP, inst_num);
+ if ((attr_p == NULL) || (attr_p->attr.cap_p == NULL)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s X-cap attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ cap_p = attr_p->attr.cap_p;
+ cap_p->payload_indicator[cap_p->num_payloads] = indicator;
+ cap_p->payload_type[cap_p->num_payloads++] = payload_type;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_attr_get_cdsc_first_cap_num
+ * Description: Gets the first capability number valid for the specified
+ * CDSC attribute instance. If the capability is not
+ * defined, zero is returned.
+ * Note: cap_num is not specified. It must be zero.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the capability.
+ * inst_num The CDSC instance number to check.
+ * Returns: Capability number or zero.
+ */
+u16 sdp_attr_get_cdsc_first_cap_num(void *sdp_ptr, u16 level, u16 inst_num)
+{
+ u16 cap_num=1;
+ u16 attr_count=0;
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_mca_t *mca_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (0);
+ }
+
+ if (level == SDP_SESSION_LEVEL) {
+ for (attr_p = sdp_p->sess_attrs_p; attr_p != NULL;
+ attr_p = attr_p->next_p) {
+ if (attr_p->type == SDP_ATTR_CDSC) {
+ attr_count++;
+ if (attr_count == inst_num) {
+ return (cap_num);
+ } else {
+ cap_num += attr_p->attr.cap_p->num_payloads;
+ }
+ }
+ }
+ } else { /* Capability is at a media level */
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ }
+ for (attr_p = mca_p->media_attrs_p; attr_p != NULL;
+ attr_p = attr_p->next_p) {
+ if (attr_p->type == SDP_ATTR_CDSC) {
+ attr_count++;
+ if (attr_count == inst_num) {
+ return (cap_num);
+ } else {
+ cap_num += attr_p->attr.cap_p->num_payloads;
+ }
+ }
+ }
+ } /* Attr is at a media level */
+
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s CDSC attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+}
+
+/* Function: sdp_attr_get_cdsc_media_type
+ * Description: Returns the media type specified for the given CDSC
+ * attribute. If the given attribute is not defined,
+ * SDP_MEDIA_INVALID is returned.
+ * Note: cap_num is not specified. It must be zero.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * inst_num The attribute instance number to check.
+ * Returns: Media type or SDP_MEDIA_INVALID.
+ */
+sdp_media_e sdp_attr_get_cdsc_media_type(void *sdp_ptr, u16 level,
+ u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_mca_t *cdsc_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_MEDIA_INVALID);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_CDSC, inst_num);
+ if ((attr_p == NULL) || (attr_p->attr.cap_p == NULL)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s CDSC attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_MEDIA_INVALID);
+ } else {
+ cdsc_p = attr_p->attr.cap_p;
+ return (cdsc_p->media);
+ }
+}
+
+/* Function: sdp_attr_get_cdsc_transport_type
+ * Description: Returns the transport type specified for the given CDSC
+ * attribute. If the given attribute is not defined,
+ * SDP_TRANSPORT_INVALID is returned.
+ * Note: cap_num is not specified. It must be zero.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * inst_num The attribute instance number to check.
+ * Returns: Media type or SDP_TRANSPORT_INVALID.
+ */
+sdp_transport_e sdp_attr_get_cdsc_transport_type(void *sdp_ptr, u16 level,
+ u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_mca_t *cdsc_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_TRANSPORT_INVALID);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_CDSC,
+ inst_num);
+ if ((attr_p == NULL) || (attr_p->attr.cap_p == NULL)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s CDSC attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_TRANSPORT_INVALID);
+ } else {
+ cdsc_p = attr_p->attr.cap_p;
+ return (cdsc_p->transport);
+ }
+}
+
+/* Function: sdp_attr_get_cdsc_num_payload_types
+ * Description: Returns the number of payload types associated with the
+ * specified CDSC attribute. If the attribute is invalid,
+ * zero will be returned. Application must validate the
+ * attribute line before using this routine.
+ * Note: cap_num is not specified. It must be zero.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Number of payload types or zero.
+ */
+u16 sdp_attr_get_cdsc_num_payload_types (void *sdp_ptr, u16 level,
+ u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_mca_t *cdsc_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (0);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_CDSC, inst_num);
+ if ((attr_p == NULL) || (attr_p->attr.cap_p == NULL)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s CDSC attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ cdsc_p = attr_p->attr.cap_p;
+ return (cdsc_p->num_payloads);
+ }
+}
+
+/* Function: sdp_attr_get_cdsc_payload_type
+ * Description: Returns the payload type of the specified payload for the
+ * CDSC attribute line. If the attr line or payload number is
+ * invalid, zero will be returned. Application must validate
+ * the CDSC attr before using this routine.
+ * Note: cap_num is not specified. It must be zero.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * inst_num The attribute instance number to check.
+ * payload_num The payload number to retrieve. Range is
+ * (1 - max num payloads).
+ * Returns: Payload type or zero.
+ */
+u16 sdp_attr_get_cdsc_payload_type (void *sdp_ptr, u16 level,
+ u16 inst_num, u16 payload_num,
+ sdp_payload_ind_e *indicator)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_mca_t *cdsc_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (0);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_CDSC, inst_num);
+ if ((attr_p == NULL) || (attr_p->attr.cap_p == NULL)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s CDSC attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ cdsc_p = attr_p->attr.cap_p;
+ if ((payload_num < 1) ||
+ (payload_num > cdsc_p->num_payloads)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s CDSC attribute, level %u instance %u, "
+ "payload num %u invalid.", sdp_p->debug_str,
+ level, inst_num, payload_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ *indicator = cdsc_p->payload_indicator[payload_num-1];
+ return (cdsc_p->payload_type[payload_num-1]);
+ }
+ }
+}
+
+/* Function: sdp_attr_set_cdsc_media_type
+ * Description: Sets the value of the media type parameter for the CDSC
+ * attribute line.
+ * Note: cap_num is not specified. It must be zero.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * inst_num The attribute instance number to check.
+ * media Media type for the CDSC attribute.
+ * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER
+ */
+sdp_result_e sdp_attr_set_cdsc_media_type (void *sdp_ptr, u16 level,
+ u16 inst_num, sdp_media_e media)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_mca_t *cdsc_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_CDSC, inst_num);
+ if ((attr_p == NULL) || (attr_p->attr.cap_p == NULL)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s CDSC attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ cdsc_p = attr_p->attr.cap_p;
+ cdsc_p->media = media;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_attr_set_cdsc_transport_type
+ * Description: Sets the value of the transport type parameter for the CDSC
+ * attribute line.
+ * Note: cap_num is not specified. It must be zero.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * inst_num The attribute instance number to check.
+ * transport Transport type for the CDSC attribute.
+ * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER
+ */
+sdp_result_e sdp_attr_set_cdsc_transport_type (void *sdp_ptr, u16 level,
+ u16 inst_num, sdp_transport_e transport)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_mca_t *cdsc_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_CDSC, inst_num);
+ if ((attr_p == NULL) || (attr_p->attr.cap_p == NULL)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s CDSC attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ cdsc_p = attr_p->attr.cap_p;
+ cdsc_p->transport = transport;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_attr_add_cdsc_payload_type
+ * Description: Add a new payload type for the CDSC attribute line
+ * specified. The new payload type will be added at the end
+ * of the payload type list.
+ * Note: cap_num is not specified. It must be zero.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * inst_num The attribute instance number to check.
+ * payload_type The new payload type.
+ * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER
+ */
+sdp_result_e sdp_attr_add_cdsc_payload_type (void *sdp_ptr, u16 level,
+ u16 inst_num, u16 payload_type,
+ sdp_payload_ind_e indicator)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ sdp_mca_t *cdsc_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_CDSC, inst_num);
+ if ((attr_p == NULL) || (attr_p->attr.cap_p == NULL)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s CDSC attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ cdsc_p = attr_p->attr.cap_p;
+ cdsc_p->payload_indicator[cdsc_p->num_payloads] = indicator;
+ cdsc_p->payload_type[cdsc_p->num_payloads++] = payload_type;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_media_dynamic_payload_valid
+ * Description: Checks if the dynamic payload type passed in is defined
+ * on the media line m_line
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * payload_type Payload type to be checked
+ *
+ * Returns: TRUE or FALSE. Returns TRUE if payload type is defined on the
+ * media line, else returns FALSE
+ */
+
+tinybool sdp_media_dynamic_payload_valid (void *sdp_ptr, u16 payload_type,
+ u16 m_line)
+{
+ u16 p_type,m_ptype;
+ ushort num_payload_types;
+ sdp_payload_ind_e ind;
+ tinybool payload_matches = FALSE;
+ tinybool result = TRUE;
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (FALSE);
+ }
+
+ if ((payload_type < SDP_MIN_DYNAMIC_PAYLOAD) ||
+ (payload_type > SDP_MAX_DYNAMIC_PAYLOAD)) {
+ return FALSE;
+ }
+
+ num_payload_types =
+ sdp_get_media_num_payload_types(sdp_p, m_line);
+
+ for(p_type=1; p_type <=num_payload_types;p_type++){
+
+ m_ptype = (u16)sdp_get_media_payload_type(sdp_p,
+ m_line, p_type, &ind);
+ if (payload_type == m_ptype) {
+ payload_matches = TRUE;
+ break;
+ }
+
+ }
+
+ if (!payload_matches) {
+ return FALSE;
+ }
+
+ return (result);
+
+}
+
+/* Function: sdp_attr_set_rtr_confirm
+ * Description: Sets the rtr confirm value a= rtr:confirm.
+ * If this parameter is TRUE, the confirm parameter will be
+ * specified when the SDP description is built.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * qos_attr The specific type of qos attribute. May be
+ * qos, secure, X-pc-qos, or X-qos.
+ * inst_num The attribute instance number to check.
+ * confirm New qos confirm parameter.
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_rtr_confirm (void *sdp_ptr, u16 level, u8 cap_num,
+ u16 inst_num,
+ tinybool confirm)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_RTR, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s %s attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str,
+ sdp_get_attr_name(SDP_ATTR_RTR), level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ attr_p->attr.rtr.confirm = confirm;
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_get_rtr_confirm
+ * Description: Returns the value of the rtr attribute confirm
+ * parameter specified for the given attribute. Returns TRUE if
+ * the confirm parameter is specified.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Boolean value.
+ */
+tinybool sdp_attr_get_rtr_confirm (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (FALSE);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_RTR, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s %s attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str,
+ sdp_get_attr_name(SDP_ATTR_RTR), level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (FALSE);
+ } else {
+ return (attr_p->attr.rtr.confirm);
+ }
+}
+
+
+
+sdp_mediadir_role_e sdp_attr_get_comediadir_role (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_MEDIADIR_ROLE_UNKNOWN);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_DIRECTION, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Comediadir role attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_MEDIADIR_ROLE_UNKNOWN);
+ } else {
+ return (attr_p->attr.comediadir.role);
+ }
+}
+
+/* Function: sdp_attr_set_comediadir_role
+ * Description: Sets the value of the comediadir role parameter
+ * for the direction attribute.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * comediadir_role The role of the comedia direction attribute
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_comediadir_role (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ sdp_mediadir_role_e comediadir_role)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_DIRECTION, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Comediadir role attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ attr_p->attr.comediadir.role = comediadir_role;
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_get_silencesupp_enabled
+ * Description: Returns the value of the silencesupp attribute enable
+ * parameter specified for the given attribute. Returns TRUE if
+ * the confirm parameter is specified.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Boolean value.
+ */
+tinybool sdp_attr_get_silencesupp_enabled (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (FALSE);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SILENCESUPP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s silenceSuppEnable attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (FALSE);
+ } else {
+ return (attr_p->attr.silencesupp.enabled);
+ }
+}
+
+/* Function: sdp_attr_get_silencesupp_timer
+ * Description: Returns the value of the silencesupp attribute timer
+ * parameter specified for the given attribute. null_ind
+ * is set to TRUE if no value was specified, but instead the
+ * null "-" value was specified.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: 16-bit timer value
+ * boolean null_ind
+ */
+u16 sdp_attr_get_silencesupp_timer (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ tinybool *null_ind)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (0);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SILENCESUPP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s silenceTimer attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ *null_ind = attr_p->attr.silencesupp.timer_null;
+ return (attr_p->attr.silencesupp.timer);
+ }
+}
+
+/* Function: sdp_attr_get_silencesupp_pref
+ * Description: Sets the silencesupp supppref value
+ * If this parameter is TRUE, the confirm parameter will be
+ * specified when the SDP description is built.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * confirm New qos confirm parameter.
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_silencesupp_pref_e sdp_attr_get_silencesupp_pref (void *sdp_ptr,
+ u16 level, u8 cap_num,
+ u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_SILENCESUPP_PREF_UNKNOWN);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SILENCESUPP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s silence suppPref attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_SILENCESUPP_PREF_UNKNOWN);
+ } else {
+ return (attr_p->attr.silencesupp.pref);
+ }
+}
+
+/* Function: sdp_attr_get_silencesupp_siduse
+ * Description: Returns the value of the silencesupp attribute siduse
+ * parameter specified for the given attribute. If the given
+ * attribute is not defined, SDP_QOS_STRENGTH_UNKNOWN is
+ * returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: silencesupp siduse enum.
+ */
+sdp_silencesupp_siduse_e sdp_attr_get_silencesupp_siduse (void *sdp_ptr,
+ u16 level,
+ u8 cap_num,
+ u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_SILENCESUPP_SIDUSE_UNKNOWN);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SILENCESUPP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s silence sidUse attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_SILENCESUPP_SIDUSE_UNKNOWN);
+ } else {
+ return (attr_p->attr.silencesupp.siduse);
+ }
+}
+
+/* Function: sdp_attr_get_silencesupp_fxnslevel
+ * Description: Returns the value of the silencesupp attribute fxns
+ * (fixed noise) parameter specified for the given attribute.
+ * null_ind is set to TRUE if no value was specified,
+ * but instead the null "-" value was specified.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: 7-bit fxns value
+ * boolean null_ind
+ */
+u8 sdp_attr_get_silencesupp_fxnslevel (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ tinybool *null_ind)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (0);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SILENCESUPP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s silence fxnslevel attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ *null_ind = attr_p->attr.silencesupp.fxnslevel_null;
+ return (attr_p->attr.silencesupp.fxnslevel);
+ }
+}
+
+/* Function: sdp_attr_set_silencesupp_enabled
+ * Description: Sets the silencesupp enable value
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * confirm New silencesupp enable parameter.
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_silencesupp_enabled (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ tinybool enable)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SILENCESUPP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s silenceSuppEnable attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ attr_p->attr.silencesupp.enabled = enable;
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_set_silencesupp_timer
+ * Description: Sets the silencesupp timer value
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * value New silencesupp timer parameter.
+ * null_ind if TRUE, timer value is set to "-" instead of
+ * the 16 bit numeric value
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_silencesupp_timer (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u16 value, tinybool null_ind)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SILENCESUPP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s silenceTimer attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ attr_p->attr.silencesupp.timer = value;
+ attr_p->attr.silencesupp.timer_null = null_ind;
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_set_silencesupp_pref
+ * Description: Sets the silencesupp supppref value
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * pref New silencesupp supppref parameter.
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_silencesupp_pref (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ sdp_silencesupp_pref_e pref)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SILENCESUPP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s silence SuppPref attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ attr_p->attr.silencesupp.pref = pref;
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_set_silencesupp_siduse
+ * Description: Sets the silencesupp supppref value
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * siduse New silencesupp siduse parameter.
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_silencesupp_siduse (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ sdp_silencesupp_siduse_e siduse)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SILENCESUPP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s silence sidUse attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ attr_p->attr.silencesupp.siduse = siduse;
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_set_silencesupp_fxnslevel
+ * Description: Sets the silencesupp timer value
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * value New silencesupp timer parameter.
+ * null_ind if TRUE, timer value is set to "-" instead of
+ * the 16 bit numeric value
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_silencesupp_fxnslevel (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u16 value, tinybool null_ind)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SILENCESUPP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s silenceTimer attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ attr_p->attr.silencesupp.fxnslevel = (u8)value;
+ attr_p->attr.silencesupp.fxnslevel_null = null_ind;
+ return (SDP_SUCCESS);
+ }
+}
+
+
+/* Function: sdp_attr_get_mptime_num_intervals
+ * Description: Returns the number of intervals specified for the
+ * given mptime attribute. If the given attribute is not
+ * defined, zero is returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Number of intervals.
+ */
+u16 sdp_attr_get_mptime_num_intervals (
+ void *sdp_ptr,
+ u16 level,
+ u8 cap_num,
+ u16 inst_num) {
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return 0;
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_MPTIME, inst_num);
+ if (attr_p != NULL) {
+ return attr_p->attr.mptime.num_intervals;
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s mptime attribute, level %u instance %u not found.",
+ sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return 0;
+}
+
+/* Function: sdp_attr_get_mptime_interval
+ * Description: Returns the value of the specified interval for the
+ * given mptime attribute. If the given attribute is not
+ * defined, zero is returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * interval_num The interval number to get. Range is (1 -
+ * max num payloads).
+ * Returns: Interval.
+ */
+u16 sdp_attr_get_mptime_interval (
+ void *sdp_ptr,
+ u16 level,
+ u8 cap_num,
+ u16 inst_num,
+ u16 interval_num) {
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return 0;
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_MPTIME, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s mptime attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return 0;
+ }
+
+ if ((interval_num<1) || (interval_num>attr_p->attr.mptime.num_intervals)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s mptime attribute, level %u instance %u, "
+ "invalid interval number %u requested.",
+ sdp_p->debug_str, level, inst_num, interval_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return 0;
+ }
+
+ return attr_p->attr.mptime.intervals[interval_num-1];
+}
+
+/* Function: sdp_attr_add_mptime_interval
+ * Description: Add a new value to the list of intervals specified for
+ * the given mptime attribute. The interval will be
+ * added to the end of the list so these values should be added
+ * in the order they will be displayed within the attribute.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * mp_interval The interval to add.
+ * Returns: SDP_SUCCESS Interval was added successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ * SDP_INVALID_SDP_PTR Supplied SDP pointer is invalid
+ */
+sdp_result_e sdp_attr_add_mptime_interval (
+ void *sdp_ptr,
+ u16 level,
+ u8 cap_num,
+ u16 inst_num,
+ u16 mp_interval) {
+
+ u16 interval_num;
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return SDP_INVALID_SDP_PTR;
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_MPTIME, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s mptime attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return SDP_INVALID_PARAMETER;
+ }
+
+ interval_num = attr_p->attr.mptime.num_intervals;
+ if (interval_num>=SDP_MAX_PAYLOAD_TYPES) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s mptime attribute, level %u instance %u "
+ "exceeds maximum length.",
+ sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return SDP_INVALID_PARAMETER;
+ }
+
+ attr_p->attr.mptime.intervals[interval_num] = mp_interval;
+ ++attr_p->attr.mptime.num_intervals;
+ return SDP_SUCCESS;
+}
+
+
+
+/* Function: sdp_get_group_attr
+ * Description: Returns the attribute parameter from the a=group:<>
+ * line. If no attrib has been set ,
+ * SDP_GROUP_ATTR_UNSUPPORTED will be returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level SDP_SESSION_LEVEL
+ * Returns: Valid attrib value or SDP_GROUP_ATTR_UNSUPPORTED.
+ */
+sdp_group_attr_e sdp_get_group_attr (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_GROUP_ATTR_UNSUPPORTED);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_GROUP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Group (a= group line) attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_GROUP_ATTR_UNSUPPORTED);
+ } else {
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Stream data group attr field is :%s ",
+ sdp_p->debug_str,
+ sdp_get_group_attr_name(attr_p->attr.stream_data.group_attr) );
+ }
+ return (attr_p->attr.stream_data.group_attr);
+ }
+}
+
+/* Function: sdp_set_group_attr
+ * Description: Sets the value of the group attribute for the
+ * a=group: line.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level SDP_SESSION_LEVEL
+ * group_attr group attribute value ( LS/FID ).
+ * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER/SDP_INVALID_SDP_PTR
+*/
+
+sdp_result_e sdp_set_group_attr (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ sdp_group_attr_e group_attr)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_GROUP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Group attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ attr_p->attr.stream_data.group_attr = group_attr;
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_get_group_num_id
+ * Description: Returns the number of ids from the a=group:<> line.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level SDP_SESSION_LEVEL
+ * Returns: Num of group ids present or 0 if there is an error.
+ */
+u16 sdp_get_group_num_id (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (0);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_GROUP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s a=group level attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Stream data group attr - num of ids is :%d ",
+ sdp_p->debug_str,
+ attr_p->attr.stream_data.num_group_id);
+ }
+ }
+ return (attr_p->attr.stream_data.num_group_id);
+}
+
+/* Function: sdp_set_group_num_id
+ * Description: Sets the number og group ids that would be added on
+ * a=group: ...line.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level SDP_SESSION_LEVEL
+ * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER/SDP_INVALID_SDP_PTR
+ * Note: The application must call this API to set the number of group
+ * ids to be provided before actually setting the group ids on
+ * the a=group line.
+*/
+
+sdp_result_e sdp_set_group_num_id (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u16 group_num_id)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_GROUP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Group attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else if ((group_num_id == 0) || (group_num_id > SDP_MAX_GROUP_STREAM_ID)){
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Number of group id value provided - %u is invalid\n",
+ sdp_p->debug_str, group_num_id);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ attr_p->attr.stream_data.num_group_id = group_num_id;
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_get_group_id
+ * Description: Returns the number of ids from the a=group:<> line.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level SDP_SESSION_LEVEL
+ * id_num Number of the id to retrieve. The range is (1 -
+ * SDP_MAX_GROUP_STREAM_ID)
+ * Returns: Value of the group id at the index specified or
+ * SDP_INVALID_VALUE if an error
+ */
+int32 sdp_get_group_id (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num, u16 id_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_VALUE);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_GROUP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s a=group level attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ } else {
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Stream data group attr - num of ids is :%d ",
+ sdp_p->debug_str,
+ attr_p->attr.stream_data.num_group_id);
+ }
+ if ((id_num < 1) || (id_num > attr_p->attr.stream_data.num_group_id)) {
+ return (SDP_INVALID_VALUE);
+ }
+ }
+ return (attr_p->attr.stream_data.group_id_arr[id_num-1]);
+}
+
+/* Function: sdp_set_group_id
+ * Description: Sets the number og group ids that would be added on
+ * a=group: ...line.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level SDP_SESSION_LEVEL
+ * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER/SDP_INVALID_SDP_PTR
+*/
+
+sdp_result_e sdp_set_group_id (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ u16 group_id)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ u16 num_group_id;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_GROUP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Group attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ num_group_id = attr_p->attr.stream_data.num_group_id;
+ if (num_group_id == SDP_MAX_GROUP_STREAM_ID) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Max number of Group Ids already defined "
+ "for this group line %u", sdp_p->debug_str, level);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p->attr.stream_data.group_id_arr[num_group_id] = group_id;
+ attr_p->attr.stream_data.num_group_id++;
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_get_x_sidin
+ * Description: Returns the attribute parameter from the a=X-sidin:<>
+ * line. If no attrib has been set NULL will be returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level media level index
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Pointer to sidin or NULL.
+ */
+const char* sdp_attr_get_x_sidin (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (NULL);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_X_SIDIN, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s X-sidin attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (NULL);
+ } else {
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Stream X-sidin attr field is :%s ",
+ sdp_p->debug_str,
+ attr_p->attr.stream_data.x_sidin);
+ }
+ return (attr_p->attr.stream_data.x_sidin);
+ }
+}
+
+/* Function: sdp_attr_set_x_sidin
+ * Description: Sets the value of the X-sidin parameter
+ * for the given attribute. The address is copied into the
+ * SDP structure so application memory will not be
+ * referenced by the SDP lib.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * sidin Ptr to the sidin string
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_x_sidin (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ const char *sidin)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_X_SIDIN, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s X-sidin attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ sstrncpy(attr_p->attr.stream_data.x_sidin, sidin,
+ sizeof(attr_p->attr.stream_data.x_sidin)) ;
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_get_x_sidout
+ * Description: Returns the attribute parameter from the a=X-sidout:<>
+ * line. If no attrib has been set NULL will be returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level media level index
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Pointer to sidout or NULL.
+ */
+const char* sdp_attr_get_x_sidout (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (NULL);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_X_SIDOUT, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s X-sidout attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (NULL);
+ } else {
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Stream X-sidout attr field is :%s ",
+ sdp_p->debug_str,
+ attr_p->attr.stream_data.x_sidout);
+ }
+ return (attr_p->attr.stream_data.x_sidout);
+ }
+}
+
+/* Function: sdp_attr_set_x_sidout
+ * Description: Sets the value of the x-sidout parameter
+ * for the given attribute. The address is copied into the
+ * SDP structure so application memory will not be
+ * referenced by the SDP lib.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * sidout Ptr to the sidout string.
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_x_sidout (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ const char *sidout)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_X_SIDOUT, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s X-sidout attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ sstrncpy(attr_p->attr.stream_data.x_sidout, sidout,
+ sizeof(attr_p->attr.stream_data.x_sidout)) ;
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_get_x_confid
+ * Description: Returns the attribute parameter from the a=X-confid:<>
+ * line. If no attrib has been set NULL will be returned.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level media level index
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Pointer to confid or NULL.
+ */
+const char* sdp_attr_get_x_confid (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (NULL);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_X_CONFID, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s X-confid attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (NULL);
+ } else {
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Stream X-confid attr field is :%s ",
+ sdp_p->debug_str,
+ attr_p->attr.stream_data.x_confid);
+ }
+ return (attr_p->attr.stream_data.x_confid);
+ }
+}
+
+/* Function: sdp_attr_set_x_confid
+ * Description: Sets the value of the X-confid parameter
+ * for the given attribute. The address is copied into the
+ * SDP structure so application memory will not be
+ * referenced by the SDP lib.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * confid Ptr to the confid string.
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_x_confid (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ const char *confid)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_X_CONFID, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s X-confid attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ sstrncpy(attr_p->attr.stream_data.x_confid, confid,
+ sizeof(attr_p->attr.stream_data.x_confid)) ;
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_set_source_filter
+ * Description: Sets the value of the source filter attribute for the
+ * a=source-filter: line.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level SDP_SESSION_LEVEL/Media level
+ * mode Filter-mode (incl/excl)
+ * nettype Network type
+ * addrtype Address type of the destination
+ * dest_addr Destination unicast/multicast address
+ * (ip-addr/ fqdn/ *)
+ * src_addr One of the source address to which the filter
+ * applies, i.e. process/drop the packets.
+ * (More source addresses are added using
+ * sdp_include_new_filter_src_addr)
+ * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER/SDP_INVALID_SDP_PTR
+ */
+sdp_result_e
+sdp_set_source_filter (void *sdp_ptr, u16 level, u8 cap_num,
+ u16 inst_num, sdp_src_filter_mode_e mode,
+ sdp_nettype_e nettype, sdp_addrtype_e addrtype,
+ const char *dest_addr, const char *src_addr)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ u16 index;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SOURCE_FILTER, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Source filter attribute, level %u instance %u "
+ "not found", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p->attr.source_filter.mode = mode;
+ attr_p->attr.source_filter.nettype = nettype;
+ attr_p->attr.source_filter.addrtype = addrtype;
+ sstrncpy(attr_p->attr.source_filter.dest_addr, dest_addr,
+ SDP_MAX_STRING_LEN+1);
+ if (src_addr) {
+ index = attr_p->attr.source_filter.num_src_addr;
+ sstrncpy(attr_p->attr.source_filter.src_list[index],
+ src_addr,SDP_MAX_STRING_LEN+1);
+ /* Increment source list count if the api was invoked for
+ * first time or else we're basically replacing the index 0
+ * element in src-list.
+ */
+ ++attr_p->attr.source_filter.num_src_addr;
+ SDP_PRINT("%s Source address (%s) number %d added to source filter",
+ sdp_p->debug_str,src_addr,
+ attr_p->attr.source_filter.num_src_addr);
+
+ }
+
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_include_new_filter_src_addr
+ * Description: Adds source addresses to the list to which the filter applies
+ * This is to be invoked only as follow-up to
+ * sdp_set_source_filter() to include more source addresses
+ * Parameters: sdp_ptr The SDP handle to which the filter attributes
+ * were added using sdp_set_source_filter
+ * level SDP_SESSION_LEVEL/Media level
+ * src_addr Source address to be added to the list
+ * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER/SDP_INVALID_SDP_PTR
+ */
+
+sdp_result_e
+sdp_include_new_filter_src_addr (void *sdp_ptr, u16 level, u8 cap_num,
+ u16 inst_num, const char *src_addr)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SOURCE_FILTER, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Source filter attribute, level %u instance %u "
+ "not found", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ if (attr_p->attr.source_filter.num_src_addr >= SDP_MAX_SRC_ADDR_LIST) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Max number of source addresses included for "
+ "filter for the instance %u", sdp_p->debug_str,
+ inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_FAILURE);
+ }
+ sstrncpy(attr_p->attr.source_filter.src_list[
+ attr_p->attr.source_filter.num_src_addr],
+ src_addr, SDP_MAX_STRING_LEN+1);
+ ++attr_p->attr.source_filter.num_src_addr;
+
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_get_source_filter_mode
+ * Description: Gets the filter mode in internal representation
+ * Parameters: sdp_ptr The SDP handle which contains the attributes
+ * level SDP_SESSION_LEVEL/m-line number
+ * inst_num The attribute instance number
+ * Returns: Filter mode (incl/excl/not present)
+ */
+sdp_src_filter_mode_e
+sdp_get_source_filter_mode (void *sdp_ptr, u16 level, u8 cap_num,
+ u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_FILTER_MODE_NOT_PRESENT);
+ }
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SOURCE_FILTER, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Source filter attribute, level %u, "
+ "instance %u not found", sdp_p->debug_str,
+ level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_FILTER_MODE_NOT_PRESENT);
+ }
+ return (attr_p->attr.source_filter.mode);
+}
+
+/* Function: sdp_get_filter_destination_attributes
+ * Description: Gets the destination address parameters
+ * Parameters: Network type (optional), destination address type
+ * (optional), and destination address (mandatory) variables
+ * which gets updated.
+ * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER/SDP_INVALID_SDP_PTR
+ */
+sdp_result_e
+sdp_get_filter_destination_attributes (void *sdp_ptr, u16 level, u8 cap_num,
+ u16 inst_num, sdp_nettype_e *nettype,
+ sdp_addrtype_e *addrtype,
+ char *dest_addr)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SOURCE_FILTER, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Source filter attribute, level %u instance %u "
+ "not found", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ if (nettype) {
+ *nettype = attr_p->attr.source_filter.nettype;
+ }
+ if (addrtype) {
+ *addrtype = attr_p->attr.source_filter.addrtype;
+ }
+ sstrncpy(dest_addr, attr_p->attr.source_filter.dest_addr,
+ SDP_MAX_STRING_LEN+1);
+
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_get_filter_source_address_count
+ * Description: Gets the number of source addresses in the list
+ * Parameters: sdp_ptr The SDP handle which contains the attributes
+ * level SDP_SESSION_LEVEL/m-line number
+ * inst_num The attribute instance number
+ * Returns: Source-list count
+ */
+
+int32
+sdp_get_filter_source_address_count (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_VALUE);
+ }
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SOURCE_FILTER, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Source filter attribute, level %u instance %u "
+ "not found", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ }
+ return (attr_p->attr.source_filter.num_src_addr);
+}
+
+/* Function: sdp_get_filter_source_address
+ * Description: Gets one of the source address that is indexed by the user
+ * Parameters: sdp_ptr The SDP handle which contains the attributes
+ * level SDP_SESSION_LEVEL/m-line number
+ * inst_num The attribute instance number
+ * src_addr_id User provided index (value in range between
+ * 0 to (SDP_MAX_SRC_ADDR_LIST-1) which obtains
+ * the source addr corresponding to it.
+ * src_addr The user provided variable which gets updated
+ * with source address corresponding to the index
+ */
+sdp_result_e
+sdp_get_filter_source_address (void *sdp_ptr, u16 level, u8 cap_num,
+ u16 inst_num, u16 src_addr_id,
+ char *src_addr)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ src_addr[0] = '\0';
+
+ if (src_addr_id >= SDP_MAX_SRC_ADDR_LIST) {
+ return (SDP_INVALID_PARAMETER);
+ }
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SOURCE_FILTER, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Source filter attribute, level %u instance %u "
+ "not found", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ if (src_addr_id >= attr_p->attr.source_filter.num_src_addr) {
+ return (SDP_INVALID_PARAMETER);
+ }
+ sstrncpy(src_addr, attr_p->attr.source_filter.src_list[src_addr_id],
+ SDP_MAX_STRING_LEN+1);
+
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e
+sdp_set_rtcp_unicast_mode (void *sdp_ptr, u16 level, u8 cap_num,
+ u16 inst_num, sdp_rtcp_unicast_mode_e mode)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+ if (mode >= SDP_RTCP_MAX_UNICAST_MODE) {
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_RTCP_UNICAST, inst_num);
+
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s RTCP Unicast attribute, level %u instance %u "
+ "not found", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p->attr.u32_val = mode;
+
+ return (SDP_SUCCESS);
+}
+
+sdp_rtcp_unicast_mode_e
+sdp_get_rtcp_unicast_mode(void *sdp_ptr, u16 level, u8 cap_num,
+ u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_RTCP_UNICAST_MODE_NOT_PRESENT);
+ }
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_RTCP_UNICAST, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s RTCP Unicast attribute, level %u, "
+ "instance %u not found", sdp_p->debug_str,
+ level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_RTCP_UNICAST_MODE_NOT_PRESENT);
+ }
+ return ((sdp_rtcp_unicast_mode_e)attr_p->attr.u32_val);
+}
+
+
+/* Function: sdp_attr_get_sdescriptions_tag
+ * Description: Returns the value of the sdescriptions tag
+ * parameter specified for the given attribute.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Tag value or SDP_INVALID_VALUE (-2) if error encountered.
+ */
+
+int32
+sdp_attr_get_sdescriptions_tag (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return SDP_INVALID_VALUE;
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SDESCRIPTIONS, inst_num);
+
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s srtp attribute tag, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return SDP_INVALID_VALUE;
+ } else {
+ return attr_p->attr.srtp_context.tag;
+ }
+}
+
+/* Function: sdp_attr_get_sdescriptions_crypto_suite
+ * Description: Returns the value of the sdescriptions crypto suite
+ * parameter specified for the given attribute. Note that
+ * this is a common api for both version 2 and version 9
+ * sdescriptions. It has no knowledge which version is being
+ * used so it will first try to find if a version 2 sdescriptions
+ * attribute is present. If it is, return the suite. If it's not,
+ * try to find the version 9. This assumes you cannot have both
+ * versions in the same SDP.
+ *
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: SDP_SRTP_UNKNOWN_CRYPTO_SUITE is returned if an error was
+ * encountered otherwise the crypto suite is returned.
+ */
+
+sdp_srtp_crypto_suite_t
+sdp_attr_get_sdescriptions_crypto_suite (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return SDP_SRTP_UNKNOWN_CRYPTO_SUITE;
+ }
+
+
+ /* Try version 2 first */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SRTP_CONTEXT, inst_num);
+
+ if (attr_p == NULL) {
+ /* There's no version 2 so now try version 9 */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SDESCRIPTIONS, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s srtp attribute suite, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return SDP_SRTP_UNKNOWN_CRYPTO_SUITE;
+ }
+ }
+
+ return attr_p->attr.srtp_context.suite;
+
+}
+
+/* Function: sdp_attr_get_sdescriptions_key
+ * Description: Returns the value of the sdescriptions master key
+ * parameter specified for the given attribute. Note that
+ * this is a common api for both version 2 and version 9
+ * sdescriptions. It has no knowledge which version is being
+ * used so it will first try to find if a version 2 sdescriptions
+ * attribute is present. If it is, return the key. If it's not,
+ * try to find the version 9. This assumes you cannot have both
+ * versions in the same SDP.
+ *
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: NULL if error encountered or master key salt string
+ */
+
+const char*
+sdp_attr_get_sdescriptions_key (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return NULL;
+ }
+
+ /* Try version 2 first */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SRTP_CONTEXT, inst_num);
+
+ if (attr_p == NULL) {
+ /* Couldn't find version 2 now try version 9 */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SDESCRIPTIONS, inst_num);
+
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s srtp attribute key, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return NULL;
+ }
+ }
+
+ return (char*)attr_p->attr.srtp_context.master_key;
+}
+
+
+/* Function: sdp_attr_get_sdescriptions_salt
+ * Description: Returns the value of the sdescriptions master salt
+ * parameter specified for the given attribute. Note that
+ * this is a common api for both version 2 and version 9
+ * sdescriptions. It has no knowledge which version is being
+ * used so it will first try to find if a version 2 sdescriptions
+ * attribute is present. If it is, return the salt. If it's not,
+ * try to find the version 9. This assumes you cannot have both
+ * versions in the same SDP.
+ *
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: NULL if error encountered or master key salt string
+ */
+
+const char*
+sdp_attr_get_sdescriptions_salt (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return NULL;
+ }
+
+ /* Try version 2 first */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SRTP_CONTEXT, inst_num);
+
+ if (attr_p == NULL) {
+ /* Couldn't find version 2 now try version 9 */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SDESCRIPTIONS, inst_num);
+
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s srtp attribute salt, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return NULL;
+ }
+ }
+
+ return (char*) attr_p->attr.srtp_context.master_salt;
+
+}
+
+
+
+/* Function: sdp_attr_get_sdescriptions_lifetime
+ * Description: Returns the value of the sdescriptions lifetime
+ * parameter specified for the given attribute.Note that
+ * this is a common api for both version 2 and version 9
+ * sdescriptions. It has no knowledge which version is being
+ * used so it will first try to find if a version 2 sdescriptions
+ * attribute is present. If it is, return the lifetime. If it's
+ * not, try to find the version 9. This assumes you cannot have
+ * both versions in the same SDP.
+ *
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: NULL if error encountered or lifetime string
+ */
+
+const char*
+sdp_attr_get_sdescriptions_lifetime (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return NULL;
+ }
+
+ /* Try version 2 first. */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SRTP_CONTEXT, inst_num);
+
+ if (attr_p == NULL) {
+ /* Couldn't find version 2 now try version 9 */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SDESCRIPTIONS, inst_num);
+
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s srtp attribute lifetime, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return NULL;
+ }
+ }
+
+ return (char*)attr_p->attr.srtp_context.master_key_lifetime;
+
+}
+
+/* Function: sdp_attr_get_sdescriptions_mki
+ * Description: Returns the value of the sdescriptions MKI value and length
+ * parameter of the specified attribute instance. Note that
+ * this is a common api for both version 2 and version 9
+ * sdescriptions. It has no knowledge which version is being
+ * used so it will first try to find if a version 2 sdescriptions
+ * attribute is present. If it is, return the MKI. If it's
+ * not, try to find version 9. This assumes you cannot have
+ * both versions in the same SDP.
+ *
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * mki_value application provided pointer that on exit
+ * is set to the MKI value string if one exists.
+ * mki_length application provided pointer that on exit
+ * is set to the MKI length if one exists.
+ * Returns: SDP_SUCCESS no errors encountered otherwise sdp error
+ * based upon the specific error.
+ */
+
+sdp_result_e
+sdp_attr_get_sdescriptions_mki (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ const char **mki_value,
+ u16 *mki_length)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ *mki_value = NULL;
+ *mki_length = 0;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return SDP_INVALID_SDP_PTR;
+ }
+
+ /* Try version 2 first */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SRTP_CONTEXT, inst_num);
+
+ if (attr_p == NULL) {
+ /* Couldn't find version 2 now try version 9 */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SDESCRIPTIONS, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s srtp attribute MKI, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+
+ *mki_value = (char*)attr_p->attr.srtp_context.mki;
+ *mki_length = attr_p->attr.srtp_context.mki_size_bytes;
+ return SDP_SUCCESS;
+
+}
+
+
+/* Function: sdp_attr_get_sdescriptions_session_params
+ * Description: Returns the unparsed session parameters string. Note that
+ * this is a common api for both version 2 and version 9
+ * sdescriptions. It has no knowledge which version is being
+ * used so it will first try to find if a version 2 sdescriptions
+ * attribute is present. If it is, return session parameters. If
+ * it's not, try to find version 9. This assumes you cannot have
+ * both versions in the same SDP.
+ *
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: NULL if no session parameters were received in the sdp,
+ * otherwise returns a pointer to the start of the session
+ * parameters string. Note that the calling function should
+ * not free the returned pointer.
+ */
+
+const char*
+sdp_attr_get_sdescriptions_session_params (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return NULL;
+ }
+
+ /* Try version 2 first */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SRTP_CONTEXT, inst_num);
+
+ if (attr_p == NULL) {
+ /* Couldn't find version 2 try version 9 */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SDESCRIPTIONS, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s srtp attribute session params, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return NULL;
+ }
+ }
+
+ return attr_p->attr.srtp_context.session_parameters;
+}
+
+
+/* Function: sdp_attr_get_sdescriptions_key_size
+ * Description: Returns the master key size. Note that
+ * this is a common api for both version 2 and version 9
+ * sdescriptions. It has no knowledge which version is being
+ * used so it will first try to find if a version 2 sdescriptions
+ * attribute is present. If it is, return key size. If
+ * it's not, try to find version 9. This assumes you cannot have
+ * both versions in the same SDP.
+ *
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: 0 (SDP_SDESCRIPTIONS_KEY_SIZE_UNKNOWN) if error was
+ * encountered, otherwise key size.
+ */
+
+unsigned char
+sdp_attr_get_sdescriptions_key_size (void *sdp_ptr,
+ u16 level,
+ u8 cap_num,
+ u16 inst_num)
+{
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return SDP_SDESCRIPTIONS_KEY_SIZE_UNKNOWN;
+ }
+
+ /* Try version 2 first */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SRTP_CONTEXT, inst_num);
+
+ if (attr_p == NULL) {
+ /* Couldn't find version 2 now try version 9 */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SDESCRIPTIONS, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s srtp attribute MKI, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return SDP_SDESCRIPTIONS_KEY_SIZE_UNKNOWN;
+ }
+ }
+
+ return attr_p->attr.srtp_context.master_key_size_bytes;
+
+}
+
+
+/* Function: sdp_attr_get_sdescriptions_salt_size
+ * Description: Returns the salt key size. Note that
+ * this is a common api for both version 2 and version 9
+ * sdescriptions. It has no knowledge which version is being
+ * used so it will first try to find if a version 2 sdescriptions
+ * attribute is present. If it is, return salt size. If
+ * it's not, try to find version 9. This assumes you cannot have
+ * both versions in the same SDP.
+ *
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: 0 (SDP_SDESCRIPTIONS_KEY_SIZE_UNKNOWN) if error was
+ * encountered, otherwise salt size.
+ */
+
+unsigned char
+sdp_attr_get_sdescriptions_salt_size (void *sdp_ptr,
+ u16 level,
+ u8 cap_num,
+ u16 inst_num)
+{
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return SDP_SDESCRIPTIONS_KEY_SIZE_UNKNOWN;
+ }
+
+ /* Try version 2 first */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SRTP_CONTEXT, inst_num);
+
+ if (attr_p == NULL) {
+ /* Couldn't find version 2 now try version 9 */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SDESCRIPTIONS, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s srtp attribute MKI, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return SDP_SDESCRIPTIONS_KEY_SIZE_UNKNOWN;
+ }
+ }
+
+ return attr_p->attr.srtp_context.master_salt_size_bytes;
+
+}
+
+
+/* Function: sdp_attr_get_srtp_crypto_selection_flags
+ * Description: Returns the selection flags. Note that
+ * this is a common api for both version 2 and version 9
+ * sdescriptions. It has no knowledge which version is being
+ * used so it will first try to find if a version 2 sdescriptions
+ * attribute is present. If it is, return selection flags. If
+ * it's not, try to find version 9. This assumes you cannot have
+ * both versions in the same SDP.
+ * Currently only necessary for MGCP.
+ *
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: 0 (SDP_SRTP_CRYPTO_SELECTION_FLAGS_UNKNOWN) if error was
+ * encountered, otherwise selection flags.
+ */
+
+unsigned long
+sdp_attr_get_srtp_crypto_selection_flags (void *sdp_ptr,
+ u16 level,
+ u8 cap_num,
+ u16 inst_num)
+{
+
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return SDP_SRTP_CRYPTO_SELECTION_FLAGS_UNKNOWN;
+ }
+
+ /* Try version 2 first */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SRTP_CONTEXT, inst_num);
+
+ if (attr_p == NULL) {
+ /* Couldn't find version 2 now try version 9 */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SDESCRIPTIONS, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s srtp attribute MKI, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return SDP_SRTP_CRYPTO_SELECTION_FLAGS_UNKNOWN;
+ }
+ }
+
+ return attr_p->attr.srtp_context.selection_flags;
+
+}
+
+
+
+/* Function: sdp_attr_set_sdescriptions_tag
+ * Description: Sets the sdescriptions tag parameter
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * tag_num tag
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+
+sdp_result_e
+sdp_attr_set_sdescriptions_tag (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ int32 tag_num)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SDESCRIPTIONS, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s srtp attribute tag, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ attr_p->attr.srtp_context.tag = tag_num;
+ return (SDP_SUCCESS);
+ }
+}
+
+
+/* Function: sdp_attr_set_sdescriptions_crypto_suite
+ * Description: Sets the sdescriptions crypto suite parameter. Note that
+ * this is a common api for both version 2 and version 9
+ * sdescriptions. It has no knowledge which version is being
+ * used so it will first try to find if a version 2 sdescriptions
+ * attribute is present. If it is, it will set the crypto suite
+ * for version 2. If it's not, try to find version 9. This assumes
+ * you cannot have both versions in the same SDP.
+ *
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * crypto_suite crypto suite
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+
+sdp_result_e
+sdp_attr_set_sdescriptions_crypto_suite (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ sdp_srtp_crypto_suite_t crypto_suite)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+ int i;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return SDP_INVALID_SDP_PTR;
+ }
+
+ /* Try to find version 2 first */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SRTP_CONTEXT, inst_num);
+ if (attr_p == NULL) {
+
+ /* Version 2 not found, try version 9 */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SDESCRIPTIONS, inst_num);
+ if (attr_p == NULL) {
+
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s srtp attribute suite, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+
+ attr_p->attr.srtp_context.suite = crypto_suite;
+ for (i=0; i < SDP_SRTP_MAX_NUM_CRYPTO_SUITES; i++) {
+ /* For the specified crypto suite, get the size of the
+ * key and salt.
+ */
+ if (sdp_srtp_crypto_suite_array[i].crypto_suite_val ==
+ crypto_suite) {
+
+ attr_p->attr.srtp_context.master_key_size_bytes =
+ sdp_srtp_crypto_suite_array[i].key_size_bytes;
+
+ attr_p->attr.srtp_context.master_salt_size_bytes =
+ sdp_srtp_crypto_suite_array[i].salt_size_bytes;
+
+ }
+ }
+
+ return SDP_SUCCESS;
+
+}
+
+
+/* Function: sdp_attr_set_sdescriptions_key
+ * Description: Sets the sdescriptions key parameter. Note that
+ * this is a common api for both version 2 and version 9
+ * sdescriptions. It has no knowledge which version is being
+ * used so it will first try to find if a version 2 sdescriptions
+ * attribute is present. If it is, it will set the key for
+ * version 2. If it's not, try to find version 9. This assumes
+ * you cannot have both versions in the same SDP.
+ *
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * key buffer containing the key assumes null terminated
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+
+sdp_result_e
+sdp_attr_set_sdescriptions_key (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ char *key)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return SDP_INVALID_SDP_PTR;
+ }
+
+ /* Try version 2 first */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SRTP_CONTEXT, inst_num);
+ if (attr_p == NULL) {
+ /* Couldn't find version 2 try version 9 */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SDESCRIPTIONS, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s srtp attribute key, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return SDP_INVALID_PARAMETER;
+ }
+
+ }
+
+ bcopy(key, attr_p->attr.srtp_context.master_key,
+ SDP_SRTP_MAX_KEY_SIZE_BYTES);
+
+ return SDP_SUCCESS;
+
+}
+
+
+/* Function: sdp_attr_set_sdescriptions_salt
+ * Description: Sets the sdescriptions salt parameter. Note that
+ * this is a common api for both version 2 and version 9
+ * sdescriptions. It has no knowledge which version is being
+ * used so it will first try to find if a version 2 sdescriptions
+ * attribute is present. If it is, it will set the salt for
+ * version 2. If it's not, try to find version 9. This assumes
+ * you cannot have both versions in the same SDP.
+ *
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * salt buffer containing the salt assumes null terminated
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+
+sdp_result_e
+sdp_attr_set_sdescriptions_salt (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ char *salt)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return SDP_INVALID_SDP_PTR;
+ }
+
+ /* Try to find version 2 first */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SRTP_CONTEXT, inst_num);
+ if (attr_p == NULL) {
+ /* Couldn't find version 2, try version 9 */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SDESCRIPTIONS, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s srtp attribute salt, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ }
+
+ bcopy(salt, attr_p->attr.srtp_context.master_salt,
+ SDP_SRTP_MAX_SALT_SIZE_BYTES);
+
+ return SDP_SUCCESS;
+}
+
+
+/* Function: sdp_attr_set_sdescriptions_lifetime
+ * Description: Sets the sdescriptions lifetime parameter. Note that
+ * this is a common api for both version 2 and version 9
+ * sdescriptions. It has no knowledge which version is being
+ * used so it will first try to find if a version 2 sdescriptions
+ * attribute is present. If it is, it will set the lifetime for
+ * version 2. If it's not, try to find version 9. This assumes
+ * you cannot have both versions in the same SDP.
+ *
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * lifetime buffer containing the lifetime assumes null terminated
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+
+sdp_result_e
+sdp_attr_set_sdescriptions_lifetime (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ char *lifetime)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return SDP_INVALID_SDP_PTR;
+ }
+
+ /* Try version 2 first */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SRTP_CONTEXT, inst_num);
+ if (attr_p == NULL) {
+ /* Couldn't find version 2, try version 9 */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SDESCRIPTIONS, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s srtp lifetime attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return SDP_INVALID_PARAMETER;
+ }
+
+ }
+
+ sstrncpy((char*)attr_p->attr.srtp_context.master_key_lifetime, lifetime,
+ SDP_SRTP_MAX_LIFETIME_BYTES);
+ return SDP_SUCCESS;
+
+}
+
+
+/* Function: sdp_attr_set_sdescriptions_mki
+ * Description: Sets the sdescriptions mki parameter compose of the MKI
+ * value and length. Note that this is a common api for both
+ * version 2 and version 9 sdescriptions. It has no knowledge
+ * which version is being used so it will first try to find if
+ * a version 2 sdescriptions attribute is present. If it is, it will
+ * set the lifetime for version 2. If it's not, try to find version 9.
+ * This assumes you cannot have both versions in the same SDP.
+ *
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * mki_value buffer containing the mki value. Assumes null
+ * terminated buffer.
+ * mki_length length of the MKI
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+
+sdp_result_e
+sdp_attr_set_sdescriptions_mki (void *sdp_ptr, u16 level,
+ u8 cap_num, u16 inst_num,
+ char *mki_value,
+ u16 mki_length)
+{
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return SDP_INVALID_SDP_PTR;
+ }
+
+ /* Try version 2 first */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SRTP_CONTEXT, inst_num);
+ if (attr_p == NULL) {
+ /* Couldn't find version 2, try version 9 */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SDESCRIPTIONS, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s srtp MKI attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+
+ sstrncpy((char*)attr_p->attr.srtp_context.mki, mki_value,
+ SDP_SRTP_MAX_MKI_SIZE_BYTES);
+ attr_p->attr.srtp_context.mki_size_bytes = mki_length;
+ return SDP_SUCCESS;
+
+}
+
+
+/* Function: sdp_attr_set_sdescriptions_key_size
+ * Description: Sets the sdescriptions key size parameter. Note that
+ * this is a common api for both version 2 and version 9
+ * sdescriptions. It has no knowledge which version is being
+ * used so it will first try to find if a version 2 sdescriptions
+ * attribute is present. If it is, it will set the key for
+ * version 2. If it's not, try to find version 9. This assumes
+ * you cannot have both versions in the same SDP.
+ *
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * key_size key size
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+
+sdp_result_e
+sdp_attr_set_sdescriptions_key_size (void *sdp_ptr,
+ u16 level,
+ u8 cap_num,
+ u16 inst_num,
+ unsigned char key_size)
+
+{
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return SDP_INVALID_SDP_PTR;
+ }
+
+ /* Try version 2 first */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SRTP_CONTEXT, inst_num);
+ if (attr_p == NULL) {
+ /* Couldn't find version 2, try version 9 */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SDESCRIPTIONS, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s srtp MKI attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+
+ attr_p->attr.srtp_context.master_key_size_bytes = key_size;
+ return SDP_SUCCESS;
+
+}
+
+
+/* Function: sdp_attr_set_sdescriptions_key_size
+ * Description: Sets the sdescriptions salt size parameter. Note that
+ * this is a common api for both version 2 and version 9
+ * sdescriptions. It has no knowledge which version is being
+ * used so it will first try to find if a version 2 sdescriptions
+ * attribute is present. If it is, it will set the salt for
+ * version 2. If it's not, try to find version 9. This assumes
+ * you cannot have both versions in the same SDP.
+ *
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * salt_size salt size
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+
+sdp_result_e
+sdp_attr_set_sdescriptions_salt_size (void *sdp_ptr,
+ u16 level,
+ u8 cap_num,
+ u16 inst_num,
+ unsigned char salt_size)
+{
+
+ sdp_t *sdp_p = (sdp_t *)sdp_ptr;
+ sdp_attr_t *attr_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return SDP_INVALID_SDP_PTR;
+ }
+
+ /* Try version 2 first */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SRTP_CONTEXT, inst_num);
+ if (attr_p == NULL) {
+ /* Couldn't find version 2, try version 9 */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SDESCRIPTIONS, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s srtp MKI attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, level, inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+
+ attr_p->attr.srtp_context.master_salt_size_bytes = salt_size;
+ return SDP_SUCCESS;
+
+}
+
diff --git a/libs/sipcc/core/sdp/sdp_base64.c b/libs/sipcc/core/sdp/sdp_base64.c
new file mode 100644
index 0000000000..0cef82166d
--- /dev/null
+++ b/libs/sipcc/core/sdp/sdp_base64.c
@@ -0,0 +1,394 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "sdp_base64.h"
+
+/*
+ * Local definitions for Base64 to Raw table entries.
+ */
+#define INVALID_CHAR 0xFF /* Character not in supported Base64 set */
+#define WHITE_SPACE 0xFE /* Space, tab, newline, etc character */
+#define PADDING 0xFD /* The character '=' */
+
+#define PAD_CHAR '=' /* The character '=' */
+
+/* Maximum length of a base64 encoded line */
+#define MAX_BASE64_LINE_LENGTH 76
+
+/*
+ * base64_result_table
+ * String table for translating base64 error codes into human
+ * understanable strings.
+ */
+char *base64_result_table[BASE64_RESULT_MAX] =
+{
+ "Base64 successful",
+ "Base64 Buffer Overrun",
+ "Base64 Bad Data",
+ "Base64 Bad Padding",
+ "Base64 Bad Block Size"
+};
+
+/*
+ * base64_to_raw_table
+ * Heart of the Base64 decoding algorithm. Lookup table to convert
+ * the Base64 characters into their specified representative values.
+ * Invalid characters are marked with 0xFF, white space characters
+ * are marked with 0xFE, and the special pading character is marked
+ * with 0xFD.
+ */
+unsigned char base64_to_raw_table[128] =
+{
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, /* 0-9 */
+ 0xFE, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 10-19 */
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 20-29 */
+ 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 30-39 */
+ 0xFF, 0xFF, 0xFF, 62, 0xFF, 0xFF, 0xFF, 63, 52, 53, /* 40-49 */
+ 54, 55, 56, 57, 58, 59, 60, 61, 0xFF, 0xFF, /* 50-59 */
+ 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3, 4, /* 60-69 */
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 70-79 */
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, /* 80-89 */
+ 25, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 26, 27, 28, /* 90-99 */
+ 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, /* 100-109 */
+ 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, /* 110-119 */
+ 49, 50, 51, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF /* 120-127 */
+};
+
+unsigned char raw_to_base64_table[64] =
+{
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', /* 0-9 */
+ 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', /* 10-19 */
+ 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', /* 20-29 */
+ 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', /* 30-39 */
+ 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', /* 40-49 */
+ 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', /* 50-59 */
+ '8', '9', '+', '/' /* 60-63 */
+};
+
+/*
+ * base64_encode_size_bytes
+ *
+ * DESCRIPTION
+ * Estimates the size of buffer required for holding the result of
+ * encoding data of size raw_size_bytes.
+ *
+ * PARAMETERS
+ * raw_size_bytes = Estimated size of the un-encoded data in bytes.
+ *
+ * RETURN VALUE
+ * The size of destination buffer to use for encoding in bytes.
+ */
+int base64_est_encode_size_bytes (int raw_size_bytes)
+{
+ int length;
+
+ /*
+ * Find the number of bytes needed to represent the data
+ * using a 4/3 expansion ratio. That result must be
+ * rounded to the next higher multiple of four to account
+ * for padding. Then add in a term to account for any '\n's
+ * added.
+ */
+ length = ((((raw_size_bytes * 4 + 2)/ 3) + 3) & ~(0x3)) +
+ raw_size_bytes / MAX_BASE64_LINE_LENGTH;
+
+ return length;
+}
+
+/*
+ * base64_decode_size_bytes
+ *
+ * DESCRIPTION
+ * Estimates the size of buffer required for holding the result of
+ * decoding data of size base64_size_bytes.
+ *
+ * PARAMETERS
+ * base64_size_bytes = Estimated size of the Base64 data in bytes.
+ *
+ * RETURN VALUE
+ * The size of destination buffer to use for decoding in bytes.
+ */
+int base64_est_decode_size_bytes (int base64_size_bytes)
+{
+ int length;
+
+ length = (base64_size_bytes * 3 + 3) / 4;
+ return length;
+}
+
+/*
+ * base64_encode
+ *
+ * DESCRIPTION
+ * Encode data pointed to by src into the buffer pointer to by dest
+ * using the Base64 algorithm.
+ *
+ * NOTE: No trailing '\n' character will be added.
+ *
+ * NOTE: As per specification, '\n' will be placed every 76 chars.
+ *
+ * PARAMETERS
+ * src = Pointer to the raw data to base64 encode.
+ * src_bytes = The number of bytes in the src buffer to encode.
+ * dest = Pointer to the destination buffer where the converted data
+ * will reside when complete.
+ * dest_bytes = Initially holds the size of the destination buffer
+ * but at completion holds the number of bytes converted.
+ *
+ * RETURN VALUE
+ * base64_success if the buffer was successfully converted, the
+ * appropriate error code otherwise.
+ *
+ * The dest parameter holds the converted data.
+ *
+ * The dest_bytes parameter holds the actual number of bytes converted.
+ */
+base64_result_t base64_encode(unsigned char *src, int src_bytes, unsigned char *dest, int *dest_bytes)
+{
+ int i, j=0;
+ int line_count = 0;
+ unsigned char index; /* index into base64 lookup table */
+ int smax = src_bytes-2; /* only do full multiples of 3 */
+ int dmax = *dest_bytes; /* destination maximum */
+
+ *dest_bytes = 0;
+
+ /* Do full groups. Base64 must be done in blocks of 3 src bytes */
+ for (i=0; i=MAX_BASE64_LINE_LENGTH) {
+ if (j> 2) & 0x3F;
+ dest[j++] = raw_to_base64_table[index];
+
+ /* bottom 2 bits of first word, high 4 bits of second word */
+ index = ((src[i] << 4) & 0x30) | ((src[i+1] >> 4) & 0x0F);
+ dest[j++] = raw_to_base64_table[index];
+
+ /* bottom 4 bits of second word, high 2 bits of third word */
+ index = ((src[i+1] << 2) & 0x3C) | ((src[i+2] >> 6) & 0x03);
+ dest[j++] = raw_to_base64_table[index];
+
+ /* bottom 6 bits of third word */
+ index = src[i+2] & 0x3F;
+ dest[j++] = raw_to_base64_table[index];
+ } else {
+ return BASE64_BUFFER_OVERRUN;
+ }
+ }
+
+ /* Check to see if any more work must be done */
+ if (i=MAX_BASE64_LINE_LENGTH) {
+ if (jdmax) {
+ /* No room left in output buffer! */
+ return BASE64_BUFFER_OVERRUN;
+ }
+
+ /* Find mapping of upper 6 bits */
+ index = (src[i] >> 2) & 0x3F;
+ dest[j++] = raw_to_base64_table[index];
+
+ /* check for another stragler */
+ if ((i+1)> 4) & 0x0F);
+ dest[j++] = raw_to_base64_table[index];
+
+ /* bottom 4 bits of second word */
+ index = (src[i+1] << 2) & 0x3C;
+ dest[j++] = raw_to_base64_table[index];
+ dest[j++] = PAD_CHAR;
+ } else {
+ /* bottom 2 bits of first word */
+ index = (src[i] << 4) & 0x30;
+ dest[j++] = raw_to_base64_table[index];
+ dest[j++] = PAD_CHAR;
+ dest[j++] = PAD_CHAR;
+ }
+ }
+
+ *dest_bytes = j;
+
+ return BASE64_SUCCESS;
+}
+
+/*
+ * base64_decode
+ *
+ * DESCRIPTION
+ * Decode data pointed to by src into the buffer pointer to by dest
+ * using the Base64 algorithm.
+ *
+ * PARAMETERS
+ * src = Pointer to the Base64 data to decode.
+ * src_bytes = The number of bytes in the src buffer to decode.
+ * dest = Pointer to the destination buffer where the converted data
+ * will reside when complete.
+ * dest_bytes = Initially holds the size of the destination buffer
+ * but at completion holds the number of bytes converted.
+ *
+ * RETURN VALUE
+ * base64_success if the buffer was successfully converted, the
+ * appropriate error code otherwise.
+ *
+ * The dest parameter holds the converted data.
+ *
+ * The dest_bytes parameter holds the actual number of bytes converted.
+ */
+base64_result_t base64_decode(unsigned char *src, int src_bytes, unsigned char *dest, int *dest_bytes)
+{
+ int i, j = 0;
+ int sindex = 0; /* Current NON-whitespace source
+ * index */
+ int pad_count=0; /* Number of padding characters
+ * encountered */
+ int dest_size_bytes = *dest_bytes; /* Save size of destination buffer */
+ unsigned char cindex; /* The current Base64 character to
+ * process */
+ unsigned char val; /* The value of the current Base64
+ * character */
+
+ *dest_bytes = 0;
+
+ for (i=0; i> 4;
+
+ if (j=src_bytes) ||
+ (base64_to_raw_table[src[i+1]] != PADDING)) {
+ return BASE64_BUFFER_OVERRUN;
+ }
+ }
+ break;
+ case 2:
+ /* Fill Bottom 4 bits */
+ dest[j++] |= val >> 2;
+
+ if (j=src_bytes) ||
+ (base64_to_raw_table[src[i+1]] != PADDING)) {
+ return BASE64_BUFFER_OVERRUN;
+ }
+ }
+ break;
+ case 3:
+ /*
+ * No need to check for overrun here since the
+ * previous case was already checked. If another
+ * group is present then case 0 will check again.
+ */
+
+ /* Fill Bottom 6 bits */
+ dest[j++] |= val;
+ break;
+ }
+ sindex++;
+ }
+
+ /* Check length for multiple of 3 bytes */
+ if (((j + pad_count)% 3) != 0) {
+ return BASE64_BAD_BLOCK_SIZE;
+ }
+
+ /* Save off the number of bytes converted */
+ *dest_bytes = j;
+
+ return BASE64_SUCCESS;
+}
diff --git a/libs/sipcc/core/sdp/sdp_base64.h b/libs/sipcc/core/sdp/sdp_base64.h
new file mode 100644
index 0000000000..e264245b72
--- /dev/null
+++ b/libs/sipcc/core/sdp/sdp_base64.h
@@ -0,0 +1,42 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _SDP_BASE64_H_
+#define _SDP_BASE64_H_
+
+/*
+ * base64_result_t
+ * Enumeration of the result codes for Base64 conversion.
+ */
+typedef enum base64_result_t_ {
+ BASE64_INVALID=-1,
+ BASE64_SUCCESS=0,
+ BASE64_BUFFER_OVERRUN,
+ BASE64_BAD_DATA,
+ BASE64_BAD_PADDING,
+ BASE64_BAD_BLOCK_SIZE,
+ BASE64_RESULT_MAX
+} base64_result_t;
+
+#define MAX_BASE64_STRING_LEN 60
+
+/* Result code string table */
+extern char *base64_result_table[];
+
+/*
+ * BASE64_RESULT_TO_STRING
+ * Macro to convert a Base64 result code into a human readable string.
+ */
+#define BASE64_RESULT_TO_STRING(_result) (((_result)>=0 && (_result)magic_num == SDP_MAGIC_NUM)) {
+ return (TRUE);
+ } else {
+ CSFLogError(logTag, "SDP: Invalid Config pointer.");
+ return (FALSE);
+ }
+}
+
+/* Function: void *sdp_init_config()
+ * Description: Initialize SDP configuration structure with the
+ * following defaults:
+ * All debug levels turned OFF.
+ * All token lines required per RFC2327.
+ * No media types supported.
+ * No network types supported.
+ * No address types supported.
+ * No transport types supported.
+ * Parameters: None.
+ * Returns: A handle for the configuration as a void ptr.
+ */
+sdp_conf_options_t sdp_config_options;
+void *sdp_init_config ()
+{
+ int i;
+ sdp_conf_options_t *conf_p;
+
+ conf_p = & sdp_config_options;
+
+ /* Initialize magic number. */
+ conf_p->magic_num = SDP_MAGIC_NUM;
+
+ /* Set default debug flags. */
+ conf_p->debug_flag[SDP_DEBUG_TRACE] = FALSE;
+ conf_p->debug_flag[SDP_DEBUG_WARNINGS] = FALSE;
+ conf_p->debug_flag[SDP_DEBUG_ERRORS] = FALSE;
+
+ /* Set required lines flags. Note: Only need to set those that */
+ /* are questionable. Most lines aren't required by default. */
+ conf_p->version_reqd = TRUE;
+ conf_p->owner_reqd = TRUE;
+ conf_p->session_name_reqd = TRUE;
+ conf_p->timespec_reqd = TRUE;
+
+ /* No media types supported by default. */
+ for (i=0; i < SDP_MAX_MEDIA_TYPES; i++) {
+ conf_p->media_supported[i] = FALSE;
+ }
+
+ /* No network types supported by default. */
+ for (i=0; i < SDP_MAX_NETWORK_TYPES; i++) {
+ conf_p->nettype_supported[i] = FALSE;
+ }
+
+ /* No address types supported by default. */
+ for (i=0; i < SDP_MAX_ADDR_TYPES; i++) {
+ conf_p->addrtype_supported[i] = FALSE;
+ }
+
+ /* No transport types supported by default. */
+ for (i=0; i < SDP_MAX_TRANSPORT_TYPES; i++) {
+ conf_p->transport_supported[i] = FALSE;
+ }
+
+ /* No choose parameters allowed by default. */
+ for (i=0; i < SDP_MAX_CHOOSE_PARAMS; i++) {
+ conf_p->allow_choose[i] = FALSE;
+ }
+
+ /* Initialize statistics counts */
+ conf_p->num_parses = 0;
+ conf_p->num_builds = 0;
+ conf_p->num_not_sdp_desc = 0;
+ conf_p->num_invalid_token_order = 0;
+ conf_p->num_invalid_param = 0;
+ conf_p->num_no_resource = 0;
+
+ return (conf_p);
+}
+
+
+/* Function: void sdp_appl_debug(void *config_p, sdp_debug_e debug_type,
+ * tinybool my_bool);
+ * Description: Define the default type of debug for the application.
+ * Valid debug types are ERRORS, WARNINGS, and TRACE. Each
+ * debug type can be turned on/off individually. The
+ * default debug level can be redefined at any time.
+ * Parameters: conf_p The config handle returned by sdp_init_config.
+ * debug_type Specifies the debug type being enabled/disabled.
+ * debug_flag Defines whether the debug should be enabled or not.
+ * Returns: Nothing.
+ */
+void sdp_appl_debug (void *config_p, sdp_debug_e debug_type,
+ tinybool debug_flag)
+{
+ sdp_conf_options_t *conf_p = (sdp_conf_options_t *)config_p;
+
+ if (sdp_verify_conf_ptr(conf_p) == FALSE) {
+ return;
+ }
+
+ if (debug_type < SDP_MAX_DEBUG_TYPES) {
+ conf_p->debug_flag[debug_type] = debug_flag;
+ }
+}
+
+
+/* Functions: void sdp_require_version
+ * void sdp_require_owner
+ * void sdp_require_session_name
+ * void sdp_require_timespec
+ * Description: These functions allow the application to not require several
+ * of the tokens that are specifically required by RFC 2327.
+ * Parameters: conf_p The config handle returned by sdp_init_config.
+ * version_required TRUE or FALSE whether the token should
+ * be required.
+ * Returns: Nothing.
+ */
+void sdp_require_version (void *config_p, tinybool version_required)
+{
+ sdp_conf_options_t *conf_p = (sdp_conf_options_t *)config_p;
+
+ if (sdp_verify_conf_ptr(conf_p) == FALSE) {
+ return;
+ }
+
+ conf_p->version_reqd = version_required;
+}
+
+void sdp_require_owner (void *config_p, tinybool owner_required)
+{
+ sdp_conf_options_t *conf_p = (sdp_conf_options_t *)config_p;
+
+ if (sdp_verify_conf_ptr(conf_p) == FALSE) {
+ return;
+ }
+
+ conf_p->owner_reqd = owner_required;
+}
+
+void sdp_require_session_name (void *config_p, tinybool sess_name_required)
+{
+ sdp_conf_options_t *conf_p = (sdp_conf_options_t *)config_p;
+
+ if (sdp_verify_conf_ptr(conf_p) == FALSE) {
+ return;
+ }
+
+ conf_p->session_name_reqd = sess_name_required;
+}
+
+void sdp_require_timespec (void *config_p, tinybool timespec_required)
+{
+ sdp_conf_options_t *conf_p = (sdp_conf_options_t *)config_p;
+
+ if (sdp_verify_conf_ptr(conf_p) == FALSE) {
+ return;
+ }
+
+ conf_p->timespec_reqd = timespec_required;
+}
+
+
+/* Function: sdp_media_supported
+ * Description: These functions allow the application to specify which
+ * media types it supports. The application must set any/all
+ * as required. No media types are supported by default.
+ * Parameters: config_p The config handle returned by sdp_init_config.
+ * nettype The network type for which support is being set.
+ * media_supported TRUE or FALSE whether the support is provided.
+ * Returns: Nothing.
+ */
+void sdp_media_supported (void *config_p, sdp_media_e media_type,
+ tinybool media_supported)
+{
+ sdp_conf_options_t *conf_p = (sdp_conf_options_t *)config_p;
+
+ if (sdp_verify_conf_ptr(conf_p) == FALSE) {
+ return;
+ }
+
+ conf_p->media_supported[media_type] = media_supported;
+}
+
+
+/* Function: sdp_nettype_supported
+ * Description: This function allows the application to specify which
+ * network types it supports. The application must set
+ * any/all as required. No network types are supported by
+ * default.
+ * Parameters: config_p The config handle returned by sdp_init_config.
+ * nettype The network type for which support is being set.
+ * nettype_supported TRUE or FALSE whether the support is
+ * provided.
+ * Returns: Nothing.
+ */
+void sdp_nettype_supported (void *config_p, sdp_nettype_e nettype,
+ tinybool nettype_supported)
+{
+ sdp_conf_options_t *conf_p = (sdp_conf_options_t *)config_p;
+
+ if (sdp_verify_conf_ptr(conf_p) == FALSE) {
+ return;
+ }
+
+ conf_p->nettype_supported[nettype] = nettype_supported;
+}
+
+
+/* Function: sdp_addrtype_supported
+ * Description: This function allows the application to specify which
+ * address types it supports. The application must set
+ * any/all as required. No address types are supported by
+ * default.
+ * Parameters: config_p The config handle returned by sdp_init_config.
+ * addrtype The address type for which support is being set.
+ * addrtype_supported TRUE or FALSE whether the support is
+ * provided.
+ * Returns: Nothing.
+ */
+void sdp_addrtype_supported (void *config_p, sdp_addrtype_e addrtype,
+ tinybool addrtype_supported)
+{
+ sdp_conf_options_t *conf_p = (sdp_conf_options_t *)config_p;
+
+ if (sdp_verify_conf_ptr(conf_p) == FALSE) {
+ return;
+ }
+
+ conf_p->addrtype_supported[addrtype] = addrtype_supported;
+}
+
+
+/* Function: sdp_transport_supported
+ * Description: This function allows the application to specify which
+ * transport types it supports. The application must set
+ * any/all as required. No transport types are supported
+ * by default.
+ * Parameters: config_p The config handle returned by sdp_init_config.
+ * transport The transport type for which support is being set.
+ * transport_supported TRUE or FALSE whether the support is
+ * provided.
+ * Returns: Nothing.
+ */
+void sdp_transport_supported (void *config_p, sdp_transport_e transport,
+ tinybool transport_supported)
+{
+ sdp_conf_options_t *conf_p = (sdp_conf_options_t *)config_p;
+
+ if (sdp_verify_conf_ptr(conf_p) == FALSE) {
+ return;
+ }
+
+ conf_p->transport_supported[transport] = transport_supported;
+}
+
+
+/* Function: sdp_allow_choose
+ * Description: These functions allow the CHOOSE parameter `$' to be
+ * specified in place of certain parameters.
+ * Parameters: config_p The config handle returned by sdp_init_config.
+ * param The param that may or may not be CHOOSE.
+ * choose_allowed TRUE or FALSE whether the CHOOSE parameter
+ * should be allowed.
+ * Returns: Nothing.
+ */
+void sdp_allow_choose (void *config_p, sdp_choose_param_e param, tinybool choose_allowed)
+{
+ sdp_conf_options_t *conf_p = (sdp_conf_options_t *)config_p;
+
+ if (sdp_verify_conf_ptr(conf_p) == FALSE) {
+ return;
+ }
+
+ if (param < SDP_MAX_CHOOSE_PARAMS) {
+ conf_p->allow_choose[param] = choose_allowed;
+ }
+}
diff --git a/libs/sipcc/core/sdp/sdp_main.c b/libs/sipcc/core/sdp/sdp_main.c
new file mode 100644
index 0000000000..f63857a7d7
--- /dev/null
+++ b/libs/sipcc/core/sdp/sdp_main.c
@@ -0,0 +1,1463 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "sdp_os_defs.h"
+#include "sdp.h"
+#include "sdp_private.h"
+#include "CSFLog.h"
+
+//static const char* logTag = "sdp_main";
+
+/* Note: These *must* be in the same order as the enum types. */
+const sdp_tokenarray_t sdp_token[SDP_MAX_TOKENS] =
+{
+ {"v=", sdp_parse_version, sdp_build_version },
+ {"o=", sdp_parse_owner, sdp_build_owner },
+ {"s=", sdp_parse_sessname, sdp_build_sessname },
+ {"i=", sdp_parse_sessinfo, sdp_build_sessinfo },
+ {"u=", sdp_parse_uri, sdp_build_uri },
+ {"e=", sdp_parse_email, sdp_build_email },
+ {"p=", sdp_parse_phonenum, sdp_build_phonenum },
+ {"c=", sdp_parse_connection, sdp_build_connection },
+ {"b=", sdp_parse_bandwidth, sdp_build_bandwidth },
+ {"t=", sdp_parse_timespec, sdp_build_timespec },
+ {"r=", sdp_parse_repeat_time, sdp_build_repeat_time },
+ {"z=", sdp_parse_timezone_adj, sdp_build_timezone_adj },
+ {"k=", sdp_parse_encryption, sdp_build_encryption },
+ {"a=", sdp_parse_attribute, sdp_build_attribute },
+ {"m=", sdp_parse_media, sdp_build_media }
+};
+
+
+/* Note: These *must* be in the same order as the enum types. */
+const sdp_attrarray_t sdp_attr[SDP_MAX_ATTR_TYPES] =
+{
+ {"bearer", sizeof("bearer"),
+ sdp_parse_attr_simple_string, sdp_build_attr_simple_string },
+ {"called", sizeof("called"),
+ sdp_parse_attr_simple_string, sdp_build_attr_simple_string },
+ {"connection_type", sizeof("connection_type"),
+ sdp_parse_attr_simple_string, sdp_build_attr_simple_string },
+ {"dialed", sizeof("dialed"),
+ sdp_parse_attr_simple_string, sdp_build_attr_simple_string },
+ {"dialing", sizeof("dialing"),
+ sdp_parse_attr_simple_string, sdp_build_attr_simple_string },
+ {"direction", sizeof("direction"),
+ sdp_parse_attr_comediadir, sdp_build_attr_comediadir },
+ {"eecid", sizeof("eecid"),
+ sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32 },
+ {"fmtp", sizeof("fmtp"),
+ sdp_parse_attr_fmtp, sdp_build_attr_fmtp },
+ {"framing", sizeof("framing"),
+ sdp_parse_attr_simple_string, sdp_build_attr_simple_string },
+ {"inactive", sizeof("inactive"),
+ sdp_parse_attr_direction, sdp_build_attr_direction },
+ {"ptime", sizeof("ptime"),
+ sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32 },
+ {"qos", sizeof("qos"),
+ sdp_parse_attr_qos, sdp_build_attr_qos },
+ {"curr", sizeof("curr"),
+ sdp_parse_attr_curr, sdp_build_attr_curr },
+ {"des", sizeof("des"),
+ sdp_parse_attr_des, sdp_build_attr_des},
+ {"conf", sizeof("conf"),
+ sdp_parse_attr_conf, sdp_build_attr_conf},
+ {"recvonly", sizeof("recvonly"),
+ sdp_parse_attr_direction, sdp_build_attr_direction },
+ {"rtpmap", sizeof("rtpmap"),
+ sdp_parse_attr_transport_map, sdp_build_attr_transport_map },
+ {"secure", sizeof("secure"),
+ sdp_parse_attr_qos, sdp_build_attr_qos },
+ {"sendonly", sizeof("sendonly"),
+ sdp_parse_attr_direction, sdp_build_attr_direction },
+ {"sendrecv", sizeof("sendrecv"),
+ sdp_parse_attr_direction, sdp_build_attr_direction },
+ {"subnet", sizeof("subnet"),
+ sdp_parse_attr_subnet, sdp_build_attr_subnet },
+ {"T38FaxVersion", sizeof("T38FaxVersion"),
+ sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32 },
+ {"T38MaxBitRate", sizeof("T38MaxBitRate"),
+ sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32 },
+ {"T38FaxFillBitRemoval", sizeof("T38FaxFillBitRemoval"),
+ sdp_parse_attr_simple_bool, sdp_build_attr_simple_bool },
+ {"T38FaxTranscodingMMR", sizeof("T38FaxTranscodingMMR"),
+ sdp_parse_attr_simple_bool, sdp_build_attr_simple_bool },
+ {"T38FaxTranscodingJBIG", sizeof("T38FaxTranscodingJBIG"),
+ sdp_parse_attr_simple_bool, sdp_build_attr_simple_bool },
+ {"T38FaxRateManagement", sizeof("T38FaxRateManagement"),
+ sdp_parse_attr_t38_ratemgmt, sdp_build_attr_t38_ratemgmt },
+ {"T38FaxMaxBuffer", sizeof("T38FaxMaxBuffer"),
+ sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32 },
+ {"T38FaxMaxDatagram", sizeof("T38FaxMaxDatagram"),
+ sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32 },
+ {"T38FaxUdpEC", sizeof("T38FaxUdpEC"),
+ sdp_parse_attr_t38_udpec, sdp_build_attr_t38_udpec },
+ {"X-cap", sizeof("X-cap"),
+ sdp_parse_attr_cap, sdp_build_attr_cap },
+ {"X-cpar", sizeof("X-cpar"),
+ sdp_parse_attr_cpar, sdp_build_attr_cpar },
+ {"X-pc-codec", sizeof("X-pc-codec"),
+ sdp_parse_attr_pc_codec, sdp_build_attr_pc_codec },
+ {"X-pc-qos", sizeof("X-pc-qos"),
+ sdp_parse_attr_qos, sdp_build_attr_qos },
+ {"X-qos", sizeof("X-qos"),
+ sdp_parse_attr_qos, sdp_build_attr_qos },
+ {"X-sqn", sizeof("X-sqn"),
+ sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32 },
+ {"TMRGwXid", sizeof("TMRGwXid"),
+ sdp_parse_attr_simple_bool, sdp_build_attr_simple_bool },
+ {"TC1PayloadBytes", sizeof("TC1PayloadBytes"),
+ sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32 },
+ {"TC1WindowSize", sizeof("TC1WindowSize"),
+ sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32 },
+ {"TC2PayloadBytes", sizeof("TC2PayloadBytes"),
+ sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32 },
+ {"TC2WindowSize", sizeof("TC2WindowSize"),
+ sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32 },
+ {"rtcp", sizeof("rtcp"),
+ sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32 },
+ {"rtr", sizeof("rtr"),
+ sdp_parse_attr_rtr, sdp_build_attr_rtr},
+ {"silenceSupp", sizeof("silenceSupp"),
+ sdp_parse_attr_silencesupp, sdp_build_attr_silencesupp },
+ {"X-crypto", sizeof("X-crypto"),
+ sdp_parse_attr_srtpcontext, sdp_build_attr_srtpcontext },
+ {"mptime", sizeof("mptime"),
+ sdp_parse_attr_mptime, sdp_build_attr_mptime },
+ {"X-sidin", sizeof("X-sidin"),
+ sdp_parse_attr_x_sidin, sdp_build_attr_x_sidin },
+ {"X-sidout", sizeof("X-sidout"),
+ sdp_parse_attr_x_sidout, sdp_build_attr_x_sidout },
+ {"X-confid", sizeof("X-confid"),
+ sdp_parse_attr_x_confid, sdp_build_attr_x_confid },
+ {"group", sizeof("group"),
+ sdp_parse_attr_group, sdp_build_attr_group },
+ {"mid", sizeof("mid"),
+ sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32 },
+ {"source-filter", sizeof("source-filter"),
+ sdp_parse_attr_source_filter, sdp_build_source_filter},
+ {"rtcp-unicast", sizeof("rtcp-unicast"),
+ sdp_parse_attr_rtcp_unicast, sdp_build_attr_rtcp_unicast},
+ {"maxprate", sizeof("maxprate"),
+ sdp_parse_attr_maxprate, sdp_build_attr_simple_string},
+ {"sqn", sizeof("sqn"),
+ sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32 },
+ {"cdsc", sizeof("cdsc"),
+ sdp_parse_attr_cap, sdp_build_attr_cap },
+ {"cpar", sizeof("cpar"),
+ sdp_parse_attr_cpar, sdp_build_attr_cpar },
+ {"sprtmap", sizeof("sprtmap"),
+ sdp_parse_attr_transport_map, sdp_build_attr_transport_map },
+ {"crypto", sizeof("crypto"),
+ sdp_parse_attr_sdescriptions, sdp_build_attr_sdescriptions },
+ {"label", sizeof("label"),
+ sdp_parse_attr_simple_string, sdp_build_attr_simple_string },
+ {"framerate", sizeof("framerate"),
+ sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32 },
+ {"candidate", sizeof("candidate"),
+ sdp_parse_attr_ice_attr, sdp_build_attr_ice_attr },
+ {"ice-ufrag", sizeof("ice-ufrag"),
+ sdp_parse_attr_ice_attr, sdp_build_attr_ice_attr },
+ {"ice-pwd", sizeof("ice-pwd"),
+ sdp_parse_attr_ice_attr, sdp_build_attr_ice_attr},
+ {"rtcp-mux", sizeof("rtcp-mux"),
+ sdp_parse_attr_rtcp_mux_attr, sdp_build_attr_rtcp_mux_attr},
+ {"fingerprint", sizeof("fingerprint"),
+ sdp_parse_attr_fingerprint_attr, sdp_build_attr_simple_string},
+ {"maxptime", sizeof("maxptime"),
+ sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32}
+};
+
+/* Note: These *must* be in the same order as the enum types. */
+const sdp_namearray_t sdp_media[SDP_MAX_MEDIA_TYPES] =
+{
+ {"audio", sizeof("audio")},
+ {"video", sizeof("video")},
+ {"application", sizeof("application")},
+ {"data", sizeof("data")},
+ {"control", sizeof("control")},
+ {"nas/radius", sizeof("nas/radius")},
+ {"nas/tacacs", sizeof("nas/tacacs")},
+ {"nas/diameter", sizeof("nas/diameter")},
+ {"nas/l2tp", sizeof("nas/l2tp")},
+ {"nas/login", sizeof("nas/login")},
+ {"nas/none", sizeof("nas/none")},
+ {"image", sizeof("image")},
+ {"text", sizeof("text")}
+};
+
+
+/* Note: These *must* be in the same order as the enum types. */
+const sdp_namearray_t sdp_nettype[SDP_MAX_NETWORK_TYPES] =
+{
+ {"IN", sizeof("IN")},
+ {"ATM", sizeof("ATM")},
+ {"FR", sizeof("FR")},
+ {"LOCAL", sizeof("LOCAL")}
+};
+
+
+/* Note: These *must* be in the same order as the enum types. */
+const sdp_namearray_t sdp_addrtype[SDP_MAX_ADDR_TYPES] =
+{
+ {"IP4", sizeof("IP4")},
+ {"IP6", sizeof("IP6")},
+ {"NSAP", sizeof("NSAP")},
+ {"EPN", sizeof("EPN")},
+ {"E164", sizeof("E164")},
+ {"GWID", sizeof("GWID")}
+};
+
+
+/* Note: These *must* be in the same order as the enum type. */
+const sdp_namearray_t sdp_transport[SDP_MAX_TRANSPORT_TYPES] =
+{
+ {"RTP/AVP", sizeof("RTP/AVP")},
+ {"udp", sizeof("udp")},
+ {"udptl", sizeof("udptl")},
+ {"ces10", sizeof("ces10")},
+ {"LOCAL", sizeof("LOCAL")},
+ {"AAL2/ITU", sizeof("AAL2/ITU")},
+ {"AAL2/ATMF", sizeof("AAL2/ATMF")},
+ {"AAL2/custom", sizeof("AAL2/custom")},
+ {"AAL1/AVP", sizeof("AAL1/AVP")},
+ {"udpsprt", sizeof("udpsprt")},
+ {"RTP/SAVP", sizeof("RTP/SAVP")},
+ {"tcp", sizeof("tcp")},
+ {"RTP/SAVPF", sizeof("RTP/SAVPF")},
+ {"SCTP/DTLS", sizeof("SCTP/DTLS")}
+};
+
+/* Note: These *must* be in the same order as the enum type. */
+const sdp_namearray_t sdp_encrypt[SDP_MAX_ENCRYPT_TYPES] =
+{
+ {"clear", sizeof("clear")},
+ {"base64", sizeof("base64")},
+ {"uri", sizeof("uri")},
+ {"prompt", sizeof("prompt")}
+};
+
+/* Note: These *must* be in the same order as the enum type. */
+const sdp_namearray_t sdp_payload[SDP_MAX_STRING_PAYLOAD_TYPES] =
+{
+ {"t38", sizeof("t38")},
+ {"X-tmr", sizeof("X-tmr")},
+ {"T120", sizeof("T120")}
+};
+
+/* Note: These *must* be in the same order as the enum type. */
+const sdp_namearray_t sdp_t38_rate[SDP_T38_MAX_RATES] =
+{
+ {"localTCF", sizeof("localTCF")},
+ {"transferredTCF", sizeof("transferredTCF")},
+ {"unknown", sizeof("unknown")}
+};
+
+/* Note: These *must* be in the same order as the enum type. */
+const sdp_namearray_t sdp_t38_udpec[SDP_T38_MAX_UDPEC] =
+{
+ {"t38UDPRedundancy", sizeof("t38UDPRedundancy")},
+ {"t38UDPFEC", sizeof("t38UDPFEC")},
+ {"unknown", sizeof("unknown")}
+};
+
+/* Note: These *must* be in the same order as the enum type. */
+const sdp_namearray_t sdp_qos_strength[SDP_MAX_QOS_STRENGTH] =
+{
+ {"optional", sizeof("optional")},
+ {"mandatory", sizeof("mandatory")},
+ {"success", sizeof("success")},
+ {"failure", sizeof("failure")},
+ {"none", sizeof("none")}
+};
+
+/* Note: These *must* be in the same order as the enum type. */
+const sdp_namearray_t sdp_qos_status_type[SDP_MAX_QOS_STATUS_TYPES] =
+{
+ {"local", sizeof("local")},
+ {"remote", sizeof("remote")},
+ {"e2e", sizeof("e2e")}
+};
+
+/* Note: These *must* be in the same order as the enum type. */
+const sdp_namearray_t sdp_curr_type[SDP_MAX_CURR_TYPES] =
+{
+ {"qos", sizeof("qos")},
+ {"unknown", sizeof("unknown")}
+};
+
+/* Note: These *must* be in the same order as the enum type. */
+const sdp_namearray_t sdp_des_type[SDP_MAX_DES_TYPES] =
+{
+ {"qos", sizeof("qos")},
+ {"unknown", sizeof("unknown")}
+};
+
+/* Note: These *must* be in the same order as the enum type. */
+const sdp_namearray_t sdp_conf_type[SDP_MAX_CONF_TYPES] =
+{
+ {"qos", sizeof("qos")},
+ {"unknown", sizeof("unknown")}
+};
+/* Note: These *must* be in the same order as the enum type. */
+const sdp_namearray_t sdp_qos_direction[SDP_MAX_QOS_DIR] =
+{
+ {"send", sizeof("send")},
+ {"recv", sizeof("recv")},
+ {"sendrecv", sizeof("sendrecv")},
+ {"none", sizeof("none")}
+};
+
+/* Note: These *must* be in the same order as the enum type. */
+const sdp_namearray_t sdp_silencesupp_pref[SDP_MAX_SILENCESUPP_PREF] = {
+ {"standard", sizeof("standard")},
+ {"custom", sizeof("custom")},
+ {"-", sizeof("-")}
+};
+
+/* Note: These *must* be in the same order as the enum type. */
+const sdp_namearray_t sdp_silencesupp_siduse[SDP_MAX_SILENCESUPP_SIDUSE] = {
+ {"No SID", sizeof("No SID")},
+ {"Fixed Noise", sizeof("Fixed Noise")},
+ {"Sampled Noise", sizeof("Sampled Noise")},
+ {"-", sizeof("-")}
+};
+
+/* Note: These *must* be in the same order as the enum type. */
+const sdp_namearray_t sdp_mediadir_role[SDP_MAX_MEDIADIR_ROLES] =
+{
+ {"passive", sizeof("passive")},
+ {"active", sizeof("active")},
+ {"both", sizeof("both")},
+ {"reuse", sizeof("reuse")},
+ {"unknown", sizeof("unknown")}
+};
+
+/* Note: These *must* be in the same order as the enum type. */
+const sdp_namearray_t sdp_fmtp_codec_param[SDP_MAX_FMTP_PARAM] =
+{
+ {"annexa", sizeof("annexa")}, /* 0 */
+ {"annexb", sizeof("annexb")}, /* 1 */
+ {"bitrate", sizeof("bitrate")}, /* 2 */
+ {"QCIF", sizeof("QCIF")}, /* 3 */
+ {"CIF", sizeof("CIF")}, /* 4 */
+ {"MAXBR", sizeof("MAXBR")}, /* 5 */
+ {"SQCIF", sizeof("SQCIF")}, /* 6 */
+ {"CIF4", sizeof("CIF4")}, /* 7 */
+ {"CIF16", sizeof("CIF16")}, /* 8 */
+ {"CUSTOM", sizeof("CUSTOM")}, /* 9 */
+ {"PAR", sizeof("PAR")}, /* 10 */
+ {"CPCF", sizeof("CPCF")}, /* 11 */
+ {"BPP", sizeof("BPP")}, /* 12 */
+ {"HRD", sizeof("HRD")}, /* 13 */
+ {"PROFILE", sizeof("PROFILE")}, /* 14 */
+ {"LEVEL", sizeof("LEVEL")}, /* 15 */
+ {"INTERLACE", sizeof("INTERLACE")}, /* 16 */
+
+ /* H.264 related */
+ {"profile-level-id", sizeof("profile-level-id")}, /* 17 */
+ {"sprop-parameter-sets", sizeof("sprop-parameter-sets")}, /* 18 */
+ {"packetization-mode", sizeof("packetization-mode")}, /* 19 */
+ {"sprop-interleaving-depth", sizeof("sprop-interleaving-depth")}, /* 20 */
+ {"sprop-deint-buf-req", sizeof("sprop-deint-buf-req")}, /* 21 */
+ {"sprop-max-don-diff", sizeof("sprop-max-don-diff")}, /* 22 */
+ {"sprop-init-buf-time", sizeof("sprop-init-buf-time")}, /* 23 */
+
+ {"max-mbps", sizeof("max-mbps")}, /* 24 */
+ {"max-fs", sizeof("max-fs")}, /* 25 */
+ {"max-cpb", sizeof("max-cpb")}, /* 26 */
+ {"max-dpb", sizeof("max-dpb")}, /* 27 */
+ {"max-br", sizeof("max-br")}, /* 28 */
+ {"redundant-pic-cap", sizeof("redundant-pic-cap")}, /* 29 */
+ {"deint-buf-cap", sizeof("deint-buf-cap")}, /* 30 */
+ {"max-rcmd-nalu-size", sizeof("max-rcmd_nali-size")}, /* 31 */
+ {"parameter-add", sizeof("parameter-add")}, /* 32 */
+
+ /* Annexes - require special handling */
+ {"D", sizeof("D")}, /* 33 */
+ {"F", sizeof("F")}, /* 34 */
+ {"I", sizeof("I")}, /* 35 */
+ {"J", sizeof("J")}, /* 36 */
+ {"T", sizeof("T")}, /* 37 */
+ {"K", sizeof("K")}, /* 38 */
+ {"N", sizeof("N")}, /* 39 */
+ {"P", sizeof("P")}, /* 40 */
+
+ {"mode", sizeof("mode")}, /* 41 */
+ {"level-asymmetry-allowed", sizeof("level-asymmetry-allowed")}, /* 42 */
+ {"maxaveragebitrate", sizeof("maxaveragebitrate")}, /* 43 */
+ {"usedtx", sizeof("usedtx")}, /* 44 */
+ {"stereo", sizeof("stereo")}, /* 45 */
+ {"useinbandfec", sizeof("useinbandfec")}, /* 46 */
+ {"maxcodedaudiobandwidth", sizeof("maxcodedaudiobandwidth")}, /* 47 */
+ {"cbr", sizeof("cbr")}, /* 48 */
+ {"streams", sizeof("streams")}, /* 49 */
+ {"protocol", sizeof("protocol")} /* 50 */
+
+} ;
+
+/* Note: These *must* be in the same order as the enum type. */
+const sdp_namearray_t sdp_fmtp_codec_param_val[SDP_MAX_FMTP_PARAM_VAL] =
+{
+ {"yes", sizeof("yes")},
+ {"no", sizeof("no")}
+};
+
+const sdp_namearray_t sdp_bw_modifier_val[SDP_MAX_BW_MODIFIER_VAL] =
+{
+ {"AS", sizeof("AS")},
+ {"CT", sizeof("CT")},
+ {"TIAS", sizeof("TIAS")}
+};
+
+const sdp_namearray_t sdp_group_attr_val[SDP_MAX_GROUP_ATTR_VAL] =
+{
+ {"FID", sizeof("FID")},
+ {"LS", sizeof("LS")},
+ {"ANAT", sizeof("ANAT")}
+};
+
+const sdp_namearray_t sdp_srtp_context_crypto_suite[SDP_SRTP_MAX_NUM_CRYPTO_SUITES] =
+{
+ {"UNKNOWN_CRYPTO_SUITE", sizeof("UNKNOWN_CRYPTO_SUITE")},
+ {"AES_CM_128_HMAC_SHA1_32", sizeof("AES_CM_128_HMAC_SHA1_32")},
+ {"AES_CM_128_HMAC_SHA1_80", sizeof("AES_CM_128_HMAC_SHA1_80")},
+ {"F8_128_HMAC_SHA1_80", sizeof("F8_128_HMAC_SHA1_80")}
+};
+
+/* Maintain the same order as defined in typedef sdp_src_filter_mode_e */
+const sdp_namearray_t sdp_src_filter_mode_val[SDP_MAX_FILTER_MODE] =
+{
+ {"incl", sizeof("incl")},
+ {"excl", sizeof("excl")}
+};
+
+/* Maintain the same order as defined in typdef sdp_rtcp_unicast_mode_e */
+const sdp_namearray_t sdp_rtcp_unicast_mode_val[SDP_RTCP_MAX_UNICAST_MODE] =
+{
+ {"reflection", sizeof("reflection")},
+ {"rsi", sizeof("rsi")}
+};
+
+/* Maintain same order as defined in typedef sdp_srtp_crypto_suite_t */
+const sdp_srtp_crypto_suite_list sdp_srtp_crypto_suite_array[SDP_SRTP_MAX_NUM_CRYPTO_SUITES] =
+{
+ {SDP_SRTP_UNKNOWN_CRYPTO_SUITE, UNKNOWN_CRYPTO_SUITE, 0, 0},
+ {SDP_SRTP_AES_CM_128_HMAC_SHA1_32, AES_CM_128_HMAC_SHA1_32,
+ SDP_SRTP_AES_CM_128_HMAC_SHA1_32_KEY_BYTES,
+ SDP_SRTP_AES_CM_128_HMAC_SHA1_32_SALT_BYTES},
+ {SDP_SRTP_AES_CM_128_HMAC_SHA1_80, AES_CM_128_HMAC_SHA1_80,
+ SDP_SRTP_AES_CM_128_HMAC_SHA1_80_KEY_BYTES,
+ SDP_SRTP_AES_CM_128_HMAC_SHA1_80_SALT_BYTES},
+ {SDP_SRTP_F8_128_HMAC_SHA1_80, F8_128_HMAC_SHA1_80,
+ SDP_SRTP_F8_128_HMAC_SHA1_80_KEY_BYTES,
+ SDP_SRTP_F8_128_HMAC_SHA1_80_SALT_BYTES}
+};
+
+const char* sdp_result_name[SDP_MAX_RC] =
+ {"SDP_SUCCESS",
+ "SDP_FAILURE",
+ "SDP_INVALID_SDP_PTR",
+ "SDP_NOT_SDP_DESCRIPTION",
+ "SDP_INVALID_TOKEN_ORDERING",
+ "SDP_INVALID_PARAMETER",
+ "SDP_INVALID_MEDIA_LEVEL",
+ "SDP_INVALID_CAPABILITY",
+ "SDP_NO_RESOURCE",
+ "SDP_UNRECOGNIZED_TOKEN",
+ "SDP_NULL_BUF_PTR",
+ "SDP_POTENTIAL_SDP_OVERFLOW"};
+
+const char *sdp_get_result_name ( sdp_result_e rc )
+{
+ if (rc >= SDP_MAX_RC) {
+ return ("Invalid SDP result code");
+ } else {
+ return (sdp_result_name[rc]);
+ }
+}
+
+const char *sdp_get_attr_name ( sdp_attr_e attr_type )
+{
+ if (attr_type >= SDP_MAX_ATTR_TYPES) {
+ return ("Invalid attribute type");
+ } else {
+ return (sdp_attr[attr_type].name);
+ }
+}
+
+const char *sdp_get_media_name ( sdp_media_e media_type )
+{
+ if (media_type == SDP_MEDIA_UNSUPPORTED) {
+ return (SDP_UNSUPPORTED);
+ } else if (media_type >= SDP_MAX_MEDIA_TYPES) {
+ return ("Invalid media type");
+ } else {
+ return (sdp_media[media_type].name);
+ }
+}
+
+const char *sdp_get_network_name ( sdp_nettype_e network_type )
+{
+ if (network_type == SDP_NT_UNSUPPORTED) {
+ return (SDP_UNSUPPORTED);
+ } else if (network_type >= SDP_MAX_NETWORK_TYPES) {
+ return ("Invalid network type");
+ } else {
+ return (sdp_nettype[network_type].name);
+ }
+}
+
+const char *sdp_get_address_name ( sdp_addrtype_e addr_type )
+{
+ if (addr_type == SDP_AT_UNSUPPORTED) {
+ return (SDP_UNSUPPORTED);
+ } else if (addr_type >= SDP_MAX_ADDR_TYPES) {
+ if (addr_type == SDP_AT_FQDN) {
+ return ("*");
+ } else {
+ return ("Invalid address type");
+ }
+ } else {
+ return (sdp_addrtype[addr_type].name);
+ }
+}
+
+const char *sdp_get_transport_name ( sdp_transport_e transport_type )
+{
+ if (transport_type == SDP_TRANSPORT_UNSUPPORTED) {
+ return (SDP_UNSUPPORTED);
+ } else if (transport_type >= SDP_MAX_TRANSPORT_TYPES) {
+ return ("Invalid transport type");
+ } else {
+ return (sdp_transport[transport_type].name);
+ }
+}
+
+const char *sdp_get_encrypt_name ( sdp_encrypt_type_e encrypt_type )
+{
+ if (encrypt_type == SDP_ENCRYPT_UNSUPPORTED) {
+ return (SDP_UNSUPPORTED);
+ } else if (encrypt_type >= SDP_MAX_ENCRYPT_TYPES) {
+ return ("Invalid encryption type");
+ } else {
+ return (sdp_encrypt[encrypt_type].name);
+ }
+}
+
+const char *sdp_get_payload_name ( sdp_payload_e payload )
+{
+ if (payload == SDP_PAYLOAD_UNSUPPORTED) {
+ return (SDP_UNSUPPORTED);
+ } else if (payload >= SDP_MAX_STRING_PAYLOAD_TYPES) {
+ return ("Invalid payload type");
+ } else {
+ return (sdp_payload[payload].name);
+ }
+}
+
+const char *sdp_get_t38_ratemgmt_name ( sdp_t38_ratemgmt_e rate )
+{
+ if (rate >= SDP_T38_MAX_RATES) {
+ return ("Invalid rate");
+ } else {
+ return (sdp_t38_rate[rate].name);
+ }
+}
+
+const char *sdp_get_t38_udpec_name ( sdp_t38_udpec_e udpec )
+{
+ if (udpec >= SDP_T38_MAX_UDPEC) {
+ return ("Invalid udpec");
+ } else {
+ return (sdp_t38_udpec[udpec].name);
+ }
+}
+
+const char *sdp_get_qos_strength_name ( sdp_qos_strength_e strength )
+{
+ if (strength >= SDP_MAX_QOS_STRENGTH) {
+ return ("Invalid qos strength");
+ } else {
+ return (sdp_qos_strength[strength].name);
+ }
+}
+
+const char *sdp_get_qos_direction_name ( sdp_qos_dir_e direction )
+{
+ if (direction >= SDP_MAX_QOS_DIR) {
+ return ("Invalid qos direction");
+ } else {
+ return (sdp_qos_direction[direction].name);
+ }
+}
+
+const char *sdp_get_qos_status_type_name ( sdp_qos_status_types_e status_type )
+{
+ if (status_type >= SDP_MAX_QOS_STATUS_TYPES) {
+ return ("Invalid qos status type");
+ } else {
+ return (sdp_qos_status_type[status_type].name);
+ }
+}
+
+const char *sdp_get_curr_type_name (sdp_curr_type_e curr_type )
+{
+ if (curr_type >= SDP_MAX_CURR_TYPES) {
+ return ("Invalid curr type");
+ } else {
+ return (sdp_curr_type[curr_type].name);
+ }
+}
+
+const char *sdp_get_des_type_name (sdp_des_type_e des_type )
+{
+ if (des_type >= SDP_MAX_DES_TYPES) {
+ return ("Invalid des type");
+ } else {
+ return (sdp_des_type[des_type].name);
+ }
+}
+
+const char *sdp_get_conf_type_name (sdp_conf_type_e conf_type )
+{
+ if (conf_type >= SDP_MAX_CONF_TYPES) {
+ return ("Invalid conf type");
+ } else {
+ return (sdp_conf_type[conf_type].name);
+ }
+}
+
+const char *sdp_get_silencesupp_pref_name (sdp_silencesupp_pref_e pref)
+{
+ if (pref >= SDP_MAX_SILENCESUPP_PREF) {
+ return ("Invalid silencesupp pref");
+ } else {
+ return (sdp_silencesupp_pref[pref].name);
+ }
+}
+
+const char *sdp_get_silencesupp_siduse_name (sdp_silencesupp_siduse_e siduse)
+{
+ if (siduse >= SDP_MAX_SILENCESUPP_SIDUSE) {
+ return ("Invalid silencesupp siduse");
+ } else {
+ return (sdp_silencesupp_siduse[siduse].name);
+ }
+}
+
+const char *sdp_get_mediadir_role_name (sdp_mediadir_role_e role)
+{
+ if (role >= SDP_MEDIADIR_ROLE_UNKNOWN) {
+ return ("Invalid media direction role");
+ } else {
+ return (sdp_mediadir_role[role].name);
+ }
+}
+
+
+const char *sdp_get_bw_modifier_name (sdp_bw_modifier_e bw_modifier_type)
+{
+ if (bw_modifier_type == SDP_BW_MODIFIER_UNSUPPORTED) {
+ return (SDP_UNSUPPORTED);
+ } else if (bw_modifier_type < SDP_BW_MODIFIER_AS ||
+ bw_modifier_type >= SDP_MAX_BW_MODIFIER_VAL) {
+ return ("Invalid bw modifier type");
+ } else {
+ return (sdp_bw_modifier_val[bw_modifier_type].name);
+ }
+}
+
+const char *sdp_get_group_attr_name (sdp_group_attr_e group_attr_type)
+{
+ if (group_attr_type == SDP_GROUP_ATTR_UNSUPPORTED) {
+ return (SDP_UNSUPPORTED);
+ } else if (group_attr_type >= SDP_MAX_GROUP_ATTR_VAL) {
+ return ("Invalid a=group: attribute type");
+ } else {
+ return (sdp_group_attr_val[group_attr_type].name);
+ }
+}
+
+const char *sdp_get_src_filter_mode_name (sdp_src_filter_mode_e type)
+{
+ if (type >= SDP_MAX_FILTER_MODE) {
+ return ("Invalid source filter mode");
+ } else {
+ return (sdp_src_filter_mode_val[type].name);
+ }
+}
+
+const char *sdp_get_rtcp_unicast_mode_name (sdp_rtcp_unicast_mode_e type)
+{
+ if (type >= SDP_RTCP_MAX_UNICAST_MODE) {
+ return ("Invalid rtcp unicast mode");
+ } else {
+ return (sdp_rtcp_unicast_mode_val[type].name);
+ }
+}
+
+/* Function: sdp_verify_sdp_ptr
+ * Description: Verify the SDP pointer is valid by checking for
+ * the SDP magic number. If not valid, display an error.
+ * Note that we can't keep a statistic of this because we
+ * track stats inside the config structure which is stored
+ * in the SDP structure.
+ * Parameters: sdp_p The SDP structure handle.
+ * Returns: TRUE or FALSE.
+ */
+inline tinybool sdp_verify_sdp_ptr (sdp_t *sdp_p)
+{
+ if ((sdp_p != NULL) && (sdp_p->magic_num == SDP_MAGIC_NUM)) {
+ return (TRUE);
+ } else {
+ CSFLogError(logTag, "SDP: Invalid SDP pointer.");
+ return (FALSE);
+ }
+}
+
+/* Function: sdp_init_description
+ * Description: Allocates a new SDP structure that can be used for either
+ * parsing or building an SDP description. This routine
+ * saves the config pointer passed in the SDP structure so
+ * SDP will know how to parse/build based on the options defined.
+ * An SDP structure must be allocated before parsing or building
+ * since the handle must be passed to these routines.
+ * Parameters: config_p The config handle returned by sdp_init_config
+ * Returns: A handle for a new SDP structure as a void ptr.
+*/
+sdp_t *sdp_init_description (const char *peerconnection, void *config_p)
+{
+ int i;
+ sdp_t *sdp_p;
+ sdp_conf_options_t *conf_p = (sdp_conf_options_t *)config_p;
+
+ if (sdp_verify_conf_ptr(conf_p) == FALSE) {
+ return (NULL);
+ }
+
+ sdp_p = (sdp_t *)SDP_MALLOC(sizeof(sdp_t));
+ if (sdp_p == NULL) {
+ return (NULL);
+ }
+
+ sstrncpy(sdp_p->peerconnection, peerconnection, sizeof(sdp_p->peerconnection));
+
+ /* Initialize magic number. */
+ sdp_p->magic_num = SDP_MAGIC_NUM;
+
+ sdp_p->conf_p = conf_p;
+ sdp_p->version = SDP_CURRENT_VERSION;
+ sdp_p->owner_name[0] = '\0';
+ sdp_p->owner_sessid[0] = '\0';
+ sdp_p->owner_version[0] = '\0';
+ sdp_p->owner_network_type = SDP_NT_INVALID;
+ sdp_p->owner_addr_type = SDP_AT_INVALID;
+ sdp_p->owner_addr[0] = '\0';
+ sdp_p->sessname[0] = '\0';
+ sdp_p->sessinfo_found = FALSE;
+ sdp_p->uri_found = FALSE;
+
+ sdp_p->default_conn.nettype = SDP_NT_INVALID;
+ sdp_p->default_conn.addrtype = SDP_AT_INVALID;
+ sdp_p->default_conn.conn_addr[0] = '\0';
+ sdp_p->default_conn.is_multicast = FALSE;
+ sdp_p->default_conn.ttl = 0;
+ sdp_p->default_conn.num_of_addresses = 0;
+
+ sdp_p->bw.bw_data_count = 0;
+ sdp_p->bw.bw_data_list = NULL;
+
+ sdp_p->timespec_p = NULL;
+ sdp_p->sess_attrs_p = NULL;
+ sdp_p->mca_p = NULL;
+ sdp_p->mca_count = 0;
+
+ /* Set default debug flags from application config. */
+ for (i=0; i < SDP_MAX_DEBUG_TYPES; i++) {
+ sdp_p->debug_flag[i] = conf_p->debug_flag[i];
+ }
+
+ return (sdp_p);
+}
+
+
+/* Function: void sdp_debug(sdp_t *sdp_p, sdp_debug_e debug_type,
+ * tinybool my_bool);
+ * Description: Define the type of debug for this particular SDP structure.
+ * By default, each SDP description has the settings that are
+ * set for the application.
+ * Valid debug types are ERRORS, WARNINGS, and TRACE. Each
+ * debug type can be turned on/off individually. The
+ * debug level can be redefined at any time.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * debug_type Specifies the debug type being enabled/disabled.
+ * my_bool Defines whether the debug should be enabled or not.
+ * Returns: Nothing.
+ */
+void sdp_debug (sdp_t *sdp_p, sdp_debug_e debug_type, tinybool debug_flag)
+{
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return;
+ }
+
+ if (debug_type < SDP_MAX_DEBUG_TYPES) {
+ sdp_p->debug_flag[debug_type] = debug_flag;
+ }
+}
+
+
+/* Function: void sdp_set_string_debug(sdp_t *sdp_p, char *debug_str)
+ * Description: Define a string to be associated with all debug output
+ * for this SDP. The string will be copied into the SDP
+ * structure and so the library will not be dependent on
+ * the application's memory for this string.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * debug_str Pointer to a string that should be printed out
+ * with every debug msg.
+ * Returns: Nothing.
+ */
+void sdp_set_string_debug (sdp_t *sdp_p, const char *debug_str)
+{
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return;
+ }
+
+ sstrncpy(sdp_p->debug_str, debug_str, sizeof(sdp_p->debug_str));
+}
+
+
+/* Function: sdp_validate_sdp
+ * Description: Validate an SDP structure.
+ * Parameters: sdp_p The SDP handle of the struct to validate.
+ * Returns: A result value indicating if the validation was successful.
+ * If not, what type of error was encountered.
+ */
+sdp_result_e sdp_validate_sdp (sdp_t *sdp_p)
+{
+ int i;
+ u16 num_media_levels;
+
+ /* Need to validate c= info is specified at session level or
+ * at all m= levels.
+ */
+ if (sdp_connection_valid((void *)sdp_p, SDP_SESSION_LEVEL) == FALSE) {
+ num_media_levels = sdp_get_num_media_lines((void *)sdp_p);
+ for (i=1; i <= num_media_levels; i++) {
+ if (sdp_connection_valid((void *)sdp_p, (unsigned short)i) == FALSE) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s c= connection line not specified for "
+ "every media level, validation failed.",
+ sdp_p->debug_str);
+ return (SDP_FAILURE);
+ }
+ }
+ }
+
+ /* Validate required lines were specified */
+ if ((sdp_owner_valid((void *)sdp_p) == FALSE) &&
+ (sdp_p->conf_p->owner_reqd == TRUE)) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s o= owner line not specified, validation failed.",
+ sdp_p->debug_str);
+ return (SDP_FAILURE);
+ }
+
+ if ((sdp_session_name_valid((void *)sdp_p) == FALSE) &&
+ (sdp_p->conf_p->session_name_reqd == TRUE)) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s s= session name line not specified, validation failed.",
+ sdp_p->debug_str);
+ return (SDP_FAILURE);
+ }
+
+ if ((sdp_timespec_valid((void *)sdp_p) == FALSE) &&
+ (sdp_p->conf_p->timespec_reqd == TRUE)) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s t= timespec line not specified, validation failed.",
+ sdp_p->debug_str);
+ return (SDP_FAILURE);
+ }
+
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_parse
+ * Description: Parse an SDP description in the specified buffer.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description
+ * bufp Pointer to the buffer containing the SDP
+ * description to parse.
+ * len The length of the buffer.
+ * Returns: A result value indicating if the parse was successful and
+ * if not, what type of error was encountered. The
+ * information from the parse is stored in the sdp_p structure.
+ */
+sdp_result_e sdp_parse (sdp_t *sdp_p, char **bufp, u16 len)
+{
+ u8 i;
+ u16 cur_level = SDP_SESSION_LEVEL;
+ char *ptr;
+ char *next_ptr = NULL;
+ char *line_end;
+ sdp_token_e last_token = SDP_TOKEN_V;
+ sdp_result_e result=SDP_SUCCESS;
+ tinybool parse_done = FALSE;
+ tinybool end_found = FALSE;
+ tinybool first_line = TRUE;
+ tinybool unrec_token = FALSE;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ if ((bufp == NULL) || (*bufp == NULL)) {
+ return (SDP_NULL_BUF_PTR);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Trace SDP Parse:", sdp_p->debug_str);
+ }
+
+ next_ptr = *bufp;
+ sdp_p->conf_p->num_parses++;
+
+ /* Initialize the last valid capability instance to zero. Used
+ * to help in parsing X-cpar attrs. */
+ sdp_p->cap_valid = FALSE;
+ sdp_p->last_cap_inst = 0;
+
+ /* We want to try to find the end of the SDP description, even if
+ * we find a parsing error.
+ */
+ while (!end_found) {
+ /* If the last char of this line goes beyond the end of the buffer,
+ * we don't parse it.
+ */
+ ptr = next_ptr;
+ line_end = sdp_findchar(ptr, "\n");
+ if (line_end >= (*bufp + len)) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s End of line beyond end of buffer.",
+ sdp_p->debug_str);
+ end_found = TRUE;
+ break;
+ }
+
+ /* Print the line if we're tracing. */
+ if ((parse_done == FALSE) &&
+ (sdp_p->debug_flag[SDP_DEBUG_TRACE])) {
+ SDP_PRINT("%s ", sdp_p->debug_str);
+
+ SDP_PRINT("%*s", line_end - ptr, ptr);
+
+ }
+
+ /* Find out which token this line has, if any. */
+ for (i=0; i < SDP_MAX_TOKENS; i++) {
+ if (strncmp(ptr, sdp_token[i].name, SDP_TOKEN_LEN) == 0) {
+ break;
+ }
+ }
+ if (i == SDP_MAX_TOKENS) {
+ /* See if the second char on the next line is an '=' char.
+ * If so, we note this as an unrecognized token line. */
+ if (ptr[1] == '=') {
+ unrec_token = TRUE;
+ }
+ if (first_line == TRUE) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Attempt to parse text not recognized as "
+ "SDP text, parse fails.", sdp_p->debug_str);
+ /* If we haven't already printed out the line we
+ * were trying to parse, do it now.
+ */
+ if (!sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s ", sdp_p->debug_str);
+ SDP_PRINT("%*s", line_end - ptr, ptr);
+ }
+ sdp_p->conf_p->num_not_sdp_desc++;
+ return (SDP_NOT_SDP_DESCRIPTION);
+ } else {
+ end_found = TRUE;
+ break;
+ }
+ }
+
+ /* This is the beginning of a new SDP description. */
+ if ((first_line != TRUE) && (i == SDP_TOKEN_V)) {
+ end_found = TRUE;
+ break;
+ }
+
+ /* Advance the next ptr to one char beyond the end of the line. */
+ next_ptr = line_end + 1;
+ if (next_ptr >= (*bufp + len)) {
+ end_found = TRUE;
+ }
+
+ /* If we've finished parsing and are just looking for the end of
+ * the SDP description, we don't need to do anything else here.
+ */
+ if (parse_done == TRUE) {
+ continue;
+ }
+
+ /* Only certain tokens are valid at the media level. */
+ if (cur_level != SDP_SESSION_LEVEL) {
+ if ((i != SDP_TOKEN_I) && (i != SDP_TOKEN_C) &&
+ (i != SDP_TOKEN_B) && (i != SDP_TOKEN_K) &&
+ (i != SDP_TOKEN_A) && (i != SDP_TOKEN_M)) {
+ sdp_p->conf_p->num_invalid_token_order++;
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: Invalid token %s found at media level",
+ sdp_p->debug_str, sdp_token[i].name);
+ continue;
+ }
+ }
+
+ /* Verify the token ordering. */
+ if (first_line == TRUE) {
+ if (i != SDP_TOKEN_V) {
+ if (sdp_p->conf_p->version_reqd == TRUE) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s First line not v=, parse fails",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_token_order++;
+ result = SDP_INVALID_TOKEN_ORDERING;
+ parse_done = TRUE;
+ } else {
+ last_token = (sdp_token_e)i;
+ }
+ } else {
+ last_token = (sdp_token_e)i;
+ }
+ first_line = FALSE;
+ } else {
+ if (i < last_token) {
+ sdp_p->conf_p->num_invalid_token_order++;
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: Invalid token ordering detected, "
+ "token %s found after token %s", sdp_p->debug_str,
+ sdp_token[i].name, sdp_token[last_token].name);
+ }
+ }
+
+ /* Finally parse the line. */
+ ptr += SDP_TOKEN_LEN;
+ result = sdp_token[i].parse_func(sdp_p, cur_level, (const char *)ptr);
+ last_token = (sdp_token_e)i;
+ if (last_token == SDP_TOKEN_M) {
+ if (cur_level == SDP_SESSION_LEVEL) {
+ cur_level = 1;
+ } else {
+ cur_level++;
+ }
+ /* The token ordering can start again at i= */
+ last_token = (sdp_token_e)(SDP_TOKEN_I - 1);
+ }
+ if (result != SDP_SUCCESS) {
+ parse_done = TRUE;
+ }
+
+ /* Skip the new line char at the end of this line and see if
+ * this is the end of the buffer.
+ */
+ if ((line_end + 1) == (*bufp + len)) {
+ end_found = TRUE;
+ }
+ }
+
+ /* If we found no valid lines, return an error. */
+ if (first_line == TRUE) {
+ sdp_p->conf_p->num_not_sdp_desc++;
+ return (SDP_NOT_SDP_DESCRIPTION);
+ }
+
+ /* If no errors were found yet, validate the overall sdp. */
+ if (result == SDP_SUCCESS) {
+ result = sdp_validate_sdp(sdp_p);
+ }
+ /* Return the pointer where we left off. */
+ *bufp = next_ptr;
+ /* If the SDP is valid, but the next line following was an
+ * unrecognized = line, indicate this on the return. */
+ if ((result == SDP_SUCCESS) && (unrec_token == TRUE)) {
+ return (SDP_UNRECOGNIZED_TOKEN);
+ } else {
+ return (result);
+ }
+}
+
+
+/* Function: sdp_build
+ * Description: Build an SDP description in the specified buffer based
+ * on the information in the given SDP structure.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description
+ * fs A flex_string where the SDP description should be built.
+ * Returns: A result value indicating if the build was successful and
+ * if not, what type of error was encountered - e.g.,
+ * description was too long for the given buffer.
+ */
+sdp_result_e sdp_build (sdp_t *sdp_p, flex_string *fs)
+{
+ int i, j;
+ sdp_result_e result = SDP_SUCCESS;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ if (!fs) {
+ return (SDP_NULL_BUF_PTR);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Trace SDP Build:", sdp_p->debug_str);
+ }
+
+ sdp_p->conf_p->num_builds++;
+
+ for (i=0; ((i < SDP_TOKEN_M) &&
+ (result == SDP_SUCCESS)); i++) {
+ result = sdp_token[i].build_func(sdp_p, SDP_SESSION_LEVEL, fs);
+ /* ok not to check buffer space (yet) as the if() checks it */
+ }
+ /* If the session level was ok, build the media lines. */
+ if (result == SDP_SUCCESS) {
+ for (i=1; ((i <= sdp_p->mca_count) &&
+ (result == SDP_SUCCESS)); i++) {
+ result = sdp_token[SDP_TOKEN_M].build_func(sdp_p, (u16)i, fs);
+
+ /* ok not to check buffer space (yet) as the for() checks it */
+ for (j=SDP_TOKEN_I;
+ ((j < SDP_TOKEN_M) && (result == SDP_SUCCESS));
+ j++) {
+ if ((j == SDP_TOKEN_U) || (j == SDP_TOKEN_E) ||
+ (j == SDP_TOKEN_P) || (j == SDP_TOKEN_T) ||
+ (j == SDP_TOKEN_R) || (j == SDP_TOKEN_Z)) {
+ /* These tokens not valid at media level. */
+ continue;
+ }
+ result = sdp_token[j].build_func(sdp_p, (u16)i, fs);
+ /* ok not to check buffer space (yet) as the for() checks it */
+ }
+ }
+ }
+
+ return (result);
+}
+
+/* Function: sdp_copy
+ * Description: Create a new SDP structure that is an exact copy of the
+ * one passed in.
+ * Parameters: orig_sdp_p The SDP handle of the SDP to be copied.
+ * Returns: A handle for a new SDP structure as a void ptr.
+*/
+sdp_t *sdp_copy (sdp_t *orig_sdp_p)
+{
+ int i, j;
+ u16 cur_level;
+ sdp_result_e rc;
+ sdp_t *new_sdp_p;
+ sdp_timespec_t *cur_time_p = NULL;
+ sdp_timespec_t *orig_time_p = NULL;
+ sdp_mca_t *orig_mca_p = NULL;
+ sdp_mca_t *new_mca_p = NULL;
+ sdp_mca_t *dst_mca_p = NULL;
+ sdp_media_profiles_t *src_media_profile_p;
+ sdp_media_profiles_t *dst_media_profile_p;
+
+ if (orig_sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Copy SDP:", orig_sdp_p->debug_str);
+ }
+
+ if (sdp_verify_sdp_ptr(orig_sdp_p) == FALSE) {
+ return (NULL);
+ }
+
+ new_sdp_p = (sdp_t *)SDP_MALLOC(sizeof(sdp_t));
+ if (new_sdp_p == NULL) {
+ return (NULL);
+ }
+
+ sstrncpy(new_sdp_p->peerconnection, orig_sdp_p->peerconnection,
+ sizeof(new_sdp_p->peerconnection));
+
+ /* Initialize magic number. */
+ new_sdp_p->magic_num = orig_sdp_p->magic_num;
+
+ new_sdp_p->conf_p = orig_sdp_p->conf_p;
+ new_sdp_p->version = orig_sdp_p->version;
+ sstrncpy(new_sdp_p->owner_name, orig_sdp_p->owner_name,
+ SDP_MAX_LINE_LEN+1);
+ sstrncpy(new_sdp_p->owner_sessid, orig_sdp_p->owner_sessid,
+ SDP_MAX_LINE_LEN+1);
+ sstrncpy(new_sdp_p->owner_version, orig_sdp_p->owner_version,
+ SDP_MAX_LINE_LEN+1);
+ new_sdp_p->owner_network_type = orig_sdp_p->owner_network_type;
+ new_sdp_p->owner_addr_type = orig_sdp_p->owner_addr_type;
+ sstrncpy(new_sdp_p->owner_addr, orig_sdp_p->owner_addr,
+ SDP_MAX_LINE_LEN+1);
+ sstrncpy(new_sdp_p->sessname, orig_sdp_p->sessname,
+ SDP_MAX_LINE_LEN+1);
+ new_sdp_p->sessinfo_found = orig_sdp_p->sessinfo_found;
+ new_sdp_p->uri_found = orig_sdp_p->uri_found;
+
+ new_sdp_p->default_conn.nettype = orig_sdp_p->default_conn.nettype;
+ new_sdp_p->default_conn.addrtype = orig_sdp_p->default_conn.addrtype;
+ sstrncpy(new_sdp_p->default_conn.conn_addr,
+ orig_sdp_p->default_conn.conn_addr,
+ SDP_MAX_LINE_LEN+1);
+
+ new_sdp_p->default_conn.is_multicast =
+ orig_sdp_p->default_conn.is_multicast;
+ new_sdp_p->default_conn.ttl = orig_sdp_p->default_conn.ttl;
+ new_sdp_p->default_conn.num_of_addresses
+ = orig_sdp_p->default_conn.num_of_addresses;
+ new_sdp_p->encrypt.encrypt_type = orig_sdp_p->encrypt.encrypt_type;
+ sstrncpy(new_sdp_p->encrypt.encrypt_key,
+ orig_sdp_p->encrypt.encrypt_key, SDP_MAX_LINE_LEN+1);
+
+ /* Copy all session level bw lines. */
+ rc = sdp_copy_all_bw_lines(orig_sdp_p, new_sdp_p,
+ SDP_SESSION_LEVEL, SDP_SESSION_LEVEL);
+ if (rc != SDP_SUCCESS) {
+ sdp_free_description(new_sdp_p);
+ return (NULL);
+ }
+
+ /* Copy timespec structures. */
+ orig_time_p = orig_sdp_p->timespec_p;
+ while (orig_time_p != NULL) {
+ if (cur_time_p == NULL) {
+ new_sdp_p->timespec_p = \
+ (sdp_timespec_t *)SDP_MALLOC(sizeof(sdp_timespec_t));
+ cur_time_p = new_sdp_p->timespec_p;
+ } else {
+ cur_time_p->next_p = \
+ (sdp_timespec_t *)SDP_MALLOC(sizeof(sdp_timespec_t));
+ cur_time_p = cur_time_p->next_p;
+ }
+ if (cur_time_p == NULL) {
+ sdp_free_description(new_sdp_p);
+ return (NULL);
+ }
+ sstrncpy(cur_time_p->start_time, orig_time_p->start_time,
+ SDP_MAX_LINE_LEN+1);
+ sstrncpy(cur_time_p->stop_time, orig_time_p->stop_time,
+ SDP_MAX_LINE_LEN+1);
+ cur_time_p->next_p = NULL;
+
+ /* Move to next time structure. */
+ orig_time_p = orig_time_p->next_p;
+ }
+
+ /* Copy all session attributes. */
+ rc = sdp_copy_all_attrs(orig_sdp_p, new_sdp_p,
+ SDP_SESSION_LEVEL, SDP_SESSION_LEVEL);
+ if (rc != SDP_SUCCESS) {
+ sdp_free_description(new_sdp_p);
+ return (NULL);
+ }
+
+
+ /* Now copy each media level with its parameters and all
+ * corresponding attrs. */
+ orig_mca_p = orig_sdp_p->mca_p;
+ new_mca_p = NULL;
+ cur_level = 0;
+ while (orig_mca_p != NULL) {
+ cur_level++;
+
+ /* Allocate and link in a new media level. */
+ new_mca_p = sdp_alloc_mca();
+ if (new_mca_p == NULL) {
+ sdp_free_description(new_sdp_p);
+ return (NULL);
+ }
+ if (dst_mca_p == NULL) {
+ new_sdp_p->mca_p = new_mca_p;
+ } else {
+ dst_mca_p->next_p = new_mca_p;
+ }
+ dst_mca_p = new_mca_p;
+ new_sdp_p->mca_count++;
+
+ /* Copy all the media level parameters. */
+ dst_mca_p->media = orig_mca_p->media;
+ dst_mca_p->conn.nettype = orig_mca_p->conn.nettype;
+ dst_mca_p->conn.addrtype = orig_mca_p->conn.addrtype;
+ sstrncpy(dst_mca_p->conn.conn_addr, orig_mca_p->conn.conn_addr,
+ SDP_MAX_LINE_LEN+1);
+
+ dst_mca_p->conn.is_multicast = orig_mca_p->conn.is_multicast;
+ dst_mca_p->conn.ttl = orig_mca_p->conn.ttl;
+ dst_mca_p->conn.num_of_addresses = orig_mca_p->conn.num_of_addresses;
+
+ dst_mca_p->transport = orig_mca_p->transport;
+ dst_mca_p->port_format = orig_mca_p->port_format;
+ dst_mca_p->port = orig_mca_p->port;
+ dst_mca_p->num_ports = orig_mca_p->num_ports;
+ dst_mca_p->vpi = orig_mca_p->vpi;
+ dst_mca_p->vci = orig_mca_p->vci;
+ dst_mca_p->vcci = orig_mca_p->vcci;
+ dst_mca_p->cid = orig_mca_p->cid;
+ dst_mca_p->num_payloads = orig_mca_p->num_payloads;
+
+ for (i=0; i < SDP_MAX_PAYLOAD_TYPES; i++) {
+ dst_mca_p->payload_indicator[i] = orig_mca_p->payload_indicator[i];
+ dst_mca_p->payload_type[i] = orig_mca_p->payload_type[i];
+ }
+
+ dst_mca_p->sessinfo_found = orig_mca_p->sessinfo_found;
+ dst_mca_p->encrypt.encrypt_type = orig_mca_p->encrypt.encrypt_type;
+ sstrncpy(dst_mca_p->encrypt.encrypt_key,
+ orig_mca_p->encrypt.encrypt_key, SDP_MAX_LINE_LEN+1);
+ dst_mca_p->media_direction = orig_mca_p->media_direction;
+
+ /* Now copy all the media level bw lines over. */
+ rc = sdp_copy_all_bw_lines(orig_sdp_p, new_sdp_p, cur_level, cur_level);
+ if (rc != SDP_SUCCESS) {
+ sdp_free_description(new_sdp_p);
+ return (NULL);
+ }
+
+ dst_mca_p->mid = orig_mca_p->mid;
+
+ if (orig_mca_p->media_profiles_p != NULL) {
+ src_media_profile_p = orig_mca_p->media_profiles_p;
+ dst_mca_p->media_profiles_p = (sdp_media_profiles_t *)
+ SDP_MALLOC(sizeof(sdp_media_profiles_t));
+ dst_media_profile_p = dst_mca_p->media_profiles_p;
+ if (dst_media_profile_p == NULL) {
+ sdp_free_description(new_sdp_p);
+ return (NULL);
+ }
+
+ dst_media_profile_p->num_profiles =
+ src_media_profile_p->num_profiles;
+ for (i=0; i < SDP_MAX_PROFILES; i++) {
+ dst_media_profile_p->profile[i] =
+ src_media_profile_p->profile[i];
+ dst_media_profile_p->num_payloads[i] =
+ src_media_profile_p->num_payloads[i];
+ for (j=0; j < SDP_MAX_PAYLOAD_TYPES; j++) {
+ dst_media_profile_p->payload_indicator[i][j] =
+ src_media_profile_p->payload_indicator[i][j];
+ dst_media_profile_p->payload_type[i][j] =
+ src_media_profile_p->payload_type[i][j];
+
+ }
+ }
+ }
+
+ /* Now copy all the media level attrs over. */
+ (void)sdp_copy_all_attrs(orig_sdp_p, new_sdp_p, cur_level, cur_level);
+
+ /* Now move to the next media level. */
+ orig_mca_p = orig_mca_p->next_p;
+ }
+
+
+ /* Set default debug flags from application config. */
+ for (i=0; i < SDP_MAX_DEBUG_TYPES; i++) {
+ new_sdp_p->debug_flag[i] = orig_sdp_p->debug_flag[i];
+ }
+
+ return (new_sdp_p);
+}
+
+/* Function: sdp_free_description
+ * Description: Free an SDP description and all memory associated with it.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description
+ * Returns: A result value indicating if the free was successful and
+ * if not, what type of error was encountered - e.g., sdp_p
+ * was invalid and didn't point to an SDP structure.
+*/
+sdp_result_e sdp_free_description (sdp_t *sdp_p)
+{
+ sdp_timespec_t *time_p, *next_time_p;
+ sdp_attr_t *attr_p, *next_attr_p;
+ sdp_mca_t *mca_p, *next_mca_p;
+ sdp_bw_t *bw_p;
+ sdp_bw_data_t *bw_data_p;
+
+ if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ /* Free any timespec structures - should be only one since
+ * this is all we currently support.
+ */
+ time_p = sdp_p->timespec_p;
+ while (time_p != NULL) {
+ next_time_p = time_p->next_p;
+ SDP_FREE(time_p);
+ time_p = next_time_p;
+ }
+
+ bw_p = &(sdp_p->bw);
+ bw_data_p = bw_p->bw_data_list;
+ while (bw_data_p != NULL) {
+ bw_p->bw_data_list = bw_data_p->next_p;
+ SDP_FREE(bw_data_p);
+ bw_data_p = bw_p->bw_data_list;
+ }
+
+ /* Free any session attr structures */
+ attr_p = sdp_p->sess_attrs_p;
+ while (attr_p != NULL) {
+ next_attr_p = attr_p->next_p;
+ sdp_free_attr(attr_p);
+ attr_p = next_attr_p;
+ }
+
+ /* Free any mca structures */
+ mca_p = sdp_p->mca_p;
+ while (mca_p != NULL) {
+ next_mca_p = mca_p->next_p;
+
+ /* Free any media attr structures */
+ attr_p = mca_p->media_attrs_p;
+ while (attr_p != NULL) {
+ next_attr_p = attr_p->next_p;
+ sdp_free_attr(attr_p);
+ attr_p = next_attr_p;
+ }
+
+ /* Free the media profiles struct if allocated. */
+ if (mca_p->media_profiles_p != NULL) {
+ SDP_FREE(mca_p->media_profiles_p);
+ }
+
+ bw_p = &(mca_p->bw);
+ bw_data_p = bw_p->bw_data_list;
+ while (bw_data_p != NULL) {
+ bw_p->bw_data_list = bw_data_p->next_p;
+ SDP_FREE(bw_data_p);
+ bw_data_p = bw_p->bw_data_list;
+ }
+
+ SDP_FREE(mca_p);
+ mca_p = next_mca_p;
+ }
+
+ SDP_FREE(sdp_p);
+
+ return (SDP_SUCCESS);
+}
+
+/*
+ * sdp_parse_error
+ * Send SDP parsing errors to log and up to peerconnection
+ */
+void sdp_parse_error(const char *peerconnection, const char *format, ...) {
+ va_list ap;
+
+ /* TODO - report error up to PeerConnection here */
+
+ va_start(ap, format);
+ CSFLogErrorV("SDP Parse", format, ap);
+ va_end(ap);
+}
diff --git a/libs/sipcc/core/sdp/sdp_os_defs.h b/libs/sipcc/core/sdp/sdp_os_defs.h
new file mode 100644
index 0000000000..2f04b6f6e4
--- /dev/null
+++ b/libs/sipcc/core/sdp/sdp_os_defs.h
@@ -0,0 +1,33 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _SDP_OS_DEFS_H_
+#define _SDP_OS_DEFS_H_
+
+
+#include "cpr_types.h"
+#include "cpr_stdio.h"
+#include "cpr_stdlib.h"
+#include "cpr_string.h"
+#include "phone_debug.h"
+
+
+#define SDP_PRINT buginf
+#define SDP_MALLOC(x) cpr_calloc(1, (x))
+#define SDP_FREE cpr_free
+
+typedef uint8_t tinybool;
+typedef uint8_t u8;
+typedef uint16_t u16;
+typedef uint16_t uint16;
+typedef uint32_t u32;
+typedef uint32_t uint32;
+typedef int32_t int32;
+typedef int16_t int16;
+typedef unsigned short ushort;
+typedef unsigned long ulong;
+#define inline
+
+
+#endif /* _SDP_OS_DEFS_H_ */
diff --git a/libs/sipcc/core/sdp/sdp_private.h b/libs/sipcc/core/sdp/sdp_private.h
new file mode 100644
index 0000000000..90634d4b8b
--- /dev/null
+++ b/libs/sipcc/core/sdp/sdp_private.h
@@ -0,0 +1,311 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _SDP_PRIVATE_H_
+#define _SDP_PRIVATE_H_
+
+
+#include "sdp.h"
+
+extern const sdp_attrarray_t sdp_attr[];
+extern const sdp_namearray_t sdp_media[];
+extern const sdp_namearray_t sdp_nettype[];
+extern const sdp_namearray_t sdp_addrtype[];
+extern const sdp_namearray_t sdp_transport[];
+extern const sdp_namearray_t sdp_encrypt[];
+extern const sdp_namearray_t sdp_payload[];
+extern const sdp_namearray_t sdp_t38_rate[];
+extern const sdp_namearray_t sdp_t38_udpec[];
+extern const sdp_namearray_t sdp_qos_strength[];
+extern const sdp_namearray_t sdp_qos_direction[];
+extern const sdp_namearray_t sdp_qos_status_type[];
+extern const sdp_namearray_t sdp_curr_type[];
+extern const sdp_namearray_t sdp_des_type[];
+extern const sdp_namearray_t sdp_conf_type[];
+extern const sdp_namearray_t sdp_mediadir_role[];
+extern const sdp_namearray_t sdp_fmtp_codec_param[];
+extern const sdp_namearray_t sdp_fmtp_codec_param_val[];
+extern const sdp_namearray_t sdp_silencesupp_pref[];
+extern const sdp_namearray_t sdp_silencesupp_siduse[];
+extern const sdp_namearray_t sdp_srtp_context_crypto_suite[];
+extern const sdp_namearray_t sdp_bw_modifier_val[];
+extern const sdp_namearray_t sdp_group_attr_val[];
+extern const sdp_namearray_t sdp_src_filter_mode_val[];
+extern const sdp_namearray_t sdp_rtcp_unicast_mode_val[];
+
+extern const sdp_srtp_crypto_suite_list sdp_srtp_crypto_suite_array[];
+/* Function Prototypes */
+
+/* sdp_access.c */
+extern sdp_mca_t *sdp_find_media_level(sdp_t *sdp_p, u16 level);
+extern sdp_bw_data_t* sdp_find_bw_line (void *sdp_ptr, u16 level, u16 inst_num);
+
+/* sdp_attr.c */
+extern sdp_result_e sdp_parse_attribute(sdp_t *sdp_p, u16 level,
+ const char *ptr);
+extern sdp_result_e sdp_parse_attr_simple_string(sdp_t *sdp_p,
+ sdp_attr_t *attr_p, const char *ptr);
+extern sdp_result_e sdp_build_attr_simple_string(sdp_t *sdp_p,
+ sdp_attr_t *attr_p, flex_string *fs);
+extern sdp_result_e sdp_parse_attr_simple_u32(sdp_t *sdp_p,
+ sdp_attr_t *attr_p, const char *ptr);
+extern sdp_result_e sdp_build_attr_simple_u32(sdp_t *sdp_p,
+ sdp_attr_t *attr_p, flex_string *fs);
+extern sdp_result_e sdp_parse_attr_simple_bool(sdp_t *sdp_p,
+ sdp_attr_t *attr_p, const char *ptr);
+extern sdp_result_e sdp_build_attr_simple_bool(sdp_t *sdp_p,
+ sdp_attr_t *attr_p, flex_string *fs);
+extern sdp_result_e sdp_parse_attr_maxprate(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr);
+extern sdp_result_e sdp_parse_attr_fmtp(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr);
+extern sdp_result_e sdp_build_attr_fmtp(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs);
+extern sdp_result_e sdp_parse_attr_direction(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr);
+extern sdp_result_e sdp_build_attr_direction(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs);
+extern sdp_result_e sdp_parse_attr_qos(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr);
+extern sdp_result_e sdp_build_attr_qos(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs);
+extern sdp_result_e sdp_parse_attr_curr(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr);
+extern sdp_result_e sdp_build_attr_curr (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs);
+extern sdp_result_e sdp_parse_attr_des(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr);
+extern sdp_result_e sdp_build_attr_des (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs);
+extern sdp_result_e sdp_parse_attr_conf(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr);
+extern sdp_result_e sdp_build_attr_conf (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs);
+extern sdp_result_e sdp_parse_attr_transport_map(sdp_t *sdp_p,
+ sdp_attr_t *attr_p, const char *ptr);
+extern sdp_result_e sdp_build_attr_transport_map(sdp_t *sdp_p,
+ sdp_attr_t *attr_p, flex_string *fs);
+extern sdp_result_e sdp_parse_attr_subnet(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr);
+extern sdp_result_e sdp_build_attr_subnet(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs);
+extern sdp_result_e sdp_parse_attr_t38_ratemgmt(sdp_t *sdp_p,
+ sdp_attr_t *attr_p, const char *ptr);
+extern sdp_result_e sdp_build_attr_t38_ratemgmt(sdp_t *sdp_p,
+ sdp_attr_t *attr_p, flex_string *fs);
+extern sdp_result_e sdp_parse_attr_t38_udpec(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr);
+extern sdp_result_e sdp_build_attr_t38_udpec(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs);
+extern sdp_result_e sdp_parse_attr_cap(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr);
+extern sdp_result_e sdp_build_attr_cap(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs);
+extern sdp_result_e sdp_parse_attr_cpar(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr);
+extern sdp_result_e sdp_build_attr_cpar(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs);
+extern sdp_result_e sdp_parse_attr_pc_codec(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr);
+extern sdp_result_e sdp_build_attr_pc_codec(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs);
+extern sdp_result_e sdp_parse_attr_xcap(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr);
+extern sdp_result_e sdp_build_attr_xcap(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs);
+extern sdp_result_e sdp_parse_attr_xcpar(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr);
+extern sdp_result_e sdp_build_attr_xcpar(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs);
+extern sdp_result_e sdp_parse_attr_rtr(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr);
+extern sdp_result_e sdp_build_attr_rtr(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs);
+extern sdp_result_e sdp_parse_attr_comediadir(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr);
+extern sdp_result_e sdp_build_attr_comediadir(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs);
+extern sdp_result_e sdp_parse_attr_silencesupp(sdp_t *sdp_p,
+ sdp_attr_t *attr_p,
+ const char *ptr);
+extern sdp_result_e sdp_build_attr_silencesupp(sdp_t *sdp_p,
+ sdp_attr_t *attr_p,
+ flex_string *fs);
+extern sdp_result_e sdp_parse_attr_srtpcontext(sdp_t *sdp_p,
+ sdp_attr_t *attr_p,
+ const char *ptr);
+extern sdp_result_e sdp_build_attr_srtpcontext(sdp_t *sdp_p,
+ sdp_attr_t *attr_p,
+ flex_string *fs);
+extern sdp_result_e sdp_parse_attr_mptime(
+ sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr);
+extern sdp_result_e sdp_build_attr_mptime(
+ sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs);
+
+extern sdp_result_e sdp_parse_attr_x_sidin(
+ sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr);
+extern sdp_result_e sdp_build_attr_x_sidin(
+ sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs);
+
+extern sdp_result_e sdp_parse_attr_x_sidout(
+ sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr);
+extern sdp_result_e sdp_build_attr_x_sidout(
+ sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs);
+
+extern sdp_result_e sdp_parse_attr_x_confid(
+ sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr);
+extern sdp_result_e sdp_build_attr_x_confid(
+ sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs);
+
+extern sdp_result_e sdp_parse_attr_group(
+ sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr);
+extern sdp_result_e sdp_build_attr_group(
+ sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs);
+
+extern sdp_result_e sdp_parse_attr_source_filter(
+ sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr);
+extern sdp_result_e sdp_build_source_filter(
+ sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs);
+
+extern sdp_result_e sdp_parse_attr_rtcp_unicast(
+ sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr);
+extern sdp_result_e sdp_build_attr_rtcp_unicast(
+ sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs);
+
+extern sdp_result_e sdp_build_attr_ice_attr (
+ sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs);
+extern sdp_result_e sdp_parse_attr_ice_attr (
+ sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr);
+
+extern sdp_result_e sdp_build_attr_rtcp_mux_attr (
+ sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs);
+extern sdp_result_e sdp_parse_attr_rtcp_mux_attr (
+ sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr);
+extern sdp_result_e sdp_parse_attr_fingerprint_attr (
+ sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr);
+
+/* sdp_attr_access.c */
+extern void sdp_free_attr(sdp_attr_t *attr_p);
+extern sdp_result_e sdp_find_attr_list(sdp_t *sdp_p, u16 level, u8 cap_num,
+ sdp_attr_t **attr_p, char *fname);
+extern sdp_attr_t *sdp_find_attr(sdp_t *sdp_p, u16 level, u8 cap_num,
+ sdp_attr_e attr_type, u16 inst_num);
+extern sdp_attr_t *sdp_find_capability(sdp_t *sdp_p, u16 level, u8 cap_num);
+
+/* sdp_config.c */
+extern tinybool sdp_verify_conf_ptr(sdp_conf_options_t *conf_p);
+
+/* sdp_main.c */
+extern const char *sdp_get_attr_name(sdp_attr_e attr_type);
+extern const char *sdp_get_media_name(sdp_media_e media_type);
+extern const char *sdp_get_network_name(sdp_nettype_e network_type);
+extern const char *sdp_get_address_name(sdp_addrtype_e addr_type);
+extern const char *sdp_get_transport_name(sdp_transport_e transport_type);
+extern const char *sdp_get_encrypt_name(sdp_encrypt_type_e encrypt_type);
+extern const char *sdp_get_payload_name(sdp_payload_e payload);
+extern const char *sdp_get_t38_ratemgmt_name(sdp_t38_ratemgmt_e rate);
+extern const char *sdp_get_t38_udpec_name(sdp_t38_udpec_e udpec);
+extern const char *sdp_get_qos_strength_name(sdp_qos_strength_e strength);
+extern const char *sdp_get_qos_direction_name(sdp_qos_dir_e direction);
+extern const char *sdp_get_qos_status_type_name(sdp_qos_status_types_e status_type);
+extern const char *sdp_get_curr_type_name(sdp_curr_type_e curr_type);
+extern const char *sdp_get_des_type_name(sdp_des_type_e des_type);
+extern const char *sdp_get_conf_type_name(sdp_conf_type_e conf_type);
+extern const char *sdp_get_mediadir_role_name (sdp_mediadir_role_e role);
+extern const char *sdp_get_silencesupp_pref_name(sdp_silencesupp_pref_e pref);
+extern const char *sdp_get_silencesupp_siduse_name(sdp_silencesupp_siduse_e
+ siduse);
+
+extern const char *sdp_get_bw_modifier_name(sdp_bw_modifier_e bw_modifier);
+extern const char *sdp_get_group_attr_name(sdp_group_attr_e group_attr);
+extern const char *sdp_get_src_filter_mode_name(sdp_src_filter_mode_e type);
+extern const char *sdp_get_rtcp_unicast_mode_name(sdp_rtcp_unicast_mode_e type);
+
+extern tinybool sdp_verify_sdp_ptr(sdp_t *sdp_p);
+
+
+/* sdp_tokens.c */
+extern sdp_result_e sdp_parse_version(sdp_t *sdp_p, u16 token,
+ const char *ptr);
+extern sdp_result_e sdp_build_version(sdp_t *sdp_p, u16 token, flex_string *fs);
+extern sdp_result_e sdp_parse_owner(sdp_t *sdp_p, u16 token,
+ const char *ptr);
+extern sdp_result_e sdp_build_owner(sdp_t *sdp_p, u16 token, flex_string *fs);
+extern sdp_result_e sdp_parse_sessname(sdp_t *sdp_p, u16 token,
+ const char *ptr);
+extern sdp_result_e sdp_build_sessname(sdp_t *sdp_p, u16 token, flex_string *fs);
+extern sdp_result_e sdp_parse_sessinfo(sdp_t *sdp_p, u16 token,
+ const char *ptr);
+extern sdp_result_e sdp_build_sessinfo(sdp_t *sdp_p, u16 token, flex_string *fs);
+extern sdp_result_e sdp_parse_uri(sdp_t *sdp_p, u16 token, const char *ptr);
+extern sdp_result_e sdp_build_uri(sdp_t *sdp_p, u16 token, flex_string *fs);
+extern sdp_result_e sdp_parse_email(sdp_t *sdp_p, u16 token, const char *ptr);
+extern sdp_result_e sdp_build_email(sdp_t *sdp_p, u16 token, flex_string *fs);
+extern sdp_result_e sdp_parse_phonenum(sdp_t *sdp_p, u16 token,
+ const char *ptr);
+extern sdp_result_e sdp_build_phonenum(sdp_t *sdp_p, u16 token, flex_string *fs);
+extern sdp_result_e sdp_parse_connection(sdp_t *sdp_p, u16 token,
+ const char *ptr);
+extern sdp_result_e sdp_build_connection(sdp_t *sdp_p, u16 token, flex_string *fs);
+extern sdp_result_e sdp_parse_bandwidth(sdp_t *sdp_p, u16 token,
+ const char *ptr);
+extern sdp_result_e sdp_build_bandwidth(sdp_t *sdp_p, u16 token, flex_string *fs);
+extern sdp_result_e sdp_parse_timespec(sdp_t *sdp_p, u16 token,
+ const char *ptr);
+extern sdp_result_e sdp_build_timespec(sdp_t *sdp_p, u16 token, flex_string *fs);
+extern sdp_result_e sdp_parse_repeat_time(sdp_t *sdp_p, u16 token,
+ const char *ptr);
+extern sdp_result_e sdp_build_repeat_time(sdp_t *sdp_p, u16 token, flex_string *fs);
+extern sdp_result_e sdp_parse_timezone_adj(sdp_t *sdp_p, u16 token,
+ const char *ptr);
+extern sdp_result_e sdp_build_timezone_adj(sdp_t *sdp_p, u16 token, flex_string *fs);
+extern sdp_result_e sdp_parse_encryption(sdp_t *sdp_p, u16 token,
+ const char *ptr);
+extern sdp_result_e sdp_build_encryption(sdp_t *sdp_p, u16 token, flex_string *fs);
+extern sdp_result_e sdp_parse_media(sdp_t *sdp_p, u16 token, const char *ptr);
+extern sdp_result_e sdp_build_media(sdp_t *sdp_p, u16 token, flex_string *fs);
+extern sdp_result_e sdp_parse_attribute(sdp_t *sdp_p, u16 token,
+ const char *ptr);
+extern sdp_result_e sdp_build_attribute(sdp_t *sdp_p, u16 token, flex_string *fs);
+
+extern void sdp_parse_payload_types(sdp_t *sdp_p, sdp_mca_t *mca_p,
+ const char *ptr);
+extern sdp_result_e sdp_parse_multiple_profile_payload_types(sdp_t *sdp_p,
+ sdp_mca_t *mca_p,
+ const char *ptr);
+extern sdp_result_e
+sdp_parse_attr_sdescriptions(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr);
+
+extern sdp_result_e
+sdp_build_attr_sdescriptions(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs);
+
+
+/* sdp_utils.c */
+extern sdp_mca_t *sdp_alloc_mca(void);
+extern tinybool sdp_validate_maxprate(const char *string_parm);
+extern char *sdp_findchar(const char *ptr, char *char_list);
+extern const char *sdp_getnextstrtok(const char *str, char *tokenstr, unsigned tokenstr_len,
+ const char *delim, sdp_result_e *result);
+extern u32 sdp_getnextnumtok(const char *str, const char **str_end,
+ const char *delim, sdp_result_e *result);
+extern u32 sdp_getnextnumtok_or_null(const char *str, const char **str_end,
+ const char *delim, tinybool *null_ind,
+ sdp_result_e *result);
+extern tinybool sdp_getchoosetok(const char *str, const char **str_end,
+ const char *delim, sdp_result_e *result);
+
+extern
+tinybool verify_sdescriptions_mki(char *buf, char *mkiVal, u16 *mkiLen);
+
+extern
+tinybool verify_sdescriptions_lifetime(char *buf);
+
+/* sdp_services_xxx.c */
+extern void sdp_dump_buffer(char *_ptr, int _size_bytes);
+
+tinybool sdp_checkrange(sdp_t *sdp, char *num, ulong* lval);
+
+#endif /* _SDP_PRIVATE_H_ */
diff --git a/libs/sipcc/core/sdp/sdp_services_unix.c b/libs/sipcc/core/sdp/sdp_services_unix.c
new file mode 100755
index 0000000000..79787eb2b5
--- /dev/null
+++ b/libs/sipcc/core/sdp/sdp_services_unix.c
@@ -0,0 +1,63 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "sdp_os_defs.h"
+#include "sdp.h"
+#include "sdp_private.h"
+
+
+/******************************************************************/
+/* Required Platform Routines */
+/* */
+/* These routines are called from the common SDP code. */
+/* They must be provided for each platform. */
+/* */
+/******************************************************************/
+
+#if 0
+void sdp_log_errmsg (sdp_errmsg_e errmsg, char *str)
+{
+ switch (errmsg) {
+
+ case SDP_ERR_INVALID_CONF_PTR:
+ SDP_ERROR("\nSDP: Invalid Config pointer (%s).", str);
+ break;
+
+ case SDP_ERR_INVALID_SDP_PTR:
+ SDP_ERROR("\nSDP: Invalid SDP pointer (%s).", str);
+ break;
+
+ case SDP_ERR_INTERNAL:
+ SDP_ERROR("\nSDP: Internal error (%s).", str);
+ break;
+
+ default:
+ break;
+ }
+}
+#endif
+
+/*
+ * sdp_dump_buffer
+ *
+ * Utility to send _size_bytes of data from the string
+ * pointed to by _ptr to the buginf function. This may make
+ * multiple buginf calls if the buffer is too large for buginf.
+ */
+void sdp_dump_buffer (char * _ptr, int _size_bytes)
+{
+ buginf_msg(_ptr);
+}
+
+/******************************************************************/
+/* */
+/* Platform Specific Routines */
+/* */
+/* These routines are only used in this particular platform. */
+/* They are called from the required platform specific */
+/* routines provided below, not from the common SDP code. */
+/* */
+/******************************************************************/
+
+/* There are currently no platform specific routines required. */
diff --git a/libs/sipcc/core/sdp/sdp_services_win32.c b/libs/sipcc/core/sdp/sdp_services_win32.c
new file mode 100755
index 0000000000..79787eb2b5
--- /dev/null
+++ b/libs/sipcc/core/sdp/sdp_services_win32.c
@@ -0,0 +1,63 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "sdp_os_defs.h"
+#include "sdp.h"
+#include "sdp_private.h"
+
+
+/******************************************************************/
+/* Required Platform Routines */
+/* */
+/* These routines are called from the common SDP code. */
+/* They must be provided for each platform. */
+/* */
+/******************************************************************/
+
+#if 0
+void sdp_log_errmsg (sdp_errmsg_e errmsg, char *str)
+{
+ switch (errmsg) {
+
+ case SDP_ERR_INVALID_CONF_PTR:
+ SDP_ERROR("\nSDP: Invalid Config pointer (%s).", str);
+ break;
+
+ case SDP_ERR_INVALID_SDP_PTR:
+ SDP_ERROR("\nSDP: Invalid SDP pointer (%s).", str);
+ break;
+
+ case SDP_ERR_INTERNAL:
+ SDP_ERROR("\nSDP: Internal error (%s).", str);
+ break;
+
+ default:
+ break;
+ }
+}
+#endif
+
+/*
+ * sdp_dump_buffer
+ *
+ * Utility to send _size_bytes of data from the string
+ * pointed to by _ptr to the buginf function. This may make
+ * multiple buginf calls if the buffer is too large for buginf.
+ */
+void sdp_dump_buffer (char * _ptr, int _size_bytes)
+{
+ buginf_msg(_ptr);
+}
+
+/******************************************************************/
+/* */
+/* Platform Specific Routines */
+/* */
+/* These routines are only used in this particular platform. */
+/* They are called from the required platform specific */
+/* routines provided below, not from the common SDP code. */
+/* */
+/******************************************************************/
+
+/* There are currently no platform specific routines required. */
diff --git a/libs/sipcc/core/sdp/sdp_token.c b/libs/sipcc/core/sdp/sdp_token.c
new file mode 100644
index 0000000000..89e3df66df
--- /dev/null
+++ b/libs/sipcc/core/sdp/sdp_token.c
@@ -0,0 +1,1763 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include
+
+#include "sdp_os_defs.h"
+#include "sdp.h"
+#include "sdp_private.h"
+#include "configmgr.h"
+#include "prot_configmgr.h"
+#include "ccapi.h"
+#include "CSFLog.h"
+
+//static const char *logTag = "sdp_token";
+
+#define MCAST_STRING_LEN 4
+
+
+sdp_result_e sdp_parse_version (sdp_t *sdp_p, u16 level, const char *ptr)
+{
+ sdp_result_e result = SDP_FAILURE;
+
+ sdp_p->version = (u16)sdp_getnextnumtok(ptr, &ptr, " \t", &result);
+ if ((result != SDP_SUCCESS) || (sdp_p->version != SDP_CURRENT_VERSION)) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Invalid version (%lu) found, parse failed.",
+ sdp_p->debug_str, sdp_p->version);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parse version line successful, version %u",
+ sdp_p->debug_str, (u16)sdp_p->version);
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_version (sdp_t *sdp_p, u16 level, flex_string *fs)
+{
+ if (sdp_p->version == SDP_INVALID_VALUE) {
+ if (sdp_p->conf_p->version_reqd == TRUE) {
+ CSFLogError(logTag, "%s Invalid version for v= line, "
+ "build failed.", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ /* v= line is not required. */
+ return (SDP_SUCCESS);
+ }
+ }
+
+ flex_string_sprintf(fs, "v=%u\r\n", (u16)sdp_p->version);
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Built v= version line", sdp_p->debug_str);
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_parse_owner (sdp_t *sdp_p, u16 level, const char *ptr)
+{
+ int i;
+ char *tmpptr;
+ sdp_result_e result;
+ char tmp[SDP_MAX_STRING_LEN];
+
+ if (sdp_p->owner_name[0] != '\0') {
+ sdp_p->conf_p->num_invalid_token_order++;
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: More than one o= line specified.",
+ sdp_p->debug_str);
+ }
+
+ /* Find the owner name. */
+ ptr = sdp_getnextstrtok(ptr, sdp_p->owner_name, sizeof(sdp_p->owner_name), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s No owner name specified for o=.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Find the owner session id. This is a numeric field but is
+ * stored as a string since it may be 64 bit.
+ */
+ ptr = sdp_getnextstrtok(ptr, sdp_p->owner_sessid, sizeof(sdp_p->owner_sessid), " \t", &result);
+ if (result == SDP_SUCCESS) {
+ /* Make sure the sessid is numeric, even though we store it as
+ * a string.
+ */
+ (void)sdp_getnextnumtok(sdp_p->owner_sessid,
+ (const char **)&tmpptr, " \t",&result);
+ }
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Invalid owner session id specified for o=.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Find the owner version. */
+ ptr = sdp_getnextstrtok(ptr, sdp_p->owner_version, sizeof(sdp_p->owner_version), " \t", &result);
+ if (result == SDP_SUCCESS) {
+ /* Make sure the version is numeric, even though we store it as
+ * a string.
+ */
+ (void)sdp_getnextnumtok(sdp_p->owner_version,
+ (const char **)&tmpptr," \t",&result);
+ }
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Invalid owner version specified for o=.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Find the owner network type. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s No owner network type specified for o=.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ sdp_p->owner_network_type = SDP_NT_UNSUPPORTED;
+ for (i=0; i < SDP_MAX_NETWORK_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_nettype[i].name,
+ sdp_nettype[i].strlen) == 0) {
+ if (sdp_p->conf_p->nettype_supported[i] == TRUE) {
+ sdp_p->owner_network_type = (sdp_nettype_e)i;
+ }
+ }
+ }
+ if (sdp_p->owner_network_type == SDP_NT_UNSUPPORTED) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Owner network type unsupported (%s)",
+ sdp_p->debug_str, tmp);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Find the owner address type. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s No owner address type specified for o=.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ sdp_p->owner_addr_type = SDP_AT_UNSUPPORTED;
+ for (i=0; i < SDP_MAX_ADDR_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_addrtype[i].name,
+ sdp_addrtype[i].strlen) == 0) {
+ if (sdp_p->conf_p->addrtype_supported[i] == TRUE) {
+ sdp_p->owner_addr_type = (sdp_addrtype_e)i;
+ }
+ }
+ }
+ if ((sdp_p->owner_addr_type == SDP_AT_UNSUPPORTED) &&
+ (sdp_p->owner_network_type != SDP_NT_ATM)) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Owner address type unsupported (%s)",
+ sdp_p->debug_str, tmp);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Find the owner address. */
+ ptr = sdp_getnextstrtok(ptr, sdp_p->owner_addr, sizeof(sdp_p->owner_addr), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s No owner address specified.", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parse owner: name %s, session id %s, version %s",
+ sdp_p->debug_str, sdp_p->owner_name, sdp_p->owner_sessid,
+ sdp_p->owner_version);
+ SDP_PRINT("%s network %s, address type %s, "
+ "address %s", sdp_p->debug_str,
+ sdp_get_network_name(sdp_p->owner_network_type),
+ sdp_get_address_name(sdp_p->owner_addr_type),
+ sdp_p->owner_addr);
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_owner (sdp_t *sdp_p, u16 level, flex_string *fs)
+{
+ if ((sdp_p->owner_name[0] == '\0') ||
+ (sdp_p->owner_network_type >= SDP_MAX_NETWORK_TYPES) ||
+ (sdp_p->owner_addr_type >= SDP_MAX_ADDR_TYPES) ||
+ (sdp_p->owner_addr[0] == '\0')) {
+
+ if((sdp_p->owner_network_type == SDP_NT_ATM) &&
+ (sdp_p->owner_addr_type == SDP_AT_INVALID)) {
+ flex_string_sprintf(fs, "o=%s %s %s %s - -\r\n",
+ sdp_p->owner_name, sdp_p->owner_sessid,
+ sdp_p->owner_version,
+ sdp_get_network_name(sdp_p->owner_network_type));
+ }
+
+ if (sdp_p->conf_p->owner_reqd == TRUE) {
+ CSFLogError(logTag, "%s Invalid params for o= owner line, "
+ "build failed.", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ /* o= line is not required. */
+ return (SDP_SUCCESS);
+ }
+ }
+
+ flex_string_sprintf(fs, "o=%s %s %s %s %s %s\r\n",
+ sdp_p->owner_name, sdp_p->owner_sessid,
+ sdp_p->owner_version,
+ sdp_get_network_name(sdp_p->owner_network_type),
+ sdp_get_address_name(sdp_p->owner_addr_type),
+ sdp_p->owner_addr);
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Built o= owner line", sdp_p->debug_str);
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_parse_sessname (sdp_t *sdp_p, u16 level, const char *ptr)
+{
+ int str_len;
+ char *endptr;
+
+ if (sdp_p->sessname[0] != '\0') {
+ sdp_p->conf_p->num_invalid_token_order++;
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: More than one s= line specified.",
+ sdp_p->debug_str);
+ }
+
+ endptr = sdp_findchar(ptr, "\r\n");
+ if (ptr == endptr) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No session name specified.",
+ sdp_p->debug_str);
+ }
+ str_len = MIN(endptr - ptr, SDP_MAX_STRING_LEN);
+ sstrncpy(sdp_p->sessname, ptr, str_len+1);
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parse session name, %s",
+ sdp_p->debug_str, sdp_p->sessname);
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_sessname (sdp_t *sdp_p, u16 level, flex_string *fs)
+{
+ if (sdp_p->sessname[0] == '\0') {
+ if (sdp_p->conf_p->session_name_reqd == TRUE) {
+ CSFLogError(logTag, "%s No param defined for s= session name line, "
+ "build failed.", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ /* s= line is not required. */
+ return (SDP_SUCCESS);
+ }
+ }
+
+ flex_string_sprintf(fs, "s=%s\r\n", sdp_p->sessname);
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Built s= session name line", sdp_p->debug_str);
+ }
+ return (SDP_SUCCESS);
+}
+
+/* We don't want to store the session info, but we do want to validate
+ * that at most one i= line exists at each level and if the line exists
+ * there should be a parameter.
+ */
+sdp_result_e sdp_parse_sessinfo (sdp_t *sdp_p, u16 level, const char *ptr)
+{
+ char *endptr;
+ sdp_mca_t *mca_p;
+
+ if (level == SDP_SESSION_LEVEL) {
+ if (sdp_p->sessinfo_found == TRUE) {
+ sdp_p->conf_p->num_invalid_token_order++;
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: More than one i= line specified.",
+ sdp_p->debug_str);
+ }
+ sdp_p->sessinfo_found = TRUE;
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (SDP_FAILURE);
+ }
+ if (mca_p->sessinfo_found == TRUE) {
+ sdp_p->conf_p->num_invalid_token_order++;
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: More than one i= line specified"
+ " for media line %d.", sdp_p->debug_str, level);
+ }
+ mca_p->sessinfo_found = TRUE;
+ }
+
+ endptr = sdp_findchar(ptr, "\n");
+ if (ptr == endptr) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No session info specified.",
+ sdp_p->debug_str);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed session info line.", sdp_p->debug_str);
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_sessinfo (sdp_t *sdp_p, u16 level, flex_string *fs)
+{
+ /* Build session info line not supported. */
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_parse_uri (sdp_t *sdp_p, u16 level, const char *ptr)
+{
+ char *endptr;
+
+ if (sdp_p->uri_found == TRUE) {
+ sdp_p->conf_p->num_invalid_token_order++;
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: More than one u= line specified.",
+ sdp_p->debug_str);
+ }
+ sdp_p->uri_found = TRUE;
+
+ endptr = sdp_findchar(ptr, "\n");
+ if (ptr == endptr) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No URI info specified.", sdp_p->debug_str);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed URI line.", sdp_p->debug_str);
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_uri (sdp_t *sdp_p, u16 level, flex_string *fs)
+{
+ /* Build URI line not supported. */
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_parse_email (sdp_t *sdp_p, u16 level, const char *ptr)
+{
+ char *endptr;
+
+ endptr = sdp_findchar(ptr, "\n");
+ if (ptr == endptr) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No email info specified.", sdp_p->debug_str);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parse email line", sdp_p->debug_str);
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_email (sdp_t *sdp_p, u16 level, flex_string *fs)
+{
+ /* Build email line not supported. */
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_parse_phonenum (sdp_t *sdp_p, u16 level, const char *ptr)
+{
+ char *endptr;
+
+ endptr = sdp_findchar(ptr, "\n");
+ if (ptr == endptr) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No phone number info specified.",
+ sdp_p->debug_str);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parse phone number line", sdp_p->debug_str);
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_phonenum (sdp_t *sdp_p, u16 level, flex_string *fs)
+{
+ /* Build phone number line not supported. */
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_parse_connection (sdp_t *sdp_p, u16 level, const char *ptr)
+{
+ int i;
+ const char *slash_ptr;
+ sdp_result_e result;
+ sdp_conn_t *conn_p;
+ sdp_mca_t *mca_p;
+ char tmp[SDP_MAX_STRING_LEN];
+ char mcast_str[MCAST_STRING_LEN];
+ int mcast_bits;
+ unsigned long strtoul_result;
+ char *strtoul_end;
+
+ if (level == SDP_SESSION_LEVEL) {
+ conn_p = &(sdp_p->default_conn);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (SDP_FAILURE);
+ }
+ conn_p = &(mca_p->conn);
+ }
+
+ /* See if the c= line is already defined at this level. We don't
+ * currently support multihoming and so we only support one c= at
+ * each level.
+ */
+ if (conn_p->nettype != SDP_NT_INVALID) {
+ sdp_p->conf_p->num_invalid_token_order++;
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s c= line specified twice at same level, "
+ "parse failed.", sdp_p->debug_str);
+ return (SDP_INVALID_TOKEN_ORDERING);
+ }
+
+ /* Find the connection network type. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s No connection network type specified for c=.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ conn_p->nettype = SDP_NT_UNSUPPORTED;
+ for (i=0; i < SDP_MAX_NETWORK_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_nettype[i].name,
+ sdp_nettype[i].strlen) == 0) {
+ if (sdp_p->conf_p->nettype_supported[i] == TRUE) {
+ conn_p->nettype = (sdp_nettype_e)i;
+ }
+ }
+ }
+ if (conn_p->nettype == SDP_NT_UNSUPPORTED) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: Connection network type unsupported "
+ "(%s) for c=.", sdp_p->debug_str, tmp);
+ }
+
+ /* Find the connection address type. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ if (conn_p->nettype == SDP_NT_ATM) {
+ /* If the nettype is ATM, addr type and addr are not reqd */
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parse connection: network %s", sdp_p->debug_str,
+ sdp_get_network_name(conn_p->nettype));
+ }
+ return (SDP_SUCCESS);
+ } else {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s No connection address type specified for "
+ "c=.", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ }
+ conn_p->addrtype = SDP_AT_UNSUPPORTED;
+ for (i=0; i < SDP_MAX_ADDR_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_addrtype[i].name,
+ sdp_addrtype[i].strlen) == 0) {
+ if (sdp_p->conf_p->addrtype_supported[i] == TRUE) {
+ conn_p->addrtype = (sdp_addrtype_e)i;
+ }
+ }
+ }
+ if (conn_p->addrtype == SDP_AT_UNSUPPORTED) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: Connection address type unsupported "
+ "(%s) for c=.", sdp_p->debug_str, tmp);
+ }
+
+ /* Find the connection address. */
+ ptr = sdp_getnextstrtok(ptr, conn_p->conn_addr, sizeof(conn_p->conn_addr), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s No connection address specified for c=.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ /* We currently only support addrs containing '/'s for EPN addrs.
+ * For other addrs this would indicate multicast addrs. */
+ /* Multicast host group addresses are defined to be the IP addresses
+ * whose high-order four bits are 1110, giving an address range from
+ * 224.0.0.0 through 239.255.255.255
+ */
+ /* multicast addr check */
+ sstrncpy (mcast_str, conn_p->conn_addr, MCAST_STRING_LEN);
+
+ errno = 0;
+ strtoul_result = strtoul(mcast_str, &strtoul_end, 10);
+
+ if (errno || mcast_str == strtoul_end || strtoul_result > 255) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Error parsing address %s for mcast.",
+ sdp_p->debug_str, mcast_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return SDP_INVALID_PARAMETER;
+ }
+
+
+ mcast_bits = (int) strtoul_result;
+ if ((mcast_bits >= SDP_MIN_MCAST_ADDR_HI_BIT_VAL ) &&
+ (mcast_bits <= SDP_MAX_MCAST_ADDR_HI_BIT_VAL)) {
+ SDP_PRINT("%s Parsed to be a multicast address with mcast bits %d",
+ sdp_p->debug_str, mcast_bits);
+ conn_p->is_multicast = TRUE;
+ }
+
+ if (conn_p->addrtype != SDP_AT_EPN) {
+ slash_ptr = sdp_findchar(conn_p->conn_addr, "/");
+ if (slash_ptr[0] != '\0') {
+ if (conn_p->is_multicast) {
+ SDP_PRINT("%s A multicast address with slash %s",
+ sdp_p->debug_str, conn_p->conn_addr);
+ slash_ptr++;
+ slash_ptr = sdp_getnextstrtok(slash_ptr, tmp, sizeof(tmp), "/", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s No ttl value specified for this multicast addr with a slash",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ errno = 0;
+ strtoul_result = strtoul(tmp, &strtoul_end, 10);
+
+ if (errno || tmp == strtoul_end || conn_p->ttl > SDP_MAX_TTL_VALUE) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Invalid TTL: Value must be in the range 0-255 ",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ conn_p->ttl = (int) strtoul_result;
+
+ /* search for num of addresses */
+ /*sa_ignore NO_NULL_CHK
+ {ptr is valid since the pointer was checked earlier and the
+ function would have exited if NULL.}*/
+ slash_ptr = sdp_findchar(slash_ptr, "/");
+ if (slash_ptr != NULL &&
+ slash_ptr[0] != '\0') {
+ SDP_PRINT("%s Found a num addr field for multicast addr %s ",
+ sdp_p->debug_str,slash_ptr);
+ slash_ptr++;
+
+ errno = 0;
+ strtoul_result = strtoul(slash_ptr, &strtoul_end, 10);
+
+ if (errno || slash_ptr == strtoul_end || strtoul_result == 0) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Invalid Num of addresses: Value must be > 0 ",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return SDP_INVALID_PARAMETER;
+ }
+
+ conn_p->num_of_addresses = (int) strtoul_result;
+ }
+ } else {
+ sdp_p->conf_p->num_invalid_param++;
+ SDP_PRINT("%s Only multicast addresses allowed with slashes",
+ sdp_p->debug_str);
+ return (SDP_INVALID_PARAMETER);
+ }
+ }
+ }
+
+ /* See if the address is the choose param and if it's allowed. */
+ if ((sdp_p->conf_p->allow_choose[SDP_CHOOSE_CONN_ADDR] == FALSE) &&
+ (strcmp(conn_p->conn_addr, "$") == 0)) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: Choose parameter for connection "
+ "address specified but not allowed.", sdp_p->debug_str);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parse connection: network %s, address type %s, "
+ "address %s ttl= %d num of addresses = %d",
+ sdp_p->debug_str,
+ sdp_get_network_name(conn_p->nettype),
+ sdp_get_address_name(conn_p->addrtype),
+ conn_p->conn_addr, conn_p->ttl, conn_p->num_of_addresses);
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_connection (sdp_t *sdp_p, u16 level, flex_string *fs)
+{
+ sdp_mca_t *mca_p;
+ sdp_conn_t *conn_p;
+
+ if (level == SDP_SESSION_LEVEL) {
+ conn_p = &(sdp_p->default_conn);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (SDP_FAILURE);
+ }
+ conn_p = &(mca_p->conn);
+ }
+
+ if((conn_p->nettype == SDP_NT_ATM ) &&
+ (conn_p->addrtype == SDP_AT_INVALID)) {
+ /*allow c= line to be built without address type and address fields
+ * This is a special case for ATM PVC*/
+ flex_string_sprintf(fs, "c=%s\r\n",
+ sdp_get_network_name(conn_p->nettype));
+ return SDP_SUCCESS;
+ }
+ if ((conn_p->nettype >= SDP_MAX_NETWORK_TYPES) ||
+ (conn_p->addrtype >= SDP_MAX_ADDR_TYPES) ||
+ (conn_p->conn_addr[0] == '\0')) {
+ /* Connection info isn't set - don't need to build the token. */
+ return (SDP_SUCCESS);
+ }
+
+ if (conn_p->is_multicast) {
+ if (conn_p->num_of_addresses > 1) {
+ flex_string_sprintf(fs, "c=%s %s %s/%d/%d\r\n",
+ sdp_get_network_name(conn_p->nettype),
+ sdp_get_address_name(conn_p->addrtype),
+ conn_p->conn_addr, conn_p->ttl,
+ conn_p->num_of_addresses);
+ } else {
+ flex_string_sprintf(fs, "c=%s %s %s/%d\r\n",
+ sdp_get_network_name(conn_p->nettype),
+ sdp_get_address_name(conn_p->addrtype),
+ conn_p->conn_addr, conn_p->ttl);
+ }
+ } else {
+
+ flex_string_sprintf(fs, "c=%s %s %s\r\n",
+ sdp_get_network_name(conn_p->nettype),
+ sdp_get_address_name(conn_p->addrtype),
+ conn_p->conn_addr);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Built c= connection line", sdp_p->debug_str);
+ }
+ return (SDP_SUCCESS);
+}
+
+/*
+ * sdp_parse_bandwidth
+ *
+ * This function parses a bandwidth field. The parsing is done in accordance
+ * to the following ABNF:
+ *
+ * bandwidth-fields = *("b=" bwtype ":" bandwidth CRLF)
+ * bwtype = 1*(alpha-numeric)
+ * bandwidth = 1*(DIGIT)
+ *
+ * It currently supports three types of valid bwtypes - AS, CT and TIAS
+ */
+sdp_result_e sdp_parse_bandwidth (sdp_t *sdp_p, u16 level, const char *ptr)
+{
+ int i;
+ sdp_mca_t *mca_p;
+ sdp_bw_t *bw_p;
+ sdp_bw_data_t *bw_data_p;
+ sdp_bw_data_t *new_bw_data_p;
+ sdp_result_e result;
+ char tmp[SDP_MAX_STRING_LEN];
+ sdp_bw_modifier_e bw_modifier = SDP_BW_MODIFIER_UNSUPPORTED;
+ int bw_val = 0;
+
+ if (level == SDP_SESSION_LEVEL) {
+ bw_p = &(sdp_p->bw);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (SDP_FAILURE);
+ }
+ bw_p = &(mca_p->bw);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parse bandwidth line", sdp_p->debug_str);
+ }
+
+ /* Find the bw type (AS, CT or TIAS) */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), ":", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s No bandwidth type specified for b= ",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ for (i=0; i < SDP_MAX_BW_MODIFIER_VAL; i++) {
+ if (cpr_strncasecmp(tmp, sdp_bw_modifier_val[i].name,
+ sdp_bw_modifier_val[i].strlen) == 0) {
+ bw_modifier = (sdp_bw_modifier_e)i;
+ break;
+ }
+ }
+
+ if (bw_modifier == SDP_BW_MODIFIER_UNSUPPORTED) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Error: BW Modifier type unsupported (%s).",
+ sdp_p->debug_str, tmp);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Find the BW type value */
+ /*sa_ignore NO_NULL_CHK
+ {ptr is valid since the pointer was checked earlier and the
+ function would have exited if NULL.}*/
+ if (*ptr == ':') {
+ ptr++;
+ bw_val = sdp_getnextnumtok(ptr, &ptr, " \t", &result);
+ if ((result != SDP_SUCCESS)) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Error: No BW Value specified ",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ }
+
+ /*
+ * Allocate a new sdp_bw_data_t instance and set it's values from the
+ * input parameters.
+ */
+ new_bw_data_p = (sdp_bw_data_t*)SDP_MALLOC(sizeof(sdp_bw_data_t));
+ if (new_bw_data_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_NO_RESOURCE);
+ }
+ new_bw_data_p->next_p = NULL;
+ new_bw_data_p->bw_modifier = bw_modifier;
+ new_bw_data_p->bw_val = bw_val;
+
+ /*
+ * Enqueue the sdp_bw_data_t instance at the end of the list of
+ * sdp_bw_data_t instances.
+ */
+ if (bw_p->bw_data_list == NULL) {
+ bw_p->bw_data_list = new_bw_data_p;
+ } else {
+ for (bw_data_p = bw_p->bw_data_list;
+ bw_data_p->next_p != NULL;
+ bw_data_p = bw_data_p->next_p) {
+ ; // Empty For
+ }
+ bw_data_p->next_p = new_bw_data_p;
+ }
+ bw_p->bw_data_count++;
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed bw type %s, value %d", sdp_p->debug_str,
+ sdp_get_bw_modifier_name(new_bw_data_p->bw_modifier),
+ new_bw_data_p->bw_val);
+ }
+
+ return (SDP_SUCCESS);
+}
+
+/*
+ * sdp_build_bandwidth
+ *
+ * Builds *all* the bandwith lines for the specified level.
+ */
+sdp_result_e sdp_build_bandwidth (sdp_t *sdp_p, u16 level, flex_string *fs)
+{
+ sdp_bw_t *bw_p;
+ sdp_bw_data_t *bw_data_p;
+ sdp_mca_t *mca_p;
+
+ if (level == SDP_SESSION_LEVEL) {
+ bw_p = &(sdp_p->bw);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (SDP_FAILURE);
+ }
+ bw_p = &(mca_p->bw);
+ }
+
+ bw_data_p = bw_p->bw_data_list;
+ while (bw_data_p) {
+ flex_string_sprintf(fs, "b=%s:%d\r\n",
+ sdp_get_bw_modifier_name(bw_data_p->bw_modifier),
+ bw_data_p->bw_val);
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Built b=%s:%d bandwidth line", sdp_p->debug_str,
+ sdp_get_bw_modifier_name(bw_data_p->bw_modifier),
+ bw_data_p->bw_val);
+ }
+
+ bw_data_p = bw_data_p->next_p;
+ }
+
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_parse_timespec (sdp_t *sdp_p, u16 level, const char *ptr)
+{
+ char *tmpptr;
+ sdp_result_e result;
+ sdp_timespec_t *timespec_p;
+ sdp_timespec_t *next_timespec_p;
+
+ timespec_p = (sdp_timespec_t *)SDP_MALLOC(sizeof(sdp_timespec_t));
+ if (timespec_p == NULL) {
+ sdp_p->conf_p->num_no_resource++;
+ return (SDP_NO_RESOURCE);
+ }
+
+ /* Validate start and stop times. */
+ ptr = sdp_getnextstrtok(ptr, timespec_p->start_time, sizeof(timespec_p->start_time), " \t", &result);
+ if (result == SDP_SUCCESS) {
+ /* Make sure the start_time is numeric, even though we store it as
+ * a string.
+ */
+ (void)sdp_getnextnumtok(timespec_p->start_time,
+ (const char **)&tmpptr, " \t", &result);
+ }
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Invalid timespec start time specified.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ SDP_FREE(timespec_p);
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ ptr = sdp_getnextstrtok(ptr, timespec_p->stop_time, sizeof(timespec_p->stop_time), " \t", &result);
+ if (result == SDP_SUCCESS) {
+ /* Make sure the start_time is numeric, even though we store it as
+ * a string.
+ */
+ (void)sdp_getnextnumtok(timespec_p->stop_time,
+ (const char **)&tmpptr, " \t", &result);
+ }
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Invalid timespec stop time specified.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ SDP_FREE(timespec_p);
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Link the new timespec in to the end of the list. */
+ if (sdp_p->timespec_p == NULL) {
+ sdp_p->timespec_p = timespec_p;
+ } else {
+ next_timespec_p = sdp_p->timespec_p;
+ while (next_timespec_p->next_p != NULL) {
+ next_timespec_p = next_timespec_p->next_p;
+ }
+ next_timespec_p->next_p = timespec_p;
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed timespec line", sdp_p->debug_str);
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_timespec (sdp_t *sdp_p, u16 level, flex_string *fs)
+{
+ if ((sdp_p->timespec_p == NULL) ||
+ (sdp_p->timespec_p->start_time == '\0') ||
+ (sdp_p->timespec_p->stop_time == '\0')) {
+ if (sdp_p->conf_p->timespec_reqd == TRUE) {
+ CSFLogError(logTag, "%s Invalid params for t= time spec line, "
+ "build failed.", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ /* t= line not required. */
+ return (SDP_SUCCESS);
+ }
+ }
+
+ /* Note: We only support one t= line currently. */
+ flex_string_sprintf(fs, "t=%s %s\r\n", sdp_p->timespec_p->start_time,
+ sdp_p->timespec_p->stop_time);
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Built t= timespec line", sdp_p->debug_str);
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_parse_repeat_time (sdp_t *sdp_p, u16 level, const char *ptr)
+{
+ char *endptr;
+
+ endptr = sdp_findchar(ptr, "\n");
+ if (ptr == endptr) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No repeat time parameters "
+ "specified.", sdp_p->debug_str);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed repeat time line", sdp_p->debug_str);
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_repeat_time (sdp_t *sdp_p, u16 level, flex_string *fs)
+{
+ /* Build repeat time line not supported. */
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_parse_timezone_adj (sdp_t *sdp_p, u16 level, const char *ptr)
+{
+ char *endptr;
+
+ endptr = sdp_findchar(ptr, "\n");
+ if (ptr == endptr) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No timezone parameters specified.",
+ sdp_p->debug_str);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parse timezone adustment line", sdp_p->debug_str);
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_timezone_adj (sdp_t *sdp_p, u16 level, flex_string *fs)
+{
+ /* Build timezone adjustment line not supported. */
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_parse_encryption (sdp_t *sdp_p, u16 level, const char *ptr)
+{
+ int i;
+ sdp_result_e result;
+ sdp_encryptspec_t *encrypt_p;
+ sdp_mca_t *mca_p;
+ char tmp[SDP_MAX_STRING_LEN];
+
+ if (level == SDP_SESSION_LEVEL) {
+ encrypt_p = &(sdp_p->encrypt);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (SDP_FAILURE);
+ }
+ encrypt_p = &(mca_p->encrypt);
+ }
+ encrypt_p->encrypt_key[0] = '\0';
+
+ /* Find the encryption type. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), ":", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s No encryption type specified for k=.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ encrypt_p->encrypt_type = SDP_ENCRYPT_UNSUPPORTED;
+ for (i=0; i < SDP_MAX_ENCRYPT_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_encrypt[i].name,
+ sdp_encrypt[i].strlen) == 0) {
+ encrypt_p->encrypt_type = (sdp_encrypt_type_e)i;
+ break;
+ }
+ }
+ if (encrypt_p->encrypt_type == SDP_ENCRYPT_UNSUPPORTED) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: Encryption type unsupported (%s).",
+ sdp_p->debug_str, tmp);
+ }
+
+ /* Find the encryption key. */
+ encrypt_p->encrypt_key[0] = '\0';
+ /*sa_ignore NO_NULL_CHK
+ {ptr is valid since the pointer was checked earlier and the
+ function would have exited if NULL.}*/
+ if (*ptr == ':')
+ ptr++;
+ if (encrypt_p->encrypt_type != SDP_ENCRYPT_PROMPT) {
+ ptr = sdp_getnextstrtok(ptr, encrypt_p->encrypt_key, sizeof(encrypt_p->encrypt_key), " \t", &result);
+ if ((result != SDP_SUCCESS) &&
+ ((encrypt_p->encrypt_type == SDP_ENCRYPT_CLEAR) ||
+ (encrypt_p->encrypt_type == SDP_ENCRYPT_BASE64) ||
+ (encrypt_p->encrypt_type == SDP_ENCRYPT_URI))) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No encryption key specified "
+ "as required.", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parse encryption type %s, key %s", sdp_p->debug_str,
+ sdp_get_encrypt_name(encrypt_p->encrypt_type),
+ encrypt_p->encrypt_key);
+ }
+ return (SDP_SUCCESS);
+}
+
+/* If the encryption info is valid, we build it. Else skip it. */
+sdp_result_e sdp_build_encryption (sdp_t *sdp_p, u16 level, flex_string *fs)
+{
+ sdp_encryptspec_t *encrypt_p;
+ sdp_mca_t *mca_p;
+
+ if (level == SDP_SESSION_LEVEL) {
+ encrypt_p = &(sdp_p->encrypt);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (SDP_FAILURE);
+ }
+ encrypt_p = &(mca_p->encrypt);
+ }
+
+ if ((encrypt_p->encrypt_type >= SDP_MAX_ENCRYPT_TYPES) ||
+ ((encrypt_p->encrypt_type != SDP_ENCRYPT_PROMPT) &&
+ (encrypt_p->encrypt_key[0] == '\0'))) {
+ /* Encryption info isn't set - don't need to build the token. */
+ return (SDP_SUCCESS);
+ }
+
+ flex_string_sprintf(fs, "k=%s",
+ sdp_get_encrypt_name(encrypt_p->encrypt_type));
+
+ if (encrypt_p->encrypt_type == SDP_ENCRYPT_PROMPT) {
+ /* There is no key to print. */
+ flex_string_sprintf(fs, "\r\n");
+ } else {
+ flex_string_sprintf(fs, ":%s\r\n", encrypt_p->encrypt_key);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Built k= encryption line", sdp_p->debug_str);
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_parse_media (sdp_t *sdp_p, u16 level, const char *ptr)
+{
+ u16 i;
+ u16 num_port_params=0;
+ int32 num[SDP_MAX_PORT_PARAMS];
+ tinybool valid_param = FALSE;
+ sdp_result_e result;
+ sdp_mca_t *mca_p;
+ sdp_mca_t *next_mca_p;
+ char tmp[SDP_MAX_STRING_LEN];
+ char port[SDP_MAX_STRING_LEN];
+ const char *port_ptr;
+ int32 sctp_port;
+
+ /* Allocate resource for new media stream. */
+ mca_p = sdp_alloc_mca();
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_no_resource++;
+ return (SDP_NO_RESOURCE);
+ }
+
+ /* Find the media type. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s No media type specified, parse failed.",
+ sdp_p->debug_str);
+ SDP_FREE(mca_p);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ mca_p->media = SDP_MEDIA_UNSUPPORTED;
+ for (i=0; i < SDP_MAX_MEDIA_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_media[i].name,
+ sdp_media[i].strlen) == 0) {
+ mca_p->media = (sdp_media_e)i;
+ }
+ }
+ if (mca_p->media == SDP_MEDIA_UNSUPPORTED) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: Media type unsupported (%s).",
+ sdp_p->debug_str, tmp);
+ }
+
+ /* Find the port token parameters, but don't process it until
+ * we determine the transport protocol as that determines what
+ * port number formats are valid.
+ */
+ ptr = sdp_getnextstrtok(ptr, port, sizeof(port), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s No port specified in m= media line, "
+ "parse failed.", sdp_p->debug_str);
+ SDP_FREE(mca_p);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ port_ptr = port;
+ for (i=0; i < SDP_MAX_PORT_PARAMS; i++) {
+ if (sdp_getchoosetok(port_ptr, &port_ptr, "/ \t", &result) == TRUE) {
+ num[i] = SDP_CHOOSE_PARAM;
+ } else {
+ num[i] = sdp_getnextnumtok(port_ptr, (const char **)&port_ptr,
+ "/ \t", &result);
+ if (result != SDP_SUCCESS) {
+ break;
+ }
+ }
+ num_port_params++;
+ }
+
+ /* Find the transport protocol type. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s No transport protocol type specified, "
+ "parse failed.", sdp_p->debug_str);
+ SDP_FREE(mca_p);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ mca_p->transport = SDP_TRANSPORT_UNSUPPORTED;
+ for (i=0; i < SDP_MAX_TRANSPORT_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_transport[i].name,
+ sdp_transport[i].strlen) == 0) {
+ mca_p->transport = (sdp_transport_e)i;
+ break;
+ }
+ }
+ if (mca_p->transport == SDP_TRANSPORT_UNSUPPORTED) {
+ /* If we don't recognize or don't support the transport type,
+ * just store the first num as the port.
+ */
+ mca_p->port = num[0];
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: Transport protocol type unsupported "
+ "(%s).", sdp_p->debug_str, tmp);
+ }
+
+ /* Check for each of the possible port formats according to the
+ * type of transport protocol specified.
+ */
+ valid_param = FALSE;
+ switch (num_port_params) {
+ case 1:
+ if ((mca_p->transport == SDP_TRANSPORT_RTPAVP) ||
+ (mca_p->transport == SDP_TRANSPORT_RTPSAVP) ||
+ (mca_p->transport == SDP_TRANSPORT_RTPSAVPF) ||
+ (mca_p->transport == SDP_TRANSPORT_UDP) ||
+ (mca_p->transport == SDP_TRANSPORT_TCP) ||
+ (mca_p->transport == SDP_TRANSPORT_UDPTL) ||
+ (mca_p->transport == SDP_TRANSPORT_UDPSPRT) ||
+ (mca_p->transport == SDP_TRANSPORT_LOCAL) ||
+ (mca_p->transport == SDP_TRANSPORT_SCTPDTLS)) {
+ /* Port format is simply . Make sure that either
+ * the choose param is allowed or that the choose value
+ * wasn't specified.
+ */
+ if ((sdp_p->conf_p->allow_choose[SDP_CHOOSE_PORTNUM]) ||
+ (num[0] != SDP_CHOOSE_PARAM)) {
+ mca_p->port = num[0];
+ mca_p->port_format = SDP_PORT_NUM_ONLY;
+ valid_param = TRUE;
+ }
+ } else if (mca_p->transport == SDP_TRANSPORT_AAL1AVP) {
+ /* Port format is simply , choose param is not allowed.
+ */
+ if (num[0] != SDP_CHOOSE_PARAM) {
+ mca_p->vcci = num[0];
+ mca_p->port_format = SDP_PORT_VCCI;
+ valid_param = TRUE;
+ }
+ } else if ((mca_p->transport == SDP_TRANSPORT_AAL2_ITU) ||
+ (mca_p->transport == SDP_TRANSPORT_AAL2_ATMF) ||
+ (mca_p->transport == SDP_TRANSPORT_AAL2_CUSTOM)) {
+ /* Port format is simply , and choose param is allowed,
+ * according to AAL2 definitions.
+ */
+ mca_p->port = num[0];
+ mca_p->port_format = SDP_PORT_NUM_ONLY;
+ valid_param = TRUE;
+ }
+ break;
+ case 2:
+ if ((mca_p->transport == SDP_TRANSPORT_RTPAVP) ||
+ (mca_p->transport == SDP_TRANSPORT_RTPSAVP) ||
+ (mca_p->transport == SDP_TRANSPORT_RTPSAVPF) ||
+ (mca_p->transport == SDP_TRANSPORT_UDP) ||
+ (mca_p->transport == SDP_TRANSPORT_LOCAL)) {
+ /* Port format is /. Make sure choose
+ * params were not specified.
+ */
+ if ((num[0] != SDP_CHOOSE_PARAM) &&
+ (num[1] != SDP_CHOOSE_PARAM)) {
+ mca_p->port = num[0];
+ mca_p->num_ports = num[1];
+ mca_p->port_format = SDP_PORT_NUM_COUNT;
+ valid_param = TRUE;
+ }
+ } else if (mca_p->transport == SDP_TRANSPORT_UDPTL) {
+ /* Port format is /. Make sure choose
+ * params were not specified. For UDPTL, only "1" may
+ * be specified for number of ports.
+ */
+ if ((num[0] != SDP_CHOOSE_PARAM) &&
+ (num[1] == 1)) {
+ mca_p->port = num[0];
+ mca_p->num_ports = 1;
+ mca_p->port_format = SDP_PORT_NUM_COUNT;
+ valid_param = TRUE;
+ }
+ } else if (mca_p->transport == SDP_TRANSPORT_CES10) {
+ /* Port format is /. Make sure choose
+ * params were not specified.
+ */
+ if ((num[0] != SDP_CHOOSE_PARAM) &&
+ (num[1] != SDP_CHOOSE_PARAM)) {
+ mca_p->vpi = num[0];
+ mca_p->vci = num[1];
+ mca_p->port_format = SDP_PORT_VPI_VCI;
+ valid_param = TRUE;
+ }
+ } else if ((mca_p->transport == SDP_TRANSPORT_AAL2_ITU) ||
+ (mca_p->transport == SDP_TRANSPORT_AAL2_ATMF) ||
+ (mca_p->transport == SDP_TRANSPORT_AAL2_CUSTOM)) {
+ /* Port format is either / or $/$. If one
+ * param is '$' the other must be also. The choose params
+ * are allowed by default and don't need to be allowed
+ * through the appl config.
+ */
+ if (((num[0] != SDP_CHOOSE_PARAM) &&
+ (num[1] != SDP_CHOOSE_PARAM)) ||
+ ((num[0] == SDP_CHOOSE_PARAM) &&
+ (num[1] == SDP_CHOOSE_PARAM))) {
+ mca_p->vcci = num[0];
+ mca_p->cid = num[1];
+ mca_p->port_format = SDP_PORT_VCCI_CID;
+ valid_param = TRUE;
+ }
+ }
+ break;
+ case 3:
+ if (mca_p->transport == SDP_TRANSPORT_AAL1AVP) {
+ /* Port format is //. Make sure choose
+ * params were not specified.
+ */
+ if ((num[0] != SDP_CHOOSE_PARAM) &&
+ (num[1] != SDP_CHOOSE_PARAM) &&
+ (num[2] != SDP_CHOOSE_PARAM)) {
+ mca_p->port = num[0];
+ mca_p->vpi = num[1];
+ mca_p->vci = num[2];
+ mca_p->port_format = SDP_PORT_NUM_VPI_VCI;
+ valid_param = TRUE;
+ }
+ }
+ break;
+ case 4:
+ if ((mca_p->transport == SDP_TRANSPORT_AAL2_ITU) ||
+ (mca_p->transport == SDP_TRANSPORT_AAL2_ATMF) ||
+ (mca_p->transport == SDP_TRANSPORT_AAL2_CUSTOM)) {
+ /* Port format is ///. Make sure choose
+ * params were not specified.
+ */
+ if ((num[0] != SDP_CHOOSE_PARAM) &&
+ (num[1] != SDP_CHOOSE_PARAM) &&
+ (num[2] != SDP_CHOOSE_PARAM) &&
+ (num[3] != SDP_CHOOSE_PARAM)) {
+ mca_p->port = num[0];
+ mca_p->vpi = num[1];
+ mca_p->vci = num[2];
+ mca_p->cid = num[3];
+ mca_p->port_format = SDP_PORT_NUM_VPI_VCI_CID;
+ valid_param = TRUE;
+ }
+ }
+ break;
+ }
+ if (valid_param == FALSE) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Invalid port format (%s) specified for transport "
+ "protocol (%s), parse failed.", sdp_p->debug_str,
+ port, sdp_get_transport_name(mca_p->transport));
+ sdp_p->conf_p->num_invalid_param++;
+ SDP_FREE(mca_p);
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Find payload formats. AAL2 media lines allow multiple
+ * transport/profile types per line, so these are handled differently. */
+ if ((mca_p->transport == SDP_TRANSPORT_AAL2_ITU) ||
+ (mca_p->transport == SDP_TRANSPORT_AAL2_ATMF) ||
+ (mca_p->transport == SDP_TRANSPORT_AAL2_CUSTOM)) {
+
+ if (sdp_parse_multiple_profile_payload_types(sdp_p, mca_p, ptr) !=
+ SDP_SUCCESS) {
+ sdp_p->conf_p->num_invalid_param++;
+ SDP_FREE(mca_p);
+ return (SDP_INVALID_PARAMETER);
+ }
+ } else {
+ /* Transport is a non-AAL2 type. Parse payloads normally. */
+ sdp_parse_payload_types(sdp_p, mca_p, ptr);
+ }
+
+ /* Parse SCTP/DTLS port */
+ if (mca_p->transport == SDP_TRANSPORT_SCTPDTLS) {
+ ptr = sdp_getnextstrtok(ptr, port, sizeof(port), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s No sctp port specified in m= media line, "
+ "parse failed.", sdp_p->debug_str);
+ SDP_FREE(mca_p);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ port_ptr = port;
+
+ if (sdp_getchoosetok(port_ptr, &port_ptr, "/ \t", &result)) {
+ sctp_port = SDP_CHOOSE_PARAM;
+ } else {
+ sctp_port = sdp_getnextnumtok(port_ptr, (const char **)&port_ptr,
+ "/ \t", &result);
+ if (result != SDP_SUCCESS) {
+ return (SDP_INVALID_PARAMETER);
+ }
+ mca_p->sctpport = sctp_port;
+ }
+ }
+
+ /* Media line params are valid. Add it into the SDP. */
+ sdp_p->mca_count++;
+ if (sdp_p->mca_p == NULL) {
+ sdp_p->mca_p = mca_p;
+ } else {
+ for (next_mca_p = sdp_p->mca_p; next_mca_p->next_p != NULL;
+ next_mca_p = next_mca_p->next_p) {
+ ; // Empty For
+ }
+ next_mca_p->next_p = mca_p;
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+
+ SDP_PRINT("%s Parsed media type %s, ", sdp_p->debug_str,
+ sdp_get_media_name(mca_p->media));
+ switch (mca_p->port_format) {
+ case SDP_PORT_NUM_ONLY:
+ SDP_PRINT("Port num %ld, ", mca_p->port);
+ break;
+
+ case SDP_PORT_NUM_COUNT:
+ SDP_PRINT("Port num %ld, count %ld, ",
+ mca_p->port, mca_p->num_ports);
+ break;
+ case SDP_PORT_VPI_VCI:
+ SDP_PRINT("VPI/VCI %ld/%lu, ", mca_p->vpi, mca_p->vci);
+ break;
+ case SDP_PORT_VCCI:
+ SDP_PRINT("VCCI %ld, ", mca_p->vcci);
+ break;
+ case SDP_PORT_NUM_VPI_VCI:
+ SDP_PRINT("Port %ld, VPI/VCI %ld/%lu, ", mca_p->port,
+ mca_p->vpi, mca_p->vci);
+ break;
+ case SDP_PORT_VCCI_CID:
+ SDP_PRINT("VCCI %ld, CID %ld, ", mca_p->vcci, mca_p->cid);
+ break;
+ case SDP_PORT_NUM_VPI_VCI_CID:
+ SDP_PRINT("Port %ld, VPI/VCI %ld/%lu, CID %ld, ", mca_p->port,
+ mca_p->vpi, mca_p->vci, mca_p->cid);
+ break;
+ default:
+ SDP_PRINT("Port format not valid, ");
+ break;
+ }
+
+ if ((mca_p->transport >= SDP_TRANSPORT_AAL2_ITU) &&
+ (mca_p->transport <= SDP_TRANSPORT_AAL2_CUSTOM)) {
+ for (i=0; i < mca_p->media_profiles_p->num_profiles; i++) {
+ SDP_PRINT("Profile %s, Num payloads %u ",
+ sdp_get_transport_name(mca_p->media_profiles_p->profile[i]),
+ mca_p->media_profiles_p->num_payloads[i]);
+ }
+ } else {
+ SDP_PRINT("Transport %s, Num payloads %u",
+ sdp_get_transport_name(mca_p->transport),
+ mca_p->num_payloads);
+ }
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_media (sdp_t *sdp_p, u16 level, flex_string *fs)
+{
+ int i, j;
+ sdp_mca_t *mca_p;
+ tinybool invalid_params=FALSE;
+ sdp_media_profiles_t *profile_p;
+
+ /* Find the right media line */
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (SDP_FAILURE);
+ }
+
+ /* Validate params for this media line */
+ if ((mca_p->media >= SDP_MAX_MEDIA_TYPES) ||
+ (mca_p->port_format >= SDP_MAX_PORT_FORMAT_TYPES) ||
+ (mca_p->transport >= SDP_MAX_TRANSPORT_TYPES)) {
+ invalid_params = TRUE;
+ }
+
+ if (invalid_params == TRUE) {
+ CSFLogError(logTag, "%s Invalid params for m= media line, "
+ "build failed.", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Build the media type */
+ flex_string_sprintf(fs, "m=%s ", sdp_get_media_name(mca_p->media));
+
+ /* Build the port based on the specified port format */
+ if (mca_p->port_format == SDP_PORT_NUM_ONLY) {
+ if (mca_p->port == SDP_CHOOSE_PARAM) {
+ flex_string_sprintf(fs, "$ ");
+ } else {
+ flex_string_sprintf(fs, "%u ", (u16)mca_p->port);
+ }
+ } else if (mca_p->port_format == SDP_PORT_NUM_COUNT) {
+ flex_string_sprintf(fs, "%u/%u ", (u16)mca_p->port,
+ (u16)mca_p->num_ports);
+ } else if (mca_p->port_format == SDP_PORT_VPI_VCI) {
+ flex_string_sprintf(fs, "%u/%u ",
+ (u16)mca_p->vpi, (u16)mca_p->vci);
+ } else if (mca_p->port_format == SDP_PORT_VCCI) {
+ flex_string_sprintf(fs, "%u ", (u16)mca_p->vcci);
+ } else if (mca_p->port_format == SDP_PORT_NUM_VPI_VCI) {
+ flex_string_sprintf(fs, "%u/%u/%u ", (u16)mca_p->port,
+ (u16)mca_p->vpi, (u16)mca_p->vci);
+ } else if (mca_p->port_format == SDP_PORT_VCCI_CID) {
+ if ((mca_p->vcci == SDP_CHOOSE_PARAM) &&
+ (mca_p->cid == SDP_CHOOSE_PARAM)) {
+ flex_string_sprintf(fs, "$/$ ");
+ } else if ((mca_p->vcci == SDP_CHOOSE_PARAM) ||
+ (mca_p->cid == SDP_CHOOSE_PARAM)) {
+ /* If one is set but not the other, this is an error. */
+ CSFLogError(logTag, "%s Invalid params for m= port parameter, "
+ "build failed.", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ flex_string_sprintf(fs, "%u/%u ",
+ (u16)mca_p->vcci, (u16)mca_p->cid);
+ }
+ } else if (mca_p->port_format == SDP_PORT_NUM_VPI_VCI_CID) {
+ flex_string_sprintf(fs, "%u/%u/%u/%u ", (u16)mca_p->port,
+ (u16)mca_p->vpi, (u16)mca_p->vci, (u16)mca_p->cid);
+ }
+
+ /* If the media line has AAL2 profiles, build them differently. */
+ if ((mca_p->transport == SDP_TRANSPORT_AAL2_ITU) ||
+ (mca_p->transport == SDP_TRANSPORT_AAL2_ATMF) ||
+ (mca_p->transport == SDP_TRANSPORT_AAL2_CUSTOM)) {
+ profile_p = mca_p->media_profiles_p;
+ for (i=0; i < profile_p->num_profiles; i++) {
+ flex_string_sprintf(fs, "%s",
+ sdp_get_transport_name(profile_p->profile[i]));
+
+ for (j=0; j < profile_p->num_payloads[i]; j++) {
+ flex_string_sprintf(fs, " %u",
+ profile_p->payload_type[i][j]);
+ }
+ flex_string_sprintf(fs, " ");
+ }
+ flex_string_sprintf(fs, "\n");
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Built m= media line", sdp_p->debug_str);
+ }
+ return (SDP_SUCCESS);
+ }
+
+ /* Build the transport name */
+ flex_string_sprintf(fs, "%s",
+ sdp_get_transport_name(mca_p->transport));
+
+ if(mca_p->transport != SDP_TRANSPORT_SCTPDTLS) {
+
+ /* Build the format lists */
+ for (i=0; i < mca_p->num_payloads; i++) {
+ if (mca_p->payload_indicator[i] == SDP_PAYLOAD_ENUM) {
+ flex_string_sprintf(fs, " %s",
+ sdp_get_payload_name((sdp_payload_e)mca_p->payload_type[i]));
+ } else {
+ flex_string_sprintf(fs, " %u", mca_p->payload_type[i]);
+ }
+ }
+ } else {
+ /* Add port to SDP if transport is SCTP/DTLS */
+ flex_string_sprintf(fs, " %u ", (u32)mca_p->sctpport);
+ }
+
+ flex_string_sprintf(fs, "\r\n");
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Built m= media line", sdp_p->debug_str);
+ }
+ return (SDP_SUCCESS);
+}
+
+
+/* Function: sdp_parse_payload_types
+ * Description: Parse a list of payload types. The list may be part of
+ * a media line or part of a capability line.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * mca_p The mca structure the payload types should be
+ * added to.
+ * ptr The pointer to the list of payloads.
+ * Returns: Nothing.
+ */
+void sdp_parse_payload_types (sdp_t *sdp_p, sdp_mca_t *mca_p, const char *ptr)
+{
+ u16 i;
+ u16 num_payloads;
+ sdp_result_e result;
+ tinybool valid_payload;
+ char tmp[SDP_MAX_STRING_LEN];
+ char *tmp2;
+
+ for (num_payloads = 0; (num_payloads < SDP_MAX_PAYLOAD_TYPES); ) {
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ /* If there are no more payload types, we're finished */
+ break;
+ }
+ mca_p->payload_type[num_payloads] = (u16)sdp_getnextnumtok(tmp,
+ (const char **)&tmp2,
+ " \t", &result);
+ if (result == SDP_SUCCESS) {
+ if ((mca_p->media == SDP_MEDIA_IMAGE) &&
+ (mca_p->transport == SDP_TRANSPORT_UDPTL)) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: Numeric payload type not "
+ "valid for media %s with transport %s.",
+ sdp_p->debug_str,
+ sdp_get_media_name(mca_p->media),
+ sdp_get_transport_name(mca_p->transport));
+ } else {
+ mca_p->payload_indicator[num_payloads] = SDP_PAYLOAD_NUMERIC;
+ mca_p->num_payloads++;
+ num_payloads++;
+ }
+ continue;
+ }
+
+ valid_payload = FALSE;
+ for (i=0; i < SDP_MAX_STRING_PAYLOAD_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_payload[i].name,
+ sdp_payload[i].strlen) == 0) {
+ valid_payload = TRUE;
+ break;
+ }
+ }
+ if (valid_payload == TRUE) {
+ /* We recognized the payload type. Make sure it
+ * is valid for this media line. */
+ valid_payload = FALSE;
+ if ((mca_p->media == SDP_MEDIA_IMAGE) &&
+ (mca_p->transport == SDP_TRANSPORT_UDPTL) &&
+ (i == SDP_PAYLOAD_T38)) {
+ valid_payload = TRUE;
+ } else if ((mca_p->media == SDP_MEDIA_APPLICATION) &&
+ (mca_p->transport == SDP_TRANSPORT_UDP) &&
+ (i == SDP_PAYLOAD_XTMR)) {
+ valid_payload = TRUE;
+ } else if ((mca_p->media == SDP_MEDIA_APPLICATION) &&
+ (mca_p->transport == SDP_TRANSPORT_TCP) &&
+ (i == SDP_PAYLOAD_T120)) {
+ valid_payload = TRUE;
+ }
+
+ if (valid_payload == TRUE) {
+ mca_p->payload_indicator[num_payloads] = SDP_PAYLOAD_ENUM;
+ mca_p->payload_type[num_payloads] = i;
+ mca_p->num_payloads++;
+ num_payloads++;
+ } else {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: Payload type %s not valid for "
+ "media %s with transport %s.",
+ sdp_p->debug_str,
+ sdp_get_payload_name((sdp_payload_e)i),
+ sdp_get_media_name(mca_p->media),
+ sdp_get_transport_name(mca_p->transport));
+ }
+ } else {
+ /* Payload type wasn't recognized. */
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: Payload type "
+ "unsupported (%s).", sdp_p->debug_str, tmp);
+ }
+ }
+ if (mca_p->num_payloads == 0) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No payload types specified.",
+ sdp_p->debug_str);
+ }
+}
+
+
+/* Function: sdp_parse_multiple_profile_payload_types
+ * Description: Parse a list of payload types. The list may be part of
+ * a media line or part of a capability line.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * mca_p The mca structure the payload types should be
+ * added to.
+ * ptr The pointer to the list of payloads.
+ * Returns: Nothing.
+ */
+sdp_result_e sdp_parse_multiple_profile_payload_types (sdp_t *sdp_p,
+ sdp_mca_t *mca_p,
+ const char *ptr)
+{
+ u16 i;
+ u16 prof;
+ u16 payload;
+ sdp_result_e result;
+ sdp_media_profiles_t *profile_p;
+ char tmp[SDP_MAX_STRING_LEN];
+ char *tmp2;
+
+ /* If the transport type is any of the AAL2 formats, then we
+ * need to look for multiple AAL2 profiles and their associated
+ * payload lists. */
+ mca_p->media_profiles_p = (sdp_media_profiles_t *) \
+ SDP_MALLOC(sizeof(sdp_media_profiles_t));
+ if (mca_p->media_profiles_p == NULL) {
+ sdp_p->conf_p->num_no_resource++;
+ SDP_FREE(mca_p);
+ return (SDP_NO_RESOURCE);
+ }
+ profile_p = mca_p->media_profiles_p;
+ /* Set the first profile to the one already detected. */
+ profile_p->num_profiles = 1;
+ prof = 0;
+ payload = 0;
+ profile_p->profile[prof] = mca_p->transport;
+ profile_p->num_payloads[prof] = 0;
+
+ /* Now find the payload type lists and any other profile types */
+ while (TRUE) {
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ /* If there are no more payload types, we're finished */
+ break;
+ }
+
+ /* See if the next token is a new profile type. */
+ if (prof < SDP_MAX_PROFILES) {
+ profile_p->profile[prof+1] = SDP_TRANSPORT_UNSUPPORTED;
+ for (i=SDP_TRANSPORT_AAL2_ITU;
+ i <= SDP_TRANSPORT_AAL2_CUSTOM; i++) {
+ if (cpr_strncasecmp(tmp, sdp_transport[i].name,
+ sdp_transport[i].strlen) == 0) {
+ profile_p->profile[prof+1] = (sdp_transport_e)i;
+ break;
+ }
+ }
+ /* If we recognized the profile type, start looking for the
+ * next payload list. */
+ if (profile_p->profile[prof+1] != SDP_TRANSPORT_UNSUPPORTED) {
+ /* Now reset the payload counter for the next profile type. */
+ payload = 0;
+ prof++;
+ profile_p->num_profiles++;
+ if (prof < SDP_MAX_PROFILES) {
+ profile_p->num_payloads[prof] = 0;
+ }
+ continue;
+ }
+ }
+
+ /* This token must be a payload type. Make sure there aren't
+ * too many payload types. */
+ if (payload >= SDP_MAX_PAYLOAD_TYPES) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: Too many payload types "
+ "found, truncating.", sdp_p->debug_str);
+ continue;
+ }
+
+ /* See if the payload type is numeric. */
+ if (prof < SDP_MAX_PROFILES && payload < SDP_MAX_PAYLOAD_TYPES) {
+ profile_p->payload_type[prof][payload] = (u16)sdp_getnextnumtok(tmp,
+ (const char **)&tmp2,
+ " \t", &result);
+ if (result == SDP_SUCCESS) {
+ profile_p->payload_indicator[prof][payload] = SDP_PAYLOAD_NUMERIC;
+ profile_p->num_payloads[prof]++;
+ payload++;
+ continue;
+ }
+ }
+
+ /* No string payload types are currently valid for the AAL2
+ * transport types. This support can be added when needed. */
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: Unsupported payload type "
+ "found (%s).", sdp_p->debug_str, tmp);
+ }
+ for (i=0; i < profile_p->num_profiles; i++) {
+ /* Make sure we have payloads for each profile type. */
+ if (profile_p->num_payloads[i] == 0) {
+ sdp_parse_error(sdp_p->peerconnection,
+ "%s Warning: No payload types specified "
+ "for AAL2 profile %s.", sdp_p->debug_str,
+ sdp_get_transport_name(profile_p->profile[i]));
+ }
+ }
+ return (SDP_SUCCESS);
+}
diff --git a/libs/sipcc/core/sdp/sdp_utils.c b/libs/sipcc/core/sdp/sdp_utils.c
new file mode 100644
index 0000000000..b9e534fbfa
--- /dev/null
+++ b/libs/sipcc/core/sdp/sdp_utils.c
@@ -0,0 +1,773 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include
+#include
+#include "sdp_os_defs.h"
+#include "sdp.h"
+#include "sdp_private.h"
+#include "CSFLog.h"
+
+#define MKI_BUF_LEN 4
+
+//static const char* logTag = "sdp_utils";
+
+sdp_mca_t *sdp_alloc_mca () {
+ sdp_mca_t *mca_p;
+
+ /* Allocate resource for new media stream. */
+ mca_p = (sdp_mca_t *)SDP_MALLOC(sizeof(sdp_mca_t));
+ if (mca_p == NULL) {
+ return (NULL);
+ }
+ /* Initialize mca structure */
+ mca_p->media = SDP_MEDIA_INVALID;
+ mca_p->conn.nettype = SDP_NT_INVALID;
+ mca_p->conn.addrtype = SDP_AT_INVALID;
+ mca_p->conn.conn_addr[0] = '\0';
+ mca_p->conn.is_multicast = FALSE;
+ mca_p->conn.ttl = 0;
+ mca_p->conn.num_of_addresses = 0;
+ mca_p->transport = SDP_TRANSPORT_INVALID;
+ mca_p->port = SDP_INVALID_VALUE;
+ mca_p->num_ports = SDP_INVALID_VALUE;
+ mca_p->vpi = SDP_INVALID_VALUE;
+ mca_p->vci = 0;
+ mca_p->vcci = SDP_INVALID_VALUE;
+ mca_p->cid = SDP_INVALID_VALUE;
+ mca_p->num_payloads = 0;
+ mca_p->sessinfo_found = FALSE;
+ mca_p->encrypt.encrypt_type = SDP_ENCRYPT_INVALID;
+ mca_p->media_attrs_p = NULL;
+ mca_p->next_p = NULL;
+ mca_p->mid = 0;
+ mca_p->bw.bw_data_count = 0;
+ mca_p->bw.bw_data_list = NULL;
+
+ return (mca_p);
+}
+
+/*
+ * next_token
+ *
+ * copy token param with chars from str until null, cr, lf, or one of the delimiters is found.
+ * delimiters at the beginning will be skipped.
+ * The pointer *string_of_tokens is moved forward to the next token on sucess.
+ *
+ */
+static sdp_result_e next_token(const char **string_of_tokens, char *token, unsigned token_max_len, const char *delim)
+{
+ int flag2moveon = 0;
+ const char *str = *string_of_tokens;
+ char *token_start = token;
+ const char *next_delim;
+
+ if (!string_of_tokens || !*string_of_tokens || !token || !delim) {
+ return SDP_FAILURE;
+ }
+
+ /* Locate front of token, skipping any delimiters */
+ for ( ; ((*str != '\0') && (*str != '\n') && (*str != '\r')); str++) {
+ flag2moveon = 1; /* Default to move on unless we find a delimiter */
+ for (next_delim=delim; *next_delim; next_delim++) {
+ if (*str == *next_delim) {
+ flag2moveon = 0;
+ break;
+ }
+ }
+ if( flag2moveon ) {
+ break; /* We're at the beginning of the token */
+ }
+ }
+
+ /* Make sure there's really a token present. */
+ if ((*str == '\0') || (*str == '\n') || (*str == '\r')) {
+ return SDP_FAILURE;
+ }
+
+ /* Now locate end of token */
+ flag2moveon = 0;
+
+ while (((token-token_start) < token_max_len - 1) &&
+ (*str != '\0') && (*str != '\n') && (*str != '\r')) {
+ for (next_delim=delim; *next_delim; next_delim++) {
+ if (*str == *next_delim) {
+ flag2moveon = 1;
+ break;
+ }
+ }
+ if( flag2moveon ) {
+ break;
+ } else {
+ *token++ = *str++;
+ }
+ }
+
+ /* mark end of token */
+ *token = '\0';
+
+ /* set the string of tokens to the next token */
+ *string_of_tokens = str;
+
+ return SDP_SUCCESS;
+}
+
+/*
+ * verify_sdescriptions_mki
+ *
+ * Verifies the syntax of the MKI parameter.
+ *
+ * mki = mki-value ":" mki-length
+ * mki-value = 1*DIGIT
+ * mki-length = 1*3DIGIT ; range 1..128
+ *
+ * Inputs:
+ * buf - ptr to start of MKI string assumes NULL
+ * terminated string
+ * mkiValue - buffer to store the MKI value, assumes calling
+ * function has provided memory for this.
+ * mkiLen - integer to store the MKI length
+ *
+ * Outputs:
+ * Returns TRUE if syntax is correct and stores the
+ * MKI value in mkiVal and stores the length in mkiLen.
+ * Returns FALSE otherwise.
+ */
+
+tinybool
+verify_sdescriptions_mki (char *buf, char *mkiVal, u16 *mkiLen)
+{
+
+ char *ptr,
+ mkiValBuf[SDP_SRTP_MAX_MKI_SIZE_BYTES],
+ mkiLenBuf[MKI_BUF_LEN];
+ int idx = 0;
+ unsigned long strtoul_result;
+ char *strtoul_end;
+
+ ptr = buf;
+ /* MKI must begin with a digit */
+ if (!ptr || (!isdigit((int) *ptr))) {
+ return FALSE;
+ }
+
+ /* scan until we reach a non-digit or colon */
+ while (*ptr) {
+ if (*ptr == ':') {
+ /* terminate the MKI value */
+ mkiValBuf[idx] = 0;
+ ptr++;
+ break;
+ } else if ((isdigit((int) *ptr) && (idx < SDP_SRTP_MAX_MKI_SIZE_BYTES-1))) {
+ mkiValBuf[idx++] = *ptr;
+ } else {
+ return FALSE;
+ }
+
+ ptr++;
+ }
+
+ /* there has to be a mki length */
+ if (*ptr == 0) {
+ return FALSE;
+ }
+
+ idx = 0;
+
+ /* verify the mki length (max 3 digits) */
+ while (*ptr) {
+ if (isdigit((int) *ptr) && (idx < 3)) {
+ mkiLenBuf[idx++] = *ptr;
+ } else {
+ return FALSE;
+ }
+
+ ptr++;
+ }
+
+ mkiLenBuf[idx] = 0;
+
+ errno = 0;
+ strtoul_result = strtoul(mkiLenBuf, &strtoul_end, 10);
+
+ /* mki len must be between 1..128 */
+ if (errno || mkiLenBuf == strtoul_end || strtoul_result < 1 || strtoul_result > 128) {
+ *mkiLen = 0;
+ return FALSE;
+ }
+
+ *mkiLen = (u16) strtoul_result;
+ sstrncpy(mkiVal, mkiValBuf, MKI_BUF_LEN);
+
+ return TRUE;
+}
+
+/*
+ * verify_srtp_lifetime
+ *
+ * Verifies the Lifetime parameter syntax.
+ *
+ * lifetime = ["2^"] 1*(DIGIT)
+ *
+ * Inputs:
+ * buf - pointer to start of lifetime string. Assumes string is
+ * NULL terminated.
+ * Outputs:
+ * Returns TRUE if syntax is correct. Returns FALSE otherwise.
+ */
+
+tinybool
+verify_sdescriptions_lifetime (char *buf)
+{
+
+ char *ptr;
+ tinybool tokenFound = FALSE;
+
+ ptr = buf;
+ if (!ptr || *ptr == 0) {
+ return FALSE;
+ }
+
+ while (*ptr) {
+ if (*ptr == '^') {
+ if (tokenFound) {
+ /* make sure we don't have multiple ^ */
+ return FALSE;
+ } else {
+ tokenFound = TRUE;
+ /* Lifetime is in power of 2 format, make sure first and second
+ * chars are 2^
+ */
+
+ if (buf[0] != '2' || buf[1] != '^') {
+ return FALSE;
+ }
+ }
+ } else if (!isdigit((int) *ptr)) {
+ return FALSE;
+ }
+
+ ptr++;
+
+ }
+
+ /* Make sure if the format is 2^ that there is a number after the ^. */
+ if (tokenFound) {
+ if (strlen(buf) <= 2) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * sdp_validate_maxprate
+ *
+ * This function validates that the string passed in is of the form:
+ * packet-rate = 1*DIGIT ["." 1*DIGIT]
+ */
+tinybool
+sdp_validate_maxprate(const char *string_parm)
+{
+ tinybool retval = FALSE;
+
+ if (string_parm && (*string_parm)) {
+ while (isdigit((int)*string_parm)) {
+ string_parm++;
+ }
+
+ if (*string_parm == '.') {
+ string_parm++;
+ while (isdigit((int)*string_parm)) {
+ string_parm++;
+ }
+ }
+
+ if (*string_parm == '\0') {
+ retval = TRUE;
+ } else {
+ retval = FALSE;
+ }
+ }
+
+ return retval;
+}
+
+char *sdp_findchar (const char *ptr, char *char_list)
+{
+ int i;
+
+ for (;*ptr != '\0'; ptr++) {
+ for (i=0; char_list[i] != '\0'; i++) {
+ if (*ptr == char_list[i]) {
+ return ((char *)ptr);
+ }
+ }
+ }
+ return ((char *)ptr);
+}
+
+/* Locate the next token in a line. The delim characters are passed in
+ * as a param. The token also will not go past a new line char or the
+ * end of the string. Skip any delimiters before the token.
+ */
+const char *sdp_getnextstrtok (const char *str, char *tokenstr, unsigned tokenstr_len,
+ const char *delim, sdp_result_e *result)
+{
+ const char *token_list = str;
+
+ if (!str || !tokenstr || !delim || !result) {
+ if (result) {
+ *result = SDP_FAILURE;
+ }
+ return str;
+ }
+
+ *result = next_token(&token_list, tokenstr, tokenstr_len, delim);
+
+ return token_list;
+}
+
+
+
+/* Locate the next null ("-") or numeric token in a string. The delim
+ * characters are passed in as a param. The token also will not go past
+ * a new line char or the end of the string. Skip any delimiters before
+ * the token.
+ */
+u32 sdp_getnextnumtok_or_null (const char *str, const char **str_end,
+ const char *delim, tinybool *null_ind,
+ sdp_result_e *result)
+{
+ const char *token_list = str;
+ char temp_token[SDP_MAX_STRING_LEN];
+ char *strtoul_end;
+ unsigned long numval;
+
+ *null_ind = FALSE;
+
+ if (!str || !str_end || !delim || !null_ind || !result) {
+ if (result) {
+ *result = SDP_FAILURE;
+ }
+ return 0;
+ }
+
+ *result = next_token(&token_list, temp_token, sizeof(temp_token), delim);
+
+ if (*result != SDP_SUCCESS) {
+ return 0;
+ }
+
+ /* First see if its the null char ("-") */
+ if (temp_token[0] == '-') {
+ *null_ind = TRUE;
+ *result = SDP_SUCCESS;
+ *str_end = str;
+ return 0;
+ }
+
+ errno = 0;
+ numval = strtoul(temp_token, &strtoul_end, 10);
+
+ if (errno || strtoul_end == temp_token || numval > UINT_MAX) {
+ *result = SDP_FAILURE;
+ return 0;
+ }
+
+ *result = SDP_SUCCESS;
+ *str_end = token_list;
+ return (u32) numval;
+}
+
+
+/* Locate the next numeric token in a string. The delim characters are
+ * passed in as a param. The token also will not go past a new line char
+ * or the end of the string. Skip any delimiters before the token.
+ */
+u32 sdp_getnextnumtok (const char *str, const char **str_end,
+ const char *delim, sdp_result_e *result)
+{
+ const char *token_list = str;
+ char temp_token[SDP_MAX_STRING_LEN];
+ char *strtoul_end;
+ unsigned long numval;
+
+ if (!str || !str_end || !delim || !result) {
+ if (result) {
+ *result = SDP_FAILURE;
+ }
+ return 0;
+ }
+
+ *result = next_token(&token_list, temp_token, sizeof(temp_token), delim);
+
+ if (*result != SDP_SUCCESS) {
+ return 0;
+ }
+
+ errno = 0;
+ numval = strtoul(temp_token, &strtoul_end, 10);
+
+ if (errno || strtoul_end == temp_token || numval > UINT_MAX) {
+ *result = SDP_FAILURE;
+ return 0;
+ }
+
+ *result = SDP_SUCCESS;
+ *str_end = token_list;
+ return (u32) numval;
+}
+
+
+/* See if the next token in a string is the choose character. The delim
+ * characters are passed in as a param. The check also will not go past
+ * a new line char or the end of the string. Skip any delimiters before
+ * the token.
+ */
+tinybool sdp_getchoosetok (const char *str, const char **str_end,
+ const char *delim, sdp_result_e *result)
+{
+ const char *b;
+ int flag2moveon;
+
+ if ((str == NULL) || (str_end == NULL)) {
+ *result = SDP_FAILURE;
+ return(FALSE);
+ }
+
+ /* Locate front of token, skipping any delimiters */
+ for ( ; ((*str != '\0') && (*str != '\n') && (*str != '\r')); str++) {
+ flag2moveon = 1; /* Default to move on unless we find a delimiter */
+ for (b=delim; *b; b++) {
+ if (*str == *b) {
+ flag2moveon = 0;
+ break;
+ }
+ }
+ if( flag2moveon ) {
+ break; /* We're at the beginning of the token */
+ }
+ }
+
+ /* Make sure there's really a token present. */
+ if ((*str == '\0') || (*str == '\n') || (*str == '\r')) {
+ *result = SDP_FAILURE;
+ *str_end = (char *)str;
+ return(FALSE);
+ }
+
+ /* See if the token is '$' followed by a delimiter char or end of str. */
+ if (*str == '$') {
+ str++;
+ if ((*str == '\0') || (*str == '\n') || (*str == '\r')) {
+ *result = SDP_SUCCESS;
+ /* skip the choose char in the string. */
+ *str_end = (char *)(str+1);
+ return(TRUE);
+ }
+ for (b=delim; *b; b++) {
+ if (*str == *b) {
+ *result = SDP_SUCCESS;
+ /* skip the choose char in the string. */
+ *str_end = (char *)(str+1);
+ return(TRUE);
+ }
+ }
+ }
+
+ /* If the token was not '$' followed by a delim, token is not choose */
+ *result = SDP_SUCCESS;
+ *str_end = (char *)str;
+ return(FALSE);
+
+}
+
+/*
+ * SDP Crypto Utility Functions.
+ *
+ * First a few common definitions.
+ */
+
+/*
+ * Constants
+ *
+ * crypto_string = The string used to identify the start of sensative
+ * crypto data.
+ *
+ * inline_string = The string used to identify the start of key/salt
+ * crypto data.
+ *
+ * star_string = The string used to overwrite sensative data.
+ *
+ * '*_strlen' = The length of '*_string' in bytes (not including '\0')
+ */
+static const char crypto_string[] = "X-crypto:";
+static const int crypto_strlen = sizeof(crypto_string) - 1;
+static const char inline_string[] = "inline:";
+static const int inline_strlen = sizeof(inline_string) - 1;
+/* 40 characters is the current maximum for a Base64 encoded key/salt */
+static const char star_string[] = "****************************************";
+static const int star_strlen = sizeof(star_string) - 1;
+
+/*
+ * MIN_CRYPTO_STRING_SIZE_BYTES = This value defines the minimum
+ * size of a string that could contain a key/salt. This value
+ * is used to skip out of parsing when there is no reasonable
+ * assumption that sensative data will be found. The general
+ * format of a SRTP Key Salt in SDP looks like:
+ *
+ * X-crypto: inline:||
+ *
+ * if and is at least
+ * one character and one space is used before the "inline:",
+ * then this translates to a size of (aligned by collumn from
+ * the format shown above):
+ *
+ * 9+ 1+ 1+7+ 1+ 2 = 21
+ *
+ */
+#define MIN_CRYPTO_STRING_SIZE_BYTES 21
+
+/*
+ * Utility macros
+ *
+ * CHAR_IS_WHITESPACE = macro to determine if the passed _test_char
+ * is whitespace.
+ *
+ * SKIP_WHITESPACE = Macro to advance _cptr to the next non-whitespace
+ * character. _cptr will not be advanced past _max_cptr.
+ *
+ * FIND_WHITESPACE = Macro to advance _cptr until whitespace is found.
+ * _cptr will not be advanced past _max_cptr.
+ */
+#define CHAR_IS_WHITESPACE(_test_char) \
+ ((((_test_char)==' ')||((_test_char)=='\t'))?1:0)
+
+#define SKIP_WHITESPACE(_cptr, _max_cptr) \
+ while ((_cptr)<=(_max_cptr)) { \
+ if (!CHAR_IS_WHITESPACE(*(_cptr))) break; \
+ (_cptr)++; \
+ }
+
+#define FIND_WHITESPACE(_cptr, _max_cptr) \
+ while ((_cptr)<=(_max_cptr)) { \
+ if (CHAR_IS_WHITESPACE(*(_cptr))) break; \
+ (_cptr)++; \
+ }
+
+/* Function: sdp_crypto_debug
+ * Description: Check the passed buffer for sensitive data that should
+ * not be output (such as SRTP Master Key/Salt) and output
+ * the buffer as debug. Sensitive data will be replaced
+ * with the '*' character(s). This function may be used
+ * to display very large buffers so this function ensures
+ * that buginf is not overloaded.
+ * Parameters: buffer pointer to the message buffer to filter.
+ * length_bytes size of message buffer in bytes.
+ * Returns: Nothing.
+ */
+void sdp_crypto_debug (char *buffer, ulong length_bytes)
+{
+ char *current, *start;
+ char *last = buffer + length_bytes;
+ int result;
+
+ /*
+ * For SRTP Master Key/Salt has the form:
+ * X-crypto: inline:||
+ * Where is the data to elide (filter).
+ */
+ for (start=current=buffer;
+ current<=last-MIN_CRYPTO_STRING_SIZE_BYTES;
+ current++) {
+ if ((*current == 'x') || (*current == 'X')) {
+ result = cpr_strncasecmp(current, crypto_string, crypto_strlen);
+ if (!result) {
+ current += crypto_strlen;
+ if (current > last) break;
+
+ /* Skip over crypto suite name */
+ FIND_WHITESPACE(current, last);
+
+ /* Skip over whitespace */
+ SKIP_WHITESPACE(current, last);
+
+ /* identify inline keyword */
+ result = cpr_strncasecmp(current, inline_string, inline_strlen);
+ if (!result) {
+ int star_count = 0;
+
+ current += inline_strlen;
+ if (current > last) break;
+
+ sdp_dump_buffer(start, current - start);
+
+ /* Hide sensitive key/salt data */
+ while (current<=last) {
+ if (*current == '|' || *current == '\n') {
+ /* Done, print the stars */
+ while (star_count > star_strlen) {
+ /*
+ * This code is only for the case where
+ * too much base64 data was supplied
+ */
+ sdp_dump_buffer((char*)star_string, star_strlen);
+ star_count -= star_strlen;
+ }
+ sdp_dump_buffer((char*)star_string, star_count);
+ break;
+ } else {
+ star_count++;
+ current++;
+ }
+ }
+ /* Update start pointer */
+ start=current;
+ }
+ }
+ }
+ }
+
+ if (last > start) {
+ /* Display remainder of buffer */
+ sdp_dump_buffer(start, last - start);
+ }
+}
+
+/*
+ * sdp_debug_msg_filter
+ *
+ * DESCRIPTION
+ * Check the passed message buffer for sensitive data that should
+ * not be output (such as SRTP Master Key/Salt). Sensitive data
+ * will be replaced with the '*' character(s).
+ *
+ * PARAMETERS
+ * buffer: pointer to the message buffer to filter.
+ *
+ * length_bytes: size of message buffer in bytes.
+ *
+ * RETURN VALUE
+ * The buffer modified.
+ */
+char * sdp_debug_msg_filter (char *buffer, ulong length_bytes)
+{
+ char *current;
+ char *last = buffer + length_bytes;
+ int result;
+
+ SDP_PRINT("\n%s:%d: Eliding sensitive data from debug output",
+ __FILE__, __LINE__);
+ /*
+ * For SRTP Master Key/Salt has the form:
+ * X-crypto: inline:||
+ * Where is the data to elide (filter).
+ */
+ for (current=buffer;
+ current<=last-MIN_CRYPTO_STRING_SIZE_BYTES;
+ current++) {
+ if ((*current == 'x') || (*current == 'X')) {
+ result = cpr_strncasecmp(current, crypto_string, crypto_strlen);
+ if (!result) {
+ current += crypto_strlen;
+ if (current > last) break;
+
+ /* Skip over crypto suite name */
+ FIND_WHITESPACE(current, last);
+
+ /* Skip over whitespace */
+ SKIP_WHITESPACE(current, last);
+
+ /* identify inline keyword */
+ result = cpr_strncasecmp(current, inline_string, inline_strlen);
+ if (!result) {
+ current += inline_strlen;
+ if (current > last) break;
+
+ /* Hide sensitive key/salt data */
+ while (current<=last) {
+ if (*current == '|' || *current == '\n') {
+ /* Done */
+ break;
+ } else {
+ *current = '*';
+ current++;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return buffer;
+}
+
+
+/* Function: sdp_checkrange
+ * Description: This checks the range of a ulong value to make sure its
+ * within the range of 0 and 4Gig. stroul cannot be used since
+ * for values greater greater than 4G, stroul will either wrap
+ * around or return ULONG_MAX.
+ * Parameters: sdp_p Pointer to the sdp structure
+ * num The number to check the range for
+ * u_val This variable get populated with the ulong value
+ * if the number is within the range.
+ * Returns: tinybool - returns TRUE if the number passed is within the
+ * range, FALSE otherwise
+ */
+tinybool sdp_checkrange (sdp_t *sdp_p, char *num, ulong *u_val)
+{
+ ulong l_val;
+ char *endP = NULL;
+ *u_val = 0;
+
+ if (!num || !*num) {
+ return FALSE;
+ }
+
+ if (*num == '-') {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s ERROR: Parameter value is a negative number: %s",
+ sdp_p->debug_str, num);
+ }
+ return FALSE;
+ }
+
+ l_val = strtoul(num, &endP, 10);
+ if (*endP == '\0') {
+
+ if (l_val > 4294967295UL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s ERROR: Parameter value: %s is greater than 4294967295",
+ sdp_p->debug_str, num);
+ }
+ return FALSE;
+ }
+
+ if (l_val == 4294967295UL) {
+ /*
+ * On certain platforms where ULONG_MAX is equivalent to
+ * 4294967295, strtoul will return ULONG_MAX even if the the
+ * value of the string is greater than 4294967295. To detect
+ * that scenario we make an explicit check here.
+ */
+ if (strcmp("4294967295", num)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s ERROR: Parameter value: %s is greater than 4294967295",
+ sdp_p->debug_str, num);
+ }
+ return FALSE;
+ }
+ }
+ }
+ *u_val = l_val;
+ return TRUE;
+}
+
+#undef CHAR_IS_WHITESPACE
+#undef SKIP_WHITESPACE
+#undef FIND_WHITESPACE
diff --git a/libs/sipcc/core/sipstack/ccsip_callinfo.c b/libs/sipcc/core/sipstack/ccsip_callinfo.c
new file mode 100644
index 0000000000..c76afd86a5
--- /dev/null
+++ b/libs/sipcc/core/sipstack/ccsip_callinfo.c
@@ -0,0 +1,677 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include
+#include
+
+#include "ccsip_callinfo.h"
+#include "ccsip_protocol.h"
+#include "ccsip_core.h"
+#include "cpr_string.h"
+#include "cpr_strings.h"
+#include "cpr_types.h"
+#include "cpr_stdio.h"
+#include "cpr_memory.h"
+#include "cpr_stdlib.h"
+#include "phone_debug.h"
+
+
+#define FEAT_STRING_SIZE 80
+
+/*
+ * which_feature
+ *
+ * Description:
+ *
+ * A quick determination of the feature based on the string.
+ */
+static cc_call_info_e
+which_feature (char *feat_string_p)
+{
+ if (cpr_strcasecmp(feat_string_p, SIP_CI_HOLD_STR) == 0)
+ return CC_FEAT_HOLD;
+
+ if (cpr_strcasecmp(feat_string_p, SIP_CI_RESUME_STR) == 0)
+ return CC_FEAT_RESUME;
+
+ if (cpr_strcasecmp(feat_string_p, SIP_CI_BARGE_STR) == 0)
+ return CC_FEAT_BARGE;
+
+ if (cpr_strcasecmp(feat_string_p, SIP_CI_CBARGE_STR) == 0)
+ return CC_FEAT_CBARGE;
+
+ if (cpr_strcasecmp(feat_string_p, SIP_CI_CALL_INFO_STR) == 0)
+ return CC_FEAT_CALLINFO;
+
+ return CC_FEAT_NONE;
+}
+
+/*
+ * parse_call_info_parm
+ *
+ * Description:
+ *
+ * Parse potential callinfo feature parms.
+ */
+static void
+parse_call_info_parm (char *parm_p, cc_call_info_data_t * feature_data_p)
+{
+ static const char fname[] = "parse_call_info_parm";
+ char *temp_p;
+ uint16_t instance_id;
+ unsigned long strtoul_result;
+ char *strtoul_end;
+
+ if (!parm_p)
+ return;
+
+ while (parm_p) {
+ parm_p++;
+ SKIP_LWS(parm_p);
+
+ if (!cpr_strncasecmp(parm_p, SIP_CI_SECURITY,
+ sizeof(SIP_CI_SECURITY) - 1)) {
+ parm_p = parm_p + sizeof(SIP_CI_SECURITY) - 1;
+ SKIP_LWS(parm_p);
+
+ if (*parm_p) {
+ feature_data_p->call_info_feat_data.feature_flag |= CC_SECURITY;
+ if (!cpr_strncasecmp(parm_p, SIP_CI_SECURITY_UNKNOWN,
+ sizeof(SIP_CI_SECURITY_UNKNOWN) - 1)) {
+ feature_data_p->call_info_feat_data.security = CC_SECURITY_UNKNOWN;
+ } else if (!cpr_strncasecmp(parm_p, SIP_CI_SECURITY_AUTH,
+ sizeof(SIP_CI_SECURITY_AUTH) - 1)) {
+ feature_data_p->call_info_feat_data.security = CC_SECURITY_AUTHENTICATED;
+ } else if (!cpr_strncasecmp(parm_p, SIP_CI_SECURITY_ENCRYPTED,
+ sizeof(SIP_CI_SECURITY_ENCRYPTED) - 1)) {
+ feature_data_p->call_info_feat_data.security = CC_SECURITY_ENCRYPTED;
+ } else if (!cpr_strncasecmp(parm_p, SIP_CI_SECURITY_NOT_AUTH,
+ sizeof(SIP_CI_SECURITY_NOT_AUTH) - 1)) {
+ feature_data_p->call_info_feat_data.security = CC_SECURITY_NOT_AUTHENTICATED;
+ } else {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX "Unknown security"
+ " value %s\n", fname, parm_p);
+ feature_data_p->call_info_feat_data.security = CC_SECURITY_UNKNOWN;
+ }
+ } else {
+ break;
+ }
+ } else if (!cpr_strncasecmp(parm_p, SIP_CI_POLICY,
+ sizeof(SIP_CI_POLICY) - 1)) {
+ parm_p = parm_p + sizeof(SIP_CI_POLICY) - 1;
+ SKIP_LWS(parm_p);
+
+ if (*parm_p) {
+ feature_data_p->call_info_feat_data.feature_flag |= CC_POLICY;
+ if (!cpr_strncasecmp(parm_p, SIP_CI_POLICY_CHAPERONE ,
+ sizeof(SIP_CI_POLICY_CHAPERONE) - 1)) {
+ feature_data_p->call_info_feat_data.policy = CC_POLICY_CHAPERONE;
+ } else if (!cpr_strncasecmp(parm_p, SIP_CI_POLICY_UNKNOWN,
+ sizeof(SIP_CI_POLICY_UNKNOWN) - 1)) {
+ feature_data_p->call_info_feat_data.policy = CC_POLICY_UNKNOWN;
+ } else {
+ CCSIP_DEBUG_ERROR("%s ERROR: Unknown policy"
+ " value %s\n", fname, parm_p) ;
+ feature_data_p->call_info_feat_data.policy = CC_POLICY_UNKNOWN;
+ }
+ } else {
+ break;
+ }
+ } else if (!cpr_strncasecmp(parm_p, SIP_CI_ORIENTATION,
+ sizeof(SIP_CI_ORIENTATION) - 1)) {
+ parm_p = parm_p + sizeof(SIP_CI_ORIENTATION) - 1;
+ SKIP_LWS(parm_p);
+
+ if (*parm_p) {
+ feature_data_p->call_info_feat_data.feature_flag |= CC_ORIENTATION;
+ if (!cpr_strncasecmp(parm_p, SIP_CI_ORIENTATION_FROM,
+ sizeof(SIP_CI_ORIENTATION_FROM) - 1)) {
+ feature_data_p->call_info_feat_data.orientation = CC_ORIENTATION_FROM;
+ } else if (!cpr_strncasecmp(parm_p, SIP_CI_ORIENTATION_TO,
+ sizeof(SIP_CI_ORIENTATION_TO) - 1)) {
+ feature_data_p->call_info_feat_data.orientation = CC_ORIENTATION_TO;
+ } else {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX "Unknown orientation info"
+ " value %s\n", fname, parm_p);
+ feature_data_p->call_info_feat_data.orientation = CC_ORIENTATION_NONE;
+ }
+ } else {
+ break;
+ }
+ } else if (!cpr_strncasecmp(parm_p, SIP_CI_UI_STATE,
+ sizeof(SIP_CI_UI_STATE) - 1)) {
+ parm_p = parm_p + sizeof(SIP_CI_UI_STATE) - 1;
+ SKIP_LWS(parm_p);
+
+ if (*parm_p) {
+ feature_data_p->call_info_feat_data.feature_flag |= CC_UI_STATE;
+ if (!cpr_strncasecmp(parm_p, SIP_CI_UI_STATE_RINGOUT,
+ sizeof(SIP_CI_UI_STATE_RINGOUT) - 1)) {
+ feature_data_p->call_info_feat_data.ui_state = CC_UI_STATE_RINGOUT;
+ } else if (!cpr_strncasecmp(parm_p, SIP_CI_UI_STATE_CONNECTED,
+ sizeof(SIP_CI_UI_STATE_CONNECTED) - 1)) {
+ feature_data_p->call_info_feat_data.ui_state = CC_UI_STATE_CONNECTED;
+ } else if (!cpr_strncasecmp(parm_p, SIP_CI_UI_STATE_BUSY,
+ sizeof(SIP_CI_UI_STATE_BUSY) - 1)) {
+ feature_data_p->call_info_feat_data.ui_state = CC_UI_STATE_BUSY;
+ } else {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX "Unknown call state"
+ " value %s\n", fname, parm_p);
+ /* Unknown value, ignore the call state */
+ feature_data_p->call_info_feat_data.feature_flag &=
+ ~(CC_UI_STATE);
+ feature_data_p->call_info_feat_data.ui_state =
+ CC_UI_STATE_NONE;
+ }
+ } else {
+ break;
+ }
+ } else if (!cpr_strncasecmp(parm_p, SIP_CI_CALL_INSTANCE,
+ sizeof(SIP_CI_CALL_INSTANCE) - 1)) {
+ parm_p = parm_p + sizeof(SIP_CI_CALL_INSTANCE) - 1;
+ SKIP_LWS(parm_p);
+
+ if (*parm_p) {
+ int idx=0;
+ char tempbuf[4];
+
+ feature_data_p->call_info_feat_data.feature_flag |= CC_CALL_INSTANCE;
+ /* Initialized the call instance id, just in case */
+ feature_data_p->call_info_feat_data.caller_id.call_instance_id
+ = 0;
+ /* Parse instance id from line */
+ temp_p = parm_p;
+ while (isdigit((int) *parm_p)&&idx<3) {
+ tempbuf[idx++] = *parm_p++;
+ }
+ tempbuf[idx] = 0;
+ if (idx == 0) {
+ /* Did not find any digit after "call_instance=" */
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX "no digits found for"
+ " call_instance parameter.\n", fname);
+ feature_data_p->call_info_feat_data.feature_flag &=
+ ~(CC_CALL_INSTANCE);
+ break;
+ } else {
+ errno = 0;
+ strtoul_result = strtoul(tempbuf, &strtoul_end, 10);
+
+ if (errno || tempbuf == strtoul_end || strtoul_result > USHRT_MAX) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX "parse error for call_instance_id: %s",
+ __FUNCTION__, tempbuf);
+ strtoul_result = 0;
+ }
+
+ feature_data_p->call_info_feat_data.caller_id.call_instance_id =
+ (uint16_t) strtoul_result;
+ }
+ } else {
+ break;
+ }
+ } else if (!cpr_strncasecmp(parm_p, SIP_CI_PRIORITY,
+ sizeof(SIP_CI_PRIORITY) - 1)) {
+ parm_p = parm_p + sizeof(SIP_CI_PRIORITY) - 1;
+ SKIP_LWS(parm_p);
+
+ if (*parm_p) {
+ temp_p = parm_p;
+ if ((!cpr_strncasecmp(parm_p, SIP_CI_PRIORITY_URGENT,
+ sizeof(SIP_CI_PRIORITY_URGENT) - 1)) ||
+ (!cpr_strncasecmp(parm_p, SIP_CI_PRIORITY_EMERGENCY,
+ sizeof(SIP_CI_PRIORITY_EMERGENCY) - 1))) {
+ feature_data_p->call_info_feat_data.priority = CC_CALL_PRIORITY_URGENT;
+ } // otherwise, it will be defaulted to normal priority
+ else {
+ errno = 0;
+ strtoul_result = strtoul(temp_p, &strtoul_end, 10);
+
+ if (errno || temp_p == strtoul_end || strtoul_result > MAX_INSTANCES) {
+ /*
+ * Call instance ID should not exceed max instances
+ * or calls.
+ */
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX "invalid call_instance"
+ " value %u\n", fname, (unsigned) strtoul_result);
+ feature_data_p->call_info_feat_data.feature_flag &=
+ ~(CC_CALL_INSTANCE);
+ } else {
+ instance_id = (uint16_t) strtoul_result;
+ feature_data_p->call_info_feat_data.caller_id.call_instance_id = instance_id;
+ }
+ }
+ }
+ } else if (!cpr_strncasecmp(parm_p, SIP_CI_GCID,
+ sizeof(SIP_CI_GCID) - 1)) {
+ parm_p = parm_p + sizeof(SIP_CI_GCID) - 1;
+ SKIP_LWS(parm_p);
+ memset(feature_data_p->call_info_feat_data.global_call_id, 0, CC_GCID_LEN);
+ if (*parm_p) {
+ temp_p = strchr(parm_p, SEMI_COLON);
+ if (temp_p) {
+ unsigned int length = ((temp_p - parm_p)call_info_feat_data.global_call_id, parm_p, length);
+ } else {
+ // No Semicolon found this could be the last parameter
+ sstrncpy(feature_data_p->call_info_feat_data.global_call_id, parm_p, CC_GCID_LEN);
+ }
+ feature_data_p->call_info_feat_data.global_call_id[CC_GCID_LEN-1] = 0;
+ }
+ } else if (!cpr_strncasecmp(parm_p, SIP_CI_DUSTINGCALL,
+ sizeof(SIP_CI_DUSTINGCALL) - 1)) {
+ parm_p = parm_p + sizeof(SIP_CI_DUSTINGCALL) - 1;
+ SKIP_LWS(parm_p);
+ feature_data_p->call_info_feat_data.dusting = TRUE;
+ }
+
+ parm_p = strchr(parm_p, SEMI_COLON);
+ }
+}
+
+/*
+ * parse_gen_parm
+ *
+ * Description:
+ *
+ * Parse feature parms where the only expected parm is the purpose.
+ */
+static void
+parse_gen_parm (char *parm_p, cc_call_info_data_t * feature_data_p)
+{
+ if (!parm_p)
+ return;
+
+ while (parm_p) {
+ parm_p++;
+ SKIP_LWS(parm_p);
+
+ if (!cpr_strncasecmp(parm_p, SIP_CI_GENERIC,
+ sizeof(SIP_CI_GENERIC) - 1)) {
+ parm_p = parm_p + sizeof(SIP_CI_GENERIC) - 1;
+ SKIP_LWS(parm_p);
+
+ if (*parm_p) {
+ if (!cpr_strncasecmp(parm_p, SIP_CI_GENERIC_ICON,
+ sizeof(SIP_CI_GENERIC_ICON) - 1)) {
+ feature_data_p->purpose = CC_PURPOSE_ICON;
+ } else {
+ if (!cpr_strncasecmp(parm_p, SIP_CI_GENERIC_INFO,
+ sizeof(SIP_CI_GENERIC_INFO) - 1)) {
+ feature_data_p->purpose = CC_PURPOSE_INFO;
+ } else {
+ if (!cpr_strncasecmp(parm_p, SIP_CI_GENERIC_CARD,
+ sizeof(SIP_CI_GENERIC_CARD) - 1)) {
+ feature_data_p->purpose = CC_PURPOSE_CARD;
+ }
+ }
+ }
+ }
+ } else {
+ break;
+ }
+ parm_p = strchr(parm_p, SEMI_COLON);
+ }
+}
+
+/*
+ * set_parm_defaults
+ *
+ * Description:
+ *
+ * A quick determination of the feature based on the string.
+ */
+static void
+set_parm_defaults (cc_call_info_t *call_info_p)
+{
+ switch (call_info_p->type) {
+ case CC_FEAT_HOLD:
+ case CC_FEAT_RESUME:
+ case CC_FEAT_NONE:
+ call_info_p->data.hold_resume_reason = CC_REASON_NONE;
+ break;
+
+ case CC_FEAT_BARGE:
+ case CC_FEAT_CBARGE:
+ call_info_p->data.purpose = CC_PURPOSE_NONE;
+ break;
+
+ case CC_FEAT_CALLINFO:
+ call_info_p->data.call_info_feat_data.policy = CC_POLICY_NONE;
+ call_info_p->data.call_info_feat_data.security = CC_SECURITY_NONE;
+ call_info_p->data.call_info_feat_data.orientation = CC_ORIENTATION_NONE;
+ call_info_p->data.call_info_feat_data.ui_state = CC_UI_STATE_NONE;
+ call_info_p->data.call_info_feat_data.priority = CC_CALL_PRIORITY_NORMAL;
+ call_info_p->data.call_info_feat_data.global_call_id[0] = 0;
+ call_info_p->data.call_info_feat_data.dusting = FALSE;
+ break;
+
+ default:
+ break;
+ }
+
+}
+
+/*
+ * ccsip_decode_call_info_hdr
+ *
+ * Description:
+ *
+ * Main method which decodes a single call info header and stores the
+ * related parms.
+ *
+ * Example Input:
+ * ---------------
+ * ; reason= conference
+ * ; seCuRity=unsecure; orienTation= to
+ */
+static void
+ccsip_decode_call_info_hdr (const char *call_info_hdr_p,
+ cc_call_info_t *call_info_p)
+{
+ char *ptr = NULL;
+ char *laq_ptr = NULL;
+ char *raq_ptr = NULL;
+ boolean ret_val = FALSE;
+ char feat_string[FEAT_STRING_SIZE];
+
+ memset(feat_string, '\0', sizeof(feat_string));
+
+ /*
+ * call_info_hdr_p and call_info_p are verified by caller so they
+ * are not checked here.
+ */
+
+ ptr = laq_ptr = strchr(call_info_hdr_p, LAQUOT);
+ raq_ptr = strchr(call_info_hdr_p, RAQUOT);
+
+ // Parse out the remotecc string and the feature string.
+ if (laq_ptr && raq_ptr) {
+ ptr++;
+
+ // Verify the remotecc string.
+ if (!cpr_strncasecmp(ptr, URN_REMOTECC, sizeof(URN_REMOTECC) - 1)) {
+ ptr += sizeof(URN_REMOTECC) - 1;
+ sstrncpy(feat_string, ptr, raq_ptr - ptr + 1);
+
+ // Which feature do we have in this header?
+ call_info_p->type = which_feature(feat_string);
+
+ if (call_info_p->type != CC_FEAT_NONE) {
+ ret_val = TRUE;
+ set_parm_defaults(call_info_p);
+ }
+ }
+ }
+
+ if (!ret_val) {
+ return;
+ }
+
+ if (!(ptr = strchr(raq_ptr, SEMI_COLON))) {
+ return;
+ }
+
+ switch (call_info_p->type) {
+ case CC_FEAT_CALLINFO:
+ parse_call_info_parm(ptr, &call_info_p->data);
+ break;
+ default:
+ parse_gen_parm(ptr, &call_info_p->data);
+ }
+}
+
+/*
+ * ccsip_encode_call_info_hdr
+ *
+ * Description:
+ *
+ * Encode the call info header using the passed in feature id and
+ * feature specific data.
+ *
+ * The miscParms parameter will usually be null. It exists in case
+ * you want to toss in an additional string parm without using the
+ * encoding mechanism. An example would be "extraParm= text".
+ *
+ * Remember to delete the store in the return parm. It is the
+ * caller's responsibility.
+ */
+char *
+ccsip_encode_call_info_hdr (cc_call_info_t *call_info_p,
+ const char *misc_parms_p)
+{
+ static const char *fname = "ccsip_encode_call_info_hdr";
+ char *header;
+
+ header = (char *) cpr_malloc(MAX_SIP_HEADER_LENGTH);
+ if (!header) {
+ return NULL;
+ }
+
+ if (!call_info_p) {
+ cpr_free(header);
+ return NULL;
+ }
+
+ snprintf(header, MAX_SIP_HEADER_LENGTH, "<%s", URN_REMOTECC);
+
+ switch (call_info_p->type) {
+ case CC_FEAT_HOLD:
+ case CC_FEAT_RESUME:
+ if (call_info_p->type == CC_FEAT_HOLD) {
+ sstrncat(header, SIP_CI_HOLD_STR,
+ MAX_SIP_HEADER_LENGTH - strlen(header));
+ } else {
+ sstrncat(header, SIP_CI_RESUME_STR,
+ MAX_SIP_HEADER_LENGTH - strlen(header));
+ }
+ sstrncat(header, ">", MAX_SIP_HEADER_LENGTH - strlen(header));
+
+ switch (call_info_p->data.hold_resume_reason) {
+ case CC_REASON_NONE:
+ case CC_REASON_INTERNAL:
+ case CC_REASON_SWAP:
+ break;
+ case CC_REASON_XFER:
+ sstrncat(header, "; reason= ",
+ MAX_SIP_HEADER_LENGTH - strlen(header));
+ sstrncat(header, SIP_CI_HOLD_REASON_XFER,
+ MAX_SIP_HEADER_LENGTH - strlen(header));
+ break;
+ case CC_REASON_CONF:
+ sstrncat(header, "; reason= ",
+ MAX_SIP_HEADER_LENGTH - strlen(header));
+ sstrncat(header, SIP_CI_HOLD_REASON_CONF,
+ MAX_SIP_HEADER_LENGTH - strlen(header));
+ break;
+ default:
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX "unsupported hold_resume_reason\n",
+ fname);
+ cpr_free(header);
+ return NULL;
+ }
+
+ /* Add swap information */
+ if (call_info_p->data.call_info_feat_data.swap == TRUE) {
+ sstrncat(header, "; operation= swap",
+ MAX_SIP_HEADER_LENGTH - strlen(header));
+ }
+
+ if (call_info_p->data.call_info_feat_data.protect == TRUE) {
+ sstrncat(header, "; protect= true; noholdreversion",
+ MAX_SIP_HEADER_LENGTH - strlen(header));
+ }
+
+ break;
+
+ case CC_FEAT_INIT_CALL:
+ /* Add global call id here */
+ if (call_info_p->data.initcall.gcid[0] != '\0') {
+ sstrncat(header, "callinfo>; gci= ",
+ MAX_SIP_HEADER_LENGTH - strlen(header));
+ sstrncat(header, call_info_p->data.initcall.gcid,
+ MAX_SIP_HEADER_LENGTH - strlen(header));
+ } else {
+ cpr_free(header);
+ return NULL;
+ }
+ /* Add the monitor mode here if it exists */
+ if (call_info_p->data.initcall.monitor_mode != CC_MONITOR_NONE) {
+ sstrncat(header, "; mode=",
+ MAX_SIP_HEADER_LENGTH - strlen(header));
+
+ switch (call_info_p->data.initcall.monitor_mode) {
+
+ case CC_MONITOR_SILENT :
+ sstrncat(header, SIP_CI_SILENT_STR,
+ MAX_SIP_HEADER_LENGTH - strlen(header));
+ break;
+
+ case CC_MONITOR_COACHING :
+ sstrncat(header, SIP_CI_COACHING_STR,
+ MAX_SIP_HEADER_LENGTH - strlen(header));
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+
+ case CC_FEAT_TOGGLE_TO_WHISPER_COACHING:
+ sstrncat(header, "callinfo>",
+ MAX_SIP_HEADER_LENGTH - strlen(header));
+ sstrncat(header, "; mode=",
+ MAX_SIP_HEADER_LENGTH - strlen(header));
+ sstrncat(header, SIP_CI_COACHING_STR,
+ MAX_SIP_HEADER_LENGTH - strlen(header));
+
+ break;
+
+ case CC_FEAT_TOGGLE_TO_SILENT_MONITORING:
+ sstrncat(header, "callinfo>",
+ MAX_SIP_HEADER_LENGTH - strlen(header));
+ sstrncat(header, "; mode=",
+ MAX_SIP_HEADER_LENGTH - strlen(header));
+ sstrncat(header, SIP_CI_SILENT_STR,
+ MAX_SIP_HEADER_LENGTH - strlen(header));
+
+ break;
+
+ default:
+ cpr_free(header);
+ return NULL;
+ }
+
+
+ if (misc_parms_p) {
+ sstrncat(header, misc_parms_p,
+ MAX_SIP_HEADER_LENGTH - strlen(header));
+ }
+ sstrncat(header, "\0", MAX_SIP_HEADER_LENGTH - strlen(header));
+ return (header);
+}
+
+/*
+ * ccsip_free_call_info_header
+ *
+ * Description:
+ *
+ * Frees the memory allocated to a call info structure.
+ */
+void
+ccsip_free_call_info_header (cc_call_info_t *call_info_p)
+{
+ if(call_info_p->type == CC_FEAT_CALLINFO) {
+
+ }
+ cpr_free(call_info_p);
+}
+
+/*
+ * ccsip_process_call_info_header
+ *
+ * Description:
+ *
+ * Checks if there is a call info header in the provided SIP message. If there is,
+ * the call info in the CCB is cleared and the new call info is parsed into the
+ * CCB call info structure.
+ */
+void
+ccsip_process_call_info_header (sipMessage_t *request_p, ccsipCCB_t *ccb)
+{
+ char *call_info_hdrs[MAX_CALL_INFO_HEADERS];
+ uint16_t num_call_info_headers;
+ int i = 0;
+
+ if (!ccb) {
+ return;
+ }
+
+ if (ccb->in_call_info) {
+ ccsip_free_call_info_header(ccb->in_call_info);
+ ccb->in_call_info = NULL;
+ }
+
+ if (!request_p) {
+ return;
+ }
+
+ memset(call_info_hdrs, 0, MAX_CALL_INFO_HEADERS * sizeof(char *));
+
+ num_call_info_headers = sippmh_get_num_particular_headers(request_p,
+ SIP_HEADER_CALL_INFO,
+ SIP_HEADER_CALL_INFO,
+ call_info_hdrs,
+ MAX_CALL_INFO_HEADERS);
+
+ if (num_call_info_headers > 0) {
+ ccb->in_call_info = (cc_call_info_t *)
+ cpr_calloc(1, sizeof(cc_call_info_t));
+ if (ccb->in_call_info) {
+
+ ccb->in_call_info->data.call_info_feat_data.feature_flag = 0;
+
+ // Parse each Call-Info header
+ for (i = 0; i < MAX_CALL_INFO_HEADERS; i++) {
+ if (call_info_hdrs[i]) {
+ ccsip_decode_call_info_hdr(call_info_hdrs[i], ccb->in_call_info);
+ }
+ }
+
+ } else {
+ ccb->in_call_info = NULL;
+ }
+ }
+
+}
+
+/*
+ * ccsip_store_call_info
+ *
+ * Description: Used for storing call_info received from GSM
+ *
+ * Store specified call info structure in ccb.
+ */
+void
+ccsip_store_call_info (cc_call_info_t *call_info_p, ccsipCCB_t *ccb)
+{
+ if (!ccb) {
+ return;
+ }
+
+ if (ccb->out_call_info) {
+ ccsip_free_call_info_header(ccb->out_call_info);
+ ccb->out_call_info = NULL;
+ }
+
+ if (call_info_p->type != CC_FEAT_NONE) {
+ ccb->out_call_info = (cc_call_info_t *)
+ cpr_malloc(sizeof(cc_call_info_t));
+ if (ccb->out_call_info) {
+ memcpy(ccb->out_call_info, call_info_p, sizeof(cc_call_info_t));
+ } else {
+ ccb->out_call_info = NULL;
+ }
+ }
+}
diff --git a/libs/sipcc/core/sipstack/ccsip_cc.c b/libs/sipcc/core/sipstack/ccsip_cc.c
new file mode 100755
index 0000000000..0a97efcc8b
--- /dev/null
+++ b/libs/sipcc/core/sipstack/ccsip_cc.c
@@ -0,0 +1,305 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "cpr_types.h"
+#include "ccapi.h"
+#include "string_lib.h"
+#include "ccsip_pmh.h"
+#include "ccsip_messaging.h"
+
+/*
+ * Function: sip_cc_mv_msg_body_to_cc_msg
+ *
+ * Parameters: cc_msg - pointer to cc_msgbody_info structure to
+ * move the content from the SIP body msg. to.
+ * sip_msg - pointer to sipMessage_t structure of the source
+ * body.
+ *
+ * Description: This routine moves the body parts from sipMessage_t to
+ * CCAPI body msg. Once the content is moved,
+ * the all pointers from the sipMessage_t structure,
+ * will be NULL so that they are not own by SIP stack.
+ * The destination of the msg. needs to free the
+ * memory for of the parts.
+ *
+ * Returns: N/A
+ *
+ */
+void sip_cc_mv_msg_body_to_cc_msg (cc_msgbody_info_t *cc_msg,
+ sipMessage_t *sip_msg)
+{
+ int i;
+ uint32_t num_parts = 0;
+ cc_msgbody_t *part;
+
+ if (cc_msg == NULL) {
+ /* destination to move msg. to */
+ return;
+ }
+ if (sip_msg == NULL) {
+ /* No SIP message to move from, set number of part to zero */
+ cc_msg->num_parts = 0;
+ return;
+ }
+
+ part = &cc_msg->parts[0];
+ for (i = 0; (i < sip_msg->num_body_parts) &&
+ (i < CC_MAX_BODY_PARTS); i++) {
+ if ((sip_msg->mesg_body[i].msgBody != NULL) &&
+ (sip_msg->mesg_body[i].msgLength)) {
+ /* Body */
+ part->body = sip_msg->mesg_body[i].msgBody;
+ part->body_length = sip_msg->mesg_body[i].msgLength;
+ sip_msg->mesg_body[i].msgBody = NULL;
+
+ /* Content type */
+ part->content_type =
+ sip2cctype(sip_msg->mesg_body[i].msgContentTypeValue);
+ /* Disposition */
+ part->content_disposition.disposition =
+ sip2ccdisp(sip_msg->mesg_body[i].msgContentDisp);
+ part->content_disposition.required_handling =
+ sip_msg->mesg_body[i].msgRequiredHandling;
+ /* Content ID */
+ part->content_id = sip_msg->mesg_body[i].msgContentId;
+ sip_msg->mesg_body[i].msgContentId = NULL;
+
+ /* Next part */
+ part++;
+ num_parts++;
+ }
+ }
+ /* Set the number of parts */
+ cc_msg->num_parts = num_parts;
+}
+
+/*
+ * Function: sip_cc_create_cc_msg_body_from_sip_msg
+ *
+ * Parameters: cc_msg - pointer to cc_msgbody_info structure to
+ * store the content of the SIP body msg.
+ * sip_msg - pointer to sipMessage_t structure of the source
+ * body.
+ *
+ * Description: This routine creates the cc_msgbody_info_t content
+ * from the SIP message. The original msg. body in the
+ * SIP message remains in the SIP message.
+ *
+ * Returns: TRUE - success
+ * FALSE - fail.
+ *
+ */
+boolean sip_cc_create_cc_msg_body_from_sip_msg (cc_msgbody_info_t *cc_msg,
+ sipMessage_t *sip_msg)
+{
+ int i, len;
+ uint32_t num_parts = 0;
+ cc_msgbody_t *part;
+ boolean status = TRUE;
+
+ if (cc_msg == NULL) {
+ /* destination to move msg. to */
+ return (FALSE);
+ }
+
+ if (sip_msg == NULL) {
+ /* No SIP message to move from, set number of part to zero */
+ cc_msg->num_parts = 0;
+ return (FALSE);
+ }
+
+ memset(cc_msg, 0, sizeof(cc_msgbody_info_t));
+ part = &cc_msg->parts[0];
+ for (i = 0; (i < sip_msg->num_body_parts) &&
+ (i < CC_MAX_BODY_PARTS) ; i++) {
+ if ((sip_msg->mesg_body[i].msgBody != NULL) &&
+ (sip_msg->mesg_body[i].msgLength)) {
+ /* Body */
+ part->body = (char *) cpr_malloc(sip_msg->mesg_body[i].msgLength);
+ if (part->body != NULL) {
+ part->body_length = sip_msg->mesg_body[i].msgLength;
+ memcpy(part->body,
+ sip_msg->mesg_body[i].msgBody,
+ sip_msg->mesg_body[i].msgLength);
+ } else {
+ /* Unable to allocate memory for msg. body */
+ status = FALSE;
+ break;
+ }
+
+ /* Content type */
+ part->content_type =
+ sip2cctype(sip_msg->mesg_body[i].msgContentTypeValue);
+ /* Disposition */
+ part->content_disposition.disposition =
+ sip2ccdisp(sip_msg->mesg_body[i].msgContentDisp);
+ part->content_disposition.required_handling =
+ sip_msg->mesg_body[i].msgRequiredHandling;
+
+ /* Content ID */
+ if (sip_msg->mesg_body[i].msgContentId != NULL) {
+ /* Get length of the msgContentID with NULL */
+ len = strlen(sip_msg->mesg_body[i].msgContentId) + 1;
+ part->content_id = (char *) cpr_malloc(len);
+ if (part->content_id != NULL) {
+ memcpy(part->content_id,
+ sip_msg->mesg_body[i].msgContentId,
+ len);
+ } else {
+ /* Unable to allocate allocate memory for content ID */
+ status = FALSE;
+ break;
+ }
+ } else {
+ /* No content ID */
+ part->content_id = NULL;
+ }
+ /* Next part */
+ part++;
+ num_parts++;
+ }
+ }
+ /* Set the number of parts */
+ cc_msg->num_parts = num_parts;
+
+ if (!status) {
+ /*
+ * Faied for some reason, free the resources that mighe be
+ * created before failure
+ */
+ cc_free_msg_body_parts(cc_msg);
+ }
+ return (status);
+}
+
+void sip_cc_setup (callid_t call_id, line_t line,
+ string_t calling_name, string_t calling_number, string_t alt_calling_number,
+ boolean display_calling_number,
+ string_t called_name, string_t called_number,
+ boolean display_called_number,
+ string_t orig_called_name, string_t orig_called_number,
+ string_t last_redirect_name, string_t last_redirect_number,
+ cc_call_type_e call_type,
+ cc_alerting_type alert_info,
+ vcm_ring_mode_t alerting_ring,
+ vcm_tones_t alerting_tone, cc_call_info_t *call_info_p,
+ boolean replaces, string_t recv_info_list, sipMessage_t *sip_msg)
+{
+ cc_caller_id_t caller_id;
+ cc_msgbody_info_t cc_body_info;
+
+ caller_id.calling_name = calling_name;
+ caller_id.calling_number = calling_number;
+ caller_id.alt_calling_number = alt_calling_number;
+ caller_id.display_calling_number = display_calling_number;
+ caller_id.called_name = called_name;
+ caller_id.called_number = called_number;
+ caller_id.display_called_number = display_called_number;
+ caller_id.last_redirect_name = last_redirect_name;
+ caller_id.last_redirect_number = last_redirect_number;
+ caller_id.orig_called_name = orig_called_name;
+ caller_id.orig_called_number = orig_called_number;
+ caller_id.orig_rpid_number = strlib_empty();
+ caller_id.call_type = call_type;
+
+ /* Move the SIP body parts to the CCAPI msg. body information block */
+ sip_cc_mv_msg_body_to_cc_msg(&cc_body_info, sip_msg);
+
+// Check with CraigB
+ cc_setup(CC_SRC_SIP, call_id, line, &caller_id, alert_info,
+ alerting_ring, alerting_tone, NULL, call_info_p, replaces,
+ recv_info_list, &cc_body_info);
+}
+
+
+#ifdef REMOVED_UNUSED_FUNCTION
+void sip_cc_setup_ack (callid_t call_id, line_t line,
+ cc_msgbody_info_t *msg_body)
+{
+ cc_setup_ack(CC_SRC_SIP, call_id, line, NULL, msg_body);
+}
+#endif
+
+void sip_cc_proceeding (callid_t call_id, line_t line)
+{
+ cc_proceeding(CC_SRC_SIP, call_id, line, NULL);
+}
+
+void sip_cc_alerting (callid_t call_id, line_t line,
+ sipMessage_t *sip_msg, int inband)
+{
+ cc_msgbody_info_t cc_body_info;
+
+ /* Move the SIP body parts to the CCAPI msg. body information block */
+ sip_cc_mv_msg_body_to_cc_msg(&cc_body_info, sip_msg);
+
+ cc_alerting(CC_SRC_SIP, call_id, line, NULL, &cc_body_info,
+ (boolean)inband);
+}
+
+
+void sip_cc_connected (callid_t call_id, line_t line, string_t recv_info_list, sipMessage_t *sip_msg)
+{
+ cc_msgbody_info_t cc_body_info;
+
+ /* Move the SIP body parts to the CCAPI msg. body information block */
+ sip_cc_mv_msg_body_to_cc_msg(&cc_body_info, sip_msg);
+
+ cc_connected(CC_SRC_SIP, call_id, line, NULL, recv_info_list, &cc_body_info);
+}
+
+
+void sip_cc_connected_ack (callid_t call_id, line_t line,
+ sipMessage_t *sip_msg)
+{
+ cc_msgbody_info_t cc_body_info;
+
+ /* Move the SIP body parts to the CCAPI msg. body information block */
+ sip_cc_mv_msg_body_to_cc_msg(&cc_body_info, sip_msg);
+
+ cc_connected_ack(CC_SRC_SIP, call_id, line, NULL, &cc_body_info);
+}
+
+
+void sip_cc_release (callid_t call_id, line_t line, cc_causes_t cause,
+ const char *dialstring)
+{
+ cc_release(CC_SRC_SIP, call_id, line, cause, dialstring, NULL);
+}
+
+
+void sip_cc_release_complete (callid_t call_id, line_t line, cc_causes_t cause)
+{
+ cc_release_complete(CC_SRC_SIP, call_id, line, cause, NULL);
+}
+
+
+void sip_cc_feature (callid_t call_id, line_t line, cc_features_t feature, void *data)
+{
+ cc_feature(CC_SRC_SIP, call_id, line, feature, (cc_feature_data_t *)data);
+}
+
+
+void sip_cc_feature_ack (callid_t call_id, line_t line, cc_features_t feature,
+ void *data, cc_causes_t cause)
+{
+ cc_feature_ack(CC_SRC_SIP, call_id, line, feature, (cc_feature_data_t *)data, cause);
+}
+
+
+void sip_cc_mwi (callid_t call_id, line_t line, boolean on, int type,
+ int newCount, int oldCount, int hpNewCount, int hpOldCount)
+{
+ cc_mwi(CC_SRC_SIP, call_id, line, on, type, newCount, oldCount, hpNewCount, hpOldCount);
+}
+
+void sip_cc_options (callid_t call_id, line_t line, sipMessage_t *pSipMessage)
+{
+ cc_options_sdp_req(CC_SRC_SIP, call_id, line, pSipMessage);
+}
+
+void sip_cc_audit (callid_t call_id, line_t line, boolean apply_ringout)
+{
+ cc_audit_sdp_req(CC_SRC_SIP, call_id, line, apply_ringout);
+}
diff --git a/libs/sipcc/core/sipstack/ccsip_common_util.c b/libs/sipcc/core/sipstack/ccsip_common_util.c
new file mode 100644
index 0000000000..170bd98e4d
--- /dev/null
+++ b/libs/sipcc/core/sipstack/ccsip_common_util.c
@@ -0,0 +1,260 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "cpr_in.h"
+#include "ccsip_common_cb.h"
+#include "sip_common_transport.h"
+#include "prot_configmgr.h"
+#include "ccsip_register.h"
+#include "util_string.h"
+
+/**
+ * This function will set dest ip and port in common control block of SCB and PCB.
+ *
+ * @param[in] cb_p - pointer to the header control block.
+ *
+ * @return none
+ *
+ * @pre (cb_p != NULL)
+ */
+void ccsip_common_util_set_dest_ipaddr_port (ccsip_common_cb_t *cb_p)
+{
+ char addr[MAX_IPADDR_STR_LEN];
+
+ if (cb_p->dest_sip_addr.type == CPR_IP_ADDR_INVALID) {
+ sipTransportGetPrimServerAddress(cb_p->dn_line, addr);
+ dns_error_code = sipTransportGetServerAddrPort(addr,
+ &cb_p->dest_sip_addr,
+ (uint16_t *)&cb_p->dest_sip_port,
+ &cb_p->SRVhandle,
+ FALSE);
+ if (dns_error_code == 0) {
+ util_ntohl(&(cb_p->dest_sip_addr), &(cb_p->dest_sip_addr));
+ } else {
+ sipTransportGetServerIPAddr(&(cb_p->dest_sip_addr), cb_p->dn_line);
+ }
+
+ cb_p->dest_sip_port = ((dns_error_code == 0) && (cb_p->dest_sip_port)) ?
+ ntohs((uint16_t)cb_p->dest_sip_port) :
+ (sipTransportGetPrimServerPort(cb_p->dn_line));
+ }
+}
+
+/**
+ * This function will set source ip in common control block of SCB and PCB.
+ *
+ * @param[in] cb_p - pointer to the header control block.
+ *
+ * @return none
+ *
+ * @pre (cb_p != NULL)
+ */
+void ccsip_common_util_set_src_ipaddr (ccsip_common_cb_t *cb_p)
+{
+ int nat_enable = 0;
+
+ config_get_value(CFGID_NAT_ENABLE, &nat_enable, sizeof(nat_enable));
+ if (nat_enable == 0) {
+ sip_config_get_net_device_ipaddr(&(cb_p->src_addr));
+ } else {
+ sip_config_get_nat_ipaddr(&(cb_p->src_addr));
+ }
+}
+
+/*
+ * This function will set retry settings in common control block of SCB and PCB.
+ *
+ * Description: Based on transport used, determines the value to be
+ * used to set either TimerE or TimerF
+ * 1. For reliable tranport: we SHOULD start timer F (= 64*T1),
+ * no retransmits are required.
+ * 2. To prevent retransmits for TCP/TLS, we set scbp->retx_counter
+ * to Max value.
+ * 3. For unreliable tranport: we SHOULD start timer E (= T1),
+ * retransmits are required.
+ * This routine must only be invoked before sending a request for
+ * the first time with valid args.
+ *
+ * @param[in] cb_p - pointer to header control block.
+ * @param[out] timeout_p - returns the value to be used to set a timer.
+ *
+ * @return none
+ *
+ * @pre (cb_p != NULL) and (timeout_p != NULL)
+ */
+void ccsip_common_util_set_retry_settings (ccsip_common_cb_t *cb_p, int *timeout_p)
+{
+ uint32_t max_retx = 0;
+ const char *transport = NULL;
+
+ *timeout_p = 0;
+ cb_p->retx_flag = TRUE;
+ config_get_value(CFGID_TIMER_T1, timeout_p, sizeof(*timeout_p));
+
+ transport = sipTransportGetTransportType(cb_p->dn_line, TRUE, NULL);
+ if (transport) {
+ if (strcmp(transport, "UDP") == 0) {
+ cb_p->retx_counter = 0;
+ } else {
+ config_get_value(CFGID_SIP_RETX, &max_retx, sizeof(max_retx));
+ if (max_retx > MAX_NON_INVITE_RETRY_ATTEMPTS) {
+ max_retx = MAX_NON_INVITE_RETRY_ATTEMPTS;
+ }
+ cb_p->retx_counter = max_retx;
+ (*timeout_p) = (64 * (*timeout_p));
+ }
+ }
+}
+
+
+/**
+ * This function will generate authorization header value.
+ *
+ * @param[in] pSipMessage - pointer to sipMessage_t
+ * @param[in] cb_p - pointer to header control block.
+ * @param[in] rsp_method - response method
+ * @param[in] response_code - response code
+ * @param[in] uri - uri
+ *
+ * @return TRUE if it is successful.
+ *
+ * @pre (cb_p != NULL) and (pSipMessage != NULL) and (rsp_method != NULL) and (uri != NULL)
+ */
+boolean ccsip_common_util_generate_auth (sipMessage_t *pSipMessage, ccsip_common_cb_t *cb_p,
+ const char *rsp_method, int response_code, char *uri)
+{
+ static const char fname[] = "ccsip_common_util_generate_auth";
+ const char *authenticate = NULL;
+ credentials_t credentials;
+ sip_authen_t *sip_authen = NULL;
+ char *author_str = NULL;
+
+ if (!(cb_p->authen.cred_type & CRED_LINE)) {
+ cb_p->authen.cred_type |= CRED_LINE;
+ } else {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX
+ "configured credentials for line %d not accepeted. Verify the config\n",
+ fname, cb_p->dn_line);
+ return FALSE;
+ }
+
+ /*
+ * get authname & password from configuration.
+ */
+ cred_get_line_credentials(cb_p->dn_line, &credentials,
+ sizeof(credentials.id),
+ sizeof(credentials.pw));
+ /*
+ * Extract Authenticate/Proxy-Authenticate header from the message.
+ */
+ authenticate = sippmh_get_header_val(pSipMessage, AUTH_HDR(response_code), NULL);
+ if (authenticate == NULL) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"%s header missing in the %d response\n",
+ fname, AUTH_HDR_STR(response_code), response_code);
+ return FALSE;
+ }
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Authenticate header %s = %s\n", DEB_F_PREFIX_ARGS(SIP_AUTH, fname), AUTH_HDR_STR(response_code), authenticate);
+ /*
+ * Parse Authenticate header.
+ */
+ sip_authen = sippmh_parse_authenticate(authenticate);
+ if (sip_authen == NULL) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"%s:%s header formatted incorrectly in the %d response\n",
+ fname, AUTH_HDR_STR(response_code), authenticate, response_code);
+ return FALSE;
+ }
+ cb_p->authen.new_flag = FALSE;
+ cb_p->authen.cnonce[0] = '\0';
+ /*
+ * Generate Authorization string.
+ */
+ if (sipSPIGenerateAuthorizationResponse(sip_authen,
+ uri,
+ rsp_method,
+ credentials.id,
+ credentials.pw,
+ &author_str,
+ &(cb_p->authen.nc_count),
+ NULL) == TRUE) {
+
+ if (cb_p->authen.authorization != NULL) {
+ cpr_free(cb_p->authen.authorization);
+ cb_p->authen.authorization = NULL;
+ }
+
+ if (cb_p->authen.sip_authen != NULL) {
+ sippmh_free_authen(cb_p->authen.sip_authen);
+ cb_p->authen.sip_authen = NULL;
+ }
+
+ cb_p->authen.authorization = (char *)
+ cpr_malloc(strlen(author_str) * sizeof(char) + 1);
+
+ /*
+ * Cache the Authorization header so that it can be
+ * used for later requests
+ */
+ if (cb_p->authen.authorization != NULL) {
+ memcpy(cb_p->authen.authorization, author_str,
+ strlen(author_str) * sizeof(char) + 1);
+ cb_p->authen.status_code = response_code;
+ cb_p->authen.sip_authen = sip_authen;
+ }
+
+ cpr_free(author_str);
+ } else {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Authorization header build unsuccessful\n", fname);
+ sippmh_free_authen(sip_authen);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ * This function will extract user part from sip From header.
+ *
+ * @param[in] pSipMessage - pointer to sipMessage_t
+ * @param[out] entity - pointer to user buffer.
+ *
+ * @return void
+ *
+ * @pre (pSipMessage != NULL) and (entity != NULL)
+ */
+void ccsip_util_get_from_entity (sipMessage_t *pSipMessage, char *entity)
+{
+ const char *sip_from = NULL;
+ sipLocation_t *from_loc = NULL;
+
+ sip_from = sippmh_get_cached_header_val(pSipMessage, FROM);
+ if (sip_from != NULL) {
+ from_loc = sippmh_parse_from_or_to((char *) sip_from, TRUE);
+ if ((from_loc) && (from_loc->genUrl->schema == URL_TYPE_SIP) && (from_loc->genUrl->u.sipUrl->user)) {
+ sstrncpy(entity, from_loc->genUrl->u.sipUrl->user, CC_MAX_DIALSTRING_LEN);
+ }
+ }
+ if (from_loc) {
+ sippmh_free_location(from_loc);
+ }
+}
+
+/**
+ * This function will extract user part from sip URL.
+ *
+ * @param[in] url - pointer to URL
+ * @param[out] user - pointer to user buffer.
+ *
+ * @return void
+ *
+ * @pre (url != NULL) and (user != NULL)
+ */
+void ccsip_util_extract_user (char *url, char *user)
+{
+ genUrl_t *genUrl = NULL;
+
+ genUrl = sippmh_parse_url(url, TRUE);
+ if (genUrl != NULL) {
+ sstrncpy(user, genUrl->u.sipUrl->user, CC_MAX_DIALSTRING_LEN);
+ sippmh_genurl_free(genUrl);
+ }
+}
diff --git a/libs/sipcc/core/sipstack/ccsip_core.c b/libs/sipcc/core/sipstack/ccsip_core.c
new file mode 100644
index 0000000000..e0807b30f0
--- /dev/null
+++ b/libs/sipcc/core/sipstack/ccsip_core.c
@@ -0,0 +1,12298 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "cpr_types.h"
+#include "cpr_stdlib.h"
+#include "cpr_string.h"
+#include "cpr_in.h"
+#include "cpr_rand.h"
+
+#include "ccsip_core.h"
+#include "text_strings.h"
+#include "util_string.h"
+#include "ccsip_messaging.h"
+#include "ccsip_platform_udp.h"
+#include "ccsip_platform.h"
+#include "ccsip_macros.h"
+#include "ccsip_pmh.h"
+#include "ccsip_spi_utils.h"
+#include "phone_debug.h"
+#include "ccsip_register.h"
+#include "ccsip_credentials.h"
+#include "ccsip_callinfo.h"
+#include "ccsip_cc.h"
+#include "ccsip_task.h"
+#include "config.h"
+#include "string_lib.h"
+#include "dialplan.h"
+#include "fsm.h"
+#include "sip_interface_regmgr.h"
+#include "ccsip_subsmanager.h"
+#include "ccsip_publish.h"
+#include "sdp.h"
+#include "sip_common_transport.h"
+#include "sip_common_regmgr.h"
+#include "rtp_defs.h"
+#include "uiapi.h"
+#include "text_strings.h"
+#include "platform_api.h"
+#include "misc_util.h"
+
+
+/*
+ * OS specific hooks
+ */
+
+extern void sip_platform_handle_service_control_notify(sipServiceControl_t *scp);
+extern uint32_t IPNameCk(char *name, char *addr_error);
+
+
+#define ADD_TO_ARP_CACHE(dest_sip_addr)
+#define UNBIND_UDP_ICMP_HANDLER(udp_id)
+
+
+extern boolean sip_mode_quiet;
+
+extern void ccsip_debug_init(void);
+extern void shutdownCCAck(int action);
+void ccsip_remove_wlan_classifiers(void);
+
+#define USECALLMANAGER_LEN 14
+/*
+ * Needed to parse the alert-info header
+ */
+//CPR TODO: need reference for
+extern const char *tone_names[];
+const char *ring_names[] = {
+ "Bellcore-dr1",
+ "Bellcore-dr2",
+ "Bellcore-dr3",
+ "Bellcore-dr4",
+ "Bellcore-dr5"
+};
+
+
+/* Forward function declarations */
+static int sip_sm_request_check_and_store(ccsipCCB_t *ccb, sipMessage_t *request,
+ sipMethod_t request_method,
+ boolean midcall,
+ uint16_t *request_check_reason_code,
+ char *request_check_reason_phrase,
+ boolean store_invite);
+void sip_sm_update_to_from_on_callsetup_finalresponse(ccsipCCB_t *ccb,
+ sipMessage_t *response);
+void sip_sm_update_contact_recordroute(ccsipCCB_t *ccb, sipMessage_t *response,
+ int response_code, boolean midcall);
+static boolean ccsip_set_replace_info(ccsipCCB_t *ccb, cc_setup_t * setup);
+static boolean ccsip_handle_cc_select_event(sipSMEvent_t *sip_sm_event);
+static boolean ccsip_handle_cc_b2bjoin_event(sipSMEvent_t *sip_sm_event);
+static void ccsip_set_join_info(ccsipCCB_t *ccb, cc_setup_t * setup);
+static boolean ccsip_get_join_info(ccsipCCB_t *ccb, sipMessage_t *request);
+static char *ccsip_find_preallocated_sip_call_id(line_t dn_line);
+static void ccsip_free_preallocated_sip_call_id(line_t dn_line);
+static boolean ccsip_handle_cc_hook_event(sipSMEvent_t *sip_sm_event);
+
+extern cc_int32_t dnsGetHostByName (const char *hname, cpr_ip_addr_t *ipaddr_ptr, cc_int32_t timeout, cc_int32_t retries);
+
+//CPR TODO: need reference for
+extern char *Basic_is_phone_forwarded(line_t line);
+
+/* External Declarations */
+extern sipPlatformUITimer_t sipPlatformUISMTimers[];
+extern sipGlobal_t sip;
+extern sipCallHistory_t gCallHistory[];
+
+/* Globals */
+int dns_error_code; // Global DNS error code value
+uint16_t server_caps = 0; // Server capabilities
+boolean sip_reg_all_failed;
+
+ccsipGlobInfo_t gGlobInfo;
+sipCallHistory_t gCallHistory[MAX_TEL_LINES];
+
+typedef struct {
+ int16_t sipValidEvent;
+ int16_t actionIndex;
+} subStateEvent_t;
+
+#define MAX_STATE_EVENTS 13
+typedef struct {
+ int16_t sipState;
+ subStateEvent_t validEvent[MAX_STATE_EVENTS];
+} sipSMfunctable_t;
+
+static char *preAllocatedSipCallID[MAX_REG_LINES] = { NULL };
+static char *preAllocatedTag[MAX_REG_LINES] = { NULL };
+boolean g_disable_mass_reg_debug_print = FALSE;
+
+static const sipSMfunctable_t g_sip_table[SIP_STATE_END - SIP_STATE_BASE + 1] =
+{
+ /*
+ * SIP_STATE_IDLE
+ */
+ { SIP_STATE_IDLE,
+ {
+ /* E_SIP_INVITE ccsip_handle_idle_ev_sip_invite, */
+ {E_SIP_INVITE, H_IDLE_EV_SIP_INVITE},
+ /* E_CC_SETUP ccsip_handle_idle_ev_cc_setup, */
+ {E_CC_SETUP, H_IDLE_EV_CC_SETUP},
+ /* E_SIP_NOTIFY ccsip_handle_unsolicited_notify */
+ {E_SIP_NOTIFY, H_EV_SIP_UNSOLICITED_NOTIFY},
+ /* E_CC_FEATURE ccsip_handle_default_ev_cc_feature */
+ {E_CC_FEATURE, H_DEFAULT_EV_CC_FEATURE},
+
+ /* Initializing any events which are not used to Invalid events */
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT}
+ }
+ },
+ /*
+ * SIP_STATE_SENT_INVITE
+ */
+ {SIP_STATE_SENT_INVITE,
+ {
+ /* E_SIP_1xx ccsip_handle_sentinvite_ev_sip_1xx, */
+ {E_SIP_1xx, H_SENTINVITE_EV_SIP_1XX},
+ /* E_SIP_2xx ccsip_handle_sentinvite_ev_sip_2xx, */
+ {E_SIP_2xx, H_SENTINVITE_EV_SIP_2XX},
+ /* E_SIP_3xx ccsip_handle_sentinvite_ev_sip_3xx */
+ {E_SIP_3xx, H_SENTINVITE_EV_SIP_3XX},
+ /* E_SIP_FAILURE_RESPONSE ccsip_handle_sentinvite_ev_sip_fxx, */
+ {E_SIP_FAILURE_RESPONSE, H_SENTINVITE_EV_SIP_FXX},
+ /* E_CC_RELEASE ccsip_handle_disconnect_local_early */
+ {E_CC_RELEASE, H_DISCONNECT_LOCAL_EARLY},
+ /* E_SIP_INV_EXPIRES_TIMER ccsip_handle_disconnect_local_early */
+ {E_SIP_INV_EXPIRES_TIMER, H_DISCONNECT_LOCAL_EARLY},
+ /* E_SIP_UPDATE ccsip_handle_early_ev_sip_update */
+ {E_SIP_UPDATE, H_EARLY_EV_SIP_UPDATE},
+ /* E_SIP_UPDATE_RESPONSE ccsip_handle_early_ev_sip_update_response */
+ {E_SIP_UPDATE_RESPONSE, H_EARLY_EV_SIP_UPDATE_RESPONSE},
+ /* E_CC_UPDATE ccsip_handle_early_ev_cc_feature */
+ {E_CC_FEATURE, H_EARLY_EV_CC_FEATURE},
+ /* E_CC_FEATURE_ACK ccsip_handle_early_ev_cc_feature_ack */
+ {E_CC_FEATURE_ACK, H_EARLY_EV_CC_FEATURE_ACK},
+ /* E_SIP_NOTIFY ccsip_handle_unsolicited_notify */
+ {E_SIP_NOTIFY, H_EV_SIP_UNSOLICITED_NOTIFY},
+
+ /* Initializing any events which are not used to Invalid events */
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT}
+ }
+ },
+
+ /*
+ * SIP_STATE_SENT_INVITE_CONNECTED
+ */
+ {SIP_STATE_SENT_INVITE_CONNECTED,
+ {
+ /* E_SIP_BYE ccsip_handle_disconnect_remote */
+ {E_SIP_BYE, H_DISCONNECT_REMOTE},
+ /* E_CC_CONNECTED_ACK ccsip_handle_sentinviteconnected_ev_cc_connected_ack, */
+ {E_CC_CONNECTED_ACK, H_SENTINVITECONNECTED_EV_CC_CONNECTED_ACK},
+ /* E_CC_RELEASE ccsip_handle_disconnect_local, */
+ {E_CC_RELEASE, H_DISCONNECT_LOCAL},
+ /* E_SIP_UPDATE ccsip_handle_early_ev_sip_update */
+ {E_SIP_UPDATE, H_EARLY_EV_SIP_UPDATE},
+ /* E_SIP_UPDATE_RESPONSE ccsip_handle_early_ev_sip_update_response */
+ {E_SIP_UPDATE_RESPONSE, H_EARLY_EV_SIP_UPDATE_RESPONSE},
+ /* E_CC_UPDATE ccsip_handle_early_ev_cc_feature */
+ {E_CC_FEATURE, H_EARLY_EV_CC_FEATURE},
+ /* E_CC_FEATURE_ACK ccsip_handle_early_ev_cc_feature_ack */
+ {E_CC_FEATURE_ACK, H_EARLY_EV_CC_FEATURE_ACK},
+ /* E_SIP_NOTIFY ccsip_handle_unsolicited_notify */
+ {E_SIP_NOTIFY, H_EV_SIP_UNSOLICITED_NOTIFY},
+
+ /* Initializing any events which are not used to Invalid events */
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT}
+ }
+ },
+ /*
+ * SIP_STATE_RECV_INVITE
+ */
+ {SIP_STATE_RECV_INVITE,
+ {
+ /* E_SIP_BYE ccsip_handle_disconnect_remote */
+ {E_SIP_BYE, H_DISCONNECT_REMOTE},
+ /* E_SIP_CANCEL ccsip_handle_disconnect_remote, */
+ {E_SIP_CANCEL, H_DISCONNECT_REMOTE},
+ /* E_CC_SETUP_ACK ccsip_handle_recvinvite_ev_cc_setup_ack, */
+ {E_CC_SETUP_ACK, H_RECVINVITE_EV_CC_SETUP_ACK},
+ /* E_CC_PROCEEDING ccsip_handle_recvinvite_ev_cc_proceeding, */
+ {E_CC_PROCEEDING, H_RECVINVITE_EV_CC_PROCEEDING},
+ /* E_CC_ALERTING ccsip_handle_recvinvite_ev_cc_alerting, */
+ {E_CC_ALERTING, H_RECVINVITE_EV_CC_ALERTING},
+ /* E_CC_CONNECTED ccsip_handle_recvinvite_ev_cc_connected, */
+ {E_CC_CONNECTED, H_RECVINVITE_EV_CC_CONNECTED},
+ /* E_CC_RELEASE ccsip_handle_disconnect_local_unanswered, */
+ {E_CC_RELEASE, H_DISCONNECT_LOCAL_UNANSWERED},
+ /* E_SIP_INV_LOCALEXPIRES_TIMER ccsip_handle_localexpires_timer */
+ {E_SIP_INV_LOCALEXPIRES_TIMER, H_HANDLE_LOCALEXPIRES_TIMER},
+ /* E_SIP_UPDATE ccsip_handle_early_ev_sip_update */
+ {E_SIP_UPDATE, H_EARLY_EV_SIP_UPDATE},
+ /* E_SIP_UPDATE_RESPONSE ccsip_handle_early_ev_sip_update_response */
+ {E_SIP_UPDATE_RESPONSE, H_EARLY_EV_SIP_UPDATE_RESPONSE},
+ /* E_CC_UPDATE ccsip_handle_early_ev_cc_feature */
+ {E_CC_FEATURE, H_EARLY_EV_CC_FEATURE},
+ /* E_CC_FEATURE_ACK ccsip_handle_early_ev_cc_feature_ack */
+ {E_CC_FEATURE_ACK, H_EARLY_EV_CC_FEATURE_ACK},
+ /* E_SIP_NOTIFY ccsip_handle_unsolicited_notify */
+ {E_SIP_NOTIFY, H_EV_SIP_UNSOLICITED_NOTIFY}
+
+ /* Initializing any events which are not used to Invalid events */
+ }
+ },
+
+ /*
+ * SIP_STATE_RECV_INVITE_PROCEEDING
+ */
+ {SIP_STATE_RECV_INVITE_PROCEEDING,
+ {
+ /* E_SIP_BYE ccsip_handle_disconnect_remote, */
+ {E_SIP_BYE, H_DISCONNECT_REMOTE},
+ /* E_SIP_CANCEL ccsip_handle_disconnect_remote */
+ {E_SIP_CANCEL, H_DISCONNECT_REMOTE},
+ /* E_CC_ALERTING ccsip_handle_recvinvite_ev_cc_alerting, */
+ {E_CC_ALERTING, H_RECVINVITE_EV_CC_ALERTING},
+ /* E_CC_CONNECTED ccsip_handle_recvinvite_ev_cc_connected, */
+ {E_CC_CONNECTED, H_RECVINVITE_EV_CC_CONNECTED},
+ /* E_CC_RELEASE ccsip_handle_disconnect_local_unanswered, */
+ {E_CC_RELEASE, H_DISCONNECT_LOCAL_UNANSWERED},
+ /* E_SIP_INV_LOCALEXPIRES_TIMER ccsip_handle_localexpires_timer */
+ {E_SIP_INV_LOCALEXPIRES_TIMER, H_HANDLE_LOCALEXPIRES_TIMER},
+ /* E_SIP_UPDATE ccsip_handle_early_ev_sip_update */
+ {E_SIP_UPDATE, H_EARLY_EV_SIP_UPDATE},
+ /* E_SIP_UPDATE_RESPONSE ccsip_handle_early_ev_sip_update_response */
+ {E_SIP_UPDATE_RESPONSE, H_EARLY_EV_SIP_UPDATE_RESPONSE},
+ /* E_CC_UPDATE ccsip_handle_early_ev_cc_feature */
+ {E_CC_FEATURE, H_EARLY_EV_CC_FEATURE},
+ /* E_CC_FEATURE_ACK ccsip_handle_early_ev_cc_feature_ack */
+ {E_CC_FEATURE_ACK, H_EARLY_EV_CC_FEATURE_ACK},
+ /* E_SIP_NOTIFY ccsip_handle_unsolicited_notify */
+ {E_SIP_NOTIFY, H_EV_SIP_UNSOLICITED_NOTIFY},
+
+ /* Initializing any events which are not used to Invalid events */
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT}
+ }
+ },
+ /*
+ * SIP_STATE_RECV_INVITE_ALERTING
+ */
+ {SIP_STATE_RECV_INVITE_ALERTING,
+ {
+ /* E_SIP_BYE ccsip_handle_disconnect_remote, */
+ {E_SIP_BYE, H_DISCONNECT_REMOTE},
+ /* E_SIP_CANCEL ccsip_handle_disconnect_remote, */
+ {E_SIP_CANCEL, H_DISCONNECT_REMOTE},
+ /* E_CC_CONNECTED ccsip_handle_recvinvite_ev_cc_connected, */
+ {E_CC_CONNECTED, H_RECVINVITE_EV_CC_CONNECTED},
+ /* E_CC_RELEASE ccsip_handle_disconnect_local_unanswered, */
+ {E_CC_RELEASE, H_DISCONNECT_LOCAL_UNANSWERED},
+ /* E_SIP_INV_LOCALEXPIRES_TIMER ccsip_handle_localexpires_timer */
+ {E_SIP_INV_LOCALEXPIRES_TIMER, H_HANDLE_LOCALEXPIRES_TIMER},
+ /* E_SIP_UPDATE ccsip_handle_early_ev_sip_update */
+ {E_SIP_UPDATE, H_EARLY_EV_SIP_UPDATE},
+ /* E_SIP_UPDATE_RESPONSE ccsip_handle_early_ev_sip_update_response */
+ {E_SIP_UPDATE_RESPONSE, H_EARLY_EV_SIP_UPDATE_RESPONSE},
+ /* E_CC_UPDATE ccsip_handle_early_ev_cc_feature */
+ {E_CC_FEATURE, H_EARLY_EV_CC_FEATURE},
+ /* E_CC_FEATURE_ACK ccsip_handle_early_ev_cc_feature_ack */
+ {E_CC_FEATURE_ACK, H_EARLY_EV_CC_FEATURE_ACK},
+ /* E_SIP_NOTIFY ccsip_handle_unsolicited_notify */
+ {E_SIP_NOTIFY, H_EV_SIP_UNSOLICITED_NOTIFY},
+ /* E_SIP_2xx ccsip_handle_recvinvite_ev_sip_2xx */
+ {E_SIP_2xx, H_RECVINVITE_EV_SIP_2XX},
+ /* E_SIP_FAILURE_RESPONSE ccsip_handle_sentinvite_ev_sip_fxx, */
+ {E_SIP_FAILURE_RESPONSE, H_SENTINVITE_EV_SIP_FXX},
+
+ /* Initializing any events which are not used to Invalid events */
+ {H_INVALID_EVENT, H_DEFAULT}
+ }
+ },
+ /*
+ * SIP_STATE_RECV_INVITE_CONNECTED
+ */
+ {SIP_STATE_RECV_INVITE_CONNECTED,
+ {
+ /* E_SIP_ACK ccsip_handle_recvinvite_ev_sip_ack, */
+ {E_SIP_ACK, H_RECVINVITE_EV_SIP_ACK},
+ /* E_SIP_BYE ccsip_handle_disconnect_remote, */
+ {E_SIP_BYE, H_DISCONNECT_REMOTE},
+ /* E_CC_RELEASE ccsip_handle_disconnect_local, */
+ {E_CC_RELEASE, H_DISCONNECT_LOCAL},
+ /* E_SIP_UPDATE ccsip_handle_early_ev_sip_update */
+ {E_SIP_UPDATE, H_EARLY_EV_SIP_UPDATE},
+ /* E_SIP_UPDATE_RESPONSE ccsip_handle_early_ev_sip_update_response */
+ {E_SIP_UPDATE_RESPONSE, H_EARLY_EV_SIP_UPDATE_RESPONSE},
+ /* E_CC_UPDATE ccsip_handle_early_ev_cc_feature */
+ {E_CC_FEATURE, H_EARLY_EV_CC_FEATURE},
+ /* E_CC_FEATURE_ACK ccsip_handle_early_ev_cc_feature_ack */
+ {E_CC_FEATURE_ACK, H_EARLY_EV_CC_FEATURE_ACK},
+ /* E_SIP_INV_EXPIRES_TIMER ccsip_handle_recvinvite_ev_expires_timer */
+ {E_SIP_INV_EXPIRES_TIMER, H_RECVINVITE_SENTOK_NO_SIP_ACK},
+ /* E_SIP_NOTIFY ccsip_handle_unsolicited_notify */
+ {E_SIP_NOTIFY, H_EV_SIP_UNSOLICITED_NOTIFY},
+
+ /* Initializing any events which are not used to Invalid events */
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT}
+ }
+ },
+
+ /*
+ * SIP_STATE_ACTIVE
+ */
+ {SIP_STATE_ACTIVE,
+ {
+ /* E_SIP_INVITE ccsip_handle_active_ev_sip_invite, */
+ {E_SIP_INVITE, H_ACTIVE_EV_SIP_INVITE},
+ /* E_SIP_BYE ccsip_handle_disconnect_remote, */
+ {E_SIP_BYE, H_DISCONNECT_REMOTE},
+ /* E_SIP_2xx ccsip_handle_active_2xx, */
+ {E_SIP_2xx, H_ACTIVE_2xx},
+ /* E_SIP_REFER ccsip_handle_refer_sip_message, */
+ {E_SIP_REFER, H_REFER_SIP_MESSAGE},
+ /* E_SIP_FAILURE_RESPONSE ccsip_handle_sentinvite_ev_sip_fxx, */
+ {E_SIP_FAILURE_RESPONSE, H_SENTINVITE_EV_SIP_FXX},
+ /* E_CC_RELEASE ccsip_handle_disconnect_local, */
+ {E_CC_RELEASE, H_DISCONNECT_LOCAL},
+ /* E_CC_FEATURE ccsip_handle_active_ev_cc_feature, */
+ {E_CC_FEATURE, H_ACTIVE_EV_CC_FEATURE},
+ /* E_CC_FEATURE_ACK ccsip_handle_active_ev_cc_feature_ack, */
+ {E_CC_FEATURE_ACK, H_ACTIVE_EV_CC_FEATURE_ACK},
+ /* E_SIP_UPDATE ccsip_handle_active_ev_sip_update */
+ {E_SIP_UPDATE, H_CONFIRM_EV_SIP_UPDATE},
+ /* E_SIP_NOTIFY ccsip_handle_unsolicited_notify */
+ {E_SIP_NOTIFY, H_EV_SIP_UNSOLICITED_NOTIFY},
+ /* E_CC_INFO ccsip_handle_ev_cc_info */
+ {E_CC_INFO, H_EV_CC_INFO},
+
+ /* Initializing any events which are not used to Invalid events */
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT}
+ }
+ },
+ /*
+ * SIP_STATE_SENT_MIDCALL_INVITE
+ */
+ {SIP_STATE_SENT_MIDCALL_INVITE,
+ {
+ /* E_SIP_INVITE ccsip_handle_active_ev_sip_invite, */
+ {E_SIP_INVITE, H_ACTIVE_EV_SIP_INVITE},
+ /* E_SIP_BYE ccsip_handle_disconnect_remote, */
+ {E_SIP_BYE, H_DISCONNECT_REMOTE},
+ /* E_SIP_2xx ccsip_handle_sentinvite_midcall_ev_sip_2xx, */
+ {E_SIP_2xx, H_SENTINVITE_MIDCALL_EV_SIP_2XX},
+ /* E_SIP_FAILURE_RESPONSE ccsip_handle_sentinvite_ev_sip_fxx, */
+ {E_SIP_FAILURE_RESPONSE, H_SENTINVITE_EV_SIP_FXX},
+ /* E_SIP_INV_EXPIRES_TIMER ccsip_handle_disconnect_local */
+ {E_SIP_INV_EXPIRES_TIMER, H_DISCONNECT_LOCAL},
+ /* E_CC_RELEASE ccsip_handle_disconnect_local, */
+ {E_CC_RELEASE, H_DISCONNECT_LOCAL},
+ /* E_CC_FEATURE ccsip_handle_sentinvite_midcall_ev_cc_feature, */
+ {E_CC_FEATURE, H_SENTINVITE_MIDCALL_EV_CC_FEATURE},
+ /* E_SIP_UPDATE ccsip_handle_active_ev_sip_update */
+ {E_SIP_UPDATE, H_CONFIRM_EV_SIP_UPDATE},
+ /* E_SIP_NOTIFY ccsip_handle_unsolicited_notify */
+ {E_SIP_NOTIFY, H_EV_SIP_UNSOLICITED_NOTIFY},
+ /* E_CC_INFO ccsip_handle_ev_cc_info */
+ {E_CC_INFO, H_EV_CC_INFO},
+
+ /* Initializing any events which are not used to Invalid events */
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT}
+ }
+ },
+ /*
+ * SIP_STATE_RECV_MIDCALL_INVITE_CCFEATUREACK_PENDING
+ */
+ {SIP_STATE_RECV_MIDCALL_INVITE_CCFEATUREACK_PENDING,
+ {
+ /* E_SIP_BYE ccsip_handle_disconnect_remote, */
+ {E_SIP_BYE, H_DISCONNECT_REMOTE},
+ /* E_CC_RELEASE ccsip_handle_disconnect_media_change, */
+ {E_CC_RELEASE, H_DISCONNECT_MEDIA_CHANGE},
+ /* E_CC_FEATURE_ACK ccsip_handle_recvmidcallinvite_ccfeatureackpending_ev_cc_feature_ack, */
+ {E_CC_FEATURE_ACK, H_RECVMIDCALLINVITE_CCFEATUREACKPENDING_EV_CC_FEATURE_ACK},
+ /* E_SIP_NOTIFY ccsip_handle_unsolicited_notify */
+ {E_SIP_NOTIFY, H_EV_SIP_UNSOLICITED_NOTIFY},
+ /* E_CC_FEATURE, ccsip_handle_default_recvreq_ack_pending_ev_cc_feature */
+ {E_CC_FEATURE, H_DEFAULT_RECVREQ_ACK_PENDING_EV_CC_FEATURE},
+ /* E_CC_INFO ccsip_handle_ev_cc_info */
+ {E_CC_INFO, H_EV_CC_INFO},
+
+ /* Initializing any events which are not used to Invalid events */
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT}
+ }
+ },
+
+ /*
+ * SIP_STATE_RECV_MIDCALLINVITE_SIPACK_PENDING
+ */
+ {SIP_STATE_RECV_MIDCALL_INVITE_SIPACK_PENDING,
+ {
+ /* E_SIP_ACK ccsip_handle_recvmidcallinvite_sipackpending_ev_sip_ack, */
+ {E_SIP_ACK, H_RECVMIDCALLINVITE_SIPACKPENDING_EV_SIP_ACK},
+ /* E_SIP_BYE ccsip_handle_disconnect_remote, */
+ {E_SIP_BYE, H_DISCONNECT_REMOTE},
+ /* E_CC_RELEASE ccsip_handle_disconnect_local, */
+ {E_CC_RELEASE, H_DISCONNECT_LOCAL},
+ /* E_SIP_NOTIFY ccsip_handle_unsolicited_notify */
+ {E_SIP_NOTIFY, H_EV_SIP_UNSOLICITED_NOTIFY},
+ /* E_CC_FEATURE, ccsip_handle_default_recvreq_ack_pending_ev_cc_feature */
+ {E_CC_FEATURE, H_DEFAULT_RECVREQ_ACK_PENDING_EV_CC_FEATURE},
+ /* E_CC_INFO ccsip_handle_ev_cc_info */
+ {E_CC_INFO, H_EV_CC_INFO},
+
+ /* Initializing any events which are not used to Invalid events */
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT}
+ }
+ },
+ /*
+ * SIP_STATE_RELEASE
+ */
+ {SIP_STATE_RELEASE,
+ {
+ /* E_SIP_BYE, ccsip_handle_release_ev_sip_bye */
+ {E_SIP_BYE, H_BYE_RELEASE},
+ /* E_SIP_ACK ccsip_handle_recv_error_response_ev_sip_ack, */
+ {E_SIP_ACK, H_RECV_ERR_EV_SIP_ACK},
+ /* E_SIP_INVITE ccsip_handle_sentbye_recvd_invite, */
+ {E_SIP_INVITE, H_SENTBYE_EV_SIP_INVITE},
+ /* E_SIP_1xx ccsip_handle_sentbye_ev_sip_1xx, */
+ {E_SIP_1xx, H_SENTBYE_EV_SIP_1XX},
+ /* E_SIP_2xx ccsip_handle_sentbye_ev_sip_2xx, */
+ {E_SIP_2xx, H_SENTBYE_EV_SIP_2XX},
+ /* E_SIP_FAILURE_RESPONSE ccsip_handle_sentbye_ev_sip_fxx, */
+ {E_SIP_FAILURE_RESPONSE, H_SENTBYE_EV_SIP_FXX},
+ /* E_SIP_SUPERVISION_DISCONNECT_TIMER
+ * ccsip_handle_sendbye_ev_supervision_disconnect, */
+ {E_SIP_SUPERVISION_DISCONNECT_TIMER, H_SENTBYE_SUPERVISION_DISCONNECT_TIMER},
+ /* E_CC_RELEASE_COMPLETE, ccsip_handle_release_complete, */
+ {E_CC_RELEASE_COMPLETE, H_RELEASE_COMPLETE},
+ /* E_SIP_UPDATE ccsip_handle_sentbye_recvd_invite, */
+ {E_SIP_UPDATE, H_SENTBYE_EV_SIP_INVITE},
+ /* E_SIP_NOTIFY ccsip_handle_unsolicited_notify */
+ {E_SIP_NOTIFY, H_EV_SIP_UNSOLICITED_NOTIFY},
+ /* E_CC_FEATURE ccsip_handle_release_ev_cc_feature, */
+ {E_CC_FEATURE, H_RELEASE_EV_CC_FEATURE},
+ /* E_CC_RELEASE, ccsip_handle_release_ev_release, */
+ {E_CC_RELEASE, H_RELEASE_EV_RELEASE},
+ /* Initializing any events which are not used to Invalid events */
+ {H_INVALID_EVENT, H_DEFAULT}
+ }
+ },
+
+ /*
+ * SIP_STATE_BLIND_XFER_PENDING,
+ */
+
+ {SIP_STATE_BLIND_XFER_PENDING,
+ {
+ /* E_SIP_BYE, ccsip_handle_release_ev_sip_bye */
+ {E_SIP_BYE, H_BYE_RELEASE},
+ /* E_SIP_2xx ccsip_handle_sentblindntfy_ev_sip_2xx, */
+ {E_SIP_2xx, H_SENT_BLINDNTFY},
+ /* E_SIP_FAILURE_RESPONSE ccsip_handle_sentbye_ev_sip_fxx, */
+ {E_SIP_FAILURE_RESPONSE, H_SENTBYE_EV_SIP_FXX},
+ /* E_CC_FEATURE ccsip_handle_send_blind_notify, */
+ {E_CC_FEATURE, H_BLIND_NOTIFY},
+ /* E_SIP_NOTIFY ccsip_handle_unsolicited_notify */
+ {E_SIP_NOTIFY, H_EV_SIP_UNSOLICITED_NOTIFY},
+
+ /* Initializing any events which are not used to Invalid events */
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT}
+
+ }
+ },
+
+ {SIP_STATE_IDLE_MSG_TIMER_OUTSTANDING,
+ {
+ /* E_SIP_TIMER, ccsip_handle_default_sip_timer */
+ {E_SIP_TIMER, H_DEFAULT_SIP_TIMER},
+ /* E_SIP_NOTIFY ccsip_handle_unsolicited_notify */
+ {E_SIP_NOTIFY, H_EV_SIP_UNSOLICITED_NOTIFY},
+ /* E_CC_FEATURE ccsip_handle_default_ev_cc_feature */
+ {E_CC_FEATURE, H_DEFAULT_EV_CC_FEATURE},
+
+ /* Initializing any events which are not used to Invalid events */
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT}
+ }
+ },
+
+ {SIP_STATE_SENT_OOD_REFER,
+ {
+ {E_SIP_1xx, H_OOD_REFER_RESPONSE_EV_SIP_1xx},
+ {E_SIP_2xx, H_OOD_REFER_RESPONSE_EV_SIP_2xx},
+ {E_SIP_3xx, H_OOD_REFER_RESPONSE_EV_SIP_fxx},
+ {E_SIP_FAILURE_RESPONSE, H_OOD_REFER_RESPONSE_EV_SIP_fxx},
+ /* E_CC_INFO ccsip_handle_ev_cc_info */
+ {E_CC_INFO, H_EV_CC_INFO},
+ /* Initializing any events which are not used to Invalid events */
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT}
+ }
+ },
+
+ {SIP_STATE_RECV_UPDATEMEDIA_CCFEATUREACK_PENDING,
+ {
+ /* E_SIP_BYE ccsip_handle_disconnect_remote, */
+ {E_SIP_BYE, H_DISCONNECT_REMOTE},
+ /* E_CC_RELEASE ccsip_handle_disconnect_media_change, */
+ {E_CC_RELEASE, H_DISCONNECT_MEDIA_CHANGE},
+ /* E_CC_FEATURE_ACK ccsip_handle_recvupdatenewmedia_ccfeatureackpending_ev_cc_feature_ack, */
+ {E_CC_FEATURE_ACK, H_RECVUPDATEMEDIA_CCFEATUREACKPENDING_EV_CC_FEATURE_ACK},
+ /* E_SIP_NOTIFY ccsip_handle_unsolicited_notify */
+ {E_SIP_NOTIFY, H_EV_SIP_UNSOLICITED_NOTIFY},
+ /* E_CC_FEATURE, ccsip_handle_default_recvreq_ack_pending_ev_cc_feature */
+ {E_CC_FEATURE, H_DEFAULT_RECVREQ_ACK_PENDING_EV_CC_FEATURE},
+ /* E_CC_INFO ccsip_handle_ev_cc_info */
+ {E_CC_INFO, H_EV_CC_INFO},
+
+ /* Initializing any events which are not used to Invalid events */
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT},
+ {H_INVALID_EVENT, H_DEFAULT}
+ }
+ },
+
+};
+
+static const sipSMEventActionFn_t
+ gSIPHandlerTable[SIPSPI_EV_INDEX_END - SIPSPI_EV_INDEX_BASE + 1] = {
+
+ /*0*//* H_IDLE_EV_SIP_INVITE, */
+ ccsip_handle_idle_ev_sip_invite,
+
+ /*1*//* H_IDLE_EV_CC_SETUP, */
+ ccsip_handle_idle_ev_cc_setup,
+
+ /*2*//* H_SENTINVITE_EV_SIP_1XX, */
+ ccsip_handle_sentinvite_ev_sip_1xx,
+
+ /*3*//* H_SENTINVITE_EV_SIP_2XX, */
+ ccsip_handle_sentinvite_ev_sip_2xx,
+
+ /*4*//* H_SENTINVITE_EV_SIP_FXX, */
+ ccsip_handle_sentinvite_ev_sip_fxx,
+
+ /*5*//* H_DISCONNECT_LOCAL_EARLY, */
+ ccsip_handle_disconnect_local_early,
+
+ /*6*//* H_DISCONNECT_REMOTE, */
+ ccsip_handle_disconnect_remote,
+
+ /*7*//* H_SENTINVITECONNECTED_EV_CC_CONNECTED_ACK, */
+ ccsip_handle_sentinviteconnected_ev_cc_connected_ack,
+
+ /*8*//* H_DISCONNECT_LOCAL, */
+ ccsip_handle_disconnect_local,
+
+ /*9*//* H_RECVINVITE_EV_CC_SETUP_ACK, */
+ ccsip_handle_recvinvite_ev_cc_setup_ack,
+
+ /*10*//* H_RECVINVITE_EV_CC_PROCEEDING, */
+ ccsip_handle_recvinvite_ev_cc_proceeding,
+
+ /*11*//* H_RECVINVITE_EV_CC_ALERTING, */
+ ccsip_handle_recvinvite_ev_cc_alerting,
+
+ /*12*//* H_RECVINVITE_EV_CC_CONNECTED, */
+ ccsip_handle_recvinvite_ev_cc_connected,
+
+ /*13*//* H_DISCONNECT_LOCAL_UNANSWERED, */
+ ccsip_handle_disconnect_local_unanswered,
+
+ /*14*//* H_RECVINVITE_EV_SIP_ACK, */
+ ccsip_handle_recvinvite_ev_sip_ack,
+
+ /*15*//* H_ACTIVE_EV_SIP_INVITE, */
+ ccsip_handle_active_ev_sip_invite,
+
+ /*16*//* H_ACTIVE_EV_CC_FEATURE, */
+ ccsip_handle_active_ev_cc_feature,
+
+ /*17*//* H_ACCEPT_2XX, */
+ ccsip_handle_accept_2xx,
+
+ /*18*//* H_REFER_SIP_MESSAGE, */
+ ccsip_handle_refer_sip_message,
+
+ /*19*//* H_ACTIVE_EV_CC_FEATURE_ACK, */
+ ccsip_handle_active_ev_cc_feature_ack,
+
+ /*20*//* H_SENTINVITE_MIDCALL_EV_SIP_2XX, */
+ ccsip_handle_sentinvite_midcall_ev_sip_2xx,
+
+ /*21*//* H_SENTINVITE_MIDCALL_EV_CC_FEATURE, */
+ ccsip_handle_sentinvite_midcall_ev_cc_feature,
+
+ /*22*//* H_RECVMIDCALLINVITE_CCFEATUREACKPENDING_EV_CC_FEATURE_ACK */
+ ccsip_handle_recvmidcallinvite_ccfeatureackpending_ev_cc_feature_ack,
+
+ /*23*//* H_RECVMIDCALLINVITE__SIPACKPENDING_EV_SIP_ACK, */
+ ccsip_handle_recvmidcallinvite_sipackpending_ev_sip_ack,
+
+ /*24*//* H_DEFAULT_SIP_MESSAGE, */
+ ccsip_handle_default_sip_message,
+
+ /*25*//* H_DEFAULT_SIP_RESPONSE, */
+ ccsip_handle_default_sip_response,
+
+ /*26*//* H_DEFAULT, */
+ ccsip_handle_default,
+
+ /*27*//* H_SIP_INV_EXPIRES_TIMER */
+ ccsip_handle_disconnect_local_early,
+
+ /*28*//* H_SIP_OPTIONS, */
+ ccsip_handle_process_in_call_options_request,
+
+ /*29*//* H_SENTINVITE_EV_SIP_3XX, */
+ ccsip_handle_sentinvite_ev_sip_3xx,
+
+ /*30*//*H_RECV_ERR_EV_SIP_ACK */
+ ccsip_handle_recv_error_response_ev_sip_ack,
+
+ /*31*//*H_SENTBYE_EV_SIP_2XX */
+ ccsip_handle_sentbye_ev_sip_2xx,
+
+ /*32*//*H_SENTBYE_EV_SIP_1XX */
+ ccsip_handle_sentbye_ev_sip_1xx,
+
+ /*33*//*H_SENTBYE_EV_SIP_FXX */
+ ccsip_handle_sentbye_ev_sip_fxx,
+
+ /*34*//*H_SENTBYE_EV_SIP_INVITE */
+ ccsip_handle_sentbye_recvd_invite,
+
+ /*35*//*H_SENTBYE_SUPERVISION_DISCONNECT_TIMER */
+ ccsip_handle_sendbye_ev_supervision_disconnect,
+
+ /*36*//*H_RELEASE_COMPLETE */
+ ccsip_handle_release_complete,
+
+ /*37*//*H_ACTIVE_2xx */
+ ccsip_handle_active_2xx,
+
+ /*38*//*H_BLIND_NOTIFY */
+ ccsip_handle_send_blind_notify,
+
+ /*39*//*H_SENT_BLINDNTFY */
+ ccsip_handle_sentblindntfy_ev_sip_2xx,
+
+ /*40*//*H_BYE_RELEASE, */
+ ccsip_handle_release_ev_sip_bye,
+
+ /*41*//*H_HANDLE_LOCALEXPIRES_TIMER, */
+ ccsip_handle_localexpires_timer,
+
+ /*42*//*H_DEFAULT_SIP_TIMER */
+ ccsip_handle_default_sip_timer,
+
+ /*43*//*H_EARLY_EV_SIP_UPDATE */
+ ccsip_handle_early_ev_sip_update,
+
+ /*44*//*H_EARLY_EV_SIP_UPDATE_RESPONSE */
+ ccsip_handle_early_ev_sip_update_response,
+
+ /*45*//*H_EARLY_EV_CC_FEATURE */
+ ccsip_handle_early_ev_cc_feature,
+
+ /*46*//*H_EARLY_EV_CC_FEATURE_ACK */
+ ccsip_handle_early_ev_cc_feature_ack,
+
+ /*47*//*H_CONFIRM_EV_SIP_UPDATE */
+ ccsip_handle_active_ev_sip_update,
+
+ /*48*//*H_RECVUPDATEMEDIA_CCFEATUREACKPENDING_EV_CC_FEATURE_ACK */
+ ccsip_handle_recvupdatemedia_ccfeatureackpending_ev_cc_feature_ack,
+
+ /*49*//*H_SIP_GLARE_AVOIDANCE_TIMER */
+ ccsip_handle_timer_glare_avoidance,
+
+ /*50*//*H_RECVINVITE_SENTOK_NO_SIP_ACK */
+ ccsip_handle_recvinvite_ev_expires_timer,
+
+ /*51*//*H_EV_SIP_UNSOLICITED_NOTIFY */
+ ccsip_handle_unsolicited_notify,
+
+ /*52*//*H_RECVINVITE_EV_SIP_2XX, */
+ ccsip_handle_recvinvite_ev_sip_2xx,
+
+ /*53*//*H_ICMP_UNREACHABLE, */
+ ccsip_handle_icmp_unreachable,
+
+ /*54*//*H_DISCONNECT_MEDIA_CHANGE, */
+ ccsip_handle_disconnect_media_change,
+
+ /*55*//*H_DEFAULT_EV_CC_FEATURE, */
+ ccsip_handle_default_ev_cc_feature,
+
+ /*56*//*H_DEFAULT_RECVREQ_ACK_PENDING_EV_CC_FEATURE */
+ ccsip_handle_default_recvreq_ack_pending_ev_cc_feature,
+
+ /*57*//*H_OOD_REFER_RESPONSE_EV_SIP_1xx */
+ ccsip_handle_sent_ood_refer_ev_sip_1xx,
+
+ /*58*//*H_OOD_REFER_RESPONSE_EV_SIP_2xx */
+ ccsip_handle_sent_ood_refer_ev_sip_2xx,
+
+ /*59*//*H_OOD_REFER_RESPONSE_EV_SIP_fxx */
+ ccsip_handle_sent_ood_refer_ev_sip_fxx,
+
+ /*60*//* H_RELEASE_EV_CC_FEATURE, */
+ ccsip_handle_release_ev_cc_feature,
+
+ /*61*//* H_EV_CC_INFO, */
+ ccsip_handle_ev_cc_info,
+
+ /*62*//* H_RELEASE_EV_RELEASE, */
+ ccsip_handle_release_ev_release,
+};
+
+static uint32_t get_callref(const char *tag) {
+ int32_t i, callref = 0;
+ const char * ref;
+
+ for ( i = (strlen(tag)-1); i >= 0; i--) {
+ ref = &tag[i];
+ if ( *ref == '-' ) {
+ sscanf ( ref, "-%d", &callref);
+ break;
+ }
+ }
+ return callref;
+}
+
+sipSMAction_t
+get_handler_index (sipSMStateType_t isipsmstate, sipSMEventType_t isipsmevent)
+{
+ int16_t i;
+
+ if ((isipsmstate < SIP_STATE_BASE) || (isipsmstate > SIP_STATE_END) ||
+ (isipsmevent < SIPSPI_EV_BASE) || (isipsmevent > SIPSPI_EV_END)) {
+ buginf("\nvalue of event passed isipsmevent=%d value of state = %d, "
+ "SIP_STATE_BASE = %d, SIP_STATE_END = %d, SIPSPI_EV_BASE = %d,"
+ " SIPSPI_EV_END = %d",
+ isipsmstate, isipsmevent, SIP_STATE_BASE, SIP_STATE_END,
+ SIPSPI_EV_BASE, SIPSPI_EV_END);
+
+ return H_INVALID_EVENT;
+ }
+
+ for (i = 0; i < MAX_STATE_EVENTS; i++) {
+ if (g_sip_table[isipsmstate].validEvent[i].sipValidEvent == (int16_t)isipsmevent) {
+ return ((sipSMAction_t) g_sip_table[isipsmstate].validEvent[i].actionIndex);
+ }
+ }
+ switch (isipsmevent) {
+ case E_SIP_INVITE:
+ case E_SIP_UPDATE:
+ case E_SIP_ACK:
+ case E_SIP_BYE:
+ case E_SIP_REFER:
+ case E_SIP_CANCEL:
+ return H_DEFAULT_SIP_MESSAGE;
+ case E_SIP_1xx:
+ case E_SIP_2xx:
+ case E_SIP_3xx:
+ case E_SIP_FAILURE_RESPONSE:
+ return H_DEFAULT_SIP_RESPONSE;
+ case E_SIP_TIMER:
+ return H_DEFAULT_SIP_TIMER;
+
+ case E_SIP_OPTIONS:
+ return H_SIP_OPTIONS;
+
+ case E_SIP_GLARE_AVOIDANCE_TIMER:
+ return H_SIP_GLARE_AVOIDANCE_TIMER;
+
+ case E_SIP_ICMP_UNREACHABLE:
+ return H_ICMP_UNREACHABLE;
+
+ default:
+ break;
+ }
+ return H_DEFAULT;
+}
+
+
+void
+sip_sm_change_state (ccsipCCB_t *ccb, sipSMStateType_t new_state)
+{
+ CCSIP_DEBUG_STATE(DEB_L_C_F_PREFIX"Change state %s -> %s\n",
+ DEB_L_C_F_PREFIX_ARGS(SIP_STATE, ccb->dn_line, ccb->gsm_id, "sip_sm_change_state"),
+ sip_util_state2string(ccb->state),
+ sip_util_state2string(new_state));
+
+ if (ccb->state == SIP_STATE_RELEASE &&
+ new_state == SIP_STATE_IDLE) {
+ /* Just add call marker in the log */
+ DEF_DEBUG("===================================================\n");
+ }
+
+ /*
+ * If we are moving out of SIP_STATE_RELEASE, then stop the
+ * supervision timer if it has been started
+ */
+ if (ccb->state == SIP_STATE_RELEASE) {
+ (void) sip_platform_supervision_disconnect_timer_stop(ccb->index);
+ }
+
+ ccb->state = new_state;
+
+ if (ccb->state == SIP_STATE_RELEASE) {
+ (void) sip_platform_supervision_disconnect_timer_start(SUPERVISION_DISCONNECT_TIMEOUT,
+ ccb->index);
+ }
+}
+
+/*
+ * Function: sip_util_extract_sdp()
+ *
+ * Parameters: ccb - The current call control block
+ * message - The sip message to parse
+ *
+ * Description: This routine parses the indicated message for SDP.
+ *
+ * Returns: sip_sdp_status_t - An enum which contains several return codes
+ *
+ * Note: The SIP_SDP_DNS_FAIL will not be returned from this
+ * function because GSM also handles DNS look up. The rest of
+ * this module should still check for the SIP_SDP_DNS_FAIL value
+ * for the return code of this function. They should be kept just
+ * in case that there is a need for SIP to check DNS for some
+ * reason in the future.
+ */
+static sipsdp_status_t
+sip_util_extract_sdp (ccsipCCB_t *ccb, sipMessage_t *message)
+{
+ const char *fname = "sip_util_extract_sdp";
+ // const char *content_type;
+ uint8_t content_type = 0;
+ int content_length = 0;
+ cc_sdp_t *sip_msg_sdp = NULL;
+ u16 i = 0;
+ sipsdp_status_t retval = SIP_SDP_NOT_PRESENT;
+ char *sdp_data = NULL; // message->mesg_body;
+ uint16_t num_m_lines;
+
+ /*
+ * Check to see if SDP is present in this message
+ */
+ // Go through the different body types to see if there is an
+ // SDP body
+ if (message->num_body_parts == 0) {
+ content_length = 0;
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX"\nmultipart/mixed No SDP Found!\n", DEB_F_PREFIX_ARGS(SIP_SDP, fname));
+ } else {
+ for (i = 0; i < message->num_body_parts; i++) {
+ if (message->mesg_body[i].msgContentTypeValue ==
+ SIP_CONTENT_TYPE_SDP_VALUE) {
+ content_type = SIP_CONTENT_TYPE_SDP_VALUE;
+ content_length = message->mesg_body[i].msgLength;
+ sdp_data = message->mesg_body[i].msgBody;
+ break;
+ }
+ }
+ }
+
+ /*
+ * Check for content
+ */
+ if ((content_type != SIP_CONTENT_TYPE_SDP_VALUE) ||
+ (content_length <= 0)) {
+ /* there is no SDP content or no content */
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_ENTRY), ccb->index,
+ ccb->dn_line, fname, "No SDP");
+ return (SIP_SDP_NOT_PRESENT);
+ }
+
+ /*
+ * Allocate a SDP buffer to work with (only destination buffer is needed).
+ *
+ * Here we are handing in an empty string to designate that we are not
+ * in the context of a peerconnection object
+ */
+ sipsdp_src_dest_create("", CCSIP_DEST_SDP_BIT, &sip_msg_sdp);
+ if ((sip_msg_sdp == NULL) || (sip_msg_sdp->dest_sdp == NULL)) {
+ /* Unable to get SDP */
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SDP_CREATE_BUF_ERROR),
+ fname);
+ return (SIP_SDP_ERROR);
+ }
+ /*
+ * Pasrse the SDP body
+ */
+ if (sdp_parse(sip_msg_sdp->dest_sdp, &sdp_data,
+ (uint16_t)content_length) != SDP_SUCCESS) {
+ /* unable to parse the SDP */
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_PARSE_SDP_ERROR), fname);
+
+ sipsdp_src_dest_free(CCSIP_DEST_SDP_BIT, &sip_msg_sdp);
+ return (SIP_SDP_ERROR);
+ }
+
+ /*
+ * Verify that there are media lines present
+ */
+ num_m_lines = sdp_get_num_media_lines(sip_msg_sdp->dest_sdp);
+ if (num_m_lines == 0) {
+ /* No media lines in the SDP body */
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_ENTRY),
+ ccb->index, ccb->dn_line, fname,
+ "Process SDP, no media");
+ retval = SIP_SDP_NO_MEDIA;
+ } else {
+ /* There is at least a media line in the SDP */
+ retval = SIP_SDP_SUCCESS;
+
+ /*
+ * Check to see if the sdp->session_id and version_id are
+ * the same. If they are, it could be a session audit.
+ * In most cases, this is handled the same as
+ * SIP_SDP_SUCCESS.
+ */
+ if (sip_msg_sdp->dest_sdp) {
+ const char *new_session_id = NULL;
+ const char *new_version_id = NULL;
+
+ new_session_id = sdp_get_owner_sessionid(sip_msg_sdp->dest_sdp);
+ new_version_id = sdp_get_owner_version(sip_msg_sdp->dest_sdp);
+
+ if ((ccb->old_session_id) && (ccb->old_version_id) &&
+ (new_session_id) && (new_version_id)) {
+ if ((!(strcmp(ccb->old_session_id, new_session_id))) &&
+ (!(strcmp(ccb->old_version_id, new_version_id)))) {
+ retval = SIP_SDP_SESSION_AUDIT;
+ }
+ }
+
+ if (ccb->old_session_id != NULL) {
+ cpr_free(ccb->old_session_id);
+ ccb->old_session_id = NULL;
+ }
+ if (ccb->old_version_id != NULL) {
+ cpr_free(ccb->old_version_id);
+ ccb->old_version_id = NULL;
+ }
+ if ((new_session_id) && (new_version_id)) {
+ ccb->old_session_id = cpr_strdup(new_session_id);
+ ccb->old_version_id = cpr_strdup(new_version_id);
+ }
+ }
+ }
+ /* free the SDP buffer */
+ sipsdp_src_dest_free(CCSIP_DEST_SDP_BIT, &sip_msg_sdp);
+ return (retval);
+}
+
+/*
+ * Function: ccsip_save_local_msg_body
+ *
+ * Parameters: ccb - The pointer to ccsipCCB to save message body sent
+ * by GSM.
+ * msg_body - pointer to a new msg body to be saved.
+ *
+ * Description: This routine saves the message bodies sent by GSM via CCAPI.
+ * If there is a previous message, the previous messages will
+ * be freed before the current one is saved.
+ *
+ * Returns: void
+ *
+ */
+static void
+ccsip_save_local_msg_body (ccsipCCB_t *ccb, cc_msgbody_info_t *msg_body)
+{
+ if ((msg_body == NULL) || (msg_body->num_parts == 0)) {
+ return;
+ }
+
+ /*
+ * Move the new bodies to the local_msg_body, the previous
+ * msg. bodies will be freed by the move function
+ */
+ cc_mv_msg_body_parts(&ccb->local_msg_body, msg_body);
+}
+
+/*
+ * Function: sip_redirect
+ *
+ * Parameters: ccb, response to invite request, status code of
+ * response.
+ *
+ * Description: Will create a new invite with contact information
+ * received in Redirection response to previous invite
+ * Will clear up the call if all the contacts have been
+ * used and no 2xx final response has been received.
+ *
+ * Returns:
+ *
+ */
+void
+sip_redirect (ccsipCCB_t *ccb, sipMessage_t *response, uint16_t status_code)
+{
+ const char *fname = "sip_redirect";
+ sipRedirectInfo_t *redirect_info;
+ const char *contact;
+ sipLocation_t *sipLocation;
+ sipUrl_t *pContactURL = NULL;
+ char *diversion[MAX_DIVERSION_HEADERS];
+ char *str_temp = NULL;
+ char ui_str[STATUS_LINE_MAX_LEN];
+ int i = 0;
+ boolean sent_invite = FALSE;
+ cpr_ip_addr_t cc_remote_ipaddr;
+ uint16_t diversion_count, cc_diversion_count, max_headers;
+ size_t to_length;
+ char tmp_str[STATUS_LINE_MAX_LEN];
+ char stored_to_header[MAX_SIP_URL_LENGTH];
+ char *temp = NULL;
+
+
+ CPR_IP_ADDR_INIT(cc_remote_ipaddr);
+
+ while (!sent_invite) {
+ if (ccb->redirect_info == NULL) {
+
+ /* Redirected for the first time allocating redirect_info */
+ redirect_info = (sipRedirectInfo_t *)
+ cpr_malloc(sizeof(sipRedirectInfo_t));
+ if (redirect_info == NULL) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED), ccb->index,
+ ccb->dn_line, fname, "malloc(redirect_info)");
+ sip_cc_release(ccb->gsm_id, ccb->dn_line, CC_CAUSE_ERROR, NULL);
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ return;
+ }
+
+ redirect_info->sipContact = NULL;
+ redirect_info->next_choice = 0;
+ ccb->redirect_info = redirect_info;
+ } else {
+ redirect_info = ccb->redirect_info;
+ }
+
+ /*
+ * Now we are clearing the record-route information since we
+ * want redirected invite to use contact header. New transaction
+ * will start now and that will be using new record-route information,
+ * if any.
+ */
+ if (ccb->record_route_info) {
+ sippmh_free_record_route(ccb->record_route_info);
+ ccb->record_route_info = NULL;
+ }
+
+ if (redirect_info->next_choice >= SIP_MAX_LOCATIONS) {
+ /* Exhausted all Choices */
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ ccb->index, ccb->dn_line, fname,
+ "Exhausted all Contacts");
+ sip_cc_release(ccb->gsm_id, ccb->dn_line, CC_CAUSE_ERROR, NULL);
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ return;
+ }
+
+
+ if ((status_code >= SIP_RED_MULT_CHOICES &&
+ status_code <= SIP_RED_USE_PROXY) &&
+ (ccb->first_pass_3xx == TRUE)) {
+ /* 300, 301, 302 and 305 must have contact header */
+
+ /*
+ * We have already initialized the redirect_info with the
+ * contact info once, so the next time through the loop
+ * skip this part.
+ */
+ ccb->first_pass_3xx = FALSE;
+
+ if ((platGetPhraseText(STR_INDEX_CALL_REDIRECTED,
+ (char *)tmp_str,
+ STATUS_LINE_MAX_LEN - 1)) == CPR_SUCCESS) {
+ memset(ui_str, 0, sizeof(ui_str));
+ snprintf(ui_str, sizeof(ui_str), "%s (in %d)",
+ tmp_str, status_code);
+ ui_set_call_status(ui_str, ccb->dn_line, ccb->gsm_id);
+ }
+
+ if (redirect_info->sipContact) {
+ /* Delete previously stored contact */
+ sippmh_free_contact(redirect_info->sipContact);
+ redirect_info->sipContact = NULL;
+ }
+
+ contact = sippmh_get_cached_header_val(response, CONTACT);
+ redirect_info->sipContact = sippmh_parse_contact(contact);
+ if ((redirect_info->sipContact == NULL)
+ || (contact == NULL)) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ ccb->index, ccb->dn_line, fname,
+ "sippmh_parse_contact()");
+ sip_cc_release(ccb->gsm_id, ccb->dn_line, CC_CAUSE_ERROR, NULL);
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ return;
+ }
+ /*
+ if (ccb->contact_info) {
+ sippmh_free_contact(ccb->contact_info);
+ }
+ ccb->contact_info = redirect_info->sipContact;
+ */
+
+ sipLocation = redirect_info->sipContact->locations[0];
+ redirect_info->next_choice = 1;
+
+ //if we are a part of a transfer we are going to need this.
+ //save the Contact value returned in 30x as the AOR for
+ //value to be populated in a later REFER's Refer-To
+ ccb->sip_referTo = strlib_update(ccb->sip_referTo, contact);
+
+ } else {
+ /* We should try next location in previous Contact */
+
+ if ((redirect_info->sipContact == NULL) ||
+ (redirect_info->next_choice >=
+ redirect_info->sipContact->num_locations)) {
+ /* Exhausted all Choices */
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ ccb->index, ccb->dn_line, fname,
+ "Exhausted all Contacts");
+ sip_cc_release(ccb->gsm_id, ccb->dn_line, CC_CAUSE_ERROR, NULL);
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ return;
+ }
+
+ sipLocation = redirect_info->sipContact->locations
+ [redirect_info->next_choice++];
+ }
+
+ /*
+ * Get the CC-Diversion parameter (if any).
+ */
+ for (i = 0; i < MAX_DIVERSION_HEADERS; i++) {
+ diversion[i] = NULL;
+ }
+ /*
+ * We need to to compliment to old CC-Diversion and CC_Redirect.
+ * We will either be getting CC_Diversion or Diversion or
+ * CC_Redirect, which are all basically same.
+ *
+ * So instead of changing it on the parser level I would prefer
+ * to do it at SIP level. The following code first looks for
+ * Diversion then looks for CC_Diversion and then at last
+ * priority looks for CC_Redirect
+ */
+ diversion_count = sippmh_get_num_particular_headers(response,
+ SIP_HEADER_DIVERSION,
+ SIP_HEADER_DIVERSION,
+ diversion, MAX_DIVERSION_HEADERS);
+ max_headers = MAX_DIVERSION_HEADERS - diversion_count;
+ cc_diversion_count = sippmh_get_num_particular_headers(response,
+ SIP_HEADER_CC_DIVERSION,
+ SIP_HEADER_CC_DIVERSION,
+ &diversion[diversion_count],
+ max_headers);
+ max_headers = MAX_DIVERSION_HEADERS - diversion_count - cc_diversion_count;
+ (void) sippmh_get_num_particular_headers(response,
+ SIP_HEADER_CC_REDIRECT,
+ SIP_HEADER_CC_REDIRECT,
+ &diversion[diversion_count + cc_diversion_count],
+ max_headers);
+ for (i = 0; i < MAX_DIVERSION_HEADERS; i++) {
+ if (diversion[i]) {
+ int len = 0;
+
+ len = strlen(diversion[i]);
+ if (ccb->diversion[i]) {
+ cpr_free(ccb->diversion[i]);
+ ccb->diversion[i] = NULL;
+ }
+ ccb->diversion[i] = (char *) cpr_malloc(len + 2);
+ if (ccb->diversion[i]) {
+ sstrncpy(ccb->diversion[i], diversion[i], len + 1);
+ } else {
+ CCSIP_DEBUG_ERROR(DEB_L_C_F_PREFIX"No memory left;"
+ "Ignoring CC-Diversion header #%d %d\n",
+ ccb->dn_line, ccb->gsm_id, fname,
+ ccb->index, i + 1);
+ }
+ }
+ }
+
+ /*
+ * Ignore TEL URLs so loop through until we hit SIP URL.
+ */
+ while ((sipLocation) &&
+ (redirect_info->next_choice < SIP_MAX_LOCATIONS) &&
+ (sipLocation->genUrl->schema != URL_TYPE_SIP)) {
+ sipLocation = redirect_info->sipContact->locations
+ [redirect_info->next_choice++];
+ }
+
+ if (!sipLocation) {
+ /* Exhausted all Choices */
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ ccb->index, ccb->dn_line, fname,
+ "Exhausted all Contacts");
+ sip_cc_release(ccb->gsm_id, ccb->dn_line, CC_CAUSE_ERROR, NULL);
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ return;
+ }
+
+
+ pContactURL = sipLocation->genUrl->u.sipUrl;
+
+ /*
+ * Initially, set the port to the port contained in the ContactURL. Then
+ * do a DNS Lookup on the host. If we get a new port in the response, we
+ * will use that when building the Request URI.
+ */
+ ccb->dest_sip_port = pContactURL->port;
+
+ if (!pContactURL->port_present) {
+ /* Set the IP-level destination ipaddr and port in the ccb */
+ dns_error_code = sipTransportGetServerAddrPort(pContactURL->host,
+ &cc_remote_ipaddr,
+ (uint16_t *) &ccb->dest_sip_port,
+ NULL, FALSE);
+ } else {
+ dns_error_code = dnsGetHostByName(pContactURL->host, &cc_remote_ipaddr, 100, 1);
+ }
+ if (dns_error_code == 0) {
+ util_ntohl(&(ccb->dest_sip_addr), &cc_remote_ipaddr);
+ } else {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sipTransportGetServerAddrPort or dnsGetHostByName()");
+
+ /*
+ * If DNS Lookup fails and there are more contacts, loop back up and try the next one.
+ * If we're out of contacts, then just release the call.
+ */
+ if (redirect_info->next_choice < SIP_MAX_LOCATIONS) {
+ continue;
+ } else {
+ sip_cc_release(ccb->gsm_id, ccb->dn_line, CC_CAUSE_ERROR, NULL);
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ }
+ return;
+ }
+
+ /*
+ * Get rid of transaction block for the ccb, we may have
+ * tried previous proxy in the Contact list
+ */
+ clean_method_request_trx(ccb, sipMethodInvite, TRUE);
+
+ /*
+ * Make new Req-URI and To values
+ */
+
+ temp = strstr(ccb->sip_to, ";tag");
+ to_length = (temp != NULL) ? (strlen(ccb->sip_to) - strlen(temp)) : MAX_SIP_URL_LENGTH;
+ if (to_length < MAX_SIP_URL_LENGTH) {
+ sstrncpy(stored_to_header, ccb->sip_to, to_length + 1);
+ } else {
+ sstrncpy(stored_to_header, ccb->sip_to, MAX_SIP_URL_LENGTH);
+ }
+
+ str_temp = strlib_open(ccb->sip_to, MAX_SIP_URL_LENGTH);
+ snprintf(str_temp, MAX_SIP_URL_LENGTH, "%s", stored_to_header);
+ ccb->sip_to = strlib_close(str_temp);
+
+ if (pContactURL->maddr) {
+ if (pContactURL->user) {
+ snprintf(ccb->ReqURI, MAX_SIP_URL_LENGTH,
+ "sip:%s%s%s@%s:%d;maddr=%s%s",
+ pContactURL->user,
+ (pContactURL->password ? ":" : ""),
+ (pContactURL->password ? pContactURL->password : ""),
+ pContactURL->host,
+ ccb->dest_sip_port,
+ pContactURL->maddr,
+ (pContactURL->is_phone ? ";user=phone" : ""));
+ } else {
+ snprintf(ccb->ReqURI, MAX_SIP_URL_LENGTH,
+ pContactURL->is_phone ? "sip:%s:%d;maddr=%s;user=phone"
+ : "sip:%s:%d;maddr=%s",
+ pContactURL->host, ccb->dest_sip_port,
+ pContactURL->maddr);
+ }
+ } else {
+ if (pContactURL->user) {
+ snprintf(ccb->ReqURI, MAX_SIP_URL_LENGTH,
+ "sip:%s%s%s@%s:%d%s",
+ pContactURL->user,
+ (pContactURL->password ? ":" : ""),
+ (pContactURL->password ? pContactURL->password : ""),
+ pContactURL->host,
+ ccb->dest_sip_port,
+ (pContactURL->is_phone ? ";user=phone" : ""));
+ } else {
+ snprintf(ccb->ReqURI, MAX_SIP_URL_LENGTH,
+ pContactURL->is_phone ? "sip:%s:%d;user=phone" : "sip:%s:%d",
+ pContactURL->host, ccb->dest_sip_port);
+ }
+ }
+
+
+ ccb->ReqURIOriginal = strlib_update(ccb->ReqURIOriginal, ccb->ReqURI);
+
+ ccb->sip_to_tag = strlib_update(ccb->sip_to_tag, ""); // Removing To Tag
+ ccb->authen.cred_type = 0;
+
+ ccb->last_recv_request_cseq = 0;
+ ccb->last_recv_request_cseq_method = sipMethodInvalid;
+
+ /*
+ * Send out a new INVITE
+ */
+ if (sipSPISendInvite(ccb, SIP_INVITE_TYPE_REDIRECTED, FALSE) == TRUE) {
+ sent_invite = TRUE;
+ } else {
+ status_code = SIP_1XX_TRYING;
+ }
+ }
+ return;
+
+}
+
+/*
+ * Function: parseAlertingHeader
+ *
+ * Parameters: ccb: call control block
+ * header: The Alert-Info header
+ *
+ * Description: Parses the alert-info header to
+ * determine if the value is a known
+ * internal ringer or tone.
+ *
+ * Note: Defaults to inside ring so that is what will be
+ * played if any errors are encountered
+ * during processing or if the header is not a
+ * recognized value.
+ *
+ */
+void
+parseAlertingHeader (ccsipCCB_t *ccb, const char *header)
+{
+ char alertHeader[MAX_SIP_URL_LENGTH];
+ char *pAlertHeader;
+ char *input = NULL;
+ unsigned int counter = 0;
+
+ /*
+ * Since alertHeader is a const char and
+ * we need to modify it, copy the header
+ * into a char * Easier to do this than
+ * modify SIP core to pass around a char *
+ */
+ sstrncpy(alertHeader, header, MAX_SIP_URL_LENGTH);
+ pAlertHeader = alertHeader;
+
+ /*
+ * Check for malformed url.
+ * Is opening < present?
+ */
+ if (*pAlertHeader == '<') {
+ pAlertHeader++;
+
+ /* Eat any leading white space */
+ while (isspace((int)*pAlertHeader)) {
+ pAlertHeader++;
+ }
+
+ /* Is trailing > present? */
+ input = pAlertHeader;
+ pAlertHeader = strchr(input, '>');
+ if (pAlertHeader != NULL) {
+ /*
+ * Overwrite > with NULL to terminate
+ * ringer name
+ */
+ *pAlertHeader = NUL;
+
+ /*
+ * Check input against the list of
+ * internal ringers. The bellcore
+ * ringers were added to the end of
+ * the ringer list so add the offset
+ * to match them up correctly
+ */
+ for (counter = 0; counter <= VCM_BELLCORE_MAX - VCM_RING_OFFSET; counter++) {
+ if (strstr(input, ring_names[counter]) != NULL) {
+ ccb->alert_info = ALERTING_RING;
+ ccb->alerting_ring = (vcm_ring_mode_t) (counter +
+ VCM_RING_OFFSET);
+ return;
+ }
+ }
+
+ /*
+ * Check input against the list of internal
+ * tones.
+ */
+ for (counter = 0; counter < VCM_MAX_DIALTONE; counter++) {
+ if (strstr(input, tone_names[counter]) != NULL) {
+ ccb->alert_info = ALERTING_TONE;
+ ccb->alerting_tone = (vcm_tones_t) counter;
+ return;
+ }
+ }
+ }
+ }
+
+ /*
+ * Error case. Malformed URL, external tone/ring pattern
+ * or unknown internal tone/ring pattern. Mimic old
+ * behavior.
+ */
+ ccb->alert_info = ALERTING_OLD;
+ ccb->alerting_ring = VCM_INSIDE_RING;
+}
+
+/*
+ * Function: ccsip_is_special_name_to_mask_display_number
+ *
+ * Parameters: name - name to be checked for special string.
+ *
+ * Description: The function checks the given name whether it matches
+ * a special display name or not. It is used to determined
+ * whether its associated number should be displayed or not.
+ *
+ * Return: TRUE - the given name is a special name.
+ * FALSE - the given name is not a special name.
+ */
+boolean
+ccsip_is_special_name_to_mask_display_number (const char *name)
+{
+ const char *special_string;
+
+ if (name == NULL) {
+ /* No name given ? */
+ return (FALSE);
+ }
+ /*
+ * Check for special name such as Conference or Barge. The CCM may
+ * sends string that is longer than the key words to match. Compare
+ * exactly (not even including NULL character).
+ */
+ special_string = platform_get_phrase_index_str(UI_CONFERENCE);
+ if ((cpr_strncasecmp(name, special_string, strlen(special_string)) == 0) ||
+ (cpr_strncasecmp(name, CONFERENCE_STR, CONFERENCE_STR_LEN) == 0)) {
+ return (TRUE);
+ }
+
+ /*
+ * The Barge 2 byte code is not in the phrase index table currently. Just
+ * use the define value.
+ */
+ if (cpr_strncasecmp(name, INDEX_STR_BARGE, 2) == 0) {
+ return (TRUE);
+ }
+
+ /*
+ * Detect private display name for restricted call party number.
+ */
+ if (cpr_strncasecmp(name, INDEX_STR_PRIVATE, 2) == 0) {
+ return (TRUE);
+ }
+
+ /*
+ * Detect monitoring display number.
+ */
+ if (cpr_strncasecmp(name, INDEX_STR_MONITORING, 2) == 0) {
+ return (TRUE);
+ }
+
+ /*
+ * Detect coaching display number.
+ */
+ if (cpr_strncasecmp(name, INDEX_STR_COACHING, 2) == 0) {
+ return (TRUE);
+ }
+
+ return (FALSE);
+}
+
+
+/*
+ * Function: unescape_UserInfo
+ *
+ * Parameters: esc_str: input escaped string containing "userinfo@host" or "userinfo"
+ * unesc_str: output unescaped string with escape chars unescaped
+ * unesc_str_len: length of unescaped string
+ * Description: Parses the input string to check if escaped chars are present and
+ * unescape them.
+ * Return: TRUE if escaped input exists and unescaped in output. Else FALSE.
+ *
+ * Note: -memory must be allocated by caller and freed as needed by caller. This
+ * function expects enough space for the string.
+ * -CSCsz30816: This function previously unescapes only up to @ and returns
+ * the unescaped data (along with the un-inspected host data). However,
+ * various usages in the code calls this with possible input string of
+ * "userinfo@host" or "userinfo" where "userinfo" could contain '@' which
+ * correctly needs not be escaped. Since the input is flexible as described,
+ * we've changed to escape the entire input string although the
+ * host portion, when present, should never has an escaped character anyway.
+ */
+
+static boolean
+unescape_UserInfo (const char *esc_str, char *unesc_str,
+ unsigned int unesc_str_len)
+{
+ char *user_info;
+
+ /* Look for esc char % in the provided string */
+ user_info = strpbrk(esc_str, "%");
+
+ if (user_info) {
+ if (unesc_str_len > strlen(esc_str)) {
+ unesc_str_len = strlen(esc_str);
+ }
+ sippmh_convertEscCharToChar(esc_str, unesc_str_len, unesc_str);
+ return TRUE;
+ }
+
+ return (FALSE);
+}
+
+/*
+ * Function: ccsip_identify_best_rpid
+ *
+ * Parameters: ccb: call control block
+ * calling: boolean value indicating if message is a
+ * request or response.
+ *
+ * Returns: boolean indicating if screened RPID found.
+ *
+ * Description: Identify the "best" Remote-Party-Id
+ * The top-most screened Remote-Party-ID header
+ * takes precedence. If none are screened, just
+ * use the top-most Remote-Party-Id header.
+ */
+static boolean
+ccsip_identify_best_rpid (ccsipCCB_t *ccb, boolean request)
+{
+ unsigned int j;
+ sipRemotePartyId_t *rpid;
+
+ ccb->best_rpid = ccb->rpid_info->rpid[0];
+
+ if (!ccb->best_rpid) {
+ return FALSE;
+ }
+
+ for (j = 0; j < ccb->rpid_info->num_rpid; j++) {
+ rpid = ccb->rpid_info->rpid[j];
+ if (rpid &&
+ // screen check is disabled so that mid call party updates can be displayed
+ //rpid->screen &&
+ //!cpr_strncasecmp(rpid->screen, SCREEN_YES, strlen(SCREEN_YES)) &&
+ rpid->loc->genUrl->schema == URL_TYPE_SIP) {
+ /* party_type check is disabled so that the phone is more liberal in what it accepts for RPID */
+ /*
+ * If RPID in a request, party must be set to calling.
+ * If RPID in a response, party must be set to called
+ */
+ //if (rpid->party_type) {
+ // if ((request && (!cpr_strncasecmp(rpid->party_type, PARTY_TYPE_CALLING,
+ // strlen(PARTY_TYPE_CALLING)))) ||
+ // (!request && (!cpr_strncasecmp(rpid->party_type, PARTY_TYPE_CALLED,
+ // strlen(PARTY_TYPE_CALLED)))))
+ // {
+ ccb->best_rpid = rpid;
+ return TRUE;
+ // }
+ //}
+ }
+ }
+ return FALSE;
+}
+
+static void
+ccsip_phrase_specifier (int16_t phrase, string_t * string, uint16_t len)
+{
+ char *temp_str;
+ char tmp_str[STATUS_LINE_MAX_LEN];
+
+ temp_str = strlib_open(*string, len);
+ if (temp_str) {
+ if (phrase == STR_INDEX_ANONYMOUS_SPACE) {
+ if ((platGetPhraseText(STR_INDEX_ANONYMOUS_SPACE,
+ (char *)tmp_str,
+ STATUS_LINE_MAX_LEN - 1)) == CPR_SUCCESS) {
+ sstrncpy(temp_str, tmp_str, len);
+ }
+ } else {
+ sstrncpy(temp_str, platform_get_phrase_index_str(phrase), len);
+ }
+ }
+ *string = strlib_close(temp_str);
+}
+
+/*
+ * Function: ccsip_check_set_privacy_screen
+ *
+ * Parameters:
+ * name : name returned here based on privacy and screen
+ * number : number returned here based on privacy and screen
+ * input_name: input name
+ * input_num: input number
+ * privacy: privacy
+ * screen: screen information
+ * connected_party: indicates that name/number are of the
+ * called/calling party
+ *
+ * Returns: TRUE if Number should be private
+ *
+ * Description: This function checkes privacy and screen information
+ * and based on that name and number parameter is calculated.
+ *
+ * Note: To align with SCCP display the number is not displayed if
+ * it is private. The Java UI code does not display anything
+ * if the string is an empty string. So at the beginning of
+ * the function set the number to "" and only update the number
+ * string if the number is to be displayed. In the case where
+ * the name and number represent the calling or called party,
+ * we need to provide the number to GSM in the event that this
+ * is the consultative call leg of an xfer. The xfer state machine
+ * requires a DN in order to complete the xfer. The connected_party
+ * boolean indicates whether the name/number are from the
+ * called or calling party.
+ */
+static boolean
+ccsip_check_set_privacy_screen (string_t *name, string_t *number,
+ char *input_name, char *input_num,
+ char *privacy, char *screen,
+ boolean connected_party)
+{
+ char *name_str;
+ boolean number_private = FALSE;
+
+ /* Initialize to empty required by UI */
+ *name = strlib_update(*name, "");
+
+ *number = strlib_update(*number, "");
+
+ if (!privacy || cpr_strncasecmp(privacy, PRIVACY_FULL, sizeof(PRIVACY_FULL)) == 0) {
+ /* Ignore screen parameter now
+ * (cpr_strcasecmp(screen, SCREEN_NO) == 0)) {
+ */
+ ccsip_phrase_specifier(UI_PRIVATE, name, MAX_SIP_DISPLAYNAME_LENGTH);
+ if (connected_party) {
+ /*
+ * name/number from connected party. number is required.
+ */
+ ccsip_phrase_specifier(STR_INDEX_ANONYMOUS_SPACE, number,
+ MAX_SIP_URL_LENGTH * 2);
+ }
+ return TRUE;
+ }
+
+ if (cpr_strncasecmp(privacy, PRIVACY_URI, sizeof(PRIVACY_URI)) == 0) {
+
+ if ((input_name != NULL) && (*input_name != NUL)) {
+ *name = strlib_update(*name, input_name);
+ } else {
+ ccsip_phrase_specifier(UI_UNKNOWN, name, MAX_SIP_DISPLAYNAME_LENGTH);
+ }
+ if (connected_party) {
+ /*
+ * name/number from connected party. number is required.
+ */
+ ccsip_phrase_specifier(STR_INDEX_ANONYMOUS_SPACE, number,
+ MAX_SIP_URL_LENGTH * 2);
+ }
+ number_private = TRUE;
+ } else if (cpr_strncasecmp(privacy, PRIVACY_NAME, sizeof(PRIVACY_NAME)) == 0) {
+
+ if (input_num) {
+ *number = strlib_update(*number, input_num);
+ }
+ ccsip_phrase_specifier(UI_PRIVATE, name, MAX_SIP_DISPLAYNAME_LENGTH);
+
+ } else {
+
+ if ((input_name != NULL) && (*input_name != NUL)) {
+ *name = strlib_update(*name, input_name);
+ } else {
+ if (!input_num || (*input_num == NUL)) {
+ ccsip_phrase_specifier(UI_UNKNOWN, name, MAX_SIP_DISPLAYNAME_LENGTH);
+ }
+ }
+
+ if (input_num) {
+ *number = strlib_update(*number, input_num);
+ }
+ }
+
+ name_str = strlib_open(*name, MAX_SIP_DISPLAYNAME_LENGTH);
+ if (name_str) {
+ sip_sm_dequote_string(name_str, MAX_SIP_DISPLAYNAME_LENGTH);
+ }
+ *name = strlib_close(name_str);
+ return number_private;
+}
+
+/*
+ * Function: ccsip_parse_diversion_header
+ *
+ * Parameters: ccb: call control block
+ * msg: SIP message to examine for RPID header
+ *
+ * Returns: boolean
+ *
+ * Description: Diversion header is used when the call is forwarded to this
+ * number. There are 2 different items that are extracted from diversion
+ * header, 1) originally called party 2) last redirecting party.
+ * On the Screen originally called party is shown as "By:.." and
+ * last redirecting party is shown as "From:..."
+ */
+static boolean
+ccsip_parse_diversion_header (ccsipCCB_t *ccb, sipMessage_t *msg)
+{
+ char *diversion_headers[MAX_DIVERSION_HEADERS];
+ unsigned int diversion_count;
+ sipDiversion_t *diversion_header;
+
+ /*
+ * Free up previous diversion header info.
+ */
+ sippmh_free_diversion_info(ccb->div_info);
+
+ ccb->div_info = (sipDiversionInfo_t *)
+ cpr_malloc(sizeof(sipDiversionInfo_t));
+
+ if (!ccb->div_info) {
+ return FALSE;
+ }
+
+ memset(ccb->div_info, 0, sizeof(sipDiversionInfo_t));
+ memset(diversion_headers, 0, MAX_DIVERSION_HEADERS * sizeof(char *));
+
+ ccb->div_info->last_redirect_name = strlib_empty();
+ ccb->div_info->last_redirect_number = strlib_empty();
+ ccb->div_info->orig_called_name = strlib_empty();
+ ccb->div_info->orig_called_number = strlib_empty();
+
+
+ diversion_count = sippmh_get_num_particular_headers(msg,
+ SIP_HEADER_DIVERSION,
+ SIP_HEADER_DIVERSION,
+ diversion_headers,
+ MAX_DIVERSION_HEADERS);
+
+ if (diversion_count < 1) {
+ return FALSE;
+ }
+
+ ccb->call_type = CC_CALL_FORWARDED;
+
+ /* We need 1st and last diversion headers only */
+ diversion_header = sippmh_parse_diversion(diversion_headers[0], SIP_HEADER_DIVERSION);
+
+ if (diversion_header) {
+ (void) ccsip_check_set_privacy_screen(&(ccb->div_info->last_redirect_name),
+ &(ccb->div_info->last_redirect_number),
+ diversion_header->locations->name,
+ diversion_header->locations->genUrl->u.sipUrl->user,
+ diversion_header->privacy,
+ diversion_header->screen, FALSE);
+
+ sippmh_free_diversion(diversion_header);
+ }
+
+ /* Parse last diversion header */
+ diversion_header = sippmh_parse_diversion(diversion_headers[diversion_count - 1],
+ SIP_HEADER_DIVERSION);
+
+ if (diversion_header) {
+ (void) ccsip_check_set_privacy_screen(&(ccb->div_info->orig_called_name),
+ &(ccb->div_info->orig_called_number),
+ diversion_header->locations->name,
+ diversion_header->locations->genUrl->u.sipUrl->user,
+ diversion_header->privacy,
+ diversion_header->screen, FALSE);
+
+ sippmh_free_diversion(diversion_header);
+ }
+
+ return TRUE;
+}
+
+/*
+ * Function: ccsip_parse_rpid
+ *
+ * Parameters: ccb: call control block
+ * msg: SIP message to examine for RPID header
+ *
+ * Returns: boolean
+ *
+ * Description: Gets number of RPID headers from the SIP message,
+ * parses each RPID header, and sets the parsed RPID
+ * header into the CCB.
+ */
+static boolean
+ccsip_parse_rpid (ccsipCCB_t *ccb, sipMessage_t *msg)
+{
+ char *rpid_headers[MAX_REMOTE_PARTY_ID_HEADERS];
+ unsigned int rpid_line_count;
+ const char *rpid_str = NULL;
+ unsigned int j;
+
+ /*
+ * Free up the previous RPID info and its associated data before,
+ * parsing a new one.
+ */
+ sippmh_free_remote_party_id_info(ccb->rpid_info);
+ ccb->best_rpid = NULL;
+ ccb->rpid_info = (sipRemotePartyIdInfo_t *)
+ cpr_malloc(sizeof(sipRemotePartyIdInfo_t));
+ if (!ccb->rpid_info) {
+ return FALSE;
+ }
+
+ /* Parse Remote-Party-ID */
+ memset(ccb->rpid_info, 0, sizeof(sipRemotePartyIdInfo_t));
+ memset(rpid_headers, 0, MAX_REMOTE_PARTY_ID_HEADERS * sizeof(char *));
+
+ rpid_line_count = sippmh_get_num_particular_headers(msg,
+ SIP_HEADER_REMOTE_PARTY_ID,
+ SIP_HEADER_REMOTE_PARTY_ID,
+ rpid_headers,
+ MAX_REMOTE_PARTY_ID_HEADERS);
+
+ if (rpid_line_count < 1) {
+ return FALSE;
+ }
+
+ for (j = 0; (j < rpid_line_count) && (j < MAX_REMOTE_PARTY_ID_HEADERS); j++) {
+ rpid_str = rpid_headers[j];
+ if ((rpid_str) && (rpid_str[0])) {
+ ccb->rpid_info->rpid[j] = sippmh_parse_remote_party_id(rpid_str);
+ }
+ }
+ ccb->rpid_info->num_rpid = rpid_line_count;
+ return TRUE;
+}
+
+
+/*
+ * Function: ccsip_set_url_domain
+ *
+ * Parameters: host: domain name from SIP header to be checked
+ * callingNumber: calling number to receive appended domain
+ * calledNumber: the called (destination) number
+ * line: line used for outbound call. 0 if inbound call.
+ *
+ * Returns: string_t: The updated calling number string
+ *
+ * Description: Determines if host string received in a SIP URL should
+ * be appended to the calling number for UI display and
+ * storage in the missed/received calls directory.
+ * Domain from the receive SIP URL will be appended to the
+ * calling number under the following conditions.
+ * 1. Received domain is FQDN and receiving line's proxy address
+ * is a dotted ip address.
+ * 2. Received domain is FQDN and receiving line's proxy address
+ * is a FQDN that differs from the received domain.
+ * 3. If received domain is dotted ip, it is NOT appended to
+ * the calling number under any condtion.
+ *
+ */
+static string_t ccsip_set_url_domain (char *host, string_t callingNumber, string_t calledNumber, line_t line)
+{
+ char *target;
+ char addr_error;
+ uint32_t address;
+ char buffer[MAX_SIP_URL_LENGTH];
+ boolean include_domain = FALSE;
+
+ if (host == NULL) {
+ return callingNumber;
+ }
+
+ /*
+ * First check if host is dotted ip.
+ */
+ address = IPNameCk(host, &addr_error);
+ if (!address) {
+ /*
+ * Host is not a dotted ip. Treat as a domain name.
+ * Validate the domain name and then compare the domain name
+ * to what is configured for the line.
+ */
+ target = cpr_strdup(host);
+ if (target != NULL) {
+ if (sipSPI_validate_hostname(target)) {
+ /*
+ * Get proxy address config for the receiving line. Need to first determine
+ * the line based on the called number.
+ */
+ if (line == 0) {
+ /*
+ * Incoming call, line needs to be dermined based on the called number.
+ * Otherwise, this is an outbound call and the line was provided by GSM.
+ */
+ line = sip_config_get_line_by_called_number(1, calledNumber);
+ }
+
+ if (line == 0) {
+ /*
+ * Line not found based on called number. This call will be released by
+ * GSM. Use full URL until release occurs.
+ */
+ include_domain = TRUE;
+ } else {
+ buffer[0] = '\0';
+ config_get_line_string(CFGID_PROXY_ADDRESS, buffer, line, MAX_SIP_URL_LENGTH);
+ address = IPNameCk(buffer, &addr_error);
+ if (address) {
+ /* Configured domain is dotted ip. */
+ include_domain = TRUE;
+ } else {
+ if (strncmp(host, buffer, MAX_SIP_URL_LENGTH) != 0) {
+ /*
+ * Configured domain differs from received domain
+ */
+ include_domain = TRUE;
+ }
+ }
+ }
+ if (include_domain == TRUE) {
+ callingNumber = strlib_append(callingNumber, "@");
+ callingNumber = strlib_append(callingNumber, host);
+ }
+ }
+ cpr_free(target);
+ }
+ }
+ return callingNumber;
+}
+
+/*
+ * Function: ccsip_set_alt_callback_number
+ *
+ * Parameters: ccb: call control block
+ *
+ * Returns: char *: pointer to alt_callback_number.
+ *
+ * Description: Checks to see the x-cisco-callback-number params
+ * Copies the value to ccb->altCallingNumber
+ *
+ * assumes ccb->best_rpid->loc->genUrl valid
+ */
+
+void ccsip_set_alt_callback_number(ccsipCCB_t *ccb)
+{
+ int param_idx=0;
+ char *ptr;
+
+ while ( (ptr = ccb->best_rpid->loc->genUrl->other_params[param_idx++]) != NULL )
+ {
+ if ( ! strncasecmp ( ptr, RPID_CALLBACK, RPID_CALLBACK_LEN)) {
+ ccb->altCallingNumber =
+ strlib_update(ccb->altCallingNumber, ptr + RPID_CALLBACK_LEN);
+ return;
+ }
+ }
+
+ ccb->altCallingNumber = strlib_update(ccb->altCallingNumber, "");
+}
+
+/*
+ * Function: ccsip_set_caller_id_from_rpid
+ *
+ * Parameters: ccb: call control block
+ * calling: boolean value indicating if message is a
+ * request or response.
+ * display_enabled: boolean indicating if callerid is blocked.
+ *
+ * Returns: boolean: TRUE indicates call id was obtained from RPID.
+ *
+ * Description: Determines if RPID support is enabled. If so, uses utilities
+ * to parse out the RPID header(s) and identifies the best
+ * RPID header to use for UI updates. Depending on the direction
+ * of the call (inbound or outbound) and the RPID parameter
+ * settings (privacy, screen), sets the calling/called display
+ * name and number of the CCB based on the RPID.
+ */
+static boolean
+ccsip_set_caller_id_from_rpid (ccsipCCB_t *ccb, boolean request, boolean update_ccb, boolean *display_enabled)
+{
+ int rpid_flag = RPID_DISABLED;
+ char *sip_rpid_user = NULL;
+ char *pUser = NULL;
+ string_t *name;
+ string_t *number;
+ boolean display_number = TRUE;
+ boolean private_num = FALSE;
+ line_t line = 0;
+
+
+ *display_enabled = TRUE;
+
+ /* If RPID is not enabled in config, return */
+ config_get_value(CFGID_REMOTE_PARTY_ID, &rpid_flag, sizeof(rpid_flag));
+ if (rpid_flag == RPID_DISABLED) {
+ return FALSE;
+ }
+
+ /* If a screened RPID is not found, return */
+ if (!ccsip_identify_best_rpid(ccb, request)) {
+ return FALSE;
+ }
+
+ if (ccb->flags & INCOMING) {
+ name = &ccb->callingDisplayName;
+ number = &ccb->callingNumber;
+ } else {
+ name = &ccb->calledDisplayedName;
+ number = &ccb->calledNumber;
+ line = ccb->dn_line;
+ }
+
+ sip_rpid_user = ccb->best_rpid->loc->genUrl->u.sipUrl->user;
+
+ pUser = sippmh_parse_user(sip_rpid_user);
+ if (pUser) {
+ sip_rpid_user = pUser;
+ }
+
+ private_num = ccsip_check_set_privacy_screen(name, number,
+ ccb->best_rpid->loc->name,
+ sip_rpid_user,
+ ccb->best_rpid->privacy,
+ ccb->best_rpid->screen,
+ TRUE);
+
+ /*
+ * This check is used to determine if the calling/called number should be displayed.
+ * This is true in 2 cases.If privacy=full or privacy=uri. We do not currently check
+ * for privacy=name.
+ */
+ if (private_num) {
+ /*
+ * Need to distinguish between privacy=uri and privacy=full
+ */
+ if (cpr_strncasecmp(ccb->best_rpid->privacy, PRIVACY_FULL, sizeof(PRIVACY_FULL)) == 0) {
+ /*
+ * This is used for anonymous call block
+ */
+ *display_enabled = display_number = FALSE;
+ } else {
+ /*
+ * Just used for blocking the calling/called number display
+ */
+ display_number = FALSE;
+ }
+ }
+
+ /*
+ * Update the alt Calling number if received in the RPID
+ */
+ if ( (!private_num) )
+ {
+ ccsip_set_alt_callback_number(ccb);
+ }
+
+ /*
+ * Append host portion of url if needed. If in CCM mode, skip this step.
+ * We hardcode to check line 1. If line 1 is in CCM mode, all lines are CCM mode.
+ */
+ if (sip_regmgr_get_cc_mode(1) == REG_MODE_NON_CCM) {
+ *number = ccsip_set_url_domain(ccb->best_rpid->loc->genUrl->u.sipUrl->host, *number,
+ ccb->calledNumber, line);
+ }
+
+ if (pUser) {
+ cpr_free(pUser);
+ }
+
+
+ if (update_ccb) {
+ if (ccb->flags & INCOMING) {
+ ccb->displayCallingNumber = display_number;
+ } else {
+ ccb->displayCalledNumber = display_number;
+ }
+ }
+
+ return TRUE;
+}
+/*
+ * Function: ccsip_send_callinfo
+ *
+ * Parameters: ccb: call control block
+ * update_caller_id: boolean indicates caller ID updating.
+ * delay_update: indicates that the call info. event sent
+ * to GSM to update UI can be delayed.
+ *
+ * Returns: void
+ *
+ * Description: The internal function used to send GSM call info.
+ */
+static void
+ccsip_send_callinfo (ccsipCCB_t *ccb, boolean update_caller_id,
+ boolean delay_update)
+{
+ cc_feature_data_t data;
+ char unescape_str_temp[MAX_SIP_URL_LENGTH];
+ const char *name;
+ const char *number;
+ const char *altNumber = strlib_empty();
+ boolean display_number;
+
+ if (!ccb->in_call_info) {
+ data.call_info.feature_flag = 0;
+ data.call_info.security = CC_SECURITY_UNKNOWN;
+ data.call_info.policy = CC_POLICY_UNKNOWN;
+ if (ccb->flags & INCOMING) {
+ data.call_info.orientation = CC_ORIENTATION_FROM;
+ } else {
+ data.call_info.orientation = CC_ORIENTATION_TO;
+ }
+ data.call_info.ui_state = CC_UI_STATE_NONE;
+ data.call_info.dusting = FALSE;
+ data.call_info.global_call_id[0] = 0;
+ } else {
+ cc_feature_data_call_info_t *feat_data = &ccb->in_call_info->data.call_info_feat_data;
+
+ data.call_info.feature_flag = feat_data->feature_flag;
+ data.call_info.security = feat_data->security;
+ data.call_info.policy = feat_data->policy;
+ data.call_info.orientation = feat_data->orientation;
+ data.call_info.ui_state = feat_data->ui_state;
+ data.call_info.caller_id.call_instance_id = feat_data->caller_id.call_instance_id;
+ data.call_info.dusting = feat_data->dusting;
+ sstrncpy(data.call_info.global_call_id,
+ ccb->in_call_info->data.call_info_feat_data.global_call_id, CC_GCID_LEN);
+ }
+
+ data.call_info.caller_id.orig_rpid_number = strlib_empty();
+ if (!update_caller_id) {
+ data.call_info.feature_flag &= ~CC_CALLER_ID;
+ data.call_info.caller_id.called_name = strlib_empty();
+ data.call_info.caller_id.called_number = strlib_empty();
+ data.call_info.caller_id.calling_name = strlib_empty();
+ data.call_info.caller_id.calling_number = strlib_empty();
+ data.call_info.caller_id.alt_calling_number = strlib_empty();
+ } else {
+ data.call_info.feature_flag |= CC_CALLER_ID;
+ if (ccb->flags & INCOMING) {
+ /* Convert escaped userinfo in the URL to unescaped form */
+ if (unescape_UserInfo(ccb->callingDisplayName, unescape_str_temp,
+ MAX_SIP_URL_LENGTH)) {
+ ccb->callingDisplayName = strlib_update(ccb->callingDisplayName,
+ unescape_str_temp);
+ }
+ if (unescape_UserInfo(ccb->callingNumber, unescape_str_temp,
+ MAX_SIP_URL_LENGTH)) {
+ ccb->callingNumber = strlib_update(ccb->callingNumber,
+ unescape_str_temp);
+ }
+ name = ccb->callingDisplayName;
+ number = ccb->callingNumber;
+ strlib_free(altNumber);
+ altNumber = ccb->altCallingNumber;
+ display_number = ccb->displayCallingNumber;
+ } else {
+ /* Convert escaped userinfo in the URL to unescaped form */
+ if (unescape_UserInfo(ccb->calledDisplayedName, unescape_str_temp,
+ MAX_SIP_URL_LENGTH)) {
+ ccb->calledDisplayedName = strlib_update(ccb->calledDisplayedName,
+ unescape_str_temp);
+ }
+ if (unescape_UserInfo(ccb->calledNumber, unescape_str_temp,
+ MAX_SIP_URL_LENGTH)) {
+ ccb->calledNumber = strlib_update(ccb->calledNumber,
+ unescape_str_temp);
+ }
+ name = ccb->calledDisplayedName;
+ number = ccb->calledNumber;
+ display_number = ccb->displayCalledNumber;
+ }
+
+ if (data.call_info.orientation == CC_ORIENTATION_FROM) {
+ data.call_info.caller_id.calling_name = name;
+ data.call_info.caller_id.calling_number = number;
+ data.call_info.caller_id.alt_calling_number = altNumber;
+ data.call_info.caller_id.display_calling_number = display_number;
+
+ data.call_info.caller_id.called_name = strlib_empty();
+ data.call_info.caller_id.called_number = strlib_empty();
+ data.call_info.caller_id.display_called_number = FALSE;
+ } else {
+ data.call_info.caller_id.called_name = name;
+ data.call_info.caller_id.called_number = number;
+ data.call_info.caller_id.display_called_number = display_number;
+
+ data.call_info.caller_id.calling_name = strlib_empty();
+ data.call_info.caller_id.calling_number = strlib_empty();
+ data.call_info.caller_id.alt_calling_number = strlib_empty();
+ data.call_info.caller_id.display_calling_number = FALSE;
+ if(ccb->best_rpid != NULL && ccb->best_rpid->loc->genUrl->u.sipUrl->user != NULL)
+ data.call_info.caller_id.orig_rpid_number = (const char *) ccb->best_rpid->loc->genUrl->u.sipUrl->user;
+ }
+ }
+
+ /* Include diversion information
+ * Note that a valid ccb->div_info pointer here does not indicate that call is of
+ * type Forward. It simply means a call to parse diversion header had been made.
+ */
+ if (ccb->div_info) {
+ data.call_info.caller_id.last_redirect_name = ccb->div_info->last_redirect_name;
+ data.call_info.caller_id.last_redirect_number = ccb->div_info->last_redirect_number;
+ data.call_info.caller_id.orig_called_name = ccb->div_info->orig_called_name;
+ data.call_info.caller_id.orig_called_number = ccb->div_info->orig_called_number;
+ } else {
+ data.call_info.caller_id.last_redirect_name = strlib_empty();
+ data.call_info.caller_id.last_redirect_number = strlib_empty();
+ data.call_info.caller_id.orig_called_name = strlib_empty();
+ data.call_info.caller_id.orig_called_number = strlib_empty();
+ }
+ data.call_info.caller_id.call_type = ccb->call_type;
+
+ /* Set UP update delay flag */
+ data.call_info.feature_flag &= ~(CC_DELAY_UI_UPDATE);
+ if (delay_update) {
+ data.call_info.feature_flag |= CC_DELAY_UI_UPDATE;
+ }
+ data.call_info.callref = ccb->callref;
+ sip_cc_feature(ccb->gsm_id, ccb->dn_line, CC_FEATURE_CALLINFO, &data);
+}
+
+/*
+ * Function: ccsip_update_callinfo
+ *
+ * Parameters: ccb: call control block
+ * msg: SIP message to examine for RPID
+ * calling: boolean value indicating if message is a
+ * request or response.
+ * delay_update: indicates that the call info. event sent
+ * to GSM to update UI can be delayed.
+ *
+ * Returns: void
+ *
+ * Description: Utility function used by the various SIP state handlers
+ * to pull RPID and callinfo data from a received SIP message and set the
+ * call info fields (called/calling name and number fields, security,
+ * orientation, ui-state) of the CCB. A call info feature indication
+ * is sent to the GSM to update the phone UI display.
+ */
+static void
+ccsip_update_callinfo (ccsipCCB_t *ccb, sipMessage_t *msg, boolean check_rpid,
+ boolean request, boolean delay_update)
+{
+ boolean update_caller_id = FALSE;
+ boolean display_number = TRUE;
+
+ if (!msg) {
+ return;
+ }
+
+ if (check_rpid) {
+ if (ccsip_parse_rpid(ccb, msg)) {
+ if (ccsip_set_caller_id_from_rpid(ccb, request, TRUE, &display_number)) {
+ update_caller_id = TRUE;
+ }
+ }
+ }
+
+ ccsip_process_call_info_header(msg, ccb);
+
+ ccsip_send_callinfo(ccb, update_caller_id, delay_update);
+}
+
+/*
+ * Function: ccsip_check_display_validity
+ *
+ * Parameters: ccb: call control block
+ * reuqest: sip message
+ *
+ * Returns: boolean
+ * True - Display valid
+ * False - Display not valid
+ *
+ * Description: Check if anonymous call block feature is enabled
+ * against privacy settings received in the RPID and
+ * make a decision if the call can continue
+ */
+static boolean
+ccsip_check_display_validity(ccsipCCB_t *ccb, sipMessage_t *request)
+{
+ int temp = 0;
+ boolean display_number = TRUE;
+ /*
+ * Check for Anonymous call blocking. If low bit is set,
+ * then do not allow call. Note that we must allow both upper and lowercase
+ * ANON strings, hence the use of strcasestr
+ */
+ config_get_value(CFGID_ANONYMOUS_CALL_BLOCK, &temp, sizeof(temp));
+ if (temp & 1) {
+ if (ccsip_parse_rpid(ccb, request)) {
+ if (ccsip_set_caller_id_from_rpid(ccb, TRUE, FALSE, &display_number)) {
+ if (!display_number) {
+ return FALSE;
+ }
+ }
+ }
+ }
+ return TRUE;
+}
+/*
+ *
+ ***** SIP_STATE_IDLE
+ *
+ */
+void
+ccsip_handle_idle_ev_sip_invite (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ const char *fname = "idle_ev_sip_invite";
+ char *callingDisplayNameTemp;
+ char *sip_to_tag_temp;
+ char *sip_to_temp;
+ sipMessage_t *request;
+ const char *from = NULL;
+ const char *to = NULL;
+ const char *callID = NULL;
+ const char *contact = NULL;
+ const char *record_route = NULL;
+ const char *expires = NULL;
+ const char *alert_info = NULL, *allow = NULL;
+ const char *require = NULL, *supported = NULL;
+ char *replaceshdr = NULL;
+ sipReplaces_t *replaces_t = NULL;
+ sipLocation_t *to_loc = NULL;
+ sipLocation_t *from_loc = NULL;
+ sipUrl_t *sipFromUrl = NULL;
+ sipUrl_t *sipToUrl = NULL;
+ uint32_t local_expires_timeout = 0;
+ int delta = 0;
+ uint16_t request_check_reason_code = 0;
+ char request_check_reason_phrase[SIP_WARNING_LENGTH];
+ uint32_t gmt_time;
+ uint32_t diff_time;
+ int32_t gmt_rc;
+ callid_t cc_call_id = CC_NO_CALL_ID;
+ ccsipCCB_t *refererccb = NULL;
+ ccsipCCB_t *replaces_ccb = NULL;
+ line_t dn_line;
+ sipsdp_status_t sdp_status;
+ boolean check_send_487 = FALSE;
+ char unescape_str_temp[MAX_SIP_URL_LENGTH];
+ boolean display_number = FALSE;
+ string_t recv_info_list = strlib_empty();
+
+ /* Unpack the event */
+ request = event->u.pSipMessage;
+
+ /* Request check and store */
+ if (sip_sm_request_check_and_store(ccb, request, sipMethodInvite, FALSE,
+ &request_check_reason_code,
+ request_check_reason_phrase, FALSE) < 0) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ ccb->index, ccb->dn_line, fname,
+ get_debug_string(DEBUG_FUNCTIONNAME_SIP_SM_REQUEST_CHECK_AND_STORE));
+ (void) sipSPISendErrorResponse(request, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ request_check_reason_code,
+ request_check_reason_phrase, NULL);
+ free_sip_message(request);
+ ccb->wait_for_ack = TRUE;
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ return;
+ }
+
+ ccb->flags |= INCOMING;
+
+ /* To: and From: header */
+ from = sippmh_get_cached_header_val(request, FROM);
+ ccb->sip_from = strlib_update(ccb->sip_from, from);
+ to = sippmh_get_cached_header_val(request, TO);
+ ccb->sip_to = strlib_update(ccb->sip_to, to);
+
+ /* CallID: header */
+ callID = sippmh_get_cached_header_val(request, CALLID);
+ sstrncpy(ccb->sipCallID, callID, sizeof(ccb->sipCallID));
+
+ /* Require: header */
+ require = sippmh_get_cached_header_val(request, REQUIRE);
+ if (require) {
+ char *unsupported_tokens = NULL;
+
+ ccb->required_tags = sippmh_parse_supported_require(require,
+ &unsupported_tokens);
+
+ if (unsupported_tokens != NULL) {
+ ccb->sip_unsupported = strlib_update(ccb->sip_unsupported,
+ unsupported_tokens);
+ cpr_free(unsupported_tokens);
+ }
+
+ if (ccb->required_tags & (~(SUPPORTED_TAGS))) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Unsupported Require Header in INVITE\n", fname);
+ ccb->sip_require = strlib_update(ccb->sip_require, require);
+ sipSPISendInviteResponse(ccb, SIP_CLI_ERR_EXTENSION,
+ SIP_CLI_ERR_EXTENSION_PHRASE,
+ 0, NULL,
+ FALSE, /* no SDP */ TRUE /* reTx */);
+ ccb->wait_for_ack = TRUE;
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ return;
+ }
+ }
+
+ /* Supported: header */
+ supported = sippmh_get_cached_header_val(request, SUPPORTED);
+ if (supported) {
+ ccb->supported_tags = sippmh_parse_supported_require(supported, NULL);
+ }
+
+ /* Allow: header */
+ allow = sippmh_get_header_val(request, SIP_HEADER_ALLOW, NULL);
+ if (allow) {
+ ccb->allow_methods = sippmh_parse_allow_header(allow);
+ }
+
+ /* Contact: header */
+ contact = sippmh_get_cached_header_val(request, CONTACT);
+ if (contact) {
+ if (ccb->contact_info) {
+ sippmh_free_contact(ccb->contact_info);
+ }
+ ccb->contact_info = sippmh_parse_contact(contact);
+
+ if ((ccb->contact_info == NULL) || // contact in msg, parse error
+ (sipSPICheckContact(contact) < 0)) { // If contact is invalid
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ ccb->index, ccb->dn_line, fname,
+ "sipSPICheckContact()");
+ (void) sipSPISendErrorResponse(request, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ SIP_WARN_MISC,
+ SIP_CLI_ERR_BAD_REQ_CONTACT_FIELD,
+ ccb);
+ ccb->wait_for_ack = TRUE;
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ return;
+ }
+ }
+
+ /* Record-Route: header */
+ record_route = sippmh_get_cached_header_val(request, RECORD_ROUTE);
+ if (record_route) {
+ if (ccb->record_route_info) {
+ sippmh_free_record_route(ccb->record_route_info);
+ }
+ ccb->record_route_info = sippmh_parse_record_route(record_route);
+ if (ccb->record_route_info == NULL) {
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ ccb->index, ccb->dn_line, fname,
+ "sippmh_parse_record_route()");
+ (void) sipSPISendErrorResponse(request, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ SIP_WARN_MISC,
+ SIP_CLI_ERR_BAD_REQ_RECORD_ROUTE,
+ ccb);
+ ccb->wait_for_ack = TRUE;
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ return;
+ }
+ }
+ // Save received URI in ReqURIOriginal
+ ccb->ReqURIOriginal = strlib_update(ccb->ReqURIOriginal, ccb->ReqURI);
+
+ /* Parse RPID header */
+ (void) ccsip_parse_rpid(ccb, request);
+
+
+ /* Parse Diversion header */
+ (void) ccsip_parse_diversion_header(ccb, request);
+
+ /*
+ * Parse From
+ */
+ from_loc = sippmh_parse_from_or_to((char *)ccb->sip_from, TRUE);
+ if (!from_loc) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ ccb->index, ccb->dn_line, fname,
+ get_debug_string(DEBUG_FUNCTIONNAME_SIPPMH_PARSE_FROM));
+ sipSPISendInviteResponse(ccb, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ SIP_WARN_MISC,
+ SIP_CLI_ERR_BAD_REQ_FROMURL_ERROR,
+ FALSE, /* no SDP */ TRUE /* reTx */);
+ ccb->wait_for_ack = TRUE;
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ return;
+ }
+ if (from_loc->tag && (strlen(from_loc->tag) >= MAX_SIP_TAG_LENGTH)) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED), ccb->index,
+ ccb->dn_line, fname, "Length of From Tag");
+ sipSPISendInviteResponse(ccb, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ SIP_WARN_MISC,
+ SIP_CLI_ERR_BAD_REQ_FROMURL_ERROR,
+ FALSE, /* no SDP */ TRUE /* reTx */);
+ sippmh_free_location(from_loc);
+ ccb->wait_for_ack = TRUE;
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ return;
+ }
+
+ if (from_loc->genUrl->schema == URL_TYPE_SIP) {
+ sipFromUrl = from_loc->genUrl->u.sipUrl;
+ }
+
+ /*
+ * Parse To
+ */
+ to_loc = sippmh_parse_from_or_to((char *)ccb->sip_to, TRUE);
+ if (!to_loc) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ ccb->index, ccb->dn_line, fname,
+ get_debug_string(DEBUG_FUNCTIONNAME_SIPPMH_PARSE_TO));
+ sipSPISendInviteResponse(ccb, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ SIP_WARN_MISC,
+ SIP_CLI_ERR_BAD_REQ_ToURL_ERROR,
+ FALSE, /* no SDP */ TRUE /* reTx */);
+ sippmh_free_location(from_loc);
+ ccb->wait_for_ack = TRUE;
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ return;
+ }
+
+ if (to_loc->genUrl->schema == URL_TYPE_SIP) {
+ sipToUrl = to_loc->genUrl->u.sipUrl;
+ }
+ // Check/Generate tags
+ if (to_loc->tag) {
+ /* ccb->sip_to_tag = strlib_update(ccb->sip_to_tag,
+ * sip_sm_purify_tag(to_loc->tag));
+ */
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ ccb->index, ccb->dn_line, fname,
+ "Initial invite with to_tag");
+ sipSPISendInviteResponse(ccb, SIP_CLI_ERR_CALLEG,
+ SIP_CLI_ERR_CALLEG_PHRASE,
+ 0, NULL,
+ FALSE, /* no SDP */ TRUE /* reTx */);
+ sippmh_free_location(to_loc);
+ sippmh_free_location(from_loc);
+ ccb->wait_for_ack = TRUE;
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ return;
+
+ } else {
+ sip_to_tag_temp = strlib_open(ccb->sip_to_tag, MAX_SIP_TAG_LENGTH);
+ if (sip_to_tag_temp) {
+ sip_util_make_tag(sip_to_tag_temp);
+ }
+ ccb->sip_to_tag = strlib_close(sip_to_tag_temp);
+
+ sip_to_temp = strlib_open(ccb->sip_to, MAX_SIP_URL_LENGTH);
+ if (sip_to_temp) {
+ sstrncat(sip_to_temp, ";tag=",
+ MAX_SIP_URL_LENGTH - strlen(sip_to_temp));
+ if (ccb->sip_to_tag) {
+ sstrncat(sip_to_temp, ccb->sip_to_tag,
+ MAX_SIP_URL_LENGTH - strlen(sip_to_temp));
+ }
+ }
+ ccb->sip_to = strlib_close(sip_to_temp);
+ }
+
+ if (from_loc->tag) {
+ ccb->sip_from_tag = strlib_update(ccb->sip_from_tag,
+ sip_sm_purify_tag(from_loc->tag));
+ ccb->callref = get_callref(ccb->sip_from_tag);
+ }
+
+ if (ccb->ReqURI) {
+ ccb->calledNumber = strlib_update(ccb->calledNumber, ccb->ReqURI);
+ } else if (sipToUrl) {
+ if (sipToUrl->user) {
+ char *pUser = NULL;
+
+ pUser = sippmh_parse_user(sipToUrl->user);
+ if (pUser && (pUser[0] != '\0')) {
+ ccb->calledNumber = strlib_update(ccb->calledNumber, pUser);
+ cpr_free(pUser);
+ } else {
+ /* An error occurred, copy the whole thing.. */
+ ccb->calledNumber = strlib_update(ccb->calledNumber,
+ sipToUrl->user);
+ if (pUser)
+ cpr_free(pUser);
+ }
+ }
+ }
+
+ /*
+ * Make sure we have a valid called_number.
+ */
+ if ((ccb->calledNumber == NULL) || (ccb->calledNumber[0] == '\0')) {
+ (void) sipSPISendErrorResponse(request, SIP_CLI_ERR_NOT_FOUND,
+ SIP_CLI_ERR_NOT_FOUND_PHRASE,
+ 0, NULL, ccb);
+
+ sip_cc_release_complete(ccb->gsm_id, ccb->dn_line, CC_CAUSE_NORMAL);
+ ccb->wait_for_ack = FALSE;
+ sip_sm_change_state(ccb, SIP_STATE_IDLE);
+ sip_sm_call_cleanup(ccb);
+ return;
+ }
+
+ if (!ccsip_set_caller_id_from_rpid(ccb, TRUE, TRUE, &display_number)) {
+ if (sipFromUrl) {
+ if (sipFromUrl->user) {
+ char *pUser;
+
+ pUser = sippmh_parse_user(sipFromUrl->user);
+ if (pUser) {
+ ccb->callingNumber = strlib_update(ccb->callingNumber, pUser);
+ cpr_free(pUser);
+ } else {
+ /* An error occurred, copy the whole thing.. */
+ ccb->callingNumber = strlib_update(ccb->callingNumber, sipFromUrl->user);
+ }
+ if (from_loc->genUrl->schema == URL_TYPE_SIP &&
+ sipFromUrl->host &&
+ ccb->callingNumber &&
+ sip_regmgr_get_cc_mode(1) == REG_MODE_NON_CCM) {
+ /*
+ * If we have a host name, calling number, and are not in CCM mode,
+ * check to see if the domain should be appended to the calling number
+ * for display to the user.
+ */
+ ccb->callingNumber = ccsip_set_url_domain(sipFromUrl->host, ccb->callingNumber,
+ ccb->calledNumber, 0);
+ }
+ } else {
+ ccb->callingNumber = strlib_update(ccb->callingNumber,
+ "Unknown Number");
+ }
+ }
+
+ if (from_loc->name) {
+ callingDisplayNameTemp = strlib_open(ccb->callingDisplayName,
+ MAX_SIP_DISPLAYNAME_LENGTH);
+ if (callingDisplayNameTemp) {
+ sstrncpy(callingDisplayNameTemp, from_loc->name,
+ MAX_SIP_DISPLAYNAME_LENGTH);
+ sip_sm_dequote_string(callingDisplayNameTemp, MAX_SIP_DISPLAYNAME_LENGTH);
+ }
+ ccb->callingDisplayName = strlib_close(callingDisplayNameTemp);
+
+ } else {
+ char *pUser;
+
+ pUser = NULL;
+ if (sipFromUrl) {
+ pUser = sippmh_parse_user(sipFromUrl->user);
+ }
+
+ if (pUser) {
+ ccb->callingDisplayName = strlib_update(ccb->callingDisplayName,
+ pUser);
+ cpr_free(pUser);
+ } else {
+ /* An error occurred, copy the whole thing.. */
+ if (sipFromUrl) {
+ if (sipFromUrl->user) {
+ ccb->callingDisplayName = strlib_update(ccb->callingDisplayName,
+ sipFromUrl->user);
+ }
+ }
+ }
+ }
+ }
+
+ sippmh_free_location(to_loc);
+ sippmh_free_location(from_loc);
+
+ // If there is a Replace aheader then it must be a Transfer request
+ // Store the call_id of the other call so that we can release the call when
+ // we get 200 OK on consultation call
+ (void) sippmh_get_num_particular_headers(request, SIP_HEADER_REPLACES,
+ NULL, &replaceshdr, MAX_REPLACES_HEADERS);
+ ccb->wastransferred = FALSE;
+
+
+ dn_line = ccb->dn_line;
+
+ if ((Basic_is_phone_forwarded(dn_line) == NULL) && NULL != replaceshdr) {
+ char tempreplace[MAX_SIP_URL_LENGTH];
+ boolean is_previous_call_id = FALSE;
+ line_t previous_call_index = 0;
+
+ memset(tempreplace, 0, MAX_SIP_URL_LENGTH);
+ sstrncpy(tempreplace, "Replaces=", sizeof(tempreplace));
+ sstrncat(tempreplace, replaceshdr, (sizeof(tempreplace) - sizeof("Replaces=")));
+ replaces_t = sippmh_parse_replaces(tempreplace, FALSE);
+ if (NULL != replaces_t) {
+ //Check if a call exists that matches the callid, to and from tags found in the replaces header
+ if ((cpr_strcasecmp(replaces_t->toTag, ccb->sip_to_tag)==0
+ && cpr_strcasecmp(replaces_t->fromTag, ccb->sip_from_tag)==0
+ && cpr_strcasecmp(replaces_t->callid, ccb->sipCallID)==0) ||
+ ((refererccb = sip_sm_get_ccb_by_callid(replaces_t->callid)) != NULL
+ && cpr_strcasecmp(replaces_t->toTag, refererccb->sip_to_tag) == 0
+ && cpr_strcasecmp(replaces_t->fromTag, refererccb->sip_from_tag) == 0)) {
+ ccb->sipxfercallid = strlib_update(ccb->sipxfercallid, replaces_t->callid);
+ sippmh_free_replaces(replaces_t);
+ ccb->wastransferred = TRUE;
+ check_send_487 = TRUE;
+ } else {
+ is_previous_call_id = sip_sm_is_previous_call_id(replaces_t->callid,
+ &previous_call_index);
+ replaces_ccb = sip_sm_get_ccb_by_callid(replaces_t->callid);
+ if (replaces_ccb != NULL && replaces_ccb->state == SIP_STATE_RELEASE) {
+ is_previous_call_id = TRUE;
+ CCSIP_DEBUG_STATE("%s: Replaces Header, matching call found. \n", fname);
+ }
+ if (is_previous_call_id) {
+ // The Callid refers to a previous call
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ ccb->index, ccb->dn_line, fname,
+ "Replaces Header, Callid refers to a previous call");
+ sipSPISendInviteResponse(ccb, SIP_FAIL_DECLINE,
+ SIP_FAIL_DECLINE_PHRASE,
+ 0, NULL,
+ FALSE, /* no SDP */ TRUE /* reTx */);
+
+ } else {
+ // Could not find a matching call. If the CFWD is disabled
+ // send back the error. If it is enabled, it will be processed
+ // below.
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ ccb->index, ccb->dn_line, fname,
+ "Replaces Header, No matching call found");
+ sipSPISendInviteResponse(ccb, SIP_CLI_ERR_CALLEG,
+ SIP_CLI_ERR_CALLEG_PHRASE,
+ 0, NULL,
+ FALSE, /* no SDP */ TRUE /* reTx */);
+ }
+ ccb->wait_for_ack = TRUE;
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ sippmh_free_replaces(replaces_t);
+ return;
+ }
+ } else {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ ccb->index, ccb->dn_line, fname,
+ "Bad Replaces Header, Ending transferred call");
+ sipSPISendInviteResponse(ccb, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ SIP_WARN_MISC,
+ SIP_CLI_ERR_BAD_REQ_PHRASE_REPLACES,
+ FALSE, /* no SDP */ TRUE /* reTx */);
+ ccb->wait_for_ack = TRUE;
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ return;
+
+ }
+ }
+
+ /*
+ * Extract SDP
+ */
+ sdp_status = sip_util_extract_sdp(ccb, request);
+
+ switch (sdp_status) {
+ case SIP_SDP_SUCCESS:
+ case SIP_SDP_SESSION_AUDIT:
+ ccb->oa_state = OA_OFFER_RECEIVED;
+ break;
+
+ case SIP_SDP_DNS_FAIL:
+ sipSPISendInviteResponse(ccb, SIP_SERV_ERR_INTERNAL,
+ SIP_SERV_ERR_INTERNAL_PHRASE,
+ SIP_WARN_MISC,
+ "DNS lookup failed for media destination",
+ FALSE, FALSE);
+ ccb->wait_for_ack = TRUE;
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ return;
+
+ case SIP_SDP_ERROR:
+ sipSPISendInviteResponse(ccb, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ SIP_WARN_MISC,
+ SIP_CLI_ERR_BAD_REQ_SDP_ERROR,
+ FALSE, /* no SDP */ TRUE /* reTx */);
+ ccb->wait_for_ack = TRUE;
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ return;
+
+ case SIP_SDP_NO_MEDIA:
+ sipSPISendInviteResponse(ccb, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ SIP_WARN_MISC,
+ SIP_CLI_ERR_BAD_REQ_SDP_ERROR,
+ FALSE, /* no SDP */ TRUE /* reTx */);
+ ccb->wait_for_ack = TRUE;
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ return;
+
+ case SIP_SDP_NOT_PRESENT:
+ default:
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX"Waiting for SDP in ACK\n", DEB_F_PREFIX_ARGS(SIP_SDP, fname));
+ break;
+ }
+
+
+ /* see if we are forwarded to another location */
+ if (Basic_is_phone_forwarded(dn_line)) {
+ size_t escaped_char_str_len = 8;
+ char pDiversionStr[MAX_SIP_URL_LENGTH];
+ int len = 0;
+ int blocking;
+ boolean private_flag = FALSE;
+ char line_name[MAX_LINE_NAME_SIZE];
+ char display_name[MAX_LINE_NAME_SIZE];
+ char src_addr_str[MAX_IPADDR_STR_LEN];
+
+
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_ENTRY),
+ ccb->index, ccb->dn_line, fname,
+ "Call forwarded, sending redirect");
+
+ ccb->dn_line = dn_line;
+ /*
+ * If Caller ID Blocking is OFF or emergency route is ON,
+ * set private to TRUE. Otherwise, FALSE.
+ */
+ config_get_value(CFGID_CALLERID_BLOCKING, &blocking, sizeof(blocking));
+ if ((blocking & 1) && (ccb->routeMode != RouteEmergency)) {
+ private_flag = TRUE;
+ }
+
+ /*
+ * Diversion Header format:
+ * "display_name" ;reason=unconditional;
+ * privacy="full" or "off";screen=yes
+ */
+ config_get_string((CFGID_LINE_NAME + ccb->dn_line - 1), line_name, sizeof(line_name));
+ sip_config_get_display_name(ccb->dn_line, display_name, sizeof(display_name));
+ ipaddr2dotted(src_addr_str, &ccb->src_addr);
+ snprintf(pDiversionStr, MAX_SIP_URL_LENGTH, "\"%s\" ;reason=unconditional;privacy=%s;screen=yes",
+ src_addr_str, (private_flag ? "full" : "off"));
+
+ len = strlen(pDiversionStr);
+ ccb->diversion[0] = (char *) cpr_malloc(len + 1);
+
+ if (ccb->diversion[0]) {
+ sstrncpy(ccb->diversion[0], pDiversionStr, len + 1);
+ } else {
+ CCSIP_DEBUG_ERROR(DEB_L_C_F_PREFIX "No memory left; %d"
+ "Can not create CC-Diversion header for CFWDAll\n",
+ ccb->dn_line, ccb->gsm_id, fname, ccb->index);
+ }
+ sipSPISendInviteResponse302(ccb);
+ ccb->wait_for_ack = TRUE;
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ return;
+ }
+
+ /*
+ * Start Local Expires timer
+ */
+ expires = sippmh_get_header_val(request, SIP_HEADER_EXPIRES, NULL);
+ config_get_value(CFGID_TIMER_INVITE_EXPIRES, &local_expires_timeout,
+ sizeof(local_expires_timeout));
+ if (expires) {
+//CPR TODO: need reference for
+ gmt_rc = gmt_string_to_seconds((char *)expires, (unsigned long *)&gmt_time);
+ if (gmt_rc != -1) {
+ // We only want to update the expires timeout if it is lower
+ // than our predefined threshold. We don't want to allow people
+ // to keep us hung up for infinite periods of time
+ if (gmt_rc == 1) {
+ // We got a numeric entry in the expires field
+ if (gmt_time < local_expires_timeout) {
+ local_expires_timeout = gmt_time;
+ }
+//CPR TODO: need reference for
+ } else if (diff_current_time(gmt_time, (unsigned long *) &diff_time) == 0) {
+ // We got a GMT string in the expires field
+ if (diff_time < local_expires_timeout) {
+ local_expires_timeout = diff_time;
+ }
+ }
+ }
+ } else {
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_ENTRY),
+ ccb->index, ccb->dn_line, fname,
+ "Using config timer_expires");
+ }
+
+ if (local_expires_timeout > 0) {
+ config_get_value(CFGID_TIMER_T1, &delta, sizeof(delta));
+ delta = (2 * delta) / 1000;
+ CCSIP_DEBUG_STATE(DEB_L_C_F_PREFIX"Starting INVITE Local Expires %d"
+ "timer (%d sec)\n",
+ DEB_L_C_F_PREFIX_ARGS(SIP_TIMER, ccb->dn_line, ccb->gsm_id, fname),
+ ccb->index, local_expires_timeout + delta);
+ /*
+ * Add delta to the Expires timer so that the callee gives the
+ * caller a chance to send out the CANCEL message before sending
+ * out a 408 INVITE response.
+ */
+ (void) sip_platform_localexpires_timer_start((local_expires_timeout + delta) * 1000,
+ ccb->index, &(ccb->dest_sip_addr),
+ (uint16_t) ccb->dest_sip_port);
+ }
+
+ /* check for alert-info in header */
+ alert_info = sippmh_get_header_val(request, SIP_HEADER_ALERT_INFO, NULL);
+ ccb->alert_info = ALERTING_NONE;
+ if (alert_info) {
+ parseAlertingHeader(ccb, alert_info);
+ }
+
+ /* check for and process call-info in header */
+ ccsip_process_call_info_header(request, ccb);
+
+ /*
+ * Parse join info if it exists and get
+ * the gsm id for the join target call
+ */
+ if (ccsip_get_join_info(ccb, request) == FALSE) {
+ /*
+ * There was something wrong with the joinhdr
+ * or join target call is not active
+ */
+ sipSPISendInviteResponse(ccb, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ SIP_WARN_MISC,
+ SIP_CLI_ERR_BAD_REQ_FROMURL_ERROR,
+ FALSE, /* no SDP */ TRUE /* reTx */);
+ ccb->wait_for_ack = TRUE;
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ return;
+ }
+
+ sipSPISendInviteResponse100(ccb, TRUE);
+
+ /* Inform CSM */
+ cc_call_id = cc_get_new_call_id();
+ ccb->gsm_id = cc_call_id;
+ // send XFER Request
+ if (ccb->wastransferred) {
+ refererccb = sip_sm_get_ccb_by_callid(ccb->sipxfercallid);
+ if (NULL != refererccb) {
+ cc_feature_data_t data;
+
+ data.xfer.method = CC_XFER_METHOD_REFER;
+ data.xfer.cause = CC_CAUSE_XFER_REMOTE;
+ data.xfer.target_call_id = cc_call_id;
+ data.xfer.dialstring[0] = '\0';
+ sip_cc_feature(refererccb->gsm_id, refererccb->dn_line,
+ CC_FEATURE_XFER, (void *) &data);
+ }
+ }
+
+ if (refererccb == NULL) {
+ dn_line = ccb->dn_line;
+ } else {
+ dn_line = refererccb->dn_line;
+ }
+
+ /* Convert escaped userinfo in the URL to unescaped form */
+ if (unescape_UserInfo(ccb->calledNumber, unescape_str_temp, MAX_SIP_URL_LENGTH)) {
+ ccb->calledNumber = strlib_update(ccb->calledNumber, unescape_str_temp);
+ }
+
+ if (unescape_UserInfo(ccb->callingNumber, unescape_str_temp, MAX_SIP_URL_LENGTH)) {
+ ccb->callingNumber = strlib_update(ccb->callingNumber, unescape_str_temp);
+ }
+
+ if (unescape_UserInfo(ccb->callingDisplayName, unescape_str_temp, MAX_SIP_URL_LENGTH)) {
+ ccb->callingDisplayName = strlib_update(ccb->callingDisplayName, unescape_str_temp);
+ }
+
+ if (unescape_UserInfo(ccb->altCallingNumber, unescape_str_temp, MAX_SIP_URL_LENGTH)) {
+ ccb->altCallingNumber = strlib_update(ccb->altCallingNumber, unescape_str_temp);
+ }
+
+ /* Info Package stuff */
+ ccsip_parse_send_info_header(request, &recv_info_list);
+
+
+
+ if (ccb->wastransferred) {
+ sip_cc_setup(cc_call_id, dn_line,
+ ccb->callingDisplayName,
+ ccb->callingNumber,
+ ccb->altCallingNumber,
+ ccb->displayCallingNumber,
+ ccb->calledDisplayedName,
+ ccb->calledNumber,
+ ccb->displayCalledNumber,
+ ccb->div_info->orig_called_name,
+ ccb->div_info->orig_called_number,
+ ccb->div_info->last_redirect_name,
+ ccb->div_info->last_redirect_number,
+ ccb->call_type,
+ ccb->alert_info, ccb->alerting_ring,
+ ccb->alerting_tone, ccb->in_call_info, TRUE,
+ recv_info_list, request);
+ } else {
+ sip_cc_setup(cc_call_id, dn_line,
+ ccb->callingDisplayName,
+ ccb->callingNumber,
+ ccb->altCallingNumber,
+ ccb->displayCallingNumber,
+ ccb->calledDisplayedName,
+ ccb->calledNumber,
+ ccb->displayCalledNumber,
+ ccb->div_info->orig_called_name,
+ ccb->div_info->orig_called_number,
+ ccb->div_info->last_redirect_name,
+ ccb->div_info->last_redirect_number,
+ ccb->call_type,
+ ccb->alert_info, ccb->alerting_ring,
+ ccb->alerting_tone, ccb->in_call_info, FALSE,
+ recv_info_list, request);
+ }
+
+ strlib_free(recv_info_list);
+
+ sip_sm_change_state(ccb, SIP_STATE_RECV_INVITE);
+
+ if (check_send_487) {
+ /* check to see if we need to send a 487 back to original Invite
+ * that replaces this call. If it is not connected yet, send the
+ * 487 and release the call to GSM.
+ */
+ ccsipCCB_t *other_ccb;
+
+ other_ccb = sip_sm_get_ccb_by_callid(ccb->sipxfercallid);
+ if ((other_ccb != NULL) &&
+ ((other_ccb->state >= SIP_STATE_RECV_INVITE) &&
+ (other_ccb->state < SIP_STATE_RECV_INVITE_CONNECTED))) {
+ sipSPISendInviteResponse(other_ccb, SIP_CLI_ERR_REQ_CANCEL,
+ SIP_CLI_ERR_REQ_CANCEL_PHRASE, 0, NULL,
+ FALSE /* no SDP */ , TRUE /* reTx */);
+ sip_cc_release(other_ccb->gsm_id, other_ccb->dn_line,
+ CC_CAUSE_NORMAL, NULL);
+ other_ccb->wait_for_ack = TRUE;
+ sip_sm_change_state(other_ccb, SIP_STATE_RELEASE);
+ }
+ }
+}
+
+/*
+ * This function is called when one of the following occurs:
+ *
+ * 1) Attempting to send out an INVITE and for whatever reason
+ * the call to get the IP address for the main proxy fails.
+ * 2) An ICMP unreachable event is received and there are no
+ * more DNS entries for the main proxy.
+ * 3) Retries have been exhausted on the main proxy and there
+ * are no more DNS entries for the main proxy.
+ */
+boolean
+ccsip_attempt_backup_proxy (ccsipCCB_t *ccb)
+{
+ char ip_addr_str[MAX_IPADDR_STR_LEN];
+ cpr_ip_addr_t ipaddr;
+ int tempPort = 0;
+ char tmp_str[STATUS_LINE_MAX_LEN];
+
+ CPR_IP_ADDR_INIT(ipaddr);
+ /*
+ * Get IPAddress and Port for backup proxy
+ */
+ sipTransportGetBkupServerAddress(&ipaddr, ccb->dn_line, ip_addr_str);
+ if (util_check_if_ip_valid(&ipaddr)) {
+ util_ntohl(&(ccb->dest_sip_addr), &ipaddr);
+
+ /*
+ * If the Proxy Backup Port isn't contained in the
+ * config table, use the PROXYN port instead.
+ */
+ tempPort = sipTransportGetBkupServerPort(ccb->dn_line);
+ if (tempPort != 0) {
+ ccb->dest_sip_port = tempPort;
+ } else {
+ ccb->dest_sip_port = sipTransportGetPrimServerPort(ccb->dn_line);
+ }
+
+ ccb->proxySelection = SIP_PROXY_BACKUP;
+
+ /* Note counter must be at least 2 or better to work as directed
+ * This count is decremented by one on each successful response to
+ * an invite. If we receive backup_active successful responses to
+ * an invite go back to the max retry count on the main or primary proxy.
+ * Why 12 you ask. Depending on the number of SIP messages received per
+ * call this equates to maybe 4 phone calls before going back to
+ * the full re-try count on the primary/main proxy.
+ */
+ gGlobInfo.backup_active = 12;
+
+ /*
+ * Let user know we have failed over to backup proxy
+ */
+ if ((platGetPhraseText(STR_INDEX_PROXY_UNAVAIL,
+ (char *)tmp_str,
+ STATUS_LINE_MAX_LEN - 1)) == CPR_SUCCESS) {
+ ui_set_call_status(tmp_str, ccb->dn_line, ccb->gsm_id);
+ }
+ return (TRUE);
+ }
+
+ return (FALSE);
+}
+
+/**
+ * This fucntion sends mid-call INVITE.
+ *
+ * @param[in] ccb Pointer to ccsipCCB_t structure.
+ * @param[in] hold_initiated boolean indicating whther this is
+ * a mid-call INVITE for HOLD feature.
+ *
+ * @pre (ccb not_eq NULL)
+ *
+ * @return true or false
+ */
+boolean
+send_resume_or_hold_request (ccsipCCB_t *ccb, boolean hold_initiated)
+{
+ ccb->authen.cred_type = 0;
+ ccb->authen.new_flag = TRUE;
+ ccb->hold_initiated = hold_initiated;
+ if (sipSPISendInviteMidCall(ccb, FALSE /* doesn't expire */) != TRUE) {
+ return FALSE;
+ }
+ /* Pre-fill the ARP table */
+ ADD_TO_ARP_CACHE(ccb->dest_sip_addr);
+ return TRUE;
+}
+
+void
+ccsip_handle_idle_ev_cc_setup (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ const char *fname = "idle_ev_cc_setup";
+ char *dialString;
+ char *referred_by_blind;
+ uint32_t dialStringLength = 0;
+ char *calledNumberTemp;
+ char *outputString = NULL;
+ uint32_t usernameLength = 0;
+ char *hostnameString = NULL;
+ uint32_t hostnameLength = 0;
+ char proxy_ipaddr_str[MAX_IPADDR_STR_LEN];
+ cpr_ip_addr_t proxy_ipaddr;
+
+ char *extraString = NULL;
+ uint32_t extraLength = 0;
+ uint32_t n = 0;
+ static char dialtranslate[MAX_SIP_URL_LENGTH];
+ char temp[MAX_IPADDR_STR_LEN];
+ char line_name[MAX_LINE_NAME_SIZE];
+ int port;
+ boolean sendInvite = FALSE;
+ char *tmpPtr = NULL;
+ cpr_ip_type ip_type = CPR_IP_ADDR_IPV4;
+ boolean replace = FALSE;
+
+ CPR_IP_ADDR_INIT(proxy_ipaddr);
+
+ ccb->gsm_id = event->u.cc_msg->msg.setup.call_id;
+ ccb->dn_line = event->u.cc_msg->msg.setup.line;
+
+ /*
+ * Handlle replace info if there is any before taking in any
+ * dial string.
+ */
+ if (ccsip_is_replace_setup(event->u.cc_msg->msg.setup.replaces)) {
+ replace = TRUE;
+ if (!ccsip_set_replace_info(ccb, &event->u.cc_msg->msg.setup)) {
+ /* The replace info failed */
+ sip_cc_release(ccb->gsm_id, ccb->dn_line, CC_CAUSE_ERROR, NULL);
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX"ignore setup, no replace info for"
+ " replace setup request\n", DEB_F_PREFIX_ARGS(SIP_REP, fname));
+ return;
+ }
+ }
+
+ ccsip_set_join_info(ccb, &event->u.cc_msg->msg.setup);
+
+ dialString = (char *) event->u.cc_msg->msg.setup.caller_id.called_number;
+ referred_by_blind = event->u.cc_msg->msg.setup.redirect.redirects[0].number;
+ dialStringLength = strlen(dialString);
+ if ((0 == dialStringLength) && !replace) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"No Digits to dial", fname);
+ sip_cc_release(ccb->gsm_id, ccb->dn_line, CC_CAUSE_ERROR, NULL);
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ return;
+ } else if (!dialStringLength && replace) {
+ dialString = (char *) event->u.cc_msg->msg.setup.caller_id.calling_number;
+ dialStringLength = strlen(dialString);
+ }
+
+ /*
+ * Save away what they sent us so that we can display it to them later
+ *
+ * Note: Currently only dialString which is obtained from
+ * event->u.cc_msg->msg.setup.caller_id.called_number is needed
+ * by SIP stack. Make a duplicate copy of the field. If more
+ * fields are needed from the caller_id from the setup msg.
+ * then the better use of the cc_mv_caller_id() API to move
+ * caller IDs from the setup to local storage is more efficient.
+ */
+ ccb->calledDisplayedName = strlib_update(ccb->calledDisplayedName,
+ dialString);
+
+ memset(proxy_ipaddr_str, 0, MAX_IPADDR_STR_LEN);
+ memset(temp, 0, sizeof(temp));
+
+
+ sip_util_get_new_call_id(ccb);
+ ccb->featuretype = CC_FEATURE_NONE;
+ /*
+ * Get the listen port from the Transport Interface
+ * instead of the direct config.
+ */
+ ccb->local_port = sipTransportGetListenPort(ccb->dn_line, ccb);
+
+ /*
+ * Normalize the name. This means adding u.cc_msg->msg.setup.redirect.redirects[0].number[0] != '\0') {
+ ccb->sip_referredBy = strlib_update(ccb->sip_referredBy,
+ referred_by_blind);
+ ccb->blindtransferred = TRUE;
+ }
+ if (event->u.cc_msg->msg.setup.redirect.redirects[0].number[0] != '\0') {
+ strlib_free(event->u.cc_msg->msg.setup.redirect.redirects[0].number);
+ }
+
+ /*
+ * See if the string needs to be rewritten by applying the dial template
+ */
+ ccb->routeMode = RouteDefault;
+
+#define CAST_N (int32_t *)
+
+ (void) MatchDialTemplate(ccb->calledDisplayedName, ccb->dn_line, CAST_N & n, dialtranslate,
+ sizeof(dialtranslate), (RouteMode *) & (ccb->routeMode), NULL);
+ dialString = dialtranslate;
+ dialStringLength = strlen(dialString);
+
+ /*
+ * Throw away any display name part before LAQUOT(<), if there is one
+ * Ex: "Test Test" - Display string is "Test Test"
+ * Ex: Test Test - Display string is "Test Test"
+ * Ex: - No Display string
+ * Ex: sip:31@172.18.192.230 - No Display string
+ * Ex: 31@172.18.192.230 - No Display string
+ *
+ * the last two examples have no LAQUOT and RAQUOT in them
+ *
+ */
+
+ tmpPtr = strchr(dialString, '<');
+ if (tmpPtr) {
+ dialString = tmpPtr;
+ dialStringLength = strlen(dialString);
+ }
+
+ /*
+ * Throw away any part of 0) && (dialString[0] == '<')) {
+ dialString++;
+ dialStringLength--;
+ }
+
+ /*
+ * For the SIP: part, we have to have 4 characters
+ */
+ if (!cpr_strncasecmp(dialString, "sip:", 4)) {
+ dialStringLength -= 4;
+ dialString += 4;
+ }
+
+ /*
+ * Parse the remainder of the string looking for the host name
+ */
+ for (n = 0; n <= dialStringLength; n++) {
+ /*
+ * If we hit the end of the string without encountering a ; or >
+ * then we want to put the entire string into the user name if
+ * no host name was encountered or if we found a '@' along the
+ * way we want to put the residual into the host name
+ */
+ if (n == dialStringLength) {
+ if (hostnameString == NULL) {
+ usernameLength = n;
+ } else {
+ hostnameLength = n - usernameLength - 1; //Accounts for @
+ }
+ } else if ((dialString[n] == '@') && (hostnameString == NULL)) {
+ /*
+ * We encountered an @ separator for the host name, so take
+ * everything before the @ and put it into the user name
+ */
+ usernameLength = n;
+ hostnameString = dialString + n + 1;
+ } else if ((dialString[n] == ';') || (dialString[n] == '>')) {
+ /*
+ * We hit the separator character (; or >). Take what we have
+ * seen and append it to the host name (if we already saw the @)
+ * or to the user name if not
+ */
+ if (hostnameString == NULL) {
+ usernameLength = n;
+ } else {
+ hostnameLength = n - usernameLength - 1; // Accounts for @
+ }
+ extraString = dialString + n;
+ extraLength = dialStringLength - n;
+ break;
+ }
+ }
+ /*
+ * At this point we have
+ * usernameLength - Number of characters in the user name
+ * starting from dialString[0]
+ * hostnameString - NULL if no @ was encountered, otherwise it
+ * points to the start of the host name string
+ * hostnameLength - 0 if no host name characters were encountered
+ * extraString - Points to any extra parameters
+ * extraLength - number of extra parameter characters
+ */
+ switch (ccb->routeMode) {
+ case RouteEmergency:{
+ /*
+ * If we have failed over to the backup we need
+ * to not reselect the emergency proxy
+ */
+ if (ccb->proxySelection != SIP_PROXY_BACKUP) {
+ // Get the Emergency Proxy
+ sipTransportGetEmerServerAddress(ccb->dn_line, proxy_ipaddr_str);
+ if (hostnameLength == 0) {
+ hostnameString = proxy_ipaddr_str;
+ hostnameLength = strlen(proxy_ipaddr_str);
+ }
+ if (proxy_ipaddr_str[0]) {
+ if (!str2ip((const char *)proxy_ipaddr_str, &proxy_ipaddr)) {
+ /* Fill in address and port in CCB */
+ util_ntohl(&(ccb->dest_sip_addr), &proxy_ipaddr);
+ /*
+ * If the Proxy Emergency Port isn't contained in the
+ * config table, use the PROXYN port instead.
+ */
+ port = sipTransportGetEmerServerPort(ccb->dn_line);
+ if (port) {
+ ccb->dest_sip_port = (uint32_t)port;
+ } else {
+ ccb->dest_sip_port = sipTransportGetPrimServerPort(ccb->dn_line);
+ }
+ break;
+ }
+ }
+ }
+ // Otherwise Emergency proxy is not in configuration follow thru. Let
+ // static analysis know this is intentional
+ /*FALLTHROUGH*/}
+ default:
+ ip_type = sipTransportGetPrimServerAddress(ccb->dn_line, temp);
+ if (hostnameLength == 0) {
+ hostnameString = temp;
+ hostnameLength = strlen(hostnameString);
+ }
+ sipTransportGetServerIPAddr(&(ccb->dest_sip_addr),ccb->dn_line);
+ if (util_check_if_ip_valid(&(ccb->dest_sip_addr))) {
+ ccb->dest_sip_port = sipTransportGetPrimServerPort(ccb->dn_line);
+ } else {
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Unable to reach proxy, attempting backup.\n",
+ DEB_F_PREFIX_ARGS(SIP_PROXY, fname));
+ if (!ccsip_attempt_backup_proxy(ccb)) {
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Attempt to reach backup proxy failed.\n",
+ DEB_F_PREFIX_ARGS(SIP_PROXY, fname));
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"INVITE will be broadcast.\n",
+ DEB_F_PREFIX_ARGS(SIP_PROXY, fname));
+ }
+ }
+ }
+
+ /* Pre-fill the ARP table */
+ ADD_TO_ARP_CACHE(ccb->dest_sip_addr);
+
+ /*
+ * Construct the actual dial out string
+ */
+ calledNumberTemp = strlib_open(ccb->calledNumber, (MAX_SIP_URL_LENGTH * 2));
+ outputString = calledNumberTemp;
+ sstrncpy(outputString, "
+ */
+ outputString[extraLength] = 0;
+ /*
+ * If there was no > in what they gave us, put one in for them
+ */
+ if (strchr(outputString, '>') == NULL) {
+ outputString[extraLength++] = '>';
+ }
+ outputString += extraLength;
+ } else {
+ *outputString++ = '>';
+ }
+ /*
+ * Null terminate the string for good measure and note how long it is
+ */
+ *outputString = 0;
+ ccb->calledNumber = strlib_close(calledNumberTemp);
+ if (ccb->calledNumber) {
+ ccb->calledNumberLen = (uint16_t) strlen(ccb->calledNumber);
+ }
+
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX"All digits collected. Placing the call\n",
+ DEB_F_PREFIX_ARGS(SIP_CALL_STATUS, fname));
+ config_get_line_string(CFGID_LINE_NAME, line_name, ccb->dn_line, sizeof(line_name));
+ ccb->callingNumber = strlib_update(ccb->callingNumber, line_name);
+
+ CCSIP_DEBUG_STATE(DEB_L_C_F_PREFIX"SIPSM %d: Setup\n",
+ DEB_L_C_F_PREFIX_ARGS(SIP_CALL_STATUS, ccb->dn_line, ccb->gsm_id, fname), ccb->index);
+
+ /* Copy the call-info into the CCB */
+ ccsip_store_call_info(&event->u.cc_msg->msg.setup.call_info, ccb);
+
+ /* Send INVITE */
+
+ /* Save the GSM's msg. bodies for future used */
+ ccsip_save_local_msg_body(ccb, &event->u.cc_msg->msg.setup.msg_body);
+
+ /*
+ * CC_REDIRECT_REASON_DEFLECTION shows that this is an attended transfer
+ */
+ // Note that the extra body parts will be automatically deleted
+ if (event->u.cc_msg->msg.setup.redirect.redirects[0].redirect_reason
+ == CC_REDIRECT_REASON_DEFLECTION) {
+ sendInvite = sipSPISendInvite(ccb, SIP_INVITE_TYPE_TRANSFER, TRUE);
+ } else {
+ sendInvite = sipSPISendInvite(ccb, SIP_INVITE_TYPE_NORMAL, TRUE);
+ }
+
+ if (sendInvite == TRUE) {
+ sip_sm_change_state(ccb, SIP_STATE_SENT_INVITE);
+ } else {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"sipSPISendInvite failed", fname);
+ if (event->u.cc_msg->msg.setup.redirect.redirects[0].redirect_reason
+ == CC_REDIRECT_REASON_DEFLECTION) {
+ /*
+ * Sending replaces invite for attended transfer has failed.
+ * Clean up here because a release complete from GSM
+ * is not guaranteed here like in the case of pre-mature
+ * attended transfer request. A cause value of normal
+ * causes GSM to clean up the UI as well.
+ */
+ sip_cc_release(ccb->gsm_id, ccb->dn_line, CC_CAUSE_NORMAL, NULL);
+ sip_sm_call_cleanup(ccb);
+ } else {
+ sip_cc_release(ccb->gsm_id, ccb->dn_line, CC_CAUSE_ERROR, NULL);
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ }
+
+ }
+
+}
+
+
+/*
+ *
+ ***** SIP_STATE_SENT_INVITE
+ *
+ */
+void
+ccsip_handle_sentinvite_ev_sip_1xx (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ const char *fname = "sentinvite_ev_sip_1xx";
+ sipMessage_t *response;
+ sipRespLine_t *respLine;
+ int status_code = 0;
+
+ /* Unpack the event */
+ response = event->u.pSipMessage;
+
+ /* Get the status code */
+ respLine = sippmh_get_response_line(response);
+ if (respLine) {
+ status_code = respLine->status_code;
+ SIPPMH_FREE_RESPONSE_LINE(respLine);
+ }
+
+ /*
+ * Update the Tags here so that they will be correct if
+ * the user transfers a ringing call.
+ */
+ sip_sm_200and300_update(ccb, response, status_code);
+
+ sip_decrement_backup_active_count(ccb);
+
+ /* Mark the CCB as having received a 1xx response */
+ ccb->flags |= RECD_1xx;
+
+ if (status_code != SIP_1XX_TRYING) {
+ /* Reset credentials flag since INVITE was successfully processed */
+ ccb->authen.cred_type = 0;
+ }
+
+ switch (status_code) {
+
+ case SIP_1XX_TRYING:
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_FUNCTION_ENTRY), ccb->index,
+ ccb->dn_line, fname, sip_util_state2string(ccb->state),
+ "SIP 100 TRYING");
+ /*
+ * Update connected party info from RPID and Call-Info header.
+ * Do not delay call info update to UI with proceeding. There is
+ * no media event with the proceeding that can cause UI update
+ * automatically.
+ */
+ ccsip_update_callinfo(ccb, response, TRUE, FALSE, FALSE);
+ free_sip_message(response);
+ sip_cc_proceeding(ccb->gsm_id, ccb->dn_line);
+ return;
+
+ case SIP_1XX_RINGING:
+ {
+ sipsdp_status_t sdp_status;
+ CCSIP_DEBUG_STATE(DEB_L_C_F_PREFIX"%d: %s <- SIP 180 RINGING\n",
+ DEB_L_C_F_PREFIX_ARGS(SIP_CALL_STATUS, ccb->dn_line, ccb->gsm_id, fname),
+ ccb->index, sip_util_state2string(ccb->state));
+
+ /* check for alert-info in header.
+ * Commented out until DSP upgrade
+ alert_info = sippmh_get_header_val(request, SIP_HEADER_ALERT_INFO,
+ NULL);
+ ccb->alert_info = ALERTING_NONE;
+ if (alert_info) {
+ parseAlertingHeader(ccb, alert_info);
+ }
+ */
+ sdp_status = sip_util_extract_sdp(ccb, response);
+
+ switch (sdp_status) {
+ case SIP_SDP_SUCCESS:
+ case SIP_SDP_SESSION_AUDIT:
+ ccb->oa_state = OA_IDLE;
+ /* ccsip_update_callinfo needs to occur before cc_alerting */
+ ccsip_update_callinfo(ccb, response, TRUE, FALSE, TRUE);
+ sip_cc_alerting(ccb->gsm_id, ccb->dn_line, response, TRUE);
+ break;
+
+ case SIP_SDP_NOT_PRESENT:
+ /* ccsip_update_callinfo needs to occur before cc_alerting */
+ ccsip_update_callinfo(ccb, response, TRUE, FALSE, TRUE);
+ sip_cc_alerting(ccb->gsm_id, ccb->dn_line, NULL, 0);
+ break;
+
+ case SIP_SDP_DNS_FAIL:
+ case SIP_SDP_NO_MEDIA:
+ case SIP_SDP_ERROR:
+ default:
+ sipSPISendCancel(ccb);
+ free_sip_message(response);
+ sip_cc_release(ccb->gsm_id, ccb->dn_line, CC_CAUSE_ERROR, NULL);
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ return;
+ }
+ /*
+ * Update connected party info from RPID and Call-Info header.
+ * The call update to UI can be delayed due to altert processing
+ * can potentially manipulate media or port.
+ */
+ free_sip_message(response);
+ return;
+
+ } /* case SIP_1XX_RINGING */
+ case SIP_1XX_SESSION_PROGRESS:
+ {
+ sipsdp_status_t sdp_status;
+
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_FUNCTION_ENTRY), ccb->index,
+ ccb->dn_line, fname, sip_util_state2string(ccb->state),
+ "SIP 183 IN BAND SESSION PROGRESS");
+
+ sdp_status = sip_util_extract_sdp(ccb, response);
+
+ switch (sdp_status) {
+ case SIP_SDP_SUCCESS:
+ case SIP_SDP_SESSION_AUDIT:
+ ccb->oa_state = OA_IDLE;
+ break;
+
+ case SIP_SDP_NOT_PRESENT:
+ // In this case no SDP is present in the 183 message.
+ // Call flows exist where a callee may send 183 with no SDP and
+ // the right way to handle it is to remain in the same state.
+ // DDTS for reference is CSCdu17240
+ /* Update connected party info from RPID and Call-Info header */
+ ccsip_update_callinfo(ccb, response, TRUE, FALSE, FALSE);
+ free_sip_message(response);
+ return;
+
+ case SIP_SDP_DNS_FAIL:
+ case SIP_SDP_NO_MEDIA:
+ case SIP_SDP_ERROR:
+ default:
+ sipSPISendCancel(ccb);
+ free_sip_message(response);
+ sip_cc_release(ccb->gsm_id, ccb->dn_line, CC_CAUSE_ERROR, NULL);
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ return;
+ }
+
+ /*
+ * Update connected party info from RPID and Call-Info header.
+ * The call update to UI can be delayed due to altert processing
+ * can potentially manipulate media or port.
+ */
+ ccsip_update_callinfo(ccb, response, TRUE, FALSE, TRUE);
+ sip_cc_alerting(ccb->gsm_id, ccb->dn_line, response, TRUE);
+
+ /*UI-STATE tag with value of "BUSY" is being sent to indicate the busy line
+ *and to support callback feature. GSM needs to be informed so it can
+ *trigger the LSM to transition to BUSY state and display appropriate
+ *softkeys.
+ */
+ if ((ccb->in_call_info) &&
+ (ccb->in_call_info->data.call_info_feat_data.feature_flag & CC_UI_STATE) &&
+ (ccb->in_call_info->data.call_info_feat_data.ui_state == CC_UI_STATE_BUSY)) {
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX"DETECTED UI_STATE=BUSY IN 183.\n",
+ DEB_F_PREFIX_ARGS(SIP_CALL_STATUS, fname));
+ sip_cc_release(ccb->gsm_id, ccb->dn_line, CC_CAUSE_UI_STATE_BUSY, NULL);
+ }
+ free_sip_message(response);
+ return;
+ } /* case SIP_1XX_SESSION_PROGRESS */
+
+ case SIP_1XX_CALL_FWD:
+ CCSIP_DEBUG_STATE(DEB_L_C_F_PREFIX"%d: %s <- SIP 181 CALL IS BEING"
+ "FORWARDED\n",
+ DEB_L_C_F_PREFIX_ARGS(SIP_CALL_STATUS, ccb->dn_line, ccb->gsm_id, fname),
+ ccb->index, sip_util_state2string(ccb->state));
+ /* Update connected party info from RPID and Call-Info header */
+ ccsip_update_callinfo(ccb, response, TRUE, FALSE, FALSE);
+ free_sip_message(response);
+ sip_cc_proceeding(ccb->gsm_id, ccb->dn_line);
+ return;
+
+ case SIP_1XX_QUEUED:
+ CCSIP_DEBUG_STATE(DEB_L_C_F_PREFIX"%d: %s <- SIP 182 QUEUED\n",
+ DEB_L_C_F_PREFIX_ARGS(SIP_CALL_STATUS, ccb->dn_line, ccb->gsm_id, fname),
+ ccb->index, sip_util_state2string(ccb->state));
+ /* Update connected party info from RPID and Call-Info header */
+ ccsip_update_callinfo(ccb, response, TRUE, FALSE, FALSE);
+ free_sip_message(response);
+ sip_cc_proceeding(ccb->gsm_id, ccb->dn_line);
+ return;
+
+ default:
+ CCSIP_DEBUG_STATE(DEB_L_C_F_PREFIX"%d: %s <- SIP BAD 1xx\n",
+ DEB_L_C_F_PREFIX_ARGS(SIP_CALL_STATUS, ccb->dn_line, ccb->gsm_id, fname),
+ ccb->index, sip_util_state2string(ccb->state));
+ free_sip_message(response);
+ return;
+ }
+}
+
+
+void
+ccsip_handle_sentinvite_ev_sip_2xx (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ const char *fname = "sentinvite_ev_sip_2xx";
+ sipMessage_t *response;
+ const char *contact = NULL;
+ sipsdp_status_t sdp_status;
+ string_t recv_info_list = strlib_empty();
+
+ /* Unpack the event */
+ response = event->u.pSipMessage;
+
+ /* Check if this is an INVITE response */
+ if (!sip_sm_is_invite_response(response)) {
+ sipMethod_t method = sipMethodInvalid;
+ int response_code = 0;
+
+ // If this is a 202 response to a REFER, we should handle it separately
+ if (sipGetResponseCode(response, &response_code) < 0) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sipGetResponseCode");
+ free_sip_message(response);
+ return;
+ }
+ if (sipGetResponseMethod(response, &method) < 0) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sipGetResponseMethod");
+ free_sip_message(response);
+ return;
+ }
+
+ if (response_code == SIP_ACCEPTED && method == sipMethodRefer) {
+ ccsip_handle_accept_2xx(ccb, event);
+ return;
+ }
+ free_sip_message(response);
+ clean_method_request_trx(ccb, method, TRUE);
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_STATE_UNCHANGED), ccb->index,
+ ccb->dn_line, fname,
+ sip_util_state2string(ccb->state));
+ return;
+ }
+
+ /*
+ * Record the "tag=" parameter.
+ * Update To/From (to capture tag). Also Contact, and Record-Route
+ */
+ sip_sm_200and300_update(ccb, response, SIP_STATUS_SUCCESS);
+
+ /* Reset credentials flag since INVITE was successfully processed */
+ ccb->authen.cred_type = 0;
+
+ sip_decrement_backup_active_count(ccb);
+ (void) sip_platform_expires_timer_stop(ccb->index);
+ /* Check Contact header */
+ contact = sippmh_get_cached_header_val(response, CONTACT);
+ if (contact) {
+ if (sipSPICheckContact(contact) < 0) {
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ ccb->index, ccb->dn_line, fname,
+ "sipSPICheckContact()");
+ free_sip_message(response);
+ ccb->authen.cred_type = 0;
+ sipSPISendBye(ccb, NULL, NULL);
+ sip_cc_release(ccb->gsm_id, ccb->dn_line, CC_CAUSE_ERROR, NULL);
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ clean_method_request_trx(ccb, sipMethodAck, FALSE);
+ return;
+ }
+ }
+
+ /* Extract destination SDP and related fields */
+ sdp_status = sip_util_extract_sdp(ccb, response);
+
+ switch (sdp_status) {
+ case SIP_SDP_SUCCESS:
+ case SIP_SDP_SESSION_AUDIT:
+ ccb->oa_state = OA_IDLE;
+ break;
+
+ case SIP_SDP_NOT_PRESENT:
+ break;
+
+ case SIP_SDP_DNS_FAIL:
+ case SIP_SDP_NO_MEDIA:
+ case SIP_SDP_ERROR:
+ default:
+ /* First Ack and then send Bye to the far end */
+ if (sipSPISendAck(ccb, response) == FALSE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sipSPISendAck");
+ }
+ /* Update connected party info from RPID and Call-Info header */
+ ccsip_update_callinfo(ccb, response, TRUE, FALSE, FALSE);
+
+ free_sip_message(response);
+ sipSPISendBye(ccb, NULL, NULL);
+ sip_cc_release(ccb->gsm_id, ccb->dn_line, CC_CAUSE_ERROR, NULL);
+ if (ccb->wastransferred) {
+ /*
+ * The referred call was implicitly subscribed for the
+ * notification. Since we get the Error from target we
+ * need to send this notify to transferor
+ */
+ cc_feature_data_t data;
+
+ data.notify.cause = CC_CAUSE_ERROR;
+ data.notify.subscription = CC_SUBSCRIPTIONS_XFER;
+ data.notify.method = CC_XFER_METHOD_REFER;
+ data.notify.blind_xferror_gsm_id = 0;
+ sip_cc_feature(ccb->gsm_id, ccb->dn_line, CC_FEATURE_NOTIFY,
+ (void *) &data);
+ }
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ return;
+ }
+
+ /*
+ * Parse the diversion header which could be present, as in case of
+ * Auto Pick up
+ */
+ ccsip_parse_diversion_header (ccb, response);
+
+ /* Info Package stuff */
+ ccsip_parse_send_info_header(response, &recv_info_list);
+
+ /*
+ * Update connected party info from RPID and Call-Info header.
+ * The call update to UI can be delayed due to connected processing
+ * manipulates media or port.
+ */
+ ccsip_update_callinfo(ccb, response, TRUE, FALSE, TRUE);
+ sip_cc_connected(ccb->gsm_id, ccb->dn_line, recv_info_list, response);
+
+ strlib_free(recv_info_list);
+
+ /* Deallocate the memory for the response */
+ free_sip_message(response);
+ sip_sm_change_state(ccb, SIP_STATE_SENT_INVITE_CONNECTED);
+
+ /*
+ * The referred call was implicitely subscribed for the notification.
+ * Since we get the 200 OK from target we need to send this notify
+ * to transferor. So make a feature request to the GSM
+ */
+ if ((ccb->wastransferred) || (ccb->blindtransferred == TRUE)) {
+ cc_feature_data_t data;
+
+ data.notify.cause = CC_CAUSE_OK;
+ data.notify.cause_code = SIP_SUCCESS_SETUP;
+ data.notify.subscription = CC_SUBSCRIPTIONS_XFER;
+ data.notify.method = CC_XFER_METHOD_REFER;
+ data.notify.blind_xferror_gsm_id =
+ sip_sm_get_blind_xfereror_ccb_by_gsm_id(ccb->gsm_id);
+ sip_cc_feature(ccb->gsm_id, ccb->dn_line, CC_FEATURE_NOTIFY,
+ (void *) &data);
+ strlib_free(ccb->sipxfercallid);
+ ccb->sipxfercallid = strlib_empty();
+ } else if (ccb->flags & SENT_INVITE_REPLACE) {
+ strlib_free(ccb->sipxfercallid);
+ ccb->sipxfercallid = strlib_empty();
+ }
+}
+
+
+/*
+ *
+ ***** SIP_STATE_RELEASING
+ *
+ */
+
+void
+ccsip_handle_sentbye_recvd_invite (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ sipMessage_t *request;
+
+ /* Unpack the event */
+ request = event->u.pSipMessage;
+ (void) sipSPISendErrorResponse(request, SIP_CLI_ERR_CALLEG,
+ SIP_CLI_ERR_CALLEG_PHRASE, 0, NULL, NULL);
+ free_sip_message(request);
+}
+
+void
+ccsip_handle_release_complete (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ const char *fname = "release_complete";
+
+ if (ccb->blind_xfer_call_id == CC_NO_CALL_ID) {
+ if (!ccb->wait_for_ack) {
+ if ((ccb->flags & RECD_BYE) && (ccb->last_request)) {
+ (void) sipSPISendByeOrCancelResponse(ccb, ccb->last_request, sipMethodBye);
+ ccb->flags &= ~RECD_BYE;
+ }
+ if (!(sip_platform_msg_timer_outstanding_get(ccb->index))) {
+ sip_sm_call_cleanup(ccb);
+ }
+ } else {
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"INFO: waiting for Invite Response Ack "
+ "before clearing call\n", DEB_F_PREFIX_ARGS(SIP_ACK, fname));
+ /*
+ * Restart the disconnect timer. Call to start will also stop
+ * the timer if it is currently running.
+ */
+ (void) sip_platform_supervision_disconnect_timer_start(
+ SUPERVISION_DISCONNECT_TIMEOUT, ccb->index);
+ }
+ } else {
+ /*
+ * Wait for the transfered call to finish and then we have
+ * to send Notify for the transferred call to the transferror.
+ * HACK to please customer.
+ */
+ (void) sip_platform_supervision_disconnect_timer_stop(ccb->index);
+ sip_sm_change_state(ccb, SIP_STATE_BLIND_XFER_PENDING);
+ }
+}
+
+void
+ccsip_handle_sentbye_ev_sip_1xx (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ const char *fname = "sentbye_ev_sip_1xx";
+ sipMessage_t *response;
+
+ /* Unpack the event */
+ response = event->u.pSipMessage;
+
+ /* Check if this is an BYE/CANCEL response */
+ if (!sip_sm_is_bye_or_cancel_response(response)) {
+ if (sip_sm_is_invite_response(response)) {
+ // It could be an INVITE response if user opted to end the call
+ // before we received a 1xx from the remote end
+ // Send the deferred CANCEL now
+ if (ccb->flags & SEND_CANCEL) {
+ sipSPISendCancel(ccb);
+ }
+ }
+ free_sip_message(response);
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_STATE_UNCHANGED), ccb->index,
+ ccb->dn_line, fname,
+ sip_util_state2string(ccb->state));
+ return;
+ }
+ /*
+ * Restart the disconnect timer. Call to start will also stop
+ * the timer if it is currently running.
+ */
+ (void) sip_platform_supervision_disconnect_timer_start(
+ SUPERVISION_DISCONNECT_TIMEOUT, ccb->index);
+ free_sip_message(response);
+}
+
+void
+ccsip_handle_sentbye_ev_sip_2xx (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ const char *fname = "sentbye_ev_sip_2xx";
+ sipMessage_t *response;
+
+ /* Unpack the event */
+ response = event->u.pSipMessage;
+
+ /* Check if this is not a response to either CANCEL or BYE */
+ if (!sip_sm_is_bye_or_cancel_response(response)) {
+ /* Check if this is an INVITE response */
+
+ //Check if the response to an INVITE and we have sent out a CANCEL
+ if (sip_sm_is_invite_response(response) &&
+ (get_method_request_trx_index(ccb, sipMethodCancel, TRUE) != -1)) {
+ /*
+ * We have an outgoing CANCEL and 200 OK(INVITE) cross on the wire.
+ *
+ * We may have sent a CANCEL and around the same time,
+ * UAS may have responded with a 200 OK(INVITE) and
+ * so the CANCEL and 200 OK(INVITE) cross on the wire.
+ * So, the CANCEL is now useless.
+ *
+ * Actions:
+ * send ACK to satisfy 200 OK(INVITE)
+ * send BYE to initiate hangup since CANCEL is now useless
+ */
+ char *to_tag, *sip_to_temp;
+
+ to_tag = strstr(ccb->sip_to,";tag");
+ /*
+ * Add the to_tag to the Ack and Bye message if it is not
+ * already present.
+ */
+ if (!to_tag) {
+ sip_to_temp = strlib_open(ccb->sip_to, MAX_SIP_URL_LENGTH);
+ if (sip_to_temp) {
+ sstrncat(sip_to_temp, ";tag=",
+ MAX_SIP_URL_LENGTH - strlen(sip_to_temp));
+ if (ccb->sip_to_tag) {
+ sstrncat(sip_to_temp, ccb->sip_to_tag,
+ MAX_SIP_URL_LENGTH - strlen(sip_to_temp));
+ }
+ }
+ ccb->sip_to = strlib_close(sip_to_temp);
+ }
+
+ if (sipSPISendAck(ccb, NULL) == FALSE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sipSPISendAck");
+ }
+ sipSPISendBye(ccb, NULL, NULL);
+
+ CCSIP_DEBUG_STATE(DEB_L_C_F_PREFIX" %d %s Cross-over situation CANCEL/200 OK(INVITE).\n",
+ DEB_L_C_F_PREFIX_ARGS(SIP_ACK, ccb->dn_line, ccb->gsm_id, fname),
+ ccb->index, sip_util_state2string(ccb->state));
+ } else {
+ //This 200 OK is not related to BYE, CANCEL, nor INVITE
+ //We still need to account for it remove the transaction
+ sipMethod_t method = sipMethodInvalid;
+
+ if (sipGetResponseMethod(response, &method) < 0) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sipGetResponseMethod");
+ free_sip_message(response);
+ return;
+ }
+
+ clean_method_request_trx(ccb, method, TRUE);
+ }
+
+ free_sip_message(response);
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_STATE_UNCHANGED),
+ ccb->index, ccb->dn_line, fname,
+ sip_util_state2string(ccb->state));
+ return;
+ }
+ (void) sip_platform_expires_timer_stop(ccb->index);
+ if (!ccb->send_delayed_bye) {
+ sip_cc_release_complete(ccb->gsm_id, ccb->dn_line, CC_CAUSE_NORMAL);
+ }
+
+ if (!ccb->wait_for_ack) {
+ sip_sm_call_cleanup(ccb);
+ } else {
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"INFO: waiting for Invite Response Ack "
+ "before clearing call\n", DEB_F_PREFIX_ARGS(SIP_ACK, fname));
+ /*
+ * Restart the disconnect timer. Call to start will also stop
+ * the timer if it is currently running.
+ */
+ (void) sip_platform_supervision_disconnect_timer_start(
+ SUPERVISION_DISCONNECT_TIMEOUT, ccb->index);
+ }
+ free_sip_message(response);
+}
+
+
+/*
+ * Just respond to the Bye in the Release state.
+ */
+void
+ccsip_handle_release_ev_sip_bye (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ const char *fname = "blindxfr_ev_sip_bye";
+ sipMessage_t *request;
+ uint16_t request_check_reason_code = 0;
+ char request_check_reason_phrase[SIP_WARNING_LENGTH];
+ sipMethod_t method = sipMethodInvalid;
+
+ memset(request_check_reason_phrase, 0, SIP_WARNING_LENGTH);
+
+ /* Unpack the event */
+ request = event->u.pSipMessage;
+
+ /* Request check and store */
+ sipGetRequestMethod(request, &method);
+ if (sip_sm_request_check_and_store(ccb, request, method, TRUE,
+ &request_check_reason_code,
+ request_check_reason_phrase, FALSE) < 0) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ ccb->index, ccb->dn_line, fname,
+ get_debug_string(DEBUG_FUNCTIONNAME_SIP_SM_REQUEST_CHECK_AND_STORE));
+ (void) sipSPISendErrorResponse(request, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ request_check_reason_code,
+ request_check_reason_phrase, NULL);
+ free_sip_message(request);
+ return;
+ }
+
+ (void) sipSPISendByeOrCancelResponse(ccb, request, sipMethodBye);
+}
+
+
+void
+ccsip_handle_sentblindntfy_ev_sip_2xx (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ sipMessage_t *response;
+
+ /* Unpack the event */
+ response = event->u.pSipMessage;
+ (void) sip_platform_expires_timer_stop(ccb->index);
+
+ if (ccb->flags & FINAL_NOTIFY) {
+ sip_sm_call_cleanup(ccb);
+ } else {
+ clean_method_request_trx(ccb, sipMethodNotify, TRUE);
+ }
+
+ free_sip_message(response);
+}
+
+
+void
+ccsip_handle_sendbye_ev_supervision_disconnect (ccsipCCB_t *ccb,
+ sipSMEvent_t *event)
+{
+
+ (void) sip_platform_expires_timer_stop(ccb->index);
+ sip_cc_release_complete(ccb->gsm_id, ccb->dn_line, CC_CAUSE_NORMAL);
+ sip_sm_call_cleanup(ccb);
+}
+
+/**
+ *
+ * Handler for SIP_STATE_RELEASE features. Currently only CANCEL feature is
+ * supported in this state.
+ *
+ * @param line, ccb, event
+ *
+ * @return void
+ *
+ * @pre (event not NULL)
+ */
+/*
+ * SIP_STATE_RELEASE
+ */
+void
+ccsip_handle_release_ev_cc_feature (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ const char *fname = "release_ev_cc_feature";
+ cc_features_t feature_type;
+
+ feature_type = event->u.cc_msg->msg.feature.feature_id;
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_FUNCTION_ENTRY),
+ ccb->index, ccb->dn_line, fname,
+ sip_util_state2string(ccb->state),
+ cc_feature_name(feature_type));
+
+ switch (feature_type) {
+ case CC_FEATURE_CANCEL:
+ break;
+ default:
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_FEATURE_UNSUPPORTED),
+ ccb->index, ccb->dn_line, fname);
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_STATE_UNCHANGED),
+ ccb->index, ccb->dn_line, fname,
+ sip_util_state2string(ccb->state));
+ sip_cc_feature_ack(ccb->gsm_id, ccb->dn_line, feature_type, NULL,
+ CC_CAUSE_ERROR);
+ break;
+ }
+}
+
+/**
+ *
+ * Handler for event RELEASE at SIP_STATE_RELEASE.
+ * sipstack is waiting for RELEASE_COMPLETE from gsm, but it got RELEASE from gsm.
+ * so we know that gsm also want to release the call.
+ * to avoid defects like CSCtg46399, we need to send RELEASE_COMPLETE to both sipstack & gsm,
+ * then sipstack & gsm will not wait for each other, and the call can be cleared on both sides.
+ *
+ */
+void
+ccsip_handle_release_ev_release (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ const char *fname = "release_ev_release";
+
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_FUNCTION_ENTRY),
+ ccb->index, ccb->dn_line, fname,
+ sip_util_state2string(ccb->state),
+ "sipstack at SIP_STATE_RELEASE received a RELEASE event from gsm");
+
+ /* send RELEASE_COMPLETE to sipstack */
+ ccsip_handle_release_complete(ccb, event);
+
+ /* send RELEASE_COMPLETE to gsm */
+ ccsip_handle_sendbye_ev_supervision_disconnect(ccb, event);
+}
+
+
+void
+ccsip_handle_recv_error_response_ev_sip_ack (ccsipCCB_t *ccb,
+ sipSMEvent_t *event)
+{
+ sipMessage_t *response;
+
+ /* Unpack the event */
+ response = event->u.pSipMessage;
+
+ ccb->wait_for_ack = FALSE;
+
+ if (ccb->send_delayed_bye) {
+ // If we need to send a bye, do it now. Do not change state. Clean up
+ // the CCB once we receive the OK for the BYE
+ sipSPISendBye(ccb, NULL, NULL);
+ } else {
+ sip_cc_release_complete(ccb->gsm_id, ccb->dn_line, CC_CAUSE_NORMAL);
+ sip_sm_call_cleanup(ccb);
+ }
+
+ free_sip_message(response);
+}
+
+void
+ccsip_handle_sentbye_ev_sip_fxx (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ const char *fname = "sentbye_ev_sip_fxx";
+ sipMessage_t *response;
+ sipRespLine_t *respLine = NULL;
+ int status_code = 0;
+ const char *authenticate = NULL;
+ credentials_t credentials;
+ sip_authen_t *sip_authen = NULL;
+ char *author_str = NULL;
+ boolean good_authorization = FALSE;
+ const char *rsp_method = NULL;
+ char *alsoString = NULL;
+ sipMethod_t method = sipMethodInvalid;
+ enum {
+ INVALID,
+ RESP_OF_BYE,
+ RESP_OF_CANCEL,
+ RESP_OF_NOTIFY,
+ RESP_OF_INVITE
+ } resp_type = INVALID;
+
+ /* Unpack the event */
+ response = event->u.pSipMessage;
+ if (sipGetResponseMethod(response, &method) < 0) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sipGetResponseMethod");
+ free_sip_message(response);
+ return;
+ }
+ switch (method) {
+ case sipMethodInvite:
+ resp_type = RESP_OF_INVITE;
+ rsp_method = SIP_METHOD_INVITE;
+ break;
+ case sipMethodBye:
+ resp_type = RESP_OF_BYE;
+ rsp_method = SIP_METHOD_BYE;
+ break;
+ case sipMethodCancel:
+ resp_type = RESP_OF_CANCEL;
+ rsp_method = SIP_METHOD_CANCEL;
+ break;
+ case sipMethodNotify:
+ resp_type = RESP_OF_NOTIFY;
+ rsp_method = SIP_METHOD_NOTIFY;
+ break;
+ default:
+ resp_type = INVALID;
+ break;
+ }
+
+ if (INVALID == resp_type) {
+ free_sip_message(response);
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_STATE_UNCHANGED),
+ ccb->index, ccb->dn_line, fname,
+ sip_util_state2string(ccb->state));
+ if (ccb->state == SIP_STATE_BLIND_XFER_PENDING) {
+ /* Got an error Response for Notify Message
+ * Just clean up at this point.
+ */
+ sip_sm_call_cleanup(ccb);
+ }
+ return;
+ }
+
+ sip_decrement_backup_active_count(ccb);
+ /* Get the status code */
+ respLine = sippmh_get_response_line(response);
+ if (respLine) {
+ status_code = respLine->status_code;
+ SIPPMH_FREE_RESPONSE_LINE(respLine);
+ }
+
+
+ if ((strcmp(rsp_method, SIP_METHOD_INVITE) == 0) &&
+ (status_code == SIP_SERV_ERR_INTERNAL)) {
+ /*
+ * This is likely a late arriving 500 response to INVITE.
+ * We are already in the releasing stage of the call having
+ * sent a CANCEL that crossed with the 500 response.
+ * Just ACK the 500 and return.
+ */
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX"Acking delayed 500 response to INVITE "
+ "request\n", DEB_F_PREFIX_ARGS(SIP_ACK, fname));
+ sipSPISendFailureResponseAck(ccb, response, FALSE, 0);
+ return;
+ }
+
+
+ switch (status_code) {
+ case SIP_CLI_ERR_UNAUTH:
+ case SIP_CLI_ERR_PROXY_REQD:
+ CCSIP_DEBUG_STATE(DEB_L_C_F_PREFIX"%d: %s\n",
+ DEB_L_C_F_PREFIX_ARGS(SIP_CALL_STATUS, ccb->dn_line, ccb->gsm_id, fname),
+ ccb->index, AUTH_BUGINF(status_code));
+
+ if (cred_get_credentials_r(ccb, &credentials) == FALSE) {
+ CCSIP_DEBUG_STATE(DEB_L_C_F_PREFIX"retries exceeded: %d/%d\n",
+ DEB_L_C_F_PREFIX_ARGS(SIP_CALL_STATUS, ccb->dn_line, ccb->gsm_id, fname),
+ ccb->index, ccb->authen.cred_type, MAX_RETRIES_401);
+
+ free_sip_message(response);
+ sip_cc_release_complete(ccb->gsm_id, ccb->dn_line, CC_CAUSE_ERROR);
+ sip_sm_call_cleanup(ccb);
+ return;
+ }
+
+ authenticate = sippmh_get_header_val(response, AUTH_HDR(status_code), NULL);
+ if (authenticate != NULL) {
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX"Authenticate header %s= %s\n", DEB_F_PREFIX_ARGS(SIP_STATE, fname),
+ AUTH_HDR_STR(status_code), authenticate);
+ ccb->retx_counter = 0;
+ sip_authen = sippmh_parse_authenticate(authenticate);
+ if (sip_authen) {
+ ccb->authen.new_flag = FALSE;
+ ccb->authen.cnonce[0] = '\0';
+ if (sipSPIGenerateAuthorizationResponse(sip_authen, ccb->ReqURI,
+ rsp_method, credentials.id,
+ credentials.pw,
+ &author_str,
+ &(ccb->authen.nc_count),
+ ccb))
+ {
+ good_authorization = TRUE;
+ if (ccb->authen.authorization != NULL) {
+ cpr_free(ccb->authen.authorization);
+ ccb->authen.authorization = NULL;
+ }
+ if (ccb->authen.sip_authen != NULL) {
+ sippmh_free_authen(ccb->authen.sip_authen);
+ ccb->authen.sip_authen = NULL;
+ }
+ ccb->authen.authorization = (char *)
+ cpr_malloc(strlen(author_str) * sizeof(char) + 1);
+
+ /*
+ * Cache the Authorization header so that it can be used for
+ * later requests
+ */
+ if (ccb->authen.authorization != NULL) {
+ sstrncpy(ccb->authen.authorization, author_str,
+ strlen(author_str) * sizeof(char) + 1);
+ ccb->authen.status_code = status_code;
+ ccb->authen.sip_authen = sip_authen;
+ }
+
+ cpr_free(author_str);
+ } else {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Authorization header "
+ "build unsuccessful\n", fname);
+ }
+ /*
+ * CSCds70538
+ * Do not free the sip_authen structure if the Authorization
+ * build was successful. We will need these values to generate
+ * an Authorization header for the BYE response
+ */
+ if (good_authorization == FALSE) {
+ sippmh_free_authen(sip_authen);
+ }
+ }
+ if (strcmp(rsp_method, SIP_METHOD_BYE) == 0) {
+ clean_method_request_trx(ccb, sipMethodBye, TRUE);
+ if (ccb->referto[0]) {
+ alsoString = (char *) cpr_malloc(MAX_SIP_URL_LENGTH);
+ if (!alsoString) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ ccb->index, ccb->dn_line, fname,
+ "malloc(also string)");
+ sipSPISendBye(ccb, NULL, NULL);
+ return;
+ }
+ sstrncpy(alsoString, ccb->referto, MAX_SIP_URL_LENGTH);
+ sipSPISendBye(ccb, alsoString, NULL);
+ cpr_free(alsoString);
+ return;
+ }
+ /* Send BYE message */
+ sipSPISendBye(ccb, NULL, NULL);
+ } else if (strcmp(rsp_method, SIP_METHOD_CANCEL) == 0){
+ sipSPISendCancel(ccb);
+ } else {
+ (void) sipSPISendNotify(ccb, ccb->xfer_status);
+ }
+
+ } else {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"401/407 response missing "
+ "Authenticate\n", fname);
+ sip_cc_release_complete(ccb->gsm_id, ccb->dn_line, CC_CAUSE_ERROR);
+ sip_sm_call_cleanup(ccb);
+ }
+ free_sip_message(response);
+ return;
+
+
+ case SIP_CLI_ERR_LOOP_DETECT:
+ case SIP_CLI_ERR_BUSY_HERE:
+ case SIP_CLI_ERR_MANY_HOPS:
+ case SIP_CLI_ERR_AMBIGUOUS:
+ case SIP_CLI_ERR_REQ_CANCEL:
+ if (sipSPISendAck(ccb, NULL) == FALSE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sipSPISendAck");
+ }
+
+ (void) sip_platform_expires_timer_stop(ccb->index);
+ if (!ccb->send_delayed_bye) {
+ sip_cc_release_complete(ccb->gsm_id, ccb->dn_line, CC_CAUSE_NORMAL);
+ }
+
+ if (!ccb->wait_for_ack) {
+ sip_sm_call_cleanup(ccb);
+ } else {
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"waiting for Invite Response Ack "
+ "before clearing call\n", DEB_F_PREFIX_ARGS(SIP_ACK, fname));
+ /*
+ * Restart the disconnect timer. Call to start will also stop
+ * the timer if it is currently running.
+ */
+ (void) sip_platform_supervision_disconnect_timer_start(
+ SUPERVISION_DISCONNECT_TIMEOUT, ccb->index);
+ }
+
+ free_sip_message(response);
+ return;
+
+ case SIP_SERV_ERR_NOT_IMPLEM:
+ /* It's an error response to a notify. rfc3515 tells us:
+ * Terminating a subscription,
+ * either by explicitly unsubscribing or rejecting NOTIFY, is not an
+ * indication that the referenced request should be withdrawn or
+ * abandoned.
+ */
+
+ if (strcmp (rsp_method,SIP_METHOD_NOTIFY) == 0){
+ //ignore error
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX"Ignoring NOTIFY error. But clean up "
+ "transaction.\n", DEB_F_PREFIX_ARGS(SIP_CALL_STATUS, fname));
+ clean_method_request_trx(ccb, sipMethodNotify, TRUE);
+
+ if (ccb->flags & FINAL_NOTIFY) {
+ sip_sm_call_cleanup(ccb);
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX"Ignoring NOTIFY error. but "
+ "cleaning up call.\n", DEB_F_PREFIX_ARGS(SIP_CALL_STATUS, fname));
+ }
+ free_sip_message(response);
+ return;
+ }
+ /*FALLTHROUGH*/
+
+ default:
+ sip_cc_release_complete(ccb->gsm_id, ccb->dn_line, CC_CAUSE_ERROR);
+ sip_sm_call_cleanup(ccb);
+ free_sip_message(response);
+ return;
+ }
+}
+
+/*
+ * Function: ccsip_handle_sentinvite_ev_sip_3xx
+ *
+ * Parameters: CCB and the event
+ *
+ * Description: Sends ack for 3xx events and appropriate invite
+ *
+ * Returns: void
+ *
+ */
+void
+ccsip_handle_sentinvite_ev_sip_3xx (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ const char *fname = "sentinvite_ev_sip_3xx";
+ sipMessage_t *response;
+ sipRespLine_t *respLine;
+ uint16_t status_code = 0;
+
+ /* Unpack the event */
+ response = event->u.pSipMessage;
+
+ sip_decrement_backup_active_count(ccb);
+
+ /* Get the status code */
+ respLine = sippmh_get_response_line(response);
+ if (respLine) {
+ status_code = respLine->status_code;
+ SIPPMH_FREE_RESPONSE_LINE(respLine);
+ }
+
+ switch (status_code) {
+ case SIP_RED_MULT_CHOICES /* 300 */:
+ case SIP_RED_MOVED_PERM /* 301 */:
+ case SIP_RED_MOVED_TEMP /* 302 */:
+ case SIP_RED_USE_PROXY /* 305 */:
+ /*
+ * Record the "tag=" parameter.
+ * Update To/From (to capture tag). Also Contact, and Record-Route
+ */
+ sip_sm_update_to_from_on_callsetup_finalresponse(ccb, response);
+ sip_sm_update_contact_recordroute(ccb, response, status_code,
+ FALSE /* not midcall */);
+
+ /*
+ * Send ACK to the original INVITE destination or to the address
+ * specified by the Record-Route
+ */
+ sipSPISendFailureResponseAck(ccb, response, FALSE, 0);
+
+ /* Reset credentials flag before attempting redirect */
+ ccb->authen.cred_type = 0;
+ ccb->first_pass_3xx = TRUE;
+ sip_redirect(ccb, response, status_code);
+
+ break;
+ default:
+ CCSIP_DEBUG_STATE(DEB_L_C_F_PREFIX"%d %d unsupported\n",
+ DEB_L_C_F_PREFIX_ARGS(SIP_CALL_STATUS, ccb->dn_line, ccb->gsm_id, fname),
+ ccb->index, status_code);
+ break;
+ }
+
+ free_sip_message(response);
+}
+
+void
+handle_error_for_state (ccsipCCB_t *ccb, int status_code)
+{
+ ccsipCCB_t *referccb = NULL;
+ cc_causes_t fail_reason = CC_CAUSE_MIN;
+
+ if (ccb->state == SIP_STATE_SENT_INVITE) {
+ if (status_code == SIP_CLI_ERR_BUSY_HERE) {
+ sip_cc_release(ccb->gsm_id, ccb->dn_line, CC_CAUSE_BUSY, NULL);
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+
+ } else if (status_code == SIP_SERV_ERR_UNAVAIL) {
+ sip_cc_release(ccb->gsm_id, ccb->dn_line, CC_CAUSE_CONGESTION, NULL);
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+
+ } else if (status_code == SIP_CLI_ERR_NOT_AVAIL) {
+ sip_cc_release(ccb->gsm_id, ccb->dn_line, CC_TEMP_NOT_AVAILABLE, NULL);
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+
+ } else if ((status_code == SIP_CLI_ERR_MEDIA) ||
+ (status_code == SIP_CLI_ERR_NOT_ACCEPT_HERE) ||
+ (status_code == SIP_FAIL_NOT_ACCEPT)) {
+ sip_cc_release(ccb->gsm_id, ccb->dn_line, CC_CAUSE_PAYLOAD_MISMATCH, NULL);
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+
+ } else if (status_code == SIP_SERV_ERR_INTERNAL) {
+ // This is used to indicate a successful cfwdall interaction
+ sip_cc_release(ccb->gsm_id, ccb->dn_line, CC_CAUSE_REMOTE_SERVER_ERROR, NULL);
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+
+ } else if (((status_code == SIP_CLI_ERR_BAD_REQ) ||
+ (status_code == SIP_CLI_ERR_CALLEG)) &&
+ (ccb->wastransferred)) {
+ /* clean up here because a release complete from GSM
+ * is not guaranteed here like in the case of pre-mature
+ * attended transfer request. A cause value of normal
+ * causes GSM to clean up the UI as well.
+ */
+ sip_cc_release(ccb->gsm_id, ccb->dn_line, CC_CAUSE_NORMAL, NULL);
+ sip_sm_call_cleanup(ccb);
+ } else if (status_code == SIP_CLI_ERR_NOT_FOUND) {
+ sip_cc_release(ccb->gsm_id, ccb->dn_line, CC_CAUSE_NOT_FOUND, NULL);
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ } else if (status_code == SIP_CLI_ERR_REQ_CANCEL) {
+ sip_cc_release(ccb->gsm_id, ccb->dn_line, CC_CAUSE_NO_USER_ANS, NULL);
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ } else {
+ /*
+ * This should take care of miscellaneous errors including 400
+ * bad request when its not a transfer. No special handling is
+ * done in case of 491 SIP_CLI_ERR_REQ_PENDING as that error is
+ * treated like any other 4xx in this state
+ */
+ sip_cc_release(ccb->gsm_id, ccb->dn_line, CC_CAUSE_ERROR, NULL);
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ }
+ if (ccb->blindtransferred == TRUE) {
+ cc_feature_data_t data;
+
+ data.notify.cause = CC_CAUSE_ERROR;
+ data.notify.cause_code = status_code;
+ data.notify.subscription = CC_SUBSCRIPTIONS_XFER;
+ data.notify.method = CC_XFER_METHOD_REFER;
+ data.notify.blind_xferror_gsm_id = sip_sm_get_blind_xfereror_ccb_by_gsm_id(ccb->gsm_id);
+ sip_cc_feature(ccb->gsm_id, ccb->dn_line, CC_FEATURE_NOTIFY,
+ (void *) &data);
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ }
+
+ /* make sure to send the Notify if we are in a transfer
+ * scenario. This way the transferor can cleanup properly.
+ */
+ if (ccb->wastransferred) {
+ referccb = sip_sm_get_target_call_by_gsm_id(ccb->gsm_id);
+ if (referccb != NULL) {
+ ccb->flags |= FINAL_NOTIFY;
+ (void) sipSPISendNotify(referccb, status_code);
+ ccb->xfer_status = status_code;
+ }
+ }
+ } else if (ccb->state == SIP_STATE_ACTIVE) {
+ sip_cc_feature_ack(ccb->gsm_id, ccb->dn_line, CC_FEATURE_NONE, NULL,
+ CC_CAUSE_ERROR);
+ } else if (ccb->state == SIP_STATE_SENT_MIDCALL_INVITE) {
+ if (status_code == SIP_CLI_ERR_BUSY_HERE) {
+ fail_reason = CC_CAUSE_BUSY;
+ } else if ((status_code == SIP_CLI_ERR_MEDIA) ||
+ (status_code == SIP_CLI_ERR_NOT_ACCEPT_HERE) ||
+ (status_code == SIP_FAIL_NOT_ACCEPT)) {
+ fail_reason = CC_CAUSE_PAYLOAD_MISMATCH;
+ } else if (status_code == SIP_CLI_ERR_REQ_PENDING) {
+ // The other side has sent us a 491. We will let GSM handle this error and
+ // we shall fall back to the state we were in prior to being in any of the
+ // states. These are:
+ fail_reason = CC_CAUSE_REQUEST_PENDING;
+ } else if (status_code == SIP_SERV_ERR_UNAVAIL) {
+ fail_reason = CC_CAUSE_SERV_ERR_UNAVAIL;
+ } else {
+ fail_reason = CC_CAUSE_ERROR;
+ }
+
+ /* ack the feature */
+ sip_cc_feature_ack(ccb->gsm_id, ccb->dn_line, ccb->featuretype, NULL,
+ fail_reason);
+ if (status_code == SIP_CLI_ERR_REQ_TIMEOUT) {
+ sip_cc_release(ccb->gsm_id, ccb->dn_line, CC_CAUSE_ERROR, NULL);
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ } else {
+ /* Other error goes back to active, let GSM decide */
+ sip_sm_change_state(ccb, SIP_STATE_ACTIVE);
+ }
+ } else if (ccb->state == SIP_STATE_BLIND_XFER_PENDING) {
+ if (status_code == SIP_CLI_ERR_REQ_TIMEOUT) {
+ sip_cc_release(ccb->gsm_id, ccb->dn_line, CC_CAUSE_ERROR, NULL);
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ }
+ }
+ if (ccb->wastransferred) {
+ /*
+ * The referred call was implicitely subscribed for the notification.
+ * Since we get the Error from target we need to send this notify
+ * to transferor.
+ */
+ cc_feature_data_t data;
+
+ data.notify.cause = fail_reason;
+ data.notify.cause_code = status_code;
+ data.notify.subscription = CC_SUBSCRIPTIONS_XFER;
+ data.notify.method = CC_XFER_METHOD_REFER;
+ data.notify.blind_xferror_gsm_id = 0;
+ sip_cc_feature(ccb->gsm_id, ccb->dn_line, CC_FEATURE_NOTIFY,
+ (void *)&data);
+ }
+}
+
+
+void
+ccsip_handle_sentinvite_ev_sip_fxx (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ const char *fname = "sentinvite_ev_sip_fxx";
+ sipMessage_t *response;
+ sipRespLine_t *respLine = NULL;
+ uint16_t status_code = 0;
+ const char *authenticate = NULL;
+ credentials_t credentials;
+ sip_authen_t *sip_authen = NULL;
+ char *author_str = NULL;
+ boolean good_authorization = FALSE;
+ sipMethod_t method = sipMethodInvalid;
+ const char *rsp_method = NULL;
+
+ enum {
+ INVALID,
+ RESP_OF_INVITE,
+ RESP_OF_REFER,
+ RESP_OF_NOTIFY
+ } resp_type = INVALID;
+
+ response = event->u.pSipMessage;
+
+ /* Check if this is an INVITE response */
+ if (sipGetResponseMethod(response, &method) < 0) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sipGetResponseMethod");
+ free_sip_message(response);
+ return;
+ }
+ switch (method) {
+ case sipMethodInvite:
+ resp_type = RESP_OF_INVITE;
+ rsp_method = SIP_METHOD_INVITE;
+
+ /* Stop the expires timer started to await this response */
+ (void) sip_platform_expires_timer_stop(ccb->index);
+
+ /* Update connected party info from RPID and Call-Info header */
+ ccsip_update_callinfo(ccb, response, TRUE, FALSE, FALSE);
+
+ break;
+ case sipMethodRefer:
+ resp_type = RESP_OF_REFER;
+ rsp_method = SIP_METHOD_REFER;
+ break;
+ case sipMethodNotify:
+ resp_type = RESP_OF_NOTIFY;
+ rsp_method = SIP_METHOD_NOTIFY;
+ break;
+ default:
+ resp_type = INVALID;
+ break;
+ }
+
+ if (INVALID == resp_type) {
+ free_sip_message(response);
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_STATE_UNCHANGED),
+ ccb->index, ccb->dn_line, fname,
+ sip_util_state2string(ccb->state));
+ return;
+ }
+
+ /* Get the status code */
+ respLine = sippmh_get_response_line(response);
+ if (respLine) {
+ status_code = respLine->status_code;
+ SIPPMH_FREE_RESPONSE_LINE(respLine);
+ }
+
+ /*
+ * Update the Tags here so that they will be correct if
+ * the user transfers a ringing call.
+ */
+ sip_sm_200and300_update(ccb, response, status_code);
+
+ // If the resp_type is RESP_OF_REFER and the feature type is one of the
+ // extendedrefer features, and the reason code is not a failure of authentication
+ // then indicate the error condition back to GSM
+ if (resp_type == RESP_OF_REFER) {
+ switch (ccb->featuretype) {
+ case CC_FEATURE_B2BCONF:
+ case CC_FEATURE_SELECT:
+ case CC_FEATURE_CANCEL:
+ if (status_code != SIP_CLI_ERR_UNAUTH && status_code != SIP_CLI_ERR_PROXY_REQD) {
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX"Received error response for ext refer\n",
+ DEB_F_PREFIX_ARGS(SIP_CALL_STATUS, fname));
+ sip_cc_feature_ack(ccb->gsm_id, ccb->dn_line, ccb->featuretype, NULL,
+ CC_CAUSE_ERROR);
+ clean_method_request_trx(ccb, sipMethodRefer, TRUE);
+ free_sip_message(response);
+ return;
+ }
+ /*FALLTHROUGH*/
+ default:
+ break;
+ }
+ }
+
+ sip_decrement_backup_active_count(ccb);
+
+ switch (status_code) {
+ case SIP_CLI_ERR_UNAUTH:
+ case SIP_CLI_ERR_PROXY_REQD:
+ CCSIP_DEBUG_STATE(DEB_L_C_F_PREFIX"SIP_CLI_ERR_PROXY_REQD: %d: %s\n",
+ DEB_L_C_F_PREFIX_ARGS(SIP_CALL_STATUS, ccb->dn_line, ccb->gsm_id, fname),
+ ccb->index, AUTH_BUGINF(status_code));
+
+ /* Send ACK */
+ if (method == sipMethodInvite) {
+ sipSPISendFailureResponseAck(ccb, response, FALSE, 0);
+ }
+
+ if (cred_get_credentials_r(ccb, &credentials) == FALSE) {
+ CCSIP_DEBUG_STATE(DEB_L_C_F_PREFIX"retries exceeded: %d/%d\n",
+ DEB_L_C_F_PREFIX_ARGS(SIP_CALL_STATUS, ccb->dn_line, ccb->gsm_id, fname),
+ ccb->authen.cred_type, MAX_RETRIES_401);
+ /*
+ * Retries exceeded for 40X could be due to remote end
+ * not responding to our Request, and while we are retrying,
+ * proxy could ask us to reauthenticate. So, we may exceed
+ * retries for credentials due to some other reason than just
+ * auth failure, but we do not care. status_code is passed.
+ */
+
+ handle_error_for_state(ccb, status_code);
+ free_sip_message(response);
+ return;
+ }
+
+ authenticate = sippmh_get_header_val(response, AUTH_HDR(status_code),
+ NULL);
+ if (authenticate != NULL) {
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX"Authenticate header %s= %s\n", DEB_F_PREFIX_ARGS(SIP_AUTH, fname),
+ AUTH_HDR_STR(status_code), authenticate);
+
+ ccb->retx_counter = 0;
+
+ sip_authen = sippmh_parse_authenticate(authenticate);
+ if (sip_authen) {
+ ccb->authen.new_flag = FALSE;
+ /* We are sure at this point that it is either a response of
+ * INVITE or REFER and nothing else
+ */
+ ccb->authen.cnonce[0] = '\0';
+ ccb->authen.nc_count = 0; // New nonce, hence reset
+ if (sipSPIGenerateAuthorizationResponse(sip_authen,
+ ccb->ReqURI,
+ rsp_method,
+ credentials.id,
+ credentials.pw,
+ &author_str,
+ &(ccb->authen.nc_count), ccb)) {
+
+ good_authorization = TRUE;
+
+ if (ccb->authen.authorization != NULL) {
+ cpr_free(ccb->authen.authorization);
+ ccb->authen.authorization = NULL;
+ }
+
+ if (ccb->authen.sip_authen != NULL) {
+ sippmh_free_authen(ccb->authen.sip_authen);
+ ccb->authen.sip_authen = NULL;
+ }
+
+ ccb->authen.authorization = (char *) cpr_malloc(strlen(author_str) *
+ sizeof(char) + 1);
+
+ /*
+ * Cache the Authorization header so that it can be used for
+ * later requests
+ */
+ if (ccb->authen.authorization != NULL) {
+ sstrncpy(ccb->authen.authorization, author_str,
+ strlen(author_str) * sizeof(char) + 1);
+ ccb->authen.status_code = status_code;
+ ccb->authen.sip_authen = sip_authen;
+ }
+
+ /* tell GSM we are trying */
+ if (ccb->state == SIP_STATE_SENT_INVITE) {
+ sip_cc_proceeding(ccb->gsm_id, ccb->dn_line);
+ }
+ cpr_free(author_str);
+ } else {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Authorization header "
+ "build unsuccessful\n", fname);
+ }
+ /*
+ * CSCds70538
+ * Do not free the sip_authen structure if the Authorization
+ * build was successful. We will need these values to generate
+ * an Authorization header for the BYE response
+ */
+ if (good_authorization == FALSE) {
+ sippmh_free_authen(sip_authen);
+ }
+ }
+
+ switch (resp_type) {
+ case RESP_OF_REFER:
+ /* We do not need to inform about this error to GSM */
+ // Delete the previous transaction block
+ clean_method_request_trx(ccb, sipMethodRefer, TRUE);
+
+ {
+ boolean refer_sent = FALSE;
+
+ switch (ccb->featuretype) {
+ case CC_FEATURE_B2BCONF:
+ case CC_FEATURE_SELECT:
+ case CC_FEATURE_CANCEL:
+ break;
+ default:
+ break;
+ }
+
+ if (refer_sent) {
+ break;
+ }
+ }
+
+ if (sipSPISendRefer(ccb, (char *) ccb->sip_referTo, SIP_REF_XFER) != TRUE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ ccb->index, ccb->dn_line, fname,
+ "sipSPISendRefer Failed");
+ }
+ break;
+
+ case RESP_OF_INVITE:
+ if (ccb->state == SIP_STATE_SENT_INVITE) {
+ // Since we need to start a new Dialog we should clear
+ // any previous record route info
+ if (ccb->record_route_info) {
+ sippmh_free_record_route(ccb->record_route_info);
+ ccb->record_route_info = NULL;
+ }
+
+ (void) sipSPISendInviteMidCall(ccb, TRUE /* does expire */);
+ } else {
+ (void) sipSPISendInviteMidCall(ccb, FALSE /* doesn't expire */);
+ }
+ break;
+ case RESP_OF_NOTIFY:
+ // Delete the previous transaction block
+ clean_method_request_trx(ccb, sipMethodNotify, TRUE);
+ if (sipSPISendNotify(ccb, ccb->xfer_status) != TRUE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ ccb->index, ccb->dn_line, fname,
+ "sipSPISendNotify Failed");
+ }
+ break;
+ default:
+ break;
+ }
+ } else {
+ if ((ccb->redirect_info != NULL)
+ && (method == sipMethodInvite)
+ && (ccb->state == SIP_STATE_SENT_INVITE)) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"401/407 response missing "
+ "Authenticate, redirecting to next add.\n", fname);
+ sip_redirect(ccb, response, status_code);
+ } else {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"401/407 response missing "
+ "Authenticate\n", fname);
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX "Clearing call\n", fname);
+ // Delete the previous transaction block
+ clean_method_request_trx(ccb, method, TRUE);
+ sip_cc_release(ccb->gsm_id, ccb->dn_line, CC_CAUSE_ERROR, NULL);
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ }
+ }
+
+ free_sip_message(response);
+ return;
+
+ case SIP_CLI_ERR_NOT_ALLOWED:
+ case SIP_SERV_ERR_NOT_IMPLEM:
+ if (RESP_OF_REFER == resp_type) {
+ /* Error occurred on the target end so need to inform transferror */
+ /*
+ * Since REFER method is not implemented at far side we got
+ * this error, at this point we need to switch to BYE/ALSO
+ * method. It is assumed that BYE/ALSO will be successful;
+ * otherwise, any way this call will be disconnected without
+ * any notification to the enduser which is normal if you
+ * use BYE/ALSO anyway. So fill up the cause as CC_CAUSE_OK
+ * and mimic as if transfer is done through BYE/ALSO and
+ * have GSM to disconnect and post us a disconnect local with
+ * also string
+ */
+ cc_feature_data_t data;
+
+ // Delete the previous transaction block
+ clean_method_request_trx(ccb, sipMethodRefer, TRUE);
+
+ ccb->referto = strlib_update(ccb->referto, ccb->sip_referTo);
+ data.notify.cause = CC_CAUSE_OK;
+ data.notify.cause_code = status_code;
+ data.notify.subscription = CC_SUBSCRIPTIONS_XFER;
+ data.notify.method = CC_XFER_METHOD_BYE;
+ data.notify.blind_xferror_gsm_id = 0;
+ sip_cc_feature(ccb->gsm_id, ccb->dn_line, CC_FEATURE_NOTIFY,
+ (void *) &data);
+ }
+ if (method == sipMethodInvite) {
+ sipSPISendFailureResponseAck(ccb, response, FALSE, 0);
+ if ((ccb->redirect_info != NULL) &&
+ (ccb->state == SIP_STATE_SENT_INVITE)) {
+ sip_redirect(ccb, response, status_code);
+ } else {
+ handle_error_for_state(ccb, status_code);
+ }
+ }
+
+ if (method == sipMethodNotify) {
+ clean_method_request_trx(ccb, sipMethodNotify, TRUE);
+ }
+ free_sip_message(response);
+ break;
+
+ case SIP_CLI_ERR_REQ_PENDING:
+ if (method == sipMethodInvite) {
+ CCSIP_DEBUG_STATE(DEB_L_C_F_PREFIX"%d Glare detected!\n",
+ DEB_L_C_F_PREFIX_ARGS(SIP_CALL_STATUS, ccb->dn_line, ccb->gsm_id, fname),
+ ccb->index);
+ sipSPISendFailureResponseAck(ccb, response, FALSE, 0);
+ // The other side has detected a glare condition -
+ // Need to inform GSM and let it take appropriate action
+ handle_error_for_state(ccb, status_code);
+ /*
+ * The glare condition handling is now handled by GSM so do not need
+ * to set the glare timers in the stack...
+ if (ccb->flags & INCOMING) {
+ // We did not initiate this call, so set timer between 0 and 2000ms
+ sip_platform_glare_avoidance_timer_start(cpr_rand()%2000,
+ ccb->index);
+ } else {
+ // We initiated this call, so set the timer between 2100 and 4000ms
+ sip_platform_glare_avoidance_timer_start(cpr_rand()%2000+2100,
+ ccb->index);
+ }
+ */
+ }
+
+ if (method == sipMethodNotify) {
+ clean_method_request_trx(ccb, sipMethodNotify, TRUE);
+ }
+
+ free_sip_message(response);
+ break;
+
+ default:
+ if (method == sipMethodInvite) {
+ sipSPISendFailureResponseAck(ccb, response, FALSE, 0);
+
+ if ((ccb->redirect_info != NULL)
+ && (ccb->state == SIP_STATE_SENT_INVITE)) {
+ sip_redirect(ccb, response, status_code);
+ } else {
+ handle_error_for_state(ccb, status_code);
+ }
+
+ } else if (method == sipMethodRefer) {
+ ccsipCCB_t *other_ccb;
+
+ /*
+ * The Transfer has failed. If the call being transferred is in the
+ * "Ringing" state, send a Cancel to the Proxy to tear down the call
+ * and free up the CCB.
+ */
+ // Delete the previous transaction block
+ clean_method_request_trx(ccb, sipMethodRefer, TRUE);
+
+ other_ccb = sip_sm_get_ccb_by_target_call_id(ccb->con_call_id);
+ if ((other_ccb != NULL) &&
+ (other_ccb->state == SIP_STATE_SENT_INVITE)) {
+ sipSPISendCancel(other_ccb);
+ sip_cc_release(other_ccb->gsm_id, other_ccb->dn_line,
+ CC_CAUSE_NORMAL, NULL);
+ sip_sm_change_state(other_ccb, SIP_STATE_RELEASE);
+ }
+ sip_cc_feature_ack(ccb->gsm_id, ccb->dn_line, CC_FEATURE_XFER,
+ NULL, CC_CAUSE_ERROR);
+
+ } else if (method == sipMethodNotify) {
+ clean_method_request_trx(ccb, sipMethodNotify, TRUE);
+ } else {
+ handle_error_for_state(ccb, status_code);
+ }
+ free_sip_message(response);
+ }
+
+}
+
+
+
+/*
+ *
+ ***** SIP_STATE_SENT_INVITE_CONNECTED
+ *
+ */
+void
+ccsip_handle_sentinviteconnected_ev_cc_connected_ack (ccsipCCB_t *ccb,
+ sipSMEvent_t *event)
+{
+ const char *fname = "ccsip_handle_sentinviteconnected_ev_cc_connected_ack";
+
+ /*
+ * Do not support sending out any body in the ACK.
+ * Send ACK.
+ */
+ if (sipSPISendAck(ccb, NULL) == FALSE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sipSPISendAck");
+ }
+ /*
+ * Reset the number of retires we have for authentication
+ * back to 0 because at this point, if the proxy required
+ * authentication, our ACK with our credentials must have
+ * succeeded
+ */
+// ccb->authen.retries_401_407 = 0;
+
+ sip_sm_change_state(ccb, SIP_STATE_ACTIVE);
+}
+
+
+/*
+ *
+ ***** SIP_STATE_RECV_INVITE
+ ***** SIP_STATE_RECV_INVITE_PROCEEDING
+ ***** SIP_STATE_RECV_INVITE_ALERTING
+ ***** SIP_STATE_RECV_INVITE_CONNECTED
+ *
+ */
+void
+ccsip_handle_recvinvite_ev_cc_setup_ack (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ sip_sm_change_state(ccb, SIP_STATE_RECV_INVITE);
+ ccb->dn_line = event->u.cc_msg->msg.setup_ack.line;
+}
+
+
+void
+ccsip_handle_recvinvite_ev_cc_proceeding (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ const char *fname = "recvinvite_ev_cc_proceeding";
+
+
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_FUNCTION_ENTRY),
+ ccb->index, ccb->dn_line, fname,
+ sip_util_state2string(ccb->state),
+ sip_util_event2string(event->type));
+
+ sip_sm_change_state(ccb, SIP_STATE_RECV_INVITE_PROCEEDING);
+}
+
+
+void
+ccsip_handle_recvinvite_ev_cc_alerting (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ sipSPISendInviteResponse180(ccb);
+ sip_sm_change_state(ccb, SIP_STATE_RECV_INVITE_ALERTING);
+}
+
+
+void
+ccsip_handle_recvinvite_ev_cc_connected (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ const char *fname = "recvinvite_ev_cc_connected";
+ int timer_h, timer_t1 = 500;
+
+ (void) sip_platform_localexpires_timer_stop(ccb->index);
+
+ CCSIP_DEBUG_STATE(DEB_L_C_F_PREFIX"SIPSM %d: connected\n",
+ DEB_L_C_F_PREFIX_ARGS(SIP_CALL_STATUS, ccb->dn_line, ccb->gsm_id, fname), ccb->index);
+
+ /* Send 200 OK */
+ ccsip_save_local_msg_body(ccb, &event->u.cc_msg->msg.connected.msg_body);
+ sipSPISendInviteResponse200(ccb);
+
+ // Start the INVITE Expires timer so that if we don't get an ACK we
+ // can release the call. Note that this timer is being reused.
+ config_get_value(CFGID_TIMER_T1, &timer_t1, sizeof(timer_t1));
+ timer_h = 64 * timer_t1;
+
+ if (sip_platform_expires_timer_start(timer_h, ccb->index, NULL, 0) != SIP_OK) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED), fname,
+ "sip_platform_expires_timer_start(ACK Timer)");
+ }
+
+ sip_sm_change_state(ccb, SIP_STATE_RECV_INVITE_CONNECTED);
+}
+
+// The handler below is called when we sent a 200OK for a received INVITE
+// but never received an ACK
+void
+ccsip_handle_recvinvite_ev_expires_timer (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ const char *fname = "recvinvite_ev_expires_timer";
+
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX"Sent 200OK but received no ACK\n",
+ DEB_F_PREFIX_ARGS(SIP_ACK, fname));
+
+ // Stop the retry timer, if any
+ sip_platform_msg_timer_stop(ccb->index);
+
+ // Send a BYE to the other side and change state to release
+ // and send release complete to GSM
+ sipSPISendBye(ccb, NULL, NULL);
+ sip_cc_release(ccb->gsm_id, ccb->dn_line, CC_CAUSE_ERROR, NULL);
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+}
+
+void
+ccsip_handle_recvinvite_ev_sip_ack (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ const char *fname = "recvinvite_ev_sip_ack";
+ sipMessage_t *request;
+ boolean no_media = FALSE;
+ uint16_t request_check_reason_code = 0;
+ char request_check_reason_phrase[SIP_WARNING_LENGTH];
+ sipsdp_status_t sdp_status;
+
+ /* Unpack the event */
+ request = event->u.pSipMessage;
+
+ /* Request check and store */
+ if (sip_sm_request_check_and_store(ccb, request, sipMethodAck, FALSE,
+ &request_check_reason_code,
+ request_check_reason_phrase, FALSE) < 0) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED), ccb->index,
+ ccb->dn_line, fname,
+ get_debug_string(DEBUG_FUNCTIONNAME_SIP_SM_REQUEST_CHECK_AND_STORE));
+ free_sip_message(request);
+ return;
+ }
+ // Stop the expires timer
+ (void) sip_platform_expires_timer_stop(ccb->index);
+
+ ccb->authen.cred_type = 0;
+
+ /*
+ * Extract SDP
+ */
+ sdp_status = sip_util_extract_sdp(ccb, request);
+
+ switch (sdp_status) {
+ case SIP_SDP_SUCCESS:
+ case SIP_SDP_SESSION_AUDIT:
+ if (ccb->oa_state != OA_OFFER_SENT) {
+ /*
+ * Received an offer SDP in an ACK.
+ */
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_ENTRY),
+ ccb->index, ccb->dn_line, fname,
+ "Received OFFER SDP in ACK, releasing call");
+ sipSPISendBye(ccb, NULL, NULL);
+ sip_cc_release(ccb->gsm_id, ccb->dn_line, CC_CAUSE_ERROR, NULL);
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ clean_method_request_trx(ccb, sipMethodInvite, FALSE);
+ clean_method_request_trx(ccb, sipMethodAck, FALSE);
+ return;
+ } else {
+ ccb->oa_state = OA_IDLE;
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX"Using the SDP in INVITE\n",
+ DEB_F_PREFIX_ARGS(SIP_ACK, fname));
+ }
+ break;
+
+ case SIP_SDP_DNS_FAIL:
+ case SIP_SDP_ERROR:
+ sipSPISendBye(ccb, NULL, NULL);
+ sip_cc_release(ccb->gsm_id, ccb->dn_line, CC_CAUSE_ERROR, NULL);
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ clean_method_request_trx(ccb, sipMethodInvite, FALSE);
+ clean_method_request_trx(ccb, sipMethodAck, FALSE);
+ return;
+
+ case SIP_SDP_NO_MEDIA:
+ case SIP_SDP_NOT_PRESENT:
+ default:
+ no_media = TRUE;
+ if (ccb->oa_state == OA_OFFER_SENT) {
+ sipSPISendBye(ccb, NULL, NULL);
+ sip_cc_release(ccb->gsm_id, ccb->dn_line, CC_CAUSE_ERROR, NULL);
+ clean_method_request_trx(ccb, sipMethodInvite, FALSE);
+ clean_method_request_trx(ccb, sipMethodAck, FALSE);
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ return;
+ } else {
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX"Using the SDP in INVITE\n",
+ DEB_F_PREFIX_ARGS(SIP_ACK, fname));
+ }
+ }
+
+ /*
+ * Update connected party info from RPID and Call-Info header.
+ * Received ACK from the remote, media manipulation may occur. Defer
+ * call information update.
+ */
+ ccsip_update_callinfo(ccb, request, TRUE, TRUE, TRUE);
+
+ if (no_media) {
+ sip_cc_connected_ack(ccb->gsm_id, ccb->dn_line, NULL);
+ } else {
+ sip_cc_connected_ack(ccb->gsm_id, ccb->dn_line, request);
+ }
+
+ // Add code to send BYE the transferee
+ if (ccb->wastransferred) {
+ ccsipCCB_t *refererccb = NULL;
+ cc_feature_data_t data;
+
+ refererccb = sip_sm_get_ccb_by_callid(ccb->sipxfercallid);
+ if (NULL != refererccb) {
+ data.notify.cause = CC_CAUSE_OK;
+ data.notify.cause_code = 200;
+ data.notify.subscription = CC_SUBSCRIPTIONS_XFER;
+ data.notify.method = CC_XFER_METHOD_REFER;
+ data.notify.blind_xferror_gsm_id = 0;
+ sip_cc_feature(refererccb->gsm_id, refererccb->dn_line,
+ CC_FEATURE_NOTIFY, (void *) &data);
+ }
+ strlib_free(ccb->sipxfercallid);
+ ccb->sipxfercallid = strlib_empty();
+ }
+
+ sip_sm_change_state(ccb, SIP_STATE_ACTIVE);
+ clean_method_request_trx(ccb, sipMethodAck, FALSE);
+ clean_method_request_trx(ccb, sipMethodInvite, FALSE);
+}
+
+// Handle a 2xx received in this state. Could be a 202 for a REFER we sent
+// out while in this state
+void
+ccsip_handle_recvinvite_ev_sip_2xx (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ const char *fname = "recvinvite_ev_sip_2xx";
+ sipMessage_t *response;
+ sipMethod_t method = sipMethodInvalid;
+ int response_code = 0;
+
+ /* Unpack the event */
+ response = event->u.pSipMessage;
+
+ /* Check if this is a REFER response */
+ if (sipGetResponseCode(response, &response_code) < 0) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sipGetResponseCode");
+ free_sip_message(response);
+ return;
+ }
+ if (sipGetResponseMethod(response, &method) < 0) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sipGetResponseMethod");
+ return;
+ }
+ if (response_code == SIP_ACCEPTED && method == sipMethodRefer) {
+ ccsip_handle_accept_2xx(ccb, event);
+ return;
+ }
+ free_sip_message(response);
+ clean_method_request_trx(ccb, method, TRUE);
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_STATE_UNCHANGED), ccb->index,
+ ccb->dn_line, fname, sip_util_state2string(ccb->state));
+}
+
+void
+ccsip_handle_disconnect_local (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ const char *fname = "disconnect_local";
+ char *alsoString = NULL;
+
+
+ /*
+ * If we arrived here from the SENT_INVITE_CONNECTED state,
+ * send an ACK for the 200 we received.
+ */
+ if (ccb->state == SIP_STATE_SENT_INVITE_CONNECTED) {
+ if (sipSPISendAck(ccb, NULL) == FALSE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sipSPISendAck");
+ }
+ }
+ // If we have sent an OK but not yet received the ACK, we should wait
+ // until it arrives before sending the BYE
+ if (ccb->state == SIP_STATE_RECV_INVITE_CONNECTED) {
+ // Stop the expires timer to receive ACK
+ (void) sip_platform_expires_timer_stop(ccb->index);
+ ccb->wait_for_ack = TRUE;
+ ccb->send_delayed_bye = TRUE;
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ sip_cc_release_complete(ccb->gsm_id, ccb->dn_line, CC_CAUSE_NORMAL);
+ return;
+ }
+
+ if (ccb->referto[0]) {
+ alsoString = (char *) cpr_malloc(MAX_SIP_URL_LENGTH);
+ if (alsoString == NULL) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ ccb->index, ccb->dn_line, fname,
+ "malloc(also string)");
+ } else {
+ sstrncpy(alsoString, ccb->referto, MAX_SIP_URL_LENGTH);
+ }
+ }
+
+ /* Send BYE message */
+ ccb->authen.cred_type = 0;
+
+ sipSPISendBye(ccb, alsoString, NULL);
+ if (ccb->state == SIP_STATE_SENT_MIDCALL_INVITE) {
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ sip_cc_release(ccb->gsm_id, ccb->dn_line, CC_CAUSE_RESP_TIMEOUT, NULL);
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "MIDCALL INVITE TMR EXPIRED");
+ } else {
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ sip_cc_release_complete(ccb->gsm_id, ccb->dn_line, CC_CAUSE_NORMAL);
+ }
+}
+
+
+void
+ccsip_handle_disconnect_media_change (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ const char *fname = "ccsip_handle_disconnect_media_change";
+ int code;
+ char *phrase;
+ char *alsoString = NULL;
+ cc_causes_t cause = CC_CAUSE_NORMAL;
+
+ cause = event->u.cc_msg->msg.release.cause;
+ if (cause == CC_CAUSE_NO_MEDIA || cause == CC_CAUSE_PAYLOAD_MISMATCH) {
+ /*
+ * Send Invite Response with correct cause message
+ */
+ code = ccsip_cc_to_sip_cause(cause, &phrase);
+ if (ccb->state == SIP_STATE_RECV_MIDCALL_INVITE_CCFEATUREACK_PENDING) {
+ sipSPISendInviteResponse(ccb, (uint16_t) code, phrase, 0, NULL,
+ FALSE /* no SDP */, TRUE /* reTx */);
+ ccb->wait_for_ack = TRUE;
+ ccb->send_delayed_bye = TRUE;
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ sip_cc_release_complete(ccb->gsm_id, ccb->dn_line, CC_CAUSE_NORMAL);
+ return;
+ } else {
+ (void) sipSPISendUpdateResponse(ccb, FALSE, cause, FALSE);
+ }
+ }
+
+ if (ccb->referto[0]) {
+ alsoString = (char *) cpr_malloc(MAX_SIP_URL_LENGTH);
+ if (alsoString == NULL) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ ccb->index, ccb->dn_line, fname, "malloc(also string)");
+ } else {
+ sstrncpy(alsoString, ccb->referto, MAX_SIP_URL_LENGTH);
+ }
+ }
+
+ /* Send BYE message */
+ ccb->authen.cred_type = 0;
+ sipSPISendBye(ccb, alsoString, NULL);
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ sip_cc_release_complete(ccb->gsm_id, ccb->dn_line, CC_CAUSE_NORMAL);
+}
+
+void
+ccsip_handle_disconnect_local_early (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ const char *fname = "disconnect_local_early";
+
+ /*
+ * Note that event.type should always be checked prior to dereferencing. Failure
+ * to check the event type can cause non-deterministic behavior when dereferencing
+ * the event structure.
+ */
+
+ /*
+ * Check for special case early attended transfer release.
+ */
+ if (event->type == E_CC_RELEASE) {
+ if (event->u.cc_msg->msg.release.cause == CC_CAUSE_NO_USER_RESP) {
+ ccb->early_transfer = TRUE;
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_ENTRY),
+ ccb->index, ccb->dn_line, fname,
+ "No action, Early Attended Transfer");
+ return;
+ }
+ }
+
+ /* Send CANCEL message only if we have recd at least a 1xx message in
+ * response to our INVITE. If not, we will mark the CCB and send it only
+ * when a 1xx is received - or if not - not at all
+ */
+ if (ccb->flags & RECD_1xx) {
+ sipSPISendCancel(ccb);
+ } else {
+ // Defer the CANCEL - Note we'll move to the RELEASE state even if we
+ // defer the CANCEL
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX"Received CC disconnect without 1xx from far side\n",
+ DEB_F_PREFIX_ARGS(SIP_CALL_STATUS, fname));
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_ENTRY),
+ ccb->index, ccb->dn_line, fname,
+ "Stopping retx timer");
+ sip_platform_msg_timer_stop(ccb->index);
+ ccb->flags |= SEND_CANCEL;
+ }
+
+ if (ccb->blindtransferred == TRUE) {
+ cc_feature_data_t data;
+
+ data.notify.cause = CC_CAUSE_OK;
+ data.notify.cause_code = SIP_CLI_ERR_REQ_CANCEL;
+ data.notify.subscription = CC_SUBSCRIPTIONS_XFER;
+ data.notify.method = CC_XFER_METHOD_REFER;
+ data.notify.blind_xferror_gsm_id = sip_sm_get_blind_xfereror_ccb_by_gsm_id(ccb->gsm_id);
+ sip_cc_feature(ccb->gsm_id, ccb->dn_line, CC_FEATURE_NOTIFY, (void *)&data);
+ } else if (ccb->wastransferred) {
+ /* The call was a transfer and we are ending it before
+ * we connect. GSM has already cleaned up the transfer
+ * data blocks for this when it received the END_CALL
+ * message from UI. We still need to send the NOTIFY
+ * message to the transferor, so we will send it from
+ * here.
+ */
+ ccsipCCB_t *referccb = NULL;
+
+ referccb = sip_sm_get_target_call_by_gsm_id(ccb->gsm_id);
+ if (referccb != NULL) {
+ ccb->flags |= FINAL_NOTIFY;
+ (void) sipSPISendNotify(referccb, SIP_CLI_ERR_REQ_CANCEL);
+ ccb->xfer_status = SIP_CLI_ERR_REQ_CANCEL;
+ }
+ }
+
+ if (event->type == E_SIP_INV_EXPIRES_TIMER) {
+ sip_cc_release(ccb->gsm_id, ccb->dn_line, CC_CAUSE_ERROR, NULL);
+ } else {
+ sip_cc_release_complete(ccb->gsm_id, ccb->dn_line, CC_CAUSE_NORMAL);
+ }
+
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+}
+
+void
+ccsip_handle_localexpires_timer (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ /* Send 486 error */
+ sipSPISendInviteResponse(ccb, SIP_CLI_ERR_BUSY_HERE,
+ SIP_CLI_ERR_BUSY_HERE_PHRASE,
+ 0, NULL, FALSE, /* no SDP */ TRUE /* reTx */);
+
+ /* tell GSM to cleanup */
+ sip_cc_release(ccb->gsm_id, ccb->dn_line, CC_CAUSE_NORMAL, NULL);
+
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+}
+
+static void
+ccsip_cc_to_warning (cc_causes_t cause, char **warning_phrase,
+ uint16_t *warning_code)
+{
+ switch (cause) {
+
+ case CC_CAUSE_PAYLOAD_MISMATCH:
+ *warning_phrase = SIP_WARN_INCOMPAT_MEDIA_FORMAT_PHRASE;
+ *warning_code = SIP_WARN_INCOMPAT_MEDIA_FORMAT;
+ break;
+
+ case CC_CAUSE_NO_MEDIA:
+ *warning_phrase = SIP_WARN_MEDIA_TYPE_UNAVAIL_PHRASE;
+ *warning_code = SIP_WARN_MEDIA_TYPE_UNAVAIL;
+ break;
+
+ default:
+ *warning_phrase = NULL;
+ *warning_code = 0;
+ }
+
+}
+
+
+int
+ccsip_cc_to_sip_cause (cc_causes_t cause, char **phrase)
+{
+ switch (cause) {
+
+ case CC_CAUSE_OK:
+ *phrase = SIP_SUCCESS_SETUP_PHRASE;
+ return SIP_SUCCESS_SETUP;
+
+ case CC_CAUSE_ERROR:
+ *phrase = SIP_CLI_ERR_BAD_REQ_PHRASE;
+ return SIP_CLI_ERR_BAD_REQ;
+
+ case CC_CAUSE_UNASSIGNED_NUM:
+ *phrase = SIP_CLI_ERR_NOT_FOUND_PHRASE;
+ return SIP_CLI_ERR_NOT_FOUND;
+
+ case CC_CAUSE_NO_RESOURCE:
+ *phrase = SIP_SERV_ERR_INTERNAL_PHRASE;
+ return SIP_SERV_ERR_INTERNAL;
+
+ case CC_CAUSE_BUSY:
+ *phrase = SIP_CLI_ERR_BUSY_HERE_PHRASE;
+ return SIP_CLI_ERR_BUSY_HERE;
+
+ case CC_CAUSE_ANONYMOUS:
+ *phrase = SIP_CLI_ERR_ANONYMITY_NOT_ALLOWED_PHRASE;
+ return SIP_CLI_ERR_ANONYMITY_NOT_ALLOWED;
+
+ case CC_CAUSE_INVALID_NUMBER:
+ *phrase = SIP_CLI_ERR_ADDRESS_PHRASE;
+ return SIP_CLI_ERR_ADDRESS;
+
+ case CC_CAUSE_PAYLOAD_MISMATCH:
+ *phrase = SIP_CLI_ERR_NOT_ACCEPT_HERE_PHRASE;
+ return SIP_CLI_ERR_NOT_ACCEPT_HERE;
+
+ case CC_CAUSE_NO_REPLACE_CALL:
+ *phrase = SIP_CLI_ERR_CALLEG_PHRASE;
+ return SIP_CLI_ERR_CALLEG;
+
+ case CC_CAUSE_REQUEST_PENDING:
+ *phrase = SIP_CLI_ERR_REQ_PENDING_PHRASE;
+ return SIP_CLI_ERR_REQ_PENDING;
+
+ default:
+ *phrase = SIP_CLI_ERR_BAD_REQ_PHRASE;
+ return SIP_CLI_ERR_BAD_REQ;
+ }
+}
+
+void
+ccsip_handle_disconnect_local_unanswered (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ int code;
+ char *phrase;
+ uint16_t warning_code = 0;
+ char *warning_phrase = NULL;
+
+ ccb->dn_line = event->u.cc_msg->msg.release.line;
+ code = ccsip_cc_to_sip_cause(event->u.cc_msg->msg.release.cause, &phrase);
+
+ ccsip_cc_to_warning(event->u.cc_msg->msg.release.cause, &warning_phrase, &warning_code);
+
+ /* Send Invite Response with correct cause message */
+ sipSPISendInviteResponse(ccb, (uint16_t)code, phrase, warning_code,
+ warning_phrase,
+ FALSE /*no SDP */ , TRUE /*reTx */ );
+
+ sip_cc_release_complete(ccb->gsm_id, ccb->dn_line, CC_CAUSE_NORMAL);
+ ccb->wait_for_ack = TRUE;
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+}
+
+
+void
+ccsip_handle_disconnect_remote (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ const char *fname = "disconnect_remote";
+ sipMessage_t *request;
+ sipMessage_t *store_invite_req;
+ const char *alsoString = NULL, *reasonHdr=NULL;
+ uint16_t request_check_reason_code = 0;
+ char request_check_reason_phrase[SIP_WARNING_LENGTH];
+ sipMethod_t method = sipMethodInvalid;
+ cc_causes_t cause = CC_CAUSE_NORMAL;
+
+ memset(request_check_reason_phrase, 0, SIP_WARNING_LENGTH);
+
+ /* Unpack the event */
+ request = event->u.pSipMessage;
+ store_invite_req = ccb->last_request;
+
+ sipGetRequestMethod(request, &method);
+
+ /* Request check and store */
+ if (sip_sm_request_check_and_store(ccb, request, method, TRUE,
+ &request_check_reason_code,
+ request_check_reason_phrase, TRUE) < 0) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ ccb->index, ccb->dn_line, fname,
+ get_debug_string(DEBUG_FUNCTIONNAME_SIP_SM_REQUEST_CHECK_AND_STORE));
+ (void) sipSPISendErrorResponse(request, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ request_check_reason_code,
+ request_check_reason_phrase, NULL);
+ free_sip_message(request);
+ return;
+ }
+
+ // Stop the expires timer
+ (void) sip_platform_expires_timer_stop(ccb->index);
+
+ //Check if this BYE is for the original call (between
+ //transferor and transferee) in attended transfer scenario.
+ if (ccb->con_call_id != CC_NO_CALL_ID) {
+ //Transferee has received a BYE
+ //from the transferor. Two scenarios are possible:
+ //1. BYE is received after receiving the 2xx/4xx/5xx/6xx for the
+ // consultative call. Therefore, setting wasTransferred flag
+ // to FALSE has no impact.
+ //2. BYE is received before receiving the 2xx/4xx/5xx/6xx for the
+ // consultative call.
+ // Therefore, setting wastransferred flag
+ // to FALSE, results in not sending the final NOTIFY
+ // after receiving 2xx/4xx/5xx/6xx from the target.
+ ccsipCCB_t *other_ccb;
+
+ other_ccb = sip_sm_get_ccb_by_target_call_id(ccb->con_call_id);
+ if (other_ccb) {
+ other_ccb->wastransferred = FALSE;
+ strlib_free(other_ccb->sipxfercallid);
+ other_ccb->sipxfercallid = strlib_empty();
+ }
+ }
+
+
+ /*
+ * Detect whether this is a Call Transfer by checking
+ * for the presence of the "Also:" header
+ */
+ alsoString = sippmh_get_header_val(request, SIP_HEADER_ALSO, NULL);
+ if (alsoString) {
+ cc_feature_data_t data;
+
+ CCSIP_DEBUG_STATE(DEB_L_C_F_PREFIX"%d Far end requested Call Transfer, "
+ "destination=<%s>\n",
+ DEB_L_C_F_PREFIX_ARGS(SIP_CALL_STATUS, ccb->dn_line, ccb->gsm_id, fname),
+ ccb->index, alsoString);
+ sstrncpy(data.xfer.dialstring, alsoString, strlen(alsoString) + 1);
+ data.xfer.cause = CC_CAUSE_XFER_REMOTE;
+ data.xfer.method = CC_XFER_METHOD_BYE;
+ data.xfer.target_call_id = CC_NO_CALL_ID;
+ ccb->referto = strlib_update(ccb->referto, alsoString);
+ sip_cc_feature(ccb->gsm_id, ccb->dn_line, CC_FEATURE_XFER, (void *)&data);
+ (void) sipSPISendByeOrCancelResponse(ccb, request, sipMethodBye);
+ free_sip_message(store_invite_req);
+ return;
+ } else {
+ /* Send BYE response message */
+ if (event->type == E_SIP_BYE) {
+ /*
+ * We want to wait for release_complete from GSM before sending
+ * the 200 OK out, in order to collect call_stats
+ */
+ ccb->flags |= RECD_BYE;
+ } else {
+ (void) sipSPISendByeOrCancelResponse(ccb, request, sipMethodCancel);
+ // if the reason header contains a reason code of 200
+ // we should pass this forward to gsm
+ reasonHdr = sippmh_get_header_val(request, SIP_HEADER_REASON, NULL);
+ if ( reasonHdr && strcasestr(reasonHdr, "cause=200;") ) {
+ cause = CC_SIP_CAUSE_ANSWERED_ELSEWHERE;
+ }
+ }
+
+ if (SIP_SM_CALL_SETUP_RESPONDING(ccb) ||
+ ccb->state == SIP_STATE_RECV_INVITE ||
+ ccb->state == SIP_STATE_RECV_INVITE_CONNECTED) {
+ /*
+ * Store invite request into ccb before sending 487. This is a
+ * temporary solution and should be removed in Moonpie
+ */
+ sipGetRequestMethod(store_invite_req, &method);
+ if (sip_sm_request_check_and_store(ccb, store_invite_req, method,
+ TRUE, &request_check_reason_code,
+ request_check_reason_phrase, FALSE) < 0) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED), ccb->index,
+ ccb->dn_line, fname,
+ get_debug_string(DEBUG_FUNCTIONNAME_SIP_SM_REQUEST_CHECK_AND_STORE));
+ free_sip_message(store_invite_req);
+ return;
+ }
+ sipSPISendInviteResponse(ccb, 487, SIP_CLI_ERR_REQ_CANCEL_PHRASE, 0,
+ NULL, FALSE, /* no SDP */ TRUE /* reTx */);
+ ccb->wait_for_ack = TRUE;
+ } else {
+ free_sip_message(store_invite_req);
+ }
+
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ sip_cc_release(ccb->gsm_id, ccb->dn_line, cause, NULL);
+ }
+}
+
+/* E_SIP_REFER */
+void
+ccsip_handle_refer_sip_message (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ const char *fname = "refer_sip_message";
+ sipMessage_t *request;
+ const char *contact = NULL;
+ uint16_t request_check_reason_code = 0;
+ char request_check_reason_phrase[SIP_WARNING_LENGTH];
+ sipMethod_t method = sipMethodInvalid;
+ cc_feature_data_t data;
+ char *referToString[MAX_REFER_TO_HEADERS] = { NULL };
+ char *referByString;
+ sipReferTo_t *referto = NULL;
+ sipReplaces_t *replaces_t = NULL;
+ int noOfReferTo = 0;
+ int noOfReferBy = 0;
+ char tempreferto[MAX_SIP_URL_LENGTH];
+ int rpid_flag = RPID_DISABLED;
+ char tempreferby[MAX_SIP_URL_LENGTH];
+ char *semi_token = NULL;
+ int rcode;
+ sipContact_t *contact_info = NULL;
+
+ memset(tempreferto, 0, MAX_SIP_URL_LENGTH);
+
+ /* Unpack the event */
+ request = event->u.pSipMessage;
+
+ /* transfer method if attended or blind */
+ ccb->featuretype = CC_FEATURE_BLIND_XFER; // Default is Blind
+
+ sipGetRequestMethod(request, &method);
+
+ // Check if we are already processing a previously received REFER
+ if (get_method_request_trx_index(ccb, method, FALSE) > -1) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Received REFER while processing an old one!\n", fname);
+ (void) sipSPISendErrorResponse(request, SIP_CLI_ERR_REQ_PENDING,
+ SIP_CLI_ERR_REQ_PENDING_PHRASE,
+ 0, NULL, NULL);
+ free_sip_message(request);
+ return;
+ }
+
+
+ /* Request check and store */
+ rcode = sip_sm_request_check_and_store(ccb, request, method, TRUE,
+ &request_check_reason_code,
+ request_check_reason_phrase, FALSE);
+ if (rcode < 0) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ ccb->index, ccb->dn_line, fname,
+ get_debug_string(DEBUG_FUNCTIONNAME_SIP_SM_REQUEST_CHECK_AND_STORE));
+
+ if (rcode == -2) { // trx malloc error
+ (void) sipSPISendErrorResponse(request, SIP_SERV_ERR_INTERNAL,
+ SIP_SERV_ERR_INTERNAL_PHRASE,
+ request_check_reason_code,
+ request_check_reason_phrase, NULL);
+ } else {
+ (void) sipSPISendErrorResponse(request, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ request_check_reason_code,
+ request_check_reason_phrase, NULL);
+ }
+ free_sip_message(request);
+ return;
+ }
+ contact = sippmh_get_cached_header_val(request, CONTACT);
+ if (contact) {
+ if (sipSPICheckContact(contact) < 0) { // If contact is invalid
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ ccb->index, ccb->dn_line, fname,
+ "sipSPICheckContact()");
+ (void) sipSPISendErrorResponse(request, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ SIP_WARN_MISC,
+ SIP_CLI_ERR_BAD_REQ_CONTACT_FIELD,
+ ccb);
+ return;
+ }
+ contact_info = sippmh_parse_contact(contact);
+ if (contact_info && contact_info->num_locations > 1) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Received REFER with multiple contacts!\n", fname);
+ (void) sipSPISendErrorResponse(request, SIP_CLI_ERR_AMBIGUOUS,
+ SIP_CLI_ERR_AMBIGUOUS_PHRASE,
+ SIP_WARN_MISC,
+ SIP_WARN_REFER_AMBIGUOUS_PHRASE,
+ ccb);
+ sippmh_free_contact(contact_info);
+ return;
+ }
+ if (contact_info) {
+ sippmh_free_contact(contact_info);
+ }
+ } else { // If No contact header
+ (void) sipSPISendErrorResponse(request, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ SIP_WARN_MISC,
+ SIP_CLI_ERR_BAD_REQ_CONTACT_FIELD,
+ ccb);
+ return;
+ }
+
+ /*
+ * Update connected party info from RPID and Call-Info header.
+ * Handing REFER, do not defer call information update.
+ */
+ ccsip_update_callinfo(ccb, request, TRUE, TRUE, FALSE);
+
+ // Store Refer Information such as Call_id and to-tag
+ // If replace is present then it must be attended transfer
+ noOfReferTo = sippmh_get_num_particular_headers(request, SIP_HEADER_REFER_TO,
+ SIP_C_HEADER_REFER_TO,
+ referToString, MAX_REFER_TO_HEADERS);
+
+ if (noOfReferTo == 1) {
+ referto = sippmh_parse_refer_to(referToString[0]);
+ }
+
+ if ((noOfReferTo == 0) || (noOfReferTo > 1) || (referto == NULL)) {
+
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED), ccb->index,
+ ccb->dn_line, fname,
+ "Incorrect number of Refer-To headers and/or value.\n");
+ (void) sipSPISendErrorResponse(request, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ SIP_WARN_MISC,
+ SIP_CLI_ERR_BAD_REQ_PHRASE_REFER_TO,
+ ccb);
+
+ if (referto) {
+ cpr_free(referto);
+ }
+ return;
+ }
+
+ sipSPIGenerateTargetUrl(referto->targetUrl, tempreferto);
+ ccb->sip_referTo = strlib_update(ccb->sip_referTo, tempreferto);
+ if (referto->sip_replaces_hdr != NULL) {
+ char tempreplace[MAX_SIP_URL_LENGTH];
+
+ memset(tempreplace, 0, MAX_SIP_URL_LENGTH);
+ sstrncpy(tempreplace, "Replaces=", sizeof(tempreplace));
+ sstrncat(tempreplace, referto->sip_replaces_hdr, (sizeof(tempreplace) - sizeof("Replaces=")));
+ replaces_t = sippmh_parse_replaces(tempreplace, FALSE);
+ if (NULL != replaces_t) {
+ ccb->sipxfercallid = strlib_update(ccb->sipxfercallid, replaces_t->callid);
+ if (ccb->sipxfercallid) {
+ ccb->sipxfercallid = strlib_append(ccb->sipxfercallid, ";to-tag=");
+ if (ccb->sipxfercallid) {
+ ccb->sipxfercallid = strlib_append(ccb->sipxfercallid, replaces_t->toTag);
+ }
+ if (ccb->sipxfercallid) {
+ ccb->sipxfercallid = strlib_append(ccb->sipxfercallid, ";from-tag=");
+ }
+ if (ccb->sipxfercallid) {
+ ccb->sipxfercallid = strlib_append(ccb->sipxfercallid, replaces_t->fromTag);
+ }
+ }
+ ccb->featuretype = CC_FEATURE_XFER;
+ sippmh_free_replaces(replaces_t);
+ } else {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED), ccb->index,
+ ccb->dn_line, fname,
+ "replaces header in referto missing callid or to/from tags");
+ (void) sipSPISendErrorResponse(request, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ SIP_WARN_MISC,
+ SIP_CLI_ERR_BAD_REQ_PHRASE_REFER_TO,
+ ccb);
+ sippmh_free_refer_to(referto);
+ return;
+ }
+ }
+#ifdef SIP_ACC_CONT
+ if (referto->sip_acc_cont != NULL) {
+ // attach the new string to the ccb...
+ // Note: This doesn't currently generate any header, but the hook
+ // is here if we need it later.
+ if (ccb->refer_acc_cont != NULL) {
+ cpr_free(ccb->refer_acc_cont);
+ ccb->refer_acc_cont = NULL;
+ }
+ ccb->refer_acc_cont = cpr_strdup(referto->sip_acc_cont);
+ }
+#endif
+
+ if (referto->sip_proxy_auth != NULL) {
+ if (ccb->refer_proxy_auth != NULL) {
+ // if there was already one of these, toss it out
+ cpr_free(ccb->refer_proxy_auth);
+ ccb->refer_proxy_auth = NULL;
+ }
+ // attach the new string to the ccb...
+ ccb->refer_proxy_auth = cpr_strdup(referto->sip_proxy_auth);
+ }
+
+ noOfReferBy = sippmh_get_num_particular_headers(request,
+ SIP_HEADER_REFERRED_BY,
+ SIP_C_HEADER_REFERRED_BY,
+ &referByString,
+ MAX_REFER_BY_HEADERS);
+
+ if (noOfReferBy == 0) {
+
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ ccb->index, ccb->dn_line, fname,
+ "Missing referred by header\n");
+ (void) sipSPISendErrorResponse(request, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ SIP_WARN_MISC,
+ SIP_CLI_ERR_BAD_REQ_PHRASE_REFER_BY,
+ ccb);
+ sippmh_free_refer_to(referto);
+ return;
+ }
+
+ if (noOfReferTo > 1 || noOfReferBy > 1) {
+
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ ccb->index, ccb->dn_line, fname,
+ "Multiple referto or refer by headers found in message");
+ (void) sipSPISendErrorResponse(request, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ SIP_WARN_MISC,
+ SIP_CLI_ERR_BAD_REQ_PHRASE_REFER,
+ ccb);
+ sippmh_free_refer_to(referto);
+ return;
+ }
+
+ config_get_value(CFGID_REMOTE_PARTY_ID, &rpid_flag, sizeof(rpid_flag));
+
+ if ((rpid_flag == RPID_ENABLED) && (ccb->best_rpid)
+ && (cpr_strcasecmp(ccb->best_rpid->privacy, PRIVACY_OFF) != 0)) {
+ snprintf(tempreferby, MAX_SIP_URL_LENGTH, "\"%s\" ",
+ SIP_HEADER_ANONYMOUS_STR,
+ ccb->best_rpid->loc->genUrl->u.sipUrl->user,
+ ccb->best_rpid->loc->genUrl->u.sipUrl->host);
+ ccb->sip_referredBy = strlib_update(ccb->sip_referredBy, tempreferby);
+ } else {
+ ccb->sip_referredBy = strlib_update(ccb->sip_referredBy, referByString);
+ }
+
+ sstrncpy(data.xfer.dialstring, referToString[0], sizeof(data.xfer.dialstring));
+ semi_token = strchr(data.xfer.dialstring, '?');
+ if (semi_token) {
+ *semi_token++ = '>';
+ *semi_token = 0;
+ }
+ if (data.xfer.dialstring[0] != '<') {
+ semi_token = strchr(data.xfer.dialstring, '>');
+ if (semi_token) {
+ *semi_token = 0;
+ }
+ }
+
+ /* Convert the escapeed userino part, if any to unescaped format */
+ if (unescape_UserInfo(data.xfer.dialstring, tempreferto, MAX_SIP_URL_LENGTH)) {
+ memset(data.xfer.dialstring, 0, CC_MAX_DIALSTRING_LEN);
+ sstrncpy(data.xfer.dialstring, tempreferto, CC_MAX_DIALSTRING_LEN);
+ }
+
+ data.xfer.method = CC_XFER_METHOD_REFER;
+ data.xfer.target_call_id = CC_NO_CALL_ID;
+ data.xfer.cause = CC_CAUSE_XFER_REMOTE;
+ if (ccb->featuretype == CC_FEATURE_BLIND_XFER) {
+ sstrncpy(data.xfer.referred_by, ccb->sip_referredBy,
+ MAX_SIP_URL_LENGTH);
+ sip_cc_feature(ccb->gsm_id, ccb->dn_line, CC_FEATURE_BLIND_XFER,
+ (void *) &data);
+ } else {
+ sip_cc_feature(ccb->gsm_id, ccb->dn_line, CC_FEATURE_XFER,
+ (void *) &data);
+ }
+ sippmh_free_refer_to(referto);
+}
+
+void
+ccsip_handle_process_in_call_options_request (ccsipCCB_t *ccb,
+ sipSMEvent_t *event)
+{
+ const char *fname = "ccsip_handle_process_in_call_options_request";
+ uint16_t request_check_reason_code = 0;
+ char request_check_reason_phrase[SIP_WARNING_LENGTH];
+ sipMessage_t *request;
+ sipMethod_t method = sipMethodInvalid;
+
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX"Processing within-dialog OPTIONS request\n",
+ DEB_F_PREFIX_ARGS(SIP_CALL_STATUS, fname));
+
+ /* Unpack the event */
+ request = event->u.pSipMessage;
+
+ ccb->featuretype = CC_FEATURE_NONE;
+
+ /* Request check and store */
+ sipGetRequestMethod(request, &method);
+ if (sip_sm_request_check_and_store(ccb, request, method, TRUE,
+ &request_check_reason_code,
+ request_check_reason_phrase, FALSE) < 0) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ ccb->index, ccb->dn_line, fname,
+ get_debug_string(DEBUG_FUNCTIONNAME_SIP_SM_REQUEST_CHECK_AND_STORE));
+ (void) sipSPISendErrorResponse(request, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ request_check_reason_code,
+ request_check_reason_phrase, NULL);
+ free_sip_message(request);
+ return;
+ }
+ // fixed CSCsi68191: The ccb->last_request and event->u.pSipMessage pointed to same memory address.
+ // Set last_request to NULL to avoid double deletion of memory, which is freed by
+ // gsm event of OPTION ACK later.
+ ccb->last_request = NULL;
+ sip_cc_options(ccb->gsm_id, ccb->dn_line, event->u.pSipMessage);
+}
+
+void
+ccsip_handle_ev_cc_answer_options_request (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ const char *fname = "ccsip_handle_ev_cc_answer_options_request";
+ cc_options_sdp_ack_t *options_sdp_ack;
+
+ options_sdp_ack = (cc_options_sdp_ack_t *) event->u.cc_msg;
+
+ if (!ccb) {
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX"Processing OPTIONS (out of dialog) "
+ "request(GSM has responded)\n", DEB_F_PREFIX_ARGS(SIP_CALL_STATUS, fname));
+ (void) sipSPIsendNonActiveOptionResponse((sipMessage_t *) options_sdp_ack->pMessage,
+ &options_sdp_ack->msg_body);
+
+ //since there is no call and therefore no ccb, we must free
+ //the SIP OPTIONS message here.
+ free_sip_message((sipMessage_t *)options_sdp_ack->pMessage);
+ options_sdp_ack->pMessage = NULL;
+ } else {
+ //Since there is a ccb, the SIP OPTIONS message will be freed
+ //in sip_sm_call_cleanup() after the call is done.
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX"Processing OPTIONS (in dialog) "
+ "request(GSM has responded)\n", DEB_F_PREFIX_ARGS(SIP_CALL_STATUS, fname));
+
+ // Must save sdp from gsm to ccb before building the response
+ ccsip_save_local_msg_body(ccb, &options_sdp_ack->msg_body);
+ (void) sipSPISendOptionResponse(ccb, event->u.pSipMessage);
+ }
+}
+
+void
+ccsip_handle_ev_cc_answer_audit_request (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ cc_audit_sdp_ack_t *audit_ack;
+
+
+ audit_ack = (cc_audit_sdp_ack_t *) event->u.cc_msg;
+ /*
+ * Use the new sdp generated by the gsm and free the old copy.
+ */
+ ccsip_save_local_msg_body(ccb, &audit_ack->msg_body);
+ sipSPISendInviteResponse200(ccb);
+}
+
+int
+sip_sm_process_event (sipSMEvent_t *pEvent)
+{
+ const char *fname = "sip_sm_process_event";
+ ccsipCCB_t *ccb;
+ sipSMAction_t event_handler = H_INVALID_EVENT;
+
+ ccb = pEvent->ccb;
+ if (!ccb) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"ccb is null. Unable to process event "
+ "<%d>\n", fname, pEvent->type);
+ return (-1);
+ }
+
+ /* Unbind UDP ICMP response handler */
+ UNBIND_UDP_ICMP_HANDLER(ccb->udpId);
+
+ /*
+ * ccb->index is an unsigned type and TEL_CCB_START is zero,
+ * so just check the end condition
+ */
+ if ((int) (ccb->index) > TEL_CCB_END) {
+ // We got an illegal line for our SIP SM
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"illegal line number: %d\n",
+ fname, ccb->index);
+ return (-1);
+ }
+
+ if (!sip_config_check_line(ccb->dn_line)) {
+ // We got an illegal DN for our SIP SM
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"illegal directory number: %d\n",
+ fname, ccb->dn_line);
+ return (-1);
+ }
+
+ if ((event_handler = get_handler_index(ccb->state, pEvent->type))
+ != H_INVALID_EVENT) {
+ CCSIP_DEBUG_STATE(DEB_L_C_F_PREFIX"Processing SM event: %d: --0x%08lx--%21s: %s <- %s\n",
+ DEB_L_C_F_PREFIX_ARGS(SIP_EVT, ccb->dn_line, ccb->gsm_id, fname),
+ ccb->index, EVENT_ACTION_SM(event_handler),
+ "", sip_util_state2string(ccb->state),
+ sip_util_event2string(pEvent->type));
+
+ EVENT_ACTION_SM(event_handler) (ccb, pEvent);
+ } else {
+ /* Invalid State/Event pair */
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"illegal state/event pair: "
+ "(%d <-- %d)\n", fname, ccb->state, pEvent->type);
+ return (-1);
+ }
+
+ return (0);
+}
+
+
+/**
+ *
+ * Extract the k factor stats sent by GSM and store a ptr on ccb
+ *
+ * @param pCCMsg - msg from GSM
+ * @param ccb - ccb for this call
+ *
+ * @return nothing
+ */
+void
+sip_extract_kfactor_stats (cc_msg_t *pCCMsg, ccsipCCB_t *ccb)
+{
+ if (pCCMsg->msg.release.msg_id == CC_MSG_RELEASE) {
+ ccb->kfactor_ptr = &pCCMsg->msg.release.kfactor;
+ } else if (pCCMsg->msg.release_complete.msg_id == CC_MSG_RELEASE_COMPLETE) {
+ ccb->kfactor_ptr = &pCCMsg->msg.release_complete.kfactor;
+ } else if ((pCCMsg->msg.feature.msg_id == CC_MSG_FEATURE) ||
+ (pCCMsg->msg.feature.msg_id == CC_MSG_FEATURE_ACK)) {
+ if (pCCMsg->msg.feature.feature_id == CC_FEATURE_HOLD) {
+ ccb->kfactor_ptr = &pCCMsg->msg.feature.data.hold.kfactor;
+ } else if (pCCMsg->msg.feature.feature_id == CC_FEATURE_MEDIA) {
+ ccb->kfactor_ptr = &pCCMsg->msg.feature.data.resume.kfactor;
+ } else {
+ ccb->kfactor_ptr = NULL;
+ }
+ } else {
+ ccb->kfactor_ptr = NULL;
+ }
+}
+int
+sip_sm_process_cc_event (cprBuffer_t buf)
+{
+ const char *fname = "sip_sm_process_cc_event";
+ sipSMEvent_t sip_sm_event;
+ line_t idx = 0;
+ sipSMAction_t event_handler = H_INVALID_EVENT;
+ cc_msg_t *pCCMsg = (cc_msg_t *) buf;
+
+ memset(&sip_sm_event, 0, sizeof(sipSMEvent_t));
+
+ sip_sm_event.u.cc_msg = pCCMsg;
+ sip_sm_event.type = sip_util_ccevent2sipccevent(pCCMsg->msg.setup.msg_id);
+ if (pCCMsg->msg.setup.msg_id == CC_MSG_SETUP) {
+ sip_sm_event.ccb = sip_sm_get_ccb_next_available(&idx);
+ if (!sip_sm_event.ccb) {
+ sip_cc_release(pCCMsg->msg.setup.call_id, pCCMsg->msg.setup.line,
+ CC_CAUSE_ERROR, NULL);
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"No free lines available\n",
+ DEB_F_PREFIX_ARGS(SIP_CALL_STATUS, fname));
+ cc_free_msg_data(sip_sm_event.u.cc_msg);
+ cpr_free(pCCMsg);
+ return SIP_OK;
+ }
+ } else if (pCCMsg->msg.setup.msg_id == CC_MSG_OPTIONS_ACK) {
+ /*
+ * Process the out of dialogue and in dialogue option ack
+ * (local sdp built by the gsm)
+ */
+ sip_sm_event.ccb = sip_sm_get_ccb_by_gsm_id(pCCMsg->msg.setup.call_id);
+ ccsip_handle_ev_cc_answer_options_request(sip_sm_event.ccb, &sip_sm_event);
+ cc_free_msg_data(sip_sm_event.u.cc_msg);
+ cpr_free(pCCMsg);
+ return (SIP_OK);
+ } else if (ccsip_handle_cc_select_event(&sip_sm_event)) {
+ /*
+ * The select feature has been handled.
+ */
+ cc_free_msg_data(sip_sm_event.u.cc_msg);
+ cpr_free(pCCMsg);
+ return SIP_OK;
+ } else if (ccsip_handle_cc_b2bjoin_event(&sip_sm_event)) {
+ /*
+ * The b2bjoin feature has been handled.
+ */
+ cc_free_msg_data(sip_sm_event.u.cc_msg);
+ cpr_free(pCCMsg);
+ return SIP_OK;
+ } else if (ccsip_handle_cc_hook_event(&sip_sm_event) == TRUE) {
+ /*
+ * The hook event has been handled.
+ */
+ cc_free_msg_data(sip_sm_event.u.cc_msg);
+ cpr_free(pCCMsg);
+ return SIP_OK;
+ } else {
+ sip_sm_event.ccb = sip_sm_get_ccb_by_gsm_id(pCCMsg->msg.setup.call_id);
+ if (!sip_sm_event.ccb) {
+ // If there is no associated CCB, this could be an
+ // Out of Dialog feature request
+ if (pCCMsg->msg.setup.msg_id == CC_MSG_FEATURE) {
+ // Call function to process an OOD Feature
+ // OOD features are handled by the sub/not API
+ // If unsuccessful processing
+ sip_cc_release(pCCMsg->msg.setup.call_id, pCCMsg->msg.setup.line,
+ CC_CAUSE_ERROR, NULL);
+ } else if (pCCMsg->msg.setup.msg_id == CC_MSG_RELEASE) {
+ sip_cc_release_complete(pCCMsg->msg.setup.call_id,
+ pCCMsg->msg.setup.line, CC_CAUSE_ERROR);
+ } else {
+ sip_cc_release(pCCMsg->msg.setup.call_id, pCCMsg->msg.setup.line,
+ CC_CAUSE_ERROR, NULL);
+ }
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"No ccb with matching gsm_id = <%d>\n",
+ DEB_F_PREFIX_ARGS(SIP_CALL_STATUS, fname),
+ pCCMsg->msg.setup.call_id);
+ cc_free_msg_data(sip_sm_event.u.cc_msg);
+ cpr_free(pCCMsg);
+ return SIP_OK;
+ }
+ }
+
+ if (pCCMsg->msg.setup.msg_id == CC_MSG_AUDIT_ACK) {
+ /*
+ * Process the in dialogue audit ack
+ * (local sdp built by the gsm)
+ */
+ ccsip_handle_ev_cc_answer_audit_request(sip_sm_event.ccb, &sip_sm_event);
+ cc_free_msg_data(sip_sm_event.u.cc_msg);
+ cpr_free(pCCMsg);
+ return (SIP_OK);
+ }
+
+ /* CSCds88133: ReTx timers cancelled prematurely */
+ if (sip_sm_event.ccb->state == SIP_STATE_IDLE_MSG_TIMER_OUTSTANDING) {
+ /* RAC FIXME - Don't like this... */
+ line_t line_index = (line_t) -1;
+
+ sip_sm_event.ccb = sip_sm_get_ccb_next_available(&line_index);
+ if (!sip_sm_event.ccb) {
+ if (pCCMsg->msg.setup.msg_id == CC_MSG_RELEASE) {
+ sip_cc_release_complete(pCCMsg->msg.setup.call_id,
+ pCCMsg->msg.setup.line, CC_CAUSE_ERROR);
+ } else {
+ sip_cc_release(pCCMsg->msg.setup.call_id, pCCMsg->msg.setup.line,
+ CC_CAUSE_ERROR, NULL);
+ }
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"sip_sm_get_ccb_next_available()"
+ " returned null.\n", fname);
+ cc_free_msg_data(sip_sm_event.u.cc_msg);
+ cpr_free(pCCMsg);
+ return SIP_OK;
+ }
+ /* Set this ccb to always be on the first DN. */
+ sip_sm_event.ccb->dn_line = 1;
+ }
+
+ sip_extract_kfactor_stats(pCCMsg, sip_sm_event.ccb);
+ event_handler = get_handler_index(sip_sm_event.ccb->state, sip_sm_event.type);
+ if (event_handler != H_INVALID_EVENT) {
+
+ DEF_DEBUG(DEB_L_C_F_PREFIX"Processing CC event: %-6d: SM: %s <- %s\n",
+ DEB_L_C_F_PREFIX_ARGS(SIP_EVT, sip_sm_event.ccb->dn_line,
+ sip_sm_event.ccb->gsm_id, fname),
+ (long)buf,
+ sip_util_state2string(sip_sm_event.ccb->state),
+ sip_util_event2string(sip_sm_event.type));
+
+ EVENT_ACTION_SM(event_handler)(sip_sm_event.ccb, &sip_sm_event);
+ } else {
+ /* Invalid State/Event pair */
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"illegal state/event pair: (%d <-- %d)\n",
+ fname, sip_sm_event.ccb->state, sip_sm_event.type);
+ cc_free_msg_data(sip_sm_event.u.cc_msg);
+ cpr_free(pCCMsg);
+ return SIP_ERROR;
+ }
+ sip_sm_event.ccb->kfactor_ptr = NULL;
+ cc_free_msg_data(sip_sm_event.u.cc_msg);
+ cpr_free(pCCMsg);
+ return SIP_OK;
+}
+
+void
+ccsip_handle_send_blind_notify (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ const char *fname = "send_blind_notify";
+ cc_features_t feature_type;
+
+ feature_type = event->u.cc_msg->msg.feature.feature_id;
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_FUNCTION_ENTRY),
+ ccb->index, ccb->dn_line, fname,
+ sip_util_state2string(ccb->state),
+ cc_feature_name(feature_type));
+
+ if (CC_FEATURE_NOTIFY == feature_type) {
+ if (event->u.cc_msg->msg.feature.data.notify.final == TRUE) {
+ ccb->flags |= FINAL_NOTIFY;
+ }
+ (void) sipSPISendNotify(ccb, event->u.cc_msg->msg.feature.data.notify.cause_code);
+ ccb->xfer_status = event->u.cc_msg->msg.feature.data.notify.cause_code;
+ } else {
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_FEATURE_UNSUPPORTED),
+ ccb->index, ccb->dn_line, fname);
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_STATE_UNCHANGED),
+ ccb->index, ccb->dn_line, fname,
+ sip_util_state2string(ccb->state));
+ sip_cc_feature_ack(ccb->gsm_id, ccb->dn_line, feature_type, NULL,
+ CC_CAUSE_ERROR);
+ }
+}
+
+void
+sip_sm_call_cleanup (ccsipCCB_t *ccb)
+{
+ const char *fname = "sip_sm_call_cleanup";
+ int i = 0;
+
+ if (ccb == NULL) {
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX"Null CCB passed into function.\n",
+ DEB_F_PREFIX_ARGS(SIP_CALL_STATUS, fname));
+ return;
+ }
+
+ /* first time the phone boots, this function gets called, but the
+ * CCBs haven't been initialized yet. This is the only time the
+ * dn_line can be zero. Otherwise, zero is invalid. On the first
+ * bootup, we don't need to do anything in this function.
+ */
+ if (ccb->dn_line == 0) {
+ return;
+ }
+
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_ENTRY),
+ ccb->index, ccb->dn_line, fname, "Cleaning up the call");
+
+ /*
+ * If there are any shared pointers because of duping
+ * make sure we have taken care of those
+ */
+ if (ccb->dup_flags & DUP_CCB) {
+ free_duped(ccb);
+ }
+
+ /* Cancel any outstanding timers */
+ (void) sip_platform_localexpires_timer_stop(ccb->index);
+
+ /*
+ * ccb->index is an unsigned type and TEL_CCB_START is zero,
+ * so just check the end condition
+ */
+ if ((int) (ccb->index) <= TEL_CCB_END) {
+ (void) sip_platform_supervision_disconnect_timer_stop(ccb->index);
+ submanager_update_ccb_addr(ccb);
+ }
+
+ /* Unbind UDP ICMP Unreachable handler just incase */
+ UNBIND_UDP_ICMP_HANDLER(ccb->udpId);
+
+ /* Free DNS Srv handle if present */
+ if (ccb->SRVhandle != NULL) {
+ dnsFreeSrvHandle(ccb->SRVhandle);
+ ccb->SRVhandle = NULL;
+ }
+
+ /* Free Ooutbound proxy DNS Srv handle if present */
+ if (ccb->ObpSRVhandle != NULL) {
+ dnsFreeSrvHandle(ccb->ObpSRVhandle);
+ ccb->ObpSRVhandle = NULL;
+ }
+
+ /*
+ * Store call history info
+ */
+ if ((int) (ccb->index) <= TEL_CCB_END) {
+ (void) sip_platform_expires_timer_stop(ccb->index);
+ (void) sip_platform_register_expires_timer_stop(ccb->index);
+ // bugid: CSCsz34666
+ memcpy(gCallHistory[ccb->index].last_call_id, ccb->sipCallID,
+ MAX_SIP_CALL_ID);
+ }
+
+ /* Free message bodies were saved during the cause of the call */
+ cc_free_msg_body_parts(&ccb->local_msg_body);
+
+ if (ccb->contact_info) {
+ sippmh_free_contact(ccb->contact_info);
+ ccb->contact_info = NULL;
+ }
+ if (ccb->record_route_info) {
+ sippmh_free_record_route(ccb->record_route_info);
+ ccb->record_route_info = NULL;
+ }
+
+ /* Free last recorded request */
+ if (ccb->last_request) {
+ free_sip_message(ccb->last_request);
+ ccb->last_request = NULL;
+ }
+
+ /* Free CC-Diversion headers */
+ for (i = 0; i < MAX_DIVERSION_HEADERS; i++) {
+ if (ccb->diversion[i]) {
+ cpr_free(ccb->diversion[i]);
+ ccb->diversion[i] = NULL;
+ }
+ }
+
+ sippmh_free_diversion_info(ccb->div_info);
+ ccb->div_info = NULL;
+ ccb->call_type = CC_CALL_NONE;
+
+ /* Free Redirection structure */
+ if (ccb->redirect_info) {
+ sippmh_free_contact(ccb->redirect_info->sipContact);
+ cpr_free(ccb->redirect_info);
+ ccb->redirect_info = NULL;
+ }
+
+ ccb->best_rpid = NULL;
+ sippmh_free_remote_party_id_info(ccb->rpid_info);
+ ccb->rpid_info = NULL;
+
+// ccb->authen.retries_401_407 = 0;
+ ccb->authen.cnonce[0] = '\0';
+ if (ccb->authen.authorization != NULL) {
+ cpr_free(ccb->authen.authorization);
+ ccb->authen.authorization = NULL;
+ }
+ if (ccb->refer_proxy_auth != NULL) {
+ cpr_free(ccb->refer_proxy_auth);
+ ccb->refer_proxy_auth = NULL;
+ }
+#ifdef SIP_ACC_CONT
+ if (ccb->refer_acc_cont != NULL) {
+ cpr_free(ccb->refer_acc_cont);
+ ccb->refer_acc_cont = NULL;
+ }
+#endif
+
+ if (ccb->authen.sip_authen != NULL) {
+ sippmh_free_authen(ccb->authen.sip_authen);
+ ccb->authen.sip_authen = NULL;
+ }
+
+ ccb->hold_initiated = FALSE;
+ ccb->wastransferred = FALSE;
+ ccb->blindtransferred = FALSE;
+ ccb->gsm_id = CC_NO_CALL_ID;
+ ccb->con_call_id = CC_NO_CALL_ID;
+ ccb->blind_xfer_call_id = CC_NO_CALL_ID;
+ ccb->xfer_status = 0;
+
+ if (ccb->old_session_id != NULL) {
+ cpr_free(ccb->old_session_id);
+ }
+ if (ccb->old_version_id != NULL) {
+ cpr_free(ccb->old_version_id);
+ }
+ ccb->old_session_id = NULL;
+ ccb->old_version_id = NULL;
+
+ ccb->displayCalledNumber = TRUE;
+ ccb->displayCallingNumber = TRUE;
+
+ /*free all the dynamically allocated strings */
+
+ strlib_free(ccb->calledDisplayedName);
+ strlib_free(ccb->callingNumber);
+ strlib_free(ccb->altCallingNumber);
+ strlib_free(ccb->callingDisplayName);
+ strlib_free(ccb->calledNumber);
+ strlib_free(ccb->ReqURIOriginal);
+ strlib_free(ccb->sip_from);
+ strlib_free(ccb->sip_to);
+ strlib_free(ccb->sip_to_tag);
+ strlib_free(ccb->sip_from_tag);
+ strlib_free(ccb->sip_contact);
+ strlib_free(ccb->sip_reqby);
+ strlib_free(ccb->sip_require);
+ strlib_free(ccb->sip_unsupported);
+ strlib_free(ccb->referto);
+ strlib_free(ccb->sip_referTo);
+ strlib_free(ccb->sip_referredBy);
+ strlib_free(ccb->sipxfercallid);
+ strlib_free(ccb->sip_remote_party_id);
+
+ if (ccb->in_call_info) {
+ ccsip_free_call_info_header(ccb->in_call_info);
+ ccb->in_call_info = NULL;
+ }
+ if (ccb->out_call_info) {
+ ccsip_free_call_info_header(ccb->out_call_info);
+ ccb->out_call_info = NULL;
+ }
+ if (ccb->join_info) {
+ sippmh_free_join_info(ccb->join_info);
+ ccb->join_info = NULL;
+ }
+ if (ccb->feature_data) {
+ cpr_free(ccb->feature_data);
+ ccb->feature_data = NULL;
+ }
+
+ for (i = 0; i < MAX_REQ_OUTSTANDING; i++) {
+ ccb->sent_request[i].cseq_number = CCSIP_START_CSEQ;
+ ccb->sent_request[i].cseq_method = sipMethodInvalid;
+ strlib_free(ccb->sent_request[i].u.sip_via_branch);
+ strlib_free(ccb->sent_request[i].sip_via_sentby);
+ ccb->recv_request[i].cseq_number = CCSIP_START_CSEQ;
+ ccb->recv_request[i].cseq_method = sipMethodInvalid;
+ strlib_free(ccb->recv_request[i].u.sip_via_header);
+ strlib_free(ccb->recv_request[i].sip_via_sentby);
+ }
+
+ if (ccb->index >= REG_CCB_START) {
+ /*
+ * Necessary to cast the SIP_REG_STATE_IDLE to properly initialize
+ * registration CCBs which use the same ccb->state field.
+ */
+ (void) sip_sm_ccb_init(ccb, ccb->index, ccb->dn_line,
+ SIP_REG_STATE_IDLE);
+ return;
+ }
+
+ if (sip_platform_msg_timer_outstanding_get(ccb->index)) {
+ sip_sm_change_state(ccb, SIP_STATE_IDLE_MSG_TIMER_OUTSTANDING);
+ (void) sip_sm_ccb_init(ccb, ccb->index, ccb->dn_line,
+ SIP_REG_STATE_IDLE /*_MSG_TIMER_OUTSTANDING */);
+ } else {
+ sip_sm_change_state(ccb, SIP_STATE_IDLE);
+ (void) sip_sm_ccb_init(ccb, ccb->index, 1, SIP_REG_STATE_IDLE);
+ }
+
+}
+
+
+int
+sip_sm_ccb_init (ccsipCCB_t *ccb, line_t ccb_index, int DN,
+ sipRegSMStateType_t initial_state)
+{
+ int nat_enable = 0;
+ uint8_t i;
+
+ /*
+ * TEL_CCB_START equates to zero and line_t is an unsigned type,
+ * so just check the end condition
+ */
+ if ((int) ccb_index <= TEL_CCB_END) {
+ memset(ccb, 0, sizeof(ccsipCCB_t));
+ }
+
+ ccb->dup_flags = DUP_NO_FLAGS;
+ ccb->mother_ccb = NULL;
+ sip_reg_sm_change_state(ccb, initial_state); /* print the debug msg also */
+ ccb->index = ccb_index;
+ ccb->hold_initiated = FALSE;
+ ccb->wastransferred = FALSE;
+ ccb->blindtransferred = FALSE;
+ ccb->callingNumber = strlib_empty();
+ ccb->calledNumberFirstDigitDialed = FALSE;
+ ccb->calledNumber = strlib_empty();
+ ccb->altCallingNumber = strlib_empty();
+ ccb->calledDisplayedName = strlib_empty();
+ ccb->callingDisplayName = strlib_empty();
+ ccb->displayCalledNumber = TRUE;
+ ccb->displayCallingNumber = TRUE;
+ ccb->calledNumberLen = 0;
+ ccb->ReqURIOriginal = strlib_empty();
+ ccb->sip_to_tag = strlib_empty();
+ ccb->sip_from_tag = strlib_empty();
+ ccb->sip_contact = strlib_empty();
+ ccb->sip_reqby = strlib_empty();
+ ccb->sip_require = strlib_empty();
+ ccb->sip_unsupported = strlib_empty();
+ ccb->sip_remote_party_id = strlib_empty();
+ ccb->flags = 0;
+ ccb->avt.payload_type = RTP_NONE;
+ ccb->alert_info = ALERTING_NONE;
+ ccb->alerting_ring = VCM_INSIDE_RING;
+ ccb->wait_for_ack = FALSE;
+ ccb->send_delayed_bye = FALSE;
+ ccb->retx_flag = FALSE;
+ ccb->early_transfer = FALSE;
+ ccb->redirect_info = NULL;
+ ccb->proxySelection = SIP_PROXY_DEFAULT;
+ ccb->outBoundProxyAddr = ip_addr_invalid;
+ ccb->outBoundProxyPort = 0;
+ ccb->oa_state = OA_IDLE;
+ ccb->call_type = CC_CALL_NONE;
+ ccb->cc_cfg_table_entry = NULL;
+ ccb->first_pass_3xx = TRUE;
+
+ /* Sip msg destination is set to proxy by default */
+ config_get_value(CFGID_NAT_ENABLE, &nat_enable, sizeof(nat_enable));
+ if (nat_enable == 0) {
+ sip_config_get_net_device_ipaddr(&(ccb->src_addr));
+ } else {
+ sip_config_get_nat_ipaddr(&(ccb->src_addr));
+ }
+
+ config_get_value(CFGID_VOIP_CONTROL_PORT, &ccb->local_port,
+ sizeof(ccb->local_port));
+
+ if ((int) ccb_index <= TEL_CCB_END) {
+ ccb->type = SIP_CALL_CCB;
+ ccb->dn_line = (line_t) DN;
+ sipTransportGetServerIPAddr(&(ccb->dest_sip_addr), ccb->dn_line);
+ ccb->dest_sip_port = sipTransportGetPrimServerPort(ccb->dn_line);
+ ccb->sipCallID[0] = '\0';
+ } else if ((ccb_index >= REG_CCB_START) && (ccb_index <= REG_CCB_END)) {
+ ccb->type = SIP_REG_CCB;
+ ccb->dn_line = ccb_index - MAX_TEL_LINES + 1;
+ sip_regmgr_set_cc_info(ccb_index, ccb->dn_line, &ccb->cc_type,
+ (void *)&ccb->cc_cfg_table_entry);
+ if (ccb->cc_type == CC_CCM) {
+ /*
+ * regmgr - If type of call control is ccm set the
+ * address here as well.
+ */
+ sipTransportGetServerIPAddr(&(ccb->dest_sip_addr), ccb->dn_line);
+ ccb->dest_sip_port = sipTransportGetPrimServerPort(ccb->dn_line);
+ } else {
+ /*
+ * regmgr - Assume it is CSPS for now.
+ */
+ ccb->dest_sip_addr = ip_addr_invalid;
+ ccb->dest_sip_port = sipTransportGetPrimServerPort(ccb->dn_line);
+ }
+ } else if (ccb_index == REG_BACKUP_CCB) {
+ ccb->type = SIP_REG_CCB;
+ ccb->dn_line = REG_BACKUP_DN;
+ sip_regmgr_set_cc_info(ccb_index, ccb->dn_line, &ccb->cc_type,
+ &ccb->cc_cfg_table_entry);
+ if (ccb->cc_type != CC_CCM) {
+ /*
+ * regmgr - Assume it is CSPS for now.
+ */
+ sipTransportGetBkupServerAddress(&ccb->dest_sip_addr, ccb->dn_line, ccb->reg.proxy);
+ ccb->dest_sip_port = sipTransportGetBkupServerPort(ccb->dn_line);
+ }
+ } else if ((ccb_index >= REG_FALLBACK_CCB_START) &&
+ (ccb_index <= REG_FALLBACK_CCB_END)) {
+ /*
+ * regmgr - There can be upto 3 fallback ccb's that get created
+ * dynamically. If the ccb index indicates that then set the
+ * type to be SIP_REG_CCB so that the register state
+ * machine gets the event.
+ */
+ ccb->type = SIP_REG_CCB;
+ ccb->dn_line = REG_BACKUP_DN;
+ }
+ /*
+ * Get the listen port that is configured from the
+ * Transport Interface instead of the direct config
+ * read from config.
+ */
+ ccb->local_port = sipTransportGetListenPort(ccb->dn_line, ccb);
+ /* Init SDP info */
+ memset(&ccb->local_msg_body, 0, sizeof(cc_msgbody_info_t));
+ //ccb->dest_port = 0;
+ //ccb->dest_addr = 0;
+ ccb->old_session_id = NULL;
+ ccb->old_version_id = NULL;
+
+ /* Into To:, From:, and Request-URI: fields */
+ ccb->ReqURI[0] = '\0';
+ ccb->sip_from = strlib_empty(); /* There is no pre-set From: field */
+ ccb->sip_to = strlib_empty(); /* There is no pre-set To: field */
+
+ // The following is the refer stuff
+
+ ccb->sip_referTo = strlib_empty();
+ ccb->sip_referredBy = strlib_empty();
+ ccb->referto = strlib_empty();
+ ccb->sipxfercallid = strlib_empty();
+ ccb->featuretype = CC_FEATURE_NONE;
+ ccb->join_info = NULL;
+ ccb->feature_data = NULL;
+
+ for (i = 0; i < MAX_REQ_OUTSTANDING; i++) {
+ ccb->sent_request[i].cseq_number = CCSIP_START_CSEQ;
+ ccb->sent_request[i].cseq_method = sipMethodInvalid;
+ ccb->sent_request[i].u.sip_via_branch = strlib_empty();
+ ccb->sent_request[i].sip_via_sentby = strlib_empty();
+ ccb->recv_request[i].cseq_number = CCSIP_START_CSEQ;
+ ccb->recv_request[i].cseq_method = sipMethodInvalid;
+ ccb->recv_request[i].u.sip_via_header = strlib_empty();
+ ccb->recv_request[i].sip_via_sentby = strlib_empty();
+ }
+
+ ccb->last_recv_request_cseq = 0;
+ ccb->last_recv_request_cseq_method = sipMethodInvalid;
+
+ if (ccb_index < REG_CCB_START) {
+ // If this is a tel CCB, restart the counter
+ ccb->last_used_cseq = CCSIP_START_CSEQ;
+ } else {
+ // If this is a reg CCB, continue from where we left off,
+ // and only initialize it the first time
+ if (ccb->last_used_cseq == 0) {
+ ccb->last_used_cseq = CCSIP_START_CSEQ;
+ }
+ }
+
+ ccb->last_request = NULL;
+
+ ccb->xfr_inprogress = SIP_SM_NO_XFR;
+
+
+ ccb->gsm_id = CC_NO_CALL_ID;
+ ccb->con_call_id = CC_NO_CALL_ID;
+ ccb->blind_xfer_call_id = CC_NO_CALL_ID;
+ ccb->xfer_status = 0;
+
+ /* AVT info */
+ config_get_value(CFGID_DTMF_AVT_PAYLOAD, &ccb->avt.payload_type,
+ sizeof(ccb->avt.payload_type));
+
+ /* SIP REGISTER info */
+ ccb->reg.registered = 0;
+ ccb->reg.tmr_expire = 0;
+ ccb->reg.act_time = 0;
+ ccb->reg.rereg_pending = 0;
+
+ /* SIP authentication info */
+ ccb->authen.retries_401_407 = 0;
+ ccb->authen.cred_type = 0;
+ ccb->authen.authorization = NULL;
+ ccb->authen.status_code = 0;
+ ccb->authen.nc_count = 0;
+ ccb->authen.new_flag = FALSE;
+ ccb->in_call_info = NULL;
+ ccb->out_call_info = NULL;
+ ccb->udpId = NULL;
+ ccb->callref = 0;
+
+ return (0);
+}
+
+
+
+const char *
+sip_util_state2string (sipSMStateType_t state)
+{
+ switch (state) {
+ case SIP_STATE_NONE:
+ return ("SIP_STATE_NONE");
+
+ case SIP_STATE_IDLE:
+ return ("SIP_STATE_IDLE");
+
+ case SIP_STATE_SENT_INVITE:
+ return ("SIP_STATE_SENT_INVITE");
+
+ case SIP_STATE_SENT_INVITE_CONNECTED:
+ return ("SIP_STATE_SENT_INVITE_CONNECTED");
+
+ case SIP_STATE_RECV_INVITE:
+ return ("SIP_STATE_RECV_INVITE");
+
+ case SIP_STATE_RECV_INVITE_PROCEEDING:
+ return ("SIP_STATE_RECV_INVITE_PROCEEDING");
+
+ case SIP_STATE_RECV_INVITE_ALERTING:
+ return ("SIP_STATE_RECV_INVITE_ALERTING");
+
+ case SIP_STATE_RECV_INVITE_CONNECTED:
+ return ("SIP_STATE_RECV_INVITE_CONNECTED");
+
+ case SIP_STATE_ACTIVE:
+ return ("SIP_STATE_ACTIVE");
+
+ case SIP_STATE_RECV_MIDCALL_INVITE_CCFEATUREACK_PENDING:
+ return ("SIP_STATE_RECV_MIDCALL_INVITE_CCFEATUREACK_PENDING");
+
+ case SIP_STATE_RECV_MIDCALL_INVITE_SIPACK_PENDING:
+ return ("SIP_STATE_RECV_MIDCALL_INVITE_SIPACK_PENDING");
+
+ case SIP_STATE_IDLE_MSG_TIMER_OUTSTANDING:
+ return ("SIP_STATE_IDLE_MSG_TIMER_OUTSTANDING");
+
+ case SIP_STATE_RELEASE:
+ return ("SIP_STATE_RELEASE");
+
+ case SIP_STATE_BLIND_XFER_PENDING:
+ return ("SIP_STATE_BLIND_XFER_PENDING");
+
+ case SIP_STATE_SENT_OOD_REFER:
+ return ("SIP_STATE_SENT_OOD_REFER");
+
+ case SIP_STATE_RECV_UPDATEMEDIA_CCFEATUREACK_PENDING:
+ return ("SIP_STATE_RECV_UPDATEMEDIA_CCFEATUREACK_PENDING");
+
+ case SIP_STATE_SENT_MIDCALL_INVITE:
+ return ("SIP_STATE_SENT_MIDCALL_INVITE");
+
+ default:
+ return ("UNKNOWN STATE");
+ }
+}
+
+
+const char *
+sip_util_event2string (sipSMEventType_t event)
+{
+ switch (event) {
+ case E_SIP_INVITE:
+ return ("E_SIP_INVITE");
+ case E_SIP_ACK:
+ return ("E_SIP_ACK");
+ case E_SIP_BYE:
+ return ("E_SIP_BYE");
+ case E_SIP_CANCEL:
+ return ("E_SIP_CANCEL");
+ case E_SIP_1xx:
+ return ("E_SIP_1xx");
+ case E_SIP_2xx:
+ return ("E_SIP_2xx");
+ case E_SIP_3xx:
+ return ("E_SIP_3xx");
+ case E_SIP_FAILURE_RESPONSE:
+ return ("E_SIP_FAILURE_RESPONSE");
+ case E_SIP_REFER:
+ return ("E_SIP_REFER");
+ case E_CC_SETUP:
+ return ("E_CC_SETUP");
+ case E_CC_SETUP_ACK:
+ return ("E_CC_SETUP_ACK");
+ case E_CC_PROCEEDING:
+ return ("E_CC_PROCEEDING");
+ case E_CC_ALERTING:
+ return ("E_CC_ALERTING");
+ case E_CC_CONNECTED:
+ return ("E_CC_CONNECTED");
+ case E_CC_CONNECTED_ACK:
+ return ("E_CC_CONNECTED_ACK");
+ case E_CC_RELEASE:
+ return ("E_CC_RELEASE");
+ case E_CC_RELEASE_COMPLETE:
+ return ("E_CC_RELEASE_COMPLETE");
+ case E_CC_FEATURE:
+ return ("E_CC_FEATURE");
+ case E_CC_FEATURE_ACK:
+ return ("E_CC_FEATURE_ACK");
+ case E_CC_CAPABILITIES:
+ return ("E_CC_CAPABILITIES");
+ case E_CC_CAPABILITIES_ACK:
+ return ("E_CC_CAPABILITIES_ACK");
+ case E_CC_SUBSCRIBE:
+ return ("E_CC_SUBSCRIBE");
+ case E_CC_INFO:
+ return ("E_CC_INFO");
+ case E_SIP_INV_EXPIRES_TIMER:
+ return ("E_SIP_INV_EXPIRES_TIMER");
+ case E_SIP_INV_LOCALEXPIRES_TIMER:
+ return ("E_SIP_INV_LOCALEXPIRES_TIMER");
+ case E_SIP_SUPERVISION_DISCONNECT_TIMER:
+ return ("E_SIP_SUPERVISION_DISCONNECT_TIMER");
+ case E_SIP_TIMER:
+ return ("E_SIP_TIMER");
+ case E_SIP_OPTIONS:
+ return ("E_SIP_OPTIONS");
+ case E_SIP_UPDATE:
+ return ("E_SIP_UPDATE");
+ case E_SIP_UPDATE_RESPONSE:
+ return ("E_SIP_UPDATE_RESPONSE");
+ case E_SIP_GLARE_AVOIDANCE_TIMER:
+ return ("E_SIP_GLARE_AVOIDANCE_TIMER");
+ case E_SIP_ICMP_UNREACHABLE:
+ return "E_SIP_ICMP_UNREACHABLE";
+ default:
+ return ("UNKNOWN EVENT");
+ }
+}
+
+
+sipSMEventType_t
+sip_util_ccevent2sipccevent (cc_msgs_t cc_msg_id)
+{
+ switch (cc_msg_id) {
+ case CC_MSG_SETUP:
+ return (E_CC_SETUP);
+ case CC_MSG_SETUP_ACK:
+ return (E_CC_SETUP_ACK);
+ case CC_MSG_PROCEEDING:
+ return (E_CC_PROCEEDING);
+ case CC_MSG_ALERTING:
+ return (E_CC_ALERTING);
+ case CC_MSG_CONNECTED:
+ return (E_CC_CONNECTED);
+ case CC_MSG_CONNECTED_ACK:
+ return (E_CC_CONNECTED_ACK);
+ case CC_MSG_RELEASE:
+ return (E_CC_RELEASE);
+ case CC_MSG_RELEASE_COMPLETE:
+ return (E_CC_RELEASE_COMPLETE);
+ case CC_MSG_FEATURE:
+ return (E_CC_FEATURE);
+ case CC_MSG_FEATURE_ACK:
+ return (E_CC_FEATURE_ACK);
+ case CC_MSG_INFO:
+ return (E_CC_INFO);
+ default:
+ return ((sipSMEventType_t) (-1));
+ }
+}
+
+
+void
+sip_create_new_sip_call_id (char *sipCallID, uint8_t *mac_address, char *pSrcAddrStr)
+{
+ static uint16_t count = 1;
+
+ count++;
+
+ if (sipCallID == NULL) {
+ return;
+ }
+ snprintf(sipCallID, MAX_SIP_CALL_ID, "%.4x%.4x-%.4x%.4x-%.8x-%.8x@%s",
+ mac_address[0] * 256 + mac_address[1],
+ mac_address[2] * 256 + mac_address[3],
+ mac_address[4] * 256 + mac_address[5],
+ count, (unsigned int)cpr_rand(), (unsigned int)cpr_rand(), pSrcAddrStr);
+}
+
+void
+sip_util_get_new_call_id (ccsipCCB_t *ccb)
+{
+ const char *fname = "sip_util_get_new_call_id";
+ uint8_t mac_address[MAC_ADDRESS_LENGTH];
+ char pSrcAddrStr[MAX_IPADDR_STR_LEN];
+ char *temp_call_id;
+
+ memset(pSrcAddrStr, 0, MAX_IPADDR_STR_LEN);
+
+ /* Args Check */
+ if (!ccb) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Args Check: ccb is null\n", fname);
+ return;
+ }
+
+ /* use same call id for registration */
+ if ((ccb->type == SIP_REG_CCB) && (ccb->sipCallID[0] != 0)) {
+ return;
+ }
+
+ /*
+ * use pre allocated sip call id, if available.
+ */
+ if (ccb->type != SIP_REG_CCB) {
+ temp_call_id = ccsip_find_preallocated_sip_call_id(ccb->dn_line);
+ if (temp_call_id != NULL) {
+ sstrncpy(ccb->sipCallID, temp_call_id, MAX_SIP_CALL_ID);
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX"using pre allocated call ID\n",
+ DEB_F_PREFIX_ARGS(SIP_CALL_STATUS, fname));
+ ccsip_free_preallocated_sip_call_id(ccb->dn_line);
+ return;
+ }
+ }
+ ipaddr2dotted(pSrcAddrStr, &ccb->src_addr);
+
+ platform_get_wired_mac_address(mac_address);
+
+ sip_create_new_sip_call_id(ccb->sipCallID, mac_address, pSrcAddrStr);
+}
+
+
+void
+sip_util_make_tag (char *pTagBuf)
+{
+ const char *fname = "sip_util_make_tag";
+ uint8_t mac_address[MAC_ADDRESS_LENGTH];
+ static uint16_t count = 1;
+
+ if (!pTagBuf) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Args Check: pTagBuf is null\n", fname);
+ return;
+ }
+
+ platform_get_wired_mac_address(mac_address);
+ count++;
+
+ snprintf(pTagBuf, MAX_SIP_URL_LENGTH, "%.4x%.4x%.4x%.4x%.8x-%.8x",
+ mac_address[0] * 256 + mac_address[1],
+ mac_address[2] * 256 + mac_address[3],
+ mac_address[4] * 256 + mac_address[5],
+ count, (unsigned int)cpr_rand(), (unsigned int)cpr_rand());
+}
+
+int
+sip_sm_init (void)
+{
+ line_t i;
+ const char *fname = "sip_sm_init";
+ int sdpmode = 0;
+
+ config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
+
+ if (!sdpmode) {
+
+ if (ccsip_register_init() == SIP_ERROR) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"registration initialization failed\n", fname);
+ return SIP_ERROR;
+ }
+
+ if (ccsip_info_package_handler_init() == SIP_ERROR) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"info package initialization failed\n", fname);
+ return SIP_ERROR;
+ }
+
+ /*
+ * Allocate timers for CCBs
+ */
+ if (sip_platform_timers_init() == SIP_ERROR) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"timer initialization failed\n", fname);
+ return SIP_ERROR;
+ }
+
+ if (sipTransportInit() != SIP_OK) {
+ return SIP_ERROR;
+ }
+
+ DEF_DEBUG(DEB_F_PREFIX"Disabling mass reg state", DEB_F_PREFIX_ARGS(SIP_REG, fname));
+ for (i = 0; i < MAX_CCBS; i++) {
+ if (i == 0 || i == (MAX_CCBS-1)) {
+ g_disable_mass_reg_debug_print = FALSE;
+ } else {
+ g_disable_mass_reg_debug_print = TRUE;
+ }
+ sip_sm_call_cleanup(&(gGlobInfo.ccbs[i]));
+ if (sip_sm_ccb_init(&(gGlobInfo.ccbs[i]), i, 1, SIP_REG_STATE_IDLE) < 0) {
+ return SIP_ERROR;
+ }
+ }
+ g_disable_mass_reg_debug_print = FALSE;
+
+ /* Initialize all timers */
+ sip_platform_msg_timers_init();
+
+ /* Initialize Subscription Manager */
+ if (sip_subsManager_init() != SIP_OK) {
+ return SIP_ERROR;
+ }
+
+ }
+
+ /* Initialize SDP Parser */
+ if (!sip_sdp_init()) {
+ /* Error initialize the SDP error */
+ return (SIP_ERROR);
+ }
+
+ return SIP_OK;
+}
+
+void
+ccsip_handle_sip_shutdown ()
+{
+ const char *fname = "handle_sip_shutdown";
+ ccsipCCB_t *ccb = NULL;
+ line_t i;
+
+ for (i = TEL_CCB_START; i <= TEL_CCB_END; i++) {
+ ccb = sip_sm_get_ccb_by_index(i);
+ if (ccb) {
+ switch (ccb->state) {
+ case SIP_STATE_RECV_INVITE:
+ case SIP_STATE_RECV_INVITE_PROCEEDING:
+ case SIP_STATE_RECV_INVITE_ALERTING:
+ CCSIP_DEBUG_STATE(DEB_L_C_F_PREFIX"Received invite: %d: STATE: %s\n",
+ DEB_L_C_F_PREFIX_ARGS(SIP_STATE, ccb->dn_line, ccb->gsm_id, fname),
+ ccb->index, sip_util_state2string(ccb->state));
+ sipSPISendInviteResponse(ccb, SIP_SERV_ERR_INTERNAL,
+ SIP_SERV_ERR_INTERNAL_PHRASE, 0, NULL,
+ FALSE /* no SDP */ , FALSE /* reTx */);
+ sip_cc_release_complete(ccb->gsm_id, ccb->dn_line,
+ CC_CAUSE_FACILITY_REJECTED);
+ ccb->wait_for_ack = FALSE;
+ sip_sm_change_state(ccb, SIP_STATE_IDLE);
+ sip_sm_call_cleanup(ccb);
+ break;
+
+ case SIP_STATE_RECV_INVITE_CONNECTED:
+ case SIP_STATE_ACTIVE:
+ default:
+ CCSIP_DEBUG_STATE(DEB_L_C_F_PREFIX"Clearing %d STATE: %s\n",
+ DEB_L_C_F_PREFIX_ARGS(SIP_STATE, ccb->dn_line, ccb->gsm_id, fname),
+ ccb->index, sip_util_state2string(ccb->state));
+ sipSPISendBye(ccb, NULL, NULL);
+ sip_sm_change_state(ccb, SIP_STATE_IDLE);
+ // send this to make sure GSM goes IDLE if it's currently in CONNECTED
+ sip_cc_release(ccb->gsm_id, ccb->dn_line, CC_CAUSE_ERROR, NULL);
+ sip_sm_call_cleanup(ccb);
+ break;
+
+ case SIP_STATE_SENT_INVITE:
+ CCSIP_DEBUG_STATE(DEB_L_C_F_PREFIX"Sent invite: Clearing %d STATE: %s\n",
+ DEB_L_C_F_PREFIX_ARGS(SIP_STATE, ccb->dn_line, ccb->gsm_id, fname),
+ ccb->index, sip_util_state2string(ccb->state));
+ sipSPISendCancel(ccb);
+ sip_sm_change_state(ccb, SIP_STATE_IDLE);
+ sip_cc_release_complete(ccb->gsm_id, ccb->dn_line,
+ CC_CAUSE_FACILITY_REJECTED);
+ sip_sm_call_cleanup(ccb);
+ break;
+
+ case SIP_STATE_SENT_INVITE_CONNECTED:
+ CCSIP_DEBUG_STATE(DEB_L_C_F_PREFIX"Sent invite connected: Clearing %d STATE: %s\n",
+ DEB_L_C_F_PREFIX_ARGS(SIP_STATE, ccb->dn_line, ccb->gsm_id, fname),
+ ccb->index, sip_util_state2string(ccb->state));
+ if (sipSPISendAck(ccb, NULL) == FALSE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sipSPISendAck");
+ }
+ sipSPISendBye(ccb, NULL, NULL);
+ sip_sm_change_state(ccb, SIP_STATE_IDLE);
+ // send this to make sure GSM goes IDLE if it's currently in CONNECTED
+ sip_cc_release(ccb->gsm_id, ccb->dn_line, CC_CAUSE_ERROR, NULL);
+ sip_sm_call_cleanup(ccb);
+ break;
+
+ case SIP_STATE_RELEASE:
+ CCSIP_DEBUG_STATE(DEB_L_C_F_PREFIX"Release: Clearing %d STATE: %s\n",
+ DEB_L_C_F_PREFIX_ARGS(SIP_STATE, ccb->dn_line, ccb->gsm_id, fname),
+ ccb->index, sip_util_state2string(ccb->state));
+ sip_sm_change_state(ccb, SIP_STATE_IDLE);
+ sip_cc_release_complete(ccb->gsm_id, ccb->dn_line,
+ CC_CAUSE_FACILITY_REJECTED);
+ sip_sm_call_cleanup(ccb);
+ break;
+
+ case SIP_STATE_IDLE:
+ break;
+ }
+
+ }
+ }
+}
+
+void
+sip_shutdown (void)
+{
+
+ DEF_DEBUG(DEB_F_PREFIX"SIP Shutting down...\n", DEB_F_PREFIX_ARGS(SIP_TASK, "sip_shutdown"));
+
+ // The SIP SM is already shut down
+ if (sip.taskInited == FALSE) {
+ return;
+ }
+
+ sip.taskInited = FALSE;
+ DEF_DEBUG(DEB_F_PREFIX" sip.taskInited is set to false\n", DEB_F_PREFIX_ARGS(SIP_TASK, "sip_shutdown"));
+
+//CPR TODO: need reference for
+ if ((PHNGetState() == STATE_CONNECTED) ||
+ (PHNGetState() == STATE_DONE_LOADING) ||
+ (PHNGetState() == STATE_CFG_UPDATE)) {
+
+ // Disconnect calls and clean CCB
+ ccsip_handle_sip_shutdown();
+
+ // Unregister from all servers and deallocate reg ack timer
+ sip_regmgr_shutdown();
+
+ // Stop and deallocate timers
+ sip_platform_timers_shutdown();
+
+ // Shutdown Subscription Manager
+ (void) sip_subsManager_shut();
+ //reset publish handler
+ publish_reset();
+
+ // Close all sockets
+ sipTransportShutdown();
+ ccsip_remove_wlan_classifiers();
+ }
+
+ ccsip_info_package_handler_shutdown();
+}
+
+/******
+void sip_restart_phase2 (void *data)
+{
+ sip.taskInited = TRUE; // Forcing sip_shutdown() to execute
+ sip_shutdown();
+ if (sip_sm_init() < 0) {
+ CCSIP_DEBUG_ERROR(" Error: sip_sm_init failed\n");
+ return;
+ }
+ sip_platform_init();
+ sip.taskInited = TRUE;
+ sip_mode_quiet = FALSE;
+ sip_reg_all_failed = FALSE;
+}
+
+void sip_restart_phase1 (void)
+{
+ if (sip_reg_all_failed) {
+ // NO CCM available; need not wait for unreg timer
+ sip_restart_phase2(NULL);
+ } else {
+ // Unregister all lines
+ ccsip_register_cancel(TRUE, TRUE);
+ // Start timer with a 2sec expiration
+ sip_platform_unregistration_timer_start(2000);
+
+ // Stop the periodic timer
+ (void) sip_platform_subnot_periodic_timer_stop();
+ }
+}
+*******/
+void
+sip_restart (void)
+{
+ const char *fname = "sip_restart";
+
+ DEF_DEBUG(DEB_F_PREFIX"In sip_restart\n", DEB_F_PREFIX_ARGS(SIP_CTRL, fname));
+ if (sip_sm_init() < 0) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"sip_sm_init failed\n", fname);
+ return;
+ }
+ sip_platform_init();
+ sip.taskInited = TRUE;
+ DEF_DEBUG(DEB_F_PREFIX"sip.taskInited is set to true \n", DEB_F_PREFIX_ARGS(SIP_CTRL, fname));
+ sip_mode_quiet = FALSE;
+ sip_reg_all_failed = FALSE;
+ ccsip_remove_wlan_classifiers();
+
+ // Initialize all GSM modules
+ cc_fail_fallback_gsm(CC_SRC_SIP, CC_RSP_COMPLETE, CC_REG_FAILOVER_RSP);
+}
+
+void
+sip_shutdown_phase2 (int action)
+{
+ DEF_DEBUG(DEB_F_PREFIX"(%d)\n",
+ DEB_F_PREFIX_ARGS(SIP_CTRL, "sip_shutdown_phase2"), action);
+ sip.taskInited = TRUE; // Forcing sip_shutdown() to execute
+ DEF_DEBUG(DEB_F_PREFIX"sip.taskInited is set to true\n", DEB_F_PREFIX_ARGS(SIP_CTRL, "sip_shutdown_phase2"));
+ sip_shutdown();
+ if (action == SIP_EXTERNAL || action == SIP_STOP) {
+ shutdownCCAck(action);
+ } else if (action == SIP_INTERNAL) {
+ // Continue on to reinit
+ sip_restart();
+ }
+}
+
+void
+sip_shutdown_phase1 (int action, int reason)
+{
+ DEF_DEBUG(DEB_F_PREFIX"In sip_shutdown_phase1 (%d)\n",
+ DEB_F_PREFIX_ARGS(SIP_CTRL, "sip_shutdown_phase1"), action);
+ if (sip_reg_all_failed) {
+ // NO CCM available; need not wait for unreg timer
+ sip_shutdown_phase2(action);
+ } else {
+ // Unregister all lines
+ ccsip_register_cancel(TRUE, TRUE);
+ // Start timer with a 2sec expiration
+ (void) sip_platform_unregistration_timer_start(2000, (boolean) action);
+ }
+}
+
+ccsipCCB_t *
+sip_sm_get_ccb_by_ccm_id_and_index (int ccmid, line_t idx)
+{
+ static const char fname[] = "sip_sm_get_ccb_by_ccm_id_and_index";
+ fallback_ccb_t *fallback_ccb;
+ ccsipCCB_t * ccb = NULL;
+ CCM_ID ccm_id = ccmid;
+
+ if (ccm_id >= MAX_CCM) {
+ CCSIP_DEBUG_ERROR(DEB_F_PREFIX"invalid ccm_id=%d "
+ "ccb_index=%d\n",DEB_F_PREFIX_ARGS(SIP_BRANCH, fname),
+ ccm_id , idx);
+ return ccb;
+ }
+
+ if ((int) idx < MAX_CCBS) {
+ ccb = &(gGlobInfo.ccbs[idx]);
+ }
+ /*
+ * regmgr - Could be Fallback ccb's
+ */
+ if (ccb == NULL) {
+ fallback_ccb = sip_regmgr_get_fallback_ccb_by_index(idx);
+ if (fallback_ccb != NULL) {
+ ccb = fallback_ccb->ccb;
+ }
+ }
+ if (ccb != NULL) {
+ if ((ccb->cc_cfg_table_entry == NULL) ||
+ (((ti_config_table_t *)(ccb->cc_cfg_table_entry))->ti_specific.ti_ccm.ccm_id != ccm_id)) {
+ /*
+ * the standby cucm must have moved to active position, but we did not
+ * yet have processed the failover response where ccb are updated to
+ * point to new active. That is why we are getting into this situation.
+ * Currently, we are throwing away the message, which is mainly the msg
+ * that standby cucm has sent. Should not do much harm.
+ */
+ DEF_DEBUG(DEB_F_PREFIX"ccb index has moved or cfg_table not initialized for the cucm=%s. "
+ "index=%d ccb=%d. Throwing away the msg.\n",DEB_F_PREFIX_ARGS(SIP_BRANCH, fname),
+ CCM_ID_PRINT(ccm_id), idx, ccb);
+ ccb = NULL;
+ }
+ }
+ if (ccb == NULL) {
+ CCSIP_DEBUG_ERROR(DEB_F_PREFIX"Could not find ccb ccb_index=%d",
+ DEB_F_PREFIX_ARGS(SIP_BRANCH, fname), idx);
+ }
+ return ccb;
+}
+
+ccsipCCB_t *
+sip_sm_get_ccb_by_index (line_t idx)
+{
+ fallback_ccb_t *fallback_ccb;
+
+ if ((int) idx < MAX_CCBS) {
+ return &(gGlobInfo.ccbs[idx]);
+ }
+ /*
+ * regmgr - Could be Fallback ccb's
+ */
+ fallback_ccb = sip_regmgr_get_fallback_ccb_by_index(idx);
+ if (fallback_ccb != NULL) {
+ return (fallback_ccb->ccb);
+ }
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_LINE_NUMBER_INVALID), "sip_sm_get_ccb_by_index",
+ idx);
+ return NULL;
+}
+
+
+ccsipCCB_t *
+sip_sm_get_ccb_by_callid (const char *callid)
+{
+ line_t i;
+
+ if (callid[0] == '\0') {
+ /* Requesting call ID is NULL string, not allow */
+ return (NULL);
+ }
+ for (i = 0; i < MAX_CCBS; i++) {
+ if (strcmp(callid, gGlobInfo.ccbs[i].sipCallID) == 0) {
+ return &(gGlobInfo.ccbs[i]);
+ }
+ }
+
+ return NULL;
+}
+
+callid_t
+sip_sm_get_blind_xfereror_ccb_by_gsm_id (callid_t gsm_id)
+{
+ uint16_t i;
+
+ for (i = 0; i < MAX_CCBS; i++) {
+ if (gsm_id == gGlobInfo.ccbs[i].blind_xfer_call_id) {
+ return gGlobInfo.ccbs[i].gsm_id;
+ }
+ }
+
+ return CC_NO_CALL_ID;
+}
+
+
+ccsipCCB_t *
+sip_sm_get_ccb_by_target_call_id (callid_t con_id)
+{
+ uint16_t i;
+
+ for (i = 0; i < MAX_CCBS; i++) {
+ if (con_id == gGlobInfo.ccbs[i].gsm_id) {
+ return &(gGlobInfo.ccbs[i]);
+ }
+ }
+
+ return NULL;
+}
+
+ccsipCCB_t *
+sip_sm_get_target_call_by_gsm_id (callid_t gsm_id)
+{
+ uint16_t i;
+
+ for (i = 0; i < MAX_CCBS; i++) {
+ if (gsm_id == gGlobInfo.ccbs[i].con_call_id) {
+ return &(gGlobInfo.ccbs[i]);
+ }
+ }
+
+ return NULL;
+}
+
+ccsipCCB_t *
+sip_sm_get_target_call_by_con_call_id (callid_t con_call_id)
+{
+ uint16_t i;
+
+ for (i = 0; i < MAX_CCBS; i++) {
+ if (con_call_id == gGlobInfo.ccbs[i].gsm_id) {
+ return &(gGlobInfo.ccbs[i]);
+ }
+ }
+
+ return NULL;
+}
+
+ccsipCCB_t *
+sip_sm_get_ccb_next_available (line_t *line_number)
+{
+ line_t i;
+
+ for (i = TEL_CCB_START; i <= TEL_CCB_END; i++) {
+ if (gGlobInfo.ccbs[i].state == SIP_STATE_IDLE) {
+ *line_number = i;
+ break;
+ }
+ }
+
+ if (i > TEL_CCB_END) {
+ return NULL;
+ }
+ return &(gGlobInfo.ccbs[i]);
+}
+
+/**
+ * sip_sm_get_ccb_by_gsm_id
+ *
+ * This fucntion tries to match the ccbs given the gsm id
+ * The algorithm tries to match the non duplicate CCB first
+ * If the only match is a DUP_CCB it shall be returned as a match
+ * @param[in] gsm_id GSM ID in the CCB
+ *
+ * @return ccsipCCB_t * or NULL
+ *
+ */
+ccsipCCB_t *
+sip_sm_get_ccb_by_gsm_id (callid_t gsm_id)
+{
+ line_t i;
+ ccsipCCB_t *dupCCB = NULL;
+
+ if ( gsm_id == CC_NO_CALL_ID )
+ return NULL;
+
+ for (i = 0; i < MAX_CCBS; i++) {
+ if (gGlobInfo.ccbs[i].gsm_id == gsm_id) {
+ if ( gGlobInfo.ccbs[i].dup_flags & DUP_CCB ) {
+ dupCCB = &(gGlobInfo.ccbs[i]);
+ } else {
+ return &(gGlobInfo.ccbs[i]);
+ }
+ }
+ }
+
+ return dupCCB;
+}
+
+/**
+ * sip_sm_ccb_match_branch_cseq
+ *
+ * This fucntion tries to match the Branch and Cseq ID for a
+ * given CCB to see if the values match in the response with the
+ * values sent in the request.
+ *
+ * @param[in] ccb Pointer to ccsipCCB_t structure.
+ * @param[in] sipCseq Pointer to sipCseq_t structure.
+ * @param[in] via_this Pointer to sipVia_t structure.
+ *
+ * @pre (ccb not_eq NULL)
+ * @pre (sipCseq not_eq NULL)
+ * @pre (via_this not_eq NULL)
+ *
+ * @return TRUE/FALSE
+ *
+ */
+static boolean
+sip_sm_ccb_match_branch_cseq (ccsipCCB_t *ccb,
+ sipCseq_t *sipCseq,
+ sipVia_t *via_this)
+{
+ const char *fname = "sip_sm_ccb_match_branch_cseq";
+ int16_t trx_index = -1;
+ sipTransaction_t *trx = NULL;
+
+ trx_index = get_method_request_trx_index(ccb, sipCseq->method,
+ TRUE);
+ if (trx_index != -1) {
+ // match cseq and viabranchid
+ trx = &(ccb->sent_request[trx_index]);
+ if ((trx->cseq_number == sipCseq->number) &&
+ (trx->u.sip_via_branch[0] != '\0') &&
+ (via_this->branch_param != NULL) &&
+ (strncmp(trx->u.sip_via_branch, via_this->branch_param,
+ VIA_BRANCH_LENGTH) == 0)) {
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX"Matched branch_id & CSeq\n", DEB_F_PREFIX_ARGS(SIP_BRANCH, fname));
+ return (TRUE);
+ } else {
+ CCSIP_DEBUG_ERROR(SIP_L_C_F_PREFIX"Mismatched CSeq or"
+ " Via's branch parameter in response:"
+ "ccb=0x%x,%d, cseq(trx,msg)=(%d,%d),"
+ "branch(trx,msg)=(%s,%s)\n",
+ ccb->dn_line, ccb->gsm_id, fname, ccb,
+ ccb->index, trx->cseq_number, sipCseq->number,
+ trx->u.sip_via_branch,
+ via_this->branch_param);
+ return (FALSE);
+ }
+ }
+
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Method index not found\n", fname);
+ return (FALSE);
+}
+
+// The function below attempts to determine more intelligently if there
+// is an existing dialog to which an incoming message should be directed.
+// In addition to call-id, it also considers the Req-URI, CSeq, etc.
+uint16_t
+sip_sm_determine_ccb (const char *callid,
+ sipCseq_t * sipCseq,
+ sipMessage_t *pSipMessage,
+ boolean is_request,
+ ccsipCCB_t **ccb_ret)
+{
+
+ const char *fname = "sip_sm_determine_ccb";
+ const char *to = NULL;
+ sipLocation_t *to_loc = NULL;
+ line_t i;
+ ccsipCCB_t *ccb = NULL;
+ sipReqLine_t *requestURI = NULL;
+ genUrl_t *genUrl = NULL;
+ sipUrl_t *sipUriUrl = NULL;
+ char *pUser = NULL;
+ char reqURI[MAX_SIP_URL_LENGTH];
+ int16_t trx_index = -1;
+ sipTransaction_t *trx = NULL;
+ sipVia_t *via_this = NULL;
+ sipVia_t *via_last = NULL;
+ const char *pViaHeaderStr = NULL;
+ boolean match = FALSE;
+
+ *ccb_ret = NULL;
+
+ // Dialog matching algorithm is as follows:
+ // First, obtain the CCB by matching call-id and to-tag, if present
+ to = sippmh_get_cached_header_val(pSipMessage, TO);
+ if (to) {
+ to_loc = sippmh_parse_from_or_to((char *)to, TRUE);
+ if (to_loc) {
+ if (to_loc->tag) {
+ for (i = 0; i < MAX_CCBS; i++) {
+ if (strcmp(callid, gGlobInfo.ccbs[i].sipCallID) == 0) {
+ ccb = &(gGlobInfo.ccbs[i]);
+ if (ccb->sip_to_tag[0] != '\0') {
+ if (strcmp(to_loc->tag, ccb->sip_to_tag) == 0) {
+ *ccb_ret = ccb;
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX"Matched to_tag\n",
+ DEB_F_PREFIX_ARGS(SIP_CALL_STATUS, fname));
+ break;
+ } else if (strcmp(to_loc->tag, ccb->sip_from_tag) == 0) {
+ *ccb_ret = ccb;
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX"Matched from_tag\n",
+ DEB_F_PREFIX_ARGS(SIP_CALL_STATUS, fname));
+ break;
+ }
+ }
+ }
+ }
+ }
+ sippmh_free_location(to_loc);
+ }
+ }
+
+ // Get the VIA parameters so proper matching can be done
+ pViaHeaderStr = sippmh_get_cached_header_val(pSipMessage, VIA);
+ if (pViaHeaderStr) {
+ via_this = sippmh_parse_via(pViaHeaderStr);
+ }
+ if (!pViaHeaderStr || !via_this) {
+ return (SIP_CLI_ERR_BAD_REQ);
+ }
+
+ // If not found, and this is a request, obtain by matching call-id,
+ // and user part of the ReqURI
+ if ((*ccb_ret == NULL) && is_request) {
+ reqURI[0] = '\0';
+ requestURI = sippmh_get_request_line(pSipMessage);
+ if (requestURI) {
+ if (requestURI->url) {
+ genUrl = sippmh_parse_url(requestURI->url, TRUE);
+ if (genUrl) {
+ if (genUrl->schema == URL_TYPE_SIP) {
+ sipUriUrl = genUrl->u.sipUrl;
+ if (sipUriUrl) {
+ pUser = sippmh_parse_user(sipUriUrl->user);
+ if (pUser) {
+ sstrncpy(reqURI, pUser, sizeof(reqURI));
+ cpr_free(pUser);
+ } else {
+ sstrncpy(reqURI, sipUriUrl->user, sizeof(reqURI));
+ }
+ }
+ }
+ sippmh_genurl_free(genUrl);
+ }
+ }
+ SIPPMH_FREE_REQUEST_LINE(requestURI);
+ }
+
+ for (i = 0; i < MAX_CCBS; i++) {
+ if (strcmp(callid, gGlobInfo.ccbs[i].sipCallID) == 0) {
+ ccb = &(gGlobInfo.ccbs[i]);
+ if (ccb->ReqURI[0] != '\0') {
+ if (strcmp(ccb->ReqURI, reqURI) == 0) {
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX"Matched reqURI\n",
+ DEB_F_PREFIX_ARGS(SIP_CALL_STATUS, fname));
+ *ccb_ret = ccb;
+ break;
+ }
+ }
+ }
+ }
+ if (*ccb_ret == NULL) {
+ for (i = 0; i < MAX_CCBS; i++) {
+ if (strcmp(callid, gGlobInfo.ccbs[i].sipCallID) == 0) {
+ ccb = &(gGlobInfo.ccbs[i]);
+ if ((sipCseq->method == sipMethodInvite) &&
+ (ccb->state < SIP_STATE_ACTIVE)) {
+ // Return this CCB if we match call-id but have
+ // not connected yet
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX"Matched Call-id - not active.\n",
+ DEB_F_PREFIX_ARGS(SIP_CALL_STATUS, fname));
+ *ccb_ret = ccb;
+ break;
+ }
+ if (((sipCseq->method == sipMethodCancel) &&
+ (ccb->state < SIP_STATE_ACTIVE)) ||
+ ((sipCseq->method == sipMethodAck) &&
+ (ccb->state == SIP_STATE_RELEASE))) {
+ // For CANCEL, try and match the via branch-id with the
+ // corresponding via branch-id of the INVITE received earlier.
+ // Normally the R-URI of the CANCEL should match the stored
+ // ReqURI but it is possible that the stored value was overwritten.
+ // via_last is the via header from the previous INVITE
+ // For ACK, we might be receiving this if there we responded with
+ // an error to the initial INVITE
+ trx_index = get_method_request_trx_index(ccb,
+ sipMethodInvite,
+ FALSE);
+
+ if (trx_index != -1) {
+ const char *toString;
+ const char *fromString;
+
+ toString = sippmh_get_cached_header_val(pSipMessage, TO);
+ fromString = sippmh_get_cached_header_val(pSipMessage, FROM);
+
+ trx = &(ccb->recv_request[trx_index]);
+
+ if (trx->u.sip_via_header[0] != '\0') {
+ pViaHeaderStr = (char *) (trx->u.sip_via_header);
+ via_last = sippmh_parse_via(pViaHeaderStr);
+ }
+
+ if (fromString && toString) {
+ if ((strcmp(ccb->sip_from, fromString) == 0) &&
+ (strncmp(ccb->sip_to, toString, strlen(toString)) == 0) &&
+ (trx->cseq_number == sipCseq->number) &&
+ (via_last && (via_last->branch_param != NULL)) &&
+ (via_this->branch_param != NULL) &&
+ (strcmp(via_last->branch_param, via_this->branch_param) == 0)) {
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX"Matched branch_id & CSeq for CANCEL/ACK\n",
+ DEB_F_PREFIX_ARGS(SIP_CALL_STATUS, fname));
+ *ccb_ret = ccb;
+ sippmh_free_via(via_last);
+ via_last = NULL;
+ break;
+ }
+ }
+ if (via_last) {
+ sippmh_free_via(via_last);
+ via_last = NULL;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // If found, and this is a request, check for any existing trx in
+ // progress by matching with recd trx's cseq method and number. If
+ // these are the same and the branch-id is different, this is a merged
+ // request. Here via_last is the via header from the last receipt of the same request
+ if ((*ccb_ret != NULL) && is_request) {
+ ccb = *ccb_ret;
+ trx_index = get_method_request_trx_index(ccb, sipCseq->method, FALSE);
+ if (trx_index != -1) {
+ if (ccb->recv_request[trx_index].u.sip_via_header[0] != '\0') {
+ pViaHeaderStr = (char *) (ccb->recv_request[trx_index].u.sip_via_header);
+ via_last = sippmh_parse_via(pViaHeaderStr);
+ }
+ if (via_last) {
+ if (sipCseq->number == ccb->recv_request[trx_index].cseq_number) {
+ if (via_this->branch_param && via_last->branch_param) {
+ if (strcmp(via_this->branch_param,
+ via_last->branch_param)) {
+ // merged request
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Found Merged Request\n", fname);
+ sippmh_free_via(via_this);
+ sippmh_free_via(via_last);
+ return (SIP_CLI_ERR_LOOP_DETECT);
+ }
+ }
+ }
+ sippmh_free_via(via_last);
+ }
+ }
+
+ }
+ // If this is a response, match it with a sent transaction in CCB
+ // by obtaining the CCB by call-id and then going through the
+ // transactions within it and matching branch-id and CSeq
+ if ((*ccb_ret == NULL) && !is_request) {
+
+ for (i = 0; i < MAX_CCBS; i++) {
+ if (strcmp(callid, gGlobInfo.ccbs[i].sipCallID) == 0) {
+ ccb = &(gGlobInfo.ccbs[i]);
+ match = sip_sm_ccb_match_branch_cseq(ccb, sipCseq,
+ via_this);
+ sippmh_free_via(via_this);
+ if (match) {
+ *ccb_ret = ccb;
+ return (0);
+ } else {
+ return (SIP_CLI_ERR_NOT_ACCEPT);
+ }
+ }
+ }
+ /*
+ * If ret_ccb is NULL after all this and the message is a
+ * response, check the fallback ccb list if any of those match
+ * the message call id.
+ */
+ sip_regmgr_find_fallback_ccb_by_callid(callid, ccb_ret);
+ }
+
+ /*
+ * If the CCB is not NULL and this is a response, then check
+ * if the branch and Cseq match.
+ */
+ if ((*ccb_ret != NULL) && !is_request) {
+ match = sip_sm_ccb_match_branch_cseq(*ccb_ret, sipCseq,
+ via_this);
+ sippmh_free_via(via_this);
+ if (match) {
+ return (0);
+ } else {
+ return (SIP_CLI_ERR_NOT_ACCEPT);
+ }
+ }
+
+ sippmh_free_via(via_this);
+ return (0);
+}
+
+void
+ccsip_handle_default (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ const char *fname = "ccsip_handle_default";
+
+ CCSIP_DEBUG_STATE(DEB_L_C_F_PREFIX"%d No action -> %s\n",
+ DEB_L_C_F_PREFIX_ARGS(SIP_CALL_STATUS, ccb->dn_line, ccb->gsm_id, fname),
+ ccb->index, sip_util_state2string(ccb->state));
+}
+
+
+void
+ccsip_handle_default_sip_message (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ const char *fname = "default_sip_message";
+ sipMessage_t *msg = NULL;
+ int16_t trx_index = -1;
+
+ msg = event->u.pSipMessage;
+
+ if (event->type == E_SIP_ACK) {
+ // If this is an ACK, make sure and clean out the corresponding INVITE
+ // transaction
+ clean_method_request_trx(ccb, sipMethodInvite, FALSE);
+ } else if (event->type == E_SIP_INVITE) {
+ // If this is an INVITE and we are already processing an earlier
+ // INVITE return a 500 response
+ trx_index = get_method_request_trx_index(ccb, sipMethodInvite, FALSE);
+ if (trx_index != -1) {
+ (void) sipSPISendErrorResponse(msg, SIP_SERV_ERR_INTERNAL,
+ SIP_SERV_ERR_INTERNAL_PHRASE,
+ SIP_WARN_PROCESSING_PREVIOUS_REQUEST,
+ "Earlier INVITE being processed",
+ NULL);
+ }
+ } else if (event->type == E_SIP_UPDATE) {
+ // If this is an UPDATE and we are already processing an earlier
+ // UPDATE return a 500 response
+ trx_index = get_method_request_trx_index(ccb, sipMethodUpdate, FALSE);
+ if (trx_index != -1) {
+ (void) sipSPISendErrorResponse(msg, SIP_SERV_ERR_INTERNAL,
+ SIP_SERV_ERR_INTERNAL_PHRASE,
+ SIP_WARN_PROCESSING_PREVIOUS_REQUEST,
+ "Earlier UPDATE being processed",
+ NULL);
+ }
+
+ } else if (event->type == E_SIP_CANCEL) {
+ (void) sipSPISendErrorResponse(msg, SIP_CLI_ERR_CALLEG,
+ SIP_CLI_ERR_CALLEG_PHRASE, 0, NULL, ccb);
+ CCSIP_DEBUG_STATE(DEB_L_C_F_PREFIX"%d: Sent 481 (CANCEL) %s\n",
+ DEB_L_C_F_PREFIX_ARGS(SIP_CALL_STATUS, ccb->dn_line, ccb->gsm_id, fname),
+ ccb->index, sip_util_state2string(ccb->state));
+ }
+
+ /* Deallocate the incoming SIP message */
+ if (msg) {
+ free_sip_message(msg);
+ }
+
+ CCSIP_DEBUG_STATE(DEB_L_C_F_PREFIX"%d: No action -> %s\n",
+ DEB_L_C_F_PREFIX_ARGS(SIP_CALL_STATUS, ccb->dn_line, ccb->gsm_id, fname),
+ ccb->index, sip_util_state2string(ccb->state));
+}
+
+/**
+ * ccsip_handle_default_ev_cc_feature
+ *
+ * The function is a default function for handling CC_FEATURE in the
+ * state that does not expect CC_FEATURE.
+ *
+ * @param[in] ccb Pointer to ccsipCCB_t structure.
+ * @param[in] event Pointer to sipSMEvent_t structure.
+ *
+ * @pre (ccb not_eq NULL)
+ *
+ * @return N/A
+ *
+ */
+void
+ccsip_handle_default_ev_cc_feature (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ const char *fname = "ccsip_handle_default_ev_cc_feature";
+ cc_features_t feature_type;
+
+ feature_type = event->u.cc_msg->msg.feature.feature_id;
+
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_FEATURE_UNSUPPORTED),
+ ccb->index, ccb->dn_line, fname);
+ /*
+ * The feature event is not supported by the current state or
+ * it is inappropriate event in the current state. Send feature ack
+ * with error code.
+ */
+ sip_cc_feature_ack(ccb->gsm_id, ccb->dn_line, feature_type, NULL,
+ CC_CAUSE_ERROR);
+}
+
+/**
+ * ccsip_handle_default_recvreq_ack_pending_ev_cc_feature
+ *
+ * The function is a default handler for CC_FEATURE while in the
+ * received INVITE, UPDATE and the state machine is waiting for
+ * feature ack from GSM or SIP ack pending.
+ *
+ * @param[in] ccb Pointer to ccsipCCB_t structure.
+ * @param[in] event Pointer to sipSMEvent_t structure.
+ *
+ * @pre (ccb not_eq NULL)
+ *
+ * @return N/A
+ */
+void
+ccsip_handle_default_recvreq_ack_pending_ev_cc_feature (ccsipCCB_t *ccb,
+ sipSMEvent_t *event)
+{
+ const char *fname =
+ "ccsip_handle_default_recvreq_ack_pending_ev_cc_feature";
+ cc_features_t feature_type;
+
+ feature_type = event->u.cc_msg->msg.feature_ack.feature_id;
+
+ switch (feature_type) {
+ case CC_FEATURE_RESUME:
+ case CC_FEATURE_HOLD:
+ case CC_FEATURE_MEDIA:
+ /*
+ * Received resume/hold/media request while waiting for feauture ack or
+ * SIP ack for hold that was received. Indicate that the request
+ * can not proceed now and it should be retried later.
+ */
+ sip_cc_feature_ack(ccb->gsm_id, ccb->dn_line, feature_type,
+ NULL, CC_CAUSE_REQUEST_PENDING);
+ break;
+
+ case CC_FEATURE_SELECT:
+ case CC_FEATURE_CANCEL:
+ break;
+ default:
+ /* Other feature request is not supported or allowed now */
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_FEATURE_UNSUPPORTED),
+ ccb->index, ccb->dn_line, fname);
+ sip_cc_feature_ack(ccb->gsm_id, ccb->dn_line, feature_type,
+ NULL, CC_CAUSE_ERROR);
+ break;
+ }
+}
+
+/*
+ * Function: sip_is_releasing()
+ *
+ * Parameters: ccb - The current call control block
+ *
+ * Description: This routine supports determining whether the
+ * the call is in releasing state or not.
+ *
+ * Returns:
+ * TRUE - call is being released.
+ * FALSE - call is not being released.
+ */
+boolean
+sip_is_releasing (ccsipCCB_t *ccb)
+{
+ if (ccb != NULL) {
+ /* Call exists */
+ if (ccb->state == SIP_STATE_RELEASE) {
+ return (TRUE);
+ }
+ }
+ return (FALSE);
+}
+
+void
+ccsip_handle_default_sip_response (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ const char *fname = "default_sip_response";
+ sipMessage_t *response;
+ int response_code = 0;
+
+ /* Unpack the event */
+ response = event->u.pSipMessage;
+
+ /* Get the response code */
+ if (sipGetResponseCode(response, &response_code) < 0) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sipGetResponseCode");
+ free_sip_message(response);
+ return;
+ }
+
+ /* Check if this is an INVITE response */
+ if ((!sip_sm_is_invite_response(response)) || (response_code < 200)) {
+ free_sip_message(response);
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_STATE_UNCHANGED), ccb->index,
+ ccb->dn_line, fname,
+ sip_util_state2string(ccb->state));
+ return;
+ }
+
+ if (sipSPISendAck(ccb, response) == FALSE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sipSPISendAck");
+ }
+ /* Deallocate the memory for the response */
+ free_sip_message(response);
+}
+
+/*
+ * ccsip_restart_reTx_timer
+ *
+ * This function is called when resending a message
+ * due to a timeout or ICMP unreachable. It just
+ * restarts the re-transmit timer.
+ */
+void
+ccsip_restart_reTx_timer (ccsipCCB_t *ccb, sipMethod_t messageType)
+{
+ const char *fname = "ccsip_restart_reTx_timer";
+ uint32_t time_t1 = 0;
+ uint32_t time_t2 = 0;
+ uint32_t timeout = 0;
+
+ /* Restart the reTx timer */
+ config_get_value(CFGID_TIMER_T1, &time_t1, sizeof(time_t1));
+ timeout = time_t1 * (1 << ccb->retx_counter);
+ // Adjust the max timer - but only for non INVITE transactions
+ if (messageType != sipMethodInvite) {
+ config_get_value(CFGID_TIMER_T2, &time_t2, sizeof(time_t2));
+ if (timeout > time_t2) {
+ timeout = time_t2;
+ }
+ }
+ CCSIP_DEBUG_STATE(DEB_L_C_F_PREFIX"%d: Restarting timer (%d msec)"
+ " (msg is %s)\n",
+ DEB_L_C_F_PREFIX_ARGS(SIP_TIMER, ccb->dn_line, ccb->gsm_id, fname),
+ ccb->index, timeout, sipGetMethodString(messageType));
+
+ ccb->retx_flag = TRUE;
+ if (sip_platform_msg_timer_start(timeout, (void *)((long)ccb->index), ccb->index,
+ sipPlatformUISMTimers[ccb->index].message_buffer,
+ sipPlatformUISMTimers[ccb->index].message_buffer_len,
+ sipPlatformUISMTimers[ccb->index].message_type,
+ &(sipPlatformUISMTimers[ccb->index].ipaddr),
+ sipPlatformUISMTimers[ccb->index].port,
+ FALSE) != SIP_OK) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED), ccb->index,
+ ccb->dn_line, fname,
+ "sip_platform_msg_timer_start()");
+ ccb->retx_flag = FALSE;
+ return;
+ }
+}
+
+/*
+ * ccsip_handle_obp_error()
+ *
+ * This function is called when a sip re-try timer
+ * pops or an ICMP unreachable is received after a
+ * msg is sent and the cause is the msg bounced or
+ * timed out trying to reach the outbound proxy.
+ *
+ * Data is the IP address that bounced or -1 if it was
+ * a timeout.
+ *
+ */
+void
+ccsip_handle_obp_error (ccsipCCB_t *ccb, sipMethod_t messageType, cpr_ip_addr_t *data)
+{
+ const char *fname = "ccsip_handle_obp_error";
+ boolean resend = FALSE;
+ uint32_t max_retx = 0;
+
+ char obp_address[MAX_IPADDR_STR_LEN];
+
+ config_get_string(CFGID_OUTBOUND_PROXY, obp_address, sizeof(obp_address));
+ /* Did the msg bounce? */
+ if (util_compare_ip(data, &ccb->outBoundProxyAddr)) {
+ /* Try next proxy if one exists */
+ ccb->outBoundProxyPort = 0;
+ ccb->retx_counter = 0;
+ if (str2ip(obp_address, &ccb->outBoundProxyAddr) != 0) {
+ resend = TRUE;
+ }
+
+ /* Msg timed out */
+ } else {
+ if (messageType == sipMethodInvite) {
+ config_get_value(CFGID_SIP_INVITE_RETX, &max_retx, sizeof(max_retx));
+ if (max_retx > MAX_INVITE_RETRY_ATTEMPTS) {
+ max_retx = MAX_INVITE_RETRY_ATTEMPTS;
+ }
+ } else {
+ config_get_value(CFGID_SIP_RETX, &max_retx, sizeof(max_retx));
+ if (max_retx > MAX_NON_INVITE_RETRY_ATTEMPTS) {
+ max_retx = MAX_NON_INVITE_RETRY_ATTEMPTS;
+ }
+ }
+
+ /* Retries exhausted, get next proxy if one exists */
+ if (ccb->retx_counter >= max_retx) {
+ ccb->outBoundProxyPort = 0;
+ ccb->retx_counter = 0;
+ if (str2ip(obp_address, &ccb->outBoundProxyAddr) != 0) {
+ /* if the obp is just an ip addr, there is nothing else to try */
+ resend = TRUE;
+ }
+
+ /* Retries not exhausted */
+ } else {
+ resend = TRUE;
+ }
+ }
+
+ if (resend) {
+ if (sipSPISendLastMessage(ccb) == TRUE) {
+ ccb->retx_counter++;
+ CCSIP_DEBUG_STATE(DEB_L_C_F_PREFIX"%d: Resent message: #%d\n",
+ DEB_L_C_F_PREFIX_ARGS(SIP_MSG_SEND, ccb->dn_line, ccb->gsm_id, fname),
+ ccb->index, ccb->retx_counter);
+ ccsip_restart_reTx_timer(ccb, messageType);
+ if (ccb->state == SIP_STATE_RELEASE) {
+ (void) sip_platform_supervision_disconnect_timer_stop(ccb->index);
+ }
+ } else {
+ sip_platform_msg_timer_outstanding_set(ccb->index, FALSE);
+ if ((ccb->state == SIP_STATE_IDLE_MSG_TIMER_OUTSTANDING) ||
+ (ccb->state == SIP_STATE_RELEASE)) {
+ sip_sm_change_state(ccb, SIP_STATE_IDLE);
+ sip_sm_call_cleanup(ccb);
+ } else {
+ sip_cc_release(ccb->gsm_id, ccb->dn_line, CC_CAUSE_ERROR, NULL);
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ }
+ }
+ } else {
+ sip_platform_msg_timer_outstanding_set(ccb->index, FALSE);
+ sip_cc_release(ccb->gsm_id, ccb->dn_line, CC_CAUSE_ERROR, NULL);
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ }
+}
+
+int
+ccsip_pick_a_proxy (ccsipCCB_t *ccb)
+{
+ uint32_t max_retx = 0;
+ sipMethod_t retxMessageType = sipPlatformUISMTimers[ccb->index].message_type;
+ char addr[MAX_IPADDR_STR_LEN];
+ const char *fname = "ccsip_pick_a_proxy";
+
+ memset(addr, 0, sizeof(addr));
+
+ /* Get the type of the retransmitted message.
+ * If it INVITE, then we need to use a different timer count
+ */
+ if (retxMessageType == sipMethodInvite) {
+ config_get_value(CFGID_SIP_INVITE_RETX, &max_retx, sizeof(max_retx));
+ if (max_retx > MAX_INVITE_RETRY_ATTEMPTS) {
+ max_retx = MAX_INVITE_RETRY_ATTEMPTS;
+ }
+ if (gGlobInfo.backup_active) {
+ if (ccb->proxySelection != SIP_PROXY_BACKUP) {
+ /*
+ * If we have previously failed to contract the normal/regular
+ * proxy then use a reduce re-try count for subsequent attempts
+ * i.e failover to the backup proxy faster
+ */
+ if (ccb->retx_counter >= 3) {
+ ccb->retx_counter = max_retx;
+ }
+ }
+ }
+ /*
+ * Check if we have maxed out the re-transmits on invite
+ * and not yet tried the backup proxy.
+ */
+ if ((ccb->retx_counter >= max_retx) &&
+ (ccb->proxySelection != SIP_PROXY_BACKUP) &&
+ (ccb->proxySelection != SIP_PROXY_DO_NOT_CHANGE_MIDCALL)) {
+ dns_error_code = DNS_ERR_HOST_UNAVAIL;
+ /* Try and fetch a proxy using DNS SRV records */
+ sipTransportGetPrimServerAddress(ccb->dn_line, addr);
+ if (str2ip(addr, &ccb->dest_sip_addr) != 0) {
+ dns_error_code = sip_dns_gethostbysrv(addr, &ccb->dest_sip_addr,
+ (uint16_t *)&ccb->dest_sip_port,
+ &ccb->SRVhandle, TRUE);
+ if (dns_error_code == DNS_OK) {
+ util_ntohl(&(ccb->dest_sip_addr), &(ccb->dest_sip_addr));
+ /*
+ * Modify destination fields in call back timer struct
+ */
+ (void) sip_platform_msg_timer_update_destination(ccb->index,
+ &(ccb->dest_sip_addr),
+ (uint16_t) ccb->dest_sip_port);
+ /*
+ * Reset re-transmit counter so we try again
+ */
+ ccb->retx_counter = 0;
+
+ }
+ }
+ /*
+ * Either we are using DNS SRV records and we exhausted the list
+ * Or we are not using DNS SRV and we need to try the backup
+ */
+ if (dns_error_code != DNS_OK) {
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Unable to reach proxy, attempting backup.\n",
+ DEB_F_PREFIX_ARGS(SIP_PROXY, fname));
+ if (ccsip_attempt_backup_proxy(ccb)) {
+
+ ccb->first_backup = TRUE;
+ /*
+ * Get rid of transaction block for the ccb, we may have
+ * tried primary proxy etc
+ */
+ clean_method_request_trx(ccb, sipMethodInvite, TRUE);
+
+ /*
+ * If contact info is supplied, as in the case of a 3xx
+ * redirect and perhaps other cases TBD. And since calls
+ * to the backup are essentially a "NEW" call so to speak,
+ * nuke it and run.
+ */
+ if (ccb->contact_info) {
+ sippmh_free_contact(ccb->contact_info);
+ ccb->contact_info = NULL;
+ }
+ /* Ditto for record route */
+ if (ccb->record_route_info) {
+ sippmh_free_record_route(ccb->record_route_info);
+ ccb->record_route_info = NULL;
+ }
+
+ /*
+ * Recreate the SIP message, because the IP address has
+ * changed. Ie. the reqURI has the old proxy IP address,
+ * but now it should have the new backup proxy address
+ * so we are setting boolean initInvite to TRUE. initInvite
+ * will be used in sipSPIGenRequestURI to make reqURI with
+ * new backup proxy address
+ */
+ if ((sipSPISendInvite(ccb,
+ ccb->wastransferred ? SIP_INVITE_TYPE_TRANSFER :
+ SIP_INVITE_TYPE_NORMAL, TRUE) != TRUE)) {
+ sip_sm_call_cleanup(ccb);
+ return FALSE;
+ }
+
+ /*
+ * Reset counters so we try again using the backup proxy
+ */
+ ccb->retx_counter = 0;
+
+ /* Backup proxy failed as well. Broadcast once */
+ } else {
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Attempt to reach backup proxy"
+ " failed. Message will be broadcast.\n",
+ DEB_F_PREFIX_ARGS(SIP_PROXY, fname));
+ return 1;
+ }
+ }
+ }
+ } else {
+ config_get_value(CFGID_SIP_RETX, &max_retx, sizeof(max_retx));
+ if (max_retx > MAX_NON_INVITE_RETRY_ATTEMPTS) {
+ max_retx = MAX_NON_INVITE_RETRY_ATTEMPTS;
+ }
+ }
+ return max_retx;
+}
+
+/*
+ * Function: ccsip_handle_icmp_unreachable:
+ * Description: This function handles ICMP events. For failed attempts
+ * for requests (that get back an ICMP) this function checks
+ * to see if we are in a dialog. If so, there is place holder
+ * to follow through with DNS SRV (future work) and if all
+ * DNS SRV calls have failed then it tears down the call.
+ *
+ * If request was an out-of-dialog request, the code sets
+ * the the ccb->retx_count to exceed max retries so it will
+ * be treated as a failure to send the server (so retries to
+ * the same server will not be attempted).
+ */
+void
+ccsip_handle_icmp_unreachable (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ const char *fname = "ccsip_handle_icmp_unreachable";
+
+ /*
+ * 1. Check to see if we are in a dialog
+ * 1.1. If we are in a dialog and the fqdn was resolved by SRV,
+ * then we must iterate to the next SRV result
+ * 1.2. if we have no more servers from the SRV lookup,
+ * we have to call it quits.
+ * 2. if we are not in a dialog, then map the icmp event to a timer event
+ * but set the retry count to appropriate value so the timer handler can
+ * pick up the next server rather than retry the same one.
+ */
+
+ if (ccb->sip_to_tag[0] != '\0') {
+ //we are in a dialog
+ // NOT USED: sipMessage_t *response;
+
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"ICMP received within a dialog.\n",
+ DEB_F_PREFIX_ARGS(SIP_CALL_STATUS, fname));
+ /*
+ * At this point we should be checking to see if we picked up an
+ * fqdn that picked up from the route set was a SRV RR. If so,
+ * we must iterate to the next result returned.
+ *
+ * But we cannot do that now. Our SRV mechanism is incorrect.
+ * Firstly we must store SRV associations (handle to srv returns)
+ * in the sipTransaction_t object.
+ *
+ * This is future work.
+ *
+ * So for now we clobber the call.
+ */
+
+ ccb->wait_for_ack = FALSE;
+ sip_cc_release_complete(ccb->gsm_id, ccb->dn_line, CC_CAUSE_NORMAL);
+ sip_sm_call_cleanup(ccb);
+ } else {
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"ICMP received outside of a dialog.\n",
+ DEB_F_PREFIX_ARGS(SIP_CALL_STATUS, fname));
+ //ccb->retx_counter = 100; //to cause failover to next proxy if one is available
+ ccsip_handle_default_sip_timer(ccb, event);
+ }
+}
+
+/*
+ * ccsip_handle_default_sip_timer()
+ *
+ * This function is called when a sip re-try timer
+ * pops or an ICMP unreachable is received after a
+ * msg is sent. The ICMP unreachable code sets
+ * retx_counter to MAX to force the code to try the
+ * next proxy in the list. Event.u.usrInfo is set to
+ * the IP address that bounced or -1 if it is a timeout.
+ *
+ * Note: Registration bounces and timeouts are handled
+ * by the function ccsip_handle_ev_tmr_retry.
+ */
+void
+ccsip_handle_default_sip_timer (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ const char *fname = "ccsip_handle_default_sip_timer";
+ uint32_t max_retx = 0;
+ sipMethod_t retxMessageType = sipPlatformUISMTimers[ccb->index].message_type;
+ char addr[MAX_IPADDR_STR_LEN];
+ cpr_ip_addr_t out_ip;
+
+ CPR_IP_ADDR_INIT(out_ip);
+
+ /* Timing issue on re-transmission and receiving an Ack.
+ * The timer could pop and we re-transmit and the Ack
+ * already be in the queue. When this happens, we process
+ * the Ack and go into the Active/Hold state. In the Active/Hold
+ * state, we don't expect an ack, so nothing happens and
+ * thus the new timer will eventually pop and start the
+ * whole process over. If we are in the Active/Hold state, we
+ * did receive the Ack. On the next time-out, just ignore it
+ * and don't re-start or re-transmit. The phone could be in
+ * the ACTIVE or HOLD states if a REFER has been sent with
+ * no response. Therefore ensure messagetype is not REFER
+ * before kicking out.
+ */
+ if ((retxMessageType != sipMethodRefer) &&
+ ((ccb->state == SIP_STATE_ACTIVE))) {
+ return;
+ }
+
+ /* OK, we got a timer pop, but the re-transmit flag
+ * isn't set. This means someone got a response that
+ * told them they could stop re-transmitting. Simply
+ * exit this function and do not re-start timer or
+ * re-transmit the message.
+ */
+ if (ccb->retx_flag == FALSE) {
+ if (ccb->state == SIP_STATE_IDLE_MSG_TIMER_OUTSTANDING) {
+ sip_platform_msg_timer_outstanding_set(ccb->index, FALSE);
+ sip_sm_change_state(ccb, SIP_STATE_IDLE);
+ sip_sm_call_cleanup(ccb);
+ }
+ return;
+ }
+
+ /* Determine if msg to outbound proxy bounced or timed out */
+ util_ntohl(&out_ip, &event->u.UsrInfo);
+ if ((util_compare_ip(&out_ip, &(ccb->outBoundProxyAddr))) ||
+ ((event->u.UsrInfo.type == CPR_IP_ADDR_INVALID) &&
+ util_check_if_ip_valid(&(ccb->outBoundProxyAddr)))) {
+ ccsip_handle_obp_error(ccb, retxMessageType, &(event->u.UsrInfo));
+ return;
+ }
+
+ /* Determine if there is a proxy to send to */
+ max_retx = ccsip_pick_a_proxy(ccb);
+
+ /* Increment counter */
+ ccb->retx_counter++;
+
+ /*
+ * Our work is done if the backup proxy has just been activated.
+ * We know that is has just been activated if the first_backup flag is TRUE.
+ */
+ if ((ccb->proxySelection == SIP_PROXY_BACKUP) && (ccb->first_backup)) {
+ ccb->first_backup = FALSE;
+ return;
+ }
+
+ /* Resend */
+ if (ccb->retx_counter <= max_retx) {
+ if (sipSPISendLastMessage(ccb) == TRUE) {
+ CCSIP_DEBUG_STATE(DEB_L_C_F_PREFIX"%d:Resent message: #%d\n",
+ DEB_L_C_F_PREFIX_ARGS(SIP_MSG_SEND, ccb->dn_line, ccb->gsm_id, fname),
+ ccb->index, ccb->retx_counter);
+ }
+ if (ccb->state == SIP_STATE_RELEASE) {
+ (void) sip_platform_supervision_disconnect_timer_stop(ccb->index);
+ }
+ ccsip_restart_reTx_timer(ccb, retxMessageType);
+
+ /* All retransmit attempts have been exhausted */
+ } else {
+ ccb->retx_counter = 0;
+ sip_platform_msg_timer_outstanding_set(ccb->index, FALSE);
+
+ /* Check for redirection */
+ if (ccb->state == SIP_STATE_SENT_INVITE) {
+ if (ccb->redirect_info != NULL) {
+ sip_redirect(ccb, NULL, SIP_CLI_ERR_REQ_TIMEOUT);
+ return;
+ }
+ }
+ /*
+ * Resend msg to next proxy in the list if one exists
+ * Try and fetch another proxy using DNS SRV or A records
+ */
+ sipTransportGetPrimServerAddress(ccb->dn_line, addr);
+ if (str2ip(addr, &ccb->dest_sip_addr) != 0) {
+ dns_error_code = sipTransportGetServerAddrPort(addr,
+ &ccb->dest_sip_addr,
+ (uint16_t *)&ccb->dest_sip_port,
+ &ccb->SRVhandle,
+ TRUE);
+ } else {
+ /* This ip addr has already been tried */
+ dns_error_code = DNS_ERR_HOST_UNAVAIL;
+ }
+ if (dns_error_code == 0) {
+ util_ntohl(&(ccb->dest_sip_addr), &(ccb->dest_sip_addr));
+ /* Modify destination fields in call back timer */
+ (void) sip_platform_msg_timer_update_destination(ccb->index,
+ &(ccb->dest_sip_addr),
+ (uint16_t)ccb->dest_sip_port);
+ if (sipSPISendLastMessage(ccb) == TRUE) {
+ CCSIP_DEBUG_STATE(DEB_L_C_F_PREFIX"%d: Resent message: #%d\n",
+ DEB_L_C_F_PREFIX_ARGS(SIP_MSG_SEND, ccb->dn_line, ccb->gsm_id, fname),
+ ccb->index, ccb->retx_counter);
+ }
+ ccsip_restart_reTx_timer(ccb, retxMessageType);
+ if (ccb->state == SIP_STATE_RELEASE) {
+ (void) sip_platform_supervision_disconnect_timer_stop(ccb->index);
+ }
+ } else {
+ if ((ccb->state == SIP_STATE_IDLE_MSG_TIMER_OUTSTANDING) ||
+ (ccb->state == SIP_STATE_RELEASE)) {
+ sip_sm_change_state(ccb, SIP_STATE_IDLE);
+ sip_sm_call_cleanup(ccb);
+ return;
+ } else if (retxMessageType == sipMethodRefer &&
+ (ccb->featuretype == CC_FEATURE_B2BCONF ||
+ ccb->featuretype == CC_FEATURE_SELECT ||
+ ccb->featuretype == CC_FEATURE_B2B_JOIN ||
+ ccb->featuretype == CC_FEATURE_CANCEL)) {
+ sip_cc_feature_ack(ccb->gsm_id, ccb->dn_line, ccb->featuretype,
+ NULL, CC_CAUSE_ERROR);
+ return;
+ } else {
+ handle_error_for_state(ccb, SIP_CLI_ERR_REQ_TIMEOUT);
+ return;
+ }
+ }
+ }
+
+ /* Restart re-transmit timer */
+ ccsip_restart_reTx_timer(ccb, retxMessageType);
+}
+
+
+void
+sip_decrement_backup_active_count (ccsipCCB_t *ccb)
+{
+ /*
+ * OK If we successfully received a response we need to back off from using the backup
+ * proxy if that was the case. Note if this is a response from the backup chuck it
+ */
+ if ((gGlobInfo.backup_active) && (ccb->proxySelection != SIP_PROXY_BACKUP))
+ gGlobInfo.backup_active -= 1;
+}
+
+boolean
+sip_sm_is_previous_call_id (const char *pCallID, line_t *pPreviousCallIndex)
+{
+ line_t i;
+
+ for (i = TEL_CCB_START; i <= TEL_CCB_END; i++) {
+ if (strcmp(gCallHistory[i].last_call_id, pCallID) == 0) {
+ *pPreviousCallIndex = i;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+void
+sip_sm_200and300_update (ccsipCCB_t *ccb, sipMessage_t *response, int response_code)
+{
+ const char *fname = "sip_sm_200and300_update";
+ const char *to;
+ const char *from;
+ const char *contact;
+ const char *record_route = NULL;
+ sipLocation_t *to_loc = NULL;
+
+ to = sippmh_get_cached_header_val(response, TO);
+ from = sippmh_get_cached_header_val(response, FROM);
+ contact = sippmh_get_cached_header_val(response, CONTACT);
+
+ if (ccb->state < SIP_STATE_ACTIVE) {
+ // We are not allowed to update the route once a call is established
+ record_route = sippmh_get_cached_header_val(response, RECORD_ROUTE);
+ }
+ /*
+ * Record the "tag=" parameter - only if the call is not active yet
+ */
+ if (ccb->state < SIP_STATE_ACTIVE) {
+ if (to) {
+ to_loc = sippmh_parse_from_or_to((char *) to, TRUE);
+ if (to_loc) {
+ if (to_loc->tag) {
+ ccb->sip_to_tag = strlib_update(ccb->sip_to_tag,
+ sip_sm_purify_tag(to_loc->tag));
+ if ( ccb->callref == 0 ) {
+ ccb->callref = get_callref(ccb->sip_to_tag);
+ }
+ } else {
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_ENTRY),
+ ccb->index, ccb->dn_line, fname,
+ "TO header:missing \"tag=\" param");
+ }
+ CCSIP_DEBUG_STATE(DEB_L_C_F_PREFIX"%d: Recorded to_tag=<%s>\n",
+ DEB_L_C_F_PREFIX_ARGS(SIP_CALL_STATUS, ccb->dn_line, ccb->gsm_id, fname),
+ ccb->index, ccb->sip_to_tag);
+ sippmh_free_location(to_loc);
+ }
+ }
+ }
+
+ /*
+ * Update To/From (to capture tag). Also Contact, and Record-Route
+ */
+ if (response_code == SIP_STATUS_SUCCESS) {
+ if (ccb->flags & INCOMING) {
+ ccb->sip_to = strlib_update(ccb->sip_to, from);
+ if (to) {
+ ccb->sip_from = strlib_update(ccb->sip_from, to);
+ }
+ } else {
+ if (to) {
+ ccb->sip_to = strlib_update(ccb->sip_to, to);
+ }
+ ccb->sip_from = strlib_update(ccb->sip_from, from);
+ }
+ }
+
+ if (response_code == SIP_STATUS_SUCCESS) {
+ if (contact) {
+ if (ccb->contact_info) {
+ sippmh_free_contact(ccb->contact_info);
+ }
+ ccb->contact_info = sippmh_parse_contact(contact);
+ }
+ }
+ if (record_route) {
+ if (ccb->record_route_info) {
+ sippmh_free_record_route(ccb->record_route_info);
+ }
+ ccb->record_route_info = sippmh_parse_record_route(record_route);
+ }
+}
+
+
+char *
+sip_sm_purify_tag (char *tag)
+{
+ char *p;
+
+ p = tag;
+ while (((*p == ';') || (*p == ' ') || (*p == '\t')) && (*p != '\0')) {
+ p++;
+ }
+
+ return p;
+}
+
+
+boolean
+sip_sm_is_invite_response (sipMessage_t *response)
+{
+ const char *cseq;
+ sipCseq_t *sipCseq;
+
+ if (response == NULL) {
+ return FALSE;
+ }
+
+ cseq = sippmh_get_cached_header_val(response, CSEQ);
+ sipCseq = sippmh_parse_cseq(cseq);
+ if (!sipCseq) {
+ return FALSE;
+ }
+
+ if (sipCseq->method == sipMethodInvite) {
+ cpr_free(sipCseq);
+ return TRUE;
+ }
+ cpr_free(sipCseq);
+ return FALSE;
+}
+
+boolean
+sip_sm_is_bye_or_cancel_response (sipMessage_t *response)
+{
+ const char *cseq;
+ sipCseq_t *sipCseq;
+
+ if (response == NULL) {
+ return FALSE;
+ }
+
+ cseq = sippmh_get_cached_header_val(response, CSEQ);
+ sipCseq = sippmh_parse_cseq(cseq);
+ if (!sipCseq) {
+ return FALSE;
+ }
+
+ if ((sipCseq->method == sipMethodBye) ||
+ (sipCseq->method == sipMethodCancel)) {
+ cpr_free(sipCseq);
+ return TRUE;
+ }
+ cpr_free(sipCseq);
+ return FALSE;
+}
+
+
+
+void
+sip_sm_dequote_string (char *str, int max_size)
+{
+ char *p;
+
+ /* Get rid of leading white space and double quote */
+ p = str;
+ while (((*p == '\"') || (*p == ' ') || (*p == '\t')) && (*p != '\0')) {
+ p++;
+ }
+
+ // The following use of sstrncpy is using over-lapping memory regions
+ sstrncpy(str, p, max_size);
+
+ /* Get rid of trailing double quote and white space */
+ // should be...
+ // end the string at the trailing double quote, if it exists
+ p = str;
+ while ((*p != '\"') && (*p != '\0')) {
+ p++;
+ }
+ *p = '\0';
+}
+
+
+void
+sip_sm_check_retx_timers (ccsipCCB_t *ccb, sipMessage_t *canceller_message)
+{
+ const char *fname = "sip_sm_check_retx_timers";
+ uint32_t canceller_cseq;
+ sipMethod_t canceller_cseq_method;
+ const char *canceller_callid;
+
+ sipMessage_t *retx_message = NULL;
+ uint32_t retx_message_buf_length = 0;
+ uint32_t retx_cseq = 0;
+ sipMethod_t retx_cseq_method = sipMethodInvalid;
+ const char *retx_callid = NULL;
+
+ const char *cseq;
+ sipCseq_t *sipCseq;
+ int response_code = -1;
+ const char *conn_type = NULL;
+
+ if (!ccb) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "CCB is NULL");
+ return;
+ }
+
+ if (ccb->index >= MAX_CCBS) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_LINE_NUMBER_INVALID),
+ fname, ccb->index);
+ return;
+ }
+
+ /* In the case of TCP/TLS, no messages are retransmitted unless there was a
+ * socket open (CPR_ENOTCONN) error. Hence there are no retx timers started
+ * in this case. If any retx timers were started, then, in the
+ * sip_platform_msg_timer_start procedure, the message_buffer_len would be
+ * set to a valid non-zero value.
+ */
+ conn_type = sipTransportGetTransportType(1, TRUE, ccb);
+ if ((!cpr_strcasecmp(conn_type, "TCP") || !cpr_strcasecmp(conn_type, "TLS")) &&
+ 0 == sipPlatformUISMTimers[ccb->index].message_buffer_len) {
+ /* This is not an error in case of TCP/TLS.
+ */
+ return;
+ }
+
+
+ /*
+ * Get canceller_message callid, cseq number, cseq method
+ */
+ cseq = sippmh_get_cached_header_val(canceller_message, CSEQ);
+ sipCseq = sippmh_parse_cseq(cseq);
+ if (sipCseq) {
+ canceller_cseq = sipCseq->number;
+ canceller_cseq_method = sipCseq->method;
+ cpr_free(sipCseq);
+ } else {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ ccb->index, ccb->dn_line, fname,
+ "sippmh_parse_cseq()");
+ return;
+ }
+
+ canceller_callid = sippmh_get_cached_header_val(canceller_message, CALLID);
+
+ /*
+ * Get canceller_message response code if it is a response
+ */
+ if (!sippmh_is_request(canceller_message)) {
+ if (sipGetResponseCode(canceller_message, &response_code) < 0) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED), ccb->index,
+ ccb->dn_line, fname, "sipGetResponseCode()");
+ return;
+ }
+ }
+
+ /*
+ * Get retx_message callid, cseq number, cseq method
+ */
+ retx_message = sippmh_message_create();
+ if (!retx_message) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED), ccb->index,
+ ccb->dn_line, fname, "sippmh_message_create()");
+ return;
+ }
+ retx_message_buf_length = sipPlatformUISMTimers[ccb->index].message_buffer_len;
+ if (sippmh_process_network_message(retx_message,
+ sipPlatformUISMTimers[ccb->index].message_buffer,
+ &retx_message_buf_length) == STATUS_FAILURE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED), ccb->index,
+ ccb->dn_line, fname,
+ "sippmh_process_network_message()");
+ free_sip_message(retx_message);
+ return;
+ }
+ if (!sippmh_is_message_complete(retx_message)) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED), ccb->index,
+ ccb->dn_line, fname, "sippmh_is_message_complete()");
+ free_sip_message(retx_message);
+ return;
+ }
+ cseq = sippmh_get_cached_header_val(retx_message, CSEQ);
+ sipCseq = sippmh_parse_cseq(cseq);
+ if (sipCseq) {
+ retx_cseq = sipCseq->number;
+ retx_cseq_method = sipCseq->method;
+ cpr_free(sipCseq);
+ } else {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ ccb->index, ccb->dn_line, fname,
+ "sippmh_parse_cseq()");
+ free_sip_message(retx_message);
+ return;
+ }
+
+ retx_callid = sippmh_get_cached_header_val(retx_message, CALLID);
+
+ /*
+ * Check whether callid, cseq number, cseq method match. If match,
+ * stop the reTx timer.
+ */
+ if ((canceller_cseq == retx_cseq) &&
+ ((canceller_cseq_method == retx_cseq_method) ||
+ ((canceller_cseq_method == sipMethodAck) &&
+ (retx_cseq_method == sipMethodInvite))) &&
+ (strcmp(canceller_callid, retx_callid) == 0)) {
+ sip_platform_msg_timer_stop(ccb->index);
+ CCSIP_DEBUG_STATE(DEB_L_C_F_PREFIX"%d: Stopping reTx timer.\n"
+ "(callid=%s, cseq=%u, cseq_method=%s)\n",
+ DEB_L_C_F_PREFIX_ARGS(SIP_TIMER, ccb->dn_line, ccb->gsm_id, fname),
+ ccb->index, retx_callid, retx_cseq,
+ sipGetMethodString(retx_cseq_method));
+
+ UNBIND_UDP_ICMP_HANDLER(ccb->udpId);
+
+ if (ccb->state == SIP_STATE_IDLE_MSG_TIMER_OUTSTANDING) {
+ if ((response_code == 401) || (response_code == 407) ||
+ ((response_code < 200) &&
+ (!sippmh_is_request(canceller_message)))) {
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_STATE_UNCHANGED), ccb->index,
+ ccb->dn_line, fname,
+ sip_util_state2string(ccb->state));
+ } else {
+ sip_sm_change_state(ccb, SIP_STATE_IDLE);
+ sip_sm_call_cleanup(ccb);
+ }
+ }
+ } else {
+ CCSIP_DEBUG_STATE(DEB_L_C_F_PREFIX"%d:CSeq mismatch:\n(Rx: callid=%s,"
+ " cseq=%u, cseq_method=%s),\n(reTx: callid=%s,"
+ " cseq=%u, cseq_method=%s)\n",
+ DEB_L_C_F_PREFIX_ARGS(SIP_CALL_STATUS, ccb->dn_line, ccb->gsm_id, fname),
+ ccb->index,
+ canceller_callid, canceller_cseq,
+ sipGetMethodString(canceller_cseq_method),
+ retx_callid, retx_cseq,
+ sipGetMethodString(retx_cseq_method));
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_ENTRY),
+ ccb->index, ccb->dn_line, fname,
+ "Not stopping retx timer");
+ }
+
+ free_sip_message(retx_message);
+}
+
+
+static int
+sip_sm_request_check_and_store (ccsipCCB_t *ccb, sipMessage_t *request,
+ sipMethod_t request_method, boolean midcall,
+ uint16_t *request_check_reason_code,
+ char *request_check_reason_phrase,
+ boolean store_invite)
+{
+ const char *fname = "sip_sm_request_check_and_store";
+ const char *request_cseq = NULL;
+ sipCseq_t *request_cseq_structure = NULL;
+ uint32_t request_cseq_number = 0;
+ sipMethod_t request_cseq_method = sipMethodInvalid;
+ const char *callID = NULL;
+ int content_length = 0;
+ boolean request_uri_error = FALSE;
+ sipReqLine_t *requestURI = NULL;
+ sipLocation_t *uri_loc = NULL;
+ const char *sip_from = NULL;
+ const char *sip_to = NULL;
+ sipLocation_t *to_loc = NULL;
+ sipLocation_t *from_loc = NULL;
+ const char *pViaHeaderStr = NULL;
+ int16_t trx_index = -1;
+ sipVia_t *via = NULL;
+
+
+ /* test incoming parameter for NULL */
+ if (!request_check_reason_phrase) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Input parameter request_check_reason_phrase is NULL\n",
+ fname);
+ return (-1);
+ }
+
+ /*
+ * Parse Call-Id
+ */
+ callID = sippmh_get_cached_header_val(request, CALLID);
+ if (!callID) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Unable to obtain request's "
+ "Call-ID header.\n", fname);
+ *request_check_reason_code = SIP_WARN_MISC;
+ sstrncpy(request_check_reason_phrase,
+ SIP_CLI_ERR_BAD_REQ_CALLID_ABSENT,
+ SIP_WARNING_LENGTH);
+ return (-1);
+ }
+
+ /*
+ * Parse CSeq
+ */
+ request_cseq = sippmh_get_cached_header_val(request, CSEQ);
+ if (!request_cseq) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Unable to obtain request's CSeq "
+ "header.\n", fname);
+ *request_check_reason_code = SIP_WARN_MISC;
+ sstrncpy(request_check_reason_phrase,
+ SIP_CLI_ERR_BAD_REQ_VIA_OR_CSEQ,
+ SIP_WARNING_LENGTH);
+ return (-1);
+ }
+ request_cseq_structure = sippmh_parse_cseq(request_cseq);
+ if (!request_cseq_structure) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Unable to parse request's CSeq "
+ "header.\n", fname);
+ *request_check_reason_code = SIP_WARN_MISC;
+ sstrncpy(request_check_reason_phrase,
+ SIP_CLI_ERR_BAD_REQ_VIA_OR_CSEQ,
+ SIP_WARNING_LENGTH);
+ return (-1);
+ }
+ request_cseq_number = request_cseq_structure->number;
+ request_cseq_method = request_cseq_structure->method;
+ cpr_free(request_cseq_structure);
+
+ /*
+ * Parsing Request-Uri
+ */
+ requestURI = sippmh_get_request_line(request);
+ if (requestURI) {
+ if (requestURI->url) {
+ uri_loc = sippmh_parse_from_or_to(requestURI->url, TRUE);
+ if (uri_loc) {
+ if (uri_loc->genUrl->schema != URL_TYPE_SIP) {
+ request_uri_error = TRUE;
+ }
+ sippmh_free_location(uri_loc);
+ } else {
+ request_uri_error = TRUE;
+ }
+ } else {
+ request_uri_error = TRUE;
+ }
+ SIPPMH_FREE_REQUEST_LINE(requestURI);
+ } else {
+ request_uri_error = TRUE;
+ }
+ if (request_uri_error) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Invalid Request URI"
+ "failed.\n", fname);
+ *request_check_reason_code = SIP_WARN_MISC;
+ sstrncpy(request_check_reason_phrase,
+ SIP_CLI_ERR_BAD_REQ_REQLINE_ERROR,
+ SIP_WARNING_LENGTH);
+ return (-1);
+ }
+
+ /*
+ * Parse From
+ */
+ sip_from = sippmh_get_cached_header_val(request, FROM);
+ from_loc = sippmh_parse_from_or_to((char *)sip_from, TRUE);
+ if (!from_loc) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, get_debug_string(DEBUG_FUNCTIONNAME_SIPPMH_PARSE_FROM));
+ *request_check_reason_code = SIP_WARN_MISC;
+ sstrncpy(request_check_reason_phrase,
+ SIP_CLI_ERR_BAD_REQ_FROMURL_ERROR,
+ SIP_WARNING_LENGTH);
+ return (-1);
+ }
+ sippmh_free_location(from_loc);
+
+ /*
+ * Parse To
+ */
+ sip_to = sippmh_get_cached_header_val(request, TO);
+ to_loc = sippmh_parse_from_or_to((char *)sip_to, TRUE);
+ if (!to_loc) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, get_debug_string(DEBUG_FUNCTIONNAME_SIPPMH_PARSE_TO));
+ *request_check_reason_code = SIP_WARN_MISC;
+ sstrncpy(request_check_reason_phrase,
+ SIP_CLI_ERR_BAD_REQ_ToURL_ERROR,
+ SIP_WARNING_LENGTH);
+ return (-1);
+ }
+ sippmh_free_location(to_loc);
+
+ /*
+ * Parse Via
+ */
+ pViaHeaderStr = sippmh_get_cached_header_val(request, VIA);
+ if (pViaHeaderStr) {
+ via = sippmh_parse_via(pViaHeaderStr);
+ }
+ if (!pViaHeaderStr || !via) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED), NULL,
+ NULL, fname, "sippmh_parse_via");
+ *request_check_reason_code = SIP_WARN_MISC;
+ sstrncpy(request_check_reason_phrase,
+ SIP_CLI_ERR_BAD_REQ_VIA_OR_CSEQ,
+ SIP_WARNING_LENGTH);
+ return (-1);
+
+ }
+ sippmh_free_via(via);
+
+ /*
+ * Check
+ */
+ switch (request_method) {
+ /* INVITE */
+ case sipMethodInvite:
+
+ content_length = sippmh_get_content_length(request);
+
+ if (request->raw_body) {
+
+ if ((size_t) content_length != strlen(request->raw_body)) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"\n Mismatched Content length and "
+ "Actual message body length:content length=%d\n"
+ "and message as %s\n and strlen of messagebody = %d\n",
+ fname, content_length, request->raw_body,
+ strlen(request->raw_body));
+ *request_check_reason_code = SIP_WARN_MISC;
+ sstrncpy(request_check_reason_phrase,
+ SIP_CLI_ERR_BAD_REQ_CONTENT_LENGTH_ERROR,
+ SIP_WARNING_LENGTH);
+ return (-1);
+ }
+ } else {
+ if ((size_t) content_length != 0) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"\n Mismatched Content length and "
+ "Actual message body length:content length=%d\n"
+ "and message is empty and strlen of messagebody = 0\n",
+ fname, content_length);
+ *request_check_reason_code = SIP_WARN_MISC;
+ sstrncpy(request_check_reason_phrase,
+ SIP_CLI_ERR_BAD_REQ_CONTENT_LENGTH_ERROR,
+ SIP_WARNING_LENGTH);
+ return (-1);
+ }
+ }
+ if (midcall &&
+ ((ccb->last_recv_request_cseq_method == sipMethodInvite) ||
+ (ccb->last_recv_request_cseq_method == sipMethodAck))) {
+ if (request_cseq_number <= ccb->last_recv_invite_cseq) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error: CSeq (%d) is not greater "
+ "than previous INVITE (%d).\n", fname,
+ request_cseq_number,
+ ccb->last_recv_invite_cseq);
+ *request_check_reason_code = SIP_WARN_MISC;
+ sstrncpy(request_check_reason_phrase,
+ SIP_CLI_ERR_BAD_REQ_CSEQ_FIELD,
+ SIP_WARNING_LENGTH);
+ return (-1);
+ }
+ }
+ ccb->last_recv_invite_cseq = request_cseq_number;
+ break;
+
+ /* BYE */
+ case sipMethodBye:
+ if (ccb->flags & INCOMING) {
+ if (request_cseq_number <= ccb->last_recv_invite_cseq) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error: CSeq (%d) is not greater "
+ "than original INVITE (%d).\n", fname,
+ request_cseq_number,
+ ccb->last_recv_invite_cseq);
+ *request_check_reason_code = SIP_WARN_MISC;
+ sstrncpy(request_check_reason_phrase,
+ SIP_CLI_ERR_BAD_REQ_CSEQ_FIELD,
+ SIP_WARNING_LENGTH);
+ return (-1);
+ }
+ }
+ break;
+
+ /* ACK and CANCEL */
+ case sipMethodCancel:
+ case sipMethodAck:
+ if (request_cseq_number != ccb->last_recv_invite_cseq) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"CSeq (%d) is not the same as "
+ "original INVITE (%d).\n", fname,
+ request_cseq_number, ccb->last_recv_request_cseq);
+ *request_check_reason_code = SIP_WARN_MISC;
+ sstrncpy(request_check_reason_phrase,
+ SIP_CLI_ERR_BAD_REQ_CSEQ_FIELD,
+ SIP_WARNING_LENGTH);
+ return (-1);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ // Allocate a tx block and store the various params there
+ trx_index = get_next_request_trx_index(ccb, FALSE);
+ if (trx_index < 0) {
+ // Internal server error
+ *request_check_reason_code = SIP_WARN_MISC;
+ sstrncpy(request_check_reason_phrase,
+ "Too many Transactions",
+ SIP_WARNING_LENGTH);
+ return (-2);
+ }
+ /*
+ * Don't free it since this request will be again required
+ * for sending 487 response. This is a temporary solution
+ * and should be removed in Moonpie
+ */
+ if (!store_invite) {
+ if (ccb->last_request) {
+ free_sip_message(ccb->last_request);
+ ccb->last_request = NULL;
+ }
+ }
+ /* Store request.Done after alloc of trx, to handle allocation failure. */
+ ccb->last_request = request;
+
+ ccb->last_recv_request_cseq = request_cseq_number;
+ ccb->last_recv_request_cseq_method = request_cseq_method;
+ ccb->recv_request[trx_index].cseq_number = request_cseq_number;
+ ccb->recv_request[trx_index].cseq_method = request_cseq_method;
+ pViaHeaderStr = sippmh_get_cached_header_val(request, VIA);
+ if (pViaHeaderStr) {
+ ccb->recv_request[trx_index].u.sip_via_header =
+ strlib_update(ccb->recv_request[trx_index].u.sip_via_header,
+ pViaHeaderStr);
+ }
+
+ return (0);
+}
+
+
+/*
+ * Function: sip_sm_update_to_from_on_callsetup_finalresponse
+ *
+ * Parameters: ccb, response
+ *
+ * Description: Updates to and from from response
+ *
+ * Returns:Void
+ *
+ */
+void
+sip_sm_update_to_from_on_callsetup_finalresponse (ccsipCCB_t *ccb,
+ sipMessage_t *response)
+{
+ const char *fname = "sip_sm_update_to_from_on_callsetup_finalresponse";
+ const char *to;
+ const char *from;
+ sipLocation_t *to_loc = NULL;
+
+ to = sippmh_get_cached_header_val(response, TO);
+ from = sippmh_get_cached_header_val(response, FROM);
+
+ /*
+ * Record the "tag=" parameter
+ */
+ if (to) {
+ to_loc = sippmh_parse_from_or_to((char *)to, TRUE);
+ if (to_loc) {
+ if (to_loc->tag) {
+ ccb->sip_to_tag = strlib_update(ccb->sip_to_tag, sip_sm_purify_tag(to_loc->tag));
+ } else {
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_ENTRY),
+ ccb->index, ccb->dn_line, fname,
+ "TO header missing \"tag=\" param");
+ /* ccb->sip_to_tag[0] = '\0'; */
+ }
+ CCSIP_DEBUG_STATE(DEB_L_C_F_PREFIX"%d: Recorded to_tag=<%s>\n",
+ DEB_L_C_F_PREFIX_ARGS(SIP_CALL_STATUS, ccb->dn_line, ccb->gsm_id, fname),
+ ccb->index, ccb->sip_to_tag);
+ sippmh_free_location(to_loc);
+ }
+ }
+
+ /*
+ * Update To/From (to capture tag). Also Contact, and Record-Route
+ */
+ if (to) {
+ ccb->sip_to = strlib_update(ccb->sip_to, to);
+ }
+ ccb->sip_from = strlib_update(ccb->sip_from, from);
+}
+
+
+/*
+ * Function: sip_sm_update_contact_recordroute
+ *
+ * Parameters:ccb, response , response_code, midcall boolean
+ *
+ * Description: Puts contact info and record_route info into ccb
+ *
+ * Returns:void
+ *
+ */
+void
+sip_sm_update_contact_recordroute (ccsipCCB_t *ccb, sipMessage_t *response,
+ int response_code, boolean midcall)
+{
+ const char *contact;
+ const char *record_route;
+
+ contact = sippmh_get_cached_header_val(response, CONTACT);
+ record_route = sippmh_get_cached_header_val(response, RECORD_ROUTE);
+
+ if (response_code == SIP_STATUS_SUCCESS) {
+ if (contact) {
+ if (ccb->contact_info) {
+ sippmh_free_contact(ccb->contact_info);
+ }
+ ccb->contact_info = sippmh_parse_contact(contact);
+ }
+ }
+ if (record_route && (!midcall)) {
+ if (ccb->record_route_info) {
+ sippmh_free_record_route(ccb->record_route_info);
+ }
+ ccb->record_route_info = sippmh_parse_record_route(record_route);
+ }
+}
+
+
+/*
+ * SIP_STATE_ACTIVE
+ */
+void
+ccsip_handle_active_ev_cc_feature (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ const char *fname = "active_ev_cc_feature";
+ cc_features_t feature_type;
+
+ feature_type = event->u.cc_msg->msg.feature.feature_id;
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_FUNCTION_ENTRY),
+ ccb->index, ccb->dn_line, fname,
+ sip_util_state2string(ccb->state),
+ cc_feature_name(feature_type));
+
+ switch (feature_type) {
+ case CC_FEATURE_HOLD:
+ ccb->hold_initiated = TRUE;
+ ccb->featuretype = CC_FEATURE_HOLD;
+ ccsip_handle_active_ev_cc_feature_hold(ccb, event);
+ break;
+ case CC_FEATURE_MEDIA:
+ ccb->featuretype = CC_FEATURE_MEDIA;
+ ccsip_handle_active_ev_cc_feature_resume_or_media(ccb, event);
+ break;
+ case CC_FEATURE_RESUME:
+ ccb->featuretype = CC_FEATURE_RESUME;
+ ccsip_handle_active_ev_cc_feature_resume_or_media(ccb, event);
+ break;
+ case CC_FEATURE_BLIND_XFER:
+ case CC_FEATURE_XFER:
+ ccsip_handle_active_ev_cc_feature_xfer(ccb, event);
+ break;
+ case CC_FEATURE_NOTIFY:
+ if (event->u.cc_msg->msg.feature.data.notify.final == TRUE) {
+ ccb->flags |= FINAL_NOTIFY;
+ }
+ if (CC_CAUSE_OK != event->u.cc_msg->msg.feature.data.notify.cause) {
+ // Get the data from msg.get data for error code but currently we do not have any.
+ (void) sipSPISendNotify(ccb, event->u.cc_msg->msg.feature.data.notify.cause_code);
+ ccb->xfer_status = event->u.cc_msg->msg.feature.data.notify.cause_code;
+ } else {
+ (void) sipSPISendNotify(ccb, SIP_SUCCESS_SETUP); // Get the data from msg.
+ ccb->xfer_status = SIP_SUCCESS_SETUP;
+ }
+ break;
+ case CC_FEATURE_B2BCONF:
+ case CC_FEATURE_SELECT:
+ case CC_FEATURE_B2B_JOIN:
+ case CC_FEATURE_CANCEL:
+ break;
+ default:
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_FEATURE_UNSUPPORTED),
+ ccb->index, ccb->dn_line, fname);
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_STATE_UNCHANGED),
+ ccb->index, ccb->dn_line, fname,
+ sip_util_state2string(ccb->state));
+ sip_cc_feature_ack(ccb->gsm_id, ccb->dn_line, feature_type, NULL,
+ CC_CAUSE_ERROR);
+ break;
+ }
+}
+
+
+/**
+ * This fucntion handles CC_FEATURE_HOLD in active state.
+ *
+ * @param[in] ccb Pointer to ccsipCCB_t structure.
+ * @param[in] event Pointer to sipSMEvent_t structure.
+ *
+ * @pre (ccb not_eq NULL)
+ *
+ * @return None.
+ *
+ */
+void
+ccsip_handle_active_ev_cc_feature_hold (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ cc_msgbody_info_t *msg_body;
+
+ /* Copy the call-info into the CCB */
+ ccsip_store_call_info(&event->u.cc_msg->msg.feature.data.hold.call_info, ccb);
+ if (event->u.cc_msg->msg.feature.data_valid) {
+ /* Replace the local copy of the msg. body */
+ msg_body = &event->u.cc_msg->msg.feature.data.hold.msg_body;
+ ccsip_save_local_msg_body(ccb, msg_body);
+ }
+
+ sip_sm_change_state(ccb, SIP_STATE_SENT_MIDCALL_INVITE);
+ if (send_resume_or_hold_request(ccb, TRUE) == FALSE) {
+ sip_cc_release(ccb->gsm_id, ccb->dn_line, CC_CAUSE_ERROR, NULL);
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ }
+}
+
+
+/**
+ * This fucntion handles CC_FEATURE_RESUME or CC_FEATURE_MEDIA in
+ * active state.
+ *
+ * @param[in] ccb Pointer to ccsipCCB_t structure.
+ * @param[in] event Pointer to sipSMEvent_t structure.
+ *
+ * @pre (ccb not_eq NULL)
+ *
+ * @return None.
+ *
+ */
+void
+ccsip_handle_active_ev_cc_feature_resume_or_media (ccsipCCB_t *ccb,
+ sipSMEvent_t *event)
+{
+ cc_msgbody_info_t *msg_body;
+
+ if (event->u.cc_msg->msg.feature.data_valid) {
+ /* Replace the local copy of the msg. body */
+ msg_body = &event->u.cc_msg->msg.feature.data.resume.msg_body;
+ ccsip_save_local_msg_body(ccb, msg_body);
+ }
+
+ /* Copy the call-info into the CCB */
+ ccsip_store_call_info(&event->u.cc_msg->msg.feature.data.resume.call_info, ccb);
+ sip_sm_change_state(ccb, SIP_STATE_SENT_MIDCALL_INVITE);
+ if (send_resume_or_hold_request(ccb, FALSE) == FALSE) {
+ sip_cc_release(ccb->gsm_id, ccb->dn_line, CC_CAUSE_ERROR, NULL);
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ }
+}
+
+void
+ccsip_handle_active_ev_cc_feature_xfer (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ const char *fname = "active_ev_cc_feature_xfer";
+ char referto[MAX_SIP_URL_LENGTH];
+ char *domainloc = NULL;
+ char *pTransferNumberString;
+ cc_feature_data_t data;
+ cc_xfer_methods_t method;
+ char addr[MAX_IPADDR_STR_LEN];
+ ccsipCCB_t *xfer_ccb = NULL;
+ int n = 0;
+ static char dialtranslate[MAX_SIP_URL_LENGTH];
+ char *pReferToStr = referto;
+ sipRefEnum_e refto_type = SIP_REF_XFER;
+
+ memset(addr, 0, MAX_IPADDR_STR_LEN);
+ method = event->u.cc_msg->msg.feature.data.xfer.method;
+
+ if (CC_FEATURE_BLIND_XFER == event->u.cc_msg->msg.feature.feature_id) {
+ ccb->featuretype = CC_FEATURE_BLIND_XFER;
+ ccb->con_call_id = CC_NO_CALL_ID;
+ } else if (CC_FEATURE_XFER == event->u.cc_msg->msg.feature.feature_id) {
+ ccb->featuretype = CC_FEATURE_XFER;
+ ccb->con_call_id = event->u.cc_msg->msg.feature.data.xfer.target_call_id;
+ xfer_ccb = sip_sm_get_ccb_by_target_call_id(ccb->con_call_id);
+ }
+
+
+ pTransferNumberString = event->u.cc_msg->msg.feature.data.xfer.dialstring;
+ (void) MatchDialTemplate(pTransferNumberString, ccb->dn_line, CAST_N &n,
+ dialtranslate, sizeof(dialtranslate),
+ (RouteMode *) &(ccb->routeMode), NULL);
+ /* Escape the characters in userinfo */
+ domainloc = strchr(dialtranslate, '@');
+ if (domainloc == NULL) {
+ (void) sippmh_convertURLCharToEscChar(dialtranslate,
+ strlen(dialtranslate),
+ pReferToStr, MAX_SIP_URL_LENGTH, TRUE);
+ } else {
+ (void) sippmh_convertURLCharToEscChar(dialtranslate,
+ domainloc - dialtranslate,
+ pReferToStr, MAX_SIP_URL_LENGTH, TRUE);
+ /* Append the host Part including @ */
+ sstrncat(pReferToStr, domainloc, MAX_SIP_URL_LENGTH - strlen(pReferToStr));
+ }
+ /* Re-write the escaped URL to dial translate */
+ sstrncpy(dialtranslate, referto, MAX_SIP_URL_LENGTH);
+ pTransferNumberString = dialtranslate;
+
+
+ ccb->authen.cred_type = 0;
+ //add refer as SIP mURI
+
+ // If there is no hostname, add proxy address as hostname
+ domainloc = strchr(referto, '@');
+ if (domainloc == NULL) {
+ char *semi = NULL;
+ size_t len;
+
+ /* see if we have ;user= */
+ semi = strchr(pTransferNumberString, ';');
+
+ if (semi) {
+ sstrncpy(referto, "con_call_id);
+ if ((xfer_ccb != NULL) &&
+ util_check_if_ip_valid(&(xfer_ccb->dest_sip_addr)) &&
+ (ccb->featuretype == CC_FEATURE_XFER)) {
+ /*
+ * Populate addr with proxy through which transferor and
+ * target are talking
+ */
+ if ((xfer_ccb->routeMode == RouteEmergency) ||
+ (xfer_ccb->proxySelection == SIP_PROXY_BACKUP)) {
+ ipaddr2dotted(addr, &xfer_ccb->dest_sip_addr);
+ } else {
+ sipTransportGetPrimServerAddress(xfer_ccb->dn_line, addr);
+ }
+ } else {
+ /*
+ * In case of blind transfer xfer_ccb->dest_sip_addr will
+ * always show primary proxy. Since we don't know whether
+ * target of transfer is reachable by primary proxy or not,
+ * We are going to use proxy through which transferor is
+ * talking to transferee, assuming that transferee and target
+ * should be able to talk through the same proxy
+ */
+ if ((ccb->routeMode == RouteEmergency) ||
+ (ccb->proxySelection == SIP_PROXY_BACKUP)) {
+ ipaddr2dotted(addr, &ccb->dest_sip_addr);
+ } else {
+ sipTransportGetPrimServerAddress(ccb->dn_line, addr);
+ }
+ }
+
+ sstrncpy(domainloc, addr,
+ MAX_SIP_URL_LENGTH - (domainloc - referto - 1));
+ }
+
+ /* if we have a ;user=, then add it to the end of the string if we can */
+ if (semi) {
+ domainloc = referto + strlen(referto);
+ sstrncpy(domainloc, semi,
+ MAX_SIP_URL_LENGTH - (domainloc - referto - 1));
+ }
+
+ if (semi) {
+ sstrncat(domainloc, ">", MAX_SIP_URL_LENGTH - strlen(referto));
+ }
+ }
+ /* If the method is direct trasnfer then
+ * add more information to referto header
+ */
+ if (method == CC_XFER_METHOD_DIRXFR) {
+ refto_type = SIP_REF_DIR_XFER;
+ }
+
+ if (CC_XFER_METHOD_REFER == method ||
+ method == CC_XFER_METHOD_DIRXFR) {
+ // Add refer as SIP Refer
+ ccsipCCB_t *xfer_refer_ccb;
+
+ ccb->sip_referTo = strlib_update(ccb->sip_referTo, referto);
+ xfer_refer_ccb = sip_sm_get_target_call_by_con_call_id(ccb->con_call_id);
+
+ if ((xfer_refer_ccb != NULL) && (xfer_ccb != NULL) && (xfer_ccb->sip_referTo[0] != '\0')) {
+ ccb->sip_referTo = strlib_update(ccb->sip_referTo,
+ xfer_refer_ccb->sip_referTo);
+ }
+
+ if (ccb->sip_referTo) {
+ if (sipSPISendRefer(ccb, (char *)ccb->sip_referTo, refto_type) != TRUE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ ccb->index, ccb->dn_line, fname,
+ "sipSPISendRefer Failed");
+ return;
+ }
+ } else {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ ccb->index, ccb->dn_line, fname,
+ "ccb->sipreferTo is NULL");
+ return;
+ }
+
+ } else if (CC_XFER_METHOD_BYE == method) {
+ cc_features_t feature;
+
+ ccb->referto = strlib_update(ccb->referto, referto);
+ data.xfer.cause = CC_CAUSE_XFER_LOCAL;
+ feature = fsmxfr_type_to_feature(fsmxfr_get_xfr_type(ccb->gsm_id));
+ data.xfer.method = CC_XFER_METHOD_BYE; // Temp Fix Need to remove
+ data.xfer.dialstring[0] = '\0';
+ data.xfer.target_call_id = CC_NO_CALL_ID;
+ sip_cc_feature_ack(ccb->gsm_id, ccb->dn_line, feature, &data,
+ CC_CAUSE_NORMAL);
+ } else {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ ccb->index, ccb->dn_line, fname,
+ "Unspecified Method of Transfer");
+
+ }
+
+ /* Pre-fill the ARP table */
+ ADD_TO_ARP_CACHE(ccb->dest_sip_addr);
+}
+
+void
+ccsip_handle_active_ev_cc_feature_ack (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ const char *fname = "ccsip_handle_active_ev_cc_feature_ack";
+ ccsipCCB_t *other_ccb = NULL;
+ cc_features_t feature_type;
+
+ feature_type = event->u.cc_msg->msg.feature.feature_id;
+ switch (feature_type) {
+ case CC_FEATURE_XFER:
+ case CC_FEATURE_BLIND_XFER:
+ if (CC_XFER_METHOD_REFER == event->u.cc_msg->msg.feature.data.xfer.method) {
+ if (CC_CAUSE_ERROR == event->u.cc_msg->msg.feature.data.xfer.cause) {
+ (void) sipSPISendErrorResponse(ccb->last_request,
+ SIP_SERV_ERR_UNAVAIL,
+ SIP_SERV_ERR_UNAVAIL_PHRASE,
+ 0, NULL, ccb);
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Got CC_CAUSE_ERROR"
+ "from GSM \n", fname);
+ return;
+ }
+ if (CC_NO_CALL_ID != event->u.cc_msg->msg.feature.data.xfer.target_call_id) {
+ ccb->con_call_id = event->u.cc_msg->msg.feature.data.xfer.target_call_id;
+ if (feature_type == CC_FEATURE_BLIND_XFER) {
+ ccb->blind_xfer_call_id = event->u.cc_msg->msg.feature.data.xfer.target_call_id;
+ }
+ if (!sipSPISendReferResponse202(ccb)) {
+ (void) sipSPISendErrorResponse(ccb->last_request,
+ SIP_SERV_ERR_UNAVAIL,
+ SIP_SERV_ERR_UNAVAIL_PHRASE,
+ 0, NULL, ccb);
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"sipSPISendReferResponse202"
+ " failed, sending 503\n", fname);
+ return;
+ } else {
+ /* Send NOTIFY 100 Trying */
+ if (!sipSPISendNotify(ccb, SIP_1XX_TRYING)) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"sipSPISendNotify"
+ " failed, sending 100\n", fname);
+ }
+ ccb->xfer_status = 100;
+
+ if (feature_type == CC_FEATURE_BLIND_XFER) {
+ /*
+ * Release this call and tell GSM to start
+ * the Blind Transfer
+ */
+ sip_cc_release(ccb->gsm_id, ccb->dn_line,
+ CC_CAUSE_NORMAL, NULL);
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ }
+ }
+ }
+ } else if (CC_XFER_METHOD_BYE == event->u.cc_msg->msg.feature.data.xfer.method) {
+ sip_cc_release(ccb->gsm_id, ccb->dn_line, CC_CAUSE_NORMAL, NULL);
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ }
+ break;
+ case CC_FEATURE_NOTIFY:
+ /* check for special case early attended transfer */
+ other_ccb = sip_sm_get_target_call_by_con_call_id(ccb->con_call_id);
+ if ((other_ccb != NULL) && (other_ccb->early_transfer)) {
+ other_ccb->early_transfer = FALSE;
+ sipSPISendCancel(other_ccb);
+ sip_cc_release_complete(other_ccb->gsm_id, other_ccb->dn_line,
+ CC_CAUSE_NORMAL);
+ sip_sm_change_state(other_ccb, SIP_STATE_RELEASE);
+ } else {
+ // This might be a simple acknowledgement for a NOTIFY
+ // received from the network. Reply to the remote side
+ // including the cause-code received from GSM
+ (void) sipSPISendNotifyResponse(ccb,
+ event->u.cc_msg->msg.feature_ack.cause);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void
+ccsip_handle_active_ev_sip_invite (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ const char *fname = "active_ev_sip_invite";
+ sipMessage_t *request;
+
+ // currently not used: const char *require = NULL;
+ const char *contact = NULL;
+ uint16_t request_check_reason_code = 0;
+ char request_check_reason_phrase[SIP_WARNING_LENGTH];
+ cc_feature_data_t data;
+ sipsdp_status_t sdp_status;
+ boolean apply_ringout = FALSE;
+
+ /* Unpack the event */
+ request = event->u.pSipMessage;
+
+ // Check for glare conditions
+ // If we have an outstanding INVITE that we sent then we have glare
+ if (get_method_request_trx_index(ccb, sipMethodInvite, TRUE) > -1) {
+ CCSIP_DEBUG_STATE(DEB_L_C_F_PREFIX"%d Glare condition detected \n",
+ DEB_L_C_F_PREFIX_ARGS(SIP_CALL_STATUS, ccb->dn_line, ccb->gsm_id, fname),
+ ccb->index);
+ // return 491
+ (void) sipSPISendErrorResponse(request, SIP_CLI_ERR_REQ_PENDING,
+ SIP_CLI_ERR_REQ_PENDING_PHRASE,
+ 0, NULL, NULL);
+ free_sip_message(request);
+ return;
+ }
+
+ /* Request check and store */
+ if (sip_sm_request_check_and_store(ccb, request, sipMethodInvite, TRUE,
+ &request_check_reason_code,
+ request_check_reason_phrase, FALSE) < 0) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED), ccb->index,
+ ccb->dn_line, fname,
+ get_debug_string(DEBUG_FUNCTIONNAME_SIP_SM_REQUEST_CHECK_AND_STORE));
+ (void) sipSPISendErrorResponse(request, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ request_check_reason_code,
+ request_check_reason_phrase, NULL);
+ free_sip_message(request);
+ return;
+ }
+
+
+ /* update the contact information if needed */
+ contact = sippmh_get_cached_header_val(request, CONTACT);
+ if (contact) {
+ if (ccb->contact_info) {
+ sippmh_free_contact(ccb->contact_info);
+ }
+ ccb->contact_info = sippmh_parse_contact(contact);
+ }
+
+ /*
+ * Process SDP
+ */
+ sdp_status = sip_util_extract_sdp(ccb, request);
+
+ switch (sdp_status) {
+ case SIP_SDP_SESSION_AUDIT:
+ ccb->oa_state = OA_OFFER_RECEIVED;
+ if (((ccb->state == SIP_STATE_SENT_MIDCALL_INVITE) &&
+ (ccb->hold_initiated)) || (ccb->state == SIP_STATE_ACTIVE)) {
+ /*
+ * Respond to the BroadSoft Session Audit Message.
+ * Do same for Refresh case / ReInvite with the same SDP
+ * First request for the current sdp from gsm.
+ *
+ * Need to check for Call-Info ringout state and pass along so that session audit
+ * does not disable CCM spoofed ringout.
+ */
+ if (ccb->in_call_info &&
+ ccb->in_call_info->data.call_info_feat_data.feature_flag & CC_UI_STATE) {
+ apply_ringout =
+ (ccb->in_call_info->data.call_info_feat_data.ui_state ==
+ CC_UI_STATE_RINGOUT ? TRUE : FALSE);
+ }
+ /* Update connected party info from RPID and Call-Info header */
+ ccsip_update_callinfo(ccb, request, TRUE, TRUE, FALSE);
+ sip_cc_audit(ccb->gsm_id, ccb->dn_line, apply_ringout);
+ return;
+ }
+ /*FALLTHROUGH*/
+
+ case SIP_SDP_SUCCESS:
+ /*
+ * Check to see if received SDP indicates hold. If it is not
+ * a hold SDP, then we received a new media invite.
+ * Send FEATURE CC event to GSM.
+ */
+ ccb->oa_state = OA_OFFER_RECEIVED;
+ /*
+ * Update connected party info from RPID and Call-Info header.
+ * Media will effect media, delay call information update.
+ */
+ ccsip_update_callinfo(ccb, request, TRUE, TRUE, TRUE);
+ /* Move the message body from the SIP msg. into CCAPI msg */
+ sip_cc_mv_msg_body_to_cc_msg(&data.resume.msg_body, request);
+ sip_cc_feature(ccb->gsm_id, ccb->dn_line, CC_FEATURE_MEDIA, &data);
+ sip_sm_change_state(ccb,
+ SIP_STATE_RECV_MIDCALL_INVITE_CCFEATUREACK_PENDING);
+ break;
+
+ case SIP_SDP_ERROR:
+ (void) sipSPISendErrorResponse(ccb->last_request, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ SIP_WARN_MISC, "Invalid SDP", ccb);
+ return;
+
+ case SIP_SDP_DNS_FAIL:
+ sipSPISendInviteResponse(ccb, SIP_SERV_ERR_INTERNAL,
+ SIP_SERV_ERR_INTERNAL_PHRASE,
+ SIP_WARN_MISC,
+ "DNS lookup failed for media destination",
+ FALSE, FALSE);
+ return;
+
+ case SIP_SDP_NO_MEDIA:
+ (void) sipSPISendErrorResponse(ccb->last_request, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ SIP_WARN_MISC,
+ "No acceptable media line in SDP", ccb);
+ return;
+
+ case SIP_SDP_NOT_PRESENT:
+ /*FALLTHROUGH*/
+
+ default:
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX"Waiting for SDP in ACK\n",
+ DEB_F_PREFIX_ARGS(SIP_SDP, fname));
+ /*
+ * Update connected party info from RPID and Call-Info header.
+ * Resuming the media,update call info now.
+ */
+ ccsip_update_callinfo(ccb, request, TRUE, TRUE, FALSE);
+ sip_cc_feature(ccb->gsm_id, ccb->dn_line, CC_FEATURE_MEDIA, NULL);
+ sip_sm_change_state(ccb,
+ SIP_STATE_RECV_MIDCALL_INVITE_CCFEATUREACK_PENDING);
+ break;
+ }
+
+ sipSPISendInviteResponse100(ccb, FALSE);
+}
+
+
+void
+ccsip_handle_active_2xx (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ const char *fname = "Active_2xx";
+ sipMessage_t *response;
+ int response_code = 0;
+
+ /* Unpack the event */
+ response = event->u.pSipMessage;
+ if (sipGetResponseCode(response, &response_code) < 0) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sipGetResponseCode");
+ free_sip_message(response);
+ return;
+ }
+ if (response_code == SIP_ACCEPTED) {
+ ccsip_handle_accept_2xx(ccb, event);
+ return;
+ }
+
+ if (sipSPISendAck(ccb, response) != TRUE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sipSPISendAck");
+ }
+ /* Update connected party info from RPID and Call-Info header */
+ ccsip_update_callinfo(ccb, response, TRUE, FALSE, FALSE);
+
+ free_sip_message(response);
+}
+
+
+/*
+ * SIP_STATE_SENT_MIDCALL_INVITE
+ */
+
+/**
+ * ccsip_handle_sentinvite_midcall_ev_cc_feature
+ *
+ * The function handles for CC_FEATURE during mid call invite.
+ *
+ * @param[in] ccb Pointer to ccsipCCB_t structure.
+ * @param[in] event Pointer to sipSMEvent_t structure.
+ *
+ * @pre (ccb not_eq NULL)
+ *
+ * @return N/A
+ */
+void ccsip_handle_sentinvite_midcall_ev_cc_feature (ccsipCCB_t *ccb,
+ sipSMEvent_t *event)
+{
+ const char *fname = "ccsip_handle_sentinvite_midcall_ev_cc_feature";
+ cc_features_t feature_type;
+
+ feature_type = event->u.cc_msg->msg.feature_ack.feature_id;
+
+ switch (feature_type) {
+ case CC_FEATURE_RESUME:
+ case CC_FEATURE_HOLD:
+ case CC_FEATURE_MEDIA:
+ /*
+ * Send resume/hold/media request and waiting for the response.
+ * Indicate that the request can not proceed now and it should be
+ * retried later. GSM should not attempt this.
+ */
+ sip_cc_feature_ack(ccb->gsm_id, ccb->dn_line, feature_type,
+ NULL, CC_CAUSE_REQUEST_PENDING);
+ break;
+
+ default:
+ /* Other feature request is not supported or allowed now */
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_FEATURE_UNSUPPORTED),
+ ccb->index, ccb->dn_line, fname);
+ sip_cc_feature_ack(ccb->gsm_id, ccb->dn_line, feature_type,
+ NULL, CC_CAUSE_ERROR);
+ break;
+ }
+}
+
+/**
+ * ccsip_handle_sentinvite_midcall_ev_sip_2xx
+ *
+ * The function handles for SIP 2xx during mid call invite.
+ *
+ * @param[in] ccb Pointer to ccsipCCB_t structure.
+ * @param[in] event Pointer to sipSMEvent_t structure.
+ *
+ * @pre (ccb not_eq NULL)
+ *
+ * @return N/A
+ */
+void ccsip_handle_sentinvite_midcall_ev_sip_2xx (ccsipCCB_t *ccb,
+ sipSMEvent_t *event)
+{
+ const char *fname = "ccsip_handle_sentinvite_midcall_ev_sip_2xx";
+ sipMessage_t *response;
+ cc_feature_data_t data;
+ sipsdp_status_t sdp_status;
+
+ response = event->u.pSipMessage;
+ if (!sip_sm_is_invite_response(response)) {
+ free_sip_message(response);
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_STATE_UNCHANGED),
+ ccb->index, ccb->dn_line, fname,
+ sip_util_state2string(ccb->state));
+ return;
+ }
+
+ /* Stop the expires timer started to await this response */
+ (void) sip_platform_expires_timer_stop(ccb->index);
+
+ sip_sm_200and300_update(ccb, response, SIP_STATUS_SUCCESS);
+
+ /* Reset credentials flag since Hold was successfully processed */
+ ccb->authen.cred_type = 0;
+
+ /*
+ * Send ACK back soon to minimize delayed cutting through at the
+ * remote end.
+ */
+ if (sipSPISendAck(ccb, response) == FALSE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sipSPISendAck");
+ }
+
+ /* Update connected party info from RPID and Call-Info header */
+ ccsip_update_callinfo(ccb, response, TRUE, FALSE, FALSE);
+
+ /* Extract destination SDP and related fields */
+ sdp_status = sip_util_extract_sdp(ccb, response);
+
+ switch (sdp_status) {
+ case SIP_SDP_SUCCESS:
+ case SIP_SDP_SESSION_AUDIT:
+ case SIP_SDP_NOT_PRESENT:
+ ccb->oa_state = OA_IDLE;
+ /* Move the messag bodies from SIP msg. to CCAPI msg. */
+ switch (ccb->featuretype) {
+ case CC_FEATURE_HOLD:
+ sip_cc_mv_msg_body_to_cc_msg(&data.hold.msg_body, response);
+ sip_cc_feature_ack(ccb->gsm_id, ccb->dn_line, ccb->featuretype,
+ &data, CC_CAUSE_NORMAL);
+ break;
+ case CC_FEATURE_RESUME:
+ case CC_FEATURE_MEDIA:
+ sip_cc_mv_msg_body_to_cc_msg(&data.resume.msg_body, response);
+ sip_cc_feature_ack(ccb->gsm_id, ccb->dn_line, ccb->featuretype,
+ &data, CC_CAUSE_NORMAL);
+ break;
+ default:
+ /*
+ * Other features are not expected.
+ */
+ CCSIP_DEBUG_ERROR(DEB_L_C_F_PREFIX"%d: unexpected feature %d\n",
+ ccb->dn_line, ccb->gsm_id, fname,
+ ccb->index, ccb->featuretype);
+ sip_cc_feature_ack(ccb->gsm_id, ccb->dn_line, ccb->featuretype,
+ NULL, CC_CAUSE_ERROR);
+ break;
+ }
+ break;
+
+ case SIP_SDP_DNS_FAIL:
+ case SIP_SDP_NO_MEDIA:
+ case SIP_SDP_ERROR:
+ default:
+ sip_cc_feature_ack(ccb->gsm_id, ccb->dn_line, ccb->featuretype, NULL,
+ CC_CAUSE_ERROR);
+ break;
+ }
+
+ free_sip_message(response);
+ sip_sm_change_state(ccb, SIP_STATE_ACTIVE);
+}
+
+void
+ccsip_handle_accept_2xx (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ cc_feature_data_t data;
+ cc_features_t feature;
+ sipMessage_t *response;
+ int response_code = 0;
+ const char *cseq = NULL;
+ sipCseq_t *sipCseq = NULL;
+ char *fname = "ccsip_handle_accept_2xx";
+ sipMethod_t response_method;
+
+ response = event->u.pSipMessage;
+ if (sipGetResponseCode(response, &response_code) < 0) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sipGetResponseCode");
+ free_sip_message(response);
+ return;
+ }
+
+ /* Update connected party info from RPID and Call-Info header */
+ ccsip_update_callinfo(ccb, response, TRUE, FALSE, FALSE);
+
+ /* don't ack a 200 on a Notify message */
+ // if ((response_code == SIP_SUCCESS_SETUP) &&
+ // (ccb->last_sent_request_cseq_method == sipMethodNotify)) {
+ // free_sip_message(response);
+ // return;
+ // }
+ // Instead of checking the last request, check the CSeq method of
+ // the response and then determine which request it is responding to
+ // Then clear that request from the cseq array
+ cseq = sippmh_get_cached_header_val(response, CSEQ);
+ if (!cseq) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sippmh_get_cached_header_val(CSEQ)");
+ free_sip_message(response);
+ return;
+ }
+ sipCseq = sippmh_parse_cseq(cseq);
+ if (!sipCseq) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sippmh_parse_cseq()");
+ free_sip_message(response);
+ return;
+ }
+ response_method = sipCseq->method;
+ cpr_free(sipCseq);
+
+ if ((response_code == SIP_SUCCESS_SETUP) &&
+ (response_method == sipMethodNotify)) {
+ clean_method_request_trx(ccb, sipMethodNotify, TRUE);
+ free_sip_message(response);
+ return;
+ }
+
+ if (response_code != SIP_ACCEPTED) {
+ if (sipSPISendAck(ccb, response) != TRUE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sipSPISendAck");
+ free_sip_message(response);
+ return;
+ }
+ }
+ switch (ccb->featuretype) {
+ case CC_FEATURE_B2BCONF:
+ case CC_FEATURE_SELECT:
+ case CC_FEATURE_B2B_JOIN:
+ case CC_FEATURE_CANCEL:
+ ccb->authen.cred_type = 0;
+ feature = ccb->featuretype;
+ sip_cc_feature_ack(ccb->gsm_id, ccb->dn_line, feature, NULL,
+ CC_CAUSE_OK);
+ clean_method_request_trx(ccb, sipMethodRefer, TRUE);
+ free_sip_message(response);
+ return;
+ default:
+ break;
+ }
+
+ data.xfer.cause = CC_CAUSE_XFER_LOCAL;
+ data.xfer.method = CC_XFER_METHOD_REFER;
+ data.xfer.dialstring[0] = '\0';
+ data.xfer.target_call_id = ccb->gsm_id;
+ feature = fsmxfr_type_to_feature(fsmxfr_get_xfr_type(ccb->gsm_id));
+
+ sip_cc_feature_ack(ccb->gsm_id, ccb->dn_line, feature, &data, CC_CAUSE_OK);
+ clean_method_request_trx(ccb, sipMethodRefer, TRUE);
+ free_sip_message(response);
+}
+
+/*
+ * SIP_STATE_RECV_MIDCALLINVITE_CCFEATUREACK_PENDING
+ */
+void
+ccsip_handle_recvmidcallinvite_ccfeatureackpending_ev_cc_feature_ack (
+ ccsipCCB_t *ccb,
+ sipSMEvent_t *event)
+{
+ cc_features_t feature_type;
+ cc_msgbody_info_t *msg_body;
+
+ feature_type = event->u.cc_msg->msg.feature_ack.feature_id;
+
+ switch (feature_type) {
+ case CC_FEATURE_HOLD:
+ if (event->u.cc_msg->msg.feature_ack.data_valid) {
+ /* Save the msg. body */
+ msg_body = &event->u.cc_msg->msg.feature_ack.data.hold.msg_body;
+ ccsip_save_local_msg_body(ccb, msg_body);
+ }
+
+ sipSPISendInviteResponse200(ccb); /* HOLD */
+ sip_sm_change_state(ccb,
+ SIP_STATE_RECV_MIDCALL_INVITE_SIPACK_PENDING);
+ break;
+
+ case CC_FEATURE_RESUME:
+ /* fall through to send the response */
+ case CC_FEATURE_MEDIA:
+ /* new media acks put the sdp in the resume area as well */
+ if (event->u.cc_msg->msg.feature_ack.data_valid) {
+ msg_body = &event->u.cc_msg->msg.feature_ack.data.resume.msg_body;
+ ccsip_save_local_msg_body(ccb, msg_body);
+ }
+ if (event->u.cc_msg->msg.feature_ack.cause == CC_CAUSE_PAYLOAD_MISMATCH ||
+ event->u.cc_msg->msg.feature_ack.cause == CC_CAUSE_NO_MEDIA ||
+ event->u.cc_msg->msg.feature_ack.cause == CC_CAUSE_ERROR) {
+ /*
+ * Rejecting the new sdp
+ * The above errors are the ones currently thrown by gsm sdp processing.
+ * If any new errors are added the above check must be updated.
+ */
+ ccb->oa_state = OA_IDLE;
+ sipSPISendInviteResponse(ccb, SIP_CLI_ERR_NOT_ACCEPT_HERE,
+ SIP_CLI_ERR_NOT_ACCEPT_HERE_PHRASE,
+ SIP_WARN_MISC,
+ "SDP Not Acceptable",
+ FALSE, /* no SDP */ TRUE /* reTx */);
+ } else {
+ sipSPISendInviteResponse200(ccb);
+ }
+ sip_sm_change_state(ccb, SIP_STATE_RECV_MIDCALL_INVITE_SIPACK_PENDING);
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+/*
+ * SIP_STATE_RECV_MIDCALL_INVITE_SIPACK_PENDING
+ */
+void
+ccsip_handle_recvmidcallinvite_sipackpending_ev_sip_ack (ccsipCCB_t *ccb,
+ sipSMEvent_t *event)
+{
+ const char *fname =
+ "ccsip_handle_recvmidcallinvite_sipackpending_ev_sip_ack";
+ sipMessage_t *request;
+ uint16_t request_check_reason_code = 0;
+ char request_check_reason_phrase[SIP_WARNING_LENGTH];
+ cc_feature_data_t data;
+ sipsdp_status_t sdp_status;
+
+ /* Unpack the event */
+ request = event->u.pSipMessage;
+
+ /* Request check and store */
+ if (sip_sm_request_check_and_store(ccb, request, sipMethodAck, FALSE,
+ &request_check_reason_code,
+ request_check_reason_phrase, FALSE) < 0) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED), ccb->index,
+ ccb->dn_line, fname,
+ get_debug_string(DEBUG_FUNCTIONNAME_SIP_SM_REQUEST_CHECK_AND_STORE));
+ free_sip_message(request);
+ return;
+ }
+
+ /*
+ * Process SDP
+ */
+ sdp_status = sip_util_extract_sdp(ccb, request);
+
+ switch (sdp_status) {
+ case SIP_SDP_SUCCESS:
+ case SIP_SDP_SESSION_AUDIT:
+ if (ccb->oa_state != OA_OFFER_SENT) {
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_ENTRY),
+ ccb->index, ccb->dn_line, fname,
+ "Unexpected SDP in ACK, releasing call");
+ sipSPISendBye(ccb, NULL, NULL);
+ sip_cc_release(ccb->gsm_id, ccb->dn_line, CC_CAUSE_ERROR, NULL);
+ clean_method_request_trx(ccb, sipMethodAck, FALSE);
+ clean_method_request_trx(ccb, sipMethodInvite, FALSE);
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ return;
+ }
+
+ /*
+ * Check to see if received SDP indicates hold. If it is not
+ * a hold SDP, then we received a new media invite.
+ * Send FEATURE CC event to GSM.
+ */
+ ccb->oa_state = OA_IDLE;
+
+ /*
+ * Update connected party info from RPID and Call-Info header.
+ * MEDIA request, delay UI update.
+ */
+ ccsip_update_callinfo(ccb, request, TRUE, TRUE, TRUE);
+
+ /* Move the msg. body from the SIP msg. to CCAPI msg. */
+ sip_cc_mv_msg_body_to_cc_msg(&data.resume.msg_body, request);
+ sip_cc_feature(ccb->gsm_id, ccb->dn_line, CC_FEATURE_MEDIA, &data);
+ break;
+
+ case SIP_SDP_ERROR:
+ (void) sipSPISendErrorResponse(ccb->last_request, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ SIP_WARN_MISC, "Invalid SDP", ccb);
+ clean_method_request_trx(ccb, sipMethodAck, FALSE);
+ clean_method_request_trx(ccb, sipMethodInvite, FALSE);
+ return;
+
+ case SIP_SDP_DNS_FAIL:
+ sipSPISendInviteResponse(ccb, SIP_SERV_ERR_INTERNAL,
+ SIP_SERV_ERR_INTERNAL_PHRASE,
+ SIP_WARN_MISC,
+ "DNS lookup failed for media destination",
+ FALSE, FALSE);
+ break;
+
+ case SIP_SDP_NO_MEDIA:
+ (void) sipSPISendErrorResponse(ccb->last_request, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ SIP_WARN_MISC,
+ "No acceptable media line in SDP", ccb);
+ clean_method_request_trx(ccb, sipMethodAck, FALSE);
+ clean_method_request_trx(ccb, sipMethodInvite, FALSE);
+ return;
+
+ case SIP_SDP_NOT_PRESENT:
+ if (ccb->oa_state == OA_OFFER_SENT) {
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_ENTRY),
+ ccb->index, ccb->dn_line, fname,
+ "No answer SDP in ACK, releasing call");
+ sipSPISendBye(ccb, NULL, NULL);
+ sip_cc_release(ccb->gsm_id, ccb->dn_line, CC_CAUSE_ERROR, NULL);
+ clean_method_request_trx(ccb, sipMethodAck, FALSE);
+ clean_method_request_trx(ccb, sipMethodInvite, FALSE);
+ sip_sm_change_state(ccb, SIP_STATE_RELEASE);
+ return;
+ } else {
+ /* Update connected party info from RPID and Call-Info header */
+ ccsip_update_callinfo(ccb, request, TRUE, TRUE, FALSE);
+ }
+ break;
+
+ default:
+ /* Update connected party info from RPID and Call-Info header */
+ ccsip_update_callinfo(ccb, request, TRUE, TRUE, FALSE);
+ break;
+
+ }
+
+ /*
+ * Update state
+ */
+ sip_sm_change_state(ccb, SIP_STATE_ACTIVE);
+ clean_method_request_trx(ccb, sipMethodAck, FALSE);
+ clean_method_request_trx(ccb, sipMethodInvite, FALSE);
+}
+
+
+void
+ccsip_handle_transienthold_ev_cc_feature (ccsipCCB_t *ccb, int feature_type,
+ sipSMStateType_t final_resume_state,
+ sipSMEvent_t *event)
+{
+ const char *fname = "transienthold_ev_cc_feature";
+ cc_msgbody_info_t *msg_body;
+
+ switch (feature_type) {
+ case CC_FEATURE_RESUME:
+ if (event->u.cc_msg->msg.feature.data_valid) {
+ msg_body = &event->u.cc_msg->msg.feature.data.resume.msg_body;
+ ccsip_save_local_msg_body(ccb, msg_body);
+ }
+
+ ccb->hold_initiated = FALSE;
+ ccb->featuretype = CC_FEATURE_RESUME;
+ sip_sm_change_state(ccb, final_resume_state);
+ break;
+
+ default:
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_FEATURE_UNSUPPORTED),
+ ccb->index, ccb->dn_line, fname);
+ sip_cc_feature_ack(ccb->gsm_id, ccb->dn_line, feature_type, NULL,
+ CC_CAUSE_ERROR);
+ break;
+ }
+}
+
+
+int
+strcasecmp_ignorewhitespace (const char *cs, const char *ct)
+{
+ const char *p;
+ const char *q;
+
+ if (cpr_strcasecmp(cs, ct) == 0) {
+ return (0);
+ }
+
+ p = cs;
+ q = ct;
+
+ /* Ignore leading white space */
+ while (((*p == ' ') || (*p == '\t')) && (*p != '\0')) {
+ p++;
+ }
+ while (((*q == ' ') || (*q == '\t')) && (*q != '\0')) {
+ q++;
+ }
+
+ /* Compare until hit end or whitespace */
+ while ((*p != ' ') && (*p != '\t') && (*p != '\0') &&
+ (*q != ' ') && (*q != '\t') && (*q != '\0')) {
+ if (toupper(*p) != toupper(*q)) {
+ return (-1);
+ }
+ p++;
+ q++;
+ }
+
+ /* Make sure that what's left (if any) is whitespace */
+ while (*p != '\0') {
+ if ((*p != ' ') && (*p != '\t')) {
+ return (-1);
+ }
+ p++;
+ }
+ while (*q != '\0') {
+ if ((*q != ' ') && (*q != '\t')) {
+ return (-1);
+ }
+ q++;
+ }
+
+ return (0);
+}
+
+
+void
+sip_sm_util_normalize_name (ccsipCCB_t *ccb, char *dialString)
+{
+ char *outputString;
+ uint32_t usernameLength = 0;
+ const char *hostnameString = NULL;
+ uint32_t hostnameLength = 0;
+ char proxy_ipaddr_str[MAX_IPADDR_STR_LEN];
+ cpr_ip_addr_t proxy_ipaddr;
+ char *extraString = NULL;
+ char *parse_token;
+ uint32_t extraLength = 0;
+ uint32_t n = 0;
+ static char dialtranslate[MAX_SIP_URL_LENGTH];
+ char dest_sip_addr_str[MAX_IPADDR_STR_LEN];
+ char addr[MAX_IPADDR_STR_LEN];
+ int port;
+ int dialStringLength;
+
+ CPR_IP_ADDR_INIT(proxy_ipaddr);
+ /*
+ * Save away what they sent us so that we can display it to them later
+ */
+ dialStringLength = strlen(dialString);
+ memcpy((void *)ccb->calledDisplayedName, dialString, dialStringLength);
+ /*
+ * See if the string needs to be rewritten by applying the dial template
+ */
+ ccb->routeMode = RouteDefault;
+ (void) MatchDialTemplate(ccb->calledDisplayedName, ccb->dn_line, CAST_N &n, dialtranslate,
+ sizeof(dialtranslate),
+ (RouteMode *) &(ccb->routeMode), NULL);
+ dialString = dialtranslate;
+ dialStringLength = strlen(dialString);
+ /*
+ * Throw away any part of 0) && (dialString[0] == '<')) {
+ dialString++;
+ dialStringLength--;
+ }
+ /*
+ * For the SIP: part, we have to have 4 characters
+ */
+ if ((dialStringLength > 4) &&
+ (tolower(dialString[0]) == 's') &&
+ (tolower(dialString[1]) == 'i') &&
+ (tolower(dialString[2]) == 'p') &&
+ (tolower(dialString[3]) == ':')) {
+ dialStringLength -= 4;
+ dialString += 4;
+ }
+
+ /*
+ * Parse the remainder of the string looking for the host name
+ */
+ parse_token = strpbrk(dialString, "@;>"); /* Skip the user name first */
+ if (parse_token == NULL) { /* Only user name exists and no host, extra and ;> */
+ usernameLength = dialStringLength;
+ } else {
+ usernameLength = parse_token - dialString; /* save username length */
+ if (parse_token[0] == '@') { /* host name exists in addition */
+ extraString = strpbrk(parse_token, ";>"); /* Skip the host name */
+ if (extraString != NULL) { /* extra params exist */
+ extraLength = dialStringLength - (extraString - dialString);
+ }
+ /*
+ * Save the host name and host length if proxy selection is
+ * not backup. In case of proxy selection being backup,
+ * ignore the hostname & rebuild using dotted IP of backup proxy later
+ */
+ if (ccb->proxySelection != SIP_PROXY_BACKUP) {
+ hostnameString = parse_token + 1;
+ /* In case of host name, the length must exclude @ and hence -1 */
+ hostnameLength = dialStringLength - usernameLength - extraLength - 1;
+ }
+ } else { /* No host, but extra param exist */
+ extraLength = dialStringLength - usernameLength;
+ extraString = parse_token;
+ }
+ }
+
+ /*
+ * At this point we have
+ * usernameLength - Number of characters in the user name
+ * starting from dialString[0]
+ * hostnameString - NULL if no @ was encountered, otherwise it
+ * points to the start of the host name string
+ * hostnameLength - 0 if no host name characters were encountered
+ * extraString - Points to any extra parameters
+ * extraLength - number of extra parameter characters
+ */
+ if (hostnameLength == 0) {
+ /*
+ * At this junctor in the quantum,
+ *
+ */
+ switch (ccb->routeMode) {
+ case RouteEmergency:
+ /*
+ * If we have failed over to the backup we need
+ * to not reselect the emergency proxy
+ */
+ if (ccb->proxySelection != SIP_PROXY_BACKUP) {
+ // Get the Emergency Proxy
+ sipTransportGetEmerServerAddress(ccb->dn_line, proxy_ipaddr_str);
+ hostnameString = &proxy_ipaddr_str[0];
+ hostnameLength = strlen(hostnameString);
+ if (hostnameLength) {
+ if (!str2ip((const char *) proxy_ipaddr_str, &proxy_ipaddr)) {
+ /* Fill in address and port in CCB */
+ util_ntohl(&(ccb->dest_sip_addr), &(proxy_ipaddr));
+
+ /*
+ * If the Proxy Emergency Port isn't contained in the
+ * config table, use the PROXYN port instead.
+ */
+ port = sipTransportGetEmerServerPort(ccb->dn_line);
+ if (port) {
+ ccb->dest_sip_port = port;
+ } else {
+ ccb->dest_sip_port = sipTransportGetPrimServerPort(ccb->dn_line);
+ }
+ break;
+ }
+ }
+ }
+ // Otherwise Emergency proxy is not in configuration follow thru
+ /*FALLTHROUGH*/
+ default:
+ /*
+ * set the proxy address differently if the backup proxy
+ * has been activated. The address has already been placed into
+ * ccb->dest_sip_addr and ccb->dest_sip_port so just use
+ * those values
+ */
+ if (ccb->proxySelection == SIP_PROXY_BACKUP) {
+ ipaddr2dotted(dest_sip_addr_str, &ccb->dest_sip_addr);
+ hostnameString = dest_sip_addr_str;
+ hostnameLength = strlen(hostnameString);
+ } else {
+ sipTransportGetPrimServerAddress(ccb->dn_line, addr);
+ hostnameString = addr;
+ hostnameLength = strlen(hostnameString);
+ sipTransportGetServerIPAddr(&(ccb->dest_sip_addr), ccb->dn_line);
+ ccb->dest_sip_port = sipTransportGetPrimServerPort(ccb->dn_line);
+ }
+ }
+ }
+
+ /*
+ * Construct the actual dial out string
+ */
+ outputString = (char *) ccb->calledNumber;
+ sstrncpy(outputString, "
+ */
+ outputString[extraLength] = 0;
+ /*
+ * If there was no > in what they gave us, put one in for them
+ */
+ if (strchr(outputString, '>') == NULL) {
+ outputString[extraLength++] = '>';
+ }
+ outputString += extraLength;
+ } else {
+ *outputString++ = '>';
+ }
+ /*
+ * Null terminate the string for good measure and note how long it is
+ */
+ *outputString = 0;
+ ccb->calledNumberLen = (uint16_t) (outputString - ccb->calledNumber);
+}
+
+
+void
+get_sip_error_string (char *errortext, int response)
+{
+
+ if (NULL == errortext)
+ return;
+ switch (response) {
+ case SIP_SUCCESS_SETUP:
+ sstrncpy(errortext, SIP_SUCCESS_SETUP_PHRASE, MAX_SIP_URL_LENGTH);
+ break;
+ case SIP_ACCEPTED:
+ sstrncpy(errortext, SIP_ACCEPTED_PHRASE, MAX_SIP_URL_LENGTH);
+ break;
+ case SIP_1XX_TRYING:
+ sstrncpy(errortext, SIP_1XX_TRYING_PHRASE, MAX_SIP_URL_LENGTH);
+ break;
+ case SIP_RED_MULT_CHOICES:
+ sstrncpy(errortext, SIP_RED_MULT_CHOICES_PHRASE, MAX_SIP_URL_LENGTH);
+ break;
+ case SIP_RED_MOVED_PERM:
+ sstrncpy(errortext, SIP_RED_MOVED_PERM_PHRASE, MAX_SIP_URL_LENGTH);
+ break;
+ case SIP_RED_MOVED_TEMP:
+ sstrncpy(errortext, SIP_RED_MOVED_TEMP_PHRASE, MAX_SIP_URL_LENGTH);
+ break;
+ case SIP_RED_SEE_OTHER:
+ sstrncpy(errortext, SIP_RED_SEE_OTHER_PHRASE, MAX_SIP_URL_LENGTH);
+ break;
+ case SIP_RED_USE_PROXY:
+ sstrncpy(errortext, SIP_RED_USE_PROXY_PHRASE, MAX_SIP_URL_LENGTH);
+ break;
+ case SIP_RED_ALT_SERVICE:
+ sstrncpy(errortext, SIP_RED_ALT_SERVICE_PHRASE, MAX_SIP_URL_LENGTH);
+ break;
+ case SIP_CLI_ERR_BAD_REQ: /* 400 Bad Request */
+ sstrncpy(errortext, SIP_CLI_ERR_BAD_REQ_PHRASE, MAX_SIP_URL_LENGTH);
+ break;
+ case SIP_CLI_ERR_UNAUTH: /* 401 Unauthorized */
+ sstrncpy(errortext, SIP_CLI_ERR_UNAUTH_PHRASE, MAX_SIP_URL_LENGTH);
+ break;
+ case SIP_CLI_ERR_PAY_REQD: /* 402 Payment Required */
+ sstrncpy(errortext, SIP_CLI_ERR_PAY_REQD_PHRASE, MAX_SIP_URL_LENGTH);
+ break;
+ case SIP_CLI_ERR_FORBIDDEN: /* 403 Forbidden */
+ sstrncpy(errortext, SIP_CLI_ERR_FORBIDDEN_PHRASE, MAX_SIP_URL_LENGTH);
+ break;
+ case SIP_CLI_ERR_NOT_FOUND: /* 404 Not Found */
+ sstrncpy(errortext, SIP_CLI_ERR_NOT_FOUND_PHRASE, MAX_SIP_URL_LENGTH);
+ break;
+ case SIP_CLI_ERR_NOT_ALLOWED: /* 405 Method Not Allowed */
+ sstrncpy(errortext, SIP_CLI_ERR_NOT_ALLOWED_PHRASE, MAX_SIP_URL_LENGTH);
+ break;
+ case SIP_CLI_ERR_NOT_ACCEPT: /* 406 Not Acceptable */
+ sstrncpy(errortext, SIP_CLI_ERR_NOT_ACCEPT_PHRASE, MAX_SIP_URL_LENGTH);
+ break;
+ case SIP_CLI_ERR_PROXY_REQD: /* 407 Proxy Authentication Required */
+ sstrncpy(errortext, SIP_CLI_ERR_PROXY_REQD_PHRASE, MAX_SIP_URL_LENGTH);
+ break;
+ case SIP_CLI_ERR_REQ_TIMEOUT: /* 408 Request Timeout */
+ sstrncpy(errortext, SIP_CLI_ERR_REQ_TIMEOUT_PHRASE, MAX_SIP_URL_LENGTH);
+ break;
+ case SIP_CLI_ERR_CONFLICT: /* 409 Conflict */
+ sstrncpy(errortext, SIP_CLI_ERR_CONFLICT_PHRASE, MAX_SIP_URL_LENGTH);
+ break;
+ case SIP_CLI_ERR_GONE: /* 410 Gone */
+ sstrncpy(errortext, SIP_CLI_ERR_GONE_PHRASE, MAX_SIP_URL_LENGTH);
+ break;
+ case SIP_CLI_ERR_LEN_REQD: /* 411 Length Required */
+ sstrncpy(errortext, SIP_CLI_ERR_LEN_REQD_PHRASE, MAX_SIP_URL_LENGTH);
+ break;
+ case SIP_CLI_ERR_LARGE_MSG: /* 413 Request Message Body Too Large */
+ sstrncpy(errortext, SIP_CLI_ERR_LARGE_MSG_PHRASE, MAX_SIP_URL_LENGTH);
+ break;
+ case SIP_CLI_ERR_LARGE_URI: /* 414 Request-URI Too Large */
+ sstrncpy(errortext, SIP_CLI_ERR_LARGE_URI_PHRASE, MAX_SIP_URL_LENGTH);
+ break;
+ case SIP_CLI_ERR_MEDIA: /* 415 Unsupported Media Type */
+ sstrncpy(errortext, SIP_CLI_ERR_MEDIA_PHRASE, MAX_SIP_URL_LENGTH);
+ break;
+ case SIP_CLI_ERR_EXTENSION: /* 420 Bad Extension */
+ sstrncpy(errortext, SIP_CLI_ERR_EXTENSION_PHRASE, MAX_SIP_URL_LENGTH);
+ break;
+ case SIP_CLI_ERR_ANONYMITY_NOT_ALLOWED: /* 433 Anonymity Disallowed */
+ sstrncpy(errortext, SIP_CLI_ERR_ANONYMITY_NOT_ALLOWED_PHRASE, MAX_SIP_URL_LENGTH);
+ break;
+ case SIP_CLI_ERR_NOT_AVAIL: /* 480 Temporarily Not Available */
+ sstrncpy(errortext, SIP_CLI_ERR_NOT_AVAIL_PHRASE, MAX_SIP_URL_LENGTH);
+ break;
+ case SIP_CLI_ERR_CALLEG: /* 481 Call Leg/Transaction Does Not Exist */
+ sstrncpy(errortext, SIP_CLI_ERR_CALLEG_PHRASE, MAX_SIP_URL_LENGTH);
+ break;
+ case SIP_CLI_ERR_LOOP_DETECT: /* 482 Loop Detected */
+ sstrncpy(errortext, SIP_CLI_ERR_LOOP_DETECT_PHRASE, MAX_SIP_URL_LENGTH);
+ break;
+ case SIP_CLI_ERR_MANY_HOPS: /* 483 Too Many Hops */
+ sstrncpy(errortext, SIP_CLI_ERR_MANY_HOPS_PHRASE, MAX_SIP_URL_LENGTH);
+ break;
+ case SIP_CLI_ERR_ADDRESS: /* 484 Address Incomplete */
+ sstrncpy(errortext, SIP_CLI_ERR_ADDRESS_PHRASE, MAX_SIP_URL_LENGTH);
+ break;
+ case SIP_CLI_ERR_AMBIGUOUS: /* 485 Ambiguous */
+ sstrncpy(errortext, SIP_CLI_ERR_AMBIGUOUS_PHRASE, MAX_SIP_URL_LENGTH);
+ break;
+ case SIP_CLI_ERR_BUSY_HERE: /* 486 Busy here */
+ sstrncpy(errortext, SIP_CLI_ERR_BUSY_HERE_PHRASE, MAX_SIP_URL_LENGTH);
+ break;
+ case SIP_CLI_ERR_REQ_CANCEL: /* 487 Request Cancelled */
+ sstrncpy(errortext, SIP_CLI_ERR_REQ_CANCEL_PHRASE, MAX_SIP_URL_LENGTH);
+ break;
+ case SIP_CLI_ERR_BAD_EVENT: /* 489 Bad Event */
+ sstrncpy(errortext, SIP_CLI_ERR_BAD_EVENT_PHRASE, MAX_SIP_URL_LENGTH);
+ break;
+ case SIP_SERV_ERR_INTERNAL: /*500 Internal Server Error */
+ sstrncpy(errortext, SIP_SERV_ERR_INTERNAL_PHRASE, MAX_SIP_URL_LENGTH);
+ break;
+ case SIP_SERV_ERR_NOT_IMPLEM: /* 501 Not Implemented */
+ sstrncpy(errortext, SIP_SERV_ERR_NOT_IMPLEM_PHRASE, MAX_SIP_URL_LENGTH);
+ break;
+ case SIP_SERV_ERR_BAD_GW: /*502 Bad Gateway */
+ sstrncpy(errortext, SIP_SERV_ERR_BAD_GW_PHRASE, MAX_SIP_URL_LENGTH);
+ break;
+ case SIP_SERV_ERR_UNAVAIL: /* 503 Service Unavailable */
+ sstrncpy(errortext, SIP_SERV_ERR_UNAVAIL_PHRASE, MAX_SIP_URL_LENGTH);
+ break;
+ case SIP_SERV_ERR_GW_TIMEOUT: /*504 Gateway Timeout */
+ sstrncpy(errortext, SIP_SERV_ERR_GW_TIMEOUT_PHRASE, MAX_SIP_URL_LENGTH);
+ break;
+ case SIP_SERV_ERR_SIP_VER: /*505 SIP Version not supported */
+ sstrncpy(errortext, SIP_SERV_ERR_SIP_VER_PHRASE, MAX_SIP_URL_LENGTH);
+ break;
+ case SIP_SERV_ERR_PRECOND_FAILED: /*580 Precondition Failed */
+ sstrncpy(errortext, SIP_SERV_ERR_PRECOND_FAILED_PHRASE,
+ MAX_SIP_URL_LENGTH);
+ break;
+ case SIP_FAIL_BUSY: /*600 BUSY */
+ sstrncpy(errortext, SIP_FAIL_BUSY_PHRASE, MAX_SIP_URL_LENGTH);
+ break;
+ case SIP_FAIL_DECLINE: /*603 Decline */
+ sstrncpy(errortext, SIP_FAIL_DECLINE_PHRASE, MAX_SIP_URL_LENGTH);
+ break;
+ case SIP_FAIL_NOT_EXIST: /*604 Does not exist anywhere */
+ sstrncpy(errortext, SIP_FAIL_NOT_EXIST_PHRASE, MAX_SIP_URL_LENGTH);
+ break;
+ case SIP_FAIL_NOT_ACCEPT: /*606 Not Acceptable */
+ sstrncpy(errortext, SIP_FAIL_NOT_ACCEPT_PHRASE, MAX_SIP_URL_LENGTH);
+ break;
+ default:
+ sstrncpy(errortext, SIP_STATUS_PHRASE_NONE, MAX_SIP_URL_LENGTH);
+ break;
+ }
+}
+
+/***********************************************************************
+ * Function: ccsip_handle_early_ev_sip_update
+ * Description: This function handles an incoming UPDATE message, parses
+ * and sends it up to GSM as cc_feature call
+ *************************************** ********************************/
+void
+ccsip_handle_early_ev_sip_update (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ const char *fname = "early_ev_sip_update";
+ sipMessage_t *request = NULL;
+ unsigned short request_check_reason_code = 0;
+ char request_check_reason_phrase[SIP_WARNING_LENGTH];
+ sipMethod_t method = sipMethodInvalid;
+ sipsdp_status_t sdp_status;
+ boolean display_valid = TRUE;
+
+
+ /* Unpack the event */
+ request = event->u.pSipMessage;
+
+ sipGetRequestMethod(request, &method);
+
+ // Check if we are already processing a previously received UPDATE
+ if (get_method_request_trx_index(ccb, method, FALSE) > -1) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Received UPDATE while processing an old one!\n",
+ fname);
+ (void) sipSPISendErrorResponse(request, SIP_SERV_ERR_INTERNAL,
+ SIP_SERV_ERR_INTERNAL_PHRASE,
+ SIP_WARN_PROCESSING_PREVIOUS_REQUEST,
+ NULL, NULL);
+ free_sip_message(request);
+ return;
+ }
+
+ // Check if we have an UPDATE outstanding - if so we have a glare condition
+ if (get_method_request_trx_index(ccb, method, TRUE) > -1) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Received UPDATE while old one outstanding!\n",
+ fname);
+ (void) sipSPISendErrorResponse(request, SIP_CLI_ERR_REQ_PENDING,
+ SIP_CLI_ERR_REQ_PENDING_PHRASE, 0, NULL, NULL);
+ free_sip_message(request);
+ return;
+ }
+
+ memset(request_check_reason_phrase, 0, SIP_WARNING_LENGTH);
+
+ /* Request check and store */
+ if (sip_sm_request_check_and_store(ccb, request, method, TRUE,
+ &request_check_reason_code,
+ request_check_reason_phrase, FALSE) < 0) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ ccb->index, ccb->dn_line, fname,
+ get_debug_string(DEBUG_FUNCTIONNAME_SIP_SM_REQUEST_CHECK_AND_STORE));
+ (void) sipSPISendErrorResponse(request, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ request_check_reason_code,
+ request_check_reason_phrase, NULL);
+ free_sip_message(request);
+ return;
+ }
+
+ /*
+ * Check if display options are acceptable.
+ */
+ display_valid = ccsip_check_display_validity(ccb, request);
+ if (!display_valid) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Rejecting UPDATE with callerid blocked.Anonymous Callback configured!\n",
+ fname);
+ (void) sipSPISendErrorResponse(request, SIP_CLI_ERR_ANONYMITY_NOT_ALLOWED,
+ SIP_CLI_ERR_ANONYMITY_NOT_ALLOWED_PHRASE,
+ SIP_WARN_PROCESSING_PREVIOUS_REQUEST,
+ NULL, NULL);
+ return;
+ }
+
+ // Check for anything in the REQUIRE header
+ // Update the contact information, if any
+
+ // Since this is still an early dialog and we have not updated our from/to headers
+ // Copy the To header so that a response can be generated correctly
+ if (!(ccb->flags & INCOMING)) {
+ const char *from;
+
+ from = sippmh_get_cached_header_val(request, FROM);
+ ccb->sip_to = strlib_update(ccb->sip_to, from);
+ }
+
+ // If there is SDP in this message, extract it and send it up to GSM
+ sdp_status = sip_util_extract_sdp(ccb, request);
+ switch (sdp_status) {
+ case SIP_SDP_SUCCESS:
+ /*
+ * Since we do not support PRACK, UPDATE received for an early
+ * dialog can not contain SDP. RFC3311 section 5.2 describes
+ * the behavior to follow when receiving UPDATE.
+ *
+ * If UAS receives UPDATE before UAS has generated answer to
+ * previous offer, UAS must respond with 500 which includes a
+ * Retry-after header field with a random value between 0 and
+ * 10 seconds.
+ *
+ * If UAS receives UPDATE before receiving an answer to an offer
+ * made by the UAS, the UAS must respond with 491.
+ */
+ if (ccb->oa_state == OA_OFFER_SENT) {
+ (void) sipSPISendUpdateResponse(ccb, FALSE, CC_CAUSE_REQUEST_PENDING, FALSE);
+ } else {
+ /*
+ * Must be case that ccb->oa_stat == OA_OFFER_RECEIVED, since we
+ * are an early dialog. In either case, we send 500 response.
+ */
+ (void) sipSPISendUpdateResponse(ccb, FALSE, CC_CAUSE_NO_RESOURCE, FALSE);
+ }
+ return;
+
+ case SIP_SDP_ERROR:
+ (void) sipSPISendErrorResponse(ccb->last_request, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ SIP_WARN_MISC, "Invalid SDP", ccb);
+ return;
+
+ case SIP_SDP_DNS_FAIL:
+ (void) sipSPISendErrorResponse(ccb->last_request, SIP_SERV_ERR_INTERNAL,
+ SIP_SERV_ERR_INTERNAL_PHRASE,
+ SIP_WARN_MISC,
+ "DNS lookup failed for media destination", ccb);
+ return;
+
+ case SIP_SDP_NO_MEDIA:
+ (void) sipSPISendErrorResponse(ccb->last_request, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ SIP_WARN_MISC,
+ "No acceptable media line in SDP", ccb);
+ return;
+
+ case SIP_SDP_NOT_PRESENT:
+ default:
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX":Update received without SDP\n", fname);
+ break;
+ }
+
+ /* Update connected party info from RPID and Call-Info header */
+ ccsip_update_callinfo(ccb, request, TRUE, TRUE, FALSE);
+
+ /*
+ * Since we do not support PRACK, media can not be changed with UPDATE
+ * during early dialog. We alread sent the call info changes to GSM above
+ * so there is nothing else to inform GSM about. Go ahead and send the
+ * response to the far end.
+ * NOTE: When PRACK is supported, we will need to update this function
+ * to send media to GSM.
+ */
+ (void) sipSPISendUpdateResponse(ccb, FALSE, CC_CAUSE_OK, FALSE);
+}
+
+/***********************************************************************
+ * Function: ccsip_handle_early_ev_sip_update_response
+ * Description: This function handles an incoming response to a previously
+ * send UPDATE message, and sends it up to GSM via cc_feature_ack
+ ***********************************************************************/
+void
+ccsip_handle_early_ev_sip_update_response (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+}
+
+/***********************************************************************
+ * Function: ccsip_handle_early_ev_cc_feature
+ * Description: This function handles GSM's request to invoke a feature
+ * before the dialog is fully established.
+ ***********************************************************************/
+void
+ccsip_handle_early_ev_cc_feature (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+
+ const char *fname = "early_ev_cc_feature";
+ cc_features_t feature_type;
+ cc_msgbody_info_t *msg_body;
+
+ feature_type = event->u.cc_msg->msg.feature.feature_id;
+ if (feature_type == CC_FEATURE_UPDATE) {
+ if (event->u.cc_msg->msg.feature.data_valid) {
+ msg_body = &event->u.cc_msg->msg.feature.data.update.msg_body;
+ ccsip_save_local_msg_body(ccb, msg_body);
+ }
+ (void) sipSPISendUpdate(ccb);
+ } else if (feature_type == CC_FEATURE_SELECT) {
+ } else {
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_FEATURE_UNSUPPORTED),
+ ccb->index, ccb->dn_line, fname);
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_STATE_UNCHANGED),
+ ccb->index, ccb->dn_line, fname,
+ sip_util_state2string(ccb->state));
+ sip_cc_feature_ack(ccb->gsm_id, ccb->dn_line, feature_type, NULL,
+ CC_CAUSE_ERROR);
+ }
+}
+
+/***********************************************************************
+ * Function: ccsip_handle_early_ev_cc_feature_ack
+ * Description: This function handles GSM's acknowledgment to an early
+ * feature invocation. At this time only responses to the
+ * UPDATE message is supported
+ ***********************************************************************/
+void
+ccsip_handle_early_ev_cc_feature_ack (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ const char *fname = "early_ev_cc_feature_ack";
+ cc_features_t feature_type;
+ cc_msgbody_info_t *msg_body;
+
+ feature_type = event->u.cc_msg->msg.feature_ack.feature_id;
+
+ switch (feature_type) {
+ case CC_FEATURE_UPDATE:
+ if (event->u.cc_msg->msg.feature.data_valid) {
+ msg_body = &event->u.cc_msg->msg.feature.data.update.msg_body;
+ ccsip_save_local_msg_body(ccb, msg_body);
+ }
+ (void) sipSPISendUpdateResponse(ccb, event->u.cc_msg->msg.feature.data_valid,
+ event->u.cc_msg->msg.feature_ack.cause,
+ FALSE);
+ break;
+
+ default:
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_FEATURE_UNSUPPORTED),
+ ccb->index, ccb->dn_line, fname);
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_STATE_UNCHANGED),
+ ccb->index, ccb->dn_line, fname,
+ sip_util_state2string(ccb->state));
+ break;
+ }
+}
+
+/***********************************************************************
+ * Function: ccsip_handle_active_ev_sip_update
+ *
+ * Description: This function handles receipt of a SIP UPDATE message
+ * when the call is in the confirmed state. Based on the SDP contained,
+ * this may be put the call on hold or to propose new media. In either
+ * case, the new SDP is sent upto the GSM using cc_feature_update.
+ *
+ * In addition or instead of a media change, the UPDATE may also send
+ * updated values of the call-info header and RPID so these need to parsed
+ * and sent to GSM as well
+ *
+ * This function is analogous to the one the processes reINVITEs
+ ***********************************************************************/
+void
+ccsip_handle_active_ev_sip_update (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ const char *fname = "active_ev_sip_update";
+ sipMessage_t *request;
+ const char *require = NULL;
+ const char *contact = NULL;
+ uint16_t request_check_reason_code = 0;
+ char request_check_reason_phrase[SIP_WARNING_LENGTH];
+ cc_feature_data_t data;
+ sipsdp_status_t sdp_status;
+ boolean display_valid = TRUE;
+
+ /* Unpack the event */
+ request = event->u.pSipMessage;
+
+ // Check if we are already processing a previously received UPDATE
+ if (get_method_request_trx_index(ccb, sipMethodUpdate, FALSE) > -1) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Received UPDATE while processing an old one!\n",
+ fname);
+ (void) sipSPISendErrorResponse(request, SIP_SERV_ERR_INTERNAL,
+ SIP_SERV_ERR_INTERNAL_PHRASE,
+ SIP_WARN_PROCESSING_PREVIOUS_REQUEST,
+ NULL, NULL);
+ free_sip_message(request);
+ return;
+ }
+
+ /* Request check and store */
+ if (sip_sm_request_check_and_store(ccb, request, sipMethodUpdate, TRUE,
+ &request_check_reason_code,
+ request_check_reason_phrase, FALSE) < 0) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ ccb->index, ccb->dn_line, fname,
+ get_debug_string(DEBUG_FUNCTIONNAME_SIP_SM_REQUEST_CHECK_AND_STORE));
+ (void) sipSPISendErrorResponse(request, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ request_check_reason_code,
+ request_check_reason_phrase, NULL);
+ free_sip_message(request);
+ return;
+ }
+
+ /*
+ * Check if display options are acceptable.
+ */
+ display_valid = ccsip_check_display_validity(ccb, request);
+ if (!display_valid) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Rejecting UPDATE with callerid blocked.Anonymous Callback configured!\n",
+ fname);
+ (void) sipSPISendErrorResponse(request, SIP_CLI_ERR_ANONYMITY_NOT_ALLOWED,
+ SIP_CLI_ERR_ANONYMITY_NOT_ALLOWED_PHRASE,
+ SIP_WARN_PROCESSING_PREVIOUS_REQUEST,
+ NULL, NULL);
+ return;
+ }
+
+ /* Require: header */
+ require = sippmh_get_cached_header_val(request, REQUIRE);
+ if (require) {
+ ccb->sip_require = strlib_update(ccb->sip_require, require);
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX"Unsupported Require Header in UPDATE\n",
+ DEB_F_PREFIX_ARGS(SIP_CALL_STATUS, fname));
+ sipSPISendInviteResponse(ccb, SIP_CLI_ERR_EXTENSION,
+ SIP_CLI_ERR_EXTENSION_PHRASE,
+ 0, NULL, FALSE, /*no SDP */ TRUE /*reTx */);
+ return;
+ }
+
+ /* update the contact information if needed */
+ contact = sippmh_get_cached_header_val(request, CONTACT);
+ if (contact) {
+ if (ccb->contact_info) {
+ sippmh_free_contact(ccb->contact_info);
+ }
+ ccb->contact_info = sippmh_parse_contact(contact);
+ }
+
+
+
+ /*
+ * Process SDP
+ */
+ sdp_status = sip_util_extract_sdp(ccb, request);
+
+ switch (sdp_status) {
+ case SIP_SDP_SESSION_AUDIT:
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX"Received Session Audit SDP in UPDATE\n",
+ DEB_F_PREFIX_ARGS(SIP_SDP, fname));
+ /*FALLTHROUGH*/
+
+ case SIP_SDP_SUCCESS:
+ /*
+ * If UAS receives UPDATE before UAS has generated answer to
+ * previous offer, UAS must respond with 500 which includes a
+ * Retry-after header field with a random value between 0 and
+ * 10 seconds.
+ *
+ * If UAS receives UPDATE before receiving an answer to an offer
+ * made by the UAS, the UAS must respond with 491.
+ */
+ if (ccb->oa_state != OA_IDLE) {
+ cc_causes_t cause;
+
+ cause = (ccb->oa_state == OA_OFFER_SENT ?
+ CC_CAUSE_REQUEST_PENDING : CC_CAUSE_NO_RESOURCE);
+ (void) sipSPISendUpdateResponse(ccb, FALSE, cause, FALSE);
+ return;
+ }
+ /*
+ * Process Call-info header, if any
+ */
+ if (sdp_status == SIP_SDP_SESSION_AUDIT) {
+ /* Update call info to UI can be not delayed */
+ ccsip_update_callinfo(ccb, request, TRUE, TRUE, FALSE);
+ } else {
+ /* Update call info to UI can be delayed */
+ ccsip_update_callinfo(ccb, request, TRUE, TRUE, TRUE);
+ }
+
+ /*
+ * Check to see if received SDP indicates hold. If it is not
+ * a hold SDP, then we received a new media invite.
+ * Send FEATURE CC event to GSM.
+ */
+ ccb->oa_state = OA_OFFER_RECEIVED;
+ /* Move the message body from the SIP msg. into CCAPI msg */
+ sip_cc_mv_msg_body_to_cc_msg(&data.resume.msg_body, request);
+ sip_cc_feature(ccb->gsm_id, ccb->dn_line, CC_FEATURE_MEDIA, &data);
+ sip_sm_change_state(ccb,
+ SIP_STATE_RECV_UPDATEMEDIA_CCFEATUREACK_PENDING);
+ break;
+
+ case SIP_SDP_ERROR:
+ (void) sipSPISendErrorResponse(ccb->last_request, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ SIP_WARN_MISC, "Invalid SDP", ccb);
+ return;
+
+ case SIP_SDP_DNS_FAIL:
+ sipSPISendInviteResponse(ccb, SIP_SERV_ERR_INTERNAL,
+ SIP_SERV_ERR_INTERNAL_PHRASE,
+ SIP_WARN_MISC,
+ "DNS lookup failed for media destination",
+ FALSE, FALSE);
+ return;
+
+ case SIP_SDP_NO_MEDIA:
+ (void) sipSPISendErrorResponse(ccb->last_request, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ SIP_WARN_MISC,
+ "No acceptable media line in SDP", ccb);
+ return;
+
+ case SIP_SDP_NOT_PRESENT:
+ default:
+ /* Update call info to UI can be not delayed */
+ ccsip_update_callinfo(ccb, request, TRUE, TRUE, FALSE);
+ sip_cc_feature(ccb->gsm_id, ccb->dn_line, CC_FEATURE_UPDATE, NULL);
+ (void) sipSPISendUpdateResponse(ccb, FALSE, CC_CAUSE_OK, FALSE);
+ break;
+ }
+
+}
+
+/***********************************************************************
+ * Function: ccsip_handle_recvupdatemedia_ccfeatureackpending_ev_cc_feature_ack
+ *
+ * Description: This function handles a CC_FEATURE_ACK from GSM that the
+ * GSM sends in response to an new media SDP or hold received in an UPDATE
+ * message and sent to it.
+ ***********************************************************************/
+void
+ccsip_handle_recvupdatemedia_ccfeatureackpending_ev_cc_feature_ack (
+ ccsipCCB_t *ccb,
+ sipSMEvent_t *event)
+{
+ cc_features_t feature_type;
+ cc_causes_t cause;
+ cc_msgbody_info_t *msg_body;
+
+ feature_type = event->u.cc_msg->msg.feature_ack.feature_id;
+ cause = event->u.cc_msg->msg.feature_ack.cause;
+
+ switch (feature_type) {
+ case CC_FEATURE_HOLD:
+ if (cause == CC_CAUSE_NORMAL) {
+ cause = CC_CAUSE_OK;
+ }
+ if (event->u.cc_msg->msg.feature_ack.data_valid) {
+ msg_body = &event->u.cc_msg->msg.feature_ack.data.hold.msg_body;
+ ccsip_save_local_msg_body(ccb, msg_body);
+ }
+ (void) sipSPISendUpdateResponse(ccb,
+ event->u.cc_msg->msg.feature.data_valid,
+ cause, FALSE);
+ sip_sm_change_state(ccb, SIP_STATE_ACTIVE);
+ break;
+
+ case CC_FEATURE_RESUME:
+ case CC_FEATURE_MEDIA:
+ if (cause == CC_CAUSE_NORMAL || cause == CC_CAUSE_NO_RESUME) {
+ cause = CC_CAUSE_OK;
+ }
+
+ /* new media acks put the sdp in the resume area as well */
+ if (event->u.cc_msg->msg.feature_ack.data_valid) {
+ msg_body = &event->u.cc_msg->msg.feature_ack.data.resume.msg_body;
+ ccsip_save_local_msg_body(ccb, msg_body);
+ }
+
+ (void) sipSPISendUpdateResponse(ccb,
+ event->u.cc_msg->msg.feature.data_valid,
+ cause, FALSE);
+ sip_sm_change_state(ccb, SIP_STATE_ACTIVE);
+ break;
+
+ default:
+ break;
+ }
+}
+
+/***********************************************************************
+ * Function: ccsip_handle_timer_glare_avoidance
+ *
+ * Description: This function handles the glare condition previously
+ * detected
+ ***********************************************************************/
+void
+ccsip_handle_timer_glare_avoidance (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ const char *fname = "timer_glare_avoidance";
+
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_ENTRY), ccb->index,
+ ccb->dn_line, fname, "Resending message");
+
+ // Check if this message still needs to be sent.
+ if (ccb->state == SIP_STATE_IDLE ||
+ ccb->state == SIP_STATE_RELEASE) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"LINE %d CCB no longer used - message not sent!\n",
+ fname, ccb->index);
+ return;
+ }
+
+ // Note that the assumption here is that the glare condition can only happen
+ // on an INVITE. Perhaps some more checks could be made here to make sure
+ // this was the case
+ (void) sipSPISendInviteMidCall(ccb, FALSE);
+}
+
+/***********************************************************************
+ *
+ * SIPTaskProcessSIPNotifyServiceControl
+ *
+ * Handles an incoming unsolicited NOTIFY service control message
+ *
+ * Parameters: Incoming pSipMessage
+ *
+ * Return Value: scb if message is validated
+ * NULL if validation fails
+ *
+ ***********************************************************************/
+sipServiceControl_t *
+ccsip_get_notify_service_control (sipMessage_t *pSipMessage)
+{
+ const char *fname = "ccsip_get_notify_service_control";
+ sipServiceControl_t *scp;
+ line_t i;
+ ccsipCCB_t *ccb = NULL;
+ boolean param_match = FALSE;
+
+ // Check the body
+ if (pSipMessage->mesg_body[0].msgBody == NULL) {
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Received NOTIFY with no body\n", DEB_F_PREFIX_ARGS(SIP_NOTIFY, fname));
+ if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ SIP_WARN_MISC,
+ SIP_CLI_ERR_BAD_REQ_NO_BODY,
+ NULL) != TRUE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
+ fname, SIP_CLI_ERR_BAD_REQ);
+ }
+ return NULL;
+ }
+ if (pSipMessage->mesg_body[0].msgContentTypeValue != SIP_CONTENT_TYPE_TEXT_PLAIN_VALUE) {
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Received NOTIFY with unknown body type\n",
+ DEB_F_PREFIX_ARGS(SIP_NOTIFY, fname));
+ if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ SIP_WARN_MISC,
+ SIP_CLI_ERR_BAD_REQ_BAD_BODY_ENCODING,
+ NULL) != TRUE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
+ fname, SIP_CLI_ERR_BAD_REQ);
+ }
+ return NULL;
+ }
+ // Parse the body
+ scp = sippmh_parse_service_control_body(pSipMessage->mesg_body[0].msgBody,
+ pSipMessage->mesg_body[0].msgLength);
+
+ if (scp == NULL) {
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Received NOTIFY but couldn't parse body\n",
+ DEB_F_PREFIX_ARGS(SIP_NOTIFY, fname));
+ if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ SIP_WARN_MISC,
+ SIP_CLI_ERR_BAD_REQ_BAD_BODY_ENCODING,
+ NULL) != TRUE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
+ fname, SIP_CLI_ERR_BAD_REQ);
+ }
+ return NULL;
+ }
+ // Verify common mandatory parms
+ if (scp->registerCallID == NULL) {
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Received NOTIFY but no mandatory params\n",
+ DEB_F_PREFIX_ARGS(SIP_NOTIFY, fname));
+ if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ 0, NULL, NULL) != TRUE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
+ fname, SIP_CLI_ERR_BAD_REQ);
+ }
+ sippmh_free_service_control_info(scp);
+ return NULL;
+ }
+
+
+ if (scp->action == SERVICE_CONTROL_ACTION_CHECK_VERSION) {
+ // make sure they gave us all the version stamps
+ boolean all_provided;
+
+ all_provided = ((scp->configVersionStamp != NULL) &&
+ (scp->dialplanVersionStamp != NULL) &&
+ (scp->softkeyVersionStamp != NULL)) ? TRUE : FALSE;
+ if (!all_provided) {
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Received NOTIFY but no mandatory params\n",
+ DEB_F_PREFIX_ARGS(SIP_NOTIFY, fname));
+ if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ 0, NULL, NULL) != TRUE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
+ fname, SIP_CLI_ERR_BAD_REQ);
+ }
+ sippmh_free_service_control_info(scp);
+ return NULL;
+ }
+ }
+
+ if (scp->action == SERVICE_CONTROL_ACTION_APPLY_CONFIG) {
+ // make sure they gave us all the mandatory parameters
+ boolean all_provided;
+
+ /*
+ * following condition checks that all mandatory filed are present.
+ * firmwareInactiveLoadId is not mandatory field because of backward
+ * compatibility purposes. So, it is not included in the following
+ * check.
+ */
+ all_provided = ((scp->configVersionStamp != NULL) &&
+ (scp->dialplanVersionStamp != NULL) &&
+ (scp->softkeyVersionStamp != NULL) &&
+ (scp->cucm_result != NULL) &&
+ (scp->firmwareLoadId != NULL) &&
+ (scp->loadServer != NULL) &&
+ (scp->logServer != NULL)) ? TRUE : FALSE;
+ if (!all_provided)
+ {
+ CCSIP_DEBUG_TASK(SIP_F_PREFIX "Incorrect message format or missing "
+ "param value for [configVer/cucmResult] in"
+ " apply-config NOTIFY\n\n"
+ "configVersionStamp=%s \ndialplanVersionStamp=%s"
+ "\nsoftkeyVersionStamp=%s \ncucmResult=%s "
+ "\nloadId=%s \ninactiveLoadId=%s \nloadServer=%s \nlogServer=%s "
+ "\nppid=%s\n\n", fname,
+ (scp->configVersionStamp != NULL) ? scp->configVersionStamp
+ : "",
+ (scp->dialplanVersionStamp != NULL) ?
+ scp->dialplanVersionStamp:"",
+ (scp->softkeyVersionStamp != NULL) ?
+ scp->softkeyVersionStamp : "",
+ scp->cucm_result != NULL ? scp->cucm_result : "",
+ (scp->firmwareLoadId != NULL) ? scp->firmwareLoadId : "",
+ (scp->firmwareInactiveLoadId != NULL) ? scp->firmwareInactiveLoadId : "",
+ (scp->loadServer != NULL) ? scp->loadServer : "",
+ (scp->logServer != NULL) ? scp->logServer : "",
+ scp->ppid == TRUE? "True": "False");
+
+ if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ 0, NULL, NULL) != TRUE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
+ fname, SIP_CLI_ERR_BAD_REQ);
+ }
+ sippmh_free_service_control_info(scp);
+ return NULL;
+ }
+ /*
+ * Now if firmwareInactiveLoadId is null, then allocate empty string to
+ * it so that an empty string can be passed on to java side.
+ */
+ if (scp->firmwareInactiveLoadId == NULL) {
+ scp->firmwareInactiveLoadId = cpr_calloc(1, 2);
+ }
+ }
+
+
+ // Take action
+ // Compare the reg call id received with call-id that we sent out
+ for (i = REG_CCB_START; i <= TEL_CCB_END + 1; i++) {
+ ccb = sip_sm_get_ccb_by_index(i);
+ if (ccb) {
+ if (strcmp(scp->registerCallID, ccb->sipCallID) == 0) {
+ param_match = TRUE;
+ break;
+ }
+ }
+ }
+
+ // Call Platform API for actually performing the called for action
+ if (param_match && ccb != NULL) {
+ if (sip_regmgr_get_cc_mode(ccb->dn_line) != REG_MODE_CCM) {
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Received NOTIFY in non CCM mode\n",
+ DEB_F_PREFIX_ARGS(SIP_NOTIFY, fname));
+ if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ 0, NULL, NULL) != TRUE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
+ fname, SIP_CLI_ERR_BAD_REQ);
+ }
+ sippmh_free_service_control_info(scp);
+ return NULL;
+ }
+ } else {
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Received NOTIFY, callid doesn't match\n",
+ DEB_F_PREFIX_ARGS(SIP_NOTIFY, fname));
+ if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ 0, NULL, NULL) != TRUE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
+ fname, SIP_CLI_ERR_BAD_REQ);
+ }
+ sippmh_free_service_control_info(scp);
+ return NULL;
+ }
+
+ /* NOTIFY message validated and scp allocated */
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Received NOTIFY, callid matches\n",
+ DEB_F_PREFIX_ARGS(SIP_NOTIFY, fname));
+ return scp;
+}
+
+void
+ccsip_handle_unsolicited_notify (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ const char *fname = "ccsip_handle_unsolicited_notify";
+ sipMessage_t *request;
+ sipServiceControl_t *scp;
+
+ /* Unpack the event */
+ request = event->u.pSipMessage;
+
+ scp = ccsip_get_notify_service_control(request);
+ if (scp != NULL) {
+ if (scp->action == SERVICE_CONTROL_ACTION_CALL_PRESERVATION) {
+ if (ccb->state == SIP_STATE_ACTIVE) {
+ sip_cc_feature(ccb->gsm_id, ccb->dn_line, CC_FEATURE_CALL_PRESERVATION, NULL);
+ } else {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"SIP state %s ignoring call preservation request\n",
+ fname, sip_util_state2string(ccb->state));
+ }
+ if (sipSPISendErrorResponse(request, 200, SIP_SUCCESS_SETUP_PHRASE,
+ 0, NULL, NULL) != TRUE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
+ fname, SIP_SUCCESS_SETUP);
+
+
+ }
+ } else {
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Unsupported unsolicited notify event\n",
+ DEB_F_PREFIX_ARGS(SIP_NOTIFY, fname));
+ if (sipSPISendErrorResponse(request, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ 0, NULL, NULL) != TRUE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
+ fname, SIP_CLI_ERR_BAD_REQ);
+ }
+ }
+ sippmh_free_service_control_info(scp);
+ }
+}
+
+
+
+/**
+ * This function frees a duped CCB.
+ *
+ * @param dup_ccb The duplicate CCB to free
+ */
+void free_duped (ccsipCCB_t *dup_ccb)
+{
+
+}
+
+/**
+ * This function dups the origCCB and returns a new ccb. It applies
+ * to only TEL CCBs. The contents of the new CCB is determined by dupCCBFlags.
+ *
+ * dupCCBFlag values are:
+ * DUPED_CCB 0x01
+ * DUP_CCB_NEW_CALLID 0x02
+ * DUP_CCB_INIT_STATE 0x04
+ * DUP_CCB_REINIT_DNS 0x08
+ * DUP_CCB_STOLEN_FEAT_DATA 0x10
+ * if this flag is set and ccb->feature_data is NULL, then
+ * feature data was stolen from this ccb.
+ *
+ * if this flag is set and ccb->feature_data is non-NULL, then
+ * this ccb stole the feature_data pointer from the mother_ccb.
+ *
+ * The concept of duping is to maximize sharing of
+ * data structures by pointer sharing where it makes sense.
+ * The companion function of freeDupedCCB() is aware that
+ * of the duping. ccb->dup_flags will remember the duping
+ * attributes (flags shown above) and will free members
+ * appropriately.
+ *
+ * @param origCCB
+ * @param dup_flags
+ *
+ * @return duplicated CCB or NULL
+ */
+ccsipCCB_t *
+create_dupCCB (ccsipCCB_t *origCCB, int dup_flags)
+{
+ ccsipCCB_t *dupCCB;
+ line_t child_line;
+ const char *fname = "dupCCB()";
+ const char *outOfDialogPrefix = "OutOfDialog--";
+
+ dupCCB = sip_sm_get_ccb_next_available(&child_line); //need to check for failure
+
+ if (dupCCB == NULL) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"sip_sm_get_ccb_next_available()"
+ " returned null.\n", fname);
+ return NULL;
+ }
+
+ dupCCB->dup_flags = dup_flags|DUP_CCB;
+ dupCCB->mother_ccb = (void *)origCCB;
+
+ dupCCB->flags = origCCB->flags;
+ sstrncpy(dupCCB->sipCallID, origCCB->sipCallID, MAX_SIP_CALL_ID);
+ dupCCB->gsm_id = origCCB->gsm_id;
+ dupCCB->con_call_id = origCCB->con_call_id;
+ dupCCB->blind_xfer_call_id = origCCB->blind_xfer_call_id;
+
+ dupCCB->state = origCCB->state;
+ dupCCB->index = origCCB->index;
+ dupCCB->dn_line = origCCB->dn_line;
+ dupCCB->retx_counter = 0;
+ dupCCB->type = origCCB->type;
+
+ dupCCB->proxySelection = origCCB->proxySelection;
+ dupCCB->outBoundProxyAddr = origCCB->outBoundProxyAddr;
+ dupCCB->outBoundProxyPort = origCCB->outBoundProxyPort;
+
+ if (!(dup_flags & DUP_CCB_REINIT_DNS)) {
+ dupCCB->SRVhandle = NULL;
+ dupCCB->ObpSRVhandle = NULL;
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX"Reiniting DNS fields in duped ccb\n",
+ DEB_F_PREFIX_ARGS(SIP_CALL_STATUS, fname));
+ } else {
+ //TBD
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX"Not reiniting DNS fields in duped ccb\n",
+ DEB_F_PREFIX_ARGS(SIP_CALL_STATUS, fname));
+ }
+
+ dupCCB->routeMode = origCCB->routeMode;
+ dupCCB->udpId = origCCB->udpId;
+
+ dupCCB->contact_info = NULL;
+
+ if (dup_flags & DUP_CCB_NEW_CALLID) {
+ dupCCB->record_route_info = NULL;
+ dupCCB->sipCallID[0] = '\0';
+ sip_util_get_new_call_id(dupCCB);
+ sstrncpy(dupCCB->sipCallID, outOfDialogPrefix,
+ sizeof(dupCCB->sipCallID));
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX"Using new Call-ID for OutofDialog ccb\n",
+ DEB_F_PREFIX_ARGS(SIP_CALL_STATUS, fname));
+ } else {
+ dupCCB->record_route_info =
+ sippmh_copy_record_route(origCCB->record_route_info);
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX"Copied mother CCB's route set.\n",
+ DEB_F_PREFIX_ARGS(SIP_CALL_STATUS, fname));
+ }
+
+ dupCCB->calledDisplayedName = strlib_update(dupCCB->calledDisplayedName,
+ origCCB->calledDisplayedName);
+ dupCCB->callingNumber = strlib_update(dupCCB->callingNumber,
+ origCCB->callingNumber);
+ dupCCB->callingDisplayName = strlib_update(dupCCB->callingDisplayName,
+ origCCB->callingDisplayName);
+ dupCCB->calledNumber = strlib_update(dupCCB->calledNumber,
+ origCCB->calledNumber);
+ dupCCB->calledNumberLen = origCCB->calledNumberLen;
+ dupCCB->calledNumberFirstDigitDialed = origCCB->calledNumberFirstDigitDialed;
+
+ dupCCB->src_addr = origCCB->src_addr;
+ dupCCB->dest_sip_addr = origCCB->dest_sip_addr;
+ dupCCB->local_port = origCCB->local_port;
+ dupCCB->dest_sip_port = origCCB->dest_sip_port;
+ //int16_t sip_socket_handle; NOT USED ANYWHERE!
+
+
+ /*
+ * Headers
+ */
+ sstrncpy(dupCCB->ReqURI, origCCB->ReqURI, sizeof(dupCCB->ReqURI));
+ dupCCB->ReqURIOriginal = strlib_update(dupCCB->ReqURIOriginal,
+ origCCB->ReqURIOriginal);
+
+ dupCCB->sip_to = strlib_update(dupCCB->sip_to, origCCB->sip_to);
+ if (dup_flags & DUP_CCB_NEW_CALLID) {
+ char *str, *str2;
+ str = strlib_open(dupCCB->sip_to, 0);
+
+ if (str == NULL) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"strlib_open returned NULL while trying"
+ " to process To.", fname);
+ return NULL;
+ }
+
+ str2 = strstr(str,";tag");
+ if (str2 != NULL) {
+ *str2 = '\0';
+ }
+ dupCCB->sip_to = strlib_close(str);
+ }
+
+ dupCCB->sip_from = strlib_update(dupCCB->sip_from, origCCB->sip_from);
+ if (dup_flags & DUP_CCB_NEW_CALLID) {
+ char *str, *str2;
+ str = strlib_open(dupCCB->sip_from, 0);
+
+ if (str == NULL) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"strlib_open returned NULL while trying"
+ " to process From.", fname);
+ return NULL;
+ }
+
+ str2 = strstr(str,";tag");
+ if (str2 != NULL) {
+ *str2 = '\0';
+ }
+ dupCCB->sip_from = strlib_close(str);
+ }
+
+ {
+ char tag[MAX_SIP_URL_LENGTH];
+ sip_util_make_tag(tag);
+
+ if (dupCCB->flags & INCOMING) {
+ dupCCB->sip_to = strlib_append(dupCCB->sip_to, ";tag=");
+ dupCCB->sip_to = strlib_append(dupCCB->sip_to, tag);
+ dupCCB->sip_to_tag = strlib_update(dupCCB->sip_to_tag, tag);
+ } else {
+ dupCCB->sip_from = strlib_append(dupCCB->sip_from, ";tag=");
+ dupCCB->sip_from = strlib_append(dupCCB->sip_from, tag);
+ dupCCB->sip_from_tag = strlib_update(dupCCB->sip_from_tag, tag);
+ }
+ }
+
+ dupCCB->sip_contact = strlib_update(dupCCB->sip_contact,
+ origCCB->sip_contact);
+
+ dupCCB->featuretype = origCCB->featuretype;
+
+ if (dup_flags & DUP_CCB_STOLEN_FEAT_DATA) {
+ dupCCB->feature_data = origCCB->feature_data;
+ dupCCB->dup_flags |= DUP_CCB_STOLEN_FEAT_DATA;
+ origCCB->feature_data = NULL;
+ origCCB->dup_flags |= DUP_CCB_STOLEN_FEAT_DATA;
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX"Stealing feature_data pointer from mother ccb\n",
+ DEB_F_PREFIX_ARGS(SIP_CALL_STATUS, fname));
+ }
+
+ return dupCCB;
+}
+
+void
+ccsip_handle_sent_ood_refer_ev_sip_1xx (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ const char *fname = "ccsip_handle_sent_ood_refer_ev_sip_1xx";
+
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_FUNCTION_ENTRY),
+ ccb->index, ccb->dn_line, fname,
+ sip_util_state2string(ccb->state),
+ sip_util_event2string(event->type));
+
+ ccsip_handle_sentinvite_ev_sip_1xx(ccb, event);
+}
+
+void
+ccsip_handle_sent_ood_refer_ev_sip_2xx (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ const char *fname = "ccsip_handle_sent_ood_refer_ev_sip_2xx";
+
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_FUNCTION_ENTRY),
+ ccb->index, ccb->dn_line, fname,
+ sip_util_state2string(ccb->state),
+ sip_util_event2string(event->type));
+
+ ccsip_handle_accept_2xx(ccb, event);
+ sip_sm_call_cleanup(ccb);
+}
+
+void
+ccsip_handle_sent_ood_refer_ev_sip_fxx (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ const char *fname = "ccsip_handle_sent_ood_refer_ev_sip_fxx";
+ sipMessage_t *response;
+ sipRespLine_t *respLine = NULL;
+ uint16_t status_code = 0;
+ sipMethod_t method = sipMethodInvalid;
+
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_FUNCTION_ENTRY),
+ ccb->index, ccb->dn_line, fname,
+ sip_util_state2string(ccb->state),
+ sip_util_event2string(event->type));
+
+ response = event->u.pSipMessage;
+
+ if (sipGetResponseMethod(response, &method) < 0) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sipGetResponseMethod");
+ free_sip_message(response);
+ return;
+ }
+
+ /* Get the status code */
+ respLine = sippmh_get_response_line(response);
+ if (respLine) {
+ status_code = respLine->status_code;
+ //status_code = 408;
+ SIPPMH_FREE_RESPONSE_LINE(respLine);
+ }
+
+ ccsip_handle_sentinvite_ev_sip_fxx(ccb, event);
+
+ if ((status_code != SIP_CLI_ERR_UNAUTH) &&
+ (status_code != SIP_CLI_ERR_PROXY_REQD)) {
+ sip_sm_call_cleanup(ccb);
+ }
+}
+
+void
+ccsip_handle_ev_cc_info (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ sipSPISendInfo(ccb,
+ (const char *)event->u.cc_msg->msg.info.info_package,
+ (const char *)event->u.cc_msg->msg.info.content_type,
+ (const char *)event->u.cc_msg->msg.info.message_body);
+}
+
+/*
+ * Function: ccsip_set_replace_info
+ *
+ * Parameters:
+ * ccb - pointer to ccsipCCB_t.
+ * setup - pointer to the cc_setup_t for the cc setup msg. that
+ * contains "replace" flag.
+ *
+ * Description:
+ * The ccsip_set_replace_info populates the information in the CCB
+ * for replace information of the INVITE to send out. The function
+ * may derives certain information from the remote dialog, etc.
+ *
+ * Returns:
+ * TRUE - when successfully set replace information.
+ * FALSE - when fail to set replace information.
+ */
+static boolean
+ccsip_set_replace_info (ccsipCCB_t *ccb, cc_setup_t * setup)
+{
+ cc_call_info_t *call_info = &setup->call_info;
+
+ if (call_info->type != CC_FEAT_REPLACE) {
+ /* The call info does not contain the replace information */
+ return (FALSE);
+ }
+
+ if (call_info->data.replace.remote_call_id != CC_NO_CALL_ID) {
+ /* This is a replacement of the remote dialog */
+ strlib_free(ccb->sipxfercallid);
+ ccb->sipxfercallid = strlib_empty();
+ }
+ return (FALSE);
+}
+
+/*
+ * Function: ccsip_handle_cc_select_event
+ *
+ * Parameters:
+ * sip_sm_event - Pointer to sipSMEvent_t
+ *
+ * Description:
+ * The ccsip_handle_cc_select_event checks for CC_FEATURE_SELECT and
+ * handled the request.
+ *
+ * Returns:
+ * TRUE - CC_FEATURE select has been handled.
+ * FALSE - CC_FEATURE select has not been handled.
+ */
+static boolean
+ccsip_handle_cc_select_event (sipSMEvent_t *sip_sm_event)
+{
+ cc_feature_t *msg;
+
+ // currently not used: line_t line_number = 0;
+
+ msg = &(sip_sm_event->u.cc_msg->msg.feature);
+ if (!((msg->msg_id == CC_MSG_FEATURE) &&
+ (msg->feature_id == CC_FEATURE_SELECT))) {
+ /* Some other feature or msg. */
+ return (FALSE);
+ }
+
+ return FALSE;
+}
+
+/*
+ * Function: ccsip_handle_cc_b2bjoin_event
+ *
+ * Parameters:
+ * sip_sm_event - Pointer to sipSMEvent_t
+ *
+ * Description:
+ * The ccsip_handle_cc_b2bjoin_event checks for CC_FEATURE_B2BJOIN and
+ * handled the request.
+ *
+ * Returns:
+ * TRUE - CC_FEATURE select has been handled.
+ * FALSE - CC_FEATURE select has not been handled.
+ */
+static boolean
+ccsip_handle_cc_b2bjoin_event (sipSMEvent_t *sip_sm_event)
+{
+ cc_feature_t *msg;
+
+ // currently not used: line_t line_number = 0;
+
+ msg = &(sip_sm_event->u.cc_msg->msg.feature);
+ if (!((msg->msg_id == CC_MSG_FEATURE) &&
+ (msg->feature_id == CC_FEATURE_B2B_JOIN))) {
+ /* Some other feature or msg. */
+ return (FALSE);
+ }
+
+ return FALSE;
+}
+
+/*
+ * Function: ccsip_set_join_info
+ *
+ * Parameters:
+ * ccb - pointer to ccsipCCB_t.
+ * setup - pointer to the cc_setup_t for the cc setup msg.
+ *
+ * Description:
+ * The ccsip_set_join_info populates the information in the CCB
+ * for join header to be sent out in the INVITE. The function
+ * may derives certain information from the remote dialog, etc.
+ *
+ * Returns:
+ * None.
+ */
+static void
+ccsip_set_join_info (ccsipCCB_t *ccb, cc_setup_t * setup)
+{
+ const char *fname = "ccsip_set_join_info";
+ cc_call_info_t *call_info = &setup->call_info;
+
+ if (((call_info->type != CC_FEAT_BARGE) &&
+ (call_info->type != CC_FEAT_CBARGE)) ||
+ (call_info->data.join.join_call_id == CC_NO_CALL_ID)) {
+ /* The call info does not contain any barge information */
+ return;
+ }
+
+ ccb->join_info = (sipJoinInfo_t *) cpr_calloc(1, sizeof(sipJoinInfo_t));
+
+ if (!ccb->join_info) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ ccb->index, ccb->dn_line, fname, "malloc(join_info)");
+ return;
+ }
+}
+
+/*
+ * Function: ccsip_get_join_info
+ *
+ * Parameters:
+ * ccb - pointer to ccsipCCB_t.
+ * request - pointer to the sipMessage_t for the sip msg.
+ *
+ * Description:
+ * The ccsip_get_join_info parses the join header, finds the
+ * the call specified by the call id, matches the from/to tag and
+ * makes sure that this call is in active state. Then, it finds the
+ * gsm of the join target call id and populates the call info with that
+ *
+ * Returns:
+ * TRUE - join hdr is good.
+ * FALSE - join hdr is not good.
+ */
+static boolean
+ccsip_get_join_info (ccsipCCB_t *ccb, sipMessage_t *request)
+{
+ const char *fname = "ccsip_get_join_info";
+ const char *joinhdr = NULL;
+
+ /* Parse Join header */
+ joinhdr = sippmh_get_header_val(request, SIP_HEADER_JOIN, NULL);
+ if (joinhdr) {
+
+ ccsipCCB_t *join_ccb = NULL;
+
+ // From-tag and To-tag check to match an active call
+ int ff_check = 0;
+ int ft_check = 0;
+ int tf_check = 0;
+ int tt_check = 0;
+
+ // currently not used: boolean joinhdr_not_valid = FALSE;
+
+ if (ccb->join_info) {
+ sippmh_free_join_info(ccb->join_info);
+ }
+ ccb->join_info = sippmh_parse_join_header(joinhdr);
+
+ if (ccb->join_info) {
+ join_ccb = sip_sm_get_ccb_by_callid(ccb->join_info->call_id);
+ }
+ if (join_ccb == NULL) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ 0, 0, fname,
+ "Attempted Join call does not exist");
+ return (FALSE);
+ }
+
+ if (!ccb->in_call_info) {
+ ccb->in_call_info = (cc_call_info_t *)
+ cpr_calloc(1, sizeof(cc_call_info_t));
+ }
+ if (!ccb->in_call_info) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ ccb->index, ccb->dn_line, fname,
+ "malloc(call_info)");
+ return (FALSE);
+ }
+
+ ccb->in_call_info->type = CC_FEAT_MONITOR;
+
+ if (join_ccb->state != SIP_STATE_ACTIVE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ join_ccb->index,
+ join_ccb->dn_line, fname,
+ "Attempted Join call is not active or held, but OK to continue.");
+ /* return (FALSE); CSCtd11077 */
+ /* OK to continue to send CC_MSG_SETUP because DCSM will hold CC_FEATURE_JOIN until */
+ /* DEF is in the CONNECTED state to process the JOIN msg. */
+ }
+
+ ff_check = cpr_strcasecmp(join_ccb->sip_from_tag, ccb->join_info->from_tag);
+ ft_check = cpr_strcasecmp(join_ccb->sip_from_tag, ccb->join_info->to_tag);
+ tt_check = cpr_strcasecmp(join_ccb->sip_to_tag, ccb->join_info->to_tag);
+ tf_check = cpr_strcasecmp(join_ccb->sip_to_tag, ccb->join_info->from_tag);
+
+ // In this issue, the correct match is to match F/F and T/T, or to match F/T and T/F.
+ // All other cases are error.
+ // So, (ff_check==0 && tt_check==0) || (ft_check==0 && tf_check==0) is the correct match
+ // thus, !( (ff_check==0 && tt_check==0) || (ft_check==0 && tf_check==0) ) represents all other cases.
+ if ( !( (ff_check==0 && tt_check==0) || (ft_check==0 && tf_check==0) ) ) {
+ CCSIP_DEBUG_ERROR(
+ get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ join_ccb->index,
+ join_ccb->dn_line, fname,
+ "Join Header's From/To tag does not match any ccb's From/To tag");
+ return (FALSE);
+ }
+ ccb->in_call_info->data.join.join_call_id = join_ccb->gsm_id;
+ }
+ return (TRUE);
+}
+
+/**
+ *
+ * Returns SIP call ID that is pre-allocated during off hook.
+ *
+ * @param dn_line - line_t of the line that is goes off hook.
+ *
+ * @return pointer to character string of the SIP call ID.
+ *
+ * @pre none
+ */
+char *
+getPreallocatedSipCallID (line_t dn_line)
+{
+ static const char *fname = "getPreallocatedSipCallID";
+ uint8_t mac_address[MAC_ADDRESS_LENGTH];
+ char pSrcAddrStr[MAX_IPADDR_STR_LEN];
+ cpr_ip_addr_t src_addr;
+ int nat_enable = 0;
+
+ CPR_IP_ADDR_INIT(src_addr);
+
+ if ((dn_line > MAX_REG_LINES) && (dn_line < 1)){
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"dn_line=%d is greater than %d or less than 1",
+ fname, dn_line, MAX_REG_LINES);
+ return NULL;
+ }
+ /*
+ * if one is already created, use it.
+ */
+ if (preAllocatedSipCallID[dn_line - 1] != NULL) {
+ return (preAllocatedSipCallID[dn_line - 1]);
+ }
+ config_get_value(CFGID_NAT_ENABLE, &nat_enable, sizeof(nat_enable));
+ if (nat_enable == 0) {
+ sip_config_get_net_device_ipaddr(&src_addr);
+ } else {
+ sip_config_get_nat_ipaddr(&src_addr);
+ }
+
+ platform_get_wired_mac_address(mac_address);
+ ipaddr2dotted(pSrcAddrStr, &src_addr);
+
+ preAllocatedSipCallID[dn_line - 1] = (char *) cpr_malloc(MAX_SIP_CALL_ID);
+
+ if (preAllocatedSipCallID[dn_line - 1] != NULL) {
+ sip_create_new_sip_call_id(preAllocatedSipCallID[dn_line - 1],
+ mac_address, pSrcAddrStr);
+ } else {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"malloc failed", fname);
+ }
+
+ return (preAllocatedSipCallID[dn_line - 1]);
+}
+
+/**
+ *
+ * Returns preallocate local SIP tag.
+ *
+ * @param dn_line - line_t of the line that is goes off hook.
+ *
+ * @return pointer to character string of the tag.
+ *
+ * @pre none
+ */
+char *
+getPreallocatedSipLocalTag (line_t dn_line)
+{
+ static const char *fname = "getPreallocatedSipLocalTag";
+
+ if ((dn_line > MAX_REG_LINES) || (dn_line < 1)) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"dn_line=%d. The valid range is 1 to %d\n",
+ fname, dn_line, MAX_REG_LINES);
+ return NULL;
+ }
+ if (preAllocatedTag[dn_line - 1] == NULL) {
+ preAllocatedTag[dn_line - 1] = (char *) cpr_malloc(MAX_SIP_TAG_LENGTH);
+ if (preAllocatedTag[dn_line - 1] == NULL) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"malloc failed\n", fname);
+ } else {
+ sip_util_make_tag(preAllocatedTag[dn_line - 1]);
+ }
+ }
+
+ return (preAllocatedTag[dn_line - 1]);
+}
+
+/**
+ *
+ * Returns the pre-allocated local TAG based on a given dn line number.
+ *
+ * @param dn_line - line_t of the line that is goes off hook.
+ *
+ * @return pointer to character string of the tag.
+ *
+ * @pre none
+ */
+char *
+ccsip_find_preallocated_sip_local_tag (line_t dn_line)
+{
+ static const char *fname = "ccsip_find_preallocated_sip_local_tag";
+
+ if ((dn_line > MAX_REG_LINES) || (dn_line < 1)) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"dn_line=%d. The valid range is 1 to %d\n",
+ fname, dn_line, MAX_REG_LINES);
+ return NULL;
+ }
+
+ return (preAllocatedTag[dn_line - 1]);
+}
+
+/**
+ *
+ * Frees pre-allocated local tag that.
+ *
+ * @param dn_line - line_t of the line that is goes off hook.
+ *
+ * @return none
+ *
+ * @pre none
+ */
+void
+ccsip_free_preallocated_sip_local_tag (line_t dn_line)
+{
+ static const char *fname = "ccsip_free_preallocated_sip_local_tag";
+
+ if ((dn_line > MAX_REG_LINES) || (dn_line < 1)) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"dn_line=%d. The valid range is 1 to %d\n",
+ fname, dn_line, MAX_REG_LINES);
+ return;
+ }
+
+ cpr_free(preAllocatedTag[dn_line - 1]);
+ preAllocatedTag[dn_line - 1] = NULL;
+}
+
+/**
+ *
+ * Returns the SIP Call ID based on the dn line number given.
+ *
+ * @param dn_line - line_t of the line that is goes off hook.
+ *
+ * @return pointer to character string of the tag.
+ *
+ * @pre none
+ */
+static char *
+ccsip_find_preallocated_sip_call_id (line_t dn_line)
+{
+ static const char *fname = "ccsip_find_preallocated_sip_call_id";
+
+ if ((dn_line > MAX_REG_LINES) && (dn_line < 1)) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"dn_line=%d is greater than %d or less than 1\n",
+ fname, dn_line, MAX_REG_LINES);
+ return NULL;
+ }
+ return (preAllocatedSipCallID[dn_line - 1]);
+}
+
+/**
+ *
+ * Frees the SIP Call ID based on the dn line number given.
+ *
+ * @param dn_line - line_t of the line that is goes off hook.
+ *
+ * @return none
+ *
+ * @pre none
+ */
+static void
+ccsip_free_preallocated_sip_call_id (line_t dn_line)
+{
+ static const char *fname = "ccsip_free_preallocated_sip_call_id";
+
+ if ((dn_line > MAX_REG_LINES) && (dn_line < 1)) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"dn_line=%d is greater than %d or less than 1\n",
+ fname, dn_line, MAX_REG_LINES);
+ return;
+ }
+ cpr_free(preAllocatedSipCallID[dn_line - 1]);
+ preAllocatedSipCallID[dn_line - 1] = NULL;
+}
+
+/*
+ * Function: ccsip_handle_cc_hook_event
+ *
+ * Parameters:
+ * sip_sm_event - Pointer to sipSMEvent_t
+ *
+ * Description:
+ * The ccsip_handle_cc_hook_event checks for
+ * CC_MSG_OFFHOOK/CC_MSG_ONHOOK and handles the request.
+ *
+ * Returns:
+ * TRUE - if it is hook event.
+ * FALSE - if it is not hook event.
+ */
+static boolean
+ccsip_handle_cc_hook_event (sipSMEvent_t *sip_sm_event)
+{
+ static const char *fname = "ccsip_handle_cc_hook_event";
+ line_t line_number = 0;
+ char *sip_call_id = NULL;
+ char *sip_local_tag;
+ cc_msg_t *pCCMsg;
+ ccsipCCB_t *ccb;
+ cc_msgs_t event;
+
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Entering with event %d", DEB_F_PREFIX_ARGS(SIP_EVT, fname),
+ sip_sm_event->u.cc_msg->msg.setup.msg_id);
+
+ pCCMsg = sip_sm_event->u.cc_msg;
+ event = pCCMsg->msg.setup.msg_id;
+
+ if ((event != CC_MSG_OFFHOOK) && (event != CC_MSG_ONHOOK)) {
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Exiting because event is not hook state\n",
+ DEB_F_PREFIX_ARGS(SIP_EVT, fname));
+ return FALSE;
+ }
+
+ if (event == CC_MSG_OFFHOOK) {
+ line_number = pCCMsg->msg.offhook.line;
+ } else {
+ line_number = pCCMsg->msg.onhook.line;
+ }
+ if (sip_regmgr_get_cc_mode(line_number) != REG_MODE_CCM) {
+ /* this is not CCM environment */
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Exiting Not CCM mode\n",
+ DEB_F_PREFIX_ARGS(SIP_CALL_STATUS, fname));
+ return TRUE;
+ }
+
+ /*
+ * Allocate SIP Call-ID and local tag, if they are not already allocated.
+ */
+ if (event == CC_MSG_OFFHOOK) {
+ ccb = sip_sm_get_ccb_by_gsm_id(pCCMsg->msg.offhook.call_id);
+ line_number = pCCMsg->msg.offhook.line;
+ } else {
+ ccb = sip_sm_get_ccb_by_gsm_id(pCCMsg->msg.onhook.call_id);
+ line_number = pCCMsg->msg.onhook.line;
+ }
+ if (ccb == NULL) {
+ /*
+ * No CCB. So user must be just trying to make a call.
+ * We will pre allocate SIP Call-ID and local tag for the potential
+ * dialog initiated by INVITE. These values are needed for sending
+ * hook event notification.
+ */
+ sip_call_id = getPreallocatedSipCallID(line_number);
+ sip_local_tag = getPreallocatedSipLocalTag(line_number);
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"preallocated callid: %s & local-tag: %s\n",
+ DEB_F_PREFIX_ARGS(SIP_CALL_STATUS, fname), sip_call_id, sip_local_tag);
+ } else {
+ sip_call_id = ccb->sipCallID;
+ sip_local_tag = (char *) (ccb->sip_from_tag);
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"callid: %s & local-tag: %s\n",
+ DEB_F_PREFIX_ARGS(SIP_CALL_STATUS, fname), sip_call_id, sip_local_tag);
+ }
+
+ /*
+ * if CCB is NULL and we are sending ONKOOK notification,
+ * free up the preallocated call-id and local-tag.
+ */
+ if ((ccb == NULL) && (event == CC_MSG_ONHOOK)) {
+ ccsip_free_preallocated_sip_call_id(line_number);
+ ccsip_free_preallocated_sip_local_tag(line_number);
+ }
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Exiting after sending hook state "
+ "notification\n",
+ DEB_F_PREFIX_ARGS(SIP_CALL_STATUS, fname));
+ return TRUE;
+}
diff --git a/libs/sipcc/core/sipstack/ccsip_debug.c b/libs/sipcc/core/sipstack/ccsip_debug.c
new file mode 100644
index 0000000000..b7d571e4f7
--- /dev/null
+++ b/libs/sipcc/core/sipstack/ccsip_debug.c
@@ -0,0 +1,392 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "debug.h"
+#include "phone_debug.h"
+#include "ccsip_publish.h"
+#include "util_string.h"
+#include "sip_interface_regmgr.h"
+
+extern boolean dump_reg_msg;
+
+/* SIP flags */
+cc_int32_t SipDebugMessage = 1; /* SIP messaging output */
+cc_int32_t SipDebugState = 0; /* SIP State Machine output */
+cc_int32_t SipDebugTask = 1; /* SIP Task output */
+cc_int32_t SipDebugRegState = 0; /* SIP Registration State Mach. output */
+
+/**
+ * SipRelDevEnabled flag is not a debug print flag. It actually turns
+ * on and off reliable delivery module in sip layer. We will keep
+ * this on as retransmissions are enabled on CUCM by default even for TCP transport
+ */
+int32_t SipRelDevEnabled = 1; /* Is reliable delivery on? */
+
+int32_t SipDebugGenContactHeader = 0; /* Generate Contact header */
+cc_int32_t SipDebugTrx = 0; /* SIP Transaction Layer output */
+
+cc_int32_t GSMDebug = 0;
+cc_int32_t FIMDebug = 0;
+cc_int32_t LSMDebug = 0;
+cc_int32_t FSMDebugSM = 0;
+int32_t CSMDebugSM = 0;
+cc_int32_t CCDebug = 0;
+cc_int32_t CCDebugMsg = 0;
+cc_int32_t AuthDebug = 0;
+cc_int32_t g_DEFDebug = 1;
+cc_int32_t TNPDebug = 1;
+cc_int32_t VCMDebug = 0;
+cc_int32_t CCEVENTDebug = 0;
+cc_int32_t PLATDebug = 0;
+cc_int32_t TMRDebug = 0;
+cc_int32_t g_dcsmDebug = 0;
+
+/**
+ *
+ * Dump sip messages
+ *
+ * @param msg - message buffer
+ * pSIPMessage - parsed message structure
+ * cc_remote_ipaddr - remote ip address
+ * cc_remote_port - remote port number
+ *
+ * @return none
+ *
+ * @pre (valid pSIPMessage AND
+ * valid cc_remote_ipaddr)
+ */
+
+void ccsip_dump_send_msg_info (char *msg, sipMessage_t *pSIPMessage,
+ cpr_ip_addr_t *cc_remote_ipaddr,
+ uint16_t cc_remote_port)
+{
+ char *disp_buf;
+ const char *req_uri;
+ const char *cseq;
+ const char *callid;
+ char ipaddr_str[MAX_IPADDR_STR_LEN];
+ static const char fname[] = "ccsip_dump_send_msg_info";
+
+ ipaddr2dotted(ipaddr_str, cc_remote_ipaddr);
+
+ req_uri = sippmh_get_header_val(pSIPMessage, SIP_HEADER_TO, NULL);
+ if (req_uri == NULL) {
+ /* No REQ URI, fill with blank */
+ req_uri = "";
+ }
+ cseq = sippmh_get_header_val(pSIPMessage, SIP_HEADER_CSEQ, NULL);
+ if (cseq == NULL) {
+ /* No REQ CSEQ, fill with blank */
+ cseq = "";
+ }
+ callid = sippmh_get_header_val(pSIPMessage, SIP_HEADER_CALLID, NULL);
+ if (callid == NULL) {
+ /* No REQ CSEQ, fill with blank */
+ callid = "";
+ }
+
+ /* For messages starting with SIP add 8 byte. default
+ * debugs do not show all the SIP message information
+ * rather show initial msg.
+ */
+ if (msg != NULL) {
+ if (msg[0] == 'S' &&
+ msg[1] == 'I' &&
+ msg[2] == 'P') {
+ disp_buf = &msg[8];
+ } else {
+ disp_buf = msg;
+ }
+ if ((strncmp(disp_buf, SIP_METHOD_REGISTER, sizeof(SIP_METHOD_REGISTER)-1) == 0) &&
+ (!dump_reg_msg)) {
+ return;
+ }
+ } else {
+ /* No msg. buffer */
+ disp_buf = NULL;
+ }
+
+
+ if (disp_buf != NULL) {
+ DEF_DEBUG(DEB_F_PREFIX"<%s:%-4d>:%c%c%c%c%c%c%c: %-10s :%-6s::%s\n",
+ DEB_F_PREFIX_ARGS(SIP_MSG_SEND, fname),
+ ipaddr_str, cc_remote_port,
+ disp_buf[0],
+ disp_buf[1],
+ disp_buf[2],
+ disp_buf[3],
+ disp_buf[4],
+ disp_buf[5],
+ disp_buf[6],
+ req_uri,
+ cseq, callid);
+ } else {
+ /* No msg to send */
+ DEF_DEBUG(DEB_F_PREFIX"<%s:%-4d>: empty message\n",
+ DEB_F_PREFIX_ARGS(SIP_MSG_SEND, fname),
+ ipaddr_str, cc_remote_port);
+ }
+}
+
+/**
+ *
+ * Dump sip messages
+ *
+ * @param msg - message buffer
+ * pSIPMessage - parsed message structure
+ * cc_remote_ipaddr - remote ip address
+ * cc_remote_port - remote port number
+ *
+ * @return none
+ *
+ * @pre (valid pSIPMessage AND
+ * valid cc_remote_ipaddr)
+ */
+
+void ccsip_dump_recv_msg_info (sipMessage_t *pSIPMessage,
+ cpr_ip_addr_t *cc_remote_ipaddr,
+ uint16_t cc_remote_port)
+{
+ char *disp_buf;
+ const char *req_uri;
+ const char *cseq;
+ const char *callid;
+ char ipaddr_str[MAX_IPADDR_STR_LEN];
+ cpr_ip_addr_t cc_ipaddr;
+ static const char fname[] = "ccsip_dump_recv_msg_info";
+
+ util_ntohl(&cc_ipaddr, cc_remote_ipaddr);
+ ipaddr2dotted(ipaddr_str, &cc_ipaddr);
+
+ req_uri = sippmh_get_cached_header_val(pSIPMessage, FROM);
+ if (req_uri == NULL) {
+ /* No REQ URI, fill with blank */
+ req_uri = "";
+ }
+ cseq = sippmh_get_cached_header_val(pSIPMessage, CSEQ);
+ if (cseq == NULL) {
+ /* No REQ CSEQ, fill with blank */
+ cseq = "";
+ }
+ callid = sippmh_get_cached_header_val(pSIPMessage, CALLID);
+ if (callid == NULL) {
+ /* No REQ CSEQ, fill with blank */
+ callid = "";
+ }
+
+ if (!dump_reg_msg) {
+ if (strstr(cseq, SIP_METHOD_REGISTER) != NULL) {
+ return;
+ }
+ }
+
+ /* For messages starting with SIP add 8 byte. default
+ * debugs do not show all the SIP message information
+ * rather show initial msg.
+ */
+ if (pSIPMessage->mesg_line != NULL) {
+ if (pSIPMessage->mesg_line[0] == 'S' &&
+ pSIPMessage->mesg_line[1] == 'I' &&
+ pSIPMessage->mesg_line[2] == 'P') {
+ disp_buf = &(pSIPMessage->mesg_line[8]);
+ } else {
+ disp_buf = pSIPMessage->mesg_line;
+ }
+ } else {
+ /*
+ * It is possible that this function is called with
+ * invalid message or partially received.
+ */
+ disp_buf = NULL;
+ }
+
+ if (disp_buf != NULL) {
+ DEF_DEBUG(DEB_F_PREFIX"<%s:%-4d>:%c%c%c%c%c%c%c: %-10s :%-6s::%s\n",
+ DEB_F_PREFIX_ARGS(SIP_MSG_RECV, fname),
+ ipaddr_str, cc_remote_port,
+ disp_buf[0],
+ disp_buf[1],
+ disp_buf[2],
+ disp_buf[3],
+ disp_buf[4],
+ disp_buf[5],
+ disp_buf[6],
+ req_uri,
+ cseq, callid);
+ } else {
+ /* No line received */
+ DEF_DEBUG(DEB_F_PREFIX"<%s:%-4d>: empty message\n",
+ DEB_F_PREFIX_ARGS(SIP_MSG_RECV, fname),
+ ipaddr_str, cc_remote_port);
+ }
+}
+
+/**
+ *
+ * platform_print_sip_msg
+ *
+ * The function perform printing SIP msg.
+ *
+ * Parameters: msg - pointer to character strings of the SIP messages.
+ *
+ * Return Value: None
+ *
+ */
+void
+platform_print_sip_msg (const char *msg)
+{
+ char *buf;
+ int msg_to_crypto_line_len, msg_to_digits_tag_len, buf_len;
+ const char *c_line_begin, *c_line_end;
+ static const char crypto_line_tag[] = "a=crypto:";
+ static const char crypto_mask[] = "...";
+ static const char digits_tag[] = "digits=";
+
+ if (msg == NULL) {
+ return;
+ }
+
+ buginf_msg("\n");
+ /* replace digits for security reasons */
+ if (strstr(msg, "kpml-response")) {
+ /* This is kpml response. so supress printing digits. */
+ c_line_begin = strstr(msg, digits_tag);
+ if (c_line_begin == NULL) {
+ /* No digits, print everything */
+ buginf_msg(msg);
+ return;
+ }
+ /*
+ * Calculate the length of the msg. to print from
+ * from the beginning to the end of the "digits=" i.e.
+ */
+ msg_to_digits_tag_len = c_line_begin - msg + sizeof(digits_tag);
+ buf_len = msg_to_digits_tag_len + sizeof(crypto_mask);
+ buf = (char *) cpr_malloc(buf_len);
+ if (buf == NULL) {
+ /* No memory */
+ return;
+ }
+
+ /* Copy the message upto "digits=" */
+ memcpy(buf, msg, msg_to_digits_tag_len);
+
+ /* Copy mask and the end NULL terminating char to the buffer */
+ memcpy(&buf[msg_to_digits_tag_len], crypto_mask, sizeof(crypto_mask));
+ /* Print it out now */
+ buginf_msg(buf);
+ cpr_free(buf);
+
+ c_line_end = c_line_begin + sizeof(digits_tag) + 3; /* 3 beacuse " + digit + " */
+ msg = c_line_end;
+ buginf_msg(msg);
+ } else if (sip_regmgr_get_sec_level(1) == ENCRYPTED) {
+ /* The 1st. line is using encrypted signaling */
+ while (TRUE) {
+ c_line_begin = strstr(msg, crypto_line_tag);
+ if (c_line_begin == NULL) {
+ /* No more crypto line, print whatever left and done */
+ buginf_msg(msg);
+ return;
+ } else {
+ /*
+ * Found a crypto line:
+ *
+ * Allocate buffer to print the msg. including this
+ * instance of crypto line but no crypto parameter.
+ * For example:
+ *
+ * v=0
+ * o=Cisco-SIPUA 3052 7 IN IP4 10.80.35.217
+ * s=SIP Call
+ * t=0 0
+ * m=audio 28926 RTP/SAVP 0 8 18 101
+ * c=IN IP4 10.80.35.217
+ * a=crypto:1 AES_CM_128_HMAC_SHA1_32 inline:GqT...
+ * a=rtpmap:0 PCMU/8000
+ *
+ *
+ * The output of printing will be
+ *
+ * v=0
+ * o=Cisco-SIPUA 3052 7 IN IP4 10.80.35.217
+ * s=SIP Call
+ * t=0 0
+ * m=audio 28926 RTP/SAVP 0 8 18 101
+ * c=IN IP4 10.80.35.217
+ * a=crypto:1...
+ * a=rtpmap:0 PCMU/8000
+ *
+ */
+
+ /*
+ * Calculate the length of the msg. to print from
+ * current position to the end of the "a=crypto:n" i.e.
+ * from the current of msg passes the ":" by one character
+ * after of the "a=crypto:". This allows the first character
+ * of the crypto tag field character to be included in the
+ * output. Note that there is no explicit adding this
+ * extra character in the code below because of the
+ * sizeof(crypto_line_tag) includes extra 1 byte of string
+ * termination character already. It will be the extra
+ * character to print after the ":".
+ */
+ msg_to_crypto_line_len = c_line_begin - msg +
+ sizeof(crypto_line_tag);
+ /*
+ * The buffer allocated to print includes the length from
+ * current msg pointer to this instance of crypto line +
+ * the mask length plus 1 byte for NULL terminating character.
+ * The NULL terminating character is included in the
+ * sizeof(crypto_mask) below.
+ */
+ buf_len = msg_to_crypto_line_len + sizeof(crypto_mask);
+ buf = (char *) cpr_malloc(buf_len);
+ if (buf == NULL) {
+ /* No memory */
+ return;
+ }
+
+ /* Copy the message including this instance of crypto line */
+ memcpy(buf, msg, msg_to_crypto_line_len);
+
+ /* Copy mask and the end NULL terminating char to the buffer */
+ memcpy(&buf[msg_to_crypto_line_len], crypto_mask,
+ sizeof(crypto_mask));
+ /* Print it out now */
+ buginf_msg(buf);
+ cpr_free(buf);
+
+ /* Find the end of the crypto line */
+ c_line_end = strpbrk(c_line_begin, "\n");
+ if (c_line_end != NULL) {
+ /* Skip pass the "\n" character of the crypto line */
+ msg = c_line_end + 1;
+ } else {
+ /* Some thing is wrong, no end line character in SDP */
+ return;
+ }
+ }
+ }
+ } else {
+ /* print full content */
+ buginf_msg(msg);
+ }
+}
+
+/*
+ * Function: ccsip_debug_init()
+ *
+ * Parameters: None
+ *
+ * Description: Initialize the Debug keywords used by the SIP protocol stack.
+ *
+ * Returns: None
+ *
+ */
+void
+ccsip_debug_init (void)
+{
+ /* Placeholder for doing any initialization related tasks */
+}
diff --git a/libs/sipcc/core/sipstack/ccsip_info.c b/libs/sipcc/core/sipstack/ccsip_info.c
new file mode 100644
index 0000000000..d58b022785
--- /dev/null
+++ b/libs/sipcc/core/sipstack/ccsip_info.c
@@ -0,0 +1,898 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "cpr_types.h"
+#include "cpr_stdio.h"
+
+#include "ccsip_core.h"
+#include "ccsip_callinfo.h"
+#include "ccsip_messaging.h"
+#include "uiapi.h"
+#include "lsm.h"
+#include "fsm.h"
+#include "vcm.h"
+#include "phone_debug.h"
+#include "singly_link_list.h"
+#include "ccapi.h"
+
+extern int httpish_strncasecmp(const char *s1, const char *s2, size_t len);
+
+typedef unsigned int info_index_t;
+typedef unsigned int type_index_t;
+
+typedef struct {
+ info_package_handler_t handler;
+ info_index_t info_index; // the index of the info_package in g_registered_info array
+ // i.e., the value returned by find_info_index()
+ type_index_t type_index; // the index of the content_type in g_registered_type array
+ // i.e., the value returned by find_type_index()
+} handler_record_t;
+
+/* Info Package handler registry */
+static sll_handle_t s_handler_registry = NULL;
+
+#define INDEX_NOT_FOUND ((unsigned int)-1)
+
+/*
+ * g_registered_info[] contains the Info Package strings (such as
+ * "conference") for the registered handlers.
+ */
+char *g_registered_info[MAX_INFO_HANDLER];
+
+static char *s_registered_type[MAX_INFO_HANDLER];
+
+static sll_match_e is_matching_type(void *find_by_p, void *data_p);
+static info_index_t find_info_index(const char *info_package);
+static info_index_t find_next_available_info_index(void);
+static type_index_t find_type_index(const char *type_package);
+static type_index_t find_next_available_type_index(void);
+static handler_record_t *find_handler_record(info_index_t info_index,
+ type_index_t type_index);
+static boolean is_info_package_registered(info_index_t info_index);
+static boolean is_content_type_registered(type_index_t type_index);
+static void update_recv_info_list(const char *header_field_value,
+ string_t *info_packages);
+static void media_control_info_package_handler(line_t line, callid_t call_id,
+ const char *info_package,
+ const char *content_type,
+ const char *message_body);
+#ifdef _CONF_ROSTER_
+static void conf_info_package_handler(line_t line, callid_t call_id,
+ const char *info_package,
+ const char *content_type,
+ const char *message_body);
+#endif
+
+
+
+/*
+ * Function: find_info_index
+ *
+ * Parameters:
+ * info_package - the Info Package to find
+ *
+ * Description:
+ * Finds the Info Package in g_registered_info array.
+ *
+ * Return:
+ * info_index_t - the index of the Info Package in the array
+ * INDEX_NOT_FOUND - the Info Package was not found in the array
+ */
+static info_index_t
+find_info_index(const char *info_package)
+{
+ info_index_t info_index;
+
+ for (info_index = 0; info_index < MAX_INFO_HANDLER; info_index++) {
+ if (g_registered_info[info_index] &&
+ httpish_strncasecmp(info_package,
+ g_registered_info[info_index],
+ strlen(g_registered_info[info_index])) == 0) {
+ return info_index;
+ }
+ }
+
+ return INDEX_NOT_FOUND;
+}
+
+/*
+ * Function: find_next_available_info_index
+ *
+ * Parameters:
+ * None
+ *
+ * Description:
+ * Finds an empty slot in g_registered_info array.
+ *
+ * Return:
+ * info_index_t - the index of the empty slot in the array
+ * INDEX_NOT_FOUND - the array is full
+ */
+static info_index_t
+find_next_available_info_index(void)
+{
+ info_index_t info_index;
+
+ for (info_index = 0; info_index < MAX_INFO_HANDLER; info_index++) {
+ if (g_registered_info[info_index] == NULL) {
+ return info_index;
+ }
+ }
+
+ return INDEX_NOT_FOUND;
+}
+
+/*
+ * Function: find_type_index
+ *
+ * Parameters:
+ * content_type - the Content Type to find
+ *
+ * Description:
+ * Finds the Content Type in s_registered_type array.
+ *
+ * Return:
+ * type_index_t - the index of the Content Type in the array
+ * INDEX_NOT_FOUND - the Content Type was not found in the array
+ */
+static type_index_t
+find_type_index(const char *content_type)
+{
+ type_index_t type_index;
+
+ for (type_index = 0; type_index < MAX_INFO_HANDLER; type_index++) {
+ if (s_registered_type[type_index] &&
+ httpish_strncasecmp(content_type,
+ s_registered_type[type_index],
+ strlen(s_registered_type[type_index])) == 0) {
+ return type_index;
+ }
+ }
+
+ return INDEX_NOT_FOUND;
+}
+
+/*
+ * Function: find_next_available_type_index
+ *
+ * Parameters:
+ * None
+ *
+ * Description:
+ * Finds an empty slot in s_registered_type array.
+ *
+ * Return:
+ * type_index_t - the index of the empty slot in the array
+ * INDEX_NOT_FOUND - the array is full
+ */
+static type_index_t
+find_next_available_type_index(void)
+{
+ type_index_t type_index;
+
+ for (type_index = 0; type_index < MAX_INFO_HANDLER; type_index++) {
+ if (s_registered_type[type_index] == NULL) {
+ return type_index;
+ }
+ }
+
+ return INDEX_NOT_FOUND;
+}
+
+/*
+ * Function: is_matching_type
+ *
+ * Parameters:
+ * find_by_p - searching criteria
+ * data_p - a node
+ *
+ * Description:
+ * Checks to see if the node matches the searching criteria.
+ *
+ * Return:
+ * SLL_MATCH_FOUND - the node is a match
+ * SLL_MATCH_NOT_FOUND - the node is not a match
+ */
+static sll_match_e
+is_matching_type(void *find_by_p, void *data_p)
+{
+ handler_record_t *tuple = (handler_record_t *)find_by_p;
+ handler_record_t *node = (handler_record_t *)data_p;
+
+ if ((node->info_index == tuple->info_index) &&
+ (node->type_index == tuple->type_index)) {
+ return SLL_MATCH_FOUND;
+ }
+ return SLL_MATCH_NOT_FOUND;
+}
+
+/*
+ * Function: find_handler_record
+ *
+ * Parameters:
+ * info_index - the index of the Info Package in g_registered_info array
+ * type_index - the index of the Content Type in s_registered_type array
+ *
+ * Description:
+ * Finds the Info Package handler registered for the Info Package/Content
+ * Type pair.
+ *
+ * Return:
+ * handler_record_t * - the registered handler record
+ * NULL - otherwise
+ */
+static handler_record_t *
+find_handler_record(info_index_t info_index, type_index_t type_index)
+{
+ handler_record_t tuple;
+
+ tuple.info_index = info_index;
+ tuple.type_index = type_index;
+
+ return (handler_record_t *)sll_find(s_handler_registry, &tuple);
+}
+
+/*
+ * Function: is_info_package_registered
+ *
+ * Parameters:
+ * info_index - the index of the Info Package in g_registered_info array
+ *
+ * Description:
+ * Checks to see if a handler was registered for the Info Package.
+ *
+ * Return:
+ * TRUE - a handler was registered for the Info Package
+ * FALSE - otherwise
+ */
+static boolean
+is_info_package_registered(info_index_t info_index)
+{
+ handler_record_t *record;
+
+ for (record = (handler_record_t *)sll_next(s_handler_registry, NULL);
+ record != NULL;
+ record = (handler_record_t *)sll_next(s_handler_registry, record)) {
+ if (record->info_index == info_index) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/*
+ * Function: is_content_type_registered
+ *
+ * Parameters:
+ * type_index - the index of the Content Type in s_registered_type array
+ *
+ * Description:
+ * Checks to see if a handler was registered for the Content Type.
+ *
+ * Return:
+ * TRUE - a handler was registered for the Content Type
+ * FALSE - otherwise
+ */
+static boolean
+is_content_type_registered(type_index_t type_index)
+{
+ handler_record_t *record;
+
+ for (record = (handler_record_t *)sll_next(s_handler_registry, NULL);
+ record != NULL;
+ record = (handler_record_t *)sll_next(s_handler_registry, record)) {
+ if (record->type_index == type_index) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/*
+ * Function: ccsip_register_info_package_handler
+ *
+ * Parameters:
+ * info_package - the Info Package for the handler
+ * content_type - the Content Type for the handler
+ * handler - the handler
+ *
+ * Description:
+ * Registers the handler for the Info Package/Content Type pair.
+ *
+ * Return:
+ * SIP_OK - the handler was registered successfully
+ * SIP_ERROR - otherwise
+ */
+int
+ccsip_register_info_package_handler(const char *info_package,
+ const char *content_type,
+ info_package_handler_t handler)
+{
+ static const char *fname = "ccsip_register_info_package_handler";
+ info_index_t info_index;
+ type_index_t type_index;
+ char *tmp_info = NULL;
+ char *tmp_type = NULL;
+ handler_record_t *record;
+
+ if (s_handler_registry == NULL) {
+ CCSIP_DEBUG_TASK("%s: Info Package handler was not initialized\n", fname);
+ return SIP_ERROR;
+ }
+
+ if ((info_package == NULL) || (content_type == NULL) || (handler == NULL)) {
+ CCSIP_DEBUG_ERROR("%s: invalid parameter\n", fname);
+ return SIP_ERROR;
+ }
+
+ /* Find the info_index for the info_package */
+ info_index = find_info_index(info_package);
+
+ if (info_index == INDEX_NOT_FOUND) {
+ /* Find the first available slot */
+ info_index = find_next_available_info_index();
+
+ if (info_index == INDEX_NOT_FOUND) {
+ CCSIP_DEBUG_ERROR("%s: maximum reached\n", fname);
+ return SIP_ERROR;
+ }
+
+ tmp_info = cpr_strdup(info_package);
+ if (tmp_info == NULL) {
+ CCSIP_DEBUG_ERROR("%s: failed to duplicate info_package string\n", fname);
+ return SIP_ERROR;
+ }
+ }
+
+ /* Find the type_index for the content_type */
+ type_index = find_type_index(content_type);
+
+ if (type_index == INDEX_NOT_FOUND) {
+ /* Find the first available slot */
+ type_index = find_next_available_type_index();
+
+ if (type_index == INDEX_NOT_FOUND) {
+ CCSIP_DEBUG_ERROR("%s: maximum reached\n", fname);
+ if (tmp_info != NULL) {
+ cpr_free(tmp_info);
+ }
+ return SIP_ERROR;
+ }
+
+ tmp_type = cpr_strdup(content_type);
+ if (tmp_type == NULL) {
+ CCSIP_DEBUG_ERROR("%s: failed to duplicate info_package string\n", fname);
+ if (tmp_info != NULL) {
+ cpr_free(tmp_info);
+ }
+ return SIP_ERROR;
+ }
+ }
+
+ /* Check to see if the info/type tuple has been registered before */
+ if (find_handler_record(info_index, type_index) != NULL) {
+ CCSIP_DEBUG_ERROR("%s: Info Package handler already registered\n", fname);
+ return SIP_ERROR;
+ }
+
+ /*
+ * At this point, info_index points to the slot in g_registered_info where
+ * either:
+ *
+ * 1) the info_package is residing, or
+ * 2) the info_package (a copy of which is pointed to by *tmp_info) will be
+ * copied to before the function returns
+ *
+ * type_index is similar.
+ */
+
+ record = (handler_record_t *)cpr_malloc(sizeof(handler_record_t));
+ if (record == NULL) {
+ if (tmp_type != NULL) {
+ cpr_free(tmp_type);
+ }
+ if (tmp_info != NULL) {
+ cpr_free(tmp_info);
+ }
+ CCSIP_DEBUG_ERROR("%s: failed to allocate info handler record\n", fname);
+ return SIP_ERROR;
+ }
+
+ record->handler = handler;
+ record->info_index = info_index;
+ record->type_index = type_index;
+
+ if (sll_append(s_handler_registry, record) != SLL_RET_SUCCESS) {
+ cpr_free(record);
+ if (tmp_type != NULL) {
+ cpr_free(tmp_type);
+ }
+ if (tmp_info != NULL) {
+ cpr_free(tmp_info);
+ }
+ CCSIP_DEBUG_ERROR("%s: failed to insert to the registry\n", fname);
+ return SIP_ERROR;
+ }
+
+ if (tmp_info != NULL) {
+ g_registered_info[info_index] = tmp_info;
+ }
+ if (tmp_type != NULL) {
+ s_registered_type[type_index] = tmp_type;
+ }
+
+ return SIP_OK;
+}
+
+/*
+ * Function: ccsip_deregister_info_package_handler
+ *
+ * Parameters:
+ * info_package - the Info Package for the handler
+ * content_type - the Content Type for the handler
+ * handler - the handler
+ *
+ * Description:
+ * Deregisters the handler for the Info Package/Content Type pair.
+ *
+ * Return:
+ * SIP_OK - the handler was registered successfully
+ * SIP_ERROR - otherwise
+ */
+int
+ccsip_deregister_info_package_handler(const char *info_package,
+ const char *content_type,
+ info_package_handler_t handler)
+{
+ static const char *fname = "ccsip_deregister_info_package_handler";
+ info_index_t info_index;
+ type_index_t type_index;
+ handler_record_t *record;
+
+ if (s_handler_registry == NULL) {
+ CCSIP_DEBUG_TASK("%s: Info Package handler was not initialized\n", fname);
+ return SIP_ERROR;
+ }
+
+ /* Find the info_index for the info_package */
+ info_index = find_info_index(info_package);
+ if (info_index == INDEX_NOT_FOUND) {
+ CCSIP_DEBUG_ERROR("%s: handler was not registered (%s)\n",
+ fname, info_package);
+ return SIP_ERROR;
+ }
+
+ /* Find the type_index for the content_type */
+ type_index = find_type_index(content_type);
+ if (type_index == INDEX_NOT_FOUND) {
+ CCSIP_DEBUG_ERROR("%s: handler was not registered (%s)\n",
+ fname, content_type);
+ return SIP_ERROR;
+ }
+
+ /* Find the handler record */
+ record = find_handler_record(info_index, type_index);
+ if ((record == NULL) || (record->handler != handler)) {
+ CCSIP_DEBUG_ERROR("%s: handler was not registered (%p)\n",
+ fname, handler);
+ return SIP_ERROR;
+ }
+
+ (void)sll_remove(s_handler_registry, record);
+
+ cpr_free(record);
+
+ if (!is_info_package_registered(info_index)) {
+ /* The info_package was not found in the registry, meaning we're
+ * the last one who registered for this particular info_package */
+ cpr_free(g_registered_info[info_index]);
+ g_registered_info[info_index] = NULL;
+ }
+
+ if (!is_content_type_registered(type_index)) {
+ /* The content_type was not found in the registry, meaning we're
+ * the last one who registered for this particular content_type */
+ cpr_free(s_registered_type[type_index]);
+ s_registered_type[type_index] = NULL;
+ }
+
+ return SIP_OK;
+}
+
+/*
+ * Function: update_recv_info_list
+ *
+ * Parameters:
+ * header_field_value - the header field value to match (e.g.,
+ * "conference")
+ * info_packages - the Info Packages string to append the header
+ * field value to
+ *
+ * Description:
+ * Checks to see if a handler is registered for the header field value
+ * (e.g., "conference"), if so, append the header field value to
+ * the end of info_packages.
+ *
+ * Returns:
+ * None
+ */
+static void
+update_recv_info_list(const char *header_field_value, string_t *info_packages)
+{
+ static const char *fname = "update_recv_info_list";
+ info_index_t info_index;
+
+ if ((header_field_value == NULL) || (info_packages == NULL) ||
+ (*info_packages == NULL)) {
+ CCSIP_DEBUG_ERROR("%s: invalid parameter\n", fname);
+ return;
+ }
+
+ info_index = find_info_index(header_field_value);
+ if (info_index != INDEX_NOT_FOUND) {
+ /* Info-Package is supported */
+ if (**info_packages == '\0') {
+ *info_packages = strlib_update(*info_packages,
+ g_registered_info[info_index]);
+ } else {
+ *info_packages = strlib_append(*info_packages, ", ");
+ *info_packages = strlib_append(*info_packages,
+ g_registered_info[info_index]);
+ }
+ }
+}
+
+/*
+ * Function: ccsip_parse_send_info_header
+ *
+ * Parameters:
+ * ccb - the SIP CCB
+ * pSipMessage - the SIP message
+ *
+ * Description:
+ * Checks the Send-Info header (if exists) to see if a handler was
+ * registered for the Info Package. If so, append the Info Package
+ * to the end of recv_info_list.
+ *
+ * Returns:
+ * None
+ */
+void
+ccsip_parse_send_info_header(sipMessage_t *pSipMessage, string_t *recv_info_list)
+{
+ char *send_info[MAX_INFO_HANDLER];
+ int count;
+ int i;
+ char *header_field_values;
+ char *header_field_value;
+ char *separator;
+
+ // leading white spaces are trimmed, but not trailing ones
+ count = sippmh_get_num_particular_headers(pSipMessage,
+ SIP_HEADER_SEND_INFO,
+ NULL,
+ send_info,
+ MAX_INFO_HANDLER);
+
+ if (count == 0) {
+ return;
+ }
+
+ for (i = 0; (i < count) && (i < MAX_INFO_HANDLER); i++) {
+ header_field_values = cpr_strdup(send_info[i]);
+ if (header_field_values == NULL) {
+ return;
+ }
+ header_field_value = header_field_values;
+
+ while ((separator = strchr(header_field_value, COMMA)) != NULL) {
+ *separator++ = '\0';
+ update_recv_info_list(header_field_value, recv_info_list);
+ header_field_value = separator;
+ SKIP_WHITE_SPACE(header_field_value);
+ }
+ update_recv_info_list(header_field_value, recv_info_list);
+
+ cpr_free(header_field_values);
+ }
+}
+
+/*
+ * Function: ccsip_handle_info_package
+ *
+ * Parameters:
+ * ccb - the SIP CCB
+ * pSipMessage - the SIP message
+ *
+ * Description:
+ * Handles an incoming unsolicited Info Package message.
+ * XXX Currently this function only handles the first part in a
+ * multi-part Info Package message.
+ *
+ * Return:
+ * SIP_OK - if request processed.
+ * SIP_ERROR - if there is error
+ */
+int
+ccsip_handle_info_package(ccsipCCB_t *ccb, sipMessage_t *pSipMessage)
+{
+ static const char *fname = "ccsip_handle_info_package";
+ const char *info_package;
+ const char *content_type;
+ info_index_t info_index;
+ type_index_t type_index;
+ handler_record_t *record;
+ uint16_t status_code;
+ const char *reason_phrase;
+ int return_code = SIP_ERROR;
+
+ /* FIXME Media Control currently does not follow the IETF draft
+ draft-ietf-sip-info-events-01, so short-circuit here and
+ bypass all the Info Package related stuff below. */
+ // leading white spaces are trimmed, but not trailing ones
+ content_type = sippmh_get_cached_header_val(pSipMessage,
+ CONTENT_TYPE);
+ if (content_type &&
+ httpish_strncasecmp(content_type,
+ SIP_CONTENT_TYPE_MEDIA_CONTROL,
+ strlen(SIP_CONTENT_TYPE_MEDIA_CONTROL)) == 0) {
+
+ media_control_info_package_handler(ccb->dn_line, ccb->gsm_id,
+ "", // legacy mode, no Info Package
+ SIP_CONTENT_TYPE_MEDIA_CONTROL,
+ pSipMessage->mesg_body[0].msgBody);
+
+ if (sipSPISendErrorResponse(pSipMessage, 200, SIP_SUCCESS_SETUP_PHRASE,
+ 0, NULL, NULL) != TRUE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
+ fname, SIP_SUCCESS_SETUP_PHRASE);
+ return SIP_ERROR;
+ }
+
+ return SIP_OK;
+ }
+
+ /*
+ * Parse the Info-Package header
+ */
+ // leading white spaces are trimmed, but not trailing ones
+ info_package = sippmh_get_header_val(pSipMessage,
+ SIP_HEADER_INFO_PACKAGE,
+ NULL);
+
+ if (info_package == NULL) {
+ /* No Info-Package header */
+ CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"Missing Info-Package header\n",
+ DEB_F_PREFIX_ARGS(SIP_INFO_PACKAGE, fname));
+
+ if (pSipMessage->num_body_parts == 0) {
+ /* No Info-Package header, and no body poarts */
+ CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"Missing message body\n",
+ DEB_F_PREFIX_ARGS(SIP_INFO_PACKAGE, fname));
+ /* Send 200 OK for legacy UA support */
+ status_code = 200;
+ reason_phrase = SIP_SUCCESS_SETUP_PHRASE;
+ return_code = SIP_OK;
+ } else {
+ /* No Info-Package header, but with body part(s) */
+ if (pSipMessage->num_body_parts > 1) {
+ CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"Multipart Info Package"
+ DEB_F_PREFIX_ARGS(SIP_INFO_PACKAGE, fname));
+ }
+
+ type_index = find_type_index(pSipMessage->mesg_body[0].msgContentType);
+ if (type_index == INDEX_NOT_FOUND) {
+ /* No Info-Package header, and Content-Type is not supported */
+ CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"Unsupported Content Type\n",
+ DEB_F_PREFIX_ARGS(SIP_INFO_PACKAGE, fname));
+ /* Send 415 Unsupported Media Type */
+ status_code = SIP_CLI_ERR_MEDIA;
+ reason_phrase = SIP_CLI_ERR_MEDIA_PHRASE;
+ } else {
+ /* No Info-Package header, but Conent-Type is supported */
+ /* Send 200 OK for legacy UA support */
+ status_code = 200;
+ reason_phrase = SIP_SUCCESS_SETUP_PHRASE;
+ return_code = SIP_OK;
+ }
+ }
+ } else {
+ /* With Info-Package header */
+ if (pSipMessage->num_body_parts == 0) {
+ /* With Info-Package header, but no body parts */
+ CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"Missing message body\n",
+ DEB_F_PREFIX_ARGS(SIP_INFO_PACKAGE, fname));
+
+ /* ? */
+ /* Send 489 Bad Event */
+ status_code = SIP_CLI_ERR_BAD_EVENT;
+ reason_phrase = SIP_CLI_ERR_BAD_EVENT_PHRASE;
+
+ } else {
+ /* With Info-Package header and body part(s) */
+ if (pSipMessage->num_body_parts > 1) {
+ CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"Multipart Info Package "
+ "(only the first part is processed)\n",
+ DEB_F_PREFIX_ARGS(SIP_INFO_PACKAGE, fname));
+ }
+
+ info_index = find_info_index(info_package);
+ if (info_index == INDEX_NOT_FOUND) {
+ /* Info-Package is not supported */
+ CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"Unsupported Info Package\n",
+ DEB_F_PREFIX_ARGS(SIP_INFO_PACKAGE, fname));
+
+ /* Send 489 Bad Event */
+ status_code = SIP_CLI_ERR_BAD_EVENT;
+ reason_phrase = SIP_CLI_ERR_BAD_EVENT_PHRASE;
+
+ } else {
+ /* Info-Package is supported */
+ type_index = find_type_index(pSipMessage->mesg_body[0].msgContentType);
+ record = find_handler_record(info_index, type_index);
+ if (record == NULL) {
+ /* Info-Package header is supported, but Content-Type is not */
+ CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"Unsupported Content Type\n",
+ DEB_F_PREFIX_ARGS(SIP_INFO_PACKAGE, fname));
+ /* Send 415 Unsupported Media Type */
+ status_code = SIP_CLI_ERR_MEDIA;
+ reason_phrase = SIP_CLI_ERR_MEDIA_PHRASE;
+ } else {
+ /* a handler is registered */
+ (*record->handler)(ccb->dn_line, ccb->gsm_id,
+ g_registered_info[record->info_index],
+ s_registered_type[record->type_index],
+ pSipMessage->mesg_body[0].msgBody);
+ /* Send 200 OK */
+ status_code = 200;
+ reason_phrase = SIP_SUCCESS_SETUP_PHRASE;
+ return_code = SIP_OK;
+ }
+ }
+ }
+ }
+
+ if (sipSPISendErrorResponse(pSipMessage, status_code, reason_phrase,
+ 0, NULL, NULL) != TRUE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
+ fname, reason_phrase);
+ return SIP_ERROR;
+ }
+
+ return return_code;
+}
+
+static void
+media_control_info_package_handler(line_t line, callid_t call_id,
+ const char *info_package,
+ const char *content_type,
+ const char *message_body)
+{
+}
+
+#ifdef _CONF_ROSTER_
+static void
+conf_info_package_handler(line_t line, callid_t call_id,
+ const char *info_package,
+ const char *content_type,
+ const char *message_body)
+{
+ static const char *fname = "conf_info_package_handler";
+
+ CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"info_package: %s content_type: %s\n",
+ DEB_F_PREFIX_ARGS(SIP_INFO_PACKAGE, fname),
+ info_package, content_type);
+
+ ui_info_received(line, lsm_get_ui_id(call_id), info_package, content_type,
+ message_body);
+}
+#endif
+
+/*
+ * Function: ccsip_info_package_handler_init
+ *
+ * Parameters:
+ * None
+ *
+ * Description:
+ * Initializes the Info Package handler framework.
+ *
+ * Return:
+ * SIP_OK - Info Package handler framework initialized successfully
+ * SIP_ERROR - otherwise
+ */
+int
+ccsip_info_package_handler_init(void)
+{
+ static const char *fname = "ccsip_info_package_handler_init";
+ info_index_t info_index;
+ type_index_t type_index;
+
+ if (s_handler_registry != NULL) {
+ // Is this considered an error?
+ CCSIP_DEBUG_TASK("%s: Info Package handler already initialized\n", fname);
+ return SIP_OK;
+ }
+
+ /* Create the SLL */
+ s_handler_registry = sll_create(is_matching_type);
+ if (s_handler_registry == NULL) {
+ CCSIP_DEBUG_ERROR("%s: failed to create the registry\n", fname);
+ return SIP_ERROR;
+ }
+
+ for (info_index = 0; info_index < MAX_INFO_HANDLER; info_index++) {
+ g_registered_info[info_index] = NULL;
+ }
+
+ for (type_index = 0; type_index < MAX_INFO_HANDLER; type_index++) {
+ s_registered_type[type_index] = NULL;
+ }
+
+ // XXX Where is the best place to register the application-specific handler?
+#ifdef _CONF_ROSTER_
+ /* Register the handler for conference & x-cisco-conference Info Packages */
+ ccsip_register_info_package_handler(INFO_PACKAGE_CONFERENCE,
+ CONTENT_TYPE_CONFERENCE_INFO,
+ conf_info_package_handler);
+ ccsip_register_info_package_handler(INFO_PACKAGE_CISCO_CONFERENCE,
+ CONTENT_TYPE_CONFERENCE_INFO,
+ conf_info_package_handler);
+#endif
+ return SIP_OK;
+}
+
+/*
+ * Function: ccsip_info_package_handler_shutdown
+ *
+ * Parameters:
+ * None
+ *
+ * Description:
+ * Shuts down the Info Package handler framework.
+ *
+ * Return:
+ * None
+ */
+void
+ccsip_info_package_handler_shutdown(void)
+{
+ static const char *fname = "ccsip_info_package_handler_shutdown";
+ info_index_t info_index;
+ type_index_t type_index;
+ handler_record_t *record;
+
+ if (s_handler_registry == NULL) {
+ // Is this considered an error?
+ CCSIP_DEBUG_TASK("%s: Info Package handler was not initialized\n", fname);
+ return;
+ }
+
+ for (type_index = 0; type_index < MAX_INFO_HANDLER; type_index++) {
+ if (s_registered_type[type_index] != NULL) {
+ cpr_free(s_registered_type[type_index]);
+ s_registered_type[type_index] = NULL;
+ }
+ }
+
+ for (info_index = 0; info_index < MAX_INFO_HANDLER; info_index++) {
+ if (g_registered_info[info_index] != NULL) {
+ cpr_free(g_registered_info[info_index]);
+ g_registered_info[info_index] = NULL;
+ }
+ }
+
+ /* Deregister each Info Package handler */
+ for (record = (handler_record_t *)sll_next(s_handler_registry, NULL);
+ record != NULL;
+ record = (handler_record_t *)sll_next(s_handler_registry, record)) {
+ cpr_free(record);
+ }
+
+ /* Destroy the SLL */
+ sll_destroy(s_handler_registry);
+ s_handler_registry = NULL;
+}
diff --git a/libs/sipcc/core/sipstack/ccsip_messaging.c b/libs/sipcc/core/sipstack/ccsip_messaging.c
new file mode 100644
index 0000000000..d9a79651e9
--- /dev/null
+++ b/libs/sipcc/core/sipstack/ccsip_messaging.c
@@ -0,0 +1,7639 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "plstr.h"
+#include "cpr_types.h"
+#include "cpr_time.h"
+#include "cpr_stdio.h"
+#include "cpr_stdlib.h"
+#include "cpr_string.h"
+#include "cpr_in.h"
+#include "cpr_rand.h"
+#include "phntask.h"
+#include "text_strings.h"
+#include "util_string.h"
+#include "ccsip_core.h"
+#include "ccsip_macros.h"
+#include "ccsip_messaging.h"
+#include "ccsip_platform.h"
+#include "ccsip_task.h"
+#include "prot_configmgr.h"
+#include "phone_debug.h"
+#include "ccsip_reldev.h"
+#include "digcalc.h"
+#include "ccsip_register.h"
+#include "ccsip_credentials.h"
+#include "dns_utils.h"
+#include "config.h"
+#include "string_lib.h"
+#include "dialplan.h"
+#include "rtp_defs.h"
+#include "ccapi.h"
+#include "ccsip_platform_udp.h"
+#include "ccsip_task.h"
+#include "sdp.h"
+#include "sip_common_transport.h"
+#include "sip_common_regmgr.h"
+#include "uiapi.h"
+#include "ccsip_callinfo.h"
+#include "sip_interface_regmgr.h"
+#include "ccsip_spi_utils.h"
+#include "ccsip_subsmanager.h"
+#include "subapi.h"
+#include "platform_api.h"
+
+#define SIPS_URL_LEN 8
+#define NONCE_LEN 9
+#define SUBS_STATE_HDR_LEN 80
+#define MAX_EXPIRES_LEN 12
+#define MAX_ESCAPED_USER_LEN 94 // Worst case all 31 chars require escaping (3 chars) + a NULL
+#define MAX_PHONE_NAME_LEN 20
+#define MAX_UNREG_REASON_STR_LEN 256
+
+#define MAX_ESCAPED_USER_LEN 94 // Worst case all 31 chars require escaping (3 chars) + a NULL
+#define INITIAL_BUFFER_SIZE 2048
+
+
+/* External declarations */
+extern int dns_error_code; // DNS error code global
+extern sipPlatformUITimer_t sipPlatformUISMTimers[];
+extern sipCallHistory_t gCallHistory[];
+extern ccsipGlobInfo_t gGlobInfo;
+extern int16_t clockIsSetup;
+extern struct tm *gmtime_r(const time_t *, struct tm *);
+extern char *Basic_is_phone_forwarded(line_t line);
+extern uint16_t server_caps;
+extern char sipPhoneModelNumber[];
+extern char phone_load_name[];
+extern sipGlobal_t sip;
+extern ccm_act_stdby_table_t CCM_Active_Standby_Table;
+
+/* Forward declarations */
+boolean sipSPIAddRequestRecordRoute(sipMessage_t *, sipMessage_t *);
+static boolean sendResponse(ccsipCCB_t *ccb, sipMessage_t *response,
+ sipMessage_t *refrequest, boolean retx,
+ sipMethod_t method);
+static sipRet_t CopyLocalSDPintoResponse(sipMessage_t *request,
+ cc_msgbody_info_t *local_msg_body);
+
+#if defined SIP_OS_WINDOWS
+#define debugif_printf printf
+#endif
+/*
+ * Functions to manipulate transaction blocks
+ */
+
+/*
+ * This function gets the index of the last request sent or received
+ * It determines this by choosing the last one that has a
+ * non CCSIP_START_CSEQ cseq value
+ */
+int16_t
+get_last_request_trx_index (ccsipCCB_t *ccb, boolean sent)
+{
+ const char *fname = "get_last_request_trx_index";
+ int16_t i;
+
+ if (ccb == NULL) {
+ return -1;
+ }
+
+ CCSIP_DEBUG_TRX(DEB_F_PREFIX"Getting last TRX index, sent = %d\n", DEB_F_PREFIX_ARGS(SIP_TRX, fname), sent);
+
+ if (sent) {
+ for (i = MAX_REQ_OUTSTANDING - 1; i >= 0; i--) {
+ if (ccb->sent_request[i].cseq_number != CCSIP_START_CSEQ) {
+ CCSIP_DEBUG_TRX(DEB_F_PREFIX"Got TRX(%d) for sent req\n", DEB_F_PREFIX_ARGS(SIP_TRX, fname), i);
+ return i;
+ }
+ }
+ } else {
+ for (i = MAX_REQ_OUTSTANDING - 1; i >= 0; i--) {
+ if (ccb->recv_request[i].cseq_number != CCSIP_START_CSEQ) {
+ CCSIP_DEBUG_TRX(DEB_F_PREFIX"Got TRX(%d) for recv req\n", DEB_F_PREFIX_ARGS(SIP_TRX, fname), i);
+ return i;
+ }
+ }
+ }
+ return -1;
+}
+
+/*
+ * This function gets the next cseq index that can be used to send
+ * a request. It determines this by choosing the next available
+ * cseq index
+ */
+int16_t
+get_next_request_trx_index (ccsipCCB_t *ccb, boolean sent)
+{
+ const char *fname = "get_next_request_trx_index";
+ int16_t i;
+
+ if (ccb == NULL) {
+ return -1;
+ }
+
+ CCSIP_DEBUG_TRX(DEB_F_PREFIX"Getting next TRX index, sent = %d\n", DEB_F_PREFIX_ARGS(SIP_TRX, fname), sent);
+ if (sent) {
+ for (i = 0; i < MAX_REQ_OUTSTANDING; i++) {
+ if (ccb->sent_request[i].cseq_number == CCSIP_START_CSEQ) {
+ CCSIP_DEBUG_TRX(DEB_F_PREFIX"Got TRX(%d) for sent req\n", DEB_F_PREFIX_ARGS(SIP_TRX, fname), i);
+ return i;
+ }
+ }
+ } else {
+ for (i = 0; i < MAX_REQ_OUTSTANDING; i++) {
+ if (ccb->recv_request[i].cseq_number == CCSIP_START_CSEQ) {
+ CCSIP_DEBUG_TRX(DEB_F_PREFIX"Got TRX(%d) for recv req\n", DEB_F_PREFIX_ARGS(SIP_TRX, fname), i);
+ return i;
+ }
+ }
+ }
+ CCSIP_DEBUG_TRX(DEB_F_PREFIX"Unable to get any open TRX!!\n", DEB_F_PREFIX_ARGS(SIP_TRX, fname));
+ return -1;
+}
+
+/*
+ * This function gets the index corresponding to a specific method
+ */
+int16_t
+get_method_request_trx_index (ccsipCCB_t *ccb, sipMethod_t method, boolean sent)
+{
+ const char *fname = "get_method_request_trx_index";
+ int16_t i;
+
+ if (ccb == NULL) {
+ return -1;
+ }
+
+ CCSIP_DEBUG_TRX(DEB_F_PREFIX"Getting TRX for method(%s), sent = %d\n",
+ DEB_F_PREFIX_ARGS(SIP_TRX, fname), sipGetMethodString(method), sent);
+
+ if (sent) {
+ for (i = 0; i < MAX_REQ_OUTSTANDING; i++) {
+ if (ccb->sent_request[i].cseq_method == method) {
+ CCSIP_DEBUG_TRX(DEB_F_PREFIX"Got TRX(%d) for sent method(%s)\n",
+ DEB_F_PREFIX_ARGS(SIP_TRX, fname), i, sipGetMethodString(method));
+ return i;
+ }
+ }
+ } else {
+ for (i = 0; i < MAX_REQ_OUTSTANDING; i++) {
+ if (ccb->recv_request[i].cseq_method == method) {
+ CCSIP_DEBUG_TRX(DEB_F_PREFIX"Got TRX(%d) for recv method(%s)\n",
+ DEB_F_PREFIX_ARGS(SIP_TRX, fname), i, sipGetMethodString(method));
+ return i;
+ }
+ }
+ }
+ CCSIP_DEBUG_TRX(DEB_F_PREFIX"Unable to find any TRX for method!!\n", DEB_F_PREFIX_ARGS(SIP_TRX, fname));
+ return -1;
+}
+
+/*
+ * This function cleans the CSeq array and removes the entry
+ * corresponding to the method and compacts the array
+ */
+void
+clean_method_request_trx (ccsipCCB_t *ccb, sipMethod_t method, boolean sent)
+{
+ const char *fname = "clean_method_request_trx";
+ uint8_t i, j, k;
+ boolean found = FALSE;
+ sipTransaction_t *transactionp = NULL;
+
+ if (ccb == NULL) {
+ return;
+ }
+
+ CCSIP_DEBUG_TRX(DEB_F_PREFIX"Removing TRX for method(%s), sent = %d\n",
+ DEB_F_PREFIX_ARGS(SIP_TRX, fname), sipGetMethodString(method), sent);
+
+ if (sent) {
+ transactionp = &(ccb->sent_request[0]);
+ } else {
+ transactionp = &(ccb->recv_request[0]);
+ }
+
+ for (i = 0; i < MAX_REQ_OUTSTANDING && !found; i++) {
+ if (transactionp[i].cseq_method == method) {
+ transactionp[i].cseq_method = sipMethodInvalid;
+ transactionp[i].cseq_number = CCSIP_START_CSEQ;
+ strlib_free(transactionp[i].u.sip_via_header);
+ strlib_free(transactionp[i].sip_via_sentby);
+ CCSIP_DEBUG_TRX(DEB_F_PREFIX"Removed TRX(%d) for method(%s)\n",
+ DEB_F_PREFIX_ARGS(SIP_TRX, fname), i, sipGetMethodString(method));
+ found = TRUE;
+ }
+ if (found) {
+ k = i;
+ for (j = k + 1; j < MAX_REQ_OUTSTANDING; j++, k++) {
+ memcpy(&(transactionp[k]), &(transactionp[j]),
+ sizeof(sipTransaction_t));
+ }
+ // re-init the last transaction
+ transactionp[MAX_REQ_OUTSTANDING - 1].cseq_method =
+ sipMethodInvalid;
+ transactionp[MAX_REQ_OUTSTANDING - 1].cseq_number =
+ CCSIP_START_CSEQ;
+ transactionp[MAX_REQ_OUTSTANDING - 1].u.sip_via_header =
+ strlib_empty();
+ transactionp[MAX_REQ_OUTSTANDING - 1].sip_via_sentby =
+ strlib_empty();
+ }
+ }
+}
+
+line_t
+get_dn_line_from_dn (const char *watcher)
+{
+ line_t dn_line;
+ char line_name[CC_MAX_DIALSTRING_LEN];
+
+ for (dn_line = 1; dn_line <= MAX_REG_LINES; dn_line++) {
+ config_get_line_string(CFGID_LINE_NAME, line_name, (int) dn_line,
+ sizeof(line_name));
+ if (!cpr_strcasecmp(watcher, line_name)) {
+ break;
+ }
+ }
+ return dn_line;
+}
+
+boolean
+validateHostName (char *str, char *dn)
+{
+ line_t dn_line = (line_t) -1;
+ char buffer[MAX_SIP_URL_LENGTH];
+ char ccm1_addr[MAX_SIP_URL_LENGTH];
+ char ccm2_addr[MAX_SIP_URL_LENGTH];
+ char ccm3_addr[MAX_SIP_URL_LENGTH];
+
+ dn_line = get_dn_line_from_dn(dn);
+ if (dn_line >= 1 && dn_line <= MAX_REG_LINES) {
+ if (sip_regmgr_get_cc_mode(dn_line) == REG_MODE_NON_CCM) {
+ config_get_line_string(CFGID_PROXY_ADDRESS, buffer, dn_line,
+ MAX_SIP_URL_LENGTH);
+ if (!strncmp(buffer, str, MAX_SIP_URL_LENGTH)) {
+ return (TRUE);
+ } else {
+ return (FALSE);
+ }
+ } else {
+ config_get_string(CFGID_CCM1_ADDRESS, ccm1_addr,
+ MAX_SIP_URL_LENGTH);
+ config_get_string(CFGID_CCM2_ADDRESS, ccm2_addr,
+ MAX_SIP_URL_LENGTH);
+ config_get_string(CFGID_CCM3_ADDRESS, ccm3_addr,
+ MAX_SIP_URL_LENGTH);
+
+ if (!strncmp(ccm1_addr, str, MAX_SIP_URL_LENGTH) ||
+ !strncmp(ccm2_addr, str, MAX_SIP_URL_LENGTH) ||
+ !strncmp(ccm3_addr, str, MAX_SIP_URL_LENGTH)) {
+ return (TRUE);
+ } else {
+ return (FALSE);
+ }
+ }
+ }
+
+ return (FALSE);
+}
+
+/*************************************************************
+ * Function: sipGetSupportedOptionList
+ * This function returns the list of the supported option tags.
+ * The function may returns NULL pointer for the case that
+ * there is no tag to add.
+ **************************************************************/
+static const char *
+sipGetSupportedOptionList (ccsipCCB_t *ccb, sipMethod_t sipmethod)
+{
+ return (SIP_CISCO_SUPPORTED_REG_TAGS);
+}
+
+/*
+ * Send REGISTER
+ *
+ * Send a SIP REGISTER request.
+ * Assumes that
+ * - connection has been setup beforehand.
+ */
+boolean
+sipSPISendRegister (ccsipCCB_t *ccb,
+ boolean no_dns_lookup,
+ const char *user,
+ int expires_int)
+{
+ const char fname[] = "SIPSPISendRegister";
+ sipMessage_t *request = NULL;
+ char obp_address[MAX_IPADDR_STR_LEN];
+ cpr_ip_addr_t ipaddr;
+ boolean obp_present = FALSE;
+ boolean send_result = FALSE;
+
+ CPR_IP_ADDR_INIT(ipaddr);
+
+ if (!(request = sipSPIBuildRegisterHeaders(ccb, user, expires_int))) {
+ CCSIP_DEBUG_ERROR("%s: Error: Building Register Headers.\n",
+ fname);
+ return (send_result);
+ }
+
+ /*
+ * If we are being called as a result of a 4xx message we need to
+ * respond to the same proxy which sent us the 4xx message so use
+ * the previous ccb->reg.addr to send to.
+ */
+ config_get_string(CFGID_OUTBOUND_PROXY, obp_address, sizeof(obp_address));
+ if ((cpr_strcasecmp(obp_address, UNPROVISIONED) != 0) &&
+ (obp_address[0] != 0) &&
+ (obp_address[0] != '0')) {
+ obp_present = TRUE;
+ }
+ if ((!no_dns_lookup) &&
+ ((obp_present == FALSE) || ((ccb->index == REG_BACKUP_CCB)))) {
+ /* See if DNS SRV record is available */
+ dns_error_code = sipTransportGetServerAddrPort(ccb->reg.proxy, &ipaddr,
+ (uint16_t *)&ccb->reg.port,
+ &ccb->SRVhandle, FALSE);
+ if (dns_error_code == 0) {
+ /*
+ * Found an SRV record. Use that address. If there is more
+ * than one record in SRV response, setup to try all the
+ * servers in the list
+ */
+ util_ntohl(&(ccb->reg.addr), &ipaddr);
+ } else {
+ /* Do a DNS A record lookup on the proxy */
+ dns_error_code = dnsGetHostByName(ccb->reg.proxy, &ipaddr, 100, 1);
+ if (dns_error_code == 0) {
+ util_ntohl(&ipaddr, &ipaddr);
+ ccb->reg.addr = ipaddr;
+ } else {
+ ccb->reg.addr = ip_addr_invalid;
+ }
+
+ }
+ }
+
+ /* If we failed to get a valid IP address for the proxy
+ * do not broadcast the REGISTER message, but bail instead.
+ */
+ if ((util_check_if_ip_valid(&(ccb->reg.addr))) || obp_present) {
+ send_result = SendRequest(ccb, request, sipMethodRegister,
+ FALSE, TRUE, FALSE);
+ } else {
+ err_msg("%s: Unable to retrieve address of proxy.\n", fname);
+ free_sip_message(request);
+ }
+
+ if (!send_result) {
+ clean_method_request_trx(ccb, sipMethodRegister, TRUE);
+ }
+ return (send_result);
+}
+
+char *
+cc2siptype (cc_content_type_t type)
+{
+ switch (type) {
+ default:
+ case cc_content_type_unknown:
+ return SIP_CONTENT_TYPE_UNKNOWN;
+ case cc_content_type_SDP:
+ return SIP_CONTENT_TYPE_SDP;
+ case cc_content_type_CMXML:
+ return SIP_CONTENT_TYPE_CMXML;
+ case cc_content_type_sipfrag:
+ return SIP_CONTENT_TYPE_SIPFRAG;
+ }
+}
+
+cc_content_type_t
+sip2cctype (uint8_t type)
+{
+ switch (type) {
+ default:
+ case SIP_CONTENT_TYPE_UNKNOWN_VALUE:
+ return cc_content_type_unknown;
+ case SIP_CONTENT_TYPE_SDP_VALUE:
+ return cc_content_type_SDP;
+ case SIP_CONTENT_TYPE_CMXML_VALUE:
+ return cc_content_type_CMXML;
+ case SIP_CONTENT_TYPE_SIPFRAG_VALUE:
+ return cc_content_type_sipfrag;
+ }
+}
+
+uint8_t
+cc2sipdisp (cc_disposition_type_t type)
+{
+ switch (type) {
+ default:
+ case cc_disposition_unknown:
+ return SIP_CONTENT_DISPOSITION_UNKNOWN_VALUE;
+ case cc_disposition_render:
+ return SIP_CONTENT_DISPOSITION_RENDER_VALUE;
+ case cc_disposition_session:
+ return SIP_CONTENT_DISPOSITION_SESSION_VALUE;
+ case cc_dispostion_icon:
+ return SIP_CONTENT_DISPOSITION_ICON_VALUE;
+ case cc_disposition_alert:
+ return SIP_CONTENT_DISPOSITION_ALERT_VALUE;
+ case cc_disposition_precondition:
+ return SIP_CONTENT_DISPOSITION_PRECONDITION_VALUE;
+ }
+}
+
+cc_disposition_type_t
+sip2ccdisp (uint8_t type)
+{
+ switch (type) {
+ default:
+ case SIP_CONTENT_DISPOSITION_UNKNOWN_VALUE:
+ return cc_disposition_unknown;
+ case SIP_CONTENT_DISPOSITION_RENDER_VALUE:
+ return cc_disposition_render;
+ case SIP_CONTENT_DISPOSITION_SESSION_VALUE:
+ return cc_disposition_session;
+ case SIP_CONTENT_DISPOSITION_ICON_VALUE:
+ return cc_dispostion_icon;
+ case SIP_CONTENT_DISPOSITION_ALERT_VALUE:
+ return cc_disposition_alert;
+ case SIP_CONTENT_DISPOSITION_PRECONDITION_VALUE:
+ return cc_disposition_precondition;
+ }
+}
+
+
+static boolean
+sipSPIIsPrivate (ccsipCCB_t *ccb)
+{
+ int blocking;
+ boolean private_flag = FALSE;
+
+ /*
+ * If Caller ID Blocking is OFF or emergency route is ON,
+ * display the actual name. Otherwise, display "Anonymous".
+ */
+ config_get_value(CFGID_CALLERID_BLOCKING, &blocking, sizeof(blocking));
+ if ((blocking & 1) && (ccb->routeMode != RouteEmergency)) {
+ private_flag = TRUE;
+ }
+ return private_flag;
+}
+
+/*
+ * sipSPISetRPID
+ *
+ * Set the RPID header string sent in either a request or response.
+ */
+
+static int
+sipSPISetRPID (ccsipCCB_t *ccb, boolean request)
+{
+ const char *fname = "sipSPISetRPID";
+ int rpid_flag = RPID_DISABLED;
+ boolean private_flag;
+ size_t escaped_url_len;
+ char remote_party_id_buf[MAX_SIP_URL_LENGTH];
+ char line_name[MAX_LINE_NAME_SIZE];
+ char display_name[MAX_LINE_NAME_SIZE];
+ char src_addr_str[MAX_IPADDR_STR_LEN];
+ cpr_ip_type ip_type;
+
+ src_addr_str[0] = '\0';
+ config_get_value(CFGID_REMOTE_PARTY_ID, &rpid_flag, sizeof(rpid_flag));
+
+ if (rpid_flag != RPID_ENABLED) {
+ return RPID_DISABLED;
+ }
+
+ if (!ccb) {
+ CCSIP_DEBUG_ERROR("%s: Error: NULL ccb.\n", fname);
+ return rpid_flag;
+ }
+
+ /* If RPID string is already set, just return */
+ if (ccb->sip_remote_party_id[0]) {
+ return RPID_ENABLED;
+ }
+
+ private_flag = sipSPIIsPrivate(ccb);
+
+ config_get_string((CFGID_LINE_NAME + ccb->dn_line - 1), line_name,
+ sizeof(line_name));
+ sip_config_get_display_name(ccb->dn_line, display_name,
+ sizeof(display_name));
+
+ ip_type = sipTransportGetPrimServerAddress(ccb->dn_line, src_addr_str);
+
+ sstrncpy(remote_party_id_buf, "\"", MAX_SIP_URL_LENGTH);
+ escaped_url_len = 1;
+ escaped_url_len +=
+ sippmh_converQuotedStrToEscStr(display_name, strlen(display_name),
+ remote_party_id_buf + escaped_url_len,
+ MAX_SIP_URL_LENGTH - escaped_url_len,
+ TRUE) - 1;
+ sstrncat(remote_party_id_buf,"\" ;party=%s;id-type=subscriber;privacy=%s;screen=yes",
+ src_addr_str, (request ? "calling" : "called"),
+ (private_flag ? "full" : "off"));
+ } else {
+ snprintf(remote_party_id_buf + escaped_url_len,
+ MAX_SIP_URL_LENGTH - escaped_url_len,
+ "@%s>;party=%s;id-type=subscriber;privacy=%s;screen=yes",
+ src_addr_str, (request ? "calling" : "called"),
+ (private_flag ? "full" : "off"));
+ }
+
+ ccb->sip_remote_party_id = strlib_update(ccb->sip_remote_party_id,
+ remote_party_id_buf);
+
+ return RPID_ENABLED;
+}
+
+static void
+sipSPISetFrom (ccsipCCB_t *ccb)
+{
+ const char *fname = "sipSPISetFrom";
+ boolean private_flag;
+ size_t escaped_url_len;
+ char *sip_from_tag;
+ char *temp_from_tag;
+ char *sip_from_temp;
+ char line_name[MAX_LINE_NAME_SIZE];
+ char display_name[MAX_LINE_NAME_SIZE];
+ char dest_sip_addr_str[MAX_IPADDR_STR_LEN];
+ char *addr_str = 0;
+ char addr[MAX_IPADDR_STR_LEN];
+ cpr_ip_type ip_type = CPR_IP_ADDR_INVALID;
+
+ if (!ccb) {
+ CCSIP_DEBUG_ERROR("%s: Error: NULL ccb.\n", fname);
+ return;
+ }
+
+ ipaddr2dotted(dest_sip_addr_str, &ccb->dest_sip_addr);
+
+ if ((ccb->routeMode == RouteEmergency) ||
+ (ccb->proxySelection == SIP_PROXY_BACKUP)) {
+ addr_str = dest_sip_addr_str;
+ } else {
+ ip_type = sipTransportGetPrimServerAddress(ccb->dn_line, addr);
+ addr_str = addr;
+ }
+
+ sip_from_temp = strlib_open(ccb->sip_from, MAX_SIP_URL_LENGTH);
+
+ if (sip_from_temp == NULL) {
+ CCSIP_DEBUG_ERROR("%s: Error: sip_from_temp is NULL.\n", fname);
+ return;
+ }
+
+ private_flag = sipSPIIsPrivate(ccb);
+
+ if (private_flag == TRUE) {
+ if (ip_type == CPR_IP_ADDR_IPV6) {
+ snprintf(sip_from_temp, MAX_SIP_URL_LENGTH, "\"%s\" ",
+ SIP_HEADER_ANONYMOUS_STR, SIP_HEADER_ANONYMOUS_STR,
+ addr_str);
+ } else {
+ snprintf(sip_from_temp, MAX_SIP_URL_LENGTH, "\"%s\" ",
+ SIP_HEADER_ANONYMOUS_STR, SIP_HEADER_ANONYMOUS_STR,
+ addr_str);
+ }
+ } else {
+ /* From header needs to have global address in it */
+ config_get_string((CFGID_LINE_NAME + ccb->dn_line - 1), line_name,
+ sizeof(line_name));
+ sip_config_get_display_name(ccb->dn_line, display_name,
+ sizeof(display_name));
+ sstrncpy(sip_from_temp, "\"", MAX_SIP_URL_LENGTH);
+ escaped_url_len = 1;
+ escaped_url_len +=
+ sippmh_converQuotedStrToEscStr(display_name, strlen(display_name),
+ sip_from_temp + escaped_url_len,
+ MAX_SIP_URL_LENGTH - escaped_url_len,
+ TRUE) - 1;
+ sstrncat(sip_from_temp,"\" ",
+ addr_str);
+ } else {
+ snprintf(sip_from_temp + escaped_url_len,
+ MAX_SIP_URL_LENGTH - escaped_url_len, "@%s>",
+ addr_str);
+ }
+ }
+
+ /* Now add tag to the From header */
+ sstrncat(sip_from_temp, ";tag=",
+ MAX_SIP_URL_LENGTH - strlen(sip_from_temp));
+ temp_from_tag = ccsip_find_preallocated_sip_local_tag(ccb->dn_line);
+ sip_from_tag = strlib_open(ccb->sip_from_tag, MAX_SIP_URL_LENGTH);
+ if (temp_from_tag == NULL) {
+ if (sip_from_tag) {
+ sip_util_make_tag(sip_from_tag);
+ sstrncat(sip_from_temp, sip_from_tag,
+ MAX_SIP_URL_LENGTH - strlen(sip_from_temp));
+ }
+ } else {
+ if (sip_from_tag) {
+ sstrncpy(sip_from_tag, temp_from_tag, MAX_SIP_URL_LENGTH);
+ sstrncat(sip_from_temp, temp_from_tag,
+ MAX_SIP_URL_LENGTH - strlen(sip_from_temp));
+ }
+ ccsip_free_preallocated_sip_local_tag(ccb->dn_line);
+ }
+ ccb->sip_from_tag = strlib_close(sip_from_tag);
+ ccb->sip_from = strlib_close(sip_from_temp);
+}
+
+/*
+ * Send INVITE
+ *
+ * As the name suggests, called to send a SIP INVITE request.
+ * Assumes that
+ * - connection has been setup beforehand.
+ * - SDP description has been setup.
+ * Does not affect call state.
+ */
+boolean
+sipSPISendInvite (ccsipCCB_t *ccb, sipInviteType_t inviteType,
+ boolean initInvite)
+{
+ const char *fname = "SIPSPISendInvite";
+ sipMessage_t *request = NULL;
+ sipRet_t flag = STATUS_SUCCESS;
+ sipRet_t tflag = STATUS_SUCCESS;
+ char called_number[MAX_SIP_URL_LENGTH];
+ ccsipCCB_t *referccb = NULL;
+ boolean inviterefer = FALSE;
+ sipMessageFlag_t messageflag;
+ int i;
+ int rpid_flag;
+
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_MSG_SENDING_REQUEST),
+ fname, "INVITE");
+
+ if (ccb->wastransferred) {
+ inviterefer = TRUE;
+ }
+ // This routine can be called in three different contexts. These are the
+ // important differences between them:
+ // CONTEXT inviteType referccb
+ // -----------------------------------------------------------
+ // Normal SIP_INVITE_TYPE_NORMAL NULL
+ // Blind Xfer SIP_INVITE_TYPE_NORMAL valid
+ // Att Xfer SIP_INVITE_TYPE_TRANSFER valid
+
+ referccb = sip_sm_get_target_call_by_gsm_id(ccb->gsm_id);
+
+ // If there is a referccb, try to get authentication stuff from it
+ if (referccb != NULL) {
+ if (referccb->refer_proxy_auth != NULL) {
+ ccb->refer_proxy_auth = cpr_strdup(referccb->refer_proxy_auth);
+ }
+ }
+
+ if (inviteType == SIP_INVITE_TYPE_TRANSFER) {
+ // For attended transfers we need to make a local copy of the
+ // referccb if it exists
+ if (NULL != referccb) {
+ ccb->sip_referredBy = strlib_update(ccb->sip_referredBy,
+ referccb->sip_referredBy);
+ if (referccb->featuretype == CC_FEATURE_XFER) {
+ ccb->sipxfercallid = strlib_update(ccb->sipxfercallid,
+ referccb->sipxfercallid);
+ if (ccb->sipxfercallid) {
+ if (ccb->sipxfercallid[0] != '\0') {
+ ccb->wastransferred = TRUE;
+ inviterefer = TRUE;
+ }
+ }
+ }
+ }
+
+ if (inviterefer == FALSE) {
+ //Not enough information for starting attended transfer
+ CCSIP_DEBUG_ERROR("%s: Error:Replaces INVITE build unsuccessful.\n",
+ fname);
+ return (FALSE);
+ }
+ }
+
+ if (inviteType != SIP_INVITE_TYPE_REDIRECTED) {
+ ccb->sip_to = strlib_update(ccb->sip_to, ccb->calledNumber);
+ }
+
+
+ /*
+ * Set from header
+ */
+ sipSPISetFrom(ccb);
+
+ /*
+ * Set RPID header.
+ */
+ rpid_flag = sipSPISetRPID(ccb, TRUE);
+
+ /*
+ * The calledNumber needs to be rewritten with the backup proxy
+ * ip address if the backup proxy is active
+ */
+ if (ccb->proxySelection == SIP_PROXY_BACKUP) {
+ sstrncpy(called_number, ccb->calledDisplayedName, MAX_SIP_URL_LENGTH);
+
+ /*
+ * NOTE: Need to replace with new routine ???
+ */
+ if (called_number[0] != '\0') {
+ sip_sm_util_normalize_name(ccb, called_number);
+ }
+ }
+
+ // Add Create Request Here
+ messageflag.flags = 0;
+ messageflag.flags |= SIP_HEADER_ACCEPT_BIT |
+ SIP_HEADER_EXPIRES_BIT |
+ SIP_HEADER_CONTACT_BIT |
+ SIP_HEADER_DIVERSION_BIT |
+ SIP_HEADER_SUPPORTED_BIT |
+ SIP_HEADER_ALLOW_EVENTS_BIT |
+ SIP_HEADER_ALLOW_BIT |
+ SIP_HEADER_RECV_INFO_BIT |
+ SIP_HEADER_REQUIRE_BIT;
+
+ if (ccb->authen.authorization != NULL) {
+ messageflag.flags |= SIP_HEADER_AUTHENTICATION_BIT;
+ }
+ if (ccb->refer_proxy_auth != NULL) {
+ messageflag.flags |= SIP_HEADER_PROXY_AUTH_BIT;
+ }
+ if (ccb->sip_referredBy[0] != '\0') {
+ messageflag.flags |= SIP_HEADER_REFERRED_BY_BIT;
+ }
+ if (((TRUE == inviterefer) || (ccb->flags & SENT_INVITE_REPLACE)) &&
+ ('\0' != ccb->sipxfercallid[0])) {
+ messageflag.flags |= SIP_HEADER_REPLACES_BIT;
+ }
+ if (ccb->sip_reqby[0]) {
+ messageflag.flags |= SIP_HEADER_REQUESTED_BY_BIT;
+ }
+ if (rpid_flag == RPID_ENABLED) {
+ messageflag.flags |= SIP_HEADER_REMOTE_PARTY_ID_BIT;
+ }
+ if (ccb->out_call_info != NULL) {
+ messageflag.flags |= SIP_HEADER_CALL_INFO_BIT;
+ }
+ if (ccb->join_info != NULL) {
+ messageflag.flags |= SIP_HEADER_JOIN_INFO_BIT;
+ }
+
+ /* Write SDP */
+ messageflag.flags |= SIP_HEADER_CONTENT_TYPE_BIT;
+ request = GET_SIP_MESSAGE();
+ if (request == NULL) {
+ CCSIP_DEBUG_ERROR("%s: Error: Unable to allocate INVITE request\n",
+ fname);
+ return (FALSE);
+ }
+ messageflag.extflags = 0;
+ if (CreateRequest(ccb, messageflag, sipMethodInvite, request,
+ initInvite, 0)) {
+ tflag = HSTATUS_SUCCESS;
+ } else {
+ tflag = HSTATUS_FAILURE;
+ }
+ UPDATE_FLAGS(flag, tflag);
+
+ ccb->ReqURIOriginal = strlib_update(ccb->ReqURIOriginal, ccb->ReqURI);
+
+ /*
+ * If overloaded headers are present from the 302, add them to the
+ * Invite message
+ */
+ if ((ccb->redirect_info) &&
+ (ccb->redirect_info->sipContact->locations[0]->genUrl) &&
+ (ccb->redirect_info->sipContact->locations[0]->genUrl->u.sipUrl) &&
+ (ccb->redirect_info->sipContact->locations[0]->genUrl->u.sipUrl->headerp) &&
+ (inviteType == SIP_INVITE_TYPE_REDIRECTED)) {
+ for (i = 0;
+ i < ccb->redirect_info->sipContact->locations[0]->genUrl->u.sipUrl->num_headers;
+ i++) {
+ tflag = sippmh_add_text_header(request,
+ ccb->redirect_info->sipContact->locations[0]->genUrl->u.
+ sipUrl->headerp[i].attr,
+ ccb->redirect_info->sipContact->locations[0]->genUrl->u.
+ sipUrl->headerp[i].value);
+ UPDATE_FLAGS(flag, tflag);
+ }
+ }
+
+ if (flag != STATUS_SUCCESS) {
+ free_sip_message(request);
+ CCSIP_DEBUG_ERROR("%s: Error: INVITE message build unsuccessful.\n",
+ fname);
+ clean_method_request_trx(ccb, sipMethodInvite, TRUE);
+ return (FALSE);
+ }
+
+ ccb->retx_counter = 0;
+
+ if (SendRequest(ccb, request, sipMethodInvite, FALSE, TRUE, TRUE)
+ == FALSE) {
+ clean_method_request_trx(ccb, sipMethodInvite, TRUE);
+ return (FALSE);
+ } else {
+ return (TRUE);
+ }
+}
+
+sipRet_t
+sipSPIAddCallStats (ccsipCCB_t *ccb, sipMessage_t *msg)
+{
+ int call_stats_flag;
+ sipRet_t tflag = STATUS_SUCCESS;
+
+ config_get_value(CFGID_CALL_STATS, &call_stats_flag, sizeof(call_stats_flag));
+ if ((call_stats_flag) && (ccb->kfactor_ptr)) {
+ if (ccb->kfactor_ptr->rxstats[0] != NUL) {
+ tflag = sippmh_add_text_header(msg, SIP_RX_CALL_STATS, ccb->kfactor_ptr->rxstats);
+ }
+ if (ccb->kfactor_ptr->txstats[0] != NUL) {
+ tflag = sippmh_add_text_header(msg, SIP_TX_CALL_STATS, ccb->kfactor_ptr->txstats);
+ }
+ }
+ return tflag;
+}
+
+boolean
+sipSPISendInviteMidCall (ccsipCCB_t *ccb, boolean expires)
+{
+ const char *fname = "sipSPISendInviteMidCall";
+ sipMessage_t *request = NULL;
+ sipRet_t flag = STATUS_SUCCESS;
+ sipRet_t tflag = STATUS_SUCCESS;
+ sipMessageFlag_t messageflag;
+ int rpid_flag;
+
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_MSG_SENDING_REQUEST),
+ fname, "INVITE");
+
+ /*
+ * Build the request Here
+ */
+ messageflag.flags = 0;
+ messageflag.flags |= SIP_HEADER_CONTACT_BIT |
+ SIP_HEADER_ROUTE_BIT |
+ SIP_HEADER_CONTENT_TYPE_BIT |
+ SIP_HEADER_ACCEPT_BIT |
+ SIP_HEADER_SUPPORTED_BIT |
+ SIP_HEADER_ALLOW_EVENTS_BIT |
+ SIP_HEADER_ALLOW_BIT |
+ SIP_HEADER_RECV_INFO_BIT |
+ SIP_HEADER_REQUIRE_BIT;
+
+ if ((ccb->authen.authorization != NULL) &&
+ ((ccb->state == SIP_STATE_SENT_INVITE) ||
+ (ccb->state == SIP_STATE_SENT_MIDCALL_INVITE))) {
+ messageflag.flags |= SIP_HEADER_AUTHENTICATION_BIT;
+ }
+
+ if ((ccb->authen.authorization != NULL) &&
+ (ccb->state == SIP_STATE_SENT_INVITE)) {
+ if (ccb->join_info != NULL) {
+ messageflag.flags |= SIP_HEADER_JOIN_INFO_BIT;
+ }
+ }
+
+ if ('\0' != ccb->sipxfercallid[0]) {
+ messageflag.flags |= SIP_HEADER_REPLACES_BIT;
+ }
+
+ if (expires > 0) {
+ messageflag.flags |= SIP_HEADER_EXPIRES_BIT;
+ }
+
+ if (ccb->sip_referredBy[0]) {
+ messageflag.flags |= SIP_HEADER_REFERRED_BY_BIT;
+ }
+
+ /*
+ * Set RPID header.
+ */
+ rpid_flag = sipSPISetRPID(ccb, TRUE);
+ if (rpid_flag == RPID_ENABLED) {
+ messageflag.flags |= SIP_HEADER_REMOTE_PARTY_ID_BIT;
+ }
+
+ if (ccb->out_call_info) {
+ messageflag.flags |= SIP_HEADER_CALL_INFO_BIT;
+ }
+
+ request = GET_SIP_MESSAGE();
+ messageflag.extflags = 0;
+ if (CreateRequest(ccb, messageflag, sipMethodInvite, request, FALSE, 0)) {
+ tflag = HSTATUS_SUCCESS;
+ } else {
+ tflag = HSTATUS_FAILURE;
+ }
+
+ UPDATE_FLAGS(flag, tflag);
+
+
+ tflag = sipSPIAddCallStats(ccb, request);
+ UPDATE_FLAGS(flag, tflag);
+
+ /* Recalc and add Authorization header if needed */
+ if ((ccb->state != SIP_STATE_SENT_INVITE) &&
+ (ccb->state != SIP_STATE_SENT_MIDCALL_INVITE)) {
+ sipSPIGenerateGenAuthorizationResponse(ccb, request, &flag,
+ SIP_METHOD_INVITE);
+ }
+
+ /* Write SDP */
+ if (flag != STATUS_SUCCESS) {
+ free_sip_message(request);
+ CCSIP_DEBUG_ERROR("%s: Error: INVITE message build unsuccessful.\n",
+ fname);
+ clean_method_request_trx(ccb, sipMethodInvite, TRUE);
+ return (FALSE);
+ }
+ /*
+ * Currently the following field is being set to zero when the
+ * midcall invite is not being done as a response to an authorization
+ * challenge. So utilize this fact to prevent proxy backup selection
+ * on a mid-call invite. The end result is to stick with the same
+ * proxy as the original invite.
+ */
+ if (ccb->authen.cred_type == 0) {
+ ccb->proxySelection = SIP_PROXY_DO_NOT_CHANGE_MIDCALL;
+ }
+
+ /* Successfully constructed msg with new URI for this INVITE to send out.
+ * Update URIOriginal before sending out.
+ */
+ ccb->ReqURIOriginal = strlib_update(ccb->ReqURIOriginal, ccb->ReqURI);
+
+ /* Enable reTx and send */
+ ccb->retx_counter = 0;
+ if (SendRequest(ccb, request, sipMethodInvite, TRUE, TRUE, TRUE) == FALSE) {
+ clean_method_request_trx(ccb, sipMethodInvite, TRUE);
+ return (FALSE);
+ } else {
+ return (TRUE);
+ }
+}
+
+
+/*
+ * Sends the ACK request.
+ * Assumes that
+ * - the connection is setup.
+ * Appends session description if sd = TRUE. (This would
+ * be the case, if we want to change the codec that
+ * was sent on the INVITE.
+ * Does not affect call state.
+ */
+boolean
+sipSPISendAck (ccsipCCB_t *ccb, sipMessage_t *response)
+{
+ const char *fname = "sipSPISendAck";
+ sipMessage_t *request = NULL;
+ sipRet_t flag = STATUS_SUCCESS;
+ sipRet_t tflag = STATUS_SUCCESS;
+ sipMessageFlag_t messageflag;
+ uint32_t response_cseq_number = 0;
+ sipCseq_t *response_cseq_structure;
+ const char *response_cseq;
+ int16_t trx_index = -1;
+ boolean retval;
+ int rpid_flag;
+
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_MSG_SENDING_REQUEST),
+ fname, "ACK");
+
+ /*
+ * Build the request
+ */
+ messageflag.flags = 0;
+ messageflag.flags = SIP_HEADER_ROUTE_BIT |
+ SIP_HEADER_RECV_INFO_BIT;
+
+ /*
+ * Cseq number in the response could be different from that in ccb.
+ * If there was no response as in
+ * ccsip_handle_sentinviteconnected_ev_cc_connected_ack
+ * then use ccb for getting Cseq number
+ */
+ if (response) {
+ response_cseq = sippmh_get_cached_header_val(response, CSEQ);
+ if (!response_cseq) {
+ CCSIP_DEBUG_ERROR("%s: Error: Unable to obtain response CSeq "
+ "header.\n", fname);
+ return (FALSE);
+ }
+ response_cseq_structure = sippmh_parse_cseq(response_cseq);
+ if (!response_cseq_structure) {
+ CCSIP_DEBUG_ERROR("%s: Error: Unable to parse response CSeq "
+ "header.\n", fname);
+ return (FALSE);
+ }
+ response_cseq_number = response_cseq_structure->number;
+ cpr_free(response_cseq_structure);
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX"Cseq from response = %d \n",
+ DEB_F_PREFIX_ARGS(SIP_ACK, "sipSPISendAck"), response_cseq_number);
+ } else {
+ trx_index = get_method_request_trx_index(ccb, sipMethodInvite, TRUE);
+ if (trx_index < 0) {
+ return (FALSE);
+ }
+ response_cseq_number = ccb->sent_request[trx_index].cseq_number;
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX"Cseq from ccb = %d \n",
+ DEB_F_PREFIX_ARGS(SIP_ACK, "sipSPISendAck"), response_cseq_number);
+ }
+
+ messageflag.flags |= SIP_HEADER_CONTENT_LENGTH_BIT;
+ if (ccb->authen.authorization != NULL) {
+ messageflag.flags |= SIP_HEADER_AUTHENTICATION_BIT;
+ }
+
+ /*
+ * Set RPID header.
+ */
+ rpid_flag = sipSPISetRPID(ccb, TRUE);
+ if (rpid_flag == RPID_ENABLED) {
+ messageflag.flags |= SIP_HEADER_REMOTE_PARTY_ID_BIT;
+ }
+
+ request = GET_SIP_MESSAGE();
+ messageflag.extflags = 0;
+ if (CreateRequest(ccb, messageflag, sipMethodAck, request, FALSE,
+ response_cseq_number)) {
+ tflag = HSTATUS_SUCCESS;
+ } else {
+ tflag = HSTATUS_FAILURE;
+ }
+
+ UPDATE_FLAGS(flag, tflag);
+ /* If build error detected, cleanup and do not send message */
+ if (flag != STATUS_SUCCESS) {
+ /* !!! Clean up */
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_BUILDFLAG_ERROR), fname);
+ if (request)
+ free_sip_message(request);
+
+ clean_method_request_trx(ccb, sipMethodInvite, TRUE);
+ return (FALSE);
+ }
+
+ /* Send message */
+ retval = SendRequest(ccb, request, sipMethodAck, FALSE, FALSE, FALSE);
+
+ // We are done with this INVITE request so lets clear and reorder our
+ // cseq list of outstanding requests. Assumes that ACK will only be
+ // sent for INVITE. Also note that no trx block is allocated for Ack
+ // and so there is no need to free it.
+ clean_method_request_trx(ccb, sipMethodInvite, TRUE);
+ return (retval);
+}
+
+
+/*
+ * Sends the BYE request for the call.
+ * Assumes that
+ * - the connection is setup.
+ * Does not change the state, but changes the disconnection flags.
+ */
+void
+sipSPISendBye (ccsipCCB_t *ccb, char *alsoString, sipMessage_t *pForked200)
+{
+ const char *fname = "sipSPISendBye";
+ sipMessage_t *request = NULL;
+ sipRet_t flag = STATUS_SUCCESS;
+ sipRet_t tflag = STATUS_SUCCESS;
+ sipContact_t *stored_contact_info = NULL;
+ sipRecordRoute_t *stored_record_route_info = NULL;
+ static char stored_sip_to[MAX_SIP_URL_LENGTH];
+ static char stored_sip_from[MAX_SIP_URL_LENGTH];
+ static char last_route[MAX_SIP_URL_LENGTH];
+ const char *forked200_contact = NULL;
+ const char *forked200_record_route = NULL;
+ const char *forked200_to = NULL;
+ const char *forked200_from = NULL;
+ sipMessageFlag_t messageflag;
+
+
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_MSG_SENDING_REQUEST),
+ fname, "BYE");
+
+ /*
+ * If this BYE is in response to the secondary forked 200 OK message
+ * (from the callee being rejected), then we need to use the
+ * Contact and Record-Route of this 200 OK message, rather than the
+ * stored ccb->contact_info and ccb->record_route_info.
+ * So, if pForked200 exists, then we will:
+ * - save existing ccb->contact_info and ccb->record_route_info fields
+ * - parse Contact and Record-Route of the forked 200
+ * - use these values to form this BYE's Req-URI
+ * - restore the original ccb->contact_info and ccb->record_route_info
+ */
+ if (pForked200) {
+ stored_contact_info = ccb->contact_info;
+ stored_record_route_info = ccb->record_route_info;
+ sstrncpy(stored_sip_to, ccb->sip_to, MAX_SIP_URL_LENGTH);
+ sstrncpy(stored_sip_from, ccb->sip_from, MAX_SIP_URL_LENGTH);
+
+ forked200_contact = sippmh_get_cached_header_val(pForked200, CONTACT);
+ forked200_record_route =
+ sippmh_get_cached_header_val(pForked200, RECORD_ROUTE);
+ forked200_to = sippmh_get_cached_header_val(pForked200, TO);
+ forked200_from = sippmh_get_cached_header_val(pForked200, FROM);
+
+ if (forked200_contact) {
+ ccb->contact_info = sippmh_parse_contact(forked200_contact);
+ }
+ if (forked200_record_route) {
+ ccb->record_route_info =
+ sippmh_parse_record_route(forked200_record_route);
+ }
+ ccb->sip_to = strlib_update(ccb->sip_to, forked200_to);
+ ccb->sip_from = strlib_update(ccb->sip_from, forked200_from);
+ }
+
+ /*
+ * Build the request
+ */
+ messageflag.flags = 0;
+ messageflag.flags = SIP_HEADER_CONTENT_LENGTH_BIT;
+
+ request = GET_SIP_MESSAGE();
+ messageflag.extflags = 0;
+ if (CreateRequest(ccb, messageflag, sipMethodBye, request, FALSE, 0)) {
+ tflag = HSTATUS_SUCCESS;
+ } else {
+ tflag = HSTATUS_FAILURE;
+ }
+
+ UPDATE_FLAGS(flag, tflag);
+
+
+ /* add in call stats header if needed */
+ tflag = sipSPIAddCallStats(ccb, request);
+ UPDATE_FLAGS(flag, tflag);
+
+ if (alsoString) {
+ tflag = sippmh_add_text_header(request, SIP_HEADER_ALSO, alsoString);
+ UPDATE_FLAGS(flag, tflag);
+ }
+
+ memset(last_route, 0, MAX_SIP_URL_LENGTH);
+ tflag = (sipSPIAddRouteHeaders(request, ccb, last_route, MAX_SIP_URL_LENGTH)) ?
+ STATUS_SUCCESS : STATUS_FAILURE;
+ UPDATE_FLAGS(flag, tflag);
+ sipSPIGenerateGenAuthorizationResponse(ccb, request, &flag, SIP_METHOD_BYE);
+
+ /* If build error detected, cleanup and do not send message */
+ if (flag != STATUS_SUCCESS) {
+ /* !!! Clean up */
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_BUILDFLAG_ERROR), fname);
+ if (request)
+ free_sip_message(request);
+ if (alsoString)
+ cpr_free(alsoString);
+ clean_method_request_trx(ccb, sipMethodBye, TRUE);
+ return;
+ }
+
+ ccb->retx_counter = 0;
+ /* Send message */
+ (void) SendRequest(ccb, request, sipMethodBye, FALSE, TRUE, FALSE);
+
+ /*
+ * Update history
+ */
+ /* Record Also header if any */
+ if (alsoString) {
+ if (alsoString[0]) {
+ sstrncpy(gCallHistory[ccb->index].last_bye_also_string, alsoString,
+ MAX_SIP_URL_LENGTH);
+ }
+ cpr_free(alsoString);
+ } else {
+ memset(gCallHistory[ccb->index].last_bye_also_string, 0,
+ MAX_SIP_URL_LENGTH);
+ }
+
+ /* Record current Route */
+ if (last_route[0]) {
+ sstrncpy(gCallHistory[ccb->index].last_route, last_route,
+ MAX_SIP_URL_LENGTH);
+ } else {
+ memset(gCallHistory[ccb->index].last_route, 0, MAX_SIP_URL_LENGTH);
+ }
+ /* Record current Request-URI */
+ if (ccb->ReqURI[0]) {
+ sstrncpy(gCallHistory[ccb->index].last_route_request_uri, ccb->ReqURI,
+ MAX_SIP_URL_LENGTH);
+ } else {
+ memset(gCallHistory[ccb->index].last_route_request_uri, 0,
+ MAX_SIP_URL_LENGTH);
+ }
+
+// bugid: CSCsz34666
+// /*
+// * Store call history info
+// */
+// if ((int) (ccb->index) <= TEL_CCB_END) {
+// memcpy(gCallHistory[ccb->index].last_call_id, ccb->sipCallID,
+// MAX_SIP_CALL_ID);
+// }
+
+ /*
+ * Restore the original ccb->contact and ccb->record_route fields
+ */
+ if (pForked200) {
+ if (ccb->contact_info) {
+ sippmh_free_contact(ccb->contact_info);
+ }
+ ccb->contact_info = stored_contact_info;
+ if (ccb->record_route_info) {
+ sippmh_free_record_route(ccb->record_route_info);
+ }
+ ccb->record_route_info = stored_record_route_info;
+
+ ccb->sip_to = strlib_update(ccb->sip_to, stored_sip_to);
+ ccb->sip_from = strlib_update(ccb->sip_from, stored_sip_from);
+ }
+
+ return;
+}
+
+
+
+/*
+ * Sends the SIP CANCEL request, to disconnect a call that
+ * is not in the active state.
+ */
+void
+sipSPISendCancel (ccsipCCB_t *ccb)
+{
+ const char *fname = "sipSPISendCancel";
+ sipMessage_t *request = NULL;
+ sipRet_t flag = STATUS_SUCCESS;
+ sipRet_t tflag = STATUS_SUCCESS;
+ sipMessageFlag_t messageflag;
+ char *temp = NULL;
+ char local_cpy[MAX_SIP_URL_LENGTH];
+ string_t hold_to_tag = strlib_copy(ccb->sip_to);
+
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_MSG_SENDING_REQUEST),
+ fname, "CANCEL");
+
+ messageflag.flags = 0;
+ ccb->authen.cred_type = 0;
+
+ messageflag.flags = SIP_HEADER_CONTENT_LENGTH_BIT;
+
+ /* Remove the to_tag from the CANCEL message if present */
+ sstrncpy(local_cpy, ccb->sip_to, MAX_SIP_URL_LENGTH);
+ temp = strstr(local_cpy, ">");
+ if (temp != NULL) {
+ *(temp + 1) = '\0';
+ }
+ ccb->sip_to = strlib_update(ccb->sip_to, local_cpy);
+
+ request = GET_SIP_MESSAGE();
+ messageflag.extflags = 0;
+ if (CreateRequest(ccb, messageflag, sipMethodCancel, request, FALSE, 0)) {
+ tflag = HSTATUS_SUCCESS;
+ } else {
+ tflag = HSTATUS_FAILURE;
+ }
+
+ /* restore the to_tag if it was there */
+ if (hold_to_tag) {
+ ccb->sip_to = strlib_update(ccb->sip_to, hold_to_tag);
+ strlib_free(hold_to_tag);
+ }
+ hold_to_tag = strlib_empty();
+
+ UPDATE_FLAGS(flag, tflag);
+ /* Recalc and add Authorization header if needed */
+ sipSPIGenerateGenAuthorizationResponse(ccb, request, &flag,
+ SIP_METHOD_CANCEL);
+
+ /* If build error detected, cleanup and do not send message */
+ if (flag != STATUS_SUCCESS) {
+ /* !!! Clean up */
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_BUILDFLAG_ERROR), fname);
+ if (request)
+ free_sip_message(request);
+ clean_method_request_trx(ccb, sipMethodCancel, TRUE);
+ return;
+ }
+ /* Record current Request-URI */
+ if (ccb->ReqURI[0]) {
+ sstrncpy(gCallHistory[ccb->index].last_route_request_uri, ccb->ReqURI,
+ MAX_SIP_URL_LENGTH);
+ } else {
+ memset(gCallHistory[ccb->index].last_route_request_uri, 0,
+ MAX_SIP_URL_LENGTH);
+ }
+ if (SendRequest(ccb, request, sipMethodCancel, FALSE, TRUE, FALSE)
+ == FALSE) {
+ clean_method_request_trx(ccb, sipMethodCancel, TRUE);
+ return;
+ } else {
+ return;
+ }
+}
+
+void
+sip_platform_icmp_unreachable_callback (void *ccb, uint32_t ipaddr)
+{
+ static const char fname[] = "sip_platform_icmp_unreachable_callback";
+ uint32_t *icmp_msg;
+
+ icmp_msg = (uint32_t *) SIPTaskGetBuffer(sizeof(uint32_t));
+ if (!icmp_msg) {
+ CCSIP_DEBUG_ERROR("%s: Error: get buffer failed.\n", fname);
+ return;
+ }
+ *icmp_msg = ((ccsipCCB_t *)ccb)->index;
+
+ if (SIPTaskSendMsg(SIP_ICMP_UNREACHABLE, (cprBuffer_t)icmp_msg,
+ sizeof(uint32_t), (void *)(long)ipaddr) == CPR_FAILURE) {
+ CCSIP_DEBUG_ERROR("%s: Error: send msg failed.\n", fname);
+ cpr_free((cprBuffer_t)icmp_msg);
+ }
+ return;
+}
+
+/*
+ * Sends the SIP REFER request, to Transfer the call
+ *
+ * Parameters:
+ * ccb - reference tio the existing call control block
+ * referto - Dial string to make a call (If null it will pick up from ccb)
+ * referto_typ to indicate if the referto is trasnfer or token refer
+ *
+ */
+boolean
+sipSPISendRefer (ccsipCCB_t *ccb, char *referto, sipRefEnum_e referto_type)
+{
+ const char *fname = "sipSPISendRefer";
+ sipMessage_t *request = NULL;
+ sipRet_t flag = STATUS_SUCCESS;
+ sipRet_t tflag = STATUS_SUCCESS;
+ ccsipCCB_t *xfer_ccb = NULL;
+ char tempreferto[MAX_SIP_URL_LENGTH + 2];
+ char callid[MAX_SIP_HEADER_LENGTH + 2];
+ sipMessageFlag_t messageflag;
+ char *semi = NULL;
+ char *left_bracket = NULL;
+ char *right_bracket = NULL;
+ char *msg_referto = NULL;
+ string_t copy_of_referto = NULL;
+ int rpid_flag;
+ char *ref_to_callid = NULL;
+ const char *to_tag = NULL;
+ const char *from_tag = NULL;
+ boolean dm_info = FALSE;
+ sipJoinInfo_t join_info;
+
+ memset(&join_info, 0, sizeof(join_info));
+
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_MSG_SENDING_REQUEST),
+ fname, "REFER");
+ /*
+ * Build the request
+ */
+
+ if (sipSPIGenerateReferredByHeader(ccb) == FALSE) {
+ tflag = HSTATUS_FAILURE;
+ } else {
+ tflag = HSTATUS_SUCCESS;
+ }
+ UPDATE_FLAGS(flag, tflag);
+
+ messageflag.flags = 0;
+ /*
+ * Don't add the content length bit here. Content length
+ * needs to be the last in the header. TCP uses the content
+ * length to do framing.
+ */
+ messageflag.flags = SIP_HEADER_CONTACT_BIT | SIP_HEADER_ROUTE_BIT;
+
+ /*
+ * Set RPID header.
+ */
+ rpid_flag = sipSPISetRPID(ccb, TRUE);
+ if (rpid_flag == RPID_ENABLED) {
+ messageflag.flags |= SIP_HEADER_REMOTE_PARTY_ID_BIT;
+ }
+
+ if (referto) {
+ // Get a new call-id if this REFER is for fallback token registration
+ if (strncmp(referto, TOKEN_REFER_TO, sizeof(TOKEN_REFER_TO)) == 0) {
+ ccb->sipCallID[0] = '\0';
+ sip_util_get_new_call_id(ccb);
+ }
+ }
+
+ request = GET_SIP_MESSAGE();
+ messageflag.extflags = 0;
+ if (CreateRequest(ccb, messageflag, sipMethodRefer, request, FALSE, 0)) {
+ tflag = HSTATUS_SUCCESS;
+ } else {
+ tflag = HSTATUS_FAILURE;
+ }
+
+ UPDATE_FLAGS(flag, tflag);
+
+ /* Recalc and add Authorization header if needed */
+ sipSPIGenerateGenAuthorizationResponse(ccb, request, &flag,
+ SIP_METHOD_REFER);
+
+ memset(tempreferto, 0, MAX_SIP_URL_LENGTH + 2);
+ memset(callid, 0, MAX_SIP_HEADER_LENGTH + 2);
+
+ /* see if we have ;user= */
+ if (referto) {
+ semi = strchr(referto, ';');
+ }
+
+ if (CC_FEATURE_XFER == ccb->featuretype) {
+ // The con_call_id is filled up by GSM when it opens up the line This
+ // is used to cross reference the call_ids
+ xfer_ccb = sip_sm_get_ccb_by_target_call_id(ccb->con_call_id);
+
+ if (xfer_ccb != NULL) {
+ ref_to_callid = xfer_ccb->sipCallID;
+ to_tag = xfer_ccb->sip_to_tag;
+ from_tag = xfer_ccb->sip_from_tag;
+ }
+
+ if (xfer_ccb != NULL || dm_info == TRUE) {
+ int i = 0;
+
+ // Create Refer_to header with replace id (call_id of other call)
+ // and To-Tag of other call - escape the replaced callid
+ while (*ref_to_callid != '\0') {
+ if (*ref_to_callid != '@') {
+ callid[i++] = *ref_to_callid;
+ } else {
+ callid[i++] = '%';
+ callid[i++] = '4';
+ callid[i++] = '0';
+ }
+ ref_to_callid++;
+ }
+ callid[i] = '\0';
+
+ /* first get rid of opening and closing braces, if there */
+ copy_of_referto = strlib_copy(referto);
+ if (copy_of_referto) {
+ left_bracket = strpbrk(copy_of_referto, "<");
+ }
+ if (left_bracket) {
+ left_bracket++;
+ right_bracket = strchr(left_bracket, '>');
+ if (right_bracket) {
+ *right_bracket++ = 0;
+ }
+ msg_referto = left_bracket;
+ } else {
+ msg_referto = referto;
+ }
+ if (msg_referto) {
+ if (strncmp(msg_referto, "sip:", 4) == 0) {
+ snprintf(tempreferto, sizeof(tempreferto),
+ "<%s%c%s%c%s%%3B%s%%3D%s%%3B%s%%3D%s>",
+ msg_referto, QUESTION_MARK,
+ SIP_HEADER_REPLACES, EQUAL_SIGN, callid,
+ TO_TAG, to_tag,
+ FROM_TAG, from_tag);
+ } else {
+ snprintf(tempreferto, sizeof(tempreferto),
+ "",
+ msg_referto, QUESTION_MARK,
+ SIP_HEADER_REPLACES, EQUAL_SIGN, callid,
+ TO_TAG, to_tag,
+ FROM_TAG, from_tag);
+ }
+ }
+ strlib_free(copy_of_referto);
+ }
+
+ if (dm_info) {
+ cpr_free(join_info.call_id);
+ cpr_free(join_info.to_tag);
+ cpr_free(join_info.from_tag);
+ }
+
+ tflag = sippmh_add_text_header(request, SIP_HEADER_REFER_TO,
+ ((NULL != xfer_ccb)|| (dm_info == TRUE)) ? tempreferto : referto);
+ UPDATE_FLAGS(flag, tflag);
+ } else {
+ if (referto) {
+ if ((strncmp(referto, "",
+ referto);
+ } else {
+ snprintf(tempreferto, sizeof(tempreferto), "sip:%s",
+ referto);
+ }
+ }
+ }
+ tflag = sippmh_add_text_header(request, SIP_HEADER_REFER_TO,
+ tempreferto);
+ UPDATE_FLAGS(flag, tflag);
+ }
+
+ ccb->sip_referTo = strlib_update(ccb->sip_referTo, referto);
+ tflag = sippmh_add_text_header(request, SIP_HEADER_REFERRED_BY,
+ ccb->sip_referredBy);
+ if (tflag != HSTATUS_SUCCESS) {
+ return FALSE;
+ }
+ /* If build error detected, cleanup and do not send message */
+ if (flag != STATUS_SUCCESS) {
+ /* !!! Clean up */
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_BUILDFLAG_ERROR), fname);
+ if (request)
+ free_sip_message(request);
+ clean_method_request_trx(ccb, sipMethodRefer, TRUE);
+ return (FALSE);
+ }
+// cpr_free(referto);
+
+ /*
+ * Add the content length now.
+ */
+ tflag = sippmh_add_int_header(request, SIP_HEADER_CONTENT_LENGTH, 0);
+ UPDATE_FLAGS(flag, tflag);
+
+ /* If build error detected, cleanup and do not send message */
+ if (flag != STATUS_SUCCESS) {
+ /* !!! Clean up */
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_BUILDFLAG_ERROR), fname);
+ if (request) {
+ free_sip_message(request);
+ }
+ return FALSE;
+ }
+
+ ccb->retx_counter = 0;
+
+ if (SendRequest(ccb, request, sipMethodRefer, FALSE, TRUE, FALSE) == FALSE) {
+ clean_method_request_trx(ccb, sipMethodRefer, TRUE);
+ return (FALSE);
+ } else {
+ return (TRUE);
+ }
+}
+
+/*
+ * Sends the Notify
+ * Will be sent when we get OK from target (in case of Refer)
+ *
+ * Note: Assumes that the connection is setup.
+ *
+ * Parameter:
+ * ccb - call control block
+ * response
+*/
+boolean
+sipSPISendNotify (ccsipCCB_t *ccb, int response)
+{
+ const char *fname = "sipSPISendNotify";
+ sipMessage_t *request = NULL;
+ sipRet_t flag = STATUS_SUCCESS;
+ sipRet_t tflag = STATUS_SUCCESS;
+ sipMessageFlag_t messageflag;
+ char *body;
+ char errortext[MAX_SIP_URL_LENGTH];
+ char subs_state_hdr[SUBS_STATE_HDR_LEN];
+ int respClass;
+
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_MSG_SENDING_REQUEST),
+ fname, "Notify");
+
+ /*
+ * Clean up any remaining transactions before sending the next request.
+ * Normally the transactions are cleaned after final responses (200OK)
+ * and if not they will be cleaned after the timeouts. Currently for
+ * NOTIFYs there are not timeout cleanups, so we will explicitly clean
+ * any outstanding transactions now before the next request.
+ *
+ * This fix works today because we don't really care about any responses
+ * to NOTIFY requests and do not act on them. The transaction layer should
+ * be enhanced to handles these cases. This should be addressed under the
+ * Ringpops feature.
+ */
+ clean_method_request_trx(ccb, sipMethodNotify, TRUE);
+
+ /*
+ * Before we do the real notify work, we may need to clean up the
+ * refer proxy authorization stuff that may have been left laying around
+ * during the transfer.
+ *
+ * This is the Proxy-Authorization that came in the REFER's Refer-To
+ * as an escaped header and therefore should only be alive till the
+ * transfer is done.
+ *
+ * But we have to do this only if we are sending the last notify for
+ * a REFER, i.e. if we are sending the last sipfrag. For ex:
+ * "200 OK", or "404 Not Found". We have to check for this because
+ * after sending a NOTIFY("100 Trying") to the Transferor we send an
+ * INVITE to the target and the Proxy-Authorization is required. When
+ * we send a NOTIFY indicating success or failure, we can remove the
+ * refer_proxy_auth in both ccbs.
+ */
+ respClass = response / 100;
+ if (respClass >= 2) {
+ if (ccb->refer_proxy_auth) {
+ ccsipCCB_t *other_ccb;
+
+ cpr_free(ccb->refer_proxy_auth);
+ ccb->refer_proxy_auth = NULL;
+ // now, find the ccb of the call we transferred to....
+ other_ccb = sip_sm_get_ccb_by_callid(ccb->sipxfercallid);
+ if (other_ccb != NULL) {
+ if (other_ccb->refer_proxy_auth) {
+ cpr_free(other_ccb->refer_proxy_auth);
+ other_ccb->refer_proxy_auth = NULL;
+ }
+ }
+ }
+ }
+
+ /*
+ * Build the request
+ */
+ // The addition of the CSeq method will be done when CSeq number is added
+ // ccb->last_sent_request_cseq_method = sipMethodNotify;
+ messageflag.flags = 0;
+ messageflag.flags = SIP_HEADER_ROUTE_BIT | SIP_HEADER_CONTACT_BIT;
+
+ request = GET_SIP_MESSAGE();
+ messageflag.extflags = 0;
+ if (CreateRequest(ccb, messageflag, sipMethodNotify, request, FALSE, 0)) {
+ tflag = HSTATUS_SUCCESS;
+ } else {
+ tflag = HSTATUS_FAILURE;
+ }
+
+ UPDATE_FLAGS(flag, tflag);
+
+ tflag = sippmh_add_text_header(request, SIP_HEADER_EVENT, SIP_EVENT_REFER);
+ UPDATE_FLAGS(flag, tflag);
+
+ // Add Subscription-State header
+ if (ccb->flags & FINAL_NOTIFY) {
+ snprintf(subs_state_hdr, SUBS_STATE_HDR_LEN,
+ "terminated; reason=noresource");
+ } else {
+ uint32_t expires_timeout = 0;
+
+ config_get_value(CFGID_TIMER_INVITE_EXPIRES, &expires_timeout,
+ sizeof(expires_timeout));
+ snprintf(subs_state_hdr, SUBS_STATE_HDR_LEN, "active; expires=%d",
+ expires_timeout);
+ }
+ tflag = sippmh_add_text_header(request, SIP_HEADER_SUBSCRIPTION_STATE,
+ subs_state_hdr);
+ UPDATE_FLAGS(flag, tflag);
+
+ /* Recalc and add Authorization header if needed */
+ sipSPIGenerateGenAuthorizationResponse(ccb, request, &flag,
+ SIP_METHOD_NOTIFY);
+
+ /* If build error detected, cleanup and do not send message */
+ if (flag != STATUS_SUCCESS) {
+ /* !!! Clean up */
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_BUILDFLAG_ERROR), fname);
+ if (request) {
+ free_sip_message(request);
+ }
+ clean_method_request_trx(ccb, sipMethodNotify, TRUE);
+ return (FALSE);
+ }
+
+ /* Write message */
+ /*
+ * Currently the only notify message the phone sends is with respect
+ * to refer. This routine looks like a general send notify routine.
+ * One would assume then there needs to be some sort of if (refer)
+ * check to cause it to send "message/sipfrag" otherwise send
+ * "application/sip"
+ */
+// tflag = sippmh_add_text_header(request, SIP_HEADER_CONTENT_TYPE,
+// SIP_CONTENT_TYPE_SIP );
+ // Don't add content-type explicitly
+ // tflag = sippmh_add_text_header(request, SIP_HEADER_CONTENT_TYPE,
+ // SIP_CONTENT_TYPE_SIPFRAG );
+// UPDATE_FLAGS(flag, tflag);
+
+ body = (char *) cpr_malloc(MAX_SIP_URL_LENGTH * sizeof(char));
+ if (!body) {
+ if (request) {
+ free_sip_message(request);
+ }
+ clean_method_request_trx(ccb, sipMethodNotify, TRUE);
+ return FALSE;
+ }
+ memset(errortext, 0, MAX_SIP_URL_LENGTH);
+ get_sip_error_string(errortext, response);
+ snprintf(body, MAX_SIP_URL_LENGTH, "%s %d %s\r\n", SIP_VERSION,
+ response, errortext);
+
+ tflag = sippmh_add_message_body(request, body, strlen(body),
+ SIP_CONTENT_TYPE_SIPFRAG,
+ SIP_CONTENT_DISPOSITION_SESSION_VALUE,
+ TRUE, NULL);
+ UPDATE_FLAGS(flag, tflag);
+
+ // No need to add header length separately
+ // tflag = sippmh_add_int_header(request, SIP_HEADER_CONTENT_LENGTH,
+ // strlen(message_body));
+ // UPDATE_FLAGS(flag, tflag);
+
+
+ /* If build error detected, cleanup and do not send message */
+ if (flag != STATUS_SUCCESS) {
+ /* !!! Clean up */
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_BUILDFLAG_ERROR), fname);
+ if (request) {
+ free_sip_message(request);
+ }
+ clean_method_request_trx(ccb, sipMethodNotify, TRUE);
+ return (FALSE);
+ }
+
+ ccb->retx_counter = 0;
+
+ if (SendRequest(ccb, request, sipMethodNotify, FALSE, TRUE, FALSE) == FALSE) {
+ clean_method_request_trx(ccb, sipMethodNotify, TRUE);
+ return (FALSE);
+ } else {
+ return (TRUE);
+ }
+}
+
+/*
+ * Sends the Info
+ *
+ * Note: Assumes that the connection is setup.
+ *
+ * Parameter:
+ * ccb - call control block
+ * info_package - the Info-Package header of the Info Package
+ * content_type - the Content-Type header of the Info Package
+ * message_body - the message body of the Info Package
+*/
+boolean
+sipSPISendInfo (ccsipCCB_t *ccb, const char *info_package,
+ const char *content_type, const char *message_body)
+{
+ const char *fname = "sipSPISendInfo";
+ sipMessage_t *request = NULL;
+ sipRet_t flag = STATUS_SUCCESS;
+ sipRet_t tflag = STATUS_SUCCESS;
+ sipMessageFlag_t messageflag;
+ char *body;
+ boolean retval;
+
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_MSG_SENDING_REQUEST),
+ fname, "Info");
+
+ /*
+ * Build the request
+ */
+ messageflag.flags = 0;
+ messageflag.flags = SIP_HEADER_ROUTE_BIT | SIP_HEADER_CONTACT_BIT;
+
+ request = GET_SIP_MESSAGE();
+ messageflag.extflags = 0;
+ if (CreateRequest(ccb, messageflag, sipMethodInfo, request, FALSE, 0)) {
+ tflag = HSTATUS_SUCCESS;
+ } else {
+ tflag = HSTATUS_FAILURE;
+ }
+
+ UPDATE_FLAGS(flag, tflag);
+
+ /* FIXME Media Control currently does not follow the offer/offer
+ negotiation process outlined in IETF draft
+ draft-ietf-sip-info-events-01, so do not add Info-Package
+ header field if it's Media Control Info Package. */
+ if (cpr_strncasecmp(content_type, SIP_CONTENT_TYPE_MEDIA_CONTROL,
+ strlen(SIP_CONTENT_TYPE_MEDIA_CONTROL)) != 0) {
+ tflag = sippmh_add_text_header(request, SIP_HEADER_INFO_PACKAGE, info_package);
+ UPDATE_FLAGS(flag, tflag);
+ }
+
+ /* If build error detected, cleanup and do not send message */
+ if (flag != STATUS_SUCCESS) {
+ /* !!! Clean up */
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_BUILDFLAG_ERROR), fname);
+ if (request) {
+ free_sip_message(request);
+ }
+ return FALSE;
+ }
+
+ body = (char *) cpr_malloc((strlen(message_body) + 1) * sizeof(char));
+ if (!body) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_MEMORY_OUT_OF_MEM), fname);
+ if (request) {
+ free_sip_message(request);
+ }
+ return FALSE;
+ }
+ memcpy(body, message_body, strlen(message_body) + 1);
+
+ tflag = sippmh_add_message_body(request, body, strlen(body),
+ content_type,
+ SIP_CONTENT_DISPOSITION_SESSION_VALUE,
+ TRUE, NULL);
+ flag = tflag;
+
+ /* If build error detected, cleanup and do not send message */
+ if (flag != STATUS_SUCCESS) {
+ /* !!! Clean up */
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_BUILDFLAG_ERROR), fname);
+ cpr_free(body);
+ if (request) {
+ free_sip_message(request);
+ }
+ return FALSE;
+ }
+
+ retval = SendRequest(ccb, request, sipMethodInfo, TRUE, FALSE, FALSE);
+
+ // Don't keep the trx so as not to mess up the retran timer of other requests
+ /*
+ * FIXME fix it when the framework is modified to support concurrent requests
+ */
+ clean_method_request_trx(ccb, sipMethodInfo, TRUE);
+
+ return retval;
+}
+
+/*
+ * Sends the BYE or CANCEL response for the call.
+ * Assumes that
+ * - the connection is setup.
+ */
+boolean
+sipSPISendByeOrCancelResponse (ccsipCCB_t *ccb, sipMessage_t *request,
+ sipMethod_t sipMethodByeorCancel)
+{
+ const char *fname = "sipSPISendByeResponse";
+ sipMessage_t *response = NULL;
+ sipRet_t flag = STATUS_SUCCESS;
+ sipMessageFlag_t messageflag;
+ boolean result;
+
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_MSG_SENDING_RESPONSE),
+ fname, 200);
+
+ messageflag.flags = 0;
+ messageflag.flags = SIP_HEADER_CONTENT_LENGTH_BIT;
+
+ response = GET_SIP_MESSAGE();
+ messageflag.extflags = 0;
+ if (CreateResponse(ccb, messageflag, SIP_STATUS_SUCCESS, response,
+ SIP_SUCCESS_SETUP_PHRASE, 0, NULL, sipMethodByeorCancel)) {
+ flag = HSTATUS_SUCCESS;
+ } else {
+ flag = HSTATUS_FAILURE;
+ }
+
+ /* send call stats on BYE response */
+ if ((flag == STATUS_SUCCESS) && (sipMethodByeorCancel == sipMethodBye)) {
+ flag = sipSPIAddCallStats(ccb, response);
+ }
+
+ /* If build error detected, cleanup and do not send message */
+ if (flag != STATUS_SUCCESS) {
+ /* !!! Clean up */
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_BUILDFLAG_ERROR), fname);
+ if (response) {
+ free_sip_message(response);
+ }
+ clean_method_request_trx(ccb, sipMethodByeorCancel, FALSE);
+ return (FALSE);
+ }
+ result = sendResponse(ccb, response, request, FALSE, sipMethodByeorCancel);
+ clean_method_request_trx(ccb, sipMethodByeorCancel, FALSE);
+ return (result);
+}
+
+
+
+/*
+ * Send 100 TRYING
+ */
+void
+sipSPISendInviteResponse100 (ccsipCCB_t *ccb, boolean remove_to_tag)
+{
+ char *temp = NULL;
+ char local_cpy[MAX_SIP_URL_LENGTH];
+ string_t hold_to_tag = NULL;
+
+ if (remove_to_tag) {
+ hold_to_tag = strlib_copy(ccb->sip_to);
+
+ /* remove the to_tag from the 100 Trying message */
+ sstrncpy(local_cpy, ccb->sip_to, MAX_SIP_URL_LENGTH);
+ temp = strstr(local_cpy, ">");
+ if (temp != NULL) {
+ *(temp + 1) = '\0';
+ }
+ ccb->sip_to = strlib_update(ccb->sip_to, local_cpy);
+ }
+
+ sipSPISendInviteResponse(ccb, SIP_1XX_TRYING, SIP_1XX_TRYING_PHRASE,
+ 0, NULL, FALSE, /* no SDP */
+ FALSE /* no reTx */);
+
+ if (hold_to_tag) {
+ ccb->sip_to = strlib_update(ccb->sip_to, hold_to_tag);
+ strlib_free(hold_to_tag);
+ }
+}
+
+
+/*
+ * Send 180 RINGING
+ */
+void
+sipSPISendInviteResponse180 (ccsipCCB_t *ccb)
+{
+ sipSPISendInviteResponse(ccb, SIP_1XX_RINGING,
+ SIP_1XX_RINGING_PHRASE, 0, NULL,
+ (boolean)(ccb->flags & INBAND_ALERTING),
+ FALSE /* no reTx */);
+}
+
+
+/*
+ * Send 200 OK
+ */
+void
+sipSPISendInviteResponse200 (ccsipCCB_t *ccb)
+{
+ sipSPISendInviteResponse(ccb, SIP_STATUS_SUCCESS,
+ SIP_SUCCESS_SETUP_PHRASE, 0, NULL,
+ TRUE, TRUE /* reTx */);
+}
+
+void
+sipSPISendInviteResponse302 (ccsipCCB_t *ccb)
+{
+
+ sipSPISendInviteResponse(ccb, SIP_RED_MOVED_TEMP,
+ SIP_RED_MOVED_TEMP_PHRASE,
+ 0, NULL, FALSE, /* no SDP */
+ TRUE /* reTx */);
+}
+
+/*Send Option Response
+ * - connection is set up.
+ * Currently just gives the methods supported
+ * Does not affect call state.
+*/
+boolean
+sipSPISendOptionResponse (ccsipCCB_t *ccb, sipMessage_t *request)
+{
+ const char *fname = "SIPSPISendOptionResponse";
+ sipMessage_t *response = NULL;
+ sipRet_t flag = STATUS_SUCCESS;
+ sipMessageFlag_t messageflag;
+ boolean result;
+
+ messageflag.flags = 0;
+ messageflag.flags = SIP_HEADER_CONTACT_BIT |
+ SIP_HEADER_RECORD_ROUTE_BIT |
+ SIP_HEADER_ALLOW_BIT |
+ SIP_HEADER_ACCEPT_BIT |
+ SIP_HEADER_ACCEPT_ENCODING_BIT |
+ SIP_HEADER_ACCEPT_LANGUAGE_BIT |
+ SIP_HEADER_SUPPORTED_BIT;
+
+ /* Write SDP */
+ messageflag.flags |= SIP_HEADER_OPTIONS_CONTENT_TYPE_BIT;
+
+ response = GET_SIP_MESSAGE();
+ messageflag.extflags = 0;
+ if (CreateResponse(ccb, messageflag, SIP_STATUS_SUCCESS, response,
+ SIP_SUCCESS_SETUP_PHRASE, 0, NULL, sipMethodOptions)) {
+ flag = HSTATUS_SUCCESS;
+ } else {
+ flag = HSTATUS_FAILURE;
+ }
+
+ /* If build error detected, cleanup and do not send message */
+ if (flag != STATUS_SUCCESS) {
+ /* !!! Clean up */
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_BUILDFLAG_ERROR), fname);
+ if (response) {
+ free_sip_message(response);
+ }
+ clean_method_request_trx(ccb, sipMethodOptions, FALSE);
+ return (FALSE);
+ }
+ result = sendResponse(ccb, response, request, FALSE, sipMethodOptions);
+ clean_method_request_trx(ccb, sipMethodOptions, FALSE);
+ return (result);
+}
+
+/*
+ * The function below handles an OPTIONS message not associated with
+ * any ongoing dialog and serves for the phone to gather capabilities
+ * of its server
+ */
+boolean
+sipSPIsendNonActiveOptionResponse (sipMessage_t *msg,
+ cc_msgbody_info_t *local_msg_body)
+{
+ const char *fname = "sipSPIsendNonActiveOptionResponse";
+ sipMessage_t *response = NULL;
+ sipRet_t flag = STATUS_SUCCESS;
+ sipRet_t tflag = STATUS_SUCCESS;
+ const char *sip_from = NULL;
+ const char *sip_to = NULL;
+ const char *request_callid = NULL;
+ const char *request_cseq = NULL;
+ sipCseq_t *request_cseq_structure = NULL;
+ char temp[MAX_SIP_HEADER_LENGTH];
+ sipLocation_t *to_loc = NULL;
+ char sip_to_tag[MAX_SIP_TAG_LENGTH];
+ char sip_to_temp[MAX_SIP_URL_LENGTH];
+ sipLocation_t *from_loc = NULL;
+ boolean request_uri_error = FALSE;
+ sipReqLine_t *requestURI = NULL;
+ sipLocation_t *uri_loc = NULL;
+ const char *accept_hdr = NULL;
+ const char *supported = NULL;
+ int kpml_config;
+
+ if (!msg) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_BADARGUMENT),
+ fname, "msg");
+ return (FALSE);
+ }
+
+ // Parse through the Accept header to get the supported capabilities
+ accept_hdr = sippmh_get_header_val(msg, SIP_HEADER_ACCEPT, NULL);
+ if (accept_hdr) {
+ server_caps = sippmh_parse_accept_header(accept_hdr);
+ }
+
+ // Parse through the Supported header to get the supported capabilities
+ supported = sippmh_get_cached_header_val(msg, SUPPORTED);
+ if (supported) {
+ sippmh_parse_supported_require(supported, NULL);
+ }
+
+ response = GET_SIP_MESSAGE();
+ if (!response) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "GET_SIP_MESSAGE()");
+ return (FALSE);
+ }
+
+ sip_from = sippmh_get_cached_header_val(msg, FROM);
+ sip_to = sippmh_get_cached_header_val(msg, TO);
+ sstrncpy(sip_to_temp, sip_to, MAX_SIP_URL_LENGTH);
+ request_callid = sippmh_get_cached_header_val(msg, CALLID);
+
+ requestURI = sippmh_get_request_line(msg);
+ if (requestURI) {
+ if (requestURI->url) {
+ uri_loc = sippmh_parse_from_or_to(requestURI->url, TRUE);
+ if (uri_loc) {
+ if (uri_loc->genUrl->schema != URL_TYPE_SIP) {
+ request_uri_error = TRUE;
+ }
+ sippmh_free_location(uri_loc);
+ } else {
+ request_uri_error = TRUE;
+ }
+ } else {
+ request_uri_error = TRUE;
+ }
+ SIPPMH_FREE_REQUEST_LINE(requestURI);
+ } else {
+ request_uri_error = TRUE;
+ }
+ if (request_uri_error) {
+ CCSIP_DEBUG_ERROR("%s: Error: Invalid Request URI failed.\n", fname);
+ free_sip_message(response);
+ /* Send 400 error */
+ if (sipSPISendErrorResponse(msg, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ SIP_WARN_MISC,
+ SIP_CLI_ERR_BAD_REQ_REQLINE_ERROR,
+ NULL) != TRUE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
+ fname, SIP_CLI_ERR_BAD_REQ);
+ }
+ return (FALSE);
+ }
+
+
+ /*
+ * Parse From
+ */
+ from_loc = sippmh_parse_from_or_to((char *)sip_from, TRUE);
+ if (!from_loc) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname,
+ get_debug_string(DEBUG_FUNCTIONNAME_SIPPMH_PARSE_FROM));
+ free_sip_message(response);
+ /* Send 400 error */
+ if (sipSPISendErrorResponse(msg, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ SIP_WARN_MISC,
+ SIP_CLI_ERR_BAD_REQ_FROMURL_ERROR,
+ NULL) != TRUE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
+ fname, SIP_CLI_ERR_BAD_REQ);
+ }
+ return (FALSE);
+ }
+
+ /*
+ * From is parsed just to make sure we got valid From
+ * Header, so we free it now
+ */
+ sippmh_free_location(from_loc);
+
+ /*
+ * Parse To
+ */
+ to_loc = sippmh_parse_from_or_to((char *)sip_to, TRUE);
+ if (!to_loc) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname,
+ get_debug_string(DEBUG_FUNCTIONNAME_SIPPMH_PARSE_TO));
+ if (response) {
+ free_sip_message(response);
+ }
+ /* Send 400 error */
+ if (sipSPISendErrorResponse(msg, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ SIP_WARN_MISC,
+ SIP_CLI_ERR_BAD_REQ_ToURL_ERROR,
+ NULL) != TRUE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
+ fname, SIP_CLI_ERR_BAD_REQ);
+ }
+ return (FALSE);
+ }
+
+ /* Check/Generate tags */
+ if (to_loc->tag) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED), NULL,
+ NULL, fname, "Initial Option with to_tag");
+ if (response) {
+ free_sip_message(response);
+ }
+ if (sipSPISendErrorResponse(msg, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ SIP_WARN_MISC,
+ SIP_CLI_ERR_BAD_REQ_ToURL_ERROR,
+ NULL) != TRUE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
+ fname, SIP_CLI_ERR_BAD_REQ);
+ }
+ sippmh_free_location(to_loc);
+ return (FALSE);
+ } else {
+ sip_util_make_tag(sip_to_tag);
+ sstrncat(sip_to_temp, ";tag=",
+ sizeof(sip_to_temp) - strlen(sip_to_temp));
+ sstrncat(sip_to_temp, sip_to_tag,
+ sizeof(sip_to_temp) - strlen(sip_to_temp));
+ }
+ sippmh_free_location(to_loc);
+
+ tflag = sippmh_add_response_line(response, SIP_VERSION, SIP_STATUS_SUCCESS,
+ SIP_SUCCESS_SETUP_PHRASE);
+ UPDATE_FLAGS(flag, tflag);
+ tflag = (sipSPIAddRequestVia(NULL, response, msg, sipMethodOptions)) ?
+ STATUS_SUCCESS : STATUS_FAILURE;
+ UPDATE_FLAGS(flag, tflag);
+ tflag = sippmh_add_text_header(response, SIP_HEADER_FROM, sip_from);
+ UPDATE_FLAGS(flag, tflag);
+ tflag = sippmh_add_text_header(response, SIP_HEADER_TO, sip_to_temp);
+ UPDATE_FLAGS(flag, tflag);
+ tflag = sippmh_add_text_header(response, SIP_HEADER_CALLID, request_callid);
+ UPDATE_FLAGS(flag, tflag);
+
+ // Add date header
+ tflag = sipAddDateHeader(response);
+ UPDATE_FLAGS(flag, tflag);
+ /* Write CSeq */
+ request_cseq = sippmh_get_cached_header_val(msg, CSEQ);
+ if (request_cseq) {
+ request_cseq_structure = sippmh_parse_cseq(request_cseq);
+ if (!request_cseq_structure) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sippmh_parse_cseq()");
+ free_sip_message(response);
+ /*
+ * We should send 400 here but as we don't have Cseq this
+ * is not possible.
+ */
+ return FALSE;
+ }
+ if (request_cseq_structure->method != sipMethodOptions) {
+ CCSIP_DEBUG_ERROR("%s: Error: Invalid method in Cseq failed.\n",
+ fname);
+ free_sip_message(response);
+ /* Send 400 error */
+ if (sipSPISendErrorResponse(msg, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ SIP_WARN_MISC,
+ SIP_CLI_ERR_BAD_REQ_VIA_OR_CSEQ,
+ NULL) != TRUE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
+ fname, SIP_CLI_ERR_BAD_REQ);
+ }
+ cpr_free(request_cseq_structure);
+ return FALSE;
+ }
+ tflag = sippmh_add_text_header(response, SIP_HEADER_CSEQ, request_cseq);
+ cpr_free(request_cseq_structure);
+ UPDATE_FLAGS(flag, tflag);
+ }
+
+ tflag = sippmh_add_text_header(response, SIP_HEADER_SERVER,
+ sipHeaderServer);
+
+ UPDATE_FLAGS(flag, tflag);
+
+ /*
+ * Add the local sdp we got from gsm into the response
+ */
+ tflag = CopyLocalSDPintoResponse(response, local_msg_body);
+ UPDATE_FLAGS(flag, tflag);
+
+ // Add Allow
+ snprintf(temp, MAX_SIP_HEADER_LENGTH, "%s,%s,%s,%s,%s,%s,%s,%s,%s",
+ SIP_METHOD_ACK, SIP_METHOD_BYE, SIP_METHOD_CANCEL,
+ SIP_METHOD_INVITE, SIP_METHOD_NOTIFY, SIP_METHOD_OPTIONS,
+ SIP_METHOD_REFER, SIP_METHOD_REGISTER, SIP_METHOD_UPDATE);
+ tflag = sippmh_add_text_header(response, SIP_HEADER_ALLOW, temp);
+ UPDATE_FLAGS(flag, tflag);
+
+ // Add Allow-Events
+ config_get_value(CFGID_KPML_ENABLED, &kpml_config, sizeof(kpml_config));
+ if (kpml_config) {
+ snprintf(temp, MAX_SIP_HEADER_LENGTH, "%s,%s,%s", SIP_EVENT_KPML,
+ SIP_EVENT_DIALOG, SIP_EVENT_REFER);
+ } else {
+ snprintf(temp, MAX_SIP_HEADER_LENGTH, "%s,%s", SIP_EVENT_DIALOG,
+ SIP_EVENT_REFER);
+ }
+ tflag = sippmh_add_text_header(response, SIP_HEADER_ALLOW_EVENTS, temp);
+ UPDATE_FLAGS(flag, tflag);
+
+ // Add Accept
+ snprintf(temp, MAX_SIP_HEADER_LENGTH, "%s,%s,%s",
+ SIP_CONTENT_TYPE_SDP,
+ SIP_CONTENT_TYPE_MULTIPART_MIXED,
+ SIP_CONTENT_TYPE_MULTIPART_ALTERNATIVE);
+ tflag = sippmh_add_text_header(response, SIP_HEADER_ACCEPT, temp);
+ UPDATE_FLAGS(flag, tflag);
+
+ // Add Accept-Encoding
+ tflag = sippmh_add_text_header(response, SIP_HEADER_ACCEPT_ENCODING,
+ "identity");
+ UPDATE_FLAGS(flag, tflag);
+
+ // Add Accept-Language
+ tflag = sippmh_add_text_header(response, SIP_HEADER_ACCEPT_LANGUAGE, "en");
+ UPDATE_FLAGS(flag, tflag);
+
+ tflag = sippmh_add_text_header(response, SIP_HEADER_SUPPORTED,
+ SIP_RFC_SUPPORTED_TAGS);
+
+ UPDATE_FLAGS(flag, tflag);
+
+ /* Determine from the Via field where the message is supposed
+ * to be sent
+ */
+
+ if (tflag != HSTATUS_SUCCESS) {
+ free_sip_message(response);
+ return FALSE;
+ }
+ return sendResponse(NULL, response, msg, FALSE, sipMethodOptions);
+}
+
+
+/*
+ * Send the invite response. Adds the session description
+ * if send_sd is TRUE. Assumes
+ * - connection is set up.
+ * Does not affect call state.
+ */
+void
+sipSPISendInviteResponse (ccsipCCB_t *ccb,
+ uint16_t statusCode,
+ const char *reason_phrase,
+ uint16_t status_code_warning,
+ const char *reason_phrase_warning,
+ boolean send_sd,
+ boolean retx)
+{
+ const char *fname = "SIPSPISendInviteResponse";
+ sipMessage_t *response = NULL;
+ sipRet_t flag = STATUS_SUCCESS;
+ sipRet_t tflag = STATUS_SUCCESS;
+ sipMessageFlag_t messageflag;
+ int rpid_flag;
+
+
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_MSG_SENDING_RESPONSE),
+ fname, statusCode);
+
+ messageflag.flags = 0;
+ messageflag.flags = SIP_HEADER_CONTACT_BIT |
+ SIP_HEADER_RECORD_ROUTE_BIT |
+ SIP_HEADER_ALLOW_BIT |
+ SIP_HEADER_DIVERSION_BIT |
+ SIP_HEADER_ALLOW_EVENTS_BIT;
+
+ /* Write Content-Type */
+ /* Add SDP body if required */
+ if (send_sd) {
+ messageflag.flags |= SIP_HEADER_CONTENT_TYPE_BIT;
+ } else {
+ messageflag.flags |= SIP_HEADER_CONTENT_LENGTH_BIT;
+ }
+ if (statusCode == SIP_CLI_ERR_EXTENSION) {
+ messageflag.flags |= SIP_HEADER_UNSUPPORTED_BIT;
+ }
+ if ((statusCode >=SIP_1XX_TRYING) && (statusCode <= SIP_STATUS_SUCCESS)) {
+ messageflag.flags |= SIP_HEADER_SUPPORTED_BIT;
+ }
+ if (statusCode == SIP_SERV_ERR_INTERNAL) {
+ messageflag.flags |= SIP_HEADER_RETRY_AFTER_BIT;
+ }
+ if ((statusCode == SIP_1XX_TRYING) || (statusCode == SIP_STATUS_SUCCESS)) {
+ messageflag.flags |= SIP_HEADER_RECV_INFO_BIT;
+ }
+
+ /*
+ * Set RPID header.
+ */
+ if (statusCode != SIP_1XX_TRYING) {
+ /*
+ * The RPID header is not sent in the 100 Trying because the response is directly
+ * sent from the SIP stack.The information needed for building the RPID is updated
+ * by the gsm later.
+ */
+ rpid_flag = sipSPISetRPID(ccb, FALSE);
+ if (rpid_flag == RPID_ENABLED) {
+ messageflag.flags |= SIP_HEADER_REMOTE_PARTY_ID_BIT;
+ }
+ }
+
+ response = GET_SIP_MESSAGE();
+ messageflag.extflags = 0;
+ if (CreateResponse(ccb, messageflag, statusCode, response, reason_phrase,
+ status_code_warning, reason_phrase_warning,
+ sipMethodInvite)) {
+ tflag = HSTATUS_SUCCESS;
+ } else {
+ tflag = HSTATUS_FAILURE;
+ }
+
+ UPDATE_FLAGS(flag, tflag);
+
+ tflag = sipSPIAddCallStats(ccb, response);
+
+ UPDATE_FLAGS(flag, tflag);
+ /* If build error detected, cleanup and do not send message */
+ if (flag != STATUS_SUCCESS) {
+ /* !!! Clean up */
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_BUILDFLAG_ERROR), fname);
+ if (response) {
+ free_sip_message(response);
+ }
+ return;
+ }
+
+ (void) sendResponse(ccb, response, ccb->last_request, retx, sipMethodInvite);
+ return;
+}
+
+
+void
+sipSPIGenerateGenAuthorizationResponse (ccsipCCB_t *ccb,
+ sipMessage_t *request,
+ sipRet_t *flag,
+ char *method)
+{
+ const char *fname = "sipSPIGenerateGenAuthorizationResponse";
+ sipRet_t tflag = STATUS_SUCCESS;
+ char *author_str = NULL;
+ credentials_t credentials;
+
+ /*
+ * CSCds70538
+ * Re-generate the Authorization header for CANCEL, BYE, mid-INVITE
+ * The header is cached after an INVITE is challenged.
+ * I know that I have been challenged preciously because sip_authen
+ * is not NULL
+ */
+ if (ccb->authen.sip_authen) {
+ cred_get_line_credentials(ccb->dn_line, &credentials,
+ sizeof(credentials.id),
+ sizeof(credentials.pw));
+ if (sipSPIGenerateAuthorizationResponse(ccb->authen.sip_authen,
+ ccb->ReqURI, method, credentials.id, credentials.pw,
+ &author_str, &(ccb->authen.nc_count), ccb)) {
+
+ if (ccb->authen.authorization != NULL) {
+ cpr_free(ccb->authen.authorization);
+ ccb->authen.authorization = NULL;
+ }
+
+ /*
+ * Don't free the sip_authen since we were not challenged
+ */
+ ccb->authen.authorization = (char *)
+ cpr_malloc(strlen(author_str) + 1);
+
+ /*
+ * Cache the Authorization header so that it can be used for later
+ * requests
+ */
+ if (ccb->authen.authorization != NULL) {
+ sstrncpy(ccb->authen.authorization, author_str,
+ strlen(author_str) * sizeof(char) + 1);
+ }
+
+ cpr_free(author_str);
+ } else {
+ CCSIP_DEBUG_ERROR("%s: Error: Authorization header build "
+ "unsuccessful\n", fname);
+ }
+ }
+
+ if (ccb->authen.authorization != NULL) {
+ tflag = sippmh_add_text_header(request,
+ AUTHOR_HDR(ccb->authen.status_code),
+ ccb->authen.authorization);
+ UPDATE_FLAGS(*flag, tflag);
+ }
+}
+
+
+/*
+ * Sends the 202 Refer Accepted .
+ * Assumes that
+ * - the connection is setup.
+ * Will be sent when we get Refer
+*/
+boolean
+sipSPISendReferResponse202 (ccsipCCB_t *ccb)
+{
+ const char *fname = "SIPSPISendReferResponse";
+ sipMessage_t *response = NULL;
+ sipRet_t flag = STATUS_SUCCESS;
+ sipMessageFlag_t messageflag;
+ boolean result;
+
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_MSG_SENDING_RESPONSE),
+ fname, SIP_ACCEPTED);
+
+ messageflag.flags = 0;
+ messageflag.flags = SIP_HEADER_CONTACT_BIT |
+ SIP_HEADER_RECORD_ROUTE_BIT |
+ SIP_HEADER_CONTENT_LENGTH_BIT;
+
+ /* Add Content Length */
+ response = GET_SIP_MESSAGE();
+ messageflag.extflags = 0;
+ if (CreateResponse(ccb, messageflag, SIP_ACCEPTED, response,
+ SIP_ACCEPTED_PHRASE, 0, NULL, sipMethodRefer)) {
+ flag = HSTATUS_SUCCESS;
+ } else {
+ flag = HSTATUS_FAILURE;
+ }
+
+ /* If build error detected, cleanup and do not send message */
+ if (flag != STATUS_SUCCESS) {
+ /* !!! Clean up */
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_BUILDFLAG_ERROR), fname);
+ if (response)
+ free_sip_message(response);
+ clean_method_request_trx(ccb, sipMethodRefer, FALSE);
+ return (FALSE);
+ }
+
+ result = sendResponse(ccb, response, ccb->last_request, FALSE,
+ sipMethodRefer);
+ clean_method_request_trx(ccb, sipMethodRefer, FALSE);
+ return (result);
+}
+
+/*
+ * General function to send an error response for a given request.
+ * Does not affect call state or disconnection flags.
+ *
+ * Valid values of warn_code is 3xx. Set warn_code to ZERO, when
+ * warn_code is absent. Use of a valid warn_code, will lead to
+ * generation of Warning Header in the response.
+ */
+boolean
+sipSPISendErrorResponse (sipMessage_t *msg,
+ uint16_t status_code,
+ const char *reason_phrase,
+ uint16_t status_code_warning,
+ const char *reason_phrase_warning,
+ ccsipCCB_t *ccb)
+{
+ const char *fname = "sipSPISendErrorResponse";
+ sipMessage_t *response = NULL;
+ sipRet_t flag = STATUS_SUCCESS;
+ sipRet_t tflag = STATUS_SUCCESS;
+ const char *sip_from = NULL;
+ const char *sip_to = NULL;
+ const char *request_callid = NULL;
+ const char *request_cseq = NULL;
+ sipCseq_t *request_cseq_structure = NULL;
+ sipMethod_t method = sipMethodInvalid;
+ boolean result = FALSE;
+ char temp[MAX_SIP_HEADER_LENGTH];
+
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_MSG_SENDING_RESPONSE),
+ fname, status_code);
+
+ if (!msg) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_BADARGUMENT),
+ fname, "msg");
+ return (FALSE);
+ }
+
+ response = GET_SIP_MESSAGE();
+ if (!response) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "GET_SIP_MESSAGE()");
+ return (FALSE);
+ }
+
+ tflag = sippmh_add_response_line(response, SIP_VERSION, status_code,
+ reason_phrase) ? STATUS_FAILURE : STATUS_SUCCESS;
+
+ UPDATE_FLAGS(flag, tflag);
+
+ tflag = (sipSPIAddRequestVia(NULL, response, msg, sipMethodInvalid)) ?
+ STATUS_SUCCESS : STATUS_FAILURE;
+ UPDATE_FLAGS(flag, tflag);
+
+ sip_from = sippmh_get_cached_header_val(msg, FROM);
+ sip_to = sippmh_get_cached_header_val(msg, TO);
+ request_callid = sippmh_get_cached_header_val(msg, CALLID);
+ tflag = sippmh_add_text_header(response, SIP_HEADER_FROM, sip_from);
+ UPDATE_FLAGS(flag, tflag);
+ tflag = sippmh_add_text_header(response, SIP_HEADER_TO, sip_to);
+ UPDATE_FLAGS(flag, tflag);
+ tflag = sippmh_add_text_header(response, SIP_HEADER_CALLID, request_callid);
+ UPDATE_FLAGS(flag, tflag);
+
+ // Add date header
+ tflag = sipAddDateHeader(response);
+ UPDATE_FLAGS(flag, tflag);
+
+ if (reason_phrase_warning) {
+ char *warning = NULL;
+
+ warning = (char *) cpr_malloc(strlen(reason_phrase_warning) + 5);
+ if (warning) {
+ snprintf(warning, strlen(reason_phrase_warning) + 5,
+ "%d %s", status_code_warning, reason_phrase_warning);
+ tflag = sippmh_add_text_header(response, SIP_HEADER_WARN, warning);
+ UPDATE_FLAGS(flag, tflag);
+ cpr_free(warning);
+ }
+ }
+
+ // Add Retry-After, if needed
+ if (status_code == SIP_SERV_ERR_INTERNAL &&
+ status_code_warning == SIP_WARN_PROCESSING_PREVIOUS_REQUEST) {
+ tflag = sippmh_add_int_header(response, SIP_HEADER_RETRY_AFTER,
+ abs((cpr_rand() % 11)));
+ }
+
+ //Add Accept-Encoding, Accept and Accept-Language headers
+ //if outgoing response is 415-Unsupported Media Type
+ if (status_code == SIP_CLI_ERR_MEDIA) {
+ snprintf(temp, MAX_SIP_HEADER_LENGTH, "%s,%s,%s,%s,%s",
+ SIP_CONTENT_TYPE_SDP,
+ SIP_CONTENT_TYPE_MULTIPART_MIXED,
+ SIP_CONTENT_TYPE_MULTIPART_ALTERNATIVE,
+ SIP_CONTENT_TYPE_SIPFRAG,
+ SIP_CONTENT_TYPE_MWI);
+ // should we add all registered Info Package Content-Type here??
+ tflag = sippmh_add_text_header(response, SIP_HEADER_ACCEPT, temp);
+ UPDATE_FLAGS(flag, tflag);
+
+ tflag = sippmh_add_text_header(response, SIP_HEADER_ACCEPT_ENCODING,
+ SIP_CONTENT_ENCODING_IDENTITY);
+ UPDATE_FLAGS(flag, tflag);
+
+ tflag = sippmh_add_text_header(response, SIP_HEADER_ACCEPT_LANGUAGE,
+ "en");
+ UPDATE_FLAGS(flag, tflag);
+ }
+
+ if (status_code == SIP_CLI_ERR_NOT_ALLOWED) {
+ // Add Allow
+ snprintf(temp, MAX_SIP_HEADER_LENGTH, "%s,%s,%s,%s,%s,%s,%s,%s,%s",
+ SIP_METHOD_ACK, SIP_METHOD_BYE, SIP_METHOD_CANCEL,
+ SIP_METHOD_INVITE, SIP_METHOD_NOTIFY, SIP_METHOD_OPTIONS,
+ SIP_METHOD_REFER, SIP_METHOD_UPDATE, SIP_METHOD_SUBSCRIBE);
+ tflag = sippmh_add_text_header(response, SIP_HEADER_ALLOW, temp);
+ UPDATE_FLAGS(flag, tflag);
+ }
+
+ /* Write CSeq */
+ request_cseq = sippmh_get_cached_header_val(msg, CSEQ);
+ if (request_cseq) {
+ request_cseq_structure = sippmh_parse_cseq(request_cseq);
+ if (!request_cseq_structure) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sippmh_parse_cseq()");
+ free_sip_message(response);
+ return (FALSE);
+ }
+ tflag = sippmh_add_text_header(response, SIP_HEADER_CSEQ, request_cseq);
+ method = request_cseq_structure->method;
+ cpr_free(request_cseq_structure);
+ UPDATE_FLAGS(flag, tflag);
+ } else {
+ CCSIP_DEBUG_ERROR("%s: Error: Did not find valid CSeq header. "
+ "Cannot send response.\n", fname);
+ if (response) {
+ free_sip_message(response);
+ response = NULL;
+ }
+ }
+
+ /* Write Content-Length: 0 */
+ tflag = sippmh_add_int_header(response, SIP_HEADER_CONTENT_LENGTH, 0);
+ UPDATE_FLAGS(flag, tflag);
+
+ /* If build error detected, cleanup and do not send message */
+ if (flag != STATUS_SUCCESS) {
+ /* !!! Clean up */
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_BUILDFLAG_ERROR), fname);
+ if (response) {
+ free_sip_message(response);
+ response = NULL;
+ }
+ }
+
+ /* Determine from the Via field where the message is supposed
+ * to be sent
+ */
+ if (response) {
+ result = sendResponse(NULL, response, msg, FALSE, method);
+ }
+ if (ccb) {
+ clean_method_request_trx(ccb, method, FALSE);
+ }
+ return (result);
+}
+
+void
+sipSPISendFailureResponseAck (ccsipCCB_t *ccb, sipMessage_t *response,
+ boolean prevcall, line_t previous_call_line)
+{
+ const char *fname = "sipSPISendFailureResponseAck";
+
+ sipMessage_t *request = NULL;
+ sipRet_t flag = STATUS_SUCCESS;
+ sipRet_t tflag = STATUS_SUCCESS;
+
+ char src_addr_str[MAX_IPADDR_STR_LEN];
+ static char via[SIP_MAX_VIA_LENGTH];
+ char via_branch[SIP_MAX_VIA_LENGTH];
+ const char *response_to = NULL;
+ const char *response_from = NULL;
+ const char *response_callid = NULL;
+ const char *response_cseq = NULL;
+
+ cpr_ip_addr_t dest_ipaddr;
+ cpr_ip_addr_t src_ipaddr;
+ uint32_t dest_port = 0;
+ uint32_t cseq_number = 0;
+ sipCseq_t *response_cseq_structure;
+ sipMethod_t response_cseq_method = sipMethodInvalid;
+ sipRespLine_t *respLine = NULL;
+ int status_code = 0;
+ char local_ReqURI[MAX_SIP_URL_LENGTH];
+ line_t dn_line;
+ const char *authenticate = NULL;
+ credentials_t credentials;
+ sip_authen_t *sip_authen = NULL;
+ sipAuthenticate_t authen;
+ char *author_str = NULL;
+ int nc_count = 0;
+ boolean bad_authentication = FALSE;
+ int16_t trx_index = -1;
+ line_t line;
+ int nat_enable = 0;
+ int reldel_stored_msg = RELDEV_NO_STORED_MSG;
+
+ CPR_IP_ADDR_INIT(dest_ipaddr);
+ CPR_IP_ADDR_INIT(src_ipaddr);
+
+ if (prevcall) {
+ dest_ipaddr = gCallHistory[previous_call_line].last_bye_dest_ipaddr;
+ dest_port = gCallHistory[previous_call_line].last_bye_dest_port;
+ dn_line = gCallHistory[previous_call_line].dn_line;
+ sstrncpy(local_ReqURI,
+ gCallHistory[previous_call_line].last_route_request_uri,
+ sizeof(local_ReqURI));
+ sstrncpy(via_branch, gCallHistory[previous_call_line].via_branch,
+ sizeof(via_branch));
+ } else {
+ /*
+ * The ACK to a 300-699 response MUST
+ * be sent to same address, port, and
+ * transport to which the original request was sent.
+ */
+ dn_line = ccb->dn_line;
+ // Get the via_branch from the last request that we sent
+ trx_index = get_method_request_trx_index(ccb, sipMethodInvite, TRUE);
+ if (trx_index != -1) {
+ sstrncpy(via_branch,
+ (const char *)(ccb->sent_request[trx_index].u.sip_via_branch),
+ sizeof(via_branch));
+ }
+ // via_branch = (char *) ccb->sip_via_branch;
+ /*
+ * Use outbound proxy if we used to send messages for this call,
+ * we are using the default proxy, we are not using the Emergency
+ * route, and it is not the backup proxy registration.
+ */
+ if (util_check_if_ip_valid(&(ccb->outBoundProxyAddr)) &&
+ (ccb->proxySelection == SIP_PROXY_DEFAULT) &&
+ (ccb->routeMode != RouteEmergency) &&
+ (ccb->index != REG_BACKUP_CCB)) {
+ dest_ipaddr = ccb->outBoundProxyAddr;
+ if (ccb->outBoundProxyPort != 0) {
+ dest_port = ccb->outBoundProxyPort;
+ } else {
+ config_get_value(CFGID_OUTBOUND_PROXY_PORT, &dest_port,
+ sizeof(dest_port));
+ }
+ } else {
+ dest_ipaddr = ccb->dest_sip_addr;
+ dest_port = ccb->dest_sip_port;
+ }
+ }
+
+ response_cseq = sippmh_get_cached_header_val(response, CSEQ);
+ if (!response_cseq) {
+ CCSIP_DEBUG_ERROR("%s: Error: Unable to obtain request's CSeq "
+ "header.\n", fname);
+ return;
+ }
+ response_cseq_structure = sippmh_parse_cseq(response_cseq);
+ if (!response_cseq_structure) {
+ CCSIP_DEBUG_ERROR("%s: Error: Unable to parse request's CSeq "
+ "header.\n", fname);
+ return;
+ }
+ cseq_number = response_cseq_structure->number;
+ response_cseq_method = response_cseq_structure->method;
+ cpr_free(response_cseq_structure);
+
+ // Process the Failure response
+ response_to = sippmh_get_cached_header_val(response, TO);
+ response_from = sippmh_get_cached_header_val(response, FROM);
+ response_callid = sippmh_get_cached_header_val(response, CALLID);
+
+ request = GET_SIP_MESSAGE();
+ if (!request) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "GET_SIP_MESSAGE()");
+ return;
+ }
+
+ /*
+ * Determine the Request-URI
+ */
+ respLine = sippmh_get_response_line(response);
+ if (respLine) {
+ status_code = respLine->status_code;
+ SIPPMH_FREE_RESPONSE_LINE(respLine);
+ }
+
+ if (prevcall == FALSE) {
+ char tmp_ReqURI[MAX_SIP_URL_LENGTH];
+
+ // Save original ReqURI
+ sstrncpy(tmp_ReqURI, ccb->ReqURI, MAX_SIP_URL_LENGTH);
+ // Update ReqURI using RR, etc
+ (void) sipSPIGenRequestURI(ccb, sipMethodAck, FALSE);
+ // Use the ReqURI
+ sstrncpy(local_ReqURI, ccb->ReqURI, MAX_SIP_URL_LENGTH);
+ // Restore original ReqURI
+ sstrncpy(ccb->ReqURI, tmp_ReqURI, MAX_SIP_URL_LENGTH);
+
+ // Clean up the INVITE transaction block as we no longer need it
+ clean_method_request_trx(ccb, sipMethodInvite, TRUE);
+ }
+
+ config_get_value(CFGID_NAT_ENABLE, &nat_enable, sizeof(nat_enable));
+ if (nat_enable == 0) {
+ sip_config_get_net_device_ipaddr(&src_ipaddr);
+ ipaddr2dotted(src_addr_str, &src_ipaddr);
+ } else {
+ sip_config_get_nat_ipaddr(&src_ipaddr);
+ ipaddr2dotted(src_addr_str, &src_ipaddr);
+ }
+
+ /*
+ * Build the request
+ */
+ tflag = sippmh_add_request_line(request, SIP_METHOD_ACK, local_ReqURI,
+ SIP_VERSION);
+ UPDATE_FLAGS(flag, tflag);
+
+ /* Write Via */
+ if (prevcall) {
+ /*
+ * Use line 1 as default to get the transport type.
+ * Transport type is going to be device specific with
+ * the first release of skittles. Will need to change
+ * for mixed cc mode support.
+ */
+ line = 1;
+ } else {
+ line = ccb->dn_line;
+ }
+ snprintf(via, sizeof(via), "SIP/2.0/%s %s:%d;%s=%s",
+ sipTransportGetTransportType(line, TRUE, ccb),
+ src_addr_str, sipTransportGetListenPort(line, ccb),
+ VIA_BRANCH, via_branch);
+ tflag = sippmh_add_text_header(request, SIP_HEADER_VIA, via);
+ UPDATE_FLAGS(flag, tflag);
+
+ /* Write To, From, and Call-ID standard headers */
+ tflag = sippmh_add_text_header(request, SIP_HEADER_FROM, response_from);
+ UPDATE_FLAGS(flag, tflag);
+ tflag = sippmh_add_text_header(request, SIP_HEADER_TO, response_to);
+ UPDATE_FLAGS(flag, tflag);
+ tflag = sippmh_add_text_header(request, SIP_HEADER_CALLID, response_callid);
+ UPDATE_FLAGS(flag, tflag);
+
+ switch (status_code) {
+ case SIP_CLI_ERR_UNAUTH:
+ case SIP_CLI_ERR_PROXY_REQD:
+ if (response_cseq_method == sipMethodAck) {
+ authen.authorization = NULL;
+ cred_get_line_credentials(dn_line, &credentials,
+ sizeof(credentials.id),
+ sizeof(credentials.pw));
+ authenticate = sippmh_get_header_val(response,
+ AUTH_HDR(status_code), NULL);
+ if (authenticate != NULL) {
+ sip_authen = sippmh_parse_authenticate(authenticate);
+ if (sip_authen) {
+ if (sipSPIGenerateAuthorizationResponse(sip_authen,
+ local_ReqURI,
+ SIP_METHOD_ACK,
+ credentials.id,
+ credentials.pw,
+ &author_str,
+ &nc_count, NULL)) {
+ authen.authorization = (char *)
+ cpr_malloc(strlen(author_str) * sizeof(char) + 1);
+ if (authen.authorization != NULL) {
+ sstrncpy(authen.authorization, author_str,
+ strlen(author_str) * sizeof(char) + 1);
+ authen.status_code = status_code;
+ } else {
+ CCSIP_DEBUG_ERROR("%s: Error: malloc() failed "
+ "for authen.authorization\n",
+ fname);
+ bad_authentication = TRUE;
+ }
+ cpr_free(author_str);
+ } else {
+ CCSIP_DEBUG_ERROR("%s: Error: "
+ "sipSPIGenerateAuthorizationResponse()"
+ " returned null.\n", fname);
+ bad_authentication = TRUE;
+ }
+ sippmh_free_authen(sip_authen);
+ } else {
+ CCSIP_DEBUG_ERROR("%s: Error: sippmh_parse_authenticate() "
+ "returned null.\n", fname);
+ bad_authentication = TRUE;
+ }
+ } else {
+ CCSIP_DEBUG_ERROR("%s: Error: sippmh_get_header_val(AUTH_HDR) "
+ "returned null.\n", fname);
+ bad_authentication = TRUE;
+ }
+
+ if (!bad_authentication) {
+ tflag = sippmh_add_text_header(request,
+ AUTHOR_HDR(status_code),
+ authen.authorization);
+ cpr_free(authen.authorization);
+ UPDATE_FLAGS(flag, tflag);
+ } else {
+ CCSIP_DEBUG_ERROR("%s: Error: Bad authentication header.\n",
+ fname);
+ if (request) {
+ free_sip_message(request);
+ }
+ if (authen.authorization) {
+ cpr_free(authen.authorization);
+ }
+ return;
+ }
+
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ /* Write Date header */
+ tflag = sipAddDateHeader(request);
+ UPDATE_FLAGS(flag, tflag);
+
+ /* Write CSeq */
+ tflag = sippmh_add_cseq(request, SIP_METHOD_ACK, cseq_number);
+ UPDATE_FLAGS(flag, tflag);
+
+ /* Add Route Header */
+ tflag = (sipSPIAddRouteHeaders(request, ccb, NULL, 0)) ?
+ STATUS_SUCCESS : STATUS_FAILURE;
+
+ /* Write Content-Length */
+ tflag = sippmh_add_int_header(request, SIP_HEADER_CONTENT_LENGTH, 0);
+ UPDATE_FLAGS(flag, tflag);
+
+ /* If build error detected, cleanup and do not send message */
+ if (flag != STATUS_SUCCESS) {
+ /* !!! Clean up */
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_BUILDFLAG_ERROR), fname);
+ if (request) {
+ free_sip_message(request);
+ }
+ return;
+ }
+ /* Store the ACK so that it can be retransmitted in response
+ * to any duplicate 200 OK or error responses
+ */
+ if ((previous_call_line == 0xFF) && (prevcall == FALSE)) {
+ CCSIP_DEBUG_ERROR("%s: INFO: Skipping store for this Ack\n", fname);
+ } else {
+ reldel_stored_msg = sipRelDevCoupledMessageStore(request,
+ response_callid,
+ cseq_number,
+ response_cseq_method,
+ TRUE,
+ status_code,
+ &dest_ipaddr,
+ (int16_t)dest_port,
+ FALSE /*Do check tag*/);
+ }
+ /* Send message */
+ if (sipTransportChannelCreateSend(NULL, request, sipMethodAck,
+ &dest_ipaddr, (int16_t)dest_port, 0,
+ reldel_stored_msg) < 0) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sipTransportChannelCreateSend()");
+ if (request)
+ free_sip_message(request);
+ return;
+ }
+
+ return;
+}
+
+
+/*
+ * Resend the last message sent
+ */
+boolean
+sipSPISendLastMessage (ccsipCCB_t *ccb)
+{
+ const char *fname = "sipSPISendLastMessage";
+
+ /* Args Check */
+ if (!ccb) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_BADARGUMENT),
+ fname, "ccb");
+ return (FALSE);
+ }
+
+
+ /* Send message */
+ if (ccb->index == 0) {
+ if (sipTransportSendMessage(ccb,
+ sipPlatformUISMTimers[ccb->index].message_buffer,
+ sipPlatformUISMTimers[ccb->index].message_buffer_len,
+ sipPlatformUISMTimers[ccb->index].message_type,
+ &(sipPlatformUISMTimers[ccb->index].ipaddr),
+ sipPlatformUISMTimers[ccb->index].port,
+ TRUE, TRUE, 0, NULL) < 0) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sipTransportSendMessage()");
+ return (FALSE);
+ }
+ } else {
+ if (sipTransportChannelSend(ccb,
+ sipPlatformUISMTimers[ccb->index].message_buffer,
+ sipPlatformUISMTimers[ccb->index].message_buffer_len,
+ sipPlatformUISMTimers[ccb->index].message_type,
+ &(sipPlatformUISMTimers[ccb->index].ipaddr),
+ sipPlatformUISMTimers[ccb->index].port, 0) < 0) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sipTransportChannelSend()");
+ return (FALSE);
+ }
+ }
+ return (TRUE);
+}
+
+void
+sipGetRequestMethod (sipMessage_t *pRequest, sipMethod_t *pMethod)
+{
+ const char *fname = "SIPGetRequestMethod";
+ sipReqLine_t *pReqLine = NULL;
+
+ *pMethod = sipMethodInvalid;
+ pReqLine = sippmh_get_request_line(pRequest);
+
+ if (!pReqLine) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sippmh_get_request_line()");
+ return;
+ }
+
+ if (pReqLine->method) {
+ *pMethod = sippmh_get_method_code(pReqLine->method);
+ } else {
+ CCSIP_DEBUG_ERROR("%s: Error: No recognizable method in Req-URI!\n",
+ fname);
+ }
+
+ SIPPMH_FREE_REQUEST_LINE(pReqLine);
+ return;
+}
+
+
+int
+sipGetResponseMethod (sipMessage_t *pResponse, sipMethod_t *pMethod)
+{
+ const char *fname = "SIPGetResponseMethod";
+ sipRespLine_t *pRespLine = NULL;
+ const char *cseq = NULL;
+ sipCseq_t *sipCseq = NULL;
+
+ pRespLine = sippmh_get_response_line(pResponse);
+ if (pRespLine) {
+ cseq = sippmh_get_cached_header_val(pResponse, CSEQ);
+ if (!cseq) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sippmh_get_cached_header_val(CSEQ)");
+ SIPPMH_FREE_RESPONSE_LINE(pRespLine);
+ return (-1);
+ }
+ /* Extract method code */
+ sipCseq = sippmh_parse_cseq(cseq);
+ if (!sipCseq) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sippmh_parse_cseq()");
+ SIPPMH_FREE_RESPONSE_LINE(pRespLine);
+ return (-1);
+ }
+ *pMethod = sipCseq->method;
+ cpr_free(sipCseq);
+ } else {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sippmh_get_response_line()");
+ return (-1);
+ }
+
+ SIPPMH_FREE_RESPONSE_LINE(pRespLine);
+ return (0);
+}
+
+
+int
+sipGetResponseCode (sipMessage_t *pResponse, int *pResponseCode)
+{
+ const char *fname = "SIPGetResponseCode";
+ sipRespLine_t *pRespLine = NULL;
+
+ pRespLine = sippmh_get_response_line(pResponse);
+ if (pRespLine) {
+ *pResponseCode = pRespLine->status_code;
+ } else {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sippmh_get_response_line()");
+ return (-1);
+ }
+
+ SIPPMH_FREE_RESPONSE_LINE(pRespLine);
+ return (0);
+}
+
+
+/*
+ * Util workhorse to add the standard headers to all SIP messages.
+ * Does not affect call state.
+ */
+boolean
+sipSPIAddStdHeaders (sipMessage_t *msg, ccsipCCB_t *ccb, boolean isResponse)
+{
+ boolean retval = FALSE;
+ boolean flip = TRUE;
+ int max_fwd = 0;
+
+ if (!(ccb && msg)) {
+ return (retval);
+ }
+
+ if (isResponse) {
+ if (ccb->flags & INCOMING) {
+ flip = FALSE;
+ } else {
+ flip = TRUE;
+ }
+ } else {
+ if (ccb->flags & INCOMING) {
+ flip = TRUE;
+ } else {
+ flip = FALSE;
+ }
+ }
+
+ if (!flip) {
+ retval = (boolean)
+ ((STATUS_SUCCESS == sippmh_add_text_header(msg,
+ SIP_HEADER_FROM,
+ ccb->sip_from)) &&
+ (STATUS_SUCCESS == sippmh_add_text_header(msg,
+ SIP_HEADER_TO,
+ ccb->sip_to)) &&
+ (STATUS_SUCCESS == sippmh_add_text_header(msg,
+ SIP_HEADER_CALLID,
+ ccb->sipCallID)));
+ } else {
+ retval = (boolean)
+ ((STATUS_SUCCESS == sippmh_add_text_header(msg,
+ SIP_HEADER_FROM,
+ ccb->sip_to)) &&
+ (STATUS_SUCCESS == sippmh_add_text_header(msg,
+ SIP_HEADER_TO,
+ ccb->sip_from)) &&
+ (STATUS_SUCCESS == sippmh_add_text_header(msg,
+ SIP_HEADER_CALLID,
+ ccb->sipCallID)));
+ }
+
+ // Add max-forwards header if this is a request
+ if (isResponse == FALSE && retval == TRUE) {
+ config_get_value(CFGID_SIP_MAX_FORWARDS, &max_fwd, sizeof(max_fwd));
+ if (max_fwd == 0) {
+ max_fwd = SIP_MAX_FORWARDS_DEFAULT_VALUE;
+ }
+ if (sippmh_add_int_header(msg, SIP_HEADER_MAX_FORWARDS, max_fwd)
+ != STATUS_SUCCESS) {
+ retval = FALSE;
+ }
+ }
+ return (retval);
+}
+
+
+/*
+ * Add a SIP Via header to the sipMessage_t.
+ * Should return (TRUE) if the right members are
+ * present in the CCB struct.
+ * Does not affect call state.
+ */
+boolean
+sipSPIAddLocalVia (sipMessage_t *msg, ccsipCCB_t *ccb, sipMethod_t method)
+{
+ const char *fname = "sipSPIAddLocalVia";
+
+ if (msg && ccb) {
+ if (util_check_if_ip_valid(&(ccb->src_addr))) {
+ static char via[SIP_MAX_VIA_LENGTH];
+ char src_addr_str[MAX_IPADDR_STR_LEN];
+ char *sip_via_branch;
+ int16_t trx_index = -1;
+
+ /*
+ * We don't allocate a block for ACK(200 OK) although
+ * it is technically another transaction. Instead we
+ * locate the INVITE transaction in ccb.
+ */
+ if (method == sipMethodAck) {
+ trx_index = get_method_request_trx_index(ccb, sipMethodInvite,
+ TRUE);
+ } else {
+ trx_index = get_last_request_trx_index(ccb, TRUE);
+ }
+
+ if (trx_index < 0) {
+ return FALSE;
+ }
+ ipaddr2dotted(src_addr_str, &ccb->src_addr);
+ if (method == sipMethodCancel) {
+ // Get the via header from last sent request transaction
+ if (trx_index < 1) {
+ return FALSE;
+ }
+ sip_via_branch = strlib_open(ccb->sent_request[trx_index].u.sip_via_branch,
+ VIA_BRANCH_LENGTH);
+ sstrncpy(sip_via_branch, (char *)(ccb->sent_request[trx_index - 1].u.sip_via_branch), VIA_BRANCH_LENGTH);
+ ccb->sent_request[trx_index].u.sip_via_branch = strlib_close(sip_via_branch);
+
+ snprintf(via, sizeof(via),
+ "SIP/2.0/%s %s:%d;%s=%s",
+ sipTransportGetTransportType(ccb->dn_line, TRUE, ccb),
+ src_addr_str, ccb->local_port, VIA_BRANCH,
+ (char *)(ccb->sent_request[trx_index].u.sip_via_branch));
+
+ } else {
+ snprintf(via, sizeof(via),
+ "SIP/2.0/%s %s:%d;%s=",
+ sipTransportGetTransportType(ccb->dn_line, TRUE, ccb),
+ src_addr_str, ccb->local_port, VIA_BRANCH);
+
+ sip_via_branch = strlib_open(ccb->sent_request[trx_index].u.sip_via_branch,
+ VIA_BRANCH_LENGTH);
+ if (sip_via_branch) {
+ snprintf(sip_via_branch, VIA_BRANCH_LENGTH,
+ "%s%.8x", VIA_BRANCH_START,
+ (unsigned int)cpr_rand());
+ }
+ ccb->sent_request[trx_index].u.sip_via_branch =
+ strlib_close(sip_via_branch);
+
+ if (sip_via_branch) {
+ sstrncat(via, sip_via_branch,
+ SIP_MAX_VIA_LENGTH - strlen(via));
+ }
+ }
+ if (sippmh_add_text_header(msg, SIP_HEADER_VIA, via)
+ != STATUS_SUCCESS) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sippmh_add_text_header(VIA)");
+ return (FALSE);
+ }
+ } else {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_BADARGUMENT),
+ fname, "ccb->src_addr");
+ return (FALSE);
+ }
+ }
+
+ return (TRUE);
+}
+
+
+/*
+ * For a response, add the Via headers that came in with the
+ * request to the response.
+ */
+boolean
+sipSPIAddRequestVia (ccsipCCB_t *ccb, sipMessage_t *response,
+ sipMessage_t *request, sipMethod_t method)
+{
+ const char *fname = "sipSPIAddRequestVia";
+ int16_t trx_index = -1;
+
+ /* Check args */
+ if (!response) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_BADARGUMENT),
+ fname, "response");
+ return (FALSE);
+ }
+ if (!request) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_BADARGUMENT),
+ fname, "request");
+ return (FALSE);
+ }
+
+ // Get the stored via from the transaction that we are responding to
+ if (ccb) {
+ trx_index = get_method_request_trx_index(ccb, method, FALSE);
+ if (trx_index >= 0) {
+ (void) sippmh_add_text_header(response, SIP_HEADER_VIA,
+ (char *)(ccb->recv_request[trx_index].u.sip_via_header));
+ return (TRUE);
+ }
+ }
+
+ // If no transaction, get the via directly from the request
+ (void) sippmh_add_text_header(response, SIP_HEADER_VIA,
+ sippmh_get_cached_header_val(request, VIA));
+
+ return (TRUE);
+}
+
+
+/*
+ * Procedure to add a Route/Record-Route header in SIP responses
+ */
+boolean
+sipSPIAddRouteHeaders (sipMessage_t *msg, ccsipCCB_t *ccb,
+ char *result_route, int result_route_length)
+{
+ const char *fname = "SIPSPIAddRouteHeaders";
+ /* NOTE: route will be limited to 4 hops */
+ static char route[MAX_SIP_HEADER_LENGTH * NUM_INITIAL_RECORD_ROUTE_BUFS];
+ static char Contact[MAX_SIP_HEADER_LENGTH];
+ boolean lr = FALSE;
+
+ /* Check args */
+ if (!msg) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_BADARGUMENT),
+ fname, "msg");
+ return (FALSE);
+ }
+ if (!ccb) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_BADARGUMENT),
+ fname, "ccb");
+ return (FALSE);
+ }
+
+ if (!ccb->record_route_info) {
+ CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"Route info not available; will not"
+ " add Route header.\n", DEB_F_PREFIX_ARGS(SIP_ROUTE, fname));
+ return (TRUE);
+ }
+
+ memset(route, 0, MAX_SIP_HEADER_LENGTH * NUM_INITIAL_RECORD_ROUTE_BUFS);
+ memset(Contact, 0, MAX_SIP_HEADER_LENGTH);
+
+ if (ccb->flags & INCOMING) {
+ /*
+ * For Incoming call (UAS), Copy the RR headers as it is
+ * If Contact is present, append it at the end
+ */
+ if (sipSPIGenerateRouteHeaderUAS(ccb->record_route_info, route,
+ sizeof(route), &lr) == FALSE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sipSPIGenerateRouteHeaderUAS()");
+ return (FALSE);
+ }
+ } else {
+ /*
+ * For Outgoing call (UAC), Copy the RR headers in the reverse
+ * order. If Contact is present, append it at the end
+ */
+ if (sipSPIGenerateRouteHeaderUAC(ccb->record_route_info, route,
+ sizeof(route), &lr) == FALSE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sipSPIGenerateRouteHeaderUAC()");
+ return (FALSE);
+ }
+ }
+ /*
+ * If loose_routing is TRUE, then the contact header is NOT appended
+ * to the Routeset but is instead used in the Req-URI
+ */
+ if (!lr) {
+ Contact[0] = '\0';
+ if (sipSPIGenerateContactHeader(ccb->contact_info, Contact,
+ sizeof(Contact)) == FALSE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sipSPIGenerateContactHeader()");
+ return (FALSE);
+ }
+
+ /* Append Contact to the Route Header, if Contact is available */
+ if (Contact[0] != '\0') {
+ if (route[0] != '\0') {
+ sstrncat(route, ", ", sizeof(route) - strlen(route));
+ }
+ sstrncat(route, Contact, sizeof(route) - strlen(route));
+ }
+ }
+
+ if (route[0] != '\0') {
+ if (sippmh_add_text_header(msg, SIP_HEADER_ROUTE, route)
+ == STATUS_SUCCESS) {
+ CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"Adding route = %s\n",
+ DEB_F_PREFIX_ARGS(SIP_ROUTE, fname), route);
+ if (result_route) {
+ sstrncpy(result_route, route, result_route_length);
+ }
+ } else {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sippmh_add_text_header(ROUTE)");
+ return (FALSE);
+ }
+ } else {
+ /* Having nothing in Route header is a legal case.
+ * This would happen when the Record-Route header has
+ * a single entry and Contact was NULL
+ */
+ CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"Not adding route \n", DEB_F_PREFIX_ARGS(SIP_ROUTE, fname));
+ }
+
+ return (TRUE);
+}
+
+
+boolean
+sipSPIAddRequestRecordRoute (sipMessage_t *response, sipMessage_t *request)
+{
+ const char *fname = "SIPSPIAddRequestRecordRoute";
+
+ /* Check args */
+ if (!response) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_BADARGUMENT),
+ fname, "response");
+ return (FALSE);
+ }
+ if (!request) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_BADARGUMENT),
+ fname, "request");
+ return (FALSE);
+ }
+
+ (void) sippmh_add_text_header(response, SIP_HEADER_RECORD_ROUTE,
+ sippmh_get_cached_header_val(request, RECORD_ROUTE));
+
+ return (TRUE);
+}
+
+
+/*
+ * Procedure to add a proprietary SIP header to carry GUID in the SIP messsage
+ */
+boolean
+sipSPIAddCiscoGuid (sipMessage_t *msg, ccsipCCB_t *ccb)
+{
+ boolean retval = STATUS_FAILURE;
+/*
+ const char *fname = "sipSPIAddCiscoGuid";
+ uint32_t guid[4];
+ char guid_char[4*CC_GUID_SIZE];
+
+ if (ccb && msg) {
+
+ memcpy(&guid[0], ccb->guid, sizeof(guid[0]));
+ memcpy(&guid[1], &ccb->guid[sizeof(guid[0])], sizeof(guid[0]));
+ memcpy(&guid[2], &ccb->guid[2*sizeof(guid[0])], sizeof(guid[0]));
+ memcpy(&guid[3], &ccb->guid[3*sizeof(guid[0])], sizeof(guid[0]));
+
+ sprintf(guid_char, "%u-%u-%u-%u", guid[0], guid[1], guid[2], guid[3]);
+
+ retval = (STATUS_SUCCESS == sippmh_add_text_header(msg,
+ SIP_HEADER_CISCO_GUID,
+ guid_char));
+ } else {
+ CCSIP_DEBUG_ERROR("%s: Error: Fatal error in parsing ccb.\n",
+ fname);
+ }
+*/
+ return (retval);
+}
+
+int
+sipSPICheckContentHeaders (sipMessage_t *msg)
+{
+ uint8_t i;
+ const char *accept_hdr = NULL;
+ const char *content_enc = NULL;
+ const char *content_disp_str = NULL;
+ const char *accepted_enc_str = NULL;
+ cc_content_disposition_t *content_disp = NULL;
+ const char *fname = "sipSPICheckContentHeaders";
+ sipMethod_t method = sipMethodInvalid;
+ char *lasts = NULL;
+
+ if (!msg) {
+ return (SIP_MESSAGING_ERROR);
+ }
+
+ if (sippmh_msg_header_present(msg, SIP_HEADER_ACCEPT)) {
+ accept_hdr = sippmh_get_header_val(msg, SIP_HEADER_ACCEPT, NULL);
+ if (!accept_hdr) {
+ if (sippmh_is_request(msg)) {
+ sipGetRequestMethod(msg, &method);
+ if (method == sipMethodInvite) {
+ /*
+ * Currently we are rejecting empty Accept headers for
+ * INVITE only. This check is done here instead of
+ * previously because Accept is Content related header
+ * and also in the future if we want to extend this
+ * check to other requests and responses this would be
+ * a good place
+ */
+ return (SIP_MESSAGING_NOT_ACCEPTABLE);
+ }
+ }
+ }
+ }
+ content_enc = sippmh_get_header_val(msg, SIP_HEADER_CONTENT_ENCODING,
+ SIP_C_HEADER_CONTENT_ENCODING);
+ content_disp_str = sippmh_get_header_val(msg, SIP_HEADER_CONTENT_DISP,
+ SIP_HEADER_CONTENT_DISP);
+ accepted_enc_str = sippmh_get_header_val(msg, SIP_HEADER_ACCEPT_ENCODING,
+ SIP_HEADER_ACCEPT_ENCODING);
+ if (content_disp_str) {
+ content_disp = sippmh_parse_content_disposition(content_disp_str);
+ }
+
+ // Check Content-Encoding
+ // Only identity encoding is supported at this time
+ if (content_enc) {
+ if (cpr_strcasecmp(content_enc, SIP_CONTENT_ENCODING_IDENTITY)) {
+ // If Content-Encoding is not understood, check to see if
+ // the Content-Disposition is required. If so, flag an error
+ if (content_disp) {
+ if (content_disp->required_handling) {
+ cpr_free(content_disp);
+ return (SIP_MESSAGING_ERROR_UNSUPPORTED_MEDIA);
+ }
+ } else {
+ return (SIP_MESSAGING_ERROR_UNSUPPORTED_MEDIA);
+ }
+ }
+ }
+
+ // Check Content-Disposition
+ // Only disposition of "session", if not reject if handling it
+ // content is required
+ if (content_disp) {
+ if (content_disp->disposition != cc_disposition_session) {
+ if (content_disp->required_handling) {
+ cpr_free(content_disp);
+ return (SIP_MESSAGING_ERROR_UNSUPPORTED_MEDIA);
+ }
+ }
+ }
+ if (content_disp) {
+ cpr_free(content_disp);
+ }
+
+ if (accepted_enc_str) {
+ //parse the accepted_enc_str
+ //check to see if it contains "identity"
+ //if it does not contain "identity" return error
+
+ boolean found = FALSE;
+ char *ptr = NULL;
+ char *accepted_enc_str_dup;
+
+ accepted_enc_str_dup = cpr_strdup(accepted_enc_str);
+ if (accepted_enc_str_dup == NULL) {
+ CCSIP_DEBUG_ERROR("%s: Error: cpr_strdup() failed "
+ "for accepted_enc_str_dup\n", fname);
+ return (SIP_SERV_ERR_INTERNAL);
+ }
+
+ ptr = PL_strtok_r(accepted_enc_str_dup, ", ", &lasts);
+
+ while (ptr) {
+ if (strcmp(ptr, SIP_CONTENT_ENCODING_IDENTITY) == 0) {
+ found = TRUE;
+ break;
+ }
+ ptr = PL_strtok_r(NULL, ", ", &lasts);
+ }
+
+ cpr_free(accepted_enc_str_dup);
+
+ if (found == FALSE) {
+ return (SIP_MESSAGING_ERROR_UNSUPPORTED_MEDIA);
+ }
+ }
+
+
+ // Check all the body parts
+ for (i = 0; i < HTTPISH_MAX_BODY_PARTS; i++) {
+ if (msg->mesg_body[i].msgBody) {
+ if (msg->mesg_body[i].msgContentTypeValue
+ == SIP_CONTENT_TYPE_UNKNOWN_VALUE) {
+ CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"Pass-through \"%s\"\n",
+ DEB_F_PREFIX_ARGS(SIP_CONTENT_TYPE, fname),
+ msg->mesg_body[i].msgContentType);
+ // return (SIP_MESSAGING_ERROR_UNSUPPORTED_MEDIA);
+ }
+ if ((msg->mesg_body[i].msgContentEnc
+ != SIP_CONTENT_ENCODING_IDENTITY_VALUE) &&
+ (msg->mesg_body[i].msgRequiredHandling == TRUE)) {
+ return (SIP_MESSAGING_ERROR_UNSUPPORTED_MEDIA);
+ }
+ if ((msg->mesg_body[i].msgContentDisp
+ != SIP_CONTENT_DISPOSITION_SESSION_VALUE) &&
+ (msg->mesg_body[i].msgRequiredHandling == TRUE)) {
+ return (SIP_MESSAGING_ERROR_UNSUPPORTED_MEDIA);
+ }
+ }
+ }
+
+ return (SIP_MESSAGING_OK);
+}
+
+// This function returns TRUE if the header length is acceptable
+boolean
+is_good_header_length (const char *header, uint8_t header_type)
+{
+
+ if (!header) {
+ return FALSE;
+ }
+ switch (header_type) {
+ case FROM:
+ case TO:
+ if ((strlen(header) >= MAX_SIP_URL_LENGTH) || (strlen(header) == 0)) {
+ return FALSE;
+ }
+ break;
+ case CALLID:
+ if ((strlen(header) >= MAX_SIP_CALL_ID) || (strlen(header) == 0)) {
+ return FALSE;
+ }
+ break;
+ default:
+ break;
+ }
+ return TRUE;
+}
+
+/*
+ * sipCheckRequestURI
+ *
+ * Check the validity of mandatory fields in Req URI
+ *
+ * Adding restrictive checks to the following will break
+ * ccm features: "user=phone"
+ *
+ */
+int
+sipCheckRequestURI (ccsipCCB_t *ccb, sipMessage_t *request)
+{
+ sipReqLine_t *requestURI = NULL;
+ genUrl_t *genUrl = NULL;
+ sipUrl_t *sipUriUrl = NULL;
+ char src_addr_str[MAX_IPADDR_STR_LEN];
+ char *pUser = NULL;
+ cpr_ip_addr_t src_addr;
+ int nat_enable = 0;
+ boolean request_uri_error = FALSE;
+ int errorCode = SIP_MESSAGING_ERROR;
+ cpr_ip_addr_t ipaddr;
+
+ CPR_IP_ADDR_INIT(src_addr);
+ CPR_IP_ADDR_INIT(ipaddr);
+
+ requestURI = sippmh_get_request_line(request);
+ if (requestURI) {
+ if (requestURI->url) {
+ genUrl = sippmh_parse_url(requestURI->url, TRUE);
+ if (genUrl) {
+ if (genUrl->schema == URL_TYPE_SIP) {
+ sipUriUrl = genUrl->u.sipUrl;
+ }
+ if (sipUriUrl) {
+ pUser = sippmh_parse_user(sipUriUrl->user);
+ if (pUser) {
+ if (sipUriUrl->host) {
+ if (!str2ip(sipUriUrl->host, &ipaddr)) {
+ config_get_value(CFGID_NAT_ENABLE, &nat_enable,
+ sizeof(nat_enable));
+ if (nat_enable == 0) {
+ sip_config_get_net_device_ipaddr(&src_addr);
+ } else {
+ sip_config_get_nat_ipaddr(&src_addr);
+ }
+ ipaddr2dotted(src_addr_str, &src_addr);
+ if (strcmp(sipUriUrl->host, src_addr_str)) {
+ if (!validateHostName(sipUriUrl->host, pUser)) {
+ CCSIP_DEBUG_ERROR("Unknown address in Request URI\n");
+ request_uri_error = TRUE;
+ errorCode = SIP_MESSAGING_ENDPOINT_NOT_FOUND;
+ }
+ }
+ } else {
+ if (!validateHostName(sipUriUrl->host, pUser)) {
+ CCSIP_DEBUG_ERROR("Unknown address in Request URI\n");
+ request_uri_error = TRUE;
+ errorCode = SIP_MESSAGING_ENDPOINT_NOT_FOUND;
+ }
+ }
+ if (sipUriUrl->port_present) {
+ if (ccb &&
+ cpr_strcasecmp(sipTransportGetTransportType(ccb->dn_line, FALSE, ccb), "udp") == 0) {
+ if (sipUriUrl->port != ccb->local_port) {
+ CCSIP_DEBUG_ERROR("Port Mismatch(UDP), URL Port: %d, Port Used: %d\n",
+ sipUriUrl->port, ccb->local_port);
+ request_uri_error = TRUE;
+ errorCode = SIP_MESSAGING_ENDPOINT_NOT_FOUND;
+ }
+ }
+ }
+ }
+ if (pUser[0] == '\0') {
+ request_uri_error = TRUE;
+ errorCode = SIP_MESSAGING_ENDPOINT_NOT_FOUND;
+ } else {
+ if (ccb && !request_uri_error) {
+ sstrncpy(ccb->ReqURI, pUser,
+ sizeof(ccb->ReqURI));
+ }
+ }
+ cpr_free(pUser);
+ }
+ }
+ sippmh_genurl_free(genUrl);
+ } else {
+ request_uri_error = TRUE;
+ errorCode = SIP_MESSAGING_ENDPOINT_NOT_FOUND;
+ }
+ } else {
+ request_uri_error = TRUE;
+ errorCode = SIP_MESSAGING_ERROR;
+ }
+ SIPPMH_FREE_REQUEST_LINE(requestURI);
+ } else {
+ request_uri_error = TRUE;
+ errorCode = SIP_MESSAGING_ERROR;
+ }
+
+ if (request_uri_error) {
+ return errorCode;
+ } else {
+ return (SIP_MESSAGING_OK);
+ }
+}
+
+/*
+ * This is called for every request received.
+ * It checks the basic fields(url, From, To).
+ * Does not affect call state.
+ * It sends error responses for generic error types.
+ */
+int
+sipSPICheckRequest (ccsipCCB_t *ccb, sipMessage_t *request)
+{
+ const char *fname = "sipSPICheckRequest";
+ const char *callID = NULL;
+ const char *via = NULL;
+ const char *from = NULL;
+ const char *to = NULL;
+ const char *contact = NULL;
+ int retval = SIP_MESSAGING_OK;
+ char *replaceshdr = NULL;
+
+ const char *request_cseq = NULL;
+ sipCseq_t *request_cseq_structure = NULL;
+ uint32_t request_cseq_number = 0;
+ sipMethod_t request_cseq_method = sipMethodInvalid;
+ sipReqLine_t *requestURI;
+
+ /*
+ * Check args - CCB may be NULL
+ */
+ if (!request) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_BADARGUMENT),
+ fname, "request");
+ return (SIP_MESSAGING_ERROR);
+ }
+
+ /*
+ * Check for the incomplete message body
+ */
+ if (!sippmh_is_message_complete(request)) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sippmh_is_message_complete()");
+ return (SIP_MESSAGING_ERROR);
+ }
+
+
+ if ((retval = sipCheckRequestURI(ccb, request)) != SIP_MESSAGING_OK) {
+ CCSIP_DEBUG_ERROR("%s: Request URI Not Found\n", fname);
+ return (retval);
+ }
+
+
+ /*
+ * Check whether all mandatory SIP request headers are there.
+ * Also check if their lengths are within an acceptable range.
+ */
+ from = sippmh_get_cached_header_val(request, FROM);
+ if (!from || (!is_good_header_length(from, FROM))) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sippmh_get_cached_header_val(FROM)");
+ return (SIP_MESSAGING_ERROR);
+ }
+
+ to = sippmh_get_cached_header_val(request, TO);
+ if (!to || (!is_good_header_length(to, TO))) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sippmh_get_cached_header_val(TO)");
+ return (SIP_MESSAGING_ERROR);
+ }
+
+ via = sippmh_get_cached_header_val(request, VIA);
+ if (!via) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sippmh_get_cached_header_val(VIA)");
+ return (SIP_MESSAGING_ERROR);
+ }
+
+ callID = sippmh_get_cached_header_val(request, CALLID);
+ if (!callID || (!is_good_header_length(callID, CALLID))) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sippmh_get_cached_header_val(CALLID)");
+ return (SIP_MESSAGING_ERROR);
+ }
+
+ contact = sippmh_get_cached_header_val(request, CONTACT);
+ if (contact) {
+ int contact_check_result = 0;
+
+ contact_check_result = sipSPICheckContact(contact);
+ if (contact_check_result < 0) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sipSPICheckContact()");
+ return contact_check_result;
+ }
+ }
+
+ if ((retval = sipSPICheckContentHeaders(request)) != SIP_MESSAGING_OK) {
+ CCSIP_DEBUG_ERROR("%s: Content header value not supported\n", fname);
+ return (retval);
+ }
+
+ /*
+ * Check whether the current call id and this request's CallId match
+ */
+ if (ccb && ccb->sipCallID[0]) {
+ if (strcmp(ccb->sipCallID, callID) != 0) {
+ CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"Call ID match: new call id.\n", DEB_F_PREFIX_ARGS(SIP_CALL_ID, fname));
+ retval = SIP_MESSAGING_NEW_CALLID;
+ } else {
+ CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"Call ID match: same call id.\n", DEB_F_PREFIX_ARGS(SIP_CALL_ID, fname));
+ }
+ }
+
+ /*
+ * Parse CSeq
+ */
+ request_cseq = sippmh_get_cached_header_val(request, CSEQ);
+ if (!request_cseq) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sippmh_get_cached_header_val(CSEQ)");
+ return (SIP_MESSAGING_ERROR);
+ }
+
+ request_cseq_structure = sippmh_parse_cseq(request_cseq);
+ if (!request_cseq_structure) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sippmh_parse_cseq()");
+ return (SIP_MESSAGING_ERROR);
+ }
+ request_cseq_number = request_cseq_structure->number;
+ request_cseq_method = request_cseq_structure->method;
+ cpr_free(request_cseq_structure);
+
+ // Check continuity of this request wrt CSeq number and method
+ if (request_cseq_method != sipMethodAck &&
+ request_cseq_method != sipMethodCancel) {
+ // If ccb is present, check if the CSeq number is acceptable
+ if (ccb) {
+ if (request_cseq_number < ccb->last_recv_request_cseq) {
+ CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"Inconsistent CSEQ number. "
+ "current= %d, last= %d.\n",
+ DEB_F_PREFIX_ARGS(SIP_CSEQ, fname), request_cseq_number,
+ ccb->last_recv_request_cseq);
+
+ return (SIP_CLI_ERR_BAD_REQ);
+ }
+ if (request_cseq_number == ccb->last_recv_request_cseq) {
+ if (request_cseq_method != ccb->last_recv_request_cseq_method) {
+ CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"Inconsistent CSEQ method. "
+ "current= %s, last= %s\n.",
+ DEB_F_PREFIX_ARGS(SIP_CSEQ, fname),
+ sipGetMethodString(request_cseq_method),
+ sipGetMethodString(ccb->last_recv_request_cseq_method));
+
+ return (SIP_CLI_ERR_BAD_REQ);
+ }
+ }
+ }
+ }
+
+ if (request->mesg_line) {
+ if (strlen(request->mesg_line) >= MAX_SIP_URL_LENGTH) {
+ CCSIP_DEBUG_ERROR("%s: Request URI length exceeds acceptable value\n",
+ fname);
+ return (SIP_MESSAGING_ERROR);
+ }
+ }
+
+ requestURI = sippmh_get_request_line(request);
+ if (requestURI) {
+ if (sippmh_get_method_code(requestURI->method) != request_cseq_method) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "Method in RURI != method in CSeq");
+ SIPPMH_FREE_REQUEST_LINE(requestURI);
+ return (SIP_MESSAGING_ERROR);
+ }
+ SIPPMH_FREE_REQUEST_LINE(requestURI);
+ }
+
+ if (request_cseq_method != sipMethodInvite) {
+ if (sippmh_msg_header_present(request, SIP_HEADER_REPLACES)) {
+ CCSIP_DEBUG_ERROR("%s: Error: Replace header is not valid for "
+ "this request\n", fname);
+ return SIP_MESSAGING_ERROR;
+ }
+ } else {
+ if (sippmh_get_num_particular_headers(request, SIP_HEADER_REPLACES,
+ NULL, &replaceshdr, MAX_REPLACES_HEADERS + 1)
+ > MAX_REPLACES_HEADERS) {
+ CCSIP_DEBUG_ERROR("%s: Error: More than one replaces header "
+ "in this request\n", fname);
+ return SIP_MESSAGING_ERROR;
+ }
+ }
+
+ /*
+ * Reliable Delivery
+ */
+ if (SipRelDevEnabled) {
+ /*
+ * responseRecord is a static because the structure it is made out of is
+ * so large.
+ */
+ static sipRelDevMessageRecord_t requestRecord;
+ int handle = -1;
+ const char *reldev_to = NULL;
+ sipLocation_t *reldev_to_loc = NULL;
+ char reldev_to_tag[MAX_SIP_TAG_LENGTH];
+ const char *reldev_from = NULL;
+ sipLocation_t *reldev_from_loc = NULL;
+ char reldev_from_tag[MAX_SIP_TAG_LENGTH];
+
+ memset(&requestRecord, 0, sizeof(requestRecord));
+ memset(reldev_to_tag, 0, MAX_SIP_TAG_LENGTH);
+ memset(reldev_from_tag, 0, MAX_SIP_TAG_LENGTH);
+
+ /* Get to_tag */
+ reldev_to = sippmh_get_cached_header_val(request, TO);
+
+ if (reldev_to) {
+ reldev_to_loc = sippmh_parse_from_or_to((char *)reldev_to, TRUE);
+ if (reldev_to_loc) {
+ if (reldev_to_loc->genUrl->schema != URL_TYPE_SIP) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_URL_ERROR),
+ fname);
+ sippmh_free_location(reldev_to_loc);
+ return (SIP_CLI_ERR_FORBIDDEN);
+ }
+
+ if (reldev_to_loc->tag) {
+ sstrncpy(reldev_to_tag,
+ sip_sm_purify_tag(reldev_to_loc->tag),
+ MAX_SIP_TAG_LENGTH);
+ }
+ sstrncpy(requestRecord.to_user,
+ reldev_to_loc->genUrl->u.sipUrl->user,
+ RELDEV_MAX_USER_NAME_LEN);
+ sippmh_free_location(reldev_to_loc);
+
+ } else {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname,
+ get_debug_string(DEBUG_FUNCTIONNAME_SIPPMH_PARSE_TO));
+ return (SIP_MESSAGING_ERROR);
+ }
+ } else {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sippmh_get_cached_header_val(TO)");
+ return (SIP_MESSAGING_ERROR);
+ }
+
+ /* Store from_user and from_host */
+ reldev_from = sippmh_get_cached_header_val(request, FROM);
+ if (reldev_from) {
+ reldev_from_loc = sippmh_parse_from_or_to((char *)reldev_from, TRUE);
+ if (reldev_from_loc) {
+ sstrncpy(requestRecord.from_user,
+ reldev_from_loc->genUrl->u.sipUrl->user,
+ RELDEV_MAX_USER_NAME_LEN);
+ sstrncpy(requestRecord.from_host,
+ reldev_from_loc->genUrl->u.sipUrl->host,
+ RELDEV_MAX_HOST_NAME_LEN);
+ if (reldev_from_loc->tag) {
+ sstrncpy(reldev_from_tag,
+ sip_sm_purify_tag(reldev_from_loc->tag),
+ MAX_SIP_TAG_LENGTH);
+ }
+ sippmh_free_location(reldev_from_loc);
+ }
+ }
+
+ /* Check whether the tag matches the stored tag */
+ if (ccb) {
+ if ((request_cseq_method == sipMethodInvite) ||
+ (request_cseq_method == sipMethodAck) ||
+ (request_cseq_method == sipMethodBye)) {
+
+ boolean to_tag_match = TRUE;
+ boolean from_tag_match = TRUE;
+
+ CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"in_to_tag:<%s>, in_from_tag:<%s>, "
+ "stored to tag=<%s>, stored from tag=<%s>\n",
+ DEB_F_PREFIX_ARGS(SIP_TAG, fname), reldev_to_tag, reldev_from_tag,
+ ccb->sip_to_tag, ccb->sip_from_tag);
+
+ /* Check to_tag first */
+ if (ccb->sip_to_tag[0]) {
+ if ((request_cseq_method == sipMethodBye) &&
+ (reldev_to_tag[0] == '\0') &&
+ (SIP_SM_CALL_SETUP_NOT_COMPLETED(ccb))) {
+ CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"Allow early call termination "
+ "BYE.\n", DEB_F_PREFIX_ARGS(SIP_CALL_STATUS, fname));
+ } else if ((request_cseq_method == sipMethodInvite) &&
+ (reldev_to_tag[0] == '\0') &&
+ (SIP_SM_CALL_SETUP_NOT_COMPLETED(ccb))) {
+ CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"Allow crossed "
+ "response and INVITE.\n", DEB_F_PREFIX_ARGS(SIP_CALL_STATUS, fname));
+ } else {
+ if (ccb->flags & INCOMING) {
+ // Incoming request for an incoming call
+ // Match the stored to-tag with the to-tag in request
+ if (strcasecmp_ignorewhitespace(reldev_to_tag,
+ ccb->sip_to_tag) != 0) {
+ to_tag_match = FALSE;
+ }
+ } else {
+ // We made the call, so match the stored to-tag
+ // with the from-tag in the incoming request
+ if (strcasecmp_ignorewhitespace(reldev_from_tag,
+ ccb->sip_to_tag) != 0) {
+ to_tag_match = FALSE;
+ }
+ }
+ }
+ }
+ if (!to_tag_match) {
+ CCSIP_DEBUG_ERROR("%s: To-Tag mismatch detected!\n", fname);
+ return (SIP_CLI_ERR_CALLEG);
+ }
+ // Now check from-tag
+ if (ccb->sip_from_tag[0]) {
+ if (ccb->flags & INCOMING) {
+ // Incoming request for an incoming call
+ // Match the stored from-tag with the from-tag in request
+ if (strcasecmp_ignorewhitespace(reldev_from_tag,
+ ccb->sip_from_tag) != 0) {
+ from_tag_match = FALSE;
+ }
+ } else {
+ // We made the call, so match the stored from-tag
+ // with the to-tag in the incoming request
+ if (strcasecmp_ignorewhitespace(reldev_to_tag,
+ ccb->sip_from_tag) != 0) {
+ from_tag_match = FALSE;
+ }
+ }
+ if (!from_tag_match) {
+ CCSIP_DEBUG_ERROR("%s: From-Tag mismatch detected!\n",
+ fname);
+ return (SIP_CLI_ERR_CALLEG);
+ }
+ }
+ }
+ }
+
+ requestRecord.is_request = TRUE;
+ sstrncpy(requestRecord.call_id, (callID) ? callID : "",
+ MAX_SIP_CALL_ID);
+ requestRecord.cseq_number = request_cseq_number;
+ requestRecord.cseq_method = request_cseq_method;
+ sstrncpy(requestRecord.tag, reldev_to_tag, MAX_SIP_TAG_LENGTH);
+ if (ccb) {
+ //requestRecord.line = ccb->index;
+ } else {
+ //requestRecord.line = 1;
+ }
+ if (ccb && (requestRecord.cseq_method == sipMethodInvite) &&
+ (ccb->state == SIP_STATE_IDLE)) {
+ sipRelDevMessagesClear(requestRecord.call_id,
+ requestRecord.from_user,
+ requestRecord.from_host,
+ requestRecord.to_user);
+ }
+ /* Check if duplicate */
+ if (sipRelDevMessageIsDuplicate(&requestRecord, &handle)) {
+ CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"Duplicate request detected...\n", DEB_F_PREFIX_ARGS(SIP_RESP, fname));
+ // If the request is an ACK we do not have any thing to send
+ // This was retransmitted ACK so drop it.
+ if (requestRecord.cseq_method != sipMethodAck) {
+ if (sipRelDevCoupledMessageSend(handle) < 0) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sipRelDevCoupledMessageSend()");
+ }
+ }
+ return (SIP_MESSAGING_DUPLICATE);
+ }
+
+ /* Record the request in Recent Requests List */
+ sipRelDevMessageStore(&requestRecord);
+ }
+ return (retval);
+}
+
+
+/*
+ * This is called for every response received.
+ * It checks the basic fields(response line, From, To).
+ * If a session description is present, it reads and parses it.
+ * (and overwrites an old one if present in the CCB.)
+ * Does not affect call state.
+ * Returns TRUE if the request is valid.
+ * Usually, but not necessarily an action function will drop
+ * an invalid response. Exceptions are usually disconnection states,
+ * where a bad response may still be accepted.
+ *
+ * NOTE:
+ * It is assumed that this routine would never be called recursively or
+ * reentered via a separate task because responseRecord is declared as a
+ * large static variable
+ */
+int
+sipSPICheckResponse (ccsipCCB_t *ccb, sipMessage_t *response)
+{
+ const char *fname = "sipSPICheckResponse";
+ const char *from = NULL;
+ const char *to = NULL;
+ const char *callID = NULL;
+ const char *cseq = NULL;
+ sipCseq_t *sipCseq = NULL;
+ sipRespLine_t *pRespLine = NULL;
+ uint32_t response_cseq_number = 0;
+ sipMethod_t response_method = sipMethodInvalid;
+ uint16_t response_code = 0;
+ sipStatusCodeClass_t code_class = codeClassInvalid;
+ int16_t trx_index = -1;
+ const char *via = NULL;
+
+ /*
+ * Check for the incomplete message body
+ */
+ if (!sippmh_is_message_complete(response)) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sippmh_is_message_complete()");
+ return (SIP_MESSAGING_ERROR);
+ }
+
+ /*
+ * Check whether all mandatory SIP request headers are there.
+ */
+ from = sippmh_get_cached_header_val(response, FROM);
+ if (!from || (!is_good_header_length(from, FROM))) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sippmh_get_cached_header_val(FROM)");
+ return (SIP_MESSAGING_ERROR);
+ }
+ to = sippmh_get_cached_header_val(response, TO);
+ if (!to || (!is_good_header_length(to, TO))) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sippmh_get_cached_header_val(TO)");
+ return (SIP_MESSAGING_ERROR);
+ }
+ callID = sippmh_get_cached_header_val(response, CALLID);
+ if (!callID || (!is_good_header_length(callID, CALLID))) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sippmh_get_cached_header_val(CALLID)");
+ return (SIP_MESSAGING_ERROR);
+ }
+ cseq = sippmh_get_cached_header_val(response, CSEQ);
+ if (!cseq) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sippmh_get_cached_header_val(CSEQ)");
+ return (SIP_MESSAGING_ERROR);
+ }
+ via = sippmh_get_cached_header_val(response, VIA);
+ if (via) {
+ if (strchr(via, COMMA)) {
+ CCSIP_DEBUG_ERROR("%s: Multiple Via headers found in response\n",
+ fname);
+ return (SIP_MESSAGING_ERROR);
+ }
+ }
+
+ if (sipSPICheckContentHeaders(response) != SIP_MESSAGING_OK) {
+ CCSIP_DEBUG_ERROR("%s: Content header value not supported\n", fname);
+ return (SIP_MESSAGING_ERROR);
+ }
+
+ /*
+ * Get SIP response code
+ */
+ pRespLine = sippmh_get_response_line(response);
+ if (!pRespLine) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sippmh_get_response_line()");
+ return (SIP_MESSAGING_ERROR);
+ }
+ response_code = pRespLine->status_code;
+ SIPPMH_FREE_RESPONSE_LINE(pRespLine);
+ code_class = sippmh_get_code_class(response_code);
+
+ /*
+ * Extract response method and Cseq number from CSeq
+ */
+ sipCseq = sippmh_parse_cseq(cseq);
+ if (!sipCseq) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sippmh_parse_cseq()");
+ return (SIP_MESSAGING_ERROR);
+ }
+ response_method = sipCseq->method;
+ response_cseq_number = sipCseq->number;
+ cpr_free(sipCseq);
+
+ /*
+ * If its a authentication response should not do any response
+ * mismatch checking since some ACK's are not stored and so this
+ * check will could return response mismatch.
+ */
+ switch (response_code) {
+ case SIP_CLI_ERR_UNAUTH:
+ case SIP_CLI_ERR_PROXY_REQD:
+ if (response_method == sipMethodAck) {
+ CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"Authentication Request for ACK: callid=%s,"
+ "cseq=%u, cseq_method=%s\n",
+ DEB_F_PREFIX_ARGS(SIP_ACK, fname), callID, response_cseq_number,
+ sipGetMethodString(response_method));
+ return (SIP_MESSAGING_OK);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (sippmh_msg_header_present(response, SIP_HEADER_REPLACES)) {
+ CCSIP_DEBUG_ERROR("%s: Error: Replace header is not valid "
+ "in a response\n", fname);
+ return SIP_MESSAGING_ERROR;
+ }
+
+ /*
+ * Reliable Delivery
+ */
+ if (SipRelDevEnabled) {
+ /*
+ * responseRecord is a static because the structure it is
+ * made out of is so large.
+ */
+ static sipRelDevMessageRecord_t responseRecord;
+ int handle = -1;
+ sipLocation_t *reldev_to_loc = NULL;
+ char reldev_to_tag[MAX_SIP_TAG_LENGTH];
+ sipLocation_t *reldev_from_loc = NULL;
+
+ memset(&responseRecord, 0, sizeof(responseRecord));
+ memset(reldev_to_tag, 0, MAX_SIP_TAG_LENGTH);
+
+ /* Get to_tag */
+ reldev_to_loc = sippmh_parse_from_or_to((char *)to, TRUE);
+ if (reldev_to_loc) {
+ if (reldev_to_loc->tag) {
+ sstrncpy(reldev_to_tag,
+ sip_sm_purify_tag(reldev_to_loc->tag),
+ MAX_SIP_TAG_LENGTH);
+ } else {
+ reldev_to_tag[0] = '\0';
+ }
+ sstrncpy(responseRecord.to_user,
+ reldev_to_loc->genUrl->u.sipUrl->user,
+ RELDEV_MAX_USER_NAME_LEN);
+ sippmh_free_location(reldev_to_loc);
+ } else {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname,
+ get_debug_string(DEBUG_FUNCTIONNAME_SIPPMH_PARSE_TO));
+ return (SIP_MESSAGING_ERROR);
+ }
+
+ reldev_from_loc = sippmh_parse_from_or_to((char *)from, TRUE);
+ if (reldev_from_loc) {
+ sstrncpy(responseRecord.from_user,
+ reldev_from_loc->genUrl->u.sipUrl->user,
+ RELDEV_MAX_USER_NAME_LEN);
+ sstrncpy(responseRecord.from_host,
+ reldev_from_loc->genUrl->u.sipUrl->host,
+ RELDEV_MAX_HOST_NAME_LEN);
+
+ /* Check from-tag */
+ if (reldev_from_loc->tag) {
+ if (!(ccb->flags & INCOMING)) {
+ if (strcmp(reldev_from_loc->tag, ccb->sip_from_tag) != 0) {
+ sippmh_free_location(reldev_from_loc);
+ CCSIP_DEBUG_ERROR("%s: Outgoing: From tag in response "
+ "does not match stored value\n",
+ fname);
+ return (SIP_MESSAGING_ERROR);
+ }
+ } else {
+ if (strcmp(reldev_from_loc->tag, ccb->sip_to_tag) != 0) {
+ sippmh_free_location(reldev_from_loc);
+ CCSIP_DEBUG_ERROR("%s: Incoming: From tag in response "
+ "does not match stored value\n",
+ fname);
+ return (SIP_MESSAGING_ERROR);
+ }
+ }
+ }
+
+ sippmh_free_location(reldev_from_loc);
+ } else {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname,
+ get_debug_string(DEBUG_FUNCTIONNAME_SIPPMH_PARSE_FROM));
+ return (SIP_MESSAGING_ERROR);
+ }
+
+ responseRecord.is_request = FALSE;
+ sstrncpy(responseRecord.call_id, (callID) ? callID : "",
+ MAX_SIP_CALL_ID);
+ responseRecord.cseq_method = response_method;
+ responseRecord.cseq_number = response_cseq_number;
+ responseRecord.response_code = response_code;
+ sstrncpy(responseRecord.tag, reldev_to_tag, MAX_SIP_TAG_LENGTH);
+ //responseRecord.line = ccb->index;
+
+ /* Check if duplicate */
+ if (sipRelDevMessageIsDuplicate(&responseRecord, &handle)) {
+ CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"Duplicate response detected...\n", DEB_F_PREFIX_ARGS(SIP_RESP, fname));
+ if (sipRelDevCoupledMessageSend(handle) < 0) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sipRelDevCoupledMessageSend()");
+ }
+ if ((response_method == sipMethodInvite) &&
+ (code_class == codeClass1xx)) {
+ /* Allow multiple provisional responses */
+ CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"Allowed duplicate provisional response\n",
+ DEB_F_PREFIX_ARGS(SIP_RESP, fname));
+ } else {
+ return (SIP_MESSAGING_DUPLICATE);
+ }
+ }
+ /* Record the response in Recent Requests List */
+ sipRelDevMessageStore(&responseRecord);
+ }
+
+ /*
+ * Check whether the outstanding request's and this response's
+ * call id, cseq, and cseq method match
+ */
+ trx_index = get_method_request_trx_index(ccb, response_method, TRUE);
+ if (trx_index < 0) {
+ CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"No Matching Request Found!:\n"
+ "(Response: cseq=%u, trx_method=%s)\n",
+ DEB_F_PREFIX_ARGS(SIP_CALL_STATUS, fname), response_cseq_number,
+ sipGetMethodString(response_method));
+ return (SIP_MESSAGING_ERROR_NO_TRX);
+ }
+ if ((ccb->sent_request[trx_index].cseq_number != response_cseq_number) ||
+ (ccb->sent_request[trx_index].cseq_method != response_method) ||
+ (strcmp(ccb->sipCallID, callID) != 0)) {
+ CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"Response mismatch:\n(Response:"
+ "callid=%s, cseq=%u, cseq_method=%s),\n"
+ "(Request: callid=%s, cseq=%u, "
+ "cseq_method=%s)\n",
+ DEB_F_PREFIX_ARGS(SIP_RESP, fname), callID, response_cseq_number,
+ sipGetMethodString(response_method),
+ ccb->sipCallID,
+ ccb->sent_request[trx_index].cseq_number,
+ sipGetMethodString(ccb->sent_request[trx_index].cseq_method));
+ /*
+ * What happened here is that a timing
+ * issue occured between the proxy and phone where we
+ * timed out at almost the same time and we have already
+ * sent another request(probably a cancel) when the proxy
+ * sends this response back to us. So that we just Ack this
+ * response, we play games with previous call fields. We don't
+ * want to store the information because this response is basically
+ * stale at this point. We set the prevcall boolean to FALSE
+ * but we set the previous_line to 0xFF. This will indicate to
+ * the send routine to skip the storing of this Ack for retransmission.
+ */
+ if (response_method == sipMethodInvite) {
+ const char *resp_via = NULL;
+ sipVia_t *resp_via_parm = NULL;
+ int16_t trx_index_temp = -1;
+ const char *sip_via_branch = NULL;
+
+ switch (code_class) {
+ case codeClass2xx:
+ /*
+ * If we get 200 response to a cancelled invite, send bye
+ * to clear up the call.
+ */
+ trx_index_temp = get_method_request_trx_index(ccb,
+ sipMethodCancel,
+ TRUE);
+ // if there is a CANCEL request outstanding -
+ // if (ccb->last_sent_request_cseq_method == sipMethodCancel) {
+ if (trx_index_temp > 0) {
+ const char *contact = NULL;
+
+ /*
+ * We need to update the contact and to, from tags recvd.
+ * in ccb because the CANCEL effectively becomes a nop due
+ * to the race condition where the UAS sent 200 OK to
+ * INVITE at the same instance we sent CANCEL. Hence we
+ * need to ACK the 200 OK for INVITE with route header and
+ * then send a BYE with to tag sent in order to clean up
+ * the call at the called party
+ */
+ ccb->sip_to = strlib_update(ccb->sip_to, to);
+ ccb->sip_from = strlib_update(ccb->sip_from, from);
+ contact = sippmh_get_cached_header_val(response, CONTACT);
+ if (contact) {
+ if (ccb->contact_info) {
+ sippmh_free_contact(ccb->contact_info);
+ }
+ ccb->contact_info = sippmh_parse_contact(contact);
+ }
+ sipSPISendFailureResponseAck(ccb, response, FALSE, 0xFF);
+ sipSPISendBye(ccb, NULL, NULL);
+ } else {
+ /*
+ * No CANCEL was sent, so this is a plain mismatch
+ * of the CSeq #
+ */
+ CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"Ignoring response message\n",
+ DEB_F_PREFIX_ARGS(SIP_RESP, fname));
+ return (SIP_MESSAGING_ERROR);
+ }
+ break;
+ case codeClass4xx:
+ case codeClass5xx:
+ case codeClass6xx:
+ /*
+ * Locate the branch Parameter. If the branch parameter is
+ * the same, we are dealing with an outstanding transaction,
+ * but the response was out of sync with expected. If branch
+ * parameter is different, the transaction is gone. Ignore
+ * stray responses
+ */
+ resp_via = sippmh_get_cached_header_val(response, VIA);
+ if (resp_via) {
+ resp_via_parm = sippmh_parse_via(resp_via);
+ if (resp_via_parm) {
+ /* check for branch param match for transaction */
+ if ((resp_via_parm->branch_param) &&
+ (strncmp(resp_via_parm->branch_param,
+ VIA_BRANCH_START, 7) == 0)) {
+ trx_index_temp = get_last_request_trx_index(ccb,
+ TRUE);
+ if (trx_index_temp != -1) {
+ sip_via_branch = (char *)
+ ccb->sent_request[trx_index_temp].u.sip_via_branch;
+ if (strncmp(resp_via_parm->branch_param,
+ // (char *) ccb->sip_via_branch,
+ sip_via_branch, VIA_BRANCH_LENGTH) != 0) {
+ CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"Stray Response: "
+ "Response branch: %s Request "
+ "branch: %s\n", DEB_F_PREFIX_ARGS(SIP_RESP, fname),
+ resp_via_parm->branch_param,
+ // (char *) ccb->sip_via_branch);
+ sip_via_branch);
+ sippmh_free_via(resp_via_parm);
+ return (SIP_MESSAGING_ERROR_STALE_RESP);
+ }
+ }
+ }
+ sippmh_free_via(resp_via_parm);
+ }
+ }
+ sipSPISendFailureResponseAck(ccb, response, FALSE, 0xFF);
+ break;
+ default:
+ sipSPISendFailureResponseAck(ccb, response, FALSE, 0xFF);
+ }
+ }
+ return (SIP_MESSAGING_ERROR_STALE_RESP);
+ }
+ CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"Response match: callid=%s, cseq=%u, "
+ "cseq_method=%s\n", DEB_F_PREFIX_ARGS(SIP_RESP, fname),
+ callID, response_cseq_number, sipGetMethodString(response_method));
+
+
+ return (SIP_MESSAGING_OK);
+}
+
+/*
+ * Generate Authorization response
+ * Concats all the right strings and MD5s the result
+ */
+boolean
+sipSPIGenerateAuthorizationResponse (sip_authen_t *sip_authen,
+ const char *uri,
+ const char *method,
+ const char *user_name,
+ const char *user_password,
+ char **author_str,
+ int *nc_count,
+ ccsipCCB_t *ccb)
+{
+ static const char fname[] = "sipSPIGenerateAuthorizationResponse";
+ sip_author_t sip_author;
+ HASHHEX HA1;
+ HASHHEX HA2 = "";
+ char cnonce_str[NONCE_LEN];
+ char nc_count_str[NONCE_LEN];
+ boolean md5_sess_used;
+ uint32_t i;
+
+ md5_sess_used = (cpr_strcasecmp(sip_authen->algorithm, "md5-sess") == 0) ?
+ TRUE : FALSE;
+
+ if ((sip_authen->scheme != SIP_DIGEST) ||
+ (!md5_sess_used &&
+ (cpr_strcasecmp(sip_authen->algorithm, "md5") != 0))) {
+ CCSIP_DEBUG_ERROR("%s: Error: invalid XXX-Authenticate.\n", fname);
+ CCSIP_DEBUG_ERROR(" scheme: %d, algorithm: %s.\n", sip_authen->scheme,
+ sip_authen->algorithm);
+ return (FALSE);
+ }
+
+ sip_author.response = (char *) cpr_malloc(33 * sizeof(char));
+
+ /* sip_author has pointers that point to the same data that sip_authen
+ * points to. Ensure that sip_authen is not freed before sip_author
+ * is finished.
+ */
+
+ sip_author.str_start = NULL;
+ sip_author.user_pass = (char *) user_password;
+ sip_author.d_username = (char *) user_name;
+ sip_author.unparsed_uri = (char *) uri;
+ sip_author.scheme = sip_authen->scheme;
+ sip_author.realm = sip_authen->realm;
+ sip_author.nonce = sip_authen->nonce;
+ sip_author.algorithm = sip_authen->algorithm;
+
+ sip_author.opaque = sip_authen->opaque;
+ sip_author.qop = sip_authen->qop;
+
+ /*
+ * Setup the cnonce and nc_count if qop options are used or if
+ * md5-sess is the algorithm requested.
+ */
+ if (!md5_sess_used && (sip_authen->qop == NULL)) {
+ sip_author.cnonce = NULL;
+ sip_author.nc_count = NULL;
+ } else {
+ if (md5_sess_used && (ccb != NULL)) {
+ if (ccb->authen.cnonce[0] == '\0') {
+ snprintf(ccb->authen.cnonce, NONCE_LEN, "%8.8x",
+ (unsigned int)cpr_rand());
+ }
+ sip_author.cnonce = ccb->authen.cnonce;
+ } else {
+ snprintf(cnonce_str, NONCE_LEN, "%8.8x",
+ (unsigned int)cpr_rand());
+ sip_author.cnonce = cnonce_str;
+ }
+ snprintf(nc_count_str, NONCE_LEN, "%08x", ++(*nc_count));
+ sip_author.nc_count = nc_count_str;
+ }
+ sip_author.auth_param = NULL;
+
+ DigestCalcHA1(sip_author.algorithm, sip_author.d_username,
+ sip_author.realm, (char *) user_password, sip_author.nonce,
+ sip_author.cnonce, HA1);
+
+ /*
+ * Need to calculate HEntity.
+ * HEntity is basically just the hash of the SDP. Only the INVITE has SDP
+ * so we hash the SDP for the INVITE and for other methods we just
+ * hash the "".
+ */
+ if ((strcmp(method, SIP_METHOD_INVITE) == 0) && (ccb != NULL)) {
+ /* Use the content from the body saved */
+ for (i = 0; i < ccb->local_msg_body.num_parts; i++) {
+ if (ccb->local_msg_body.parts[i].body != NULL) {
+ DigestString(ccb->local_msg_body.parts[i].body, HA2);
+ AUTH_DEBUG(DEB_F_PREFIX"entity body= \n", DEB_F_PREFIX_ARGS(SIP_MSG, fname));
+ }
+ }
+ } else {
+ DigestString("", HA2);
+ }
+
+ DigestCalcResponse(HA1, sip_author.nonce, sip_author.nc_count,
+ sip_author.cnonce, sip_author.qop,
+ (char *)method, //SIP_METHOD_REGISTER,
+ sip_author.unparsed_uri, HA2, sip_author.response);
+
+ *author_str = sippmh_generate_authorization(&sip_author);
+
+ cpr_free(sip_author.response);
+
+ return (TRUE);
+}
+
+
+/*
+ * Generates Route Headers for UAC
+ * Pops the first RR entry and puts in Req Line
+ * Copies the rest of RR entries in reverse order into Route Header
+ * Appends Contact Header at the end of Route
+ * header
+ * If the first route entry has loose routing,"lr", set. does not add the
+ * Contact Header to the end of Route, and does not pop the first entry.
+ * In this case, indicates loose
+ * routing to caller so that they may add the Contact to the Req-URI
+ * instead
+ */
+boolean
+sipSPIGenerateRouteHeaderUAC (sipRecordRoute_t *rr_info,
+ char *route,
+ int route_str_len,
+ boolean *loose_routing)
+{
+ boolean retval = FALSE;
+ int i, j, start, limit;
+ static char temp_route[MAX_SIP_HEADER_LENGTH];
+ sipUrl_t *url_info = NULL;
+ genUrl_t *gen;
+ boolean lr = FALSE;
+ char url[SIPS_URL_LEN];
+
+ if (route == NULL) {
+ return retval;
+ }
+
+ start = rr_info->num_locations - 1;
+ limit = 0;
+ route[0] = '\0';
+
+ for (i = start; i >= limit; i--) {
+ url_info = rr_info->locations[i]->genUrl->u.sipUrl;
+ if (i == start) {
+ if (url_info->lr_flag == FALSE) {
+ // Skip the first entry if lr flag is not set
+ continue;
+ } else {
+ lr = TRUE;
+ }
+ }
+ if (rr_info->locations[i]->genUrl->sips) {
+ snprintf(url, sizeof(url), "sips");
+ } else {
+ snprintf(url, sizeof(url), "sip");
+ }
+ temp_route[0] = '\0';
+ if (url_info->user == NULL) {
+ snprintf(temp_route, sizeof(temp_route),
+ "<%s:%s:%d", url, url_info->host, url_info->port);
+ } else {
+ if (url_info->password) {
+ snprintf(temp_route, sizeof(temp_route), "<%s:%s:%s@%s:%d",
+ url, url_info->user, url_info->password,
+ url_info->host, url_info->port);
+ } else {
+ snprintf(temp_route, sizeof(temp_route), "<%s:%s@%s:%d",
+ url, url_info->user, url_info->host, url_info->port);
+ }
+ }
+ if (url_info->maddr) {
+ /*static */ char maddr[MAX_SIP_HEADER_LENGTH];
+
+ snprintf(maddr, sizeof(maddr), ";maddr=%s", url_info->maddr);
+ sstrncat(temp_route, maddr,
+ sizeof(temp_route) - strlen(temp_route));
+ }
+
+ if (url_info->ttl_val) {
+ /*static */ char ttl[MAX_SIP_HEADER_LENGTH];
+
+ snprintf(ttl, sizeof(ttl), ";ttl=%d", url_info->ttl_val);
+ sstrncat(temp_route, ttl,
+ sizeof(temp_route) - strlen(temp_route));
+ }
+
+ switch (url_info->transport) {
+ case TRANSPORT_UDP:
+ sstrncat(temp_route, ";transport=udp",
+ sizeof(temp_route) - strlen(temp_route));
+ break;
+ case TRANSPORT_TCP:
+ sstrncat(temp_route, ";transport=tcp",
+ sizeof(temp_route) - strlen(temp_route));
+ break;
+ case TRANSPORT_TLS:
+ sstrncat(temp_route, ";transport=tls",
+ sizeof(temp_route) - strlen(temp_route));
+ break;
+ case TRANSPORT_SCTP:
+ sstrncat(temp_route, ";transport=sctp",
+ sizeof(temp_route) - strlen(temp_route));
+ break;
+ }
+
+ if (url_info->is_phone) {
+ sstrncat(temp_route, ";user=phone",
+ sizeof(temp_route) - strlen(temp_route));
+ }
+
+ if (url_info->lr_flag) {
+ sstrncat(temp_route, ";lr",
+ sizeof(temp_route) - strlen(temp_route));
+ }
+
+ j = 0;
+ gen = rr_info->locations[i]->genUrl;
+
+ while (j < SIP_MAX_LOCATIONS) {
+ if (gen->other_params[j] != NULL) {
+ sstrncat(temp_route, ";",
+ sizeof(temp_route) - strlen(temp_route));
+ sstrncat(temp_route, gen->other_params[j],
+ sizeof(temp_route) - strlen(temp_route));
+ break;
+ }
+ j++;
+ }
+
+ if (i > limit) {
+ sstrncat(temp_route, ">,",
+ sizeof(temp_route) - strlen(temp_route));
+ } else {
+ sstrncat(temp_route, ">",
+ sizeof(temp_route) - strlen(temp_route));
+ }
+
+ sstrncat(route, temp_route, route_str_len - strlen(route));
+
+ }
+
+ *loose_routing = lr;
+ retval = TRUE;
+ return retval;
+}
+
+/*
+ * Generates Route Headers for UAS
+ * Pops the first RR entry and puts in Req Line
+ * Copies the rest of RR entries into Route Header
+ * Appends Contact Header at the end of Route
+ * header
+ */
+boolean
+sipSPIGenerateRouteHeaderUAS (sipRecordRoute_t *rr_info,
+ char *route,
+ int route_str_len,
+ boolean *loose_routing)
+{
+ const char *fname = "sipSPIGenerateRouteHeaderUAS";
+ boolean retval = FALSE;
+ int i, j, start, limit;
+ static char temp_route[MAX_SIP_HEADER_LENGTH];
+ sipUrl_t *url_info;
+ genUrl_t *gen;
+ boolean lr = FALSE;
+ char url[SIPS_URL_LEN];
+
+ if (route == NULL) {
+ return (retval);
+ }
+
+ start = 0;
+ limit = rr_info->num_locations - 1;
+ route[0] = '\0';
+
+ for (i = start; i <= limit; i++) {
+ if (rr_info->locations[i]->genUrl->schema == URL_TYPE_SIP) {
+ url_info = rr_info->locations[i]->genUrl->u.sipUrl;
+ } else {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_URL_ERROR), fname);
+ return (FALSE);
+ }
+ if (i == start) {
+ if (url_info->lr_flag == FALSE) {
+ // don't add the first route, if the lr flag is not set
+ continue;
+ } else {
+ lr = TRUE;
+ }
+ }
+ if (rr_info->locations[i]->genUrl->sips) {
+ snprintf(url, sizeof(url), "sips");
+ } else {
+ snprintf(url, sizeof(url), "sip");
+ }
+ temp_route[0] = '\0';
+ if (url_info->user == NULL) {
+ snprintf(temp_route, sizeof(temp_route),
+ "<%s:%s:%d", url, url_info->host, url_info->port);
+ } else {
+ if (url_info->password) {
+ snprintf(temp_route, sizeof(temp_route), "<%s:%s:%s@%s:%d",
+ url, url_info->user,
+ url_info->password, url_info->host, url_info->port);
+ } else {
+ snprintf(temp_route, sizeof(temp_route), "<%s:%s@%s:%d",
+ url, url_info->user, url_info->host, url_info->port);
+ }
+ }
+
+ if (url_info->maddr) {
+ /*static */ char maddr[MAX_SIP_HEADER_LENGTH];
+
+ snprintf(maddr, sizeof(maddr), ";maddr=%s", url_info->maddr);
+ sstrncat(temp_route, maddr,
+ sizeof(temp_route) - strlen(temp_route));
+ }
+
+ if (url_info->ttl_val) {
+ /*static */ char ttl[MAX_SIP_HEADER_LENGTH];
+
+ snprintf(ttl, sizeof(ttl), ";ttl=%d", url_info->ttl_val);
+ sstrncat(temp_route, ttl,
+ sizeof(temp_route) - strlen(temp_route));
+ }
+
+ switch (url_info->transport) {
+ case TRANSPORT_UDP:
+ sstrncat(temp_route, ";transport=udp",
+ sizeof(temp_route) - strlen(temp_route));
+ break;
+ case TRANSPORT_TCP:
+ sstrncat(temp_route, ";transport=tcp",
+ sizeof(temp_route) - strlen(temp_route));
+ break;
+ case TRANSPORT_TLS:
+ sstrncat(temp_route, ";transport=tls",
+ sizeof(temp_route) - strlen(temp_route));
+ break;
+ case TRANSPORT_SCTP:
+ sstrncat(temp_route, ";transport=sctp",
+ sizeof(temp_route) - strlen(temp_route));
+ break;
+ }
+
+ if (url_info->is_phone) {
+ sstrncat(temp_route, ";user=phone",
+ sizeof(temp_route) - strlen(temp_route));
+ }
+
+ if (url_info->lr_flag) {
+ sstrncat(temp_route, ";lr",
+ sizeof(temp_route) - strlen(temp_route));
+ }
+
+ j = 0;
+ gen = rr_info->locations[i]->genUrl;
+
+ while (j < SIP_MAX_LOCATIONS) {
+ if (gen->other_params[j] != NULL) {
+ sstrncat(temp_route, ";",
+ sizeof(temp_route) - strlen(temp_route));
+ sstrncat(temp_route, gen->other_params[j],
+ sizeof(temp_route) - strlen(temp_route));
+ break;
+ }
+ j++;
+ }
+
+ if (i < limit) {
+ sstrncat(temp_route, ">,",
+ sizeof(temp_route) - strlen(temp_route));
+ } else {
+ sstrncat(temp_route, ">",
+ sizeof(temp_route) - strlen(temp_route));
+ }
+ sstrncat(route, temp_route, route_str_len - strlen(route));
+ }
+
+ *loose_routing = lr;
+ retval = TRUE;
+ return (retval);
+}
+
+/*
+ * This function regenerates the Contact Header
+ * from the parsed information stored in CCB
+ */
+boolean
+sipSPIGenerateContactHeader (sipContact_t *contact_info,
+ char *contact,
+ int len)
+{
+ const char *fname = "sipSPIGenerateContactHeader";
+ boolean retval = FALSE;
+ sipUrl_t *sipUrl;
+
+ if (contact == NULL) {
+ return (retval);
+ }
+
+ if (contact_info == NULL) {
+ contact[0] = '\0';
+ retval = TRUE;
+ return (retval);
+ }
+
+ if (contact_info->locations[0]->genUrl->schema == URL_TYPE_SIP) {
+ sipUrl = contact_info->locations[0]->genUrl->u.sipUrl;
+ } else {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_URL_ERROR), fname);
+ return (FALSE);
+ }
+
+ if (sipUrl->user == NULL) {
+ snprintf(contact, len, "host, sipUrl->port);
+ } else {
+ if ((sipUrl->password) && (*(sipUrl->password))) {
+ snprintf(contact, len, "user,
+ sipUrl->password, sipUrl->host, sipUrl->port);
+ } else {
+ snprintf(contact, len, "user,
+ sipUrl->host, sipUrl->port);
+ }
+ }
+
+ /* Assume contact length is the same for all clients */
+
+ if (sipUrl->maddr) {
+ /*static */ char maddr[MAX_SIP_HEADER_LENGTH];
+
+ snprintf(maddr, sizeof(maddr), ";maddr=%s", sipUrl->maddr);
+ sstrncat(contact, maddr, len - strlen(contact));
+ }
+
+ if (sipUrl->ttl_val) {
+ /*static */ char ttl[MAX_SIP_HEADER_LENGTH];
+
+ snprintf(ttl, sizeof(ttl), ";ttl=%d", sipUrl->ttl_val);
+ sstrncat(contact, ttl, len - strlen(contact));
+ }
+
+ switch (sipUrl->transport) {
+ case TRANSPORT_UDP:
+ sstrncat(contact, ";transport=udp", len - strlen(contact));
+ break;
+ case TRANSPORT_TCP:
+ sstrncat(contact, ";transport=tcp", len - strlen(contact));
+ break;
+ case TRANSPORT_TLS:
+ sstrncat(contact, ";transport=tls", len - strlen(contact));
+ break;
+ case TRANSPORT_SCTP:
+ sstrncat(contact, ";transport=sctp", len - strlen(contact));
+ break;
+ }
+
+ if (sipUrl->is_phone) {
+ sstrncat(contact, ";user=phone", len - strlen(contact));
+ }
+
+ sstrncat(contact, ">", len - strlen(contact));
+ retval = TRUE;
+ return (retval);
+}
+
+
+char *
+sipSPIUrlDestination (sipUrl_t *sipUrl)
+{
+ return ((sipUrl->maddr) ? sipUrl->maddr : sipUrl->host);
+}
+
+
+int
+sipSPICheckContact (const char *contact)
+{
+ const char *fname = "sipSPICheckContact";
+ sipContact_t *contact_info = NULL;
+ int result = 0;
+
+ contact_info = sippmh_parse_contact(contact);
+ if (contact_info) {
+ if (contact_info->locations[0]->genUrl->schema != URL_TYPE_SIP) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_URL_ERROR), fname);
+ sippmh_free_contact(contact_info);
+ return (-1);
+ }
+
+ sippmh_free_contact(contact_info);
+ }
+
+ return (result);
+}
+
+
+sipRet_t
+sipAddDateHeader (sipMessage_t *sip_message)
+{
+ char sip_date[MAX_SIP_DATE_LENGTH];
+ cpr_time_t timestamp;
+ struct tm ts;
+
+ (void) time((time_t *)×tamp);
+
+ (void) gmtime_r((time_t *)×tamp, &ts);
+
+ if (strftime(sip_date, MAX_SIP_DATE_LENGTH, "%a, %d %b %Y %H:%M:%S GMT", &ts)
+ == 0) {
+ /* If defined, allow for a failure if unable to create date header */
+ return STATUS_FAILURE;
+ }
+
+ return sippmh_add_text_header(sip_message, SIP_HEADER_DATE, sip_date);
+}
+
+int
+sipGetMessageCSeq (sipMessage_t *pMessage,
+ uint32_t *pResultCSeqNumber,
+ sipMethod_t *pResultCSeqMethod)
+{
+ const char *cseq = NULL;
+ sipCseq_t *sipCseq = NULL;
+
+ cseq = sippmh_get_cached_header_val(pMessage, CSEQ);
+ if (!cseq) {
+ return (-1);
+ }
+
+ sipCseq = sippmh_parse_cseq(cseq);
+ if (!sipCseq) {
+ return (-1);
+ }
+
+ *pResultCSeqNumber = sipCseq->number;
+ *pResultCSeqMethod = sipCseq->method;
+
+ cpr_free(sipCseq);
+ return (0);
+}
+
+
+void
+sipGetMessageToTag (sipMessage_t *pMessage, char *to_tag,
+ int to_tag_max_length)
+{
+ const char *to = NULL;
+ sipLocation_t *to_loc = NULL;
+
+ memset(to_tag, 0, to_tag_max_length);
+ //For self generated methods (i.e. outgoing), the TO HEADER
+ //may not be in the cached area of the message structue.
+ to = sippmh_get_cached_header_val(pMessage, TO);
+ if (!to) {
+ to = sippmh_get_header_val(pMessage, SIP_HEADER_TO, SIP_C_HEADER_TO);
+ }
+
+ if (to) {
+ to_loc = sippmh_parse_from_or_to((char *)to, TRUE);
+ if (to_loc) {
+ if (to_loc->tag) {
+ sstrncpy(to_tag, sip_sm_purify_tag(to_loc->tag),
+ to_tag_max_length);
+ }
+ sippmh_free_location(to_loc);
+ }
+ }
+
+ return;
+}
+
+
+boolean
+sipSPISendByeAuth (sipMessage_t *pResponse,
+ sipAuthenticate_t authen,
+ cpr_ip_addr_t *dest_ipaddr,
+ uint16_t dest_port,
+ uint32_t cseq_number,
+ char *alsoString,
+ char *last_call_route,
+ char *last_call_route_request_uri,
+ line_t previous_call_line)
+{
+ const char *fname = "sipSPISendByeAuth";
+ sipMessage_t *request = NULL;
+ sipRet_t flag = STATUS_SUCCESS;
+ sipRet_t tflag = STATUS_SUCCESS;
+ const char *response_contact = NULL;
+ const char *response_record_route = NULL;
+ const char *response_to = NULL;
+ const char *response_from = NULL;
+ const char *response_callid = NULL;
+ sipContact_t *response_contact_info = NULL;
+ sipRecordRoute_t *response_record_route_info = NULL;
+
+ cpr_ip_addr_t request_uri_addr;
+ uint16_t request_uri_port = 0;
+ cpr_ip_addr_t src_ipaddr;
+ char src_addr_str[MAX_IPADDR_STR_LEN];
+ static char ReqURI[MAX_SIP_URL_LENGTH];
+ static char via[SIP_MAX_VIA_LENGTH];
+ ccsipCCB_t *ccb = NULL;
+ int timeout = 0;
+ sipLocation_t *request_uri_loc = NULL;
+ sipUrl_t *request_uri_url = NULL;
+ sipUrl_t *sipUrl = NULL;
+ int i = 0;
+ int nat_enable = 0;
+
+ CPR_IP_ADDR_INIT(request_uri_addr);
+ CPR_IP_ADDR_INIT(src_ipaddr);
+
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_MSG_SENDING_REQUEST),
+ fname, "BYE(Auth)");
+
+ request = GET_SIP_MESSAGE();
+ if (!request) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "GET_SIP_MESSAGE()");
+ return (FALSE);
+ }
+
+ /* Init temp ccb to ccbs[previous_call_line] */
+ ccb = &gGlobInfo.ccbs[previous_call_line];
+ if (ccb->state != SIP_STATE_IDLE_MSG_TIMER_OUTSTANDING) {
+ CCSIP_DEBUG_ERROR("%s: Error: ccb %d is not in "
+ "SIP_STATE_IDLE_MSG_TIMER_OUTSTANDING state.\n",
+ fname, previous_call_line);
+ free_sip_message(request);
+ return (FALSE);
+ }
+ ccb->contact_info = NULL;
+ ccb->record_route_info = NULL;
+ ccb->flags = 0;
+
+ response_contact = sippmh_get_cached_header_val(pResponse, CONTACT);
+ response_record_route =
+ sippmh_get_cached_header_val(pResponse, RECORD_ROUTE);
+ response_to = sippmh_get_cached_header_val(pResponse, TO);
+ response_from = sippmh_get_cached_header_val(pResponse, FROM);
+ response_callid = sippmh_get_cached_header_val(pResponse, CALLID);
+
+ if (response_contact) {
+ response_contact_info = sippmh_parse_contact(response_contact);
+ ccb->contact_info = response_contact_info;
+ }
+ if (response_record_route) {
+ response_record_route_info =
+ sippmh_parse_record_route(response_record_route);
+ ccb->record_route_info = response_record_route_info;
+ }
+
+ /*
+ * Determine the Request-URI
+ */
+ memset(ReqURI, 0, sizeof(ReqURI));
+ if (response_record_route_info) {
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX"Forming Req-URI: using 401/407's Record-Route\n",
+ DEB_F_PREFIX_ARGS(SIP_REQ_URI, fname));
+ i = response_record_route_info->num_locations - 1;
+ if (response_record_route_info->locations[i]->genUrl->schema
+ == URL_TYPE_SIP) {
+ sipUrl = response_record_route_info->locations[i]->genUrl->u.sipUrl;
+ } else {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_URL_ERROR), fname);
+ if (ccb->record_route_info) {
+ sippmh_free_record_route(ccb->record_route_info);
+ ccb->record_route_info = NULL;
+ }
+ free_sip_message(request);
+ return (FALSE);
+ }
+
+ request_uri_port = sipUrl->port;
+ if (!sipUrl->port_present) {
+ dns_error_code =
+ sipTransportGetServerAddrPort(sipSPIUrlDestination(sipUrl),
+ &request_uri_addr,
+ &request_uri_port,
+ NULL, FALSE);
+ } else {
+ dns_error_code = dnsGetHostByName(sipSPIUrlDestination(sipUrl),
+ &request_uri_addr, 100, 1);
+ }
+ if (dns_error_code == 0) {
+ util_ntohl(&request_uri_addr, &request_uri_addr);
+
+ } else {
+ request_uri_addr = ip_addr_invalid;
+ }
+
+ if (sipUrl->user != NULL) {
+ if (sipUrl->password) {
+ snprintf(ReqURI, sizeof(ReqURI),
+ sipUrl->is_phone ? "sip:%s:%s@%s:%d;user=phone" :
+ "sip:%s:%s@%s:%d",
+ sipUrl->user, sipUrl->password,
+ sipUrl->host, sipUrl->port);
+ } else {
+ snprintf(ReqURI, sizeof(ReqURI),
+ sipUrl->is_phone ? "sip:%s@%s:%d;user=phone" :
+ "sip:%s@%s:%d", sipUrl->user, sipUrl->host,
+ sipUrl->port);
+ }
+ } else {
+ snprintf(ReqURI, sizeof(ReqURI),
+ sipUrl->is_phone ? "sip:%s:%d;user=phone" : "sip:%s:%d",
+ sipUrl->host, sipUrl->port);
+ }
+ } else if (last_call_route[0] && last_call_route_request_uri[0]) {
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX"Forming Req-URI: using current Route "
+ "information.\n", DEB_F_PREFIX_ARGS(SIP_REQ_URI, fname));
+ sstrncpy(ReqURI, last_call_route_request_uri, sizeof(ReqURI));
+ request_uri_addr = *dest_ipaddr;
+ request_uri_port = dest_port;
+ } else if (response_contact_info) {
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX"Forming Req-URI: using Contact\n", DEB_F_PREFIX_ARGS(SIP_REQ_URI, fname));
+ if (response_contact_info->locations[0]->genUrl->schema == URL_TYPE_SIP) {
+ sipUrl = response_contact_info->locations[0]->genUrl->u.sipUrl;
+ } else {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_URL_ERROR), fname);
+ if (ccb->contact_info) {
+ sippmh_free_contact(ccb->contact_info);
+ ccb->contact_info = NULL;
+ }
+ free_sip_message(request);
+ return (FALSE);
+ }
+
+ request_uri_port = sipUrl->port;
+ if (!sipUrl->port_present) {
+ dns_error_code =
+ sipTransportGetServerAddrPort(sipSPIUrlDestination(sipUrl),
+ &request_uri_addr,
+ &request_uri_port,
+ NULL, FALSE);
+ } else {
+ dns_error_code = dnsGetHostByName(sipSPIUrlDestination(sipUrl),
+ &request_uri_addr, 100, 1);
+ }
+ if (dns_error_code == 0) {
+
+ util_ntohl(&request_uri_addr, &request_uri_addr);
+ } else {
+ request_uri_addr = ip_addr_invalid;
+ }
+
+ if (sipUrl->user != NULL) {
+ if (sipUrl->password) {
+ snprintf(ReqURI, sizeof(ReqURI),
+ sipUrl->is_phone ? "sip:%s:%s@%s:%d;user=phone" :
+ "sip:%s:%s@%s:%d",
+ sipUrl->user, sipUrl->password,
+ sipUrl->host, sipUrl->port);
+ } else {
+ snprintf(ReqURI, sizeof(ReqURI),
+ sipUrl->is_phone ? "sip:%s@%s:%d;user=phone" :
+ "sip:%s@%s:%d", sipUrl->user,
+ sipUrl->host, sipUrl->port);
+ }
+ } else {
+ snprintf(ReqURI, sizeof(ReqURI),
+ sipUrl->is_phone ? "sip:%s:%d;user=phone" : "sip:%s:%d",
+ sipUrl->host, sipUrl->port);
+ }
+ } else {
+ request_uri_addr = *dest_ipaddr;
+ request_uri_port = dest_port;
+ request_uri_loc = sippmh_parse_from_or_to((char *)response_to, TRUE);
+ if (!request_uri_loc) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname,
+ get_debug_string(DEBUG_FUNCTIONNAME_SIPPMH_PARSE_TO));
+ free_sip_message(request);
+ return (FALSE);
+ }
+
+ if (!sippmh_valid_url(request_uri_loc->genUrl)) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sippmh_valid_url()");
+ sippmh_free_location(request_uri_loc);
+ free_sip_message(request);
+ return (FALSE);
+ }
+
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX"Forming Req-URI (Caller): using original "
+ "Req-URI\n", DEB_F_PREFIX_ARGS(SIP_REQ_URI, fname));
+ if (request_uri_loc->name) {
+ if (request_uri_loc->name[0]) {
+ sstrncat(ReqURI, "\"", sizeof(ReqURI) - strlen(ReqURI));
+ sstrncat(ReqURI, request_uri_loc->name,
+ sizeof(ReqURI) - strlen(ReqURI));
+ sstrncat(ReqURI, "\" ", sizeof(ReqURI) - strlen(ReqURI));
+ }
+ }
+ sstrncat(ReqURI, "sip:", sizeof(ReqURI) - strlen(ReqURI));
+ if (request_uri_loc->genUrl->schema == URL_TYPE_SIP) {
+ request_uri_url = request_uri_loc->genUrl->u.sipUrl;
+ } else {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_URL_ERROR), fname);
+ sippmh_free_location(request_uri_loc);
+ free_sip_message(request);
+ return (FALSE);
+ }
+
+ if (request_uri_url->user) {
+ sstrncat(ReqURI, request_uri_url->user,
+ sizeof(ReqURI) - strlen(ReqURI));
+ sstrncat(ReqURI, "@", sizeof(ReqURI) - strlen(ReqURI));
+ }
+ if (request_uri_url->is_phone) {
+ sstrncat(ReqURI, ";user=phone",
+ sizeof(ReqURI) - strlen(ReqURI));
+ }
+ sstrncat(ReqURI, request_uri_url->host,
+ sizeof(ReqURI) - strlen(ReqURI));
+ sippmh_free_location(request_uri_loc);
+ }
+
+ config_get_value(CFGID_NAT_ENABLE, &nat_enable, sizeof(nat_enable));
+ if (nat_enable == 0) {
+ sip_config_get_net_device_ipaddr(&src_ipaddr);
+ ipaddr2dotted(src_addr_str, &src_ipaddr);
+ } else {
+ sip_config_get_nat_ipaddr(&src_ipaddr);
+ ipaddr2dotted(src_addr_str, &src_ipaddr);
+ }
+
+ /*
+ * Build the request
+ */
+
+ /* Write Req-URI */
+ tflag = sippmh_add_request_line(request, SIP_METHOD_BYE, ReqURI,
+ SIP_VERSION);
+ UPDATE_FLAGS(flag, tflag);
+
+ /* Write Via */
+ snprintf(via, sizeof(via), "SIP/2.0/%s %s:%d;%s=%s%.8x",
+ sipTransportGetTransportType(ccb->dn_line, TRUE, ccb),
+ src_addr_str,
+ ccb->local_port,
+ VIA_BRANCH, VIA_BRANCH_START,
+ (unsigned int)cpr_rand());
+ tflag = sippmh_add_text_header(request, SIP_HEADER_VIA, via);
+ UPDATE_FLAGS(flag, tflag);
+
+ /* Write To, From, and Call-ID standard headers */
+ tflag = sippmh_add_text_header(request, SIP_HEADER_FROM, response_from);
+ UPDATE_FLAGS(flag, tflag);
+ tflag = sippmh_add_text_header(request, SIP_HEADER_TO, response_to);
+ UPDATE_FLAGS(flag, tflag);
+ tflag = sippmh_add_text_header(request, SIP_HEADER_CALLID, response_callid);
+ UPDATE_FLAGS(flag, tflag);
+
+ /* Write Date header */
+ tflag = sipAddDateHeader(request);
+ UPDATE_FLAGS(flag, tflag);
+
+ /* Write User Agent header */
+ tflag = sippmh_add_text_header(request, SIP_HEADER_USER_AGENT,
+ sipHeaderUserAgent);
+ UPDATE_FLAGS(flag, tflag);
+
+ /* add in call stats header if needed */
+ tflag = sipSPIAddCallStats(ccb, request);
+ UPDATE_FLAGS(flag, tflag);
+
+ /* Write Route */
+ if (response_record_route_info) {
+ tflag = (sipSPIAddRouteHeaders(request, ccb, NULL, 0)) ?
+ STATUS_SUCCESS : STATUS_FAILURE;
+ } else if (last_call_route[0]) {
+ tflag = sippmh_add_text_header(request, SIP_HEADER_ROUTE,
+ last_call_route);
+ }
+ UPDATE_FLAGS(flag, tflag);
+
+ /* Free contact and record-route */
+ if (response_contact) {
+ if (ccb->contact_info) {
+ sippmh_free_contact(ccb->contact_info);
+ ccb->contact_info = NULL;
+ }
+ }
+ if (response_record_route) {
+ if (ccb->record_route_info) {
+ sippmh_free_record_route(ccb->record_route_info);
+ ccb->record_route_info = NULL;
+ }
+ }
+
+ /* Write CSeq */
+ tflag = sippmh_add_cseq(request, SIP_METHOD_BYE, cseq_number);
+ UPDATE_FLAGS(flag, tflag);
+
+ if (alsoString) {
+ if (alsoString[0]) {
+ tflag = sippmh_add_text_header(request, SIP_HEADER_ALSO,
+ alsoString);
+ UPDATE_FLAGS(flag, tflag);
+ }
+ }
+
+ if (authen.authorization != NULL) {
+ tflag = sippmh_add_text_header(request, AUTHOR_HDR(authen.status_code),
+ authen.authorization);
+ UPDATE_FLAGS(flag, tflag);
+ cpr_free(authen.authorization);
+ }
+
+ /* If build error detected, cleanup and do not send message */
+ if (flag != STATUS_SUCCESS) {
+ /* !!! Clean up */
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_BUILDFLAG_ERROR), fname);
+ if (request)
+ free_sip_message(request);
+ return (FALSE);
+ }
+
+ /* Send message */
+ config_get_value(CFGID_TIMER_T1, &timeout, sizeof(timeout));
+ ccb->retx_counter = 0;
+ if (sipTransportChannelCreateSend(ccb, request, sipMethodBye,
+ &request_uri_addr,
+ request_uri_port, timeout,
+ RELDEV_NO_STORED_MSG) < 0) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sipTransportChannelCreateSend()");
+ if (request)
+ free_sip_message(request);
+
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+void
+free_sip_message (sipMessage_t *message)
+{
+ if (message) {
+ sippmh_message_free(message);
+ }
+}
+
+/*
+ * Generate the full URL (currently limited to the sipUrl only)
+ */
+void
+sipSPIGenerateTargetUrl (genUrl_t *genUrl, char *sipurlstr)
+{
+ uint8_t i;
+ char temp[MAX_SIP_HEADER_LENGTH];
+ size_t url_length = 0;
+ char *right_bracket = NULL;
+ boolean right_bracket_removed = FALSE;
+
+ if (genUrl->schema == URL_TYPE_SIP) {
+ sipSPIGenerateSipUrl(genUrl->u.sipUrl, sipurlstr);
+ } else {
+ return;
+ }
+
+ url_length = strlen(sipurlstr);
+ if (url_length == 0) {
+ return;
+ }
+
+ for (i = 0; i < SIP_MAX_LOCATIONS; i++) {
+ if (genUrl->other_params[i] != NULL) {
+ if (i == 0) {
+ // Remove the ">" from the end of sipurlstr
+ right_bracket = strchr(sipurlstr, '>');
+ if (right_bracket) {
+ *right_bracket = '\0';
+ right_bracket_removed = TRUE;
+ }
+ }
+ snprintf(temp, sizeof(temp), ";%s", genUrl->other_params[i]);
+ sstrncat(sipurlstr, temp, MAX_SIP_URL_LENGTH - url_length );
+ url_length = strlen(sipurlstr);
+ }
+ }
+
+ if (right_bracket_removed) {
+ sstrncat(sipurlstr, ">", MAX_SIP_URL_LENGTH - url_length);
+ }
+}
+
+/*
+ * Generates a plain string from sipUrl structure
+ *
+*/
+void
+sipSPIGenerateSipUrl (sipUrl_t *sipUrl, char *sipurlstr)
+{
+ char temp[MAX_SIP_HEADER_LENGTH];
+
+ if (sipUrl->user == NULL) {
+ snprintf(sipurlstr, MAX_SIP_HEADER_LENGTH, "host, sipUrl->port);
+ } else {
+ snprintf(sipurlstr, MAX_SIP_HEADER_LENGTH, "user, sipUrl->host, sipUrl->port);
+ }
+
+ /* Assume sipurlstr _length is the same for all clients */
+
+ if (sipUrl->maddr) {
+ snprintf(temp, sizeof(temp), ";maddr=%s", sipUrl->maddr);
+ sstrncat(sipurlstr, temp, MAX_SIP_HEADER_LENGTH );
+ }
+
+ if (sipUrl->ttl_val) {
+ snprintf(temp, sizeof(temp), ";ttl=%d", sipUrl->ttl_val);
+ sstrncat(sipurlstr, temp, MAX_SIP_HEADER_LENGTH);
+ }
+
+ switch (sipUrl->transport) {
+ case TRANSPORT_UDP:
+ sstrncat(sipurlstr, ";transport=udp", MAX_SIP_HEADER_LENGTH);
+ break;
+ case TRANSPORT_TCP:
+ sstrncat(sipurlstr, ";transport=tcp", MAX_SIP_HEADER_LENGTH);
+ break;
+ case TRANSPORT_TLS:
+ sstrncat(sipurlstr, ";transport=tls", MAX_SIP_HEADER_LENGTH);
+ break;
+ case TRANSPORT_SCTP:
+ sstrncat(sipurlstr, ";transport=sctp", MAX_SIP_HEADER_LENGTH);
+ break;
+ }
+
+ if (sipUrl->is_phone) {
+ sstrncat(sipurlstr, ";user=phone", MAX_SIP_HEADER_LENGTH);
+ }
+
+ sstrncat(sipurlstr, ">", MAX_SIP_HEADER_LENGTH);
+
+}
+
+#define MAX_SIP_METHOD_STRINGS 17
+#define MAX_SIP_METHOD_STRING_LEN 16
+const char *
+sipGetMethodString (sipMethod_t methodname /*, char *methodstring */)
+{
+ int ino = (int) methodname; //Register is defined as 100 in pmh.h file
+ //Please make sure the following array is consistent with the enum
+ int idx = 0;
+ static const char methods[MAX_SIP_METHOD_STRINGS][MAX_SIP_METHOD_STRING_LEN] =
+ { "REGISTER", "OPTIONS", "INVITE", "BYE",
+ "CANCEL", "PRACK", "COMET", "NOTIFY",
+ "REFER", "ACK", "MESSAGE", "SUBSCRIBE",
+ "PUBLISH", "UPDATE", "RESPONSE", "INFO", "UNKNOWN"
+ };
+
+
+ idx = ino - (int) sipMethodRegister;
+ if (idx >= 0 && idx <= (int) (sizeof(methods) / sizeof(methods[0]) - 1)) {
+ return methods[idx]; // Its OK to send this as it is a static array
+ } else {
+ return NULL;
+ }
+}
+
+sipRet_t
+sipSPIAddRequestLine (ccsipCCB_t *ccb, sipMessage_t *request,
+ sipMethod_t methodname, boolean initInvite)
+{
+ sipRet_t tflag = STATUS_FAILURE;
+
+ if (TRUE == sipSPIGenRequestURI(ccb, methodname, initInvite)) {
+ tflag = sippmh_add_request_line(request,
+ sipGetMethodString(methodname),
+ ccb->ReqURI,
+ SIP_VERSION);
+ } else {
+ tflag = STATUS_FAILURE;
+ }
+ return tflag;
+}
+
+boolean
+getCSeqInfo (sipMessage_t *request, sipCseq_t ** request_cseq_structure)
+{
+ const char *request_cseq = NULL;
+
+ request_cseq = sippmh_get_cached_header_val(request, CSEQ);
+ if (!request_cseq) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ "AddCSeq in Factory",
+ "sippmh_get_cached_header_val()");
+ return (FALSE);
+ }
+ *request_cseq_structure = sippmh_parse_cseq(request_cseq);
+ if (!*request_cseq_structure) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ "AddCSeq in Factory",
+ "sippmh_parse_cseq()");
+ return (FALSE);
+ }
+ return TRUE;
+}
+
+// Allocate an outgoing transaction and fill in the cseq number and method
+boolean
+allocateTrx (ccsipCCB_t *ccb, sipMethod_t method)
+{
+ uint32_t trx_cseq_number = 0;
+ int16_t new_trx_index = -1, last_trx_index = -1;
+
+ if (method == sipMethodCancel) {
+ // For CANCEL, the cseq is the same as the cseq
+ // of the earlier sent request that it cancels
+ last_trx_index = get_last_request_trx_index(ccb, TRUE);
+ if (last_trx_index < 0) {
+ return FALSE;
+ }
+ trx_cseq_number = ccb->sent_request[last_trx_index].cseq_number;
+ // Now allocate a new CSeq for the CANCEL request itself
+ new_trx_index = get_next_request_trx_index(ccb, TRUE);
+ if (new_trx_index < 0) {
+ return FALSE;
+ }
+ ccb->sent_request[new_trx_index].cseq_number = trx_cseq_number;
+ ccb->sent_request[new_trx_index].cseq_method = sipMethodCancel;
+
+ } else if (method != sipMethodAck) {
+ // No new transaction is needed for Ack
+ new_trx_index = get_next_request_trx_index(ccb, TRUE);
+ if (new_trx_index < 0) {
+ return FALSE;
+ }
+ ccb->sent_request[new_trx_index].cseq_number = ++(ccb->last_used_cseq);
+ ccb->sent_request[new_trx_index].cseq_method = method;
+ }
+ return TRUE;
+}
+
+boolean
+AddCSeq (ccsipCCB_t *ccb,
+ sipMessage_t *request,
+ boolean isResponse,
+ sipMethod_t method,
+ uint32_t response_cseq_number)
+{
+ uint32_t request_cseq_number = 0;
+ sipRet_t tflag = STATUS_FAILURE;
+ int16_t trx_index = -1;
+
+ if (TRUE == isResponse) {
+ if (response_cseq_number == 0) {
+ trx_index = get_method_request_trx_index(ccb, method, FALSE);
+ if (trx_index != -1) {
+ request_cseq_number = ccb->recv_request[trx_index].cseq_number;
+ } else {
+ return FALSE;
+ }
+ } else {
+ request_cseq_number = response_cseq_number;
+ }
+ } else {
+ // For Request
+ if (method == sipMethodAck) {
+ request_cseq_number = response_cseq_number;
+ } else {
+ // Pull up the previously allocated transaction
+ trx_index = get_last_request_trx_index(ccb, TRUE);
+ if (trx_index < 0) {
+ return FALSE;
+ }
+ request_cseq_number = ccb->sent_request[trx_index].cseq_number;
+ }
+ }
+ tflag = sippmh_add_cseq(request, sipGetMethodString(method),
+ request_cseq_number);
+ if (tflag != HSTATUS_SUCCESS) {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*
+ * This will generate the most common headers for every message
+ */
+
+sipRet_t
+sipSPIAddCommonHeaders (ccsipCCB_t *ccb,
+ sipMessage_t *request,
+ boolean isResponse,
+ sipMethod_t method,
+ uint32_t response_cseq_number)
+{
+ sipRet_t tflag = STATUS_FAILURE;
+
+ tflag = (sipSPIAddStdHeaders(request, ccb, isResponse)) ?
+ STATUS_SUCCESS : STATUS_FAILURE;
+ if (tflag != HSTATUS_SUCCESS) {
+ return tflag;
+ }
+
+ // Add date header
+ tflag = sipAddDateHeader(request);
+ if (tflag != HSTATUS_SUCCESS) {
+ return tflag;
+ }
+
+ // Add CSEQ
+ if (AddCSeq(ccb, request, isResponse, method, response_cseq_number)
+ == FALSE) {
+ return STATUS_FAILURE;
+ }
+
+ return HSTATUS_SUCCESS;
+}
+
+boolean
+is_extended_feature (ccsipCCB_t *ccb)
+{
+ if (ccb) {
+ switch (ccb->featuretype) {
+ case CC_FEATURE_B2BCONF:
+ case CC_FEATURE_CANCEL:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+ }
+ return FALSE;
+}
+
+boolean
+sipSPIGenRequestURI (ccsipCCB_t *ccb, sipMethod_t sipmethod, boolean initInvite)
+{
+ sipUrl_t *sipUrl = NULL;
+ int i = 0;
+ const char *fname = "sipSPIGenRequestURI";
+ char dest_sip_addr_str[MAX_IPADDR_STR_LEN];
+ char *domainloc;
+ genUrl_t *gen;
+ int j = 0;
+ boolean lr = FALSE, uriAdded = FALSE;
+ char hdr_str[MAX_SIP_URL_LENGTH];
+
+ /*
+ * Construct the request URI
+ */
+ // Special case for Initial Invite and Cancel messgae for creating
+ // the Request URI
+ if ((sipMethodInvite == sipmethod) && (initInvite == TRUE)) {
+ // This is the first Invite initiated so Request URI is
+ // built differently.
+ if (ccb->calledNumber[0] == '<') {
+ // Remove leading '<'
+ sstrncpy(ccb->ReqURI, ccb->calledNumber + 1, MAX_SIP_URL_LENGTH);
+ }
+ // If there is no hostname, add proxy address as hostname
+ domainloc = strchr(ccb->ReqURI, '@');
+ if (domainloc == NULL) {
+ domainloc = ccb->ReqURI + strlen(ccb->ReqURI);
+ if ((domainloc - ccb->ReqURI) < (MAX_SIP_URL_LENGTH - 1)) {
+ /*
+ * We need to check and see if we are already truncating a
+ * string string that goes into ReqURI. If we are, then we
+ * CANNOT add any more characters without overwriting memory
+ */
+ *domainloc++ = '@';
+ sstrncpy(dest_sip_addr_str, ccb->reg.proxy,
+ MAX_IPADDR_STR_LEN);
+
+ if (ccb->reg.addr.type == CPR_IP_ADDR_IPV6) {
+ *domainloc++ = '[';
+ }
+
+ sstrncpy(domainloc, dest_sip_addr_str,
+ MAX_SIP_URL_LENGTH - (domainloc - ccb->ReqURI));
+
+ if (ccb->reg.addr.type == CPR_IP_ADDR_IPV6) {
+ *domainloc++ = ']';
+ }
+ }
+ }
+ // Remove trailing '>'
+ domainloc = strchr(ccb->ReqURI, '>');
+ if (domainloc) {
+ *domainloc = '\0';
+ }
+ return TRUE;
+ } else if ((sipMethodCancel == sipmethod) ||
+ ((sipMethodAck == sipmethod) &&
+ (gCallHistory[ccb->index].last_rspcode_rcvd > codeClass2xx))) {
+ /* Use the same REQ URI that was created on the INVITE
+ * Replace the ReqURI with the contents of ReqURIOriginal
+ */
+ if (ccb->ReqURIOriginal[0] != '\0') {
+ sstrncpy(ccb->ReqURI, ccb->ReqURIOriginal, MAX_SIP_URL_LENGTH);
+ }
+ return TRUE;
+ }
+
+ if (sipMethodRegister == sipmethod ||
+ ((sipMethodRefer == sipmethod) &&
+ (ccb->type == SIP_REG_CCB || is_extended_feature(ccb)))) {
+ // If it is REGISTER or a token-registration REFER, the URI is formed
+ // simply by the destination IP address. This is also the case when
+ // sending a REFER for one of the softkey functions for TNP
+ if (ccb->reg.proxy[0] == '\0') {
+ ipaddr2dotted(dest_sip_addr_str, &ccb->dest_sip_addr);
+ } else {
+ sstrncpy(dest_sip_addr_str, ccb->reg.proxy, MAX_IPADDR_STR_LEN);
+ }
+ if (ccb->dest_sip_addr.type == CPR_IP_ADDR_IPV6) {
+
+ snprintf(ccb->ReqURI, MAX_SIP_URL_LENGTH, "sip:[%s]",
+ dest_sip_addr_str); /* proxy */
+ } else {
+ snprintf(ccb->ReqURI, MAX_SIP_URL_LENGTH, "sip:%s",
+ dest_sip_addr_str); /* proxy */
+ }
+
+ return TRUE;
+ } else {
+ if (ccb->record_route_info) {
+ /*
+ * If loose-routing is being used, use the remote contact in
+ * REQ-URI
+ */
+ if (ccb->flags & INCOMING) {
+ i = 0;
+ } else {
+ i = ccb->record_route_info->num_locations - 1;
+ }
+
+ if (ccb->record_route_info->locations[i]->genUrl->schema
+ == URL_TYPE_SIP) {
+ if (ccb->record_route_info->locations[i]->genUrl->u.sipUrl->lr_flag) {
+ lr = TRUE;
+ }
+ }
+ if (!lr) {
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX"Strict Routing: Forming Req-URI using "
+ "Record Route\n", DEB_F_PREFIX_ARGS(SIP_REQ_URI, fname));
+ if (ccb->record_route_info->locations[i]->genUrl->schema
+ == URL_TYPE_SIP) {
+ sipUrl = ccb->record_route_info->locations[i]->genUrl->u.sipUrl;
+ } else {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_URL_ERROR),
+ fname);
+ return (FALSE);
+ }
+
+ if (sipUrl->user != NULL) {
+ if (sipUrl->password) {
+ if (sipUrl->port_present) {
+ snprintf(ccb->ReqURI, MAX_SIP_URL_LENGTH,
+ sipUrl->is_phone ?
+ "sip:%s:%s@%s:%d;user=phone" :
+ "sip:%s:%s@%s:%d",
+ sipUrl->user, sipUrl->password,
+ sipUrl->host, sipUrl->port);
+ } else {
+ snprintf(ccb->ReqURI, MAX_SIP_URL_LENGTH,
+ sipUrl->is_phone ?
+ "sip:%s:%s@%s;user=phone" :
+ "sip:%s:%s@%s",
+ sipUrl->user, sipUrl->password,
+ sipUrl->host);
+ }
+ } else {
+ if (sipUrl->port_present) {
+ snprintf(ccb->ReqURI, MAX_SIP_URL_LENGTH,
+ sipUrl->is_phone ?
+ "sip:%s@%s:%d;user=phone" : "sip:%s@%s:%d",
+ sipUrl->user, sipUrl->host, sipUrl->port);
+ } else {
+ snprintf(ccb->ReqURI, MAX_SIP_URL_LENGTH,
+ sipUrl->is_phone ?
+ "sip:%s@%s;user=phone" : "sip:%s@%s",
+ sipUrl->user, sipUrl->host);
+ }
+ }
+ } else {
+ if (sipUrl->port_present) {
+ snprintf(ccb->ReqURI, MAX_SIP_URL_LENGTH,
+ sipUrl->is_phone ?
+ "sip:%s:%d;user=phone" : "sip:%s:%d",
+ sipUrl->host, sipUrl->port);
+ } else {
+ snprintf(ccb->ReqURI, MAX_SIP_URL_LENGTH,
+ sipUrl->is_phone ?
+ "sip:%s;user=phone" : "sip:%s",
+ sipUrl->host);
+ }
+ }
+ uriAdded = TRUE;
+ }
+ }
+
+ if (!uriAdded) {
+ if ((ccb->contact_info) &&
+ (lr || (ccb->state >= SIP_STATE_SENT_INVITE_CONNECTED))) {
+ // Use Contact info ONLY if loose routing or
+ // if we're fully connected - otherwise use proxy
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX"Forming Req-URI: using Contact\n",
+ DEB_F_PREFIX_ARGS(SIP_REQ_URI, fname));
+
+ if ((sipMethodInvite == sipmethod) &&
+ (ccb->redirect_info) &&
+ (ccb->state == SIP_STATE_SENT_INVITE)) {
+ sipUrl = ccb->redirect_info->sipContact->locations
+ [ccb->redirect_info->next_choice - 1]->genUrl->u.sipUrl;
+ } else if (ccb->contact_info->locations[0]->genUrl->schema
+ == URL_TYPE_SIP) {
+ sipUrl = ccb->contact_info->locations[0]->genUrl->u.sipUrl;
+ } else {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_URL_ERROR),
+ fname);
+ return (FALSE);
+ }
+ if (sipUrl->user != NULL) {
+ if (sipUrl->password) {
+ snprintf(ccb->ReqURI, MAX_SIP_URL_LENGTH,
+ sipUrl->is_phone ?
+ "sip:%s:%s@%s:%d;user=phone" :
+ "sip:%s:%s@%s:%d",
+ sipUrl->user, sipUrl->password,
+ sipUrl->host, sipUrl->port);
+ } else {
+ snprintf(ccb->ReqURI, MAX_SIP_URL_LENGTH,
+ sipUrl->is_phone ?
+ "sip:%s@%s:%d;user=phone" :
+ "sip:%s@%s:%d",
+ sipUrl->user, sipUrl->host, sipUrl->port);
+ }
+ } else {
+ snprintf(ccb->ReqURI, MAX_SIP_URL_LENGTH,
+ sipUrl->is_phone ?
+ "sip:%s:%d;user=phone" :
+ "sip:%s:%d",
+ sipUrl->host, sipUrl->port);
+ }
+ } else {
+ if (ccb->flags & INCOMING) {
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX"Forming Req-URI (Callee): using "
+ "From\n", DEB_F_PREFIX_ARGS(SIP_REQ_URI, fname));
+ if (ccb->sip_from) {
+ sstrncpy(hdr_str, ccb->sip_from, MAX_SIP_URL_LENGTH);
+ sstrncpy(ccb->ReqURI, sippmh_get_url_from_hdr(hdr_str), MAX_SIP_URL_LENGTH);
+ }
+ } else {
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX"Forming Req-URI (Caller): using "
+ "original Req-URI\n", DEB_F_PREFIX_ARGS(SIP_REQ_URI, fname));
+ sstrncpy(ccb->ReqURI, ccb->ReqURIOriginal,
+ MAX_SIP_URL_LENGTH);
+ }
+ }
+ }
+
+ // Check to see the transport parameter specified in sipUrl.
+ // If this is different than UDP, add it to the URI
+ if (sipUrl) {
+ switch (sipUrl->transport) {
+ case TRANSPORT_UDP:
+ sstrncat(ccb->ReqURI, ";transport=udp",
+ sizeof(ccb->ReqURI) - strlen(ccb->ReqURI));
+ break;
+ case TRANSPORT_TCP:
+ sstrncat(ccb->ReqURI, ";transport=tcp",
+ sizeof(ccb->ReqURI) - strlen(ccb->ReqURI));
+ break;
+ case TRANSPORT_TLS:
+ sstrncat(ccb->ReqURI, ";transport=tls",
+ sizeof(ccb->ReqURI) - strlen(ccb->ReqURI));
+ break;
+ case TRANSPORT_SCTP:
+ sstrncat(ccb->ReqURI, ";transport=sctp",
+ sizeof(ccb->ReqURI) - strlen(ccb->ReqURI));
+ break;
+ default:
+ break;
+ }
+ }
+ if (ccb->record_route_info) {
+ /*
+ * Look for any unknown params that might have been
+ * glued onto the URL
+ */
+ gen = ccb->record_route_info->locations[i]->genUrl;
+ while (j < SIP_MAX_LOCATIONS) {
+ if (gen->other_params[j] != NULL) {
+ sstrncat(ccb->ReqURI, ";",
+ sizeof(ccb->ReqURI) - strlen(ccb->ReqURI));
+ sstrncat(ccb->ReqURI, gen->other_params[j],
+ sizeof(ccb->ReqURI) - strlen(ccb->ReqURI));
+ break;
+ }
+ j++;
+ }
+ }
+ }
+ return TRUE;
+}
+
+sipRet_t
+sipSPIAddContactHeader (ccsipCCB_t *ccb, sipMessage_t *request)
+{
+ char pContactStr[MAX_SIP_URL_LENGTH];
+ char src_addr_str[MAX_IPADDR_STR_LEN];
+ char line_name[MAX_LINE_NAME_SIZE];
+ char reg_user_info[MAX_REG_USER_INFO_LEN];
+ int rpid_flag = RPID_DISABLED;
+ int blocking;
+ uint8_t mac_address[MAC_ADDRESS_LENGTH];
+ char device_instance[MAX_SIP_TAG_LENGTH];
+ char contact[MAX_LINE_CONTACT_SIZE];
+ size_t escaped_char_str_len;
+ const char *transport_type_str;
+ int size;
+ char sipDeviceName[MAX_REG_USER_INFO_LEN];
+
+ config_get_value(CFGID_REMOTE_PARTY_ID, &rpid_flag, sizeof(rpid_flag));
+
+ config_get_value(CFGID_DEVICE_NAME, sipDeviceName, sizeof(sipDeviceName));
+
+ /* get reg_user_info and pk-id */
+ contact[0] = '\0';
+ config_get_string(CFGID_REG_USER_INFO, reg_user_info,
+ sizeof(reg_user_info));
+ config_get_line_string(CFGID_LINE_CONTACT, contact, ccb->dn_line,
+ sizeof(contact));
+
+
+ ipaddr2dotted(src_addr_str, &ccb->src_addr);
+
+ config_get_value(CFGID_CALLERID_BLOCKING, &blocking, sizeof(blocking));
+
+ transport_type_str = sipTransportGetTransportType(ccb->dn_line, FALSE, ccb);
+
+ /*
+ * If caller id blocking is enabled and phone
+ * is configured to use RPID then userinfo should
+ * be random identifier same as that used in from
+ * header
+ */
+ if ((blocking & 1) && (rpid_flag == RPID_ENABLED) &&
+ (ccb->type != SIP_REG_CCB)) {
+ sstrncpy(line_name, SIP_HEADER_ANONYMOUS_STR, MAX_LINE_NAME_SIZE);
+ } else {
+ config_get_line_string(CFGID_LINE_NAME, line_name, ccb->dn_line,
+ sizeof(line_name));
+ }
+
+ if (ccb->type == SIP_REG_CCB) {
+ snprintf(pContactStr, 6, "", src_addr_str,
+ ccb->local_port, transport_type_str);
+ } else {
+ snprintf(pContactStr + 5 + escaped_char_str_len,
+ sizeof(pContactStr) - 5 - escaped_char_str_len,
+ "@%s:%d;user=%s;transport=%s>",
+ src_addr_str, ccb->local_port, reg_user_info,
+ transport_type_str);
+ }
+
+ // Add the instance ID for unique device identification
+ // The format is as follows:
+ // Contact:
+ // ;+sip.instance=""
+ // ;+u.sip!model.ccm.cisco.com="336"
+ // where the 000A95A0E128 is the MAC address of the phone and
+ // the 336 is the model number of the phone
+ // All the 000's are supposed to encode callee capabilities (RFC 3840)
+ // but we are leaving them 000 for now as no-one reads them
+ platform_get_active_mac_address(mac_address);
+ memset(device_instance, '\0', sizeof(device_instance));
+ snprintf(device_instance, MAX_SIP_TAG_LENGTH,
+ ";+sip.instance=\"\"",
+ mac_address[0] * 256 + mac_address[1],
+ mac_address[2] * 256 + mac_address[3],
+ mac_address[4] * 256 + mac_address[5]);
+ size = MAX_SIP_URL_LENGTH - strlen(pContactStr);
+ if (size > (int)strlen(device_instance)) {
+ sstrncat(pContactStr, device_instance, size);
+ }
+ // Add the instance ID for unique device identification
+ // The format is as follows:
+ // Contact: ;+sip.instance="";
+ //+u.sip!devicename.ccm.cisco.com="SEP0019E89A7F3D";
+ //++u.sip!model.ccm.cisco.com="30006"
+ // where the 000A95A0E128 is the MAC address of the phone and
+ // the 336 is the model number of the phone
+ // All the 000's are supposed to encode callee capabilities (RFC 3840)
+ // but we are leaving them 000 for now as no-one reads them
+ platform_get_wired_mac_address(mac_address);
+ memset(device_instance, '\0', sizeof(device_instance));
+ snprintf(device_instance, MAX_SIP_TAG_LENGTH,
+ ";+sip.instance=\"\""
+ ";+u.sip!devicename.ccm.cisco.com=\"%s\""
+ ";+u.sip!model.ccm.cisco.com=\"%s\"",
+ mac_address[0] * 256 + mac_address[1],
+ mac_address[2] * 256 + mac_address[3],
+ mac_address[4] * 256 + mac_address[5],
+ sipDeviceName,
+ sipPhoneModelNumber);
+ size = MAX_SIP_URL_LENGTH - strlen(pContactStr);
+ if (size > (int)strlen(device_instance)) {
+ sstrncat(pContactStr, device_instance, size);
+ }
+ // add tag cisco-keep-alive for keep alive messages in ccm mode
+ if ((ccb->cc_type == CC_CCM) && (ccb->index >= REG_BACKUP_CCB)) {
+ sipMethod_t method = sipMethodInvalid;
+
+ sipGetRequestMethod(request, &method);
+ if (method == sipMethodRegister) {
+ sstrncat(pContactStr, ";expires=0;cisco-keep-alive",
+ sizeof(pContactStr) - strlen(pContactStr));
+ }
+ }
+ } else {
+ char *forward_url = NULL;
+
+ forward_url = Basic_is_phone_forwarded(ccb->dn_line);
+ /* only use the forward URL if we are sending a 302 */
+ if ((forward_url) &&
+ (strstr(request->mesg_line, SIP_RED_MOVED_TEMP_PHRASE))) {
+ char *user_info = strchr(forward_url, '@');
+
+ /*
+ * forward_url will always have domain/host address preceded
+ * by @ following the user, returned by
+ * Basic_is_phone_forwarded. so no need to check for
+ * user_info == NULL
+ */
+ snprintf(pContactStr, 6, "",
+ user_info);
+ } else {
+ /*
+ * Use the contact value supplied to us, if available.
+ * If not, use name
+ */
+ snprintf(pContactStr, 6, "", src_addr_str,
+ ccb->local_port, transport_type_str);
+ } else {
+ snprintf(pContactStr + 5 + escaped_char_str_len,
+ sizeof(pContactStr) - 5 - escaped_char_str_len,
+ "@%s:%d;user=%s;transport=%s>",
+ src_addr_str, ccb->local_port,
+ reg_user_info, transport_type_str);
+ }
+ }
+ }
+ return (sippmh_add_text_header(request, SIP_HEADER_CONTACT, pContactStr));
+}
+
+/**
+ * Convert phone name to upper case
+ *
+ * @param phone_name - phone name
+ *
+ * @return status none
+ *
+ * @pre none
+ */
+void convert_phone_name_to_upper_case(char *phone_name)
+{
+ while (phone_name && (*phone_name) != '\0') {
+ *phone_name = (char)toupper(*phone_name);
+ phone_name++;
+ }
+}
+/**
+ * Add reason header to SIP message
+ *
+ * eg: Reason: SIP;cause=200;text="cisco:22 Name=SEP000000000000
+ * Load=SIP70.8-2-25 Last=reset-reset
+ *
+ * @param ccb call control block
+ * @param request sip message
+ *
+ * @return status
+ * success: STATUS_SUCCESS
+ * failure: STATUS_FAILURE
+ *
+ * @pre (ccb not_eq NULL)
+ * @pre (request not_eq NULL)
+ *
+ */
+sipRet_t
+sipSPIAddReasonHeader (ccsipCCB_t *ccb, sipMessage_t *request)
+{
+ const char *fname = "sipSPIAddReasonHeader";
+ char pReasonStr[MAX_SIP_HEADER_LENGTH];
+ uint8_t mac_address[MAC_ADDRESS_LENGTH];
+ char phone_name[MAX_PHONE_NAME_LEN];
+ char image_a[MAX_LOAD_ID_STRING];
+ char image_b[MAX_LOAD_ID_STRING];
+ int active_partition;
+ int unreg_reason_code = 0;
+ char unreg_reason_str[MAX_UNREG_REASON_STR_LEN];
+
+ if (ccb->send_reason_header) {
+ // should only be set when the phone is registering after a restart/reset
+ platform_get_wired_mac_address(mac_address);
+
+ snprintf(phone_name, MAX_PHONE_NAME_LEN, "SEP%04x%04x%04x", mac_address[0] * 256 + mac_address[1],
+ mac_address[2] * 256 + mac_address[3],
+ mac_address[4] * 256 + mac_address[5]);
+
+ convert_phone_name_to_upper_case(phone_name);
+
+
+ unreg_reason_code = platGetUnregReason();
+
+ unreg_reason_str[0] = '\0';
+ get_reason_string(unreg_reason_code, unreg_reason_str, MAX_UNREG_REASON_STR_LEN);
+ active_partition = platGetActiveInactivePhoneLoadName(image_a, image_b, MAX_LOAD_ID_STRING);
+ snprintf(pReasonStr, MAX_SIP_HEADER_LENGTH,
+ "SIP;cause=200;text=\"cisco-alarm:%d Name=%s ActiveLoad=%s InactiveLoad=%s Last=%s",
+ unreg_reason_code, phone_name, (active_partition == 1) ? image_a:image_b,
+ (active_partition == 1) ? image_b:image_a, unreg_reason_str);
+ sstrncat(pReasonStr, "\"",
+ MAX_SIP_HEADER_LENGTH - strlen(pReasonStr) - 1);
+ return (sippmh_add_text_header(request, SIP_HEADER_REASON, pReasonStr));
+ } else {
+ CCSIP_DEBUG_ERROR("%s called with send_reason_header set to false\n", fname);
+ return (STATUS_SUCCESS);
+ }
+}
+
+/**
+ * Return the reason string that is to be returned
+ * corresponding to the unreg reason that is to be sent
+ * in the register message.
+ *
+ * @param unreg_reason - unreg reason code
+ * @param char * - reason string corresponding to the code
+ * @return none
+ *
+ */
+void
+get_reason_string (int unreg_reason, char *unreg_reason_str, int len)
+{
+
+ switch(unreg_reason) {
+ case UNREG_REASON_RESET_RESTART:
+ snprintf(unreg_reason_str, MAX_UNREG_REASON_STR_LEN, "reset-restart");
+ break;
+ case UNREG_REASON_RESET_RESET:
+ snprintf(unreg_reason_str, MAX_UNREG_REASON_STR_LEN, "reset-reset");
+ break;
+ case UNREG_REASON_PHONE_INITIALIZED:
+ snprintf(unreg_reason_str, MAX_UNREG_REASON_STR_LEN, "initialized");
+ break;
+ case UNREG_REASON_REG_TIMEOUT:
+ snprintf(unreg_reason_str, MAX_UNREG_REASON_STR_LEN, "reg-timeout");
+ break;
+ case UNREG_REASON_PHONE_KEYPAD:
+ snprintf(unreg_reason_str, MAX_UNREG_REASON_STR_LEN, "phone-keypad");
+ break;
+ case UNREG_REASON_PHONE_REG_REJ:
+ snprintf(unreg_reason_str, MAX_UNREG_REASON_STR_LEN, "phone-reg-rej");
+ break;
+ case UNREG_REASON_FALLBACK:
+ snprintf(unreg_reason_str, MAX_UNREG_REASON_STR_LEN, "fallback");
+ break;
+ case UNREG_REASON_VERSION_STAMP_MISMATCH:
+ snprintf(unreg_reason_str, MAX_UNREG_REASON_STR_LEN, "version-stamp-mismatch(%s)", sipUnregisterReason);
+ break;
+ case UNREG_REASON_VERSION_STAMP_MISMATCH_CONFIG:
+ snprintf(unreg_reason_str, MAX_UNREG_REASON_STR_LEN, "version-stamp-mismatch-config");
+ break;
+ case UNREG_REASON_VERSION_STAMP_MISMATCH_SOFTKEY:
+ snprintf(unreg_reason_str, MAX_UNREG_REASON_STR_LEN, "version-stamp-mismatch-softkey");
+ break;
+ case UNREG_REASON_VERSION_STAMP_MISMATCH_DIALPLAN:
+ snprintf(unreg_reason_str, MAX_UNREG_REASON_STR_LEN, "version-stamp-mismatch-dialplan");
+ break;
+ case UNREG_REASON_CONFIG_RETRY_RESTART:
+ snprintf(unreg_reason_str, MAX_UNREG_REASON_STR_LEN, "config-retry-restart");
+ break;
+ case UNREG_REASON_TLS_ERROR:
+ snprintf(unreg_reason_str, MAX_UNREG_REASON_STR_LEN, "tls-error");
+ break;
+ case UNREG_REASON_TCP_TIMEOUT:
+ snprintf(unreg_reason_str, MAX_UNREG_REASON_STR_LEN, "tcp_timeout");
+ break;
+ case UNREG_REASON_CM_CLOSED_TCP:
+ snprintf(unreg_reason_str, MAX_UNREG_REASON_STR_LEN, "cm-closed-tcp");
+ break;
+ case UNREG_REASON_CM_RESET_TCP:
+ snprintf(unreg_reason_str, MAX_UNREG_REASON_STR_LEN, "cm-reset-tcp");
+ break;
+ case UNREG_REASON_CM_ABORTED_TCP:
+ snprintf(unreg_reason_str, MAX_UNREG_REASON_STR_LEN, "cm-aborted-tcp");
+ break;
+ case UNREG_REASON_APPLY_CONFIG_RESTART:
+ snprintf(unreg_reason_str, MAX_UNREG_REASON_STR_LEN, "apply_config");
+ break;
+ case UNREG_REASON_VOICE_VLAN_CHANGED:
+ snprintf(unreg_reason_str, MAX_UNREG_REASON_STR_LEN, "VLAN-Changed");
+ break;
+ default:
+ unreg_reason_str[0] = '\0';
+ CCSIP_DEBUG_ERROR("Unkown unreg reason code passed\n");
+ break;
+ }
+}
+boolean
+CreateRequest (ccsipCCB_t *ccb, sipMessageFlag_t messageflag,
+ sipMethod_t sipmethod, sipMessage_t *request,
+ boolean initInvite, uint32_t response_cseq_number)
+{
+ sipRet_t tflag = STATUS_FAILURE;
+
+ if (!request) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ "CreateRequest", "GET_SIP_MESSAGE()");
+ return FALSE;
+ }
+
+
+ if (sipMethodResponse != sipmethod) {
+ if (sipSPIAddRequestLine(ccb, request, sipmethod, initInvite)
+ == STATUS_FAILURE) {
+ return FALSE;
+ }
+ }
+
+ ccb->outBoundProxyPort = 0;
+ ccb->outBoundProxyAddr = ip_addr_invalid;
+ if (ccb->ObpSRVhandle != NULL) {
+ dnsFreeSrvHandle(ccb->ObpSRVhandle);
+ ccb->ObpSRVhandle = NULL;
+ }
+
+ tflag = (allocateTrx(ccb, sipmethod)) ? STATUS_SUCCESS : STATUS_FAILURE;
+
+ if (tflag == STATUS_SUCCESS) {
+ tflag = (sipSPIAddLocalVia(request, ccb, sipmethod)) ?
+ STATUS_SUCCESS : STATUS_FAILURE;
+ /* Don't stop adding headers to a Register just because
+ * the VIA line wasn't added. A Register doesn't really
+ * need the VIA line anyways.
+ */
+ if ((HSTATUS_SUCCESS != tflag) && (ccb->type != SIP_REG_CCB)) {
+ return FALSE;
+ }
+ }
+
+ if (tflag == STATUS_SUCCESS) {
+ tflag = sipSPIAddCommonHeaders(ccb, request, FALSE, sipmethod,
+ response_cseq_number);
+ }
+
+ if (tflag != HSTATUS_SUCCESS) {
+ return FALSE;
+ }
+
+ tflag = sippmh_add_text_header(request, SIP_HEADER_USER_AGENT,
+ sipHeaderUserAgent);
+
+ if (tflag != HSTATUS_SUCCESS) {
+ return FALSE;
+ }
+ return AddGeneralHeaders(ccb, messageflag, request, sipmethod);
+}
+
+boolean
+CreateResponse (ccsipCCB_t *ccb,
+ sipMessageFlag_t messageflag,
+ uint16_t status_code,
+ sipMessage_t *response,
+ const char *reason_phrase,
+ uint16_t status_code_warning,
+ const char *reason_phrase_warning,
+ sipMethod_t method)
+{
+ sipRet_t tflag = HSTATUS_SUCCESS;
+ char *warning = NULL;
+ uint32_t response_cseq_number = 0;
+
+ if (!ccb) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_BADARGUMENT),
+ "CreateResponse", "ccb");
+ return FALSE;
+ }
+ if (!ccb->last_request) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_BADARGUMENT),
+ "Create Response", "ccb->last_request");
+ return FALSE;
+ }
+ if (!response) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ "CreateResponse", "GET_SIP_MESSAGE()");
+ return FALSE;
+ }
+
+ tflag = sippmh_add_response_line(response, SIP_VERSION, status_code,
+ reason_phrase);
+
+ if (tflag != HSTATUS_SUCCESS)
+ return FALSE;
+
+ tflag = (sipSPIAddRequestVia(ccb, response, ccb->last_request, method)) ?
+ STATUS_SUCCESS : STATUS_FAILURE;
+
+ if (tflag != HSTATUS_SUCCESS)
+ return FALSE;
+
+ response_cseq_number = 0;
+
+ tflag = sipSPIAddCommonHeaders(ccb, response, TRUE, method,
+ response_cseq_number);
+ if (tflag != HSTATUS_SUCCESS)
+ return FALSE;
+
+ if (reason_phrase_warning) {
+ warning = (char *) cpr_malloc(strlen(reason_phrase_warning) + 5);
+ if (warning) {
+ snprintf(warning, strlen(reason_phrase_warning) + 5,
+ "%d %s", status_code_warning, reason_phrase_warning);
+ tflag = sippmh_add_text_header(response, SIP_HEADER_WARN, warning);
+ cpr_free(warning);
+ if (tflag != HSTATUS_SUCCESS)
+ return FALSE;
+ }
+ }
+
+ tflag = sippmh_add_text_header(response, SIP_HEADER_SERVER,
+ sipHeaderServer);
+ if (tflag != HSTATUS_SUCCESS) {
+ return FALSE;
+ }
+
+ return AddGeneralHeaders(ccb, messageflag, response, method);
+}
+
+/*************************************************************
+ * Function: SendRequest
+ * this function sends out a request pointed to by the request parameter
+ * in ccb's context.
+ *
+ * 'request' will be freed. The caller does not have the responsibility
+ * to free it.
+ **************************************************************/
+boolean
+SendRequest (ccsipCCB_t *ccb, sipMessage_t *request, sipMethod_t method,
+ boolean midcall, boolean reTx, boolean retranTimer)
+{
+ const char *fname = "SendRequest";
+ cpr_ip_addr_t cc_remote_ipaddr;
+ uint16_t cc_remote_port = 0;
+ int timeout = 0;
+ int expires_timeout;
+ sipUrl_t *sipUrl = NULL;
+ boolean isRegister = FALSE;
+ int16_t trx_index;
+ int reldev_stored_msg = RELDEV_NO_STORED_MSG;
+
+ CPR_IP_ADDR_INIT(cc_remote_ipaddr);
+
+ if (sipMethodRegister == method) {
+ if (ccb->reg.proxy[0] == '\0') {
+ cc_remote_ipaddr = ccb->dest_sip_addr;
+ cc_remote_port = (uint16_t) ccb->dest_sip_port;
+ } else {
+ cc_remote_ipaddr = ccb->reg.addr;
+ cc_remote_port = ccb->reg.port;
+ }
+ config_get_value(CFGID_TIMER_T1, &timeout, sizeof(timeout));
+ isRegister = TRUE;
+
+ } else if ((sipMethodInvite == method) && (midcall == FALSE)) {
+ char *host;
+
+ if (!ccb->ReqURI) {
+ free_sip_message(request);
+ return FALSE;
+ }
+ host = strchr(ccb->ReqURI, '@');
+ if (!host) {
+ free_sip_message(request);
+ return FALSE;
+ }
+
+ /* Enable reTx and send */
+ if (TRUE == reTx) {
+ config_get_value(CFGID_TIMER_T1, &timeout, sizeof(timeout));
+ }
+ cc_remote_ipaddr = ccb->dest_sip_addr;
+ cc_remote_port = (uint16_t) ccb->dest_sip_port;
+ } else {
+ if ((ccb->record_route_info) && (sipMethodCancel != method)) {
+ int16_t i;
+
+ if (ccb->flags & INCOMING) {
+ i = 0;
+ } else {
+ i = ccb->record_route_info->num_locations - 1;
+ }
+
+ if (ccb->record_route_info->locations[i]->genUrl->schema
+ == URL_TYPE_SIP) {
+ sipUrl = ccb->record_route_info->locations[i]->genUrl->u.sipUrl;
+ } else {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_URL_ERROR), fname);
+ free_sip_message(request);
+ return (FALSE);
+ }
+
+ cc_remote_port = sipUrl->port;
+
+ if (!sipUrl->port_present) {
+ dns_error_code =
+ sipTransportGetServerAddrPort(sipSPIUrlDestination(sipUrl),
+ &cc_remote_ipaddr,
+ &cc_remote_port,
+ NULL, FALSE);
+ } else {
+ dns_error_code = dnsGetHostByName(sipSPIUrlDestination(sipUrl),
+ &cc_remote_ipaddr, 100, 1);
+ }
+ if (dns_error_code == 0) {
+ util_ntohl(&cc_remote_ipaddr, &cc_remote_ipaddr);
+ } else {
+ cc_remote_ipaddr = ip_addr_invalid;
+ }
+
+ } else if ((ccb->contact_info) &&
+ (ccb->state >= SIP_STATE_SENT_INVITE_CONNECTED)) {
+ /*
+ * If the call has been set up, we are free to use the
+ * contact header. If the call has NOT been set up,
+ * drop through and use the proxy.
+ */
+ if (ccb->contact_info->locations[0]->genUrl->schema
+ == URL_TYPE_SIP) {
+ sipUrl = ccb->contact_info->locations[0]->genUrl->u.sipUrl;
+ } else {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_URL_ERROR), fname);
+ free_sip_message(request);
+ return (FALSE);
+ }
+
+ cc_remote_port = sipUrl->port;
+
+ if (!sipUrl->port_present) {
+ dns_error_code =
+ sipTransportGetServerAddrPort(sipSPIUrlDestination(sipUrl),
+ &cc_remote_ipaddr,
+ &cc_remote_port,
+ NULL, FALSE);
+ } else {
+ dns_error_code = dnsGetHostByName(sipSPIUrlDestination(sipUrl),
+ &cc_remote_ipaddr, 100, 1);
+ }
+ if (dns_error_code == 0) {
+
+ util_ntohl(&cc_remote_ipaddr, &cc_remote_ipaddr);
+ } else {
+ cc_remote_ipaddr = ip_addr_invalid;
+ }
+
+ } else {
+ cc_remote_ipaddr = ccb->dest_sip_addr;
+ cc_remote_port = (uint16_t) ccb->dest_sip_port;
+ }
+ if (TRUE == reTx)
+ config_get_value(CFGID_TIMER_T1, &timeout, sizeof(timeout));
+ }
+
+ if (util_check_if_ip_valid(&cc_remote_ipaddr) == FALSE) {
+ free_sip_message(request);
+ return (FALSE);
+ }
+
+ // Update default destination address and port
+ ccb->dest_sip_addr = cc_remote_ipaddr;
+ ccb->dest_sip_port = cc_remote_port;
+
+ /*
+ * Store the ACK so that it can be retransmitted in response
+ * to any duplicate 200 OK or error responses
+ */
+ trx_index = get_last_request_trx_index(ccb, TRUE);
+ if (trx_index < 0) {
+ CCSIP_DEBUG_ERROR("%s: No Valid Trx found!\n", "SendRequest");
+ return (FALSE);
+ }
+ if (sipMethodAck == method) {
+ reldev_stored_msg =
+ sipRelDevCoupledMessageStore(request, ccb->sipCallID,
+ ccb->sent_request[trx_index].cseq_number,
+ ccb->sent_request[trx_index].cseq_method,
+ TRUE, ccb->last_recvd_response_code,
+ &cc_remote_ipaddr, cc_remote_port,
+ FALSE /* Do check tag */);
+ }
+ if (sipTransportCreateSendMessage(ccb, request, method,
+ &cc_remote_ipaddr, cc_remote_port,
+ isRegister, reTx, timeout, NULL,
+ reldev_stored_msg) < 0) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ "SendRequest", "sipTransportCreateSendMessage()");
+ //dont need message free here..sipTransportCreateSendMessage() will free it
+ return (FALSE);
+ }
+
+ /* Start INVITE expires timer */
+ if (retranTimer) {
+ config_get_value(CFGID_TIMER_INVITE_EXPIRES, &expires_timeout,
+ sizeof(expires_timeout));
+ if (expires_timeout > 0) {
+ if (sip_platform_expires_timer_start(expires_timeout * 1000,
+ ccb->index,
+ &cc_remote_ipaddr, //ccb->dest_sip_addr,
+ cc_remote_port) //ccb->dest_sip_port,
+ != SIP_OK) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ "SendRequest",
+ "sip_platform_expires_timer_start()");
+ return (FALSE);
+ }
+ }
+ }
+ // Save Call History
+ if (sipMethodCancel == method || sipMethodBye == method) {
+ gCallHistory[ccb->index].last_bye_cseq_number =
+ ccb->sent_request[trx_index].cseq_number;
+ gCallHistory[ccb->index].proxy_dest_ipaddr = ccb->dest_sip_addr;
+ gCallHistory[ccb->index].dn_line = ccb->dn_line;
+ sstrncpy(gCallHistory[ccb->index].via_branch,
+ ccb->sent_request[trx_index].u.sip_via_branch,
+ VIA_BRANCH_LENGTH);
+ }
+ return (TRUE);
+}
+
+boolean
+sendResponse (ccsipCCB_t *ccb,
+ sipMessage_t *response,
+ sipMessage_t *refrequest,
+ boolean retx,
+ sipMethod_t method)
+{
+ sipVia_t *via = NULL;
+ const char *request_callid = NULL;
+ sipCseq_t *request_cseq_structure;
+ cpr_ip_addr_t cc_remote_ipaddr;
+ uint16_t cc_remote_port = 0;
+ int timeout = 0;
+ const char *pViaHeaderStr = NULL;
+ char *dest_ip_addr_str = 0;
+ int16_t trx_index = -1;
+ boolean port_present = FALSE;
+ int reldev_stored_msg;
+ int status_code = 0;
+
+ CPR_IP_ADDR_INIT(cc_remote_ipaddr);
+
+ if (ccb) {
+ request_callid = ccb->sipCallID;
+ trx_index = get_method_request_trx_index(ccb, method, FALSE);
+ if (trx_index >= 0) {
+ pViaHeaderStr = (const char *)
+ (ccb->recv_request[trx_index].u.sip_via_header);
+ request_cseq_structure = (sipCseq_t *)
+ cpr_malloc(sizeof(sipCseq_t));
+ if (!request_cseq_structure) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ "Sendresponse", "malloc failed");
+ free_sip_message(response);
+ return (FALSE);
+ }
+ request_cseq_structure->method =
+ ccb->recv_request[trx_index].cseq_method;
+ request_cseq_structure->number =
+ ccb->recv_request[trx_index].cseq_number;
+ } else {
+ pViaHeaderStr =
+ sippmh_get_cached_header_val(ccb->last_request, VIA);
+ if (getCSeqInfo(ccb->last_request, &request_cseq_structure)
+ == FALSE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ "Sendresponse", "getCSeqInfo returned false");
+ free_sip_message(response);
+ return (FALSE);
+ }
+ }
+ } else {
+ pViaHeaderStr = sippmh_get_cached_header_val(refrequest, VIA);
+ request_callid = sippmh_get_cached_header_val(refrequest, CALLID);
+ if (FALSE == getCSeqInfo(refrequest, &request_cseq_structure)) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ "Sendresponse", "getCSeqInfo returned false");
+ free_sip_message(response);
+ return (FALSE);
+ }
+ }
+
+ via = sippmh_parse_via(pViaHeaderStr);
+ if (!via) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ "Sendresponse", "Bad Via Header in Message!");
+ cpr_free(request_cseq_structure);
+ free_sip_message(response);
+ return (FALSE);
+ }
+
+ if (via->remote_port) {
+ cc_remote_port = via->remote_port;
+ port_present = TRUE;
+ } else {
+ /* Use default 5060 if via does not have port */
+ cc_remote_port = SIP_WELL_KNOWN_PORT;
+ }
+
+ /*
+ * if maddr is present use it
+ */
+ if (via->maddr) {
+ if (!port_present) {
+ dns_error_code = sipTransportGetServerAddrPort(via->maddr,
+ &cc_remote_ipaddr,
+ &cc_remote_port,
+ NULL, FALSE);
+ } else {
+ dns_error_code = dnsGetHostByName(via->maddr,
+ &cc_remote_ipaddr, 100, 1);
+ }
+ if (dns_error_code != 0) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ "Sendresponse",
+ "sipTransportGetServerAddrPort or dnsGetHostByName");
+ } else {
+ util_ntohl(&cc_remote_ipaddr, &cc_remote_ipaddr);
+ }
+ }
+
+ /*
+ * if maddr isn't present, or the DNS lookup failed, send the
+ * response to the IP address we received the message from.
+ */
+ if (util_check_if_ip_valid(&cc_remote_ipaddr) == FALSE) {
+ if (via->recd_host) {
+ dest_ip_addr_str = via->recd_host;
+ } else {
+ dest_ip_addr_str = via->host;
+ }
+
+ if (!port_present) {
+ dns_error_code = sipTransportGetServerAddrPort(dest_ip_addr_str,
+ &cc_remote_ipaddr,
+ &cc_remote_port,
+ NULL, FALSE);
+ } else {
+ dns_error_code = dnsGetHostByName(dest_ip_addr_str,
+ &cc_remote_ipaddr, 100, 1);
+ }
+ if (dns_error_code != 0) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ "Sendresponse",
+ "sipTransportGetServerAddrPort or dnsGetHostByName");
+ cpr_free(request_cseq_structure);
+ sippmh_free_via(via);
+ free_sip_message(response);
+ return (FALSE);
+ } else {
+ util_ntohl(&cc_remote_ipaddr , &cc_remote_ipaddr);
+ }
+ }
+
+ sippmh_free_via(via);
+
+ reldev_stored_msg =
+ sipRelDevCoupledMessageStore(response, request_callid,
+ request_cseq_structure->number,
+ request_cseq_structure->method,
+ FALSE, status_code,
+ &cc_remote_ipaddr, cc_remote_port,
+ /* If responding to call setup don't check tag */
+ (boolean)(ccb != NULL ?
+ SIP_SM_CALL_SETUP_RESPONDING(ccb) :
+ FALSE));
+ cpr_free(request_cseq_structure);
+ /* Enable reTx and send */
+ if (retx) {
+ config_get_value(CFGID_TIMER_T1, &timeout, sizeof(timeout));
+ if (ccb) {
+ ccb->retx_counter = 0;
+ }
+ } else {
+ timeout = 0; /* No reTx timer */
+ }
+
+ if (sipTransportChannelCreateSend(ccb, response, sipMethodResponse,
+ &cc_remote_ipaddr, cc_remote_port,
+ timeout, reldev_stored_msg) < 0) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ "SendResponse", "sipTransportChannelCreateSend()");
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static sipRet_t
+CopyLocalSDPintoResponse (sipMessage_t *request,
+ cc_msgbody_info_t *local_msg_body)
+{
+ sipRet_t tflag = HSTATUS_SUCCESS;
+ uint32_t body_index;
+ cc_msgbody_info_t tmp_body, *tmp_body_p;
+ cc_msgbody_t *part;
+
+ if (local_msg_body->num_parts == 0) {
+ /* content type specified but no msg. body to add */
+ return HSTATUS_FAILURE;
+ }
+
+ /*
+ * Duplicate a msg. body to send out which will be freed
+ * after the full message is created during the send of the
+ * msg.
+ */
+ tmp_body.num_parts = 0; /*initialize to no parts */
+ tmp_body_p = &tmp_body;
+ if (cc_cp_msg_body_parts(tmp_body_p, local_msg_body) != CC_RC_SUCCESS) {
+ /* Unable to duplicate the msg. body */
+ return HSTATUS_FAILURE;
+ }
+ part = &tmp_body_p->parts[0];
+ for (body_index = 0; body_index < tmp_body_p->num_parts; body_index++) {
+ if ((part->body != NULL) && (part->body_length)) {
+ tflag = sippmh_add_message_body(request, part->body,
+ part->body_length,
+ cc2siptype(part->content_type),
+ cc2sipdisp(part->content_disposition.disposition),
+ part->content_disposition.required_handling,
+ part->content_id);
+ } else {
+ /* Invalid entry */
+ tflag = HSTATUS_FAILURE;
+ break;
+ }
+ }
+ return tflag;
+}
+
+boolean
+AddGeneralHeaders (ccsipCCB_t *ccb,
+ sipMessageFlag_t messageflag,
+ sipMessage_t *request,
+ sipMethod_t sipmethod)
+{
+ const char *fname = "AddGeneralHeaders";
+ sipRet_t tflag = HSTATUS_SUCCESS;
+ unsigned int isOver = messageflag.flags;
+ unsigned int whichflag = 0x0001;
+ unsigned int bit_to_reset = 0; // Test and then reset
+ int16_t i;
+ int time_exp;
+ unsigned int info_index;
+ cpr_ip_mode_e ip_mode;
+
+ while (0 != isOver) {
+ bit_to_reset = (whichflag & messageflag.flags);
+ switch (bit_to_reset) {
+ case SIP_HEADER_CONTACT_BIT:
+ tflag = sipSPIAddContactHeader(ccb, request);
+ break;
+
+ case SIP_HEADER_RECORD_ROUTE_BIT:
+ if (ccb->record_route_info) {
+ tflag = (sipSPIAddRequestRecordRoute(request, ccb->last_request)) ?
+ STATUS_SUCCESS : STATUS_FAILURE;
+ }
+ break;
+
+ case SIP_HEADER_ROUTE_BIT:
+ tflag = (sipSPIAddRouteHeaders(request, ccb, NULL, 0)) ?
+ STATUS_SUCCESS : STATUS_FAILURE;
+ break;
+
+ case SIP_HEADER_UNSUPPORTED_BIT:
+ if (ccb->sip_unsupported[0] != '\0') {
+ tflag = sippmh_add_text_header(request,
+ SIP_HEADER_UNSUPPORTED,
+ &ccb->sip_unsupported[0]);
+ }
+ break;
+
+ case SIP_HEADER_REQUESTED_BY_BIT:
+ tflag = sippmh_add_text_header(request, SIP_HEADER_REQUESTED_BY,
+ ccb->sip_reqby);
+ break;
+
+ case SIP_HEADER_REMOTE_PARTY_ID_BIT:
+ tflag = sippmh_add_text_header(request, SIP_HEADER_REMOTE_PARTY_ID,
+ ccb->sip_remote_party_id);
+ break;
+
+ case SIP_HEADER_DIVERSION_BIT:
+ for (i = 0; i < MAX_DIVERSION_HEADERS; i++) {
+ if (ccb->diversion[i]) {
+ tflag = sippmh_add_text_header(request,
+ SIP_HEADER_DIVERSION,
+ ccb->diversion[i]);
+ if (tflag != HSTATUS_SUCCESS)
+ break;
+ }
+ }
+ break;
+
+ case SIP_HEADER_AUTHENTICATION_BIT:
+ tflag = sippmh_add_text_header(request,
+ AUTHOR_HDR(ccb->authen.status_code),
+ ccb->authen.authorization);
+ break;
+
+ case SIP_HEADER_PROXY_AUTH_BIT:
+ // This happens when we get a refer with a proxy-auth. We just
+ // parrot whatever the proxy told us to do in this invite.
+ tflag = sippmh_add_text_header(request,
+ SIP_HEADER_PROXY_AUTHORIZATION,
+ ccb->refer_proxy_auth);
+ break;
+
+ case SIP_HEADER_REFER_TO_BIT:
+ break;
+
+ case SIP_HEADER_REFERRED_BY_BIT:
+ tflag = sippmh_add_text_header(request, SIP_HEADER_REFERRED_BY,
+ ccb->sip_referredBy);
+ break;
+
+ case SIP_HEADER_REPLACES_BIT:
+ tflag = sippmh_add_text_header(request, SIP_HEADER_REPLACES,
+ ccb->sipxfercallid);
+ break;
+
+ case SIP_HEADER_EVENT_BIT:
+ break;
+
+ case SIP_HEADER_EXPIRES_BIT:
+ config_get_value(CFGID_TIMER_INVITE_EXPIRES, &time_exp,
+ sizeof(time_exp));
+ tflag = sippmh_add_int_header(request, SIP_HEADER_EXPIRES,
+ time_exp);
+ break;
+
+ case SIP_HEADER_REASON_BIT:
+ tflag = sipSPIAddReasonHeader(ccb, request);
+ break;
+
+ case SIP_HEADER_CONTENT_LENGTH_BIT:
+ if ((messageflag.flags & SIP_HEADER_CONTENT_TYPE_BIT) ||
+ (messageflag.flags & SIP_HEADER_OPTIONS_CONTENT_TYPE_BIT)) {
+ /*
+ * Header content length will be set when SDP body is added
+ * so we do not set it here.
+ */
+ break;
+ }
+ tflag = sippmh_add_int_header(request, SIP_HEADER_CONTENT_LENGTH, 0);
+ break;
+
+ case SIP_HEADER_CONTENT_TYPE_BIT:
+ tflag = CopyLocalSDPintoResponse(request, &ccb->local_msg_body);
+ if (tflag != HSTATUS_SUCCESS) {
+ /* there is some thing wrong with message body */
+ CCSIP_DEBUG_ERROR("%s: Error adding message body.\n", fname);
+ break;
+ }
+
+ /*
+ * SDP successfully added to message. Update offer/answer state.
+ */
+ if (ccb->oa_state == OA_OFFER_RECEIVED) {
+ ccb->oa_state = OA_IDLE;
+ } else {
+ ccb->oa_state = OA_OFFER_SENT;
+ }
+ break;
+
+ case SIP_HEADER_OPTIONS_CONTENT_TYPE_BIT:
+ tflag = CopyLocalSDPintoResponse(request, &ccb->local_msg_body);
+ if (tflag != HSTATUS_SUCCESS) {
+ /* there is some thing wrong with message body */
+ CCSIP_DEBUG_ERROR("%s: Error adding options message body.\n",
+ fname);
+ }
+
+ /*
+ * SDP successfully added to message. OPTIONS response does
+ * not alter offer/answer state as the
+ * SIP_HEADER_CONTENT_TYPE_BIT does.
+ */
+ break;
+
+ case SIP_HEADER_ALLOW_BIT:
+ {
+ char temp[MAX_SIP_HEADER_LENGTH];
+
+ snprintf(temp, MAX_SIP_HEADER_LENGTH,
+ "%s,%s,%s,%s,%s,%s,%s,%s,%s",
+ SIP_METHOD_ACK, SIP_METHOD_BYE, SIP_METHOD_CANCEL,
+ SIP_METHOD_INVITE, SIP_METHOD_NOTIFY,
+ SIP_METHOD_OPTIONS, SIP_METHOD_REFER,
+ SIP_METHOD_REGISTER, SIP_METHOD_UPDATE);
+ sstrncat(temp, ",", sizeof(temp) - strlen(temp));
+ sstrncat(temp, SIP_METHOD_SUBSCRIBE, sizeof(temp) - strlen(temp));
+ sstrncat(temp, ",", sizeof(temp) - strlen(temp));
+ sstrncat(temp, SIP_METHOD_INFO, sizeof(temp) - strlen(temp));
+ tflag = sippmh_add_text_header(request, SIP_HEADER_ALLOW, temp);
+ }
+ break;
+
+ case SIP_HEADER_ACCEPT_BIT:
+ tflag = sippmh_add_text_header(request, SIP_HEADER_ACCEPT,
+ "application/sdp");
+ break;
+
+ case SIP_HEADER_ACCEPT_ENCODING_BIT:
+ tflag = sippmh_add_text_header(request, SIP_HEADER_ACCEPT_ENCODING,
+ "identity");
+ break;
+
+ case SIP_HEADER_ACCEPT_LANGUAGE_BIT:
+ tflag = sippmh_add_text_header(request, SIP_HEADER_ACCEPT_LANGUAGE,
+ "en");
+ break;
+
+ case SIP_HEADER_CISCO_GUID_BIT:
+ tflag = (sipSPIAddCiscoGuid(request, ccb)) ?
+ STATUS_SUCCESS : STATUS_FAILURE;
+ break;
+
+ case SIP_HEADER_CALL_INFO_BIT:
+ /*
+ * Include call info header if in CCM mode or
+ * other end indicates that it can support it.
+ */
+ if ((sip_regmgr_get_cc_mode(ccb->dn_line) == REG_MODE_CCM) ||
+ (ccb->supported_tags & cisco_callinfo_tag)) {
+ tflag = (sipRet_t) sippmh_add_call_info(request,
+ ccb->out_call_info);
+ }
+ break;
+
+ case SIP_HEADER_JOIN_INFO_BIT:
+ tflag = (sipRet_t) sippmh_add_join_header(request, ccb->join_info);
+ break;
+
+ case SIP_HEADER_ALLOW_EVENTS_BIT:
+ {
+ char temp[MAX_SIP_HEADER_LENGTH];
+ int kpml_config;
+
+ // Get kpml configuration
+ config_get_value(CFGID_KPML_ENABLED, &kpml_config,
+ sizeof(kpml_config));
+ if (kpml_config) {
+ snprintf(temp, MAX_SIP_HEADER_LENGTH, "%s,%s",
+ SIP_EVENT_KPML, SIP_EVENT_DIALOG);
+ } else {
+ snprintf(temp, MAX_SIP_HEADER_LENGTH, "%s",
+ SIP_EVENT_DIALOG);
+ }
+ tflag = sippmh_add_text_header(request, SIP_HEADER_ALLOW_EVENTS,
+ temp);
+ }
+ break;
+
+ case SIP_HEADER_SUPPORTED_BIT:
+ {
+ const char *opt_tags;
+
+ opt_tags = sipGetSupportedOptionList(ccb, sipmethod);
+
+ tflag = sippmh_add_text_header(request,
+ SIP_HEADER_SUPPORTED,
+ opt_tags);
+ }
+ break;
+
+ case SIP_HEADER_REQUIRE_BIT:
+ ip_mode = platform_get_ip_address_mode();
+ if (ip_mode == CPR_IP_MODE_DUAL) {
+ tflag = sippmh_add_text_header(request, SIP_HEADER_REQUIRE, "sdp-anat");
+ }
+ break;
+
+ case SIP_HEADER_RETRY_AFTER_BIT:
+ tflag = sippmh_add_int_header(request,
+ SIP_HEADER_RETRY_AFTER,
+ abs((cpr_rand() % 11)));
+ break;
+
+ case SIP_HEADER_RECV_INFO_BIT:
+ for (info_index = 0; info_index < MAX_INFO_HANDLER; info_index++) {
+ if (g_registered_info[info_index] != NULL) {
+ tflag = sippmh_add_text_header(request, SIP_HEADER_RECV_INFO,
+ g_registered_info[info_index]);
+ if (tflag != HSTATUS_SUCCESS) {
+ break;
+ }
+ }
+ }
+ break;
+
+ default:
+ //tflag = HSTATUS_FAILURE;
+ break;
+ }
+
+ if (tflag != HSTATUS_SUCCESS) {
+ return FALSE;
+ }
+ whichflag = whichflag << 1;
+ /*
+ * Reset this bit so if nothing else is there we do not need to test
+ */
+ isOver &= ~bit_to_reset;
+ }
+ return TRUE;
+}
+
+
+/*************************************************************
+ * Function: sipSPISendUpdate
+ * This function creates, formats, and sends an UPDATE message
+ * on an existing (early) dialog
+ **************************************************************/
+boolean
+sipSPISendUpdate (ccsipCCB_t *ccb)
+{
+ const char *fname = "sipSPISendUpdate";
+ sipMessageFlag_t messageflag;
+ sipMessage_t *request = NULL;
+ sipRet_t flag = STATUS_SUCCESS;
+
+
+ // UPDATE requests mandates the use of the following headers:
+ // Allow, Call-ID, Contact, CSeq, From, Max-Forwards, To, and Via
+
+ messageflag.flags = 0;
+ messageflag.flags |= SIP_HEADER_ALLOW_BIT |
+ SIP_HEADER_CONTACT_BIT |
+ SIP_HEADER_ROUTE_BIT;
+
+ if (ccb->local_msg_body.num_parts) {
+ messageflag.flags |= SIP_HEADER_CONTENT_TYPE_BIT;
+ } else {
+ messageflag.flags |= SIP_HEADER_CONTENT_LENGTH_BIT;
+ }
+
+ request = GET_SIP_MESSAGE();
+ messageflag.extflags = 0;
+ // CreateRequest adds the request line, Via, Date, CSeq, User-Agent
+ // and all the headers in the messageflags above. It will also write
+ // the new SDP which it picks from the ccb (ccb->sip_sdp)
+ if (CreateRequest(ccb, messageflag, sipMethodUpdate, request, FALSE, 0)) {
+ flag = STATUS_SUCCESS;
+ } else {
+ flag = STATUS_FAILURE;
+ }
+
+ if (flag != STATUS_SUCCESS) {
+ free_sip_message(request);
+ CCSIP_DEBUG_ERROR("%s: Error: UPDATE message build unsuccessful.\n",
+ fname);
+ clean_method_request_trx(ccb, sipMethodUpdate, TRUE);
+ return (FALSE);
+ }
+ // Send the request
+ ccb->retx_counter = 0;
+ if (SendRequest(ccb, request, sipMethodUpdate, TRUE, TRUE, FALSE) == FALSE) {
+ clean_method_request_trx(ccb, sipMethodUpdate, TRUE);
+ return (FALSE);
+ } else {
+ return (TRUE);
+ }
+}
+
+/*************************************************************
+ * Function: sipSPISendUpdateResponse
+ * This function creates, formats, and sends a response to an
+ * UPDATE message received on an early dialog
+ **************************************************************/
+boolean
+sipSPISendUpdateResponse (ccsipCCB_t *ccb,
+ boolean send_sdp,
+ cc_causes_t cause,
+ boolean retx)
+{
+ const char *fname = "SIPSPISendUpdateResponse";
+ sipMessage_t *response = NULL;
+ sipRet_t flag = STATUS_SUCCESS;
+ sipMessageFlag_t messageflag;
+ int statusCode;
+ char *reason_phrase;
+ boolean result;
+
+ // Determine the statusCode and reason_phrase from the cause value
+ statusCode = ccsip_cc_to_sip_cause(cause, &reason_phrase);
+
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_MSG_SENDING_RESPONSE),
+ fname, statusCode);
+
+ messageflag.flags = 0;
+ messageflag.flags = SIP_HEADER_CONTACT_BIT |
+ SIP_HEADER_RECORD_ROUTE_BIT |
+ SIP_HEADER_ALLOW_BIT;
+
+ if (send_sdp) {
+ messageflag.flags |= SIP_HEADER_CONTENT_TYPE_BIT;
+ } else {
+ messageflag.flags |= SIP_HEADER_CONTENT_LENGTH_BIT;
+ }
+
+ if (statusCode == SIP_CLI_ERR_EXTENSION) {
+ messageflag.flags |= SIP_HEADER_UNSUPPORTED_BIT;
+ }
+ if (statusCode == SIP_SERV_ERR_INTERNAL) {
+ messageflag.flags |= SIP_HEADER_RETRY_AFTER_BIT;
+ }
+ response = GET_SIP_MESSAGE();
+ messageflag.extflags = 0;
+ if (CreateResponse(ccb, messageflag, (uint16_t)statusCode,
+ response, reason_phrase, 0, NULL, sipMethodUpdate)) {
+ flag = HSTATUS_SUCCESS;
+ } else {
+ flag = HSTATUS_FAILURE;
+ }
+
+ /* If build error detected, cleanup and do not send message */
+ if (flag != STATUS_SUCCESS) {
+ /* !!! Clean up */
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_BUILDFLAG_ERROR), fname);
+ if (response)
+ free_sip_message(response);
+ clean_method_request_trx(ccb, sipMethodUpdate, FALSE);
+ return (FALSE);
+ }
+
+ result = sendResponse(ccb, response, ccb->last_request, retx,
+ sipMethodUpdate);
+ clean_method_request_trx(ccb, sipMethodUpdate, FALSE);
+ return result;
+}
+
+boolean
+sipSPISendNotifyResponse (ccsipCCB_t *ccb, cc_causes_t cause)
+{
+ const char *fname = "SIPSPISendNotifyResponse";
+ sipMessage_t *response = NULL;
+ sipRet_t flag = STATUS_SUCCESS;
+ sipMessageFlag_t messageflag;
+ int sip_response_code;
+ char *sip_response_phrase;
+ boolean result;
+
+ sip_response_code = ccsip_cc_to_sip_cause(cause, &sip_response_phrase);
+
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_MSG_SENDING_RESPONSE),
+ fname, sip_response_code);
+
+ messageflag.flags = 0;
+ messageflag.flags = SIP_HEADER_CONTACT_BIT |
+ SIP_HEADER_RECORD_ROUTE_BIT |
+ SIP_HEADER_CONTENT_LENGTH_BIT;
+
+ /* Add Content Length */
+
+ response = GET_SIP_MESSAGE();
+ messageflag.extflags = 0;
+ if (CreateResponse(ccb, messageflag, (unsigned short)sip_response_code,
+ response, sip_response_phrase, 0, NULL, sipMethodNotify)) {
+ flag = HSTATUS_SUCCESS;
+ } else {
+ flag = HSTATUS_FAILURE;
+ }
+
+ /* If build error detected, cleanup and do not send message */
+ if (flag != STATUS_SUCCESS) {
+ /* !!! Clean up */
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_BUILDFLAG_ERROR), fname);
+ if (response)
+ free_sip_message(response);
+ clean_method_request_trx(ccb, sipMethodNotify, FALSE);
+ return (FALSE);
+ }
+
+ result = sendResponse(ccb, response, ccb->last_request, FALSE,
+ sipMethodNotify);
+ clean_method_request_trx(ccb, sipMethodNotify, FALSE);
+ return result;
+}
+
+/*
+ * sipSPIGenerateReferredByHeader
+ *
+ * This function is called to generate SIP Referred-By Header
+ * when SIP REFER request is sent, to Transfer the call
+ *
+ * @param[in,out] ccb CCB call info structure
+ *
+ * @return TRUE if the header is successfully
+ * created; FALSE otherwise.
+ *
+ * @pre (ccb not_eqs NULL)
+ *
+ */
+boolean
+sipSPIGenerateReferredByHeader (ccsipCCB_t *ccb)
+{
+ char line_name[MAX_LINE_NAME_SIZE];
+ char escaped_line_name[MAX_ESCAPED_USER_LEN];
+ char dest_sip_addr_str[MAX_IPADDR_STR_LEN];
+ char pReferByStr[MAX_SIP_URL_LENGTH];
+ boolean retval = FALSE;
+ cpr_ip_type ip_type;
+
+ /* Initialize */
+ line_name[0] = '\0';
+ escaped_line_name[0] = '\0';
+ dest_sip_addr_str[0] = '\0';
+ pReferByStr[0] = '\0';
+
+ /*
+ * get Server Ip Addr, line_name and form AOR to populate referredBy
+ */
+ config_get_line_string(CFGID_LINE_NAME, line_name, ccb->dn_line,
+ sizeof(line_name));
+
+ if (line_name[0] != '\0') {
+ (void) sippmh_convertURLCharToEscChar(line_name, strlen(line_name),
+ escaped_line_name,
+ sizeof(escaped_line_name),
+ TRUE);
+ }
+
+ ip_type = sipTransportGetPrimServerAddress(ccb->dn_line, dest_sip_addr_str);
+
+ if (escaped_line_name[0] != '\0') {
+ if (ip_type == CPR_IP_ADDR_IPV6) {
+ snprintf(pReferByStr, MAX_SIP_URL_LENGTH, "",
+ escaped_line_name, dest_sip_addr_str);
+ } else {
+ snprintf(pReferByStr, MAX_SIP_URL_LENGTH, "",
+ escaped_line_name, dest_sip_addr_str);
+ }
+ }
+
+ if (pReferByStr[0] != '\0') {
+ ccb->sip_referredBy = strlib_update(ccb->sip_referredBy, pReferByStr);
+ retval = TRUE;
+ }
+
+ return (retval);
+}
+
+/*
+ * Function: sipSPIBuildRegisterHeaders
+ *
+ * Parameters:
+ * ccsipCCB_t * - pointer to the ccb used for registration
+ * const char * user - used to build the headers
+ * int expires_int - registration expiry time
+ *
+ * Description: The function builds the register message
+ *
+ * Returns:
+ * sipMessage_t * - pointer to the sip request
+ *
+ */
+sipMessage_t *
+sipSPIBuildRegisterHeaders(ccsipCCB_t *ccb,
+ const char *user,
+ int expires_int)
+{
+ const char fname[] = "sipSPIBuildRegisterHeaders";
+ char *sip_from_temp;
+ char *sip_to_temp;
+ sipRet_t flag = STATUS_SUCCESS;
+ sipRet_t tflag = STATUS_SUCCESS;
+ char src_addr_str[MAX_IPADDR_STR_LEN];
+ char dest_sip_addr_str[MAX_IPADDR_STR_LEN];
+ char expires[MAX_EXPIRES_LEN];
+ sipMessageFlag_t messageflag;
+ char reg_user_info[MAX_REG_USER_INFO_LEN];
+ char escaped_user[MAX_ESCAPED_USER_LEN];
+ char *sip_from_tag;
+ sipMessage_t *request = NULL;
+
+ (void) sippmh_convertURLCharToEscChar(user, strlen(user),
+ escaped_user, sizeof(escaped_user),
+ TRUE);
+ /* get reg_user_info */
+ config_get_string(CFGID_REG_USER_INFO, reg_user_info,
+ sizeof(reg_user_info));
+ ipaddr2dotted(src_addr_str, &ccb->src_addr);
+
+ sstrncpy(dest_sip_addr_str, ccb->reg.proxy, MAX_IPADDR_STR_LEN);
+
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_MSG_SENDING_REQUEST),
+ fname, "REGISTER");
+
+ // Create a new From header only if the previous one in the CCB is blank.
+ // It will not be blank if we received a 401/407 response to a prior
+ // REGISTER request where we reuse the CCB that we first used without
+ // cleaning it.
+
+ if (ccb->sip_from[0] == '\0') {
+ sip_from_temp = strlib_open(ccb->sip_from, MAX_SIP_URL_LENGTH);
+ if (sip_from_temp) {
+ if (ccb->reg.addr.type == CPR_IP_ADDR_IPV6) {
+ snprintf(sip_from_temp, MAX_SIP_URL_LENGTH, "",
+ escaped_user, dest_sip_addr_str); /* proxy */
+ } else {
+ snprintf(sip_from_temp, MAX_SIP_URL_LENGTH, "",
+ escaped_user, dest_sip_addr_str); /* proxy */
+ }
+ /* Now add tag to the From header */
+ sip_from_tag = strlib_open(ccb->sip_from_tag, MAX_SIP_URL_LENGTH);
+ if (sip_from_tag) {
+ sip_util_make_tag(sip_from_tag);
+ sstrncat(sip_from_temp, ";tag=",
+ MAX_SIP_URL_LENGTH - strlen(sip_from_temp));
+ sstrncat(sip_from_temp, sip_from_tag,
+ MAX_SIP_URL_LENGTH - strlen(sip_from_temp));
+ }
+ ccb->sip_from_tag = strlib_close(sip_from_tag);
+ }
+ ccb->sip_from = strlib_close(sip_from_temp);
+ }
+ sip_to_temp = strlib_open(ccb->sip_to, MAX_SIP_URL_LENGTH);
+ if (ccb->reg.addr.type == CPR_IP_ADDR_IPV6) {
+ snprintf(sip_to_temp, MAX_SIP_URL_LENGTH, "",
+ escaped_user, dest_sip_addr_str); /* proxy */
+ } else {
+ snprintf(sip_to_temp, MAX_SIP_URL_LENGTH, "",
+ escaped_user, dest_sip_addr_str); /* proxy */
+ }
+ ccb->sip_to = strlib_close(sip_to_temp);
+ /*
+ * Build A request from Message Factory using following Flags...
+ * You do not need to specify common headers they will automatically
+ * get added
+ */
+
+ messageflag.flags = 0;
+
+ messageflag.flags |= SIP_HEADER_CONTACT_BIT |
+ SIP_HEADER_SUPPORTED_BIT |
+ SIP_HEADER_CISCO_GUID_BIT;
+
+ messageflag.flags |= SIP_HEADER_CONTENT_LENGTH_BIT;
+
+
+ if (ccb->authen.authorization != NULL) {
+ messageflag.flags |= SIP_HEADER_AUTHENTICATION_BIT;
+ }
+
+ if (ccb->send_reason_header) {
+ messageflag.flags |= SIP_HEADER_REASON_BIT;
+ }
+
+
+ request = GET_SIP_MESSAGE();
+ messageflag.extflags = 0;
+ if (CreateRequest(ccb, messageflag, sipMethodRegister, request, FALSE, 0)) {
+ tflag = HSTATUS_SUCCESS;
+ } else {
+ tflag = HSTATUS_FAILURE;
+ }
+ UPDATE_FLAGS(flag, tflag);
+
+ snprintf(expires, sizeof(expires), "%d", expires_int);
+ tflag = sippmh_add_text_header(request, SIP_HEADER_EXPIRES, expires);
+
+ UPDATE_FLAGS(flag, tflag);
+
+ if (flag != STATUS_SUCCESS) {
+ free_sip_message(request);
+ CCSIP_DEBUG_ERROR("%s: Error: REGISTER message build unsuccessful.\n",
+ fname);
+ clean_method_request_trx(ccb, sipMethodRegister, TRUE);
+ return (NULL);
+ }
+
+ return (request);
+}
+
diff --git a/libs/sipcc/core/sipstack/ccsip_platform.c b/libs/sipcc/core/sipstack/ccsip_platform.c
new file mode 100644
index 0000000000..de752158a2
--- /dev/null
+++ b/libs/sipcc/core/sipstack/ccsip_platform.c
@@ -0,0 +1,122 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "cpr_types.h"
+#include "cpr_stdio.h"
+#include "cpr_string.h"
+#include "phone.h"
+#include "phone_debug.h"
+#include "ccsip_register.h"
+#include "ccsip_task.h"
+#include "ccsip_pmh.h"
+#include "config.h"
+#include "sip_common_transport.h"
+#include "sip_csps_transport.h"
+#include "uiapi.h"
+#include "sip_interface_regmgr.h"
+
+#include "platform_api.h"
+
+extern void platform_sync_cfg_vers(char *cfg_ver, char *dp_ver, char *softkey_ver);
+extern void platform_reg_failover_ind(void *data);
+extern void platform_reg_fallback_ind(void *data);
+extern int platGetUnregReason();
+extern void ccsip_add_wlan_classifiers();
+void ccsip_remove_wlan_classifiers();
+
+/*
+ * Function: sip_platform_init()
+ *
+ * Parameters: None
+ *
+ * Description: Performs platform initialization stuff. Should probably be
+ * renamed or moved to make it more "generic".
+ *
+ * Returns: None
+ *
+ */
+void
+sip_platform_init (void)
+{
+
+ // Since we have all our configuration information now
+ // we want to do a final check to see if our network media
+ // type has changed
+
+ /* Unregister the phone */
+ ccsip_register_cancel(FALSE, TRUE);
+ ccsip_register_reset_proxy();
+
+ /*
+ * Make sure that the IP stack is up before trying to connect
+ */
+ if (PHNGetState() > STATE_IP_CFG) {
+
+ ccsip_add_wlan_classifiers();
+ /*
+ * regmgr - The SIPTaskDisconnectFromSipProxies and
+ * SIPTaskConnectToSipProxies calls will be called
+ * as part of the transport interface init and regmgr
+ * inits.
+ */
+
+ ccsip_register_all_lines();
+ ui_sip_config_done();
+ } else {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX "IP Stack Not Initialized.\n", "sip_platform_init");
+ }
+}
+
+
+/*
+ * Send StationReset message
+ * Parameters supplied by application:
+ * none
+ * Parameters supplied in the message
+ * - reset type (RESTART)
+ */
+int
+sip_platform_ui_restart (void)
+{
+ phone_reset(DEVICE_RESTART);
+ return TRUE;
+}
+
+
+void
+sip_platform_handle_service_control_notify (sipServiceControl_t *scp)
+{
+ switch (scp->action) {
+
+ case SERVICE_CONTROL_ACTION_RESET:
+ platform_reset_req(DEVICE_RESET);
+ break;
+
+ case SERVICE_CONTROL_ACTION_RESTART:
+ platform_reset_req(DEVICE_RESTART);
+ break;
+
+ case SERVICE_CONTROL_ACTION_CHECK_VERSION:
+ platform_sync_cfg_vers(scp->configVersionStamp,
+ scp->dialplanVersionStamp,
+ scp->softkeyVersionStamp);
+ break;
+
+ case SERVICE_CONTROL_ACTION_APPLY_CONFIG:
+ // call the function to process apply config NOTIFY message.
+ platform_apply_config(scp->configVersionStamp,
+ scp->dialplanVersionStamp,
+ scp->fcpVersionStamp,
+ scp->cucm_result,
+ scp->firmwareLoadId,
+ scp->firmwareInactiveLoadId,
+ scp->loadServer,
+ scp->logServer,
+ scp->ppid);
+ break;
+ default:
+ break;
+
+ }
+}
diff --git a/libs/sipcc/core/sipstack/ccsip_platform_tcp.c b/libs/sipcc/core/sipstack/ccsip_platform_tcp.c
new file mode 100644
index 0000000000..bbc09c3206
--- /dev/null
+++ b/libs/sipcc/core/sipstack/ccsip_platform_tcp.c
@@ -0,0 +1,1220 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "cpr_types.h"
+#include "cpr_ipc.h"
+#include "cpr_errno.h"
+#include "cpr_socket.h"
+#include "cpr_in.h"
+#include "ccsip_core.h"
+#include "ccsip_task.h"
+#include "sip_platform_task.h"
+#include "ccsip_platform_udp.h"
+#include "sip_common_transport.h"
+#include "sip_common_regmgr.h"
+#include "phone_debug.h"
+#include "util_string.h"
+#include "ccsip_platform_tcp.h"
+#include "ccsip_platform_timers.h"
+#include "text_strings.h"
+#include "ccsip_register.h"
+#include "phntask.h"
+#include "plat_api.h"
+#include "sip_socket_api.h"
+
+
+/*
+ * Externs
+ */
+extern cc_config_table_t CC_Config_Table[];
+extern ccm_act_stdby_table_t CCM_Active_Standby_Table;
+extern cpr_sockaddr_t *sip_set_sockaddr(cpr_sockaddr_storage *psock_storage, uint16_t family,
+ cpr_ip_addr_t ip_addr, uint16_t port, uint16_t *addr_len);
+extern void ccsip_dump_recv_msg_info(sipMessage_t *pSIPMessage,
+ cpr_ip_addr_t *cc_remote_ipaddr,
+ uint16_t cc_remote_port);
+
+#define MAX_CHUNKS 12
+#define MAX_PAYLOAD_SIZE (MAX_CHUNKS*CPR_MAX_MSG_SIZE)
+/*
+ * Globals
+ */
+static uint32_t sip_tcp_incomplete_msg = 0;
+static uint32_t sip_tcp_fail_network_msg = 0;
+int max_tcp_send_msg_q_size = 0;
+int max_tcp_send_msg_q_connid = 0;
+cpr_ip_addr_t max_tcp_send_msg_q_ipaddr = {0,{0}};
+ushort max_tcp_send_msg_q_port = 0;
+
+/*
+ * The following routine that set the socket option has been
+ * ported over from IOS. So not renaming.
+ */
+static ccsipRet_e
+ccsipSocketSetNonblock (cpr_socket_t fd, int optval)
+{
+ const char *fname = "ccsipSocketSetNonblock";
+
+ if (cprSetSockNonBlock(fd)) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Unable to set non-blocking socket mode %d\n",
+ fname, cpr_errno);
+ return SIP_INTERNAL_ERR;
+ }
+ return SIP_SUCCESS;
+}
+
+/*
+ * The following routine that set the socket option has been
+ * ported over from IOS. So not renaming.
+ */
+static ccsipRet_e
+ccsipSocketSetKeepAlive (cpr_socket_t fd, int optval)
+{
+ const char *fname = "ccsipSocketSetKeepAlive";
+
+ if (cprSetSockOpt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&optval,
+ sizeof(optval))) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Unable to set KEEP ALIVE on a socket %d\n",
+ fname, cpr_errno);
+ return SIP_INTERNAL_ERR;
+ }
+
+ return SIP_SUCCESS;
+}
+
+/*
+ * The following routine that set the socket option has been
+ * ported over from IOS. So not renaming.
+ */
+#ifdef NOT_AVAILABLE_WIN32
+static ccsipRet_e
+ccsipSocketSetTCPtos (cpr_socket_t fd, uint8_t optval)
+{
+ const char *fname = "ccsipSocketSetTCPtos";
+
+ if (cprSetSockOpt(fd, SOL_TCP, TCP_TOS, (void *)&optval,
+ sizeof(optval))) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Unable to set TCP TOS on a socket %d\n",
+ fname, cpr_errno);
+ return SIP_INTERNAL_ERR;
+ }
+
+ return SIP_SUCCESS;
+}
+
+/*
+ * The following routine that set the socket option has been
+ * ported over from IOS. So not renaming.
+ */
+static ccsipRet_e
+ccsipSocketSetPushBit (cpr_socket_t fd, int optval)
+{
+ const char *fname = "ccsipSocketSetPushBit";
+
+ if (cprSetSockOpt(fd, SOL_TCP, TCP_ALWAYSPUSH, (void *)&optval,
+ sizeof(optval))) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Unable to set PUSH BIT on a socket %d\n",
+ fname, cpr_errno);
+ return SIP_INTERNAL_ERR;
+ }
+
+ return SIP_SUCCESS;
+}
+#endif /* NOT_AVAILABLE_WIN32 */
+
+static boolean ccsipIsSecureType(sipSPIConnId_t connid)
+{
+ if (sip_tcp_conn_tab[connid].soc_type == SIP_SOC_TLS) {
+ return TRUE;
+ }
+ return FALSE;
+}
+/**
+ *
+ * sip_tcp_attach_socket
+ *
+ * Attach the socket to the select call
+ *
+ * Parameters: s - the socket
+ *
+ * Return Value: SIP_OK or SIP_ERROR
+ *
+ * Remarks: No check is made to see if socket is already attached
+ *
+ */
+int
+sip_tcp_attach_socket (cpr_socket_t s)
+{
+ int i;
+
+ /*
+ * Attach socket to select call
+ */
+ for (i = 0; i < MAX_SIP_CONNECTIONS; i++) {
+ if (sip_conn.read[i] == INVALID_SOCKET) {
+ sip_conn.read[i] = s;
+ FD_SET(s, &read_fds);
+ nfds = MAX(nfds, (uint32_t)s);
+ sip_conn.write[i] = s;
+ FD_SET(s, &write_fds);
+ break;
+ }
+ }
+
+ /*
+ * Are there already too many connections?
+ */
+ if (i == MAX_SIP_CONNECTIONS) {
+ return SIP_ERROR;
+ }
+ return SIP_OK;
+}
+
+/**
+ *
+ * sip_tcp_detach_socket
+ *
+ * Attach the socket to the select call
+ *
+ * Parameters: s - the socket
+ *
+ * Return Value: SIP_OK or SIP_ERROR
+ *
+ * Remarks: No check is made to see if socket is already attached
+ *
+ */
+static int
+sip_tcp_detach_socket (cpr_socket_t s)
+{
+ int i;
+ const char *fname = "sip_tcp_detach_socket";
+
+ if (s == INVALID_SOCKET) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Invalid socket\n", fname);
+ return SIP_ERROR;
+ }
+ /*
+ * Attach socket to select call
+ */
+ for (i = 0; i < MAX_SIP_CONNECTIONS; i++) {
+ if (sip_conn.read[i] == s) {
+ sip_conn.read[i] = INVALID_SOCKET;
+ FD_CLR(s, &read_fds);
+ nfds = MAX(nfds, (uint32_t)s);
+ sip_conn.write[i] = INVALID_SOCKET;
+ FD_CLR(s, &write_fds);
+ break;
+ }
+ }
+
+ /*
+ * Are there already too many connections?
+ */
+ if (i == MAX_SIP_CONNECTIONS) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Max TCP connections reached.\n", fname);
+ return SIP_ERROR;
+ }
+ return SIP_OK;
+}
+
+/**
+ *
+ * sip_tcp_set_sock_options
+ *
+ * Attach the socket to the select call
+ *
+ * Parameters: fd - the file descriptor
+ *
+ * Return Value: SIP_OK or SIP_ERROR
+ *
+ * Remarks: No check is made to see if socket is already attached
+ *
+ */
+boolean
+sip_tcp_set_sock_options (int fd)
+{
+ int optval;
+ ccsipRet_e status = SIP_SUCCESS;
+
+ optval = 1;
+
+ /* Set non-blocking mode */
+ status = ccsipSocketSetNonblock(fd, optval);
+ if (status != SIP_SUCCESS) {
+ return FALSE;
+ }
+
+ /* Set the keepalive option */
+ status = ccsipSocketSetKeepAlive(fd, optval);
+ if (status != SIP_SUCCESS) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ *
+ * sip_tcp_fd_to_connid
+ *
+ * returns the tcp conn table index for a particular socket
+ *
+ * Parameters: fd - the file descriptor
+ *
+ * Return Value: sip_tcp_conn_tab index
+ *
+ */
+int
+sip_tcp_fd_to_connid (cpr_socket_t fd)
+{
+ int i;
+
+ for (i = 0; i < MAX_CONNECTIONS; ++i) {
+ if (sip_tcp_conn_tab[i].fd == fd) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+/*
+ * sip_tcp_get_free_conn_entry ()
+ *
+ * Description : This procedure returns the first free entry from the TCP
+ * conn table.
+ *
+ * Input Params : None.
+ *
+ * Returns : Index to the Connection table (if SUCCESSFUL)
+ * -1 in case of failure.
+ */
+int
+sip_tcp_get_free_conn_entry (void)
+{
+ int i;
+ const char *fname = "sip_tcp_get_free_conn_entry";
+
+ for (i = 0; i < MAX_CONNECTIONS; ++i) {
+ if (sip_tcp_conn_tab[i].fd == -1) {
+ /* Zero the connection table entry */
+ memset((sip_tcp_conn_tab + i), 0, sizeof(sip_tcp_conn_t));
+ sip_tcp_conn_tab[i].state = SOCK_IDLE;
+ sip_tcp_conn_tab[i].dirtyFlag = FALSE;
+ sip_tcp_conn_tab[i].error_cause = SOCKET_NO_ERROR;
+ return i;
+ }
+ }
+
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"TCP Connection table full\n", fname);
+
+ return -1;
+}
+
+/*
+ * sip_tcp_init_conn_table()
+ * Description : Cleans up the entry associated with the connid
+ * from the sip_tcp_conn_tab
+ *
+ * Input : void
+ *
+ * Output : void
+ *
+ */
+void
+sip_tcp_init_conn_table (void)
+{
+ static boolean initial_call = TRUE;
+ int idx;
+
+ if (initial_call) {
+ /*
+ * Initialize the tcp conn table
+ */
+ for (idx = 0; idx < MAX_CONNECTIONS; ++idx) {
+ sip_tcp_conn_tab[idx].fd = -1;
+ }
+ initial_call = FALSE;
+ }
+}
+
+/*
+ * sip_tcp_purge_entry()
+ * Description : Cleans up the entry associated with the connid
+ * from the sip_tcp_conn_tab
+ *
+ * Input : connid
+ *
+ * Output : None
+ *
+ */
+void
+sip_tcp_purge_entry (sipSPIConnId_t connid)
+{
+ sip_tcp_conn_t *entry = sip_tcp_conn_tab + connid;
+ const char *fname= "sip_tcp_purge_entry";
+ boolean secure;
+
+ if (!VALID_CONNID(connid)) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Invalid TCP connection Id=%ld.\n",
+ fname, connid);
+ return;
+ }
+ secure = ccsipIsSecureType(connid);
+
+ (void) sip_tcp_detach_socket(entry->fd);
+ (void) sipSocketClose(entry->fd, secure);
+ CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"Socket fd: %d closed for connid %ld with "
+ "address: %i, remote port: %u\n",
+ DEB_F_PREFIX_ARGS(SIP_TCP_MSG, fname), entry->fd, connid, entry->ipaddr, entry->port);
+
+ entry->fd = -1; /* Free the connection table entry in the BEGINNING ! */
+ sipTcpFlushRetrySendQueue(entry);
+ entry->ipaddr = ip_addr_invalid;
+ entry->port = 0;
+ entry->context = NULL;
+ entry->dirtyFlag = FALSE;
+ if (entry->prev_bytes) {
+ cpr_free(entry->prev_msg);
+ }
+ return;
+}
+
+
+/*
+ * sip_tcp_create_connection()
+ * Description : This routine is called is response to a create connection
+ * request from SIP_SPI to SIP_TCP.
+ *
+ * Input : spi_msg - Pointer to sipSPIMessage_t containing the create conn
+ * parameters.
+ *
+ * Output : Nothing
+ */
+cpr_socket_t
+sip_tcp_create_connection (sipSPIMessage_t *spi_msg)
+{
+ const char* fname = "sip_tcp_create_connection";
+ int idx;
+ cpr_socket_t new_fd;
+ cpr_sockaddr_storage *local_addr_ptr;
+ sipSPICreateConnection_t *create_msg;
+ cpr_sockaddr_t local_addr;
+ cpr_socklen_t local_addr_len = sizeof(cpr_sockaddr_t);
+ int tos_dscp_val = 0; // set to default if there is no config. for dscp
+#ifdef IPV6_STACK_ENABLED
+
+ int ip_mode = CPR_IP_MODE_IPV4;
+#endif
+ uint16_t af_listen = AF_INET6;
+ cpr_sockaddr_storage sock_addr;
+ uint16_t addr_len;
+ cpr_sockaddr_storage local_sock_addr;
+ cpr_ip_addr_t local_ipaddr;
+
+ sip_tcp_init_conn_table();
+ create_msg = &(spi_msg->createConnMsg);
+ CPR_IP_ADDR_INIT(local_ipaddr);
+
+#ifdef IPV6_STACK_ENABLED
+
+ config_get_value(CFGID_IP_ADDR_MODE, &ip_mode, sizeof(ip_mode));
+
+ /*
+ * Create a socket
+ */
+ if (ip_mode == CPR_IP_MODE_IPV6 ||
+ ip_mode == CPR_IP_MODE_DUAL) {
+ af_listen = AF_INET6;
+ } else {
+#endif
+ af_listen = AF_INET;
+#ifdef IPV6_STACK_ENABLED
+ }
+#endif
+
+ /* Create New connection to the (addr,port) pair */
+ new_fd = cprSocket(af_listen, SOCK_STREAM, 0 /* IPPROTO_TCP */);
+ if (new_fd < 0) {
+ /* Send create connection failed message to SIP_SPI */
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Socket creation failed %d.\n",
+ fname, cpr_errno);
+ return INVALID_SOCKET;
+ }
+ idx = sip_tcp_get_free_conn_entry();
+ if (idx == -1) {
+ /* Send create connection failed message to SIP_SPI */
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"No Free connection entry.\n",
+ fname);
+ (void) sipSocketClose(new_fd, FALSE);
+ return INVALID_SOCKET;
+ }
+
+ if (sip_tcp_set_sock_options(new_fd) != TRUE) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Socket set option failed.\n",
+ fname);
+ }
+
+ sip_config_get_net_device_ipaddr(&local_ipaddr);
+
+ memset(&local_sock_addr, 0, sizeof(local_sock_addr));
+
+ (void) sip_set_sockaddr(&local_sock_addr, af_listen, local_ipaddr, 0, &addr_len);
+
+ CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"local_ipaddr.u.ip4=%x\n",
+ DEB_F_PREFIX_ARGS(SIP_TCP_MSG, fname), local_ipaddr.u.ip4);
+
+ if (cprBind(new_fd, (cpr_sockaddr_t *)&local_sock_addr, addr_len)) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"TCP bind failed with error %d\n", fname,
+ cpr_errno);
+ (void) sipSocketClose(new_fd, FALSE);
+ sip_tcp_conn_tab[idx].fd = INVALID_SOCKET;
+ return INVALID_SOCKET;
+ }
+
+ memset(&sock_addr, 0, sizeof(sock_addr));
+
+ (void) sip_set_sockaddr(&sock_addr, af_listen, create_msg->addr,
+ (uint16_t)(create_msg->port), &addr_len);
+
+ sip_tcp_conn_tab[idx].fd = new_fd;
+ sip_tcp_conn_tab[idx].ipaddr = create_msg->addr;
+ sip_tcp_conn_tab[idx].port = create_msg->port;
+ sip_tcp_conn_tab[idx].context = spi_msg->context;
+ sip_tcp_conn_tab[idx].dirtyFlag = FALSE;
+ sip_tcp_conn_tab[idx].addr = sock_addr;
+
+ if (cprConnect(new_fd, (cpr_sockaddr_t *)&sock_addr, addr_len)
+ == CPR_FAILURE) {
+ if (errno == EWOULDBLOCK || errno == EINPROGRESS) {
+ char ipaddr_str[MAX_IPADDR_STR_LEN];
+
+ ipaddr2dotted(ipaddr_str, &create_msg->addr);
+
+ /* connect in progress. Include this socket in select */
+ sip_tcp_conn_tab[idx].state = SOCK_CONNECT_PENDING;
+
+ CCSIP_DEBUG_MESSAGE(SIP_F_PREFIX"socket connection in progress errno:%d"
+ "ipaddr: %s, port: %d\n",
+ fname, errno, ipaddr_str, create_msg->port);
+ } else {
+ char ipaddr_str[MAX_IPADDR_STR_LEN];
+
+ ipaddr2dotted(ipaddr_str, &create_msg->addr);
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"socket connect failed errno: %d "
+ "ipaddr: %s, port: %d\n",
+ fname, errno, ipaddr_str, create_msg->port);
+ sip_tcp_purge_entry(idx);
+ return INVALID_SOCKET;
+ }
+ } else {
+ /* Even for this non-blocking socket, the connection was
+ * completed immediately. Is that a possibility ??
+ * I am not sure. Just send a connectioncreated msg to SIP_SPI
+ */
+ sip_tcp_conn_tab[idx].state = SOCK_CONNECTED;
+ }
+
+ if (cprGetSockName(new_fd, &local_addr, &local_addr_len) != CPR_FAILURE) {
+ local_addr_ptr = (cpr_sockaddr_storage *)&local_addr;
+
+ if (local_addr_ptr->ss_family == AF_INET6) {
+
+ create_msg->local_listener_port = ntohs(((cpr_sockaddr_in6_t *)local_addr_ptr)->sin6_port);
+
+ } else {
+
+ create_msg->local_listener_port = ntohs(((cpr_sockaddr_in_t *)local_addr_ptr)->sin_port);
+ }
+
+ (void) sip_tcp_attach_socket(new_fd);
+ } else {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error getting local port info.\n",
+ fname);
+ sip_tcp_purge_entry(idx);
+ return INVALID_SOCKET;
+ }
+
+ // set IP tos/dscp value for SIP messaging
+ config_get_value(CFGID_DSCP_FOR_CALL_CONTROL, (int *)&tos_dscp_val,
+ sizeof(tos_dscp_val));
+ if (cprSetSockOpt(new_fd, SOL_IP, IP_TOS, (void *)&tos_dscp_val,
+ sizeof(tos_dscp_val)) == CPR_FAILURE) {
+ // do NOT take hard action; just log the error and move on
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Unable to set IP TOS %d on TCP socket. cpr_errno = %d",
+ fname, tos_dscp_val, cpr_errno);
+ }
+
+ return (new_fd);
+}
+
+/*
+ * sip_tcp_newmsg_to_spi()
+ * Description : This routine is called to parse a tcp packet
+ * and send it to the spi for further processing.
+ *
+ * Input : buf: pointer to the message
+ * nbytes: length of the message
+ * connID: connid over which the message was received
+ *
+ * Output : success / failure in processing
+ */
+static int
+sip_tcp_newmsg_to_spi (char *buf, unsigned long nbytes, int connID)
+{
+ static const char *fname = "sip_tcp_newmsg_to_spi";
+ sipMessage_t *sip_msg;
+ ccsipRet_e val;
+ cpr_sockaddr_storage from;
+ char *disply_msg_buff = NULL;
+ char **display_msg_buff_p;
+ boolean error;
+ cpr_ip_addr_t ip_addr;
+
+ CPR_IP_ADDR_INIT(ip_addr);
+
+ /* Set up display msg. if debug msg. is enabled */
+ if (SipDebugMessage) {
+ display_msg_buff_p = &disply_msg_buff;
+ } else {
+ /* No display msg. is needed */
+ display_msg_buff_p = NULL;
+ }
+
+ do {
+ disply_msg_buff = NULL;
+ error = FALSE;
+ val = ccsip_process_network_message(&sip_msg, &buf, &nbytes,
+ display_msg_buff_p);
+
+ switch (val) {
+ case SIP_SUCCESS:
+ /*
+ * Print the received TCP packet info
+ */
+ if (disply_msg_buff != NULL) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"RCV: TCP message=\n", fname);
+ platform_print_sip_msg(disply_msg_buff);
+ }
+ from = sip_tcp_conn_tab[connID].addr;
+
+ util_extract_ip(&ip_addr, &from);
+ ccsip_dump_recv_msg_info(sip_msg, &ip_addr, 0);
+ /* Process SIP message */
+ SIPTaskProcessTCPMessage(sip_msg, from);
+ break;
+
+ case SIP_MSG_INCOMPLETE_ERR:
+
+ sip_tcp_conn_tab[connID].prev_msg = cpr_strdup(buf);
+ if (sip_tcp_conn_tab[connID].prev_msg) {
+ sip_tcp_conn_tab[connID].prev_bytes = nbytes;
+ }
+ sip_tcp_incomplete_msg++;
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"SIP Incomplete message.%d\n",fname,
+ sip_tcp_incomplete_msg);
+ error = TRUE;
+ break;
+
+ case SIP_MSG_PARSE_ERR:
+ /*
+ * Print the received TCP packet info
+ */
+ if (disply_msg_buff != NULL) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"RCV: TCP message=\n", fname);
+ platform_print_sip_msg(disply_msg_buff);
+ }
+ sip_tcp_fail_network_msg++;
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"SIP Message Parse error %d.\n", fname,
+ sip_tcp_fail_network_msg);
+ error = TRUE;
+ break;
+
+ case SIP_MSG_CREATE_ERR:
+ default:
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"SIP Message create error.\n", fname);
+ error = TRUE;
+ break;
+ }
+
+ /* Free display msg. buffer if it is allocated */
+ if (disply_msg_buff != NULL) {
+ cpr_free(disply_msg_buff);
+ disply_msg_buff = NULL;
+ }
+
+ if (error) {
+ /* There was an error encountered, exit */
+ return -1;
+ }
+ } while (nbytes > 0);
+ return 0;
+}
+
+void
+sip_tcp_createconnfailed_to_spi (cpr_ip_addr_t *ipaddr,
+ uint16_t port,
+ void *context,
+ ccsipSockErrCodes_e errcode,
+ int connid)
+{
+ static const char *fname = "sip_tcp_createconnfailed_to_spi";
+ ccsipCCB_t *ccb = NULL;
+ ti_config_table_t *ccm_active_table_entry = NULL,
+ *ccm_standby_table_entry = NULL,
+ *ccm_table_entry = NULL;
+ ti_common_t *active_ti_common = NULL;
+ ti_common_t *standby_ti_common = NULL;
+ uint32_t retx_value;
+ char ip_addr_str[MAX_IPADDR_STR_LEN];
+
+
+ /*
+ * Use LINE1 for now as there is only one type of cc
+ * supported, no mixed mode. Will have to change when
+ * we add mixed mode cc support on the phone.
+ */
+ if (CC_Config_Table[LINE1].cc_type == CC_CCM) {
+
+ /*
+ * Check and see which tcp link went down, active /
+ * standby and get the appropriate reg ccb.
+ * Using ipaddr:port combination to find if the active
+ * or the standby went down. To use fd we will have to
+ * write a routine to return connid of the tcp conn table
+ * for an ipaddr:port combination.
+ */
+ ccm_active_table_entry = CCM_Active_Standby_Table.active_ccm_entry;
+ ccm_standby_table_entry = CCM_Active_Standby_Table.standby_ccm_entry;
+ if (ccm_active_table_entry) {
+ active_ti_common = &ccm_active_table_entry->ti_common;
+ }
+ if (ccm_standby_table_entry) {
+ standby_ti_common = &ccm_standby_table_entry->ti_common;
+ }
+
+ ipaddr2dotted(ip_addr_str, ipaddr);
+ if (active_ti_common && util_compare_ip(&(active_ti_common->addr), ipaddr) &&
+ active_ti_common->port == port) {
+ /*
+ * Active link has gone down
+ */
+ int last_cpr_err = cpr_errno;
+ CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"Active server going down due to "
+ "%s. ip_addr:%s\n", DEB_F_PREFIX_ARGS(SIP_TCP_MSG, fname),
+ last_cpr_err == CPR_ETIMEDOUT ? "ETIMEDOUT":
+ last_cpr_err == CPR_ECONNABORTED ? "ECONNABORTED":
+ last_cpr_err == CPR_ECONNRESET ? "CM_RESET_TCP": "CM_CLOSED_TCP",
+ ip_addr_str);
+
+ ccb = sip_sm_get_ccb_by_index(REG_CCB_START);
+ ccm_table_entry = ccm_active_table_entry;
+
+ } else if (standby_ti_common &&
+ util_compare_ip(&(standby_ti_common->addr), ipaddr) &&
+ standby_ti_common->port == port) {
+ /*
+ * Standby link has gone down
+ */
+ CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"Standby server going down "
+ "ip_addr=%s\n",
+ DEB_F_PREFIX_ARGS(SIP_TCP_MSG, fname),
+ ip_addr_str);
+
+ ccb = sip_sm_get_ccb_by_index(REG_BACKUP_CCB);
+ ccm_table_entry = ccm_standby_table_entry;
+ } else {
+ /*
+ * Neither of the links, just return.
+ * This could happen with fall back ccm
+ */
+ ccsipCCB_t *ccb_of_fallback = NULL;
+
+ // Find fallback ccb and set the socket handle INVALID
+ if (sip_regmgr_find_fallback_ccb_by_addr_port(ipaddr, port,
+ &ccb_of_fallback)) {
+ if (ccb_of_fallback && (ccb_of_fallback->cc_cfg_table_entry)) {
+ CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"Fallback server going "
+ " down ip_addr=%s\n",
+ DEB_F_PREFIX_ARGS(SIP_TCP_MSG, fname),
+ ip_addr_str);
+ sip_tcp_purge_entry(connid);
+ sipTransportSetServerHandleAndPort(INVALID_SOCKET, 0,
+ (ti_config_table_t *)ccb_of_fallback->cc_cfg_table_entry);
+ }
+ } else {
+ sipTransportClearServerHandle(ipaddr, port, connid);
+ }
+ return;
+ }
+ /*
+ * In this case we need to make sure any pending
+ * calls are cleared as well... Need to make sure
+ * we clear that, because we are setting the local port
+ * to zero. So any one-time udp message that needs to get
+ * sent will have the port as 0 in the contact header.
+ */
+ if (ccm_table_entry) {
+ sip_tcp_purge_entry(connid);
+ sipTransportSetServerHandleAndPort(INVALID_SOCKET, 0,
+ (ti_config_table_t *) (ccm_table_entry));
+ } else {
+ sipTransportClearServerHandle(ipaddr, port, connid);
+ }
+ /*
+ * Set the retx_counter to the configured retx_value
+ * so no more retries happen
+ */
+ if (ccb != NULL) {
+ config_get_value(CFGID_SIP_RETX, &retx_value, sizeof(retx_value));
+ ccb->retx_counter = retx_value + 1;
+ CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"send a SIP_TMR_REG_RETRY"
+ "message so this cucm ip:%s can be put in fallback list \n",
+ DEB_F_PREFIX_ARGS(SIP_TCP_MSG, fname), ip_addr_str);
+ if (ccsip_register_send_msg(SIP_TMR_REG_RETRY, ccb->index)
+ != SIP_REG_OK) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"REG send message failed.\n", fname);
+ ccsip_register_cleanup(ccb, TRUE);
+ }
+
+ }
+ }
+}
+
+/*
+ * sip_tcp_read_socket()
+ * Description : After we come out of select call, for every valid socket in
+ * the connection table it
+ * 1. Checks it for readability
+ * 2. If it is readable, either accept the incoming connect (for master
+ * port) or receive data from network
+ * 3. Processes the data received from the network.
+ *
+ * Input : Value of read mask after call to socket_select()
+ *
+ * Output : Nothing
+ */
+void
+sip_tcp_read_socket (cpr_socket_t this_fd)
+{
+ int nbytes;
+ char *sip_tcp_buf;
+ char temp;
+ int connid;
+ const char *fname="sip_tcp_read_socket";
+ boolean secure;
+
+ connid = sip_tcp_fd_to_connid(this_fd);
+ if (connid == -1) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Read failed for unknown socket %d.\n",
+ fname, this_fd);
+ return;
+ }
+ secure = ccsipIsSecureType(connid);
+
+ if (sip_tcp_conn_tab[connid].state == SOCK_CONNECT_PENDING) {
+ int bytes_read = 0;
+
+ /* This socket is now readable, connection complete.
+ * Inform SIP SPI
+ * Do a dummy read, if it is successful, change state
+ */
+ bytes_read = sipSocketRecv(this_fd, &temp, 0, 0, secure);
+ if ((bytes_read != -1) || (errno == EWOULDBLOCK)) {
+ sip_tcp_conn_tab[connid].state = SOCK_CONNECTED;
+ } else if (errno == ENOTCONN) {
+ sip_tcp_conn_tab[connid].dirtyFlag = TRUE;
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"socket error=%d=\n", fname, errno);
+ sip_tcp_createconnfailed_to_spi(&(sip_tcp_conn_tab[connid].ipaddr),
+ sip_tcp_conn_tab[connid].port,
+ sip_tcp_conn_tab[connid].context,
+ SOCKET_CONNECT_ERROR, connid);
+ return;
+ }
+ } else {
+ unsigned long offset = sip_tcp_conn_tab[connid].prev_bytes;
+
+ if (offset) {
+ sip_tcp_buf = (char *) cpr_realloc(sip_tcp_conn_tab[connid].prev_msg,
+ (offset + CPR_MAX_MSG_SIZE + 1));
+ sip_tcp_conn_tab[connid].prev_bytes = 0;
+
+ if (sip_tcp_buf == NULL) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Unable to realloc tcp_msg buffer memory.\n",
+ fname);
+ cpr_free(sip_tcp_conn_tab[connid].prev_msg);
+ sip_tcp_conn_tab[connid].prev_msg = NULL;
+ return;
+ }
+
+ nbytes = sipSocketRecv(this_fd, &sip_tcp_buf[offset],
+ CPR_MAX_MSG_SIZE, 0, secure);
+
+ /* Ensure that we dont have too much buffered which may
+ * be due to some error conditions.
+ */
+ if ((nbytes + offset) > (MAX_PAYLOAD_SIZE + 1)) {
+
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Total SIP message size of %d "
+ "bytes exceeds maximum of %d bytes",
+ fname, (nbytes + offset),
+ (MAX_PAYLOAD_SIZE + 1));
+
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Dropping SIP message %s",
+ fname, sip_tcp_buf);
+ cpr_free(sip_tcp_buf);
+ return;
+ }
+ } else {
+ sip_tcp_buf = (char *) cpr_malloc(CPR_MAX_MSG_SIZE + 1);
+ if (sip_tcp_buf == NULL) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Unable to malloc tcp_msg buffer memory.\n",
+ fname);
+ return;
+ }
+ nbytes = sipSocketRecv(this_fd, sip_tcp_buf, CPR_MAX_MSG_SIZE, 0, secure);
+ }
+
+ if (nbytes > 0) {
+ nbytes += offset;
+ sip_tcp_buf[nbytes] = 0;
+ (void) sip_tcp_newmsg_to_spi(sip_tcp_buf, nbytes, connid);
+ } else if ((nbytes == 0) ||
+ ((nbytes == -1) && (errno != EWOULDBLOCK))) {
+ /*
+ * Remote connection closure or broken pipe - post a message
+ * to sip transport and wait for connection close command.
+ */
+ CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"CUCM closed TCP connection.\n",
+ DEB_F_PREFIX_ARGS(SIP_TCP_MSG, fname));
+ sip_tcp_conn_tab[connid].error_cause = SOCKET_REMOTE_CLOSURE;
+
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"socket error=%d=\n", fname, errno);
+
+ sip_tcp_createconnfailed_to_spi(&(sip_tcp_conn_tab[connid].ipaddr),
+ sip_tcp_conn_tab[connid].port,
+ sip_tcp_conn_tab[connid].context,
+ SOCKET_CONNECT_ERROR, connid);
+ // Clear proxy handle
+ if (CC_Config_Table[LINE1].cc_type != CC_CCM) {
+ sipTransportCSPSClearProxyHandle(&(sip_tcp_conn_tab[connid].ipaddr),
+ sip_tcp_conn_tab[connid].port,
+ this_fd);
+ sip_tcp_purge_entry(connid);
+ }
+ }
+ cpr_free(sip_tcp_buf);
+ }
+}
+
+/*
+ ** sip_tcp_find_msg
+ *
+ * FILENAME: ip_phone\sip\ccsip_platform_tcp.c
+ *
+ * PARAMETERS:
+ *
+ * DESCRIPTION:
+ *
+ * RETURNS:
+ *
+ */
+sll_match_e
+sip_tcp_find_msg (void *find_by_p, void *data_p)
+{
+ return (SLL_MATCH_FOUND);
+}
+
+/* Socket is not writable. Queue the data to be sent.
+ *
+ * Inputs:
+ * total_len - total length of message
+ * connid - connection id
+ * buf - buffer of data to be written (this is the entire
+ * contents not just the remaining data. We do this
+ * so we can display the entire message when the last
+ * chunk is written.
+ * send_msg_display - boolean indicating whether the sent message
+ * is to be displayed for debugging etc.
+ */
+static void
+sipTcpQueueSendData (int total_len, int connid,
+ char *buf, void *context, boolean send_msg_display,
+ uint8_t ip_sig_tos)
+{
+ static const char *fname = "sipTcpQueueSendData";
+ ccsipTCPSendData_t *sendData;
+ sip_tcp_conn_t *entry;
+ int send_msg_q_size = 0;
+
+ entry = sip_tcp_conn_tab + connid;
+ if (entry->sendQueue == NULL) {
+ entry->sendQueue = sll_create(sip_tcp_find_msg);
+ if (entry->sendQueue == NULL) {
+ CCSIP_DEBUG_ERROR("%s Failed to create sendQueue to buffer data!\n", fname);
+ return;
+ }
+ }
+
+ sendData = (ccsipTCPSendData_t *) cpr_malloc(sizeof(ccsipTCPSendData_t));
+ if (sendData == NULL) {
+ CCSIP_DEBUG_ERROR("%s Failed to allocate memory for sendData!\n", fname);
+ return;
+ }
+ memset(sendData, 0, sizeof(ccsipTCPSendData_t));
+
+ sendData->data = (char *) cpr_malloc(total_len + 1);
+
+ if (sendData->data) {
+ sstrncpy(sendData->data, buf, total_len);
+ } else {
+ CCSIP_DEBUG_ERROR("%s Failed to allocate memory for sendData->data!\n", fname);
+ cpr_free(sendData);
+ return;
+ }
+
+ sendData->bytesSent = 0;
+ sendData->bytesLeft = (uint16_t) total_len;
+ sendData->context = context;
+ sendData->msg_display = send_msg_display;
+ sendData->ip_sig_tos = ip_sig_tos;
+ (void) sll_append(entry->sendQueue, sendData);
+
+ CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"Data queued length %d\n",
+ DEB_F_PREFIX_ARGS(SIP_TCP_MSG, fname), total_len);
+
+ if (send_msg_q_size > max_tcp_send_msg_q_size) {
+ max_tcp_send_msg_q_size = send_msg_q_size;
+ max_tcp_send_msg_q_connid = connid;
+ max_tcp_send_msg_q_ipaddr = entry->ipaddr;
+ max_tcp_send_msg_q_port = entry->port;
+ }
+}
+
+/*
+ * Free memory for any queued write data.
+ */
+void
+sipTcpFlushRetrySendQueue (sip_tcp_conn_t *entry)
+{
+ ccsipTCPSendData_t *sendData = NULL;
+
+ if (entry->sendQueue) {
+ sendData = (ccsipTCPSendData_t *) sll_next(entry->sendQueue, sendData);
+ while (sendData) {
+ cpr_free(sendData->data);
+ (void) sll_remove(entry->sendQueue, sendData);
+ cpr_free(sendData);
+ sendData = (ccsipTCPSendData_t *) sll_next(entry->sendQueue, NULL);
+ }
+ (void) sll_destroy(entry->sendQueue);
+ entry->sendQueue = NULL;
+ }
+}
+
+void
+sip_tcp_resend (int connid)
+{
+ static const char *fname = "sip_tcp_resend";
+ ccsipTCPSendData_t *qElem = NULL;
+ sip_tcp_conn_t *entry;
+ int bytes_sent;
+ boolean secure;
+
+ if (!VALID_CONNID(connid)) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Resend failed for unknown socket %d.\n",
+ fname, connid);
+ return;
+ }
+
+ secure = ccsipIsSecureType(connid);
+
+ entry = sip_tcp_conn_tab + connid;
+ if (entry->sendQueue) {
+ qElem = (ccsipTCPSendData_t *) sll_next(entry->sendQueue, NULL);
+// ccsipSocketSetIPtos(entry->fd, qElem->ip_sig_tos);
+ while (qElem) {
+ while (qElem->bytesLeft) {
+ bytes_sent = sipSocketSend(entry->fd, &qElem->data[qElem->bytesSent],
+ qElem->bytesLeft, 0, secure);
+ if (bytes_sent > 0) {
+ qElem->bytesSent += bytes_sent;
+ qElem->bytesLeft -= bytes_sent;
+ } else {
+ if (errno == EWOULDBLOCK) {
+ CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"Socket blocked requeue data\n",
+ DEB_F_PREFIX_ARGS(SIP_TCP_MSG, fname));
+ } else {
+ entry->error_cause = SOCKET_SEND_ERROR;
+ sipTcpFlushRetrySendQueue(entry);
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"socket error=%d=\n", fname, errno);
+ sip_tcp_createconnfailed_to_spi(
+ &(sip_tcp_conn_tab[connid].ipaddr),
+ sip_tcp_conn_tab[connid].port,
+ sip_tcp_conn_tab[connid].context,
+ SOCKET_CONNECT_ERROR, connid);
+ CCSIP_DEBUG_ERROR("%s: Socket send error."
+ "Purge queued entry data.\n", fname);
+ }
+ return;
+ }
+ } /* while (qElem->bytesLeft) */
+
+ cpr_free(qElem->data);
+ (void) sll_remove(entry->sendQueue, qElem);
+ cpr_free(qElem);
+ CCSIP_DEBUG_REG_STATE("%s: sent out successfully, dequeue an entry.\n", fname);
+
+ qElem = (ccsipTCPSendData_t *) sll_next(entry->sendQueue, NULL);
+ } /* while qElem */
+ }
+}
+
+
+/*
+ * sip_tcp_channel_send()
+ * Description : This routine is called to send out a tcp message
+ *
+ *
+ * Input : s: socket to send the message over
+ * buf: message to send
+ * len: length of the message
+ *
+ * Output : success / failure in processing
+ */
+int
+sip_tcp_channel_send (cpr_socket_t s, char *buf, uint32_t len)
+{
+ static const char *fname = "sip_tcp_channel_send";
+ int bytesSent = 0, totalBytesSent = 0;
+ int connid = 0;
+ sip_tcp_conn_t *entry;
+ boolean secure;
+
+ /* convert socket to connid */
+ connid = sip_tcp_fd_to_connid(s);
+ if (!VALID_CONNID(connid)) {
+ CCSIP_DEBUG_ERROR("%s: Couldn't map socket to a valid connid!\n", fname);
+ return SIP_TCP_SEND_ERROR;
+ }
+ /* use connid we can get this socket's entry in sip_tcp_conn_tab[] */
+ entry = sip_tcp_conn_tab + connid;
+
+ /* secd requires that the socket should be in connected state
+ * to send message. Return if the status is pending.
+ * Currently this gets control in fallback state. The retry timer
+ * event in fallback state will resend the message.
+ */
+ if ((sip_tcp_conn_tab[connid].soc_type == SIP_SOC_TLS) &&
+ (sip_tcp_conn_tab[connid].state == SOCK_CONNECT_PENDING)) {
+ plat_soc_connect_status_e conn_status;
+ conn_status = platSecSockIsConnected(s);
+ if (conn_status == PLAT_SOCK_CONN_OK) {
+ sip_tcp_conn_tab[connid].state = SOCK_CONNECTED;
+
+ } else if (conn_status == PLAT_SOCK_CONN_WAITING) {
+
+ CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"tls socket waiting %d\n", DEB_F_PREFIX_ARGS(SIP_TCP_MSG, fname), s);
+ return SIP_TCP_SEND_OK;
+
+ } else if (conn_status == PLAT_SOCK_CONN_FAILED) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"socket error=%d=\n", fname, errno);
+ sip_tcp_createconnfailed_to_spi(&(sip_tcp_conn_tab[connid].ipaddr),
+ sip_tcp_conn_tab[connid].port,
+ sip_tcp_conn_tab[connid].context,
+ SOCKET_CONNECT_ERROR, connid);
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"TLS socket connect failed %d\n",
+ fname, s);
+ return SIP_TCP_SEND_ERROR;
+ }
+ }
+
+ /*
+ * Check not exceeding max allowed payload size
+ */
+ if (len >= MAX_PAYLOAD_SIZE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_TCP_PAYLOAD_TOO_LARGE),
+ fname, len, CPR_MAX_MSG_SIZE);
+ return SIP_TCP_SIZE_ERROR;
+ }
+
+ /*
+ * Check to see if the send q is empty. If it is not, then
+ * queue the current message in the sendqueue so that it
+ * gets sent in order when the socket is ready.
+ */
+ if (entry->sendQueue && sll_count(entry->sendQueue)) {
+ CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"%d Socket waiting on EWOULDBLOCK, "
+ " queueing data\n", DEB_F_PREFIX_ARGS(SIP_TCP_MSG, fname), connid);
+ sipTcpQueueSendData(len, connid, buf, NULL, TRUE, 0x0);
+ return SIP_TCP_SEND_OK;
+ }
+
+ secure = ccsipIsSecureType(connid);
+
+ while (len > 0) {
+ bytesSent = sipSocketSend(s, (void *)buf, (size_t) len, 0, secure);
+ if (bytesSent == SOCKET_ERROR) {
+ if (cpr_errno == CPR_EWOULDBLOCK) {
+ CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"%d Socket EWOULDBLOCK while "
+ "sending, queueing data\n", DEB_F_PREFIX_ARGS(SIP_TCP_MSG, fname),
+ connid);
+ sipTcpQueueSendData(len, connid, buf, NULL,
+ TRUE, 0x0);
+ break;
+ }
+ if (cpr_errno != CPR_ENOTCONN) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"socket error=%d=\n", fname, errno);
+ sip_tcp_createconnfailed_to_spi(&(sip_tcp_conn_tab[connid].ipaddr),
+ sip_tcp_conn_tab[connid].port,
+ sip_tcp_conn_tab[connid].context,
+ SOCKET_CONNECT_ERROR, connid);
+ }
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_SYSTEMCALL_FAILED),
+ fname, "sipSocketSend", cpr_errno);
+ return (cpr_errno== CPR_ENOTCONN? cpr_errno: SIP_TCP_SEND_ERROR);
+ }
+ len -= bytesSent;
+ totalBytesSent += bytesSent;
+ buf += bytesSent;
+ }
+ return SIP_TCP_SEND_OK;
+}
+
+/*
+ * Free memory for any queued write data.
+ */
+void
+sipTcpFreeSendQueue (int connid)
+{
+ static const char *fname = "sipTcpFreeSendQueue";
+ sip_tcp_conn_t *entry;
+
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Free TCP send queue for connid %d \n",
+ DEB_F_PREFIX_ARGS(SIP_TCP_MSG, fname), connid);
+ if (!VALID_CONNID(connid)) {
+ return;
+ }
+ entry = sip_tcp_conn_tab + connid;
+ sipTcpFlushRetrySendQueue(entry);
+}
+
+/*
+ * sip_tcp_create_conn_using_blocking_socket()
+ * Description : This routine is called to create blocking socket
+ * request from SIP_SPI to SIP_TCP.
+ *
+ * Input : spi_msg - Pointer to sipSPIMessage_t containing the create conn
+ * parameters.
+ *
+ * Output : socket fd
+ */
+cpr_socket_t
+sip_tcp_create_conn_using_blocking_socket (sipSPIMessage_t *spi_msg) {
+
+ cpr_socket_t server_conn_handle = INVALID_SOCKET;
+
+ server_conn_handle = sip_tcp_create_connection(spi_msg);
+
+ return server_conn_handle;
+}
diff --git a/libs/sipcc/core/sipstack/ccsip_platform_timers.c b/libs/sipcc/core/sipstack/ccsip_platform_timers.c
new file mode 100644
index 0000000000..7de215d448
--- /dev/null
+++ b/libs/sipcc/core/sipstack/ccsip_platform_timers.c
@@ -0,0 +1,989 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "cpr_types.h"
+#include "cpr_string.h"
+#include "cpr_memory.h"
+#include "phntask.h"
+#include "text_strings.h"
+#include "ccsip_platform.h"
+#include "phone_debug.h"
+#include "ccsip_task.h"
+#include "ccsip_pmh.h"
+#include "ccsip_register.h"
+#include "ccsip_core.h"
+#include "ccsip_subsmanager.h"
+
+/*
+ * Constants
+ */
+
+/*
+ * Globals TODO: hang off of a single SIP global
+ */
+sipPlatformUITimer_t sipPlatformUISMTimers[MAX_CCBS];
+sipPlatformUIExpiresTimer_t sipPlatformUISMExpiresTimers[MAX_CCBS];
+sipPlatformUIExpiresTimer_t sipPlatformUISMRegExpiresTimers[MAX_CCBS];
+sipPlatformUIExpiresTimer_t sipPlatformUISMLocalExpiresTimers[MAX_CCBS];
+// This timer will kick in after 1xx in releasing state so if 2xx gets lost
+// we will be able to kill the ccb
+sipPlatformSupervisionTimer_t sipPlatformSupervisionTimers[MAX_TEL_LINES];
+
+sipPlatformUITimer_t sipPlatformUISMSubNotTimers[MAX_SCBS];
+sipPlatformSupervisionTimer_t sipPlatformSubNotPeriodicTimer;
+static cprTimer_t sipPlatformRegAllFailedTimer;
+static cprTimer_t sipPlatformNotifyTimer;
+static cprTimer_t sipPlatformStandbyKeepaliveTimer;
+static cprTimer_t sipPlatformUnRegistrationTimer;
+static cprTimer_t sipPassThroughTimer;
+int
+sip_platform_timers_init (void)
+{
+ static const char fname[] = "sip_platform_timers_init";
+ static const char sipMsgTimerName[] = "sipMsg";
+ static const char sipExpireTimerName[] = "sipExp";
+ static const char sipRegTimeOutTimerName[] = "sipRegTimeout";
+ static const char sipRegExpireTimerName[] = "sipRegExp";
+ static const char sipLocalExpireTimerName[] = "sipLocalExp";
+ static const char sipSupervisionTimerName[] = "sipSupervision";
+ static const char sipSubNotTimerName[] = "sipSubNot";
+ static const char sipSubNotPeriodicTimerName[] = "sipSubNotPeriodic";
+ static const char sipRegAllFailedTimerName[] = "sipRegAllFailed";
+ static const char sipNotifyTimerName[] = "sipNotify";
+ static const char sipStandbyKeepaliveTimerName[] = "sipStandbyKeepalive";
+ static const char sipUnregistrationTimerName[] = "sipUnregistration";
+ static const char sipPassThroughTimerName[] = "sipPassThrough";
+
+ int i;
+
+ for (i = 0; i < MAX_CCBS; i++) {
+ sipPlatformUISMTimers[i].timer =
+ cprCreateTimer(sipMsgTimerName,
+ SIP_MSG_TIMER,
+ TIMER_EXPIRATION,
+ sip_msgq);
+
+ sipPlatformUISMTimers[i].reg_timer =
+ cprCreateTimer(sipRegTimeOutTimerName,
+ SIP_REG_TIMEOUT_TIMER,
+ TIMER_EXPIRATION,
+ sip_msgq);
+
+ sipPlatformUISMExpiresTimers[i].timer =
+ cprCreateTimer(sipExpireTimerName,
+ SIP_EXPIRES_TIMER,
+ TIMER_EXPIRATION,
+ sip_msgq);
+
+ sipPlatformUISMRegExpiresTimers[i].timer =
+ cprCreateTimer(sipRegExpireTimerName,
+ SIP_REG_EXPIRES_TIMER,
+ TIMER_EXPIRATION,
+ sip_msgq);
+
+ sipPlatformUISMLocalExpiresTimers[i].timer =
+ cprCreateTimer(sipLocalExpireTimerName,
+ SIP_LOCAL_EXPIRES_TIMER,
+ TIMER_EXPIRATION,
+ sip_msgq);
+
+ if (!sipPlatformUISMTimers[i].timer ||
+ !sipPlatformUISMTimers[i].reg_timer ||
+ !sipPlatformUISMExpiresTimers[i].timer ||
+ !sipPlatformUISMRegExpiresTimers[i].timer ||
+ !sipPlatformUISMLocalExpiresTimers[i].timer) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX
+ "Failed to create one or more"
+ " UISM timers: %d\n", fname, i);
+ return SIP_ERROR;
+ }
+ }
+ for (i = 0; i < MAX_TEL_LINES; i++) {
+ sipPlatformSupervisionTimers[i].timer =
+ cprCreateTimer(sipSupervisionTimerName,
+ SIP_SUPERVISION_TIMER,
+ TIMER_EXPIRATION,
+ sip_msgq);
+ }
+ for (i = 0; i < MAX_SCBS; i++) {
+ sipPlatformUISMSubNotTimers[i].timer =
+ cprCreateTimer(sipSubNotTimerName,
+ SIP_SUBNOT_TIMER,
+ TIMER_EXPIRATION,
+ sip_msgq);
+
+ if (!sipPlatformUISMSubNotTimers[i].timer) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX
+ "Failed to create Sub/Not"
+ " UISM timers: %d\n", fname, i);
+ return SIP_ERROR;
+ }
+ }
+ sipPlatformSubNotPeriodicTimer.timer =
+ cprCreateTimer(sipSubNotPeriodicTimerName,
+ SIP_SUBNOT_PERIODIC_TIMER,
+ TIMER_EXPIRATION,
+ sip_msgq);
+
+ if (!sipPlatformSubNotPeriodicTimer.timer) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX
+ "Failed to create supervision timer: %d\n",
+ fname, i);
+ return SIP_ERROR;
+ }
+
+ sipPlatformRegAllFailedTimer =
+ cprCreateTimer(sipRegAllFailedTimerName,
+ SIP_REGALLFAIL_TIMER,
+ TIMER_EXPIRATION,
+ sip_msgq);
+ if (!sipPlatformRegAllFailedTimer) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX
+ "Failed to create RegAllFailed timer\n", fname);
+ return SIP_ERROR;
+ }
+ /*
+ * Create the standby cc keepalive timer used by the
+ * registration Manager.
+ */
+ sipPlatformStandbyKeepaliveTimer =
+ cprCreateTimer(sipStandbyKeepaliveTimerName,
+ SIP_KEEPALIVE_TIMER,
+ TIMER_EXPIRATION,
+ sip_msgq);
+
+ if (!sipPlatformStandbyKeepaliveTimer) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX
+ "Failed to create Standby"
+ " keepalive timer\n", fname);
+ return SIP_ERROR;
+ }
+ sipPlatformUnRegistrationTimer =
+ cprCreateTimer(sipUnregistrationTimerName,
+ SIP_UNREGISTRATION_TIMER,
+ TIMER_EXPIRATION,
+ sip_msgq);
+ if (!sipPlatformUnRegistrationTimer) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX
+ "Failed to create Stanby keepalive timer\n",
+ fname);
+ return SIP_ERROR;
+ }
+ sipPlatformNotifyTimer =
+ cprCreateTimer(sipNotifyTimerName,
+ SIP_NOTIFY_TIMER,
+ TIMER_EXPIRATION,
+ sip_msgq);
+ if (!sipPlatformNotifyTimer) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX
+ "Failed to create Notify timer\n", fname);
+ return SIP_ERROR;
+ }
+
+ sipPassThroughTimer =
+ cprCreateTimer(sipPassThroughTimerName,
+ SIP_PASSTHROUGH_TIMER,
+ TIMER_EXPIRATION,
+ sip_msgq);
+ if (!sipPassThroughTimer) {
+ CCSIP_DEBUG_ERROR("%s: failed to create sip PassThrough timer\n", fname);
+ return SIP_ERROR;
+ }
+
+ return SIP_OK;
+}
+
+void
+sip_platform_timers_shutdown (void)
+{
+ int i;
+
+ for (i = 0; i < MAX_CCBS; i++) {
+ sip_platform_msg_timer_stop(i);
+ (void) cprDestroyTimer(sipPlatformUISMTimers[i].timer);
+ sipPlatformUISMTimers[i].timer = NULL;
+ (void) cprDestroyTimer(sipPlatformUISMTimers[i].reg_timer);
+ sipPlatformUISMTimers[i].reg_timer = NULL;
+
+ (void) sip_platform_expires_timer_stop(i);
+ (void) cprDestroyTimer(sipPlatformUISMExpiresTimers[i].timer);
+ sipPlatformUISMExpiresTimers[i].timer = NULL;
+
+ (void) sip_platform_register_expires_timer_stop(i);
+ (void) cprDestroyTimer(sipPlatformUISMRegExpiresTimers[i].timer);
+ sipPlatformUISMRegExpiresTimers[i].timer = NULL;
+
+ (void) sip_platform_localexpires_timer_stop(i);
+ (void) cprDestroyTimer(sipPlatformUISMLocalExpiresTimers[i].timer);
+ sipPlatformUISMLocalExpiresTimers[i].timer = NULL;
+ }
+
+ for (i = 0; i < MAX_TEL_LINES; i++) {
+ (void) sip_platform_supervision_disconnect_timer_stop(i);
+ (void) cprDestroyTimer(sipPlatformSupervisionTimers[i].timer);
+ sipPlatformSupervisionTimers[i].timer = NULL;
+ }
+
+ for (i = 0; i < MAX_SCBS; i++) {
+ sip_platform_msg_timer_subnot_stop(&sipPlatformUISMSubNotTimers[i]);
+ (void) cprDestroyTimer(sipPlatformUISMSubNotTimers[i].timer);
+ sipPlatformUISMSubNotTimers[i].timer = NULL;
+ }
+ (void) sip_platform_subnot_periodic_timer_stop();
+ (void) cprDestroyTimer(sipPlatformSubNotPeriodicTimer.timer);
+ sipPlatformSubNotPeriodicTimer.timer = NULL;
+ (void) sip_platform_reg_all_fail_timer_stop();
+ (void) cprDestroyTimer(sipPlatformRegAllFailedTimer);
+ sipPlatformRegAllFailedTimer = NULL;
+ (void) sip_platform_standby_keepalive_timer_stop();
+ (void) cprDestroyTimer(sipPlatformStandbyKeepaliveTimer);
+ sipPlatformStandbyKeepaliveTimer = NULL;
+ (void) sip_platform_unregistration_timer_stop();
+ (void) cprDestroyTimer(sipPlatformUnRegistrationTimer);
+ sipPlatformUnRegistrationTimer = NULL;
+ (void) sip_platform_notify_timer_stop();
+ (void) cprDestroyTimer(sipPlatformNotifyTimer);
+ sipPlatformNotifyTimer = NULL;
+ (void) sip_platform_pass_through_timer_stop();
+ (void) cprDestroyTimer(sipPassThroughTimer);
+ sipPassThroughTimer = NULL;
+}
+
+/********************************************************
+ *
+ * Message timer support functions for SIP SM
+ *
+ ********************************************************/
+void
+sip_platform_msg_timers_init (void)
+{
+ static const char fname[] = "sip_platform_msg_timers_init";
+ static long timer_init_complete = 0;
+ int i;
+ cprTimer_t timer, reg_timer;
+
+ for (i = 0; i < MAX_CCBS; i++) {
+ if (timer_init_complete) {
+ if ((cprCancelTimer(sipPlatformUISMTimers[i].timer)
+ == CPR_FAILURE) ||
+ (cprCancelTimer(sipPlatformUISMTimers[i].reg_timer)
+ == CPR_FAILURE)) {
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "cprCancelTimer");
+ }
+ }
+ timer = sipPlatformUISMTimers[i].timer;
+ reg_timer = sipPlatformUISMTimers[i].reg_timer;
+
+ if (sipPlatformUISMTimers[i].message_buffer != NULL) {
+ cpr_free(sipPlatformUISMTimers[i].message_buffer);
+ sipPlatformUISMTimers[i].message_buffer = NULL;
+ sipPlatformUISMTimers[i].message_buffer_len = 0;
+ }
+
+ memset(&sipPlatformUISMTimers[i], 0, sizeof(sipPlatformUITimer_t));
+ sipPlatformUISMTimers[i].timer = timer;
+ sipPlatformUISMTimers[i].reg_timer = reg_timer;
+ }
+ timer_init_complete = 1;
+ return;
+}
+
+
+int
+sip_platform_msg_timer_start (uint32_t msec,
+ void *data,
+ int idx,
+ char *message_buffer,
+ int message_buffer_len,
+ int message_type,
+ cpr_ip_addr_t *ipaddr,
+ uint16_t port,
+ boolean isRegister)
+{
+ static const char fname[] = "sip_platform_msg_timer_start";
+ cprTimer_t timer;
+
+ /* validate index */
+ if ((idx < MIN_TEL_LINES) || (idx >= MAX_CCBS)) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_LINE_NUMBER_INVALID),
+ fname, idx);
+ return SIP_ERROR;
+ }
+
+ /* validate length */
+ if (message_buffer_len >= SIP_UDP_MESSAGE_SIZE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_MSG_BUFFER_TOO_BIG),
+ fname, message_buffer_len);
+ return SIP_ERROR;
+ }
+
+ /* stop the timer if it is running */
+ if (cprCancelTimer(sipPlatformUISMTimers[idx].timer) == CPR_FAILURE) {
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ idx, 0, fname, "cprCancelTimer");
+ return SIP_ERROR;
+ }
+ if (cprCancelTimer(sipPlatformUISMTimers[idx].reg_timer) == CPR_FAILURE) {
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ idx, 0, fname, "cprCancelTimer");
+ return SIP_ERROR;
+ }
+
+ if (sipPlatformUISMTimers[idx].message_buffer == NULL) {
+ sipPlatformUISMTimers[idx].message_buffer = (char *)cpr_malloc(message_buffer_len+1);
+ if (sipPlatformUISMTimers[idx].message_buffer == NULL) return SIP_ERROR;
+ }
+ else if (message_buffer != sipPlatformUISMTimers[idx].message_buffer) {
+ cpr_free(sipPlatformUISMTimers[idx].message_buffer);
+ sipPlatformUISMTimers[idx].message_buffer = (char *)cpr_malloc(message_buffer_len+1);
+ if (sipPlatformUISMTimers[idx].message_buffer == NULL) return SIP_ERROR;
+ }
+
+ sipPlatformUISMTimers[idx].message_buffer_len = message_buffer_len;
+ sipPlatformUISMTimers[idx].message_buffer[message_buffer_len] = '\0';
+ memcpy(sipPlatformUISMTimers[idx].message_buffer, message_buffer,
+ message_buffer_len);
+ sipPlatformUISMTimers[idx].message_type = (sipMethod_t) message_type;
+ sipPlatformUISMTimers[idx].ipaddr = *ipaddr;
+ sipPlatformUISMTimers[idx].port = port;
+
+ /* start the timer */
+ if (isRegister) {
+ timer = sipPlatformUISMTimers[idx].reg_timer;
+ } else {
+ timer = sipPlatformUISMTimers[idx].timer;
+ }
+
+ if (cprStartTimer(timer, msec, data) == CPR_FAILURE) {
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ idx, 0, fname, "cprStartTimer");
+ cpr_free(sipPlatformUISMTimers[idx].message_buffer);
+ sipPlatformUISMTimers[idx].message_buffer = NULL;
+ sipPlatformUISMTimers[idx].message_buffer_len = 0;
+ return SIP_ERROR;
+ }
+ sipPlatformUISMTimers[idx].outstanding = TRUE;
+ return SIP_OK;
+}
+
+
+void
+sip_platform_msg_timer_stop (int idx)
+{
+ static const char fname[] = "sip_platform_msg_timer_stop";
+
+ if ((idx < MIN_TEL_LINES) || (idx >= MAX_CCBS)) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_LINE_NUMBER_INVALID),
+ fname, idx);
+ return;
+ }
+
+ if ((cprCancelTimer(sipPlatformUISMTimers[idx].timer) == CPR_FAILURE) ||
+ (cprCancelTimer(sipPlatformUISMTimers[idx].reg_timer) == CPR_FAILURE)) {
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ idx, 0, fname, "cprCancelTimer");
+ return;
+ }
+ sipPlatformUISMTimers[idx].outstanding = FALSE;
+}
+
+
+boolean
+sip_platform_msg_timer_outstanding_get (int idx)
+{
+ return sipPlatformUISMTimers[idx].outstanding;
+}
+
+
+void
+sip_platform_msg_timer_outstanding_set (int idx, boolean value)
+{
+ sipPlatformUISMTimers[idx].outstanding = value;
+}
+
+
+int
+sip_platform_msg_timer_update_destination (int idx,
+ cpr_ip_addr_t *ipaddr,
+ uint16_t port)
+{
+ static const char fname[] = "sip_platform_msg_timer_update_destination";
+
+ if ((idx < TEL_CCB_START) || (idx > REG_BACKUP_CCB)) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_LINE_NUMBER_INVALID),
+ fname, idx);
+ return SIP_ERROR;
+ }
+
+ if (ipaddr == NULL) {
+ sipPlatformUISMExpiresTimers[idx].ipaddr = ip_addr_invalid;
+ } else {
+ sipPlatformUISMTimers[idx].ipaddr = *ipaddr;
+ }
+
+ sipPlatformUISMTimers[idx].port = port;
+
+ return SIP_OK;
+}
+
+/********************************************************
+ *
+ * Expires timer support functions for SIP SM
+ *
+ ********************************************************/
+int
+sip_platform_expires_timer_start (uint32_t msec,
+ int idx,
+ cpr_ip_addr_t *ipaddr,
+ uint16_t port)
+{
+ static const char fname[] = "sip_platform_expires_timer_start";
+
+ if (sip_platform_expires_timer_stop(idx) == SIP_ERROR) {
+ return SIP_ERROR;
+ }
+
+ if (ipaddr == NULL) {
+ sipPlatformUISMExpiresTimers[idx].ipaddr = ip_addr_invalid;
+ } else {
+ sipPlatformUISMExpiresTimers[idx].ipaddr = *ipaddr;
+ }
+
+ sipPlatformUISMExpiresTimers[idx].port = port;
+
+ //sip_platform_expires_timer_callback
+ if (cprStartTimer(sipPlatformUISMExpiresTimers[idx].timer, msec,
+ (void *) (long)idx) == CPR_FAILURE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ idx, 0, fname, "cprStartTimer");
+ return SIP_ERROR;
+ }
+
+ return SIP_OK;
+}
+
+
+int
+sip_platform_expires_timer_stop (int idx)
+{
+ static const char fname[] = "sip_platform_expires_timer_stop";
+
+ if ((idx < MIN_TEL_LINES) || (idx >= MAX_CCBS)) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_LINE_NUMBER_INVALID),
+ fname, idx);
+ return SIP_ERROR;
+ }
+
+ if (cprCancelTimer(sipPlatformUISMExpiresTimers[idx].timer)
+ == CPR_FAILURE) {
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ idx, 0, fname, "cprCancelTimer");
+ return SIP_ERROR;
+ }
+
+ return SIP_OK;
+}
+
+
+int
+sip_platform_register_expires_timer_start (uint32_t msec, int idx)
+{
+ static const char fname[] = "sip_platform_register_expires_timer_start";
+
+ if (sip_platform_register_expires_timer_stop(idx) == SIP_ERROR) {
+ return SIP_ERROR;
+ }
+
+ if (cprStartTimer(sipPlatformUISMRegExpiresTimers[idx].timer, msec,
+ (void *)(long) idx) == CPR_FAILURE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ idx, 0, fname, "cprStartTimer");
+ return SIP_ERROR;
+ }
+
+ return SIP_OK;
+}
+
+
+int
+sip_platform_register_expires_timer_stop (int idx)
+{
+ static const char fname[] = "sip_platform_register_expires_timer_stop";
+
+ if ((idx < MIN_TEL_LINES) || (idx >= MAX_CCBS)) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_LINE_NUMBER_INVALID),
+ fname, idx);
+ return SIP_ERROR;
+ }
+
+ if (cprCancelTimer(sipPlatformUISMRegExpiresTimers[idx].timer)
+ == CPR_FAILURE) {
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ idx, 0, fname, "cprCancelTimer");
+ return SIP_ERROR;
+ }
+
+ return SIP_OK;
+}
+
+/********************************************************
+ *
+ * Local Expires timer support functions for SIP SM
+ *
+ ********************************************************/
+int
+sip_platform_localexpires_timer_start (uint32_t msec,
+ int idx,
+ cpr_ip_addr_t *ipaddr,
+ uint16_t port)
+{
+ static const char fname[] = "sip_platform_localexpires_timer_start";
+
+ if (sip_platform_localexpires_timer_stop(idx) == SIP_ERROR) {
+ return SIP_ERROR;
+ }
+
+ sipPlatformUISMLocalExpiresTimers[idx].ipaddr = *ipaddr;
+ sipPlatformUISMLocalExpiresTimers[idx].port = port;
+
+ //sip_platform_localexpires_timer_callback
+ if (cprStartTimer(sipPlatformUISMLocalExpiresTimers[idx].timer, msec,
+ (void *)(long) idx) == CPR_FAILURE) {
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ idx, 0, fname, "cprStartTimer");
+ return SIP_ERROR;
+ }
+
+ return SIP_OK;
+}
+
+
+int
+sip_platform_localexpires_timer_stop (int idx)
+{
+ static const char fname[] = "sip_platform_localexpires_timer_stop";
+
+ if ((idx < MIN_TEL_LINES) || (idx >= MAX_CCBS)) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_LINE_NUMBER_INVALID),
+ fname, idx);
+ return SIP_ERROR;
+ }
+
+ if (cprCancelTimer(sipPlatformUISMLocalExpiresTimers[idx].timer)
+ == CPR_FAILURE) {
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ idx, 0, fname, "cprCancelTimer");
+ return SIP_ERROR;
+ }
+
+ return SIP_OK;
+}
+
+
+sipMethod_t
+sip_platform_msg_timer_messageType_get (int idx)
+{
+ if ((idx >= TEL_CCB_START) && (idx <= REG_BACKUP_CCB)) {
+ if (sipPlatformUISMTimers[idx].outstanding) {
+ return sipPlatformUISMTimers[idx].message_type;
+ }
+ }
+ return sipMethodUnknown;
+}
+
+/*
+ * Call disconnect timer
+ */
+int
+sip_platform_supervision_disconnect_timer_start (uint32_t msec, int idx)
+{
+ static const char fname[] = "sip_platform_supervision_disconnect_timer_start";
+
+ if (sip_platform_supervision_disconnect_timer_stop(idx) == SIP_ERROR) {
+ return SIP_ERROR;
+ }
+
+ if (cprStartTimer(sipPlatformSupervisionTimers[idx].timer, msec,
+ (void *)(long) idx) == CPR_FAILURE) {
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ idx, 0, fname, "cprStartTimer");
+ return SIP_ERROR;
+ }
+
+ return SIP_OK;
+}
+
+
+int
+sip_platform_supervision_disconnect_timer_stop (int idx)
+{
+ static const char fname[] = "sip_platform_supervision_disconnect_timer_stop";
+
+ if ((idx < TEL_CCB_START) || (idx > TEL_CCB_END)) {
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_LINE_NUMBER_INVALID), fname, idx);
+ return SIP_ERROR;
+ }
+
+ if (cprCancelTimer(sipPlatformSupervisionTimers[idx].timer)
+ == CPR_FAILURE) {
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ idx, 0, fname, "cprCancelTimer");
+ return SIP_ERROR;
+ }
+
+ return SIP_OK;
+}
+
+void
+sip_platform_post_timer (uint32_t cmd, void *data)
+{
+ static const char fname[] = "sip_platform_post_timer";
+ uint32_t *timer_msg = NULL;
+
+ /* grab msg buffer */
+ timer_msg = (uint32_t *) SIPTaskGetBuffer(sizeof(uint32_t));
+ if (!timer_msg) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SYSBUF_UNAVAILABLE), fname);
+ return;
+ }
+ *timer_msg = (long) data;
+
+ /* Put it on the SIP message queue */
+ if (SIPTaskSendMsg(cmd, (cprBuffer_t) timer_msg, sizeof(uint32_t), NULL)
+ == CPR_FAILURE) {
+ cpr_free(timer_msg);
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX "Send msg failed.\n", fname);
+ }
+ return;
+}
+
+
+/****************************************************
+ * Timer functions for Subscribe / Notify operations
+ ****************************************************/
+
+int
+sip_platform_msg_timer_subnot_start (uint32_t msec,
+ sipPlatformUITimer_t *timer_p,
+ uint32_t id,
+ char *message_buffer,
+ int message_buffer_len,
+ int message_type,
+ cpr_ip_addr_t *ipaddr,
+ uint16_t port)
+{
+ static const char fname[] = "sip_platform_msg_timer_start_subnot";
+
+ sip_platform_msg_timer_subnot_stop(timer_p);
+
+ if (message_buffer_len > SIP_UDP_MESSAGE_SIZE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_MSG_BUFFER_TOO_BIG),
+ fname, message_buffer_len);
+ return SIP_ERROR;
+ }
+
+ if (timer_p->message_buffer == NULL) {
+ timer_p->message_buffer = (char *)cpr_malloc(message_buffer_len+1);
+ if (timer_p->message_buffer == NULL) return SIP_ERROR;
+ }
+ else if (timer_p->message_buffer != message_buffer) {
+ cpr_free(timer_p->message_buffer);
+ timer_p->message_buffer = (char *)cpr_malloc(message_buffer_len+1);
+ if (timer_p->message_buffer == NULL) return SIP_ERROR;
+ }
+
+ timer_p->message_buffer_len = message_buffer_len;
+ timer_p->message_buffer[message_buffer_len] = '\0';
+ memcpy(timer_p->message_buffer, message_buffer,
+ message_buffer_len);
+ timer_p->message_type =
+ (sipMethod_t) message_type;
+ timer_p->ipaddr = *ipaddr;
+ timer_p->port = port;
+
+ if (cprStartTimer(timer_p->timer, msec, (void *)(long)id) == CPR_FAILURE) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX "%s failed\n",
+ fname, "cprStartTimer");
+ cpr_free(timer_p->message_buffer);
+ timer_p->message_buffer = NULL;
+ timer_p->message_buffer_len = 0;
+ return SIP_ERROR;
+ }
+
+ return SIP_OK;
+
+}
+
+void
+sip_platform_msg_timer_subnot_stop (sipPlatformUITimer_t *timer_p)
+{
+ static const char fname[] = "sip_platform_msg_timer_stop_subnot";
+
+ if (timer_p->message_buffer != NULL) {
+ cpr_free(timer_p->message_buffer);
+ timer_p->message_buffer = NULL;
+ }
+ if (cprCancelTimer(timer_p->timer) == CPR_FAILURE) {
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX "%s failed\n",
+ DEB_F_PREFIX_ARGS(SIP_TIMER, fname), "cprCancelTimer");
+ return;
+ }
+}
+
+void
+sip_platform_subnot_msg_timer_callback (void *data)
+{
+ sip_platform_post_timer(SIP_TMR_MSG_RETRY_SUBNOT, data);
+}
+
+int
+sip_platform_subnot_periodic_timer_start (uint32_t msec)
+{
+ static const char fname[] = "sip_platform_subnot_periodic_timer_start";
+
+ if (sip_platform_subnot_periodic_timer_stop() == SIP_ERROR) {
+ return SIP_ERROR;
+ }
+
+ if (cprStartTimer(sipPlatformSubNotPeriodicTimer.timer, msec, (void *) 0)
+ == CPR_FAILURE) {
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ -1, 0, fname, "cprStartTimer");
+ return SIP_ERROR;
+ }
+ sipPlatformSubNotPeriodicTimer.started = TRUE;
+ return SIP_OK;
+}
+
+int
+sip_platform_subnot_periodic_timer_stop (void)
+{
+ static const char fname[] = "sip_platform_subnot_periodic_timer_stop";
+
+ if (sipPlatformSubNotPeriodicTimer.started == TRUE) {
+ if (cprCancelTimer(sipPlatformSubNotPeriodicTimer.timer)
+ == CPR_FAILURE) {
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ -1, 0, fname, "cprCancelTimer");
+ return SIP_ERROR;
+ }
+ }
+ sipPlatformSubNotPeriodicTimer.started = FALSE;
+ return SIP_OK;
+}
+
+void
+sip_platform_subnot_periodic_timer_callback (void *data)
+{
+ sip_platform_post_timer(SIP_TMR_PERIODIC_SUBNOT, data);
+}
+
+/**
+ ** sip_platform_reg_all_fail_timer_start
+ * Starts a timer when all registrations fail.
+ *
+ * @param msec Value of the timer to be started
+ *
+ * @return SIP_OK if timer could be started; else SIP_ERROR
+ *
+ */
+int
+sip_platform_reg_all_fail_timer_start (uint32_t msec)
+{
+
+ static const char fname[] = "sip_platform_reg_all_fail_timer_start";
+ if (sip_platform_reg_all_fail_timer_stop() == SIP_ERROR) {
+ return SIP_ERROR;
+ }
+
+ if (cprStartTimer(sipPlatformRegAllFailedTimer, msec, NULL) == CPR_FAILURE) {
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ 0, 0, fname, "cprStartTimer");
+ return SIP_ERROR;
+ }
+ CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX
+ "Timer started for %lu msecs\n", DEB_F_PREFIX_ARGS(SIP_TIMER, fname), msec);
+ return SIP_OK;
+}
+
+/**
+ ** sip_platform_reg_all_fail_timer_stop
+ * Stops the Reg-All Fail timer
+ *
+ * @param none
+ *
+ * @return SIP_OK if timer could be stopped; else SIP_ERROR
+ *
+ */
+int
+sip_platform_reg_all_fail_timer_stop (void)
+{
+ static const char fname[] = "sip_platform_reg_all_fail_timer_stop";
+
+ if (cprCancelTimer(sipPlatformRegAllFailedTimer) == CPR_FAILURE) {
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ 0, 0, fname, "cprCancelTimer");
+ return SIP_ERROR;
+ }
+ return SIP_OK;
+}
+
+/****************************************************
+ * Timer functions for standby cc keepalive operations
+ ****************************************************/
+int
+sip_platform_standby_keepalive_timer_start (uint32_t msec)
+{
+ static const char fname[] = "sip_platform_standby_keepalive_timer_start";
+
+ if (sip_platform_standby_keepalive_timer_stop() == SIP_ERROR) {
+ return SIP_ERROR;
+ }
+
+ if (cprStartTimer(sipPlatformStandbyKeepaliveTimer, msec, NULL)
+ == CPR_FAILURE) {
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ 0, 0, fname, "cprStartTimer");
+ return SIP_ERROR;
+ }
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX
+ "Timer started for %lu msecs\n", DEB_F_PREFIX_ARGS(SIP_TIMER, fname), msec);
+ return SIP_OK;
+}
+
+int
+sip_platform_standby_keepalive_timer_stop ()
+{
+ static const char fname[] = "sip_platform_standby_keepalive_timer_stop";
+
+ if (cprCancelTimer(sipPlatformStandbyKeepaliveTimer) == CPR_FAILURE) {
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ 0, 0, fname, "cprCancelTimer");
+ return SIP_ERROR;
+ }
+ return SIP_OK;
+}
+
+int
+sip_platform_unregistration_timer_start (uint32_t msec, boolean external)
+{
+ static const char fname[] = "sip_platform_unregistration_timer_start";
+
+ if (sip_platform_unregistration_timer_stop() == SIP_ERROR) {
+ return SIP_ERROR;
+ }
+
+ if (cprStartTimer(sipPlatformUnRegistrationTimer, msec, (void *)(long)external)
+ == CPR_FAILURE) {
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ 0, 0, fname, "cprStartTimer");
+ return SIP_ERROR;
+ }
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX
+ "Timer started for %lu msecs\n", DEB_F_PREFIX_ARGS(SIP_TIMER, fname), msec);
+ return SIP_OK;
+}
+
+int
+sip_platform_unregistration_timer_stop ()
+{
+ static const char fname[] = "sip_platform_unregistration_timer_stop";
+
+ if (cprCancelTimer(sipPlatformUnRegistrationTimer) == CPR_FAILURE) {
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ 0, 0, fname, "cprCancelTimer");
+ return SIP_ERROR;
+ }
+ return SIP_OK;
+}
+
+void
+sip_platform_unregistration_callback (void *data)
+{
+ sip_platform_post_timer(SIP_TMR_SHUTDOWN_PHASE2, data);
+}
+
+int
+sip_platform_notify_timer_start (uint32_t msec)
+{
+ static const char fname[] = "sip_platform_notify_timer_start";
+
+ if (sip_platform_notify_timer_stop() == SIP_ERROR) {
+ return SIP_ERROR;
+ }
+
+ if (cprStartTimer(sipPlatformNotifyTimer, msec, NULL) == CPR_FAILURE) {
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ 0, 0, fname, "cprStartTimer");
+ return SIP_ERROR;
+ }
+ CCSIP_DEBUG_STATE(DEB_F_PREFIX
+ "Timer started for %lu msecs\n", DEB_F_PREFIX_ARGS(SIP_TIMER, fname), msec);
+ return SIP_OK;
+}
+
+int
+sip_platform_notify_timer_stop ()
+{
+ static const char fname[] = "sip_platform_notify_timer_stop";
+
+ if (cprCancelTimer(sipPlatformNotifyTimer) == CPR_FAILURE) {
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ 0, 0, fname, "cprCancelTimer");
+ return SIP_ERROR;
+ }
+ return SIP_OK;
+}
+
+/***********************************************
+ * PassThrough Timer
+ ***********************************************
+ ** sip_platform_pass_through_timer_start
+ * Starts a timer when all registrations fail.
+ *
+ * @param sec Value of the timer to be started
+ *
+ * @return SIP_OK if timer could be started; else SIP_ERROR
+ *
+ */
+int
+sip_platform_pass_through_timer_start (uint32_t sec)
+{
+ static const char fname[] = "sip_platform_pass_through_timer_start";
+
+ if (sip_platform_pass_through_timer_stop() == SIP_ERROR) {
+ return SIP_ERROR;
+ }
+ if (cprStartTimer(sipPassThroughTimer, sec*1000, NULL) == CPR_FAILURE) {
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ 0, 0, fname, "cprStartTimer");
+ return SIP_ERROR;
+ }
+
+ CCSIP_DEBUG_REG_STATE("%s: Regmgr Pass Through Timer started for %lu secs\n", fname, sec);
+ return SIP_OK;
+}
+
+ /**
+ ** sip_platform_pass_through_timer_stop
+ * Stops the Pass Through timer
+ *
+ * @param none
+ *
+ * @return SIP_OK if timer could be stopped; else SIP_ERROR
+ *
+ */
+int
+sip_platform_pass_through_timer_stop (void)
+{
+ static const char fname[] = "sip_platform_pass_through_timer_stop";
+
+ if (cprCancelTimer(sipPassThroughTimer) == CPR_FAILURE) {
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ 0, 0, fname, "cprCancelTimer");
+ return SIP_ERROR;
+ }
+ return SIP_OK;
+}
diff --git a/libs/sipcc/core/sipstack/ccsip_platform_tls.c b/libs/sipcc/core/sipstack/ccsip_platform_tls.c
new file mode 100644
index 0000000000..7183841780
--- /dev/null
+++ b/libs/sipcc/core/sipstack/ccsip_platform_tls.c
@@ -0,0 +1,176 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "cpr_types.h"
+#include "cpr_ipc.h"
+#include "cpr_errno.h"
+#include "cpr_socket.h"
+#include "cpr_in.h"
+#include "ccsip_core.h"
+#include "ccsip_task.h"
+#include "sip_platform_task.h"
+#include "ccsip_platform_udp.h"
+#include "sip_common_transport.h"
+#include "sip_common_regmgr.h"
+#include "phone_debug.h"
+#include "util_string.h"
+#include "ccsip_platform_tcp.h"
+#include "text_strings.h"
+#include "ccsip_register.h"
+#include "phntask.h"
+#include "plat_api.h"
+#include "sip_socket_api.h"
+
+#define HOST_SIZE 64
+
+
+cpr_socket_t sip_tls_create_connection(sipSPIMessage_t *spi_msg,
+ boolean blocking,
+ sec_level_t sec);
+extern cpr_sockaddr_t *sip_set_sockaddr(cpr_sockaddr_storage *psock_storage, uint16_t family,
+ cpr_ip_addr_t ip_addr, uint16_t port, uint16_t *addr_len);
+
+/*
+ * sip_tls_create_connection()
+ * Description : This routine is called is response to a create connection
+ * request from SIP_SPI to SIP_TLS.
+ *
+ * Input : spi_msg - Pointer to sipSPIMessage_t containing the create conn
+ * parameters.
+ * blocking - connection mode; FALSE - nonblock; TRUE - block
+ *
+ * Output : Nothing
+ */
+cpr_socket_t
+sip_tls_create_connection (sipSPIMessage_t *spi_msg, boolean blocking,
+ sec_level_t sec)
+{
+ const char fname[] = "sip_tls_create_connection";
+ int idx;
+ sipSPICreateConnection_t *create_msg;
+ char ipaddr_str[MAX_IPADDR_STR_LEN];
+ plat_soc_status_e ret;
+ cpr_socket_t sock = INVALID_SOCKET;
+ uint16_t sec_port = 0;
+ plat_soc_connect_status_e conn_status;
+ int tos_dscp_val = 0; // set to default if there is no config. for dscp
+#ifdef IPV6_STACK_ENABLED
+ int ip_mode = CPR_IP_MODE_IPV4;
+#endif
+ uint16_t af_listen = AF_INET6;
+ cpr_sockaddr_storage sock_addr;
+ uint16_t addr_len;
+ int ip_mode = 0; // currently hardcoded to ipv4
+ plat_soc_connect_mode_e conn_mode;
+
+#ifdef IPV6_STACK_ENABLED
+
+ config_get_value(CFGID_IP_ADDR_MODE, &ip_mode, sizeof(ip_mode));
+
+ /*
+ * Create a socket
+ */
+ if (ip_mode == CPR_IP_MODE_IPV6 ||
+ ip_mode == CPR_IP_MODE_DUAL) {
+ af_listen = AF_INET6;
+ } else {
+#endif
+ af_listen = AF_INET;
+#ifdef IPV6_STACK_ENABLED
+ }
+#endif
+
+ sip_tcp_init_conn_table();
+ create_msg = &(spi_msg->createConnMsg);
+ ipaddr2dotted(ipaddr_str, &create_msg->addr);
+ ret = platSecIsServerSecure();
+ if (ret != PLAT_SOCK_SECURE) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX
+ "Secure connection is not created because"
+ " there is no secure servers\n", fname);
+ return INVALID_SOCKET;
+ }
+ CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX
+ "Creating secure connection\n", DEB_F_PREFIX_ARGS(SIP_TLS, fname));
+ /* connect securely via TLS */
+ config_get_value(CFGID_DSCP_FOR_CALL_CONTROL, (int *)&tos_dscp_val,
+ sizeof(tos_dscp_val));
+
+ if (sec == AUTHENTICATED) {
+ conn_mode = PLAT_SOCK_AUTHENTICATED;
+ } else if (sec == ENCRYPTED) {
+ conn_mode = PLAT_SOCK_ENCRYPTED;
+ } else {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX
+ "Secure connection is not created. Security mode was"
+ " not encrypyted or authenticated.\n", fname);
+ conn_mode = PLAT_SOCK_NON_SECURE;
+ }
+ sock = platSecSocConnect(ipaddr_str, /* host */
+ create_msg->port, /* port */
+ ip_mode, /* ip mode, ipv4 = 0, ipv6 = 1, dual = 2 */
+ blocking, /* 1 - block */
+ tos_dscp_val, /* TOS value */
+ conn_mode, /* The mode (Auth/Encry/None) */
+ &sec_port); /* local port */
+
+ if (sock < 0) {
+
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX
+ "Secure connect failed!!\n",fname);
+ return INVALID_SOCKET;
+ }
+ CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX "Secure connect ok\n", DEB_F_PREFIX_ARGS(SIP_TLS, fname));
+ if (!blocking) {
+ /* should not call this api in blocking mode */
+ conn_status = platSecSockIsConnected(sock);
+ if (conn_status == PLAT_SOCK_CONN_FAILED) {
+ (void)sipSocketClose(sock, TRUE);
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX
+ "Establish non-blocking mode secure"
+ " connection failed!!\n", fname);
+ return INVALID_SOCKET;
+ }
+ } else {
+ conn_status = PLAT_SOCK_CONN_OK;
+ }
+ if (sip_tcp_set_sock_options(sock) != TRUE) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX "Socket set option failure\n",
+ fname);
+ }
+
+ idx = sip_tcp_get_free_conn_entry();
+ if (idx == -1) {
+ /* Send create connection failed message to SIP_SPI */
+ (void)sipSocketClose(sock, TRUE);
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX
+ "Get free TCP connection entry failed\n",
+ fname);
+ return INVALID_SOCKET;
+ }
+
+ memset(&sock_addr, 0, sizeof(sock_addr));
+ (void) sip_set_sockaddr(&sock_addr, af_listen, create_msg->addr,
+ (uint16_t)(create_msg->port), &addr_len);
+
+ sip_tcp_conn_tab[idx].fd = sock;
+ sip_tcp_conn_tab[idx].ipaddr = create_msg->addr;
+ sip_tcp_conn_tab[idx].port = create_msg->port;
+ sip_tcp_conn_tab[idx].context = spi_msg->context;
+ sip_tcp_conn_tab[idx].dirtyFlag = FALSE;
+ sip_tcp_conn_tab[idx].addr = sock_addr;
+ sip_tcp_conn_tab[idx].soc_type = SIP_SOC_TLS;
+
+ if (conn_status == PLAT_SOCK_CONN_OK) {
+ sip_tcp_conn_tab[idx].state = SOCK_CONNECTED;
+ } else {
+ sip_tcp_conn_tab[idx].state = SOCK_CONNECT_PENDING;
+ }
+ create_msg->local_listener_port = (uint16) sec_port;
+ CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX
+ "Local listening port=%d\n", DEB_F_PREFIX_ARGS(SIP_TLS, fname),
+ create_msg->local_listener_port);
+ (void)sip_tcp_attach_socket(sock);
+ return (sock);
+}
diff --git a/libs/sipcc/core/sipstack/ccsip_platform_udp.c b/libs/sipcc/core/sipstack/ccsip_platform_udp.c
new file mode 100644
index 0000000000..0b09bbc792
--- /dev/null
+++ b/libs/sipcc/core/sipstack/ccsip_platform_udp.c
@@ -0,0 +1,455 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "cpr_types.h"
+#include "cpr_socket.h"
+#include "cpr_memory.h"
+#include "cpr_ipc.h"
+#include "cpr_in.h"
+#include "cpr_errno.h"
+#include "cpr_string.h"
+#include "util_string.h"
+#include "text_strings.h"
+#include "ccsip_core.h"
+#include "ccsip_task.h"
+#include "ccsip_platform_udp.h"
+#include "phone.h"
+#include "phone_debug.h"
+#include "sip_common_transport.h"
+#include "sip_platform_task.h"
+#include "sip_socket_api.h"
+
+// FIXME include does not exist on windows
+//#include
+
+static uint16_t af_family_listen = AF_INET6;
+static uint16_t af_family_connect = AF_INET6;
+
+/*
+ * To set the appropriate socket strcutre based on the family. The called
+ * of the function is responsible for allocating the memory.
+ *
+ * @param psock_storage pointer to cpar_sockaddr_storage
+ * family network family AF_INET or AF_INET6
+ * ip_addr ip address
+ * port
+ * addr_len legth returned based on family
+ *
+ *
+ * @return pointer to cpr_sockaddr, which is also psock_storage
+ *
+ * @pre none
+ *
+ */
+
+cpr_sockaddr_t *sip_set_sockaddr (cpr_sockaddr_storage *psock_storage, uint16_t family,
+ cpr_ip_addr_t ip_addr, uint16_t port, uint16_t *addr_len)
+{
+ static const char fname[] = "sip_set_sockaddr";
+
+ cpr_sockaddr_in6_t *pin6_addr;
+ cpr_sockaddr_in_t *pin_addr;
+ cpr_sockaddr_t *psock_addr;
+ uint32_t tmp_ip;
+ int i,j;
+ unsigned char tmp;
+
+ switch (family) {
+ case AF_INET6:
+
+ pin6_addr = (cpr_sockaddr_in6_t *)psock_storage;
+ memset(pin6_addr, 0, sizeof(cpr_sockaddr_in6_t));
+ pin6_addr->sin6_family = family;
+ pin6_addr->sin6_port = htons(port);
+
+ if (ip_addr.type == CPR_IP_ADDR_IPV4) {
+
+ if (ip_addr.u.ip4 != INADDR_ANY) {
+ pin6_addr->sin6_addr.addr.base16[5] = 0xffff;
+ }
+ tmp_ip = ntohl(ip_addr.u.ip4);
+ memcpy((void *)&(pin6_addr->sin6_addr.addr.base16[6]), (void *)&tmp_ip, 4);
+
+ } else {
+
+ for (i=0, j=15; i<16; i++, j--) {
+ tmp = pin6_addr->sin6_addr.addr.base8[j];
+ pin6_addr->sin6_addr.addr.base8[j] = ip_addr.u.ip6.addr.base8[i];
+ ip_addr.u.ip6.addr.base8[i] = tmp;
+ }
+
+ }
+
+ *addr_len = sizeof(cpr_sockaddr_in6_t);
+ return(psock_addr=(cpr_sockaddr_t *)pin6_addr);
+
+ case AF_INET:
+ if (ip_addr.type == CPR_IP_ADDR_IPV6) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Setting ipv6 address in AF_INET\n",fname);
+ break;
+ }
+ pin_addr = (cpr_sockaddr_in_t *)psock_storage;
+ memset(pin_addr, 0, sizeof(cpr_sockaddr_in_t));
+ pin_addr->sin_family = family;
+ pin_addr->sin_addr.s_addr = htonl(ip_addr.u.ip4);
+ pin_addr->sin_port = htons(port);
+
+ *addr_len = sizeof(cpr_sockaddr_in_t);
+ return(psock_addr=(cpr_sockaddr_t *)pin_addr);
+
+ default:
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Unable to set sockaddr.\n",fname);
+ break;
+ }
+
+ return(NULL);
+}
+
+int
+sip_platform_udp_channel_listen (cpr_ip_mode_e ip_mode, cpr_socket_t *s,
+ cpr_ip_addr_t *local_ipaddr,
+ uint16_t local_port)
+{
+ static const char fname[] = "sip_platform_udp_channel_listen";
+ cpr_sockaddr_storage sock_addr;
+ uint16_t addr_len;
+
+ /*
+ * If socket passed is is not INVALID_SOCKET close it first
+ */
+
+ if (*s != INVALID_SOCKET) {
+ if (sipSocketClose(*s, FALSE) != CPR_SUCCESS) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_SYSTEMCALL_FAILED),
+ fname, "sipSocketClose", cpr_errno);
+ }
+ sip_platform_task_reset_listen_socket(*s);
+ }
+
+ /*
+ * Create a socket
+ */
+ if (ip_mode == CPR_IP_MODE_IPV6 ||
+ ip_mode == CPR_IP_MODE_DUAL) {
+ af_family_listen = AF_INET6;
+ } else {
+ af_family_listen = AF_INET;
+ }
+
+ *s = cprSocket(af_family_listen, SOCK_DGRAM, 0);
+ if (*s == INVALID_SOCKET) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_SYSTEMCALL_FAILED),
+ fname, "cprSocket unable to open socket", cpr_errno);
+ if (ip_mode == CPR_IP_MODE_DUAL) {
+
+ af_family_listen = AF_INET;
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Socket open failed for IPv6 using IPv4 address.",
+ DEB_F_PREFIX_ARGS(SIP_SDP, fname));
+
+ *s = cprSocket(af_family_listen, SOCK_DGRAM, 0);
+ if (*s == INVALID_SOCKET) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_SYSTEMCALL_FAILED),
+ fname, "cprSocket unable to open socket for IPv4",
+ cpr_errno);
+ return SIP_ERROR;
+ }
+ }
+ }
+
+ (void) sip_set_sockaddr(&sock_addr, af_family_listen, *local_ipaddr,
+ local_port, &addr_len);
+
+ if (cprBind(*s, (cpr_sockaddr_t *)&sock_addr, addr_len) == CPR_FAILURE) {
+ (void) sipSocketClose(*s, FALSE);
+ *s = INVALID_SOCKET;
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_SYSTEMCALL_FAILED),
+ fname, "cprBind", cpr_errno);
+ return SIP_ERROR;
+ }
+ sip_platform_task_set_listen_socket(*s);
+
+ return SIP_OK;
+}
+
+int
+sip_platform_udp_channel_create (cpr_ip_mode_e ip_mode, cpr_socket_t *s,
+ cpr_ip_addr_t *remote_ipaddr,
+ uint16_t remote_port,
+ uint32_t local_udp_port)
+{
+ static const char *fname = "sip_platform_udp_channel_create";
+ cpr_sockaddr_storage sock_addr;
+ uint16_t addr_len;
+ cpr_sockaddr_storage local_sock_addr;
+ cpr_ip_addr_t local_signaladdr;
+
+ int tos_dscp_val = 0; // set to default if there is no config. for dscp
+
+ CPR_IP_ADDR_INIT(local_signaladdr);
+
+ if (*s != INVALID_SOCKET) {
+ (void) sipSocketClose(*s, FALSE);
+ }
+
+ if (ip_mode == CPR_IP_MODE_IPV6 ||
+ ip_mode == CPR_IP_MODE_DUAL) {
+ af_family_connect = AF_INET6;
+ } else {
+ af_family_connect = AF_INET;
+ }
+ /*
+ * Create socket
+ */
+ *s = cprSocket(af_family_connect, SOCK_DGRAM, 0);
+ if (*s == INVALID_SOCKET) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_SYSTEMCALL_FAILED),
+ fname, "cprSocket unable to open socket",
+ cpr_errno);
+ /* Try opening ipv4 socket */
+ if (ip_mode == CPR_IP_MODE_DUAL) {
+
+ CCSIP_DEBUG_TASK("%s: cprSocket Open failed for IPv6 trying IPv4",
+ fname);
+ af_family_connect = AF_INET;
+ *s = cprSocket(af_family_connect, SOCK_DGRAM, 0);
+ if (*s == INVALID_SOCKET) {
+
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_SYSTEMCALL_FAILED),
+ fname, "cprSocket unable to open AF_INET socket",
+ cpr_errno);
+ return SIP_ERROR;
+ }
+ }
+ }
+
+ sip_config_get_net_device_ipaddr(&local_signaladdr);
+ memset(&local_sock_addr, 0, sizeof(local_sock_addr));
+
+ (void) sip_set_sockaddr(&local_sock_addr, af_family_connect, local_signaladdr, 0, &addr_len);
+ CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"local_signaladdr.u.ip4=%x\n",
+ DEB_F_PREFIX_ARGS(SIP_SDP, fname), local_signaladdr.u.ip4);
+
+ if(cprBind(*s, (cpr_sockaddr_t *)&local_sock_addr, addr_len)){
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"UDP bind failed with errno %d\n", fname, cpr_errno);
+ (void) sipSocketClose(*s, FALSE);
+ *s = INVALID_SOCKET;
+ return SIP_ERROR;
+ }
+
+ /*
+ * Connect to remote address
+ */
+ (void) sip_set_sockaddr(&sock_addr, af_family_connect, *remote_ipaddr,
+ remote_port, &addr_len);
+
+ /* if (cprConnect(*s, (cpr_sockaddr_t *)&sock_addr, addr_len) == CPR_FAILURE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_SYSTEMCALL_FAILED),
+ fname, "cprConnect", cpr_errno);
+ (void) sipSocketClose(*s, FALSE);
+ *s = INVALID_SOCKET;
+ return SIP_ERROR;
+ }
+*/
+ // set IP tos/dscp value for SIP messaging
+ config_get_value(CFGID_DSCP_FOR_CALL_CONTROL, (int *)&tos_dscp_val,
+ sizeof(tos_dscp_val));
+
+ if (cprSetSockOpt(*s, SOL_IP, IP_TOS, (void *)&tos_dscp_val,
+ sizeof(tos_dscp_val)) == CPR_FAILURE) {
+ // do NOT take hard action; just log the error and move on
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Unable to set IP TOS %d on UDP socket. "
+ "cpr_errno = %d\n", fname, tos_dscp_val, cpr_errno);
+ }
+ return SIP_OK;
+}
+
+
+int
+sip_platform_udp_channel_destroy (cpr_socket_t s)
+{
+ static const char fname[] = "sip_platform_udp_channel_destroy";
+
+ if (s != INVALID_SOCKET) {
+ if (sipSocketClose(s, FALSE) == CPR_FAILURE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_SYSTEMCALL_FAILED),
+ fname, "sipSocketClose", cpr_errno);
+ return SIP_ERROR;
+ }
+ }
+ return SIP_OK;
+}
+
+int
+sip_platform_udp_channel_read (cpr_socket_t s,
+ cprBuffer_t buf,
+ uint16_t *len,
+ cpr_sockaddr_t *soc_addr,
+ cpr_socklen_t *soc_addr_len)
+{
+ static const char *fname = "sip_platform_udp_channel_read";
+ int bytes_read;
+ // NOT USED: cpr_sockaddr_in_t *addr = (cpr_sockaddr_in_t *)soc_addr;
+
+ bytes_read = cprRecvFrom(s, buf, CPR_MAX_MSG_SIZE, 0, soc_addr,
+ soc_addr_len);
+
+ switch (bytes_read) {
+ case SOCKET_ERROR:
+ /*
+ * If no data is available to read (CPR_EWOULDBLOCK),
+ * for non-blocking socket, it is not an error.
+ */
+ cpr_free(buf);
+ *len = 0;
+ if (cpr_errno != CPR_EWOULDBLOCK) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"fd[%d]\n", fname, s);
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_SYSTEMCALL_FAILED),
+ fname, "cprRecvFrom", cpr_errno);
+ return SIP_ERROR;
+ }
+ /*
+ * Will continue reading when data arrives at socket
+ */
+ break;
+ case 0:
+ /*
+ * Return value 0 is OK. This does NOT mean the connection
+ * has closed by the peer, as with TCP sockets. With UDP
+ * sockets, there is no such thing as closing a connection.
+ */
+ CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"No data on fd %d\n", DEB_F_PREFIX_ARGS(SIP_SDP, fname), s);
+ cpr_free(buf);
+ *len = 0;
+ break;
+ default:
+ /* PKT has been read */
+ CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"Recvd on fd %d\n", DEB_F_PREFIX_ARGS(SIP_SDP, fname), s);
+ *len = (uint16_t) bytes_read;
+ break;
+ }
+
+ return SIP_OK;
+}
+
+int
+sip_platform_udp_channel_send (cpr_socket_t s, char *buf, uint16_t len)
+{
+ static const char *fname = "sip_platform_udp_channel_send";
+ ssize_t bytesSent;
+
+ /*
+ * Check not exceeding max allowed payload size
+ */
+ if (len >= PKTBUF_SIZ) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_UDP_PAYLOAD_TOO_LARGE),
+ fname, len, PKTBUF_SIZ);
+ return SIP_ERROR;
+ }
+
+ while (len > 0) {
+ bytesSent = sipSocketSend(s, (void *)buf, (size_t)len, 0, FALSE);
+ if (bytesSent == SOCKET_ERROR) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_SYSTEMCALL_FAILED),
+ fname, "cprSend", cpr_errno);
+ return SIP_ERROR;
+ }
+
+ len -= bytesSent;
+ buf += bytesSent;
+ }
+
+ return SIP_OK;
+}
+
+/**
+ *
+ * sip_platform_udp_read_socket
+ *
+ * Read from the socket to extract received message
+ *
+ * Parameters: s - the socket
+ *
+ * Return Value: None
+ *
+ */
+void
+sip_platform_udp_read_socket (cpr_socket_t s)
+{
+ cprBuffer_t buf;
+ uint16_t len = 0;
+ cpr_sockaddr_storage from;
+ cpr_socklen_t from_len;
+ const char *fname = "sip_platform_udp_read_socket";
+
+ if (af_family_listen == AF_INET6) {
+ from_len = sizeof(cpr_sockaddr_in6_t);
+ } else {
+ from_len = sizeof(cpr_sockaddr_in_t);
+ }
+
+ buf = SIPTaskGetBuffer(CPR_MAX_MSG_SIZE);
+ if (buf) {
+ if ((sip_platform_udp_channel_read(s, buf, &len,
+ (cpr_sockaddr_t *)&from, &from_len) == SIP_OK) &&
+ (len != 0)) {
+ (void) SIPTaskProcessUDPMessage(buf, len, from);
+ }
+ } else {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"No buffers available to read UDP socket.\n",
+ fname);
+ }
+}
+
+int
+sip_platform_udp_channel_sendto (cpr_socket_t s, char *buf, uint32_t len,
+ cpr_ip_addr_t *dst_ipaddr, uint16_t dst_port)
+{
+ static const char *fname = "sip_platform_udp_channel_sendto";
+ ssize_t bytesSent;
+ cpr_sockaddr_storage sock_addr;
+ uint16_t addr_len;
+ cpr_ip_addr_t dest_ip_addr;
+
+ /*
+ * Connect to remote address
+ */
+ dest_ip_addr = *dst_ipaddr;
+ (void) sip_set_sockaddr(&sock_addr, af_family_connect, dest_ip_addr,
+ dst_port, &addr_len);
+
+
+ /*
+ * Check not exceeding max allowed payload size
+ */
+ if (len >= PKTBUF_SIZ) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_UDP_PAYLOAD_TOO_LARGE),
+ fname, len, PKTBUF_SIZ);
+ return SIP_ERROR;
+ }
+
+ while (len > 0) {
+ bytesSent = cprSendTo(s, (void *)buf, (size_t)len, 0,
+ (cpr_sockaddr_t *)&sock_addr, addr_len);
+
+ if ((bytesSent == SOCKET_ERROR) && (cpr_errno == CPR_ECONNREFUSED)) {
+ /*
+ * Will get socket error ECONNREFUSED after an ICMP message
+ * resend the message
+ */
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"UDP send to error %d\n", DEB_F_PREFIX_ARGS(SIP_SOCK, fname), cpr_errno);
+ bytesSent = cprSendTo(s, (void *)buf, (size_t)len, 0,
+ (cpr_sockaddr_t *)&sock_addr, addr_len);
+ }
+ if (bytesSent == SOCKET_ERROR) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_SYSTEMCALL_FAILED),
+ fname, "cprSendTo", cpr_errno);
+ return SIP_ERROR;
+ }
+
+ len -= bytesSent;
+ buf += bytesSent;
+ }
+
+ return SIP_OK;
+}
diff --git a/libs/sipcc/core/sipstack/ccsip_pmh.c b/libs/sipcc/core/sipstack/ccsip_pmh.c
new file mode 100644
index 0000000000..399de6a993
--- /dev/null
+++ b/libs/sipcc/core/sipstack/ccsip_pmh.c
@@ -0,0 +1,5751 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * Routines that parse SIP messages into individual components
+ * defined in ccsip_pmh.h. Used by the code that receives the
+ * messages to decipher them and then effect callstate as
+ * appropriate.
+ * Some SIP messages are exactly the same as HTTP/1.1 messages,
+ * and these are parsed using wrapper functions to those in
+ * httpish.c
+ */
+
+#include
+#include
+
+#include "plstr.h"
+#include "cpr_types.h"
+#include "cpr_stdio.h"
+#include "cpr_stdlib.h"
+#include "cpr_string.h"
+#include "cpr_in.h"
+#include "cpr_memory.h"
+#include "ccsip_pmh.h"
+#include "phone_debug.h"
+#include "ccapi.h"
+#include "text_strings.h"
+#include "util_string.h"
+#include "ccsip_spi_utils.h"
+#include "ccsip_callinfo.h"
+#include "ccsip_core.h"
+
+/* Skip linear whitespace */
+#define SKIP_LWS(p) while (*p == SPACE || *p == TAB) { \
+ p++; \
+ }
+
+#define SKIP_WHITE_SPACE(p) while (*p == SPACE || *p == TAB || \
+ *p == '\n') { \
+ p++; \
+ }
+
+#define AUTHENTICATION_BASIC "Basic"
+#define AUTHENTICATION_DIGEST "Digest"
+#define AUTHENTICATION_REALM "realm"
+#define AUTHENTICATION_NONCE "nonce"
+#define AUTHENTICATION_URI "uri"
+#define AUTHENTICATION_DOMAIN "domain"
+#define AUTHENTICATION_ALGORITHM "algorithm"
+#define AUTHENTICATION_OPAQUE "opaque"
+#define AUTHENTICATION_USERNAME "username"
+#define AUTHENTICATION_RESPONSE "response"
+
+
+/* Trim trailing space from end of string */
+static void
+trim_right (char *pstr)
+{
+ char *pend;
+
+ if (!pstr) {
+ return;
+ }
+
+ pend = (pstr + (strlen(pstr) - 1));
+ while (pend > pstr) {
+ if (!isspace((int) *pend)) {
+ break;
+ }
+ *pend = '\0';
+ pend--;
+ }
+}
+
+/*
+ * Remove square brackets from IPv6 address
+ *
+ * @param pstr address string
+ *
+ * @return none
+ *
+ * @pre none
+ *
+ */
+
+static void trim_ipv6_host(char *pstr)
+{
+ if (!pstr) {
+ return;
+ }
+
+ if (*pstr == '[') {
+ pstr++;
+ }
+
+ if (*(pstr + strlen(pstr)-1) == ']') {
+ *(pstr + strlen(pstr)-1) = '\0';
+ }
+}
+
+int parse_errno = 0;
+
+/* The order of these error messages corresponds to parse error codes
+ * defined in ccsip_pmh.h
+ */
+static char *parse_errors[] = { "",
+ ERROR_1,
+ ERROR_2,
+ ERROR_3,
+ ERROR_4,
+ ERROR_5,
+ ERROR_6,
+ ERROR_7,
+ ERROR_8
+};
+
+/*
+ * These headers are defined as per the values of Header indexes ( in
+ * ccsip_protocol.h. To include a header in the cached list, increase
+ * the HEADER_CACHE_SIZE in httpish.h and add its entry here. Its index
+ * should be consistent with the index value in ccsip_protocol.h.
+ * For example, #define VIA 2, implies sip_cached_headers[2] has Via header
+ * related stuff.
+ */
+sip_header_t sip_cached_headers[] = {
+/* 0 */ {"From", "f"},
+/* 1 */ {"To", "t"},
+/* 2 */ {HTTPISH_HEADER_VIA, "v"},
+/* 3 */ {"Call-ID", "i"},
+/* 4 */ {"CSeq", NULL},
+/* 5 */ {"Contact", "m"},
+/* 6 */ {HTTPISH_HEADER_CONTENT_LENGTH, HTTPISH_C_HEADER_CONTENT_LENGTH},
+/* 7 */ {HTTPISH_HEADER_CONTENT_TYPE, "c"},
+/* 8 */ {"Record-Route", NULL},
+/* 9 */ {"Require", NULL},
+/* 10 */ {"Route", NULL},
+/* 11 */ {"Supported", "k"}
+};
+
+static boolean
+is_dtmf_or_pause (char *digit)
+{
+ if (!(*digit)) {
+ return FALSE;
+ }
+ switch (*digit) {
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case '*':
+ case '#':
+ case 'p':
+ case 'w':
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+/* Inefficient ? Somewhat... */
+sipMethod_t
+sippmh_get_method_code (const char *method)
+{
+ sipMethod_t ret = sipMethodInvalid;
+
+ if (method) {
+
+ ret = sipMethodUnknown;
+
+ if (strcmp(method, SIP_METHOD_INVITE) == 0)
+ ret = sipMethodInvite;
+ else if (strcmp(method, SIP_METHOD_BYE) == 0)
+ ret = sipMethodBye;
+ else if (strcmp(method, SIP_METHOD_ACK) == 0)
+ ret = sipMethodAck;
+ else if (strcmp(method, SIP_METHOD_PRACK) == 0)
+ ret = sipMethodPrack;
+ else if (strcmp(method, SIP_METHOD_COMET) == 0)
+ ret = sipMethodComet;
+ else if (strcmp(method, SIP_METHOD_OPTIONS) == 0)
+ ret = sipMethodOptions;
+ else if (strcmp(method, SIP_METHOD_CANCEL) == 0)
+ ret = sipMethodCancel;
+ else if (strcmp(method, SIP_METHOD_NOTIFY) == 0)
+ ret = sipMethodNotify;
+ else if (strcmp(method, SIP_METHOD_REFER) == 0)
+ ret = sipMethodRefer;
+ else if (strcmp(method, SIP_METHOD_SUBSCRIBE) == 0)
+ ret = sipMethodSubscribe;
+ else if (strcmp(method, SIP_METHOD_REGISTER) == 0)
+ ret = sipMethodRegister;
+ else if (strcmp(method, SIP_METHOD_UPDATE) == 0)
+ ret = sipMethodUpdate;
+ else if (strcmp(method, SIP_METHOD_INFO) == 0)
+ ret = sipMethodInfo;
+ else if (strcmp(method, SIP_METHOD_PUBLISH) == 0)
+ ret = sipMethodPublish;
+ else if (strcmp(method, SIP_METHOD_MESSAGE) == 0)
+ ret = sipMethodMessage;
+ else if (strcmp(method, SIP_METHOD_INFO) == 0)
+ ret = sipMethodInfo;
+ }
+
+ return ret;
+}
+
+#define SKIP_SIP_TOKEN(inp_str) \
+ while (isalnum((int)*inp_str) || *inp_str == DASH || \
+ *inp_str == DOT || *inp_str == EXCLAMATION || \
+ *inp_str == PERCENT || *inp_str == STAR || \
+ *inp_str == UNDERSCORE || *inp_str == PLUS || \
+ *inp_str == '`' || *inp_str == SINGLE_QUOTE || \
+ *inp_str == COLON || *inp_str == TILDA || \
+ *inp_str == AT_SIGN) { \
+ inp_str++; \
+ }
+
+static char *
+parse_generic_param (char *param, char **param_val)
+{
+ boolean match_found;
+ char *tok_start;
+
+ /*
+ * param is pointing to the first character after the name of the
+ * parameter. It could be
+ * white space or
+ * equal sign or
+ * semi-colon or
+ * comma or
+ * end of string
+ */
+ if (*param == SPACE || *param == TAB) {
+ *param++ = 0;
+ SKIP_LWS(param);
+ }
+
+ if (*param != EQUAL_SIGN) {
+ /*
+ * Parameter exists but its value is empty
+ */
+ *param_val = "";
+ return param;
+ }
+
+ *param++ = 0;
+ SKIP_LWS(param);
+ *param_val = param;
+ if (*param == DOUBLE_QUOTE) {
+ param++;
+ match_found = FALSE;
+ while (*param) {
+ if (*param == DOUBLE_QUOTE && *(param - 1) != ESCAPE_CHAR) {
+ param++;
+ match_found = TRUE;
+ break;
+ }
+ param++;
+ }
+ if (match_found == FALSE) {
+ return NULL;
+ }
+ } else {
+ tok_start = param;
+ SKIP_SIP_TOKEN(param);
+ if (param == tok_start) {
+ return NULL;
+ }
+ }
+ return param;
+}
+
+/*
+ * The syntax of other-param in SIP URL is same as extension-attribute in
+ * Contact header. A pointer to the start of the token=value or
+ * token="value" string is returned in other_param_value. This allows
+ * the calling code to store this value if needed such as in the
+ * case of supporting contact-extensions. The function returns
+ * a pointer to the next character to be parsed.
+ */
+static char *
+parse_other_param (char *inp_str, char **other_param_value)
+{
+ char temp;
+ char *token_string;
+
+
+ SKIP_LWS(inp_str);
+ token_string = inp_str;
+ SKIP_SIP_TOKEN(inp_str);
+ switch (*inp_str) {
+ case COMMA:
+ case '\0':
+ case SEMI_COLON:
+ /*
+ * Either we have encountered end of string or another
+ * parameter follows this other-param. In either case we
+ * are done with parsing other-param. Since this is
+ * not in the form of token=value or token="value" discard
+ * it.
+ */
+ *other_param_value = NULL;
+
+ /* check for loose routing specifier */
+ temp = *inp_str;
+ *inp_str = 0;
+ if (!cpr_strcasecmp(token_string, "lr")) {
+ *other_param_value = (char *) cpr_malloc(4);
+ if (*other_param_value != NULL) {
+ sstrncpy(*other_param_value, token_string, 4);
+ }
+ }
+ *inp_str = temp;
+ break;
+
+ case EQUAL_SIGN:
+ /* It is either token=token form or token=quoted-string form */
+ inp_str++;
+ if (*inp_str == DOUBLE_QUOTE) {
+ /* quoted-string follows */
+ inp_str++; /* skip the " char */
+ while (*inp_str) {
+ if (*inp_str == DOUBLE_QUOTE && *(inp_str - 1) != ESCAPE_CHAR) {
+ inp_str++;
+ break;
+ }
+ inp_str++;
+ }
+ } else {
+ /* token follows */
+ // SKIP_SIP_TOKEN(inp_str);
+ // Continue until another semicolon is found or end of string is
+ // reached
+ while (*inp_str != '\0' && *inp_str != SEMI_COLON) {
+ inp_str++;
+ }
+ }
+
+ /*
+ * Terminate the string that token_string is pointing
+ * to while keeping the value of *inp_str unchanged.
+ * Then assign the null terminated string to other_param_value
+ */
+ *other_param_value = (char *) cpr_malloc(SIP_MAX_OTHER_PARAM_LENGTH + 1 * sizeof(char));
+ if (*other_param_value != NULL) {
+ temp = *inp_str;
+ *inp_str = 0;
+ sstrncpy(*other_param_value, token_string, SIP_MAX_OTHER_PARAM_LENGTH);
+ *inp_str = temp;
+ }
+ break;
+
+ default:
+ CCSIP_DEBUG_ERROR(ERROR_3, "parse_other_param", inp_str);
+ *other_param_value = NULL;
+ return NULL;
+ }
+ return inp_str;
+}
+
+/*
+ * This function creates an array of url headers. Each
+ * element of the array has two member pointers:
+ * char pointer to header name,
+ * char pointer to header value
+ */
+static int
+url_add_headers_to_list (char *url_strp, sipUrl_t *sip_url)
+{
+ char *tmp_ptr = NULL;
+ char num_head = 1;
+ char *lasts = NULL;
+
+ if (!url_strp) {
+ return (PARSE_ERR_NULL_PTR);
+ }
+
+ tmp_ptr = strchr(url_strp, AMPERSAND);
+ while (tmp_ptr != NULL) {
+ num_head++;
+ tmp_ptr++;
+ tmp_ptr = strchr(tmp_ptr, AMPERSAND);
+ }
+
+ sip_url->headerp = (attr_value_pair_t *)
+ cpr_malloc(sizeof(attr_value_pair_t) * num_head);
+ if (!sip_url->headerp) {
+ return (PARSE_ERR_NO_MEMORY);
+ }
+
+ sip_url->num_headers = num_head;
+ num_head = 0;
+ url_strp = PL_strtok_r(url_strp, "&?", &lasts);
+ while ((url_strp != NULL) && (num_head < sip_url->num_headers)) {
+
+ tmp_ptr = strchr(url_strp, EQUAL_SIGN);
+ if (!tmp_ptr) {
+ return (PARSE_ERR_SYNTAX);
+ }
+ *tmp_ptr++ = 0;
+
+ sip_url->headerp[(uint16_t)num_head].attr = url_strp;
+ sip_url->headerp[(uint16_t)num_head].value = tmp_ptr;
+
+ num_head++;
+ url_strp = PL_strtok_r(NULL, "&", &lasts);
+ }
+
+ return 0;
+}
+
+static int
+parseUrlParams (char *url_param, sipUrl_t *sipUrl, genUrl_t *genUrl)
+{
+ static const char fname[] = "parseUrlParams";
+ char *param_val;
+ char *url_other_param = NULL;
+ uint16_t i;
+ // uint32_t ttl_val;
+ unsigned long strtoul_result;
+ char *strtoul_end;
+
+
+ /*
+ * url-parameters = *( ";" url-parameter )
+ * url-parameter = transport-param | user-param | method-param
+ * | ttl-param | maddr-param | other-param
+ * transport-param = "transport=" ( "udp" | "tcp" | "sctp" | "tls"
+ * | other-transport )
+ * ttl-param = "ttl=" ttl
+ * ttl = 1*3DIGIT ; 0 to 255
+ * maddr-param = "maddr=" host
+ * user-param = "user=" ( "phone" | "ip" )
+ * method-param = "method=" Method
+ * tag-param = "tag=" UUID
+ * lr-param = "lr"
+ * UUID = 1*( hex | "-" )
+ * other-param = ( token | ( token "=" ( token | quoted-string )))
+ * other-transport = token
+ */
+
+ /*
+ * url_param is pointing to the first character after the ';'
+ * This routine only prints error message for SYNTAX error, since we
+ * want to pinpoint the error location. For other errors it simply
+ * returns the error code.
+ */
+ SKIP_LWS(url_param);
+ if (*url_param == 0) {
+ return PARSE_ERR_UNEXPECTED_EOS;
+ }
+ while (1) {
+ if (cpr_strncasecmp(url_param, "transport=", 10) == 0) {
+ url_param += 10;
+ SKIP_LWS(url_param);
+ if (cpr_strncasecmp(url_param, "tcp", 3) == 0) {
+ sipUrl->transport = TRANSPORT_TCP;
+ url_param += 3;
+ } else if (cpr_strncasecmp(url_param, "tls", 3) == 0) {
+ sipUrl->transport = TRANSPORT_TLS;
+ url_param += 3;
+ } else if (cpr_strncasecmp(url_param, "sctp", 4) == 0) {
+ sipUrl->transport = TRANSPORT_SCTP;
+ url_param += 4;
+ } else if (cpr_strncasecmp(url_param, "udp", 3) == 0) {
+ sipUrl->transport = TRANSPORT_UDP;
+ url_param += 3;
+ } else {
+ SKIP_SIP_TOKEN(url_param);
+ SKIP_LWS(url_param);
+ if (*url_param != SEMI_COLON && *url_param != 0) {
+ CCSIP_DEBUG_ERROR(ERROR_3, fname, url_param);
+ return PARSE_ERR_SYNTAX;
+ }
+ }
+ } else if (cpr_strncasecmp(url_param, "user=", 5) == 0) {
+ url_param += 5;
+ SKIP_LWS(url_param);
+ if (cpr_strncasecmp(url_param, "phone", 5) == 0) {
+ sipUrl->is_phone = 1;
+ url_param += 5;
+ } else if (cpr_strncasecmp(url_param, "ip", 2) == 0) {
+ url_param += 2;
+ } else {
+ CCSIP_DEBUG_ERROR(ERROR_3, fname, url_param);
+ return PARSE_ERR_SYNTAX;
+ }
+ } else if (cpr_strncasecmp(url_param, "method=", 7) == 0) {
+ url_param += 7;
+ SKIP_LWS(url_param);
+ param_val = url_param;
+ while (isalpha((int) *url_param)) {
+ url_param++;
+ }
+ if (param_val == url_param) {
+ return PARSE_ERR_UNEXPECTED_EOS;
+ }
+ sipUrl->method = param_val;
+ /* Note that we have not terminated the method str yet */
+ } else if (cpr_strncasecmp(url_param, "ttl=", 4) == 0) {
+ char save_ch;
+
+ url_param += 4;
+ SKIP_LWS(url_param);
+ param_val = url_param;
+ while (isdigit((int) *url_param)) {
+ url_param++;
+ /* Atmost 3 digits allowed in ttl value */
+ if ((url_param - param_val) > 3) {
+ CCSIP_DEBUG_ERROR(ERROR_3, fname, url_param);
+ return PARSE_ERR_SYNTAX;
+ }
+ }
+ if (url_param == param_val) {
+ /* Did not find any digit after "ttl=" */
+ return PARSE_ERR_UNEXPECTED_EOS;
+ }
+ save_ch = *url_param;
+ *url_param = 0; /* Terminate the string for strtoul */
+
+ errno = 0;
+ strtoul_result = strtoul(param_val, &strtoul_end, 10);
+
+ if (errno || param_val == strtoul_end || strtoul_result > MAX_TTL_VAL) {
+ CCSIP_DEBUG_ERROR(ERROR_7, fname, sipUrl->ttl_val);
+ return PARSE_ERR_INVALID_TTL_VAL;
+ }
+ sipUrl->ttl_val = (unsigned char) strtoul_result;
+ *url_param = save_ch; /* Restore string state */
+ } else if (cpr_strncasecmp(url_param, "maddr=", 6) == 0) {
+ url_param += 6;
+ SKIP_LWS(url_param);
+ param_val = url_param; /* maddr now points to a host */
+ while (isalnum((int) *url_param) || *url_param == DOT ||
+ *url_param == DASH) {
+ url_param++;
+ }
+ if (url_param == param_val) {
+ /* Empty value of maddr */
+ return PARSE_ERR_UNEXPECTED_EOS;
+ }
+ sipUrl->maddr = param_val;
+ } else if (cpr_strncasecmp(url_param, "phone-context=", 14) == 0) {
+ url_param += 14;
+ SKIP_LWS(url_param);
+ param_val = url_param;
+
+ while (isalpha((int) *url_param)) {
+ url_param++;
+ }
+ if (param_val == url_param) {
+ return PARSE_ERR_SYNTAX;
+ }
+
+ /* If the next character is a space, we want to zero the
+ * string, otherwise the next character is EOF or ; in
+ * which case the code below will handle these cases.
+ */
+ if (isspace((int) *url_param)) {
+ *url_param++ = 0;
+ }
+ genUrl->phone_context = param_val;
+ } else if (cpr_strncasecmp(url_param, "lr", 2) == 0) {
+ // skip to the following SEMI_COLON or end
+ while (*url_param && *url_param != SEMI_COLON) {
+ url_param++;
+ }
+ sipUrl->lr_flag = TRUE;
+ } else {
+ /* other-param */
+ url_param = parse_other_param(url_param, &url_other_param);
+
+ if (url_param == NULL) {
+ return PARSE_ERR_SYNTAX;
+ }
+
+ if (url_other_param != NULL) {
+ /* Store it in first free slot */
+ i = 0;
+ while (i < SIP_MAX_LOCATIONS) {
+ if (genUrl->other_params[i] == NULL) {
+ break;
+ }
+ i++;
+ }
+
+ if (i == SIP_MAX_LOCATIONS) {
+ cpr_free(url_other_param);
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"parseUrlParams: Too many unknown parameters"
+ " in URL of Contact header", fname);
+ } else {
+ genUrl->other_params[i] = url_other_param;
+ url_other_param = NULL;
+ }
+ }
+ }
+
+ SKIP_LWS(url_param);
+ /* We either expect - end of string or ';' */
+ if (*url_param == 0) {
+ return 0;
+ }
+ if (*url_param != SEMI_COLON) {
+ CCSIP_DEBUG_ERROR(ERROR_3, fname, url_param);
+ return PARSE_ERR_SYNTAX;
+ }
+ *url_param++ = 0; /* Zero the ';' and advance pointer */
+ SKIP_LWS(url_param);
+ if (*url_param == 0) {
+ return PARSE_ERR_UNEXPECTED_EOS;
+ }
+ }
+}
+
+
+
+
+/*
+ * This routine is based on a very simple and valid assumption. SIP URL can be
+ * of the following forms (before the parameters, which start with ';')
+ * My understanding is that it is NOT a context-free grammar
+ * sip:host
+ * sip:host:port
+ * sip:user@host
+ * sip:user@host:port
+ * sip:user:password@host
+ * sip:user:password@host:port
+ * sip:user:password@[ipv6host]:port
+ *
+ * e.g. "1218@[2001:db8:c18:1:211:11ff:feb1:fb65]"
+ *
+ * Parse the SIP URL and zero the separators ( @ : ; etc)
+ * Point fields of sipUrl to appropriate places in the duplicated string
+ * This saves multiple mallocs for different fields of the sipUrl
+ * For a SIP URL of the form sip:user:password@host:port;params...
+ * loc_ptr[0] = Beginning of user part
+ * loc_ptr[1] = Beginning of password
+ * loc_ptr[2] = Beginning of host
+ * loc_ptr[3] = Beginning of port
+ * loc_ptr[4] = Beginning of parameters
+ */
+static int
+parseSipUrl (char *url_start, genUrl_t *genUrl)
+{
+ static const char fname[] = "parseSipUrl";
+ sipUrl_t *sipUrl = genUrl->u.sipUrl;
+ char ch = 0;
+ int token_cnt, separator_cnt;
+ char *url_main;
+ char *tokens[4];
+ char separator[4];
+ char *endptr;
+ uint16_t port;
+ boolean parsing_user_part;
+ char *temp_url;
+ boolean ipv6_addr = FALSE;
+
+ /* initializing separator */
+ separator[0] = '\0';
+
+ /*
+ * SIP-URL = "sip:" [ userinfo "@" ] hostport
+ * url-parameters [ headers ]
+ * userinfo = user [ ":" password ]
+ * user = *( unreserved | escaped
+ * | "&" | "=" | "+" | "$" | "," )
+ * password = *( unreserved | escaped
+ * | "&" | "=" | "+" | "$" | "," )
+ * hostport = host [ ":" port ]
+ * host = hostname | IPv4address | IPv6reference
+ * IPv6reference = "[" IPv6address "]"
+ * IPv6address = hexpart [ ":" IPv4address ]
+ * hexpart = hexseq / hexseq "::" [ hexseq ] / "::" [ hexseq ]
+ * hexseq = hex4 *( ":" hex4)
+ * hex4 = 1*4HEXDIG
+ * port = 1*DIGIT
+ * hostname = *( domainlabel "." ) toplabel [ "." ]
+ * domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum
+ * toplabel = alpha | alpha *( alphanum | "-" ) alphanum
+ * IPv4address = 1*digit "." 1*digit "." 1*digit "." 1*digit
+ * port = *digit
+ */
+
+ /* Ignore any leading white spaces too, */
+ SKIP_LWS(url_start);
+
+ /* we are pointing at whatever is after "sip:" */
+ url_main = url_start;
+
+ tokens[0] = url_main;
+ token_cnt = 0;
+ separator_cnt = 0;
+
+ /* Scan the string for : and @ and store their pointers. Terminate
+ * the search when you reach end of string or beginning of parameters
+ * indicated by ;. However the bis02 version of the spec allows ; in
+ * the user part of the URL. Thus the code must differentiate between
+ * a ; in the user part and a ; indicating the start of URL params.
+ */
+ while (1) {
+ if (*url_main == 0 || *url_main == SEMI_COLON ||
+ *url_main == QUESTION_MARK) {
+ /* Either end of string or beginning of SIP URL parameters
+ * or a ; encountered in the user part
+ */
+ parsing_user_part = FALSE;
+ temp_url = url_main;
+ while (*temp_url != 0) {
+ if (*temp_url == AT_SIGN) {
+ parsing_user_part = TRUE;
+ break;
+ } else if (*temp_url == QUESTION_MARK) {
+ /* overloaded headers in url */
+ break;
+ }
+ temp_url++;
+ }
+ temp_url = NULL;
+
+ if (!parsing_user_part) {
+ ch = *url_main;
+ *url_main++ = 0; /* Terminate the current token */
+ token_cnt++;
+ break;
+ }
+ }
+
+ /* For IPv6 address colon present so skip that */
+ if ((*url_main == COLON && ipv6_addr == FALSE)|| *url_main == AT_SIGN || *url_main == SPACE ||
+ *url_main == TAB) {
+
+ if (*url_main == SPACE || *url_main == TAB) {
+ *url_main++ = 0; /* Terminate current token */
+ SKIP_LWS(url_main);
+ }
+ /*
+ * Now we should be pointing to end of string or a separator
+ * (even ';' - beginning of parameters
+ */
+ if (*url_main == COLON || *url_main == AT_SIGN) {
+ if (separator_cnt == 3) {
+ /* Too many separators */
+ CCSIP_DEBUG_ERROR(ERROR_3_1, fname, *url_main);
+ return PARSE_ERR_SYNTAX;
+ }
+ separator[separator_cnt++] = *url_main;
+ *url_main++ = 0; /* Zero the separator */
+ SKIP_LWS(url_main);
+
+ if (*url_main == LEFT_SQUARE_BRACKET) {
+ *url_main++ = 0; /* Must be IPv6 address */
+ ipv6_addr = TRUE;
+ }
+ tokens[++token_cnt] = url_main;
+ if (*url_main == 0) {
+ break;
+ }
+ }
+
+ } else if (*url_main == RIGHT_SQUARE_BRACKET && ipv6_addr == TRUE) {
+
+ *url_main++ = 0; /* Found complete IPv6 address*/
+ } else {
+ url_main++;
+ }
+ }
+
+ sipUrl->port = SIP_WELL_KNOWN_PORT;
+ sipUrl->port_present = FALSE;
+
+ /* token_cnt contains the number of entries in the tokens array */
+ switch (token_cnt) {
+
+ case 1:
+ /* sip:host */
+ sipUrl->host = tokens[0];
+ break;
+
+ case 2:
+ if (separator[0] == AT_SIGN) {
+ /* sip:user@host */
+ sipUrl->user = tokens[0];
+ sipUrl->host = tokens[1];
+ sipUrl->is_ipv6 = ipv6_addr;
+ } else {
+ /* sip:host:port */
+ sipUrl->host = tokens[0];
+ port = (uint16_t) strtol(tokens[1], &endptr, 10);
+ if (*endptr == 0) {
+ sipUrl->port = port;
+ sipUrl->port_present = TRUE;
+ } else {
+ sipUrl->port = 0;
+ }
+ }
+ break;
+
+ case 3:
+ if (separator[0] == separator[1]) {
+ /* Cannot have 2 successive entries of : or @ */
+ CCSIP_DEBUG_ERROR(ERROR_3_1, fname, separator[1]);
+ return PARSE_ERR_SYNTAX;
+ }
+ if (separator[0] == AT_SIGN) {
+ /* sip:user@host:port */
+ sipUrl->user = tokens[0];
+ sipUrl->host = tokens[1];
+ port = (uint16_t) strtol(tokens[2], &endptr, 10);
+ if (*endptr == 0) {
+ sipUrl->port = port;
+ sipUrl->port_present = TRUE;
+ } else {
+ sipUrl->port = 0;
+ }
+ } else {
+ /* sip:user:password@host */
+ sipUrl->user = tokens[0];
+ sipUrl->password = tokens[1];
+ sipUrl->host = tokens[2];
+ }
+ break;
+
+ case 4:
+ /* sip:user:password@host:port */
+
+ if (separator[0] == COLON && separator[1] == AT_SIGN &&
+ separator[2] == COLON) {
+ sipUrl->user = tokens[0];
+ sipUrl->password = tokens[1];
+ sipUrl->host = tokens[2];
+ port = (uint16_t) strtol(tokens[3], &endptr, 10);
+ if (*endptr == 0) {
+ sipUrl->port = port;
+ sipUrl->port_present = TRUE;
+ } else {
+ sipUrl->port = 0;
+ }
+ } else {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Bad separator sequence", fname);
+ return PARSE_ERR_SYNTAX;
+ }
+ break;
+
+ }
+
+ /* Remove [ and ] from IPv6 address*/
+ trim_ipv6_host(sipUrl->host);
+
+ /* Verify the Port */
+ if (sipUrl->port == 0) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Received Bad Port", fname);
+ return PARSE_ERR_SYNTAX;
+ }
+
+ /* Verify the host portion */
+ if (sipSPI_validate_ip_addr_name(sipUrl->host) == FALSE) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Received Bad Host", fname);
+ return PARSE_ERR_SYNTAX;
+ }
+
+ /* Set default transport to UNSPECIFIED */
+ sipUrl->transport = TRANSPORT_UNSPECIFIED;
+ if (ch == SEMI_COLON) { /* Process URL parameters */
+ return parseUrlParams(url_main, sipUrl, genUrl);
+ } else if (ch == QUESTION_MARK) { /* Process URL headers */
+ return url_add_headers_to_list(url_main, sipUrl);
+ }
+ return 0; /* SUCCESS */
+}
+
+/*
+ * This routine is based on a very simple and valid assumption. TEL URL can be
+ * of the following forms (before the parameters, which start with ';')
+ * tel:user
+ *
+ * Parse the TEL URL and zero the separators (;)
+ * Point fields of sipUrl to appropriate places in the duplicated string
+ * This saves multiple mallocs for different fields of the telUrl
+ * For a TEL URL of the form tel:user;params...
+ */
+static int
+parseTelUrl (char *url_start, genUrl_t *genUrl)
+{
+ static const char fname[] = "parseTelUrl";
+ char *url_main;
+ telUrl_t *telUrl = genUrl->u.telUrl;
+ boolean is_local_subscriber = FALSE;
+
+ /*
+ * TEL-URL = telephone-scheme ":" telephone-subscriber
+ * telephone-scheme = "tel"
+ * telephone-subscriber = global-phone-number/local-phone-number
+ * global-phone-number = "+" base-phone-number [isdn-subaddress]
+ * [post-dial] *(area-specifier/service-provider/
+ * future-extension)
+ * base-phone-number = 1*phonedigit
+ * local-phone-number = 1*(phonedigit / dtmf-digit /pause-character)
+ * [isdn-subaddress] [post-dial] area-specifier
+ * *(are-specifier/service-provider/
+ * future-extension)
+ * isdn-subaddress = ";isub=" 1*phonedigit
+ * post-dial = ";postd=" 1*(phonedigit / dtmf-digit /
+ * pause-character)
+ * area-specifier = ";" phone-context-tag "=" phone-context-ident
+ * phone-context-tag = "phone-context"
+ * phone-context-ident = network-prefix / private-prefix
+ * network-prefix = global-network-prefix / local-network-prefix
+ * global-network-prefix = "+" 1*phonedigit
+ * local-network-prefix = 1*(phonedigit / dtmf-digit / pause-character)
+ * private-prefix = (%x21-22 / %x24-27 / %x2C / %x2F / %x3A /
+ * %x3C-40 /%x45-4F / %x51-56 / %x58-60 /
+ * %x65-6F / %x71-76 / %x78-7E /) *(%x21-3A /
+ * %x3C-7E)
+ * service-provider = ";" provider-tag "=" provider-hostname
+ * provider-tag = "tsp"
+ * provider-hostname = domain ; is defined in [RFC1035]
+ * future-extension = ";" token ["=" token]
+ * phonedigit = DIGIT / visual-separator
+ * visual-separator = "-" / "." / "(" / ")"
+ * pause-character = "p" / "w"
+ * dtmf-digit = "*" / "#" / "A" / "B" / "C" / "D"
+ */
+
+ if (!url_start) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Missing user field", fname);
+ return PARSE_ERR_SYNTAX;
+ }
+
+ url_main = url_start;
+ SKIP_LWS(url_main);
+ /*
+ * User field is the only mandatory field. The rest are optional
+ */
+
+ if (*url_main == PLUS) {
+ /* global-phone number */
+ url_main++;
+ telUrl->user = url_main;
+
+ while ((url_main) && ((*url_main == DASH) ||
+ (isdigit((int)*url_main)) || (*url_main == DOT))) {
+ url_main++;
+ }
+ } else {
+ /* local-phone-number */
+ telUrl->user = url_main;
+ is_local_subscriber = TRUE;
+
+ while ((url_main) && ((is_dtmf_or_pause(url_main)) ||
+ (*url_main == DASH) || (isdigit((int)*url_main)) ||
+ (*url_main == DOT))) {
+ url_main++;
+ }
+ }
+ if (url_main) {
+ SKIP_LWS(url_main);
+ }
+ if ((url_main) && (!(*url_main))) {
+ if (!is_local_subscriber) {
+ return 0; /* no fields to parse */
+ } else {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"local-phone-number must have area-specifier",
+ fname);
+ return PARSE_ERR_SYNTAX;
+ }
+ }
+ if (url_main) {
+ if ((*url_main) && (*url_main == SEMI_COLON)) {
+ *url_main++ = 0; /* skip separator */
+ } else {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Need ';' before parameters", fname);
+ return PARSE_ERR_SYNTAX;
+ }
+ }
+
+ while (url_main) {
+ SKIP_LWS(url_main);
+ if (cpr_strncasecmp(url_main, "isub=", 5) == 0) {
+ url_main += 5;
+ SKIP_LWS(url_main);
+ telUrl->isdn_subaddr = url_main;
+ } else if (cpr_strncasecmp(url_main, "postd=", 6) == 0) {
+ url_main += 6;
+ SKIP_LWS(url_main);
+ telUrl->post_dial = url_main;
+ } else if (cpr_strncasecmp(url_main, "phone-context", 13) == 0) {
+ url_main += 13;
+ SKIP_LWS(url_main);
+ if (*url_main != EQUAL_SIGN) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Bad syntax in phone_context field", fname);
+ return PARSE_ERR_SYNTAX;
+ }
+ *url_main++ = 0; /* skip "=" */
+ SKIP_LWS(url_main);
+ genUrl->phone_context = url_main;
+ } else if (cpr_strncasecmp(url_main, "tsp", 3) == 0) {
+ url_main += 3;
+ SKIP_LWS(url_main);
+ if (*url_main != EQUAL_SIGN) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Bad syntax in service-provider field", fname);
+ return PARSE_ERR_SYNTAX;
+ }
+ *url_main++ = 0; /* skip "=" */
+ SKIP_LWS(url_main);
+ telUrl->unparsed_tsp = url_main;
+ } else {
+ /* future extension */
+ if (telUrl->future_ext) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Only one future extension allowed", fname);
+ return PARSE_ERR_SYNTAX;
+ }
+ SKIP_LWS(url_main);
+ url_main = strchr(url_main, EQUAL_SIGN);
+ if (!url_main) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Bad field value", fname);
+ return PARSE_ERR_SYNTAX;
+ } else {
+ *url_main++ = 0;
+ SKIP_LWS(url_main);
+ telUrl->future_ext = url_main;
+ }
+ }
+ url_main = strchr(url_main, SEMI_COLON);
+ if (url_main) {
+ *url_main++ = 0; /* skip and zero separator */
+ }
+ }
+ if ((is_local_subscriber) && (!genUrl->phone_context)) {
+ /* local-phone-number must have area-specifier */
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"local-phone-number requires area-specifier", fname);
+ return PARSE_ERR_SYNTAX;
+ }
+ return 0; /* Success */
+}
+
+/*
+ * Parses a URL
+ * (eg. "sip:14085266593@sip.cisco.com;transport=UDP;user=phone")
+ * (eg. "tel:+1-555-555-5555")
+ * into a usable genUrl_t struct. Memory is created by this function.
+ * To free first free internal members(sippmh_genurl_free(genUrl)).
+ * Returns NULL if there is a parse error or malloc fails. Components/tokens
+ * not found in the URL are set to NULL, unless they have a default value
+ * defined by the protocol ( for example port 5060 is default)
+ * Parse error will set parse_errno variable to indicate the error.
+ * Expects a NULL terminated string in url.
+ * See comment block before parseSipUrl() and parseTelUrl()
+ * for some other details.
+ *
+ * url - Pointer to URL to be parsed
+ * dup_flag - Should this URL be duplicated and modified ??
+ */
+genUrl_t *
+sippmh_parse_url (char *url, boolean dup_flag)
+{
+ genUrl_t *genUrl;
+ char *url_main;
+ uint16_t i;
+ uint16_t skipValue;
+
+ if (url == NULL) {
+ return NULL;
+ }
+
+ genUrl = (genUrl_t *) cpr_calloc(1, sizeof(genUrl_t));
+ if (genUrl == NULL) {
+ return NULL;
+ }
+
+ /*
+ * Ensure clean other params pointers
+ */
+ i = 0;
+ while (i < SIP_MAX_LOCATIONS) {
+ genUrl->other_params[i] = NULL;
+ i++;
+ }
+
+ if (dup_flag) {
+ url_main = cpr_strdup(url);
+ if (!url_main) {
+ cpr_free(genUrl);
+ return NULL;
+ }
+ genUrl->str_start = url_main;
+ } else {
+ url_main = url;
+ }
+
+ SKIP_LWS(url_main);
+ if (!cpr_strncasecmp(url_main, "sips", 4)) {
+ genUrl->schema = URL_TYPE_SIP;
+ genUrl->sips = TRUE;
+ skipValue = 4;
+ } else if (!cpr_strncasecmp(url_main, "sip", 3)) {
+ genUrl->schema = URL_TYPE_SIP;
+ skipValue = 3;
+ } else if (!cpr_strncasecmp(url_main, "tel", 3)) {
+ genUrl->schema = URL_TYPE_TEL;
+ skipValue = 3;
+ } else if (!cpr_strncasecmp(url_main, "cid", 3)) {
+ genUrl->schema = URL_TYPE_CID;
+ skipValue = 3;
+ } else {
+ genUrl->schema = URL_TYPE_UNKNOWN;
+ skipValue = 0;
+ }
+ url_main += skipValue; /* skip "sip", "sips", cid, or "tel" */
+ if (*url_main != COLON) {
+ if (dup_flag) {
+ cpr_free(genUrl->str_start);
+ }
+ cpr_free(genUrl);
+ return NULL;
+ }
+ *url_main++ = 0; /* terminate ":" for schema */
+ switch (genUrl->schema) {
+ case URL_TYPE_CID:
+ case URL_TYPE_SIP:
+ genUrl->u.sipUrl = (sipUrl_t *) cpr_calloc(1, sizeof(sipUrl_t));
+ if (!genUrl->u.sipUrl) {
+ if (dup_flag) {
+ cpr_free(genUrl->str_start);
+ }
+ cpr_free(genUrl);
+ return NULL;
+ }
+ parse_errno = parseSipUrl(url_main, genUrl);
+ if (parse_errno == 0) {
+ //remove_visual_separators(genUrl);
+ if (genUrl->u.sipUrl->port == 0) {
+ /* If no port specified in SIP-URL, then use 5060 */
+ genUrl->u.sipUrl->port = SIP_WELL_KNOWN_PORT;
+ genUrl->u.sipUrl->port_present = FALSE;
+ }
+ return genUrl;
+ }
+ /* For syntax error, we would already have printed the error msg */
+ if (parse_errno != PARSE_ERR_SYNTAX) {
+ if (parse_errno == PARSE_ERR_NO_MEMORY) {
+ parse_errno = 0; /* Not really a parse error (out of mem) */
+ } else {
+ CCSIP_DEBUG_ERROR(parse_errors[parse_errno], "sippmh_parse_url");
+ }
+ }
+ sippmh_genurl_free(genUrl);
+ return NULL;
+ case URL_TYPE_TEL:
+ genUrl->u.telUrl = (telUrl_t *) cpr_calloc(1, sizeof(telUrl_t));
+ if (!genUrl->u.telUrl) {
+ if (dup_flag) {
+ cpr_free(genUrl->str_start);
+ }
+ cpr_free(genUrl);
+ return NULL;
+ }
+ parse_errno = parseTelUrl(url_main, genUrl);
+ if (parse_errno == 0) {
+ //remove_visual_separators(genUrl);
+ return genUrl;
+ }
+ /* For syntax error, we would already have printed the error msg */
+ if (parse_errno != PARSE_ERR_SYNTAX) {
+ if (parse_errno == PARSE_ERR_NO_MEMORY) {
+ parse_errno = 0; /* Not really a parse error (out of mem) */
+ } else {
+ CCSIP_DEBUG_ERROR(parse_errors[parse_errno], "sippmh_parse_url");
+ }
+ }
+ sippmh_genurl_free(genUrl);
+ return NULL;
+ default:
+ sippmh_genurl_free(genUrl);
+ return NULL;
+ }
+}
+
+/* If this is a SIP URL, free the sipUrl_t. If this is
+ * a telUrl_t free the telUrl_t. Also, free memory allocated by creation
+ * of the genUrl_t then free the genUrl_t.
+ */
+void
+sippmh_genurl_free (genUrl_t *genUrl)
+{
+ uint16_t i;
+
+ if (!genUrl) {
+ return;
+ }
+ if (genUrl->str_start) {
+ cpr_free(genUrl->str_start);
+ }
+ if ((genUrl->schema == URL_TYPE_SIP) ||
+ (genUrl->schema == URL_TYPE_CID)) {
+ if (genUrl->u.sipUrl->headerp) {
+ cpr_free(genUrl->u.sipUrl->headerp);
+ }
+ cpr_free(genUrl->u.sipUrl);
+ } else if (genUrl->schema == URL_TYPE_TEL) {
+ cpr_free(genUrl->u.telUrl);
+ }
+
+ /* Free any "other" parameters that were saved */
+ i = 0;
+ while (i < SIP_MAX_LOCATIONS) {
+ if (genUrl->other_params[i] != NULL) {
+ cpr_free(genUrl->other_params[i]);
+ }
+ i++;
+ }
+
+ cpr_free(genUrl);
+}
+
+/* Parse display name:
+ * "Mr. Watson"
+ * "Mr. Watson" is the display-name
+ * Return pointer to the '<'
+ */
+
+static char *
+parse_display_name (char *ptr)
+{
+ static const char fname[] = "parse_display_name";
+
+ while (*ptr) {
+ if (*ptr == DOUBLE_QUOTE && *(ptr - 1) != ESCAPE_CHAR) {
+ /* We reached end of quoted-string, mark end of display name */
+ *ptr++ = 0;
+ SKIP_LWS(ptr); /* Skip spaces till '<' */
+ /* ptr should now be pointing to '<' */
+ if (*ptr != LEFT_ANGULAR_BRACKET) {
+ parse_errno = PARSE_ERR_UNMATCHED_BRACKET;
+ CCSIP_DEBUG_ERROR(parse_errors[parse_errno], fname);
+
+ return NULL;
+ }
+ return ptr;
+ }
+ ptr++;
+ }
+
+ parse_errno = PARSE_ERR_UNTERMINATED_STRING;
+ CCSIP_DEBUG_ERROR(parse_errors[parse_errno], fname);
+
+ return NULL; /* Unmatched " */
+}
+
+
+/*
+ * Parse the name-addr form or the addr-spec form. These parse entities can
+ * be present in the From, To and Contact headers. So it is called either
+ * by sippmh_parse_contact() or sippmh_parse_from_or_to().
+ *
+ * input_loc_ptr - Pointer to the string to be parsed
+ * dup_flag - Should the input string be duplicated before parsing
+ * more_ptr - Return pointer to the next
+ * Tokens are extracted in place, i.e. we do not do a strdup for every token.
+ * We have on string and the output struct has pointers pointing to various
+ * tokens in the string.
+ * Note that this routine relies on the caller setting parse_errno to 0
+ * before calling.
+ *
+ * input_loc_ptr - Pointer to input string to be parsed
+ * start_ptr - Pointer to beginning of the string, which will be used for
+ * cleanup.
+ * dup_flag - Should the input string be duplicated before parsing
+ * name_addr_only_flag - If TRUE, means only name-addr form is allowed
+ * more_ptr - Return pointer to start of remaining string ( string that
+ * remains after parsing name-addr or addr-spec
+ *
+ * Output: A pointer to a valid SIP location OR
+ * NULL (in case of error)
+ *
+ */
+sipLocation_t *
+sippmh_parse_nameaddr_or_addrspec (char *input_loc_ptr,
+ char *start_ptr,
+ boolean dup_flag,
+ boolean name_addr_only_flag,
+ char **more_ptr)
+{
+ const char *fname = "sippmh_parse_nameaddr_or_addrspec";
+ char *addr_param;
+ char *loc_ptr, *addr_spec, *left_bracket;
+ sipLocation_t *sipLoc = NULL;
+ char *right_bracket = NULL;
+ char save_ch = 0;
+ char *displayNameStart;
+
+ *more_ptr = NULL;
+
+ /*
+ * name-addr = [ display-name ] "<" addr-spec ">"
+ * addr-spec = SIP-URL | URI
+ * display-name = *token | quoted-string
+ */
+ if (dup_flag) {
+ /* Duplicate the string and work with it */
+ start_ptr = loc_ptr = cpr_strdup(input_loc_ptr);
+ if (loc_ptr == NULL) {
+ return NULL;
+ }
+ } else {
+ loc_ptr = input_loc_ptr;
+ }
+
+ if (*loc_ptr == DOUBLE_QUOTE) {
+ displayNameStart = loc_ptr + 1;
+ left_bracket = parse_display_name(loc_ptr + 1);
+ if (left_bracket == NULL) {
+ /* Could not find matching " or reached end of string or could not
+ * find <
+ */
+ if (dup_flag) {
+ cpr_free(loc_ptr);
+ }
+ /* parse_display_name has already set the parse_errno */
+
+ return NULL;
+ }
+ } else {
+
+ displayNameStart = loc_ptr;
+ /* Either we have token(s) preceding '<' or start of addr-spec */
+ left_bracket = strpbrk(loc_ptr, ",<");
+ if (left_bracket) {
+ if (*left_bracket == COMMA) {
+ *left_bracket = 0;
+ *more_ptr = left_bracket;
+ left_bracket = NULL;
+ save_ch = COMMA;
+ }
+ } else {
+ *more_ptr = NULL;
+ }
+ }
+
+ sipLoc = (sipLocation_t *) cpr_calloc(1, sizeof(sipLocation_t));
+ if (sipLoc == NULL) {
+ if (dup_flag) {
+ cpr_free(loc_ptr);
+ }
+ return NULL;
+ }
+ sipLoc->loc_start = start_ptr; /* Save pointer to start of allocated mem */
+
+ if (left_bracket) {
+ /* This is a name-addr form */
+
+ *left_bracket = 0; /* Terminate the display-name portion */
+ sipLoc->name = displayNameStart;
+ addr_spec = left_bracket + 1;
+ right_bracket = strchr(addr_spec, RIGHT_ANGULAR_BRACKET);
+ if (right_bracket == NULL) {
+ if (dup_flag) {
+ cpr_free(loc_ptr);
+ }
+ cpr_free(sipLoc);
+ parse_errno = PARSE_ERR_UNMATCHED_BRACKET;
+ CCSIP_DEBUG_ERROR(parse_errors[parse_errno],
+ "sippmh_parse_nameaddr_or_addrspec");
+ return NULL;
+ }
+
+ /* Terminate the addr_spec at the > */
+ *right_bracket++ = 0;
+
+ /* Look for the next non-whitespace character */
+ SKIP_LWS(right_bracket);
+ *more_ptr = right_bracket;
+ } else {
+
+ /* This is addr-spec format */
+
+ if (name_addr_only_flag) {
+ if (dup_flag) {
+ cpr_free(loc_ptr);
+ }
+ cpr_free(sipLoc);
+ CCSIP_ERR_DEBUG {
+ buginf("\n%s: Bad name-addr format", fname);
+ }
+ return NULL;
+ }
+
+ addr_spec = loc_ptr;
+ /* In addr-spec form, it is illegal to have URL special
+ * chars such as SEMI_COLON, QUESTION MARK
+ */
+ addr_param = addr_spec;
+ while (*addr_param) {
+ if (*addr_param == QUESTION_MARK || *addr_param == SEMI_COLON) {
+
+ if ((save_ch != 0) && *more_ptr) {
+ /* restore the saved char mostly COMMA */
+ **more_ptr = save_ch;
+ }
+
+ save_ch = *addr_param;
+ *more_ptr = addr_param;
+
+ /* Terminate the addr-spec form at Special char */
+ *addr_param = 0;
+ break;
+ }
+ addr_param++;
+ }
+ }
+
+ sipLoc->genUrl = sippmh_parse_url(addr_spec, FALSE);
+ if (sipLoc->genUrl == NULL) {
+ if (dup_flag) {
+ cpr_free(loc_ptr);
+ }
+ cpr_free(sipLoc);
+ /* sippmh_parse_url would have set the parse_errno */
+ return NULL;
+ }
+
+ /*
+ * There is more stuff to follow since *more_ptr is not NULL
+ * replace the special chars (such as ? or ;) in original string
+ */
+ if ((save_ch != 0) && (*more_ptr != NULL)) {
+ **more_ptr = save_ch;
+ }
+ return sipLoc;
+}
+
+
+/*
+ * Validate the tag. The tag is composed of tokens. The tag_ptr
+ * points to the start of the tag and a list of semicolon
+ * separated addr-extensions or just the tag itself.
+ *
+ * Returns 0 (no error) if the tag is valid, else
+ * returns PARSE_ERR_SYNTAX.
+ *
+ */
+static int
+validate_tag (sipLocation_t *sipLoc, char *tag_ptr)
+{
+ static const char fname[] = "validate_tag";
+ int ret_val = 0;
+ char *term_ptr;
+
+ /* Skip "tag=", points to value */
+ tag_ptr += 4;
+ SKIP_LWS(tag_ptr);
+ if (*tag_ptr == 0) {
+ ret_val = PARSE_ERR_UNEXPECTED_EOS;
+ CCSIP_ERR_DEBUG {
+ buginf(parse_errors[ret_val], fname);
+ }
+
+ return ret_val;
+ }
+
+ sipLoc->tag = tag_ptr;
+
+ /* Walk the string until we encounter a non-token
+ * character. The only valid character at the end of
+ * string is either semicolon or end-of-line.
+ */
+
+ SKIP_SIP_TOKEN(tag_ptr);
+ term_ptr = tag_ptr;
+ /* skip trailing spaces */
+ SKIP_LWS(tag_ptr);
+ if ((*tag_ptr != SEMI_COLON) && (*tag_ptr != 0)) {
+ ret_val = PARSE_ERR_SYNTAX;
+ CCSIP_ERR_DEBUG {
+ buginf(parse_errors[ret_val], fname, tag_ptr);
+ }
+ } else {
+ /* terminate the tag */
+ *term_ptr = 0;
+ }
+
+ return ret_val;
+}
+
+
+sipLocation_t *
+sippmh_parse_from_or_to (char *input_loc_ptr, boolean dup_flag)
+{
+ static const char fname[] = "sippmh_parse_from_or_to";
+ char *more_ptr;
+ sipLocation_t *sipLoc;
+ boolean tag_found = FALSE;
+ char *lasts = NULL;
+
+ /*
+ * From = ( "From" | "f" ) ":" ( name-addr | addr-spec )
+ * *( ";" addr-params )
+ * addr-params = tag-param | addr-extension
+ * tag-param = "tag=" token
+ * addr-exten = token = ["=" (token | quoted-string)]
+ *
+ * NOTE: Only the tag parameter in the addr-params is relevant to
+ * SIP so we skip all addr-extensions when parsing addr-params.
+ */
+
+ parse_errno = 0;
+ more_ptr = NULL;
+ sipLoc = sippmh_parse_nameaddr_or_addrspec(input_loc_ptr, input_loc_ptr,
+ dup_flag, FALSE, &more_ptr);
+
+ if (sipLoc) { /* valid sipLocation */
+
+ if (more_ptr == NULL) {
+ return sipLoc;
+ }
+
+ /* initialize the tag */
+ sipLoc->tag = NULL;
+ if (*more_ptr == SEMI_COLON) {
+ *more_ptr++ = 0;
+ more_ptr = PL_strtok_r(more_ptr, ";", &lasts);
+ /* if we had a ; without any addr-params */
+ if (more_ptr == NULL) {
+ parse_errno = PARSE_ERR_UNEXPECTED_EOS;
+ CCSIP_DEBUG_ERROR(parse_errors[parse_errno], fname);
+ } else {
+ /* parse the tag but skip any addr-extensions */
+ while (more_ptr && tag_found == FALSE) {
+ SKIP_LWS(more_ptr);
+ if (strncmp(more_ptr, "tag=", 4) == 0) {
+ tag_found = TRUE;
+ parse_errno = validate_tag(sipLoc, more_ptr);
+ } else {
+ more_ptr = PL_strtok_r(NULL, ";", &lasts);
+ }
+ }
+ }
+
+ } else if (*more_ptr) {
+ parse_errno = PARSE_ERR_SYNTAX;
+ CCSIP_DEBUG_ERROR(parse_errors[parse_errno], fname, more_ptr);
+ }
+ }
+
+ if (parse_errno) {
+ sippmh_free_location(sipLoc);
+ sipLoc = NULL;
+ }
+
+ return sipLoc;
+}
+
+void
+sippmh_free_location (sipLocation_t * sipLoc)
+{
+ if (sipLoc) {
+ cpr_free(sipLoc->loc_start);
+ /* make sure to free contents in genUrl_t. */
+ sippmh_genurl_free(sipLoc->genUrl);
+ cpr_free(sipLoc);
+ }
+}
+
+static char *
+sippmh_parse_contact_params (char *params, sipContactParams_t *contact_params)
+{
+ char *param_value;
+ char *contact_other_param = NULL;
+ boolean good_params;
+ boolean good_qval;
+ char tmp_char;
+
+
+ /*
+ * contact-params = "q" "=" qvalue
+ * | "action" "=" "proxy" | "redirect"
+ * | "expires" "=" delta-seconds | <"> SIP-date <">
+ * | extension-attribute
+ *
+ * params is pointing to first character after ';'
+ */
+ SKIP_LWS(params);
+ if (*params == 0) {
+ return params;
+ }
+ while (1) {
+ good_params = FALSE;
+
+ /* Parse qval parameter */
+ if (*params == 'q' || *params == 'Q') {
+ params++;
+ SKIP_LWS(params);
+ if (*params == EQUAL_SIGN) {
+ params++;
+ SKIP_LWS(params);
+ if (*params) {
+ param_value = params;
+ good_qval = TRUE;
+ tmp_char = *params;
+ /* the qval must be in one of these forms */
+ if ((!strncmp(params, "0", 1)) ||
+ (!strncmp(params, "1", 1))) {
+ params++; /* move up to "." if present */
+ if (*params == DOT) {
+ params++;
+ if (isdigit((int) *params)) {
+ while (isdigit((int) *params)) {
+ if ((tmp_char == '1') &&
+ (*params != '0')) {
+ good_qval = FALSE;
+ break;
+ }
+ params++;
+ }
+ } else {
+ good_qval = FALSE;
+ }
+ } else if (((*params)) && ((*params != SPACE) &&
+ (*params != SEMI_COLON) &&
+ (*params != TAB))) {
+ good_qval = FALSE;
+ }
+ } else {
+ good_qval = FALSE;
+ }
+ if (good_qval) {
+ good_params = TRUE;
+ contact_params->qval = param_value;
+ if (*params == SPACE || *params == TAB) {
+ *params++ = 0; /* Terminate the qval */
+ }
+ }
+ }
+ }
+
+ /* Parse action paramater */
+ } else if (cpr_strncasecmp(params, "action", 6) == 0) {
+ params += 6;
+ SKIP_LWS(params);
+ if (*params == EQUAL_SIGN) {
+ params++;
+ SKIP_LWS(params);
+ if (cpr_strncasecmp(params, "proxy", 5) == 0) {
+ contact_params->action = PROXY;
+ params += 5;
+ good_params = TRUE;
+ } else if (cpr_strncasecmp(params, "redirect", 8) == 0) {
+ contact_params->action = REDIRECT;
+ params += 8;
+ good_params = TRUE;
+ }
+ }
+
+ /* Parse expires paramater */
+ } else if (cpr_strncasecmp(params, "expires", 7) == 0) {
+ params += 7;
+ SKIP_LWS(params);
+ if (*params == EQUAL_SIGN) {
+ params++;
+ SKIP_LWS(params);
+ if (*params) {
+ char save_ch;
+ boolean is_int = FALSE;
+
+ /* Expires can be given in delta seconds or date format.
+ * If date is used, the date must be enclosed in quotes.
+ * IOS does not use this parameter, but the SIP phones
+ * do.
+ */
+ contact_params->expires_gmt = '\0';
+ good_params = TRUE;
+ param_value = params;
+ while (isdigit((int) *params)) {
+ params++;
+ is_int = TRUE;
+ }
+ if (is_int == TRUE) {
+ save_ch = *params;
+ *params = 0; /* terminate the string for strtoul */
+ contact_params->expires = strtoul(param_value, NULL, 10);
+ *params = save_ch;
+ } else {
+ /* expires may be in SIP-date format */
+ char *gmt_str;
+
+ if (*params == DOUBLE_QUOTE) { /* skip the quote */
+ params++;
+ }
+ if ((gmt_str = strstr(params, "GMT")) != NULL) {
+ contact_params->expires_gmt = params;
+ params = gmt_str + 3;
+ contact_params->expires = 0;
+
+ if (*params == SPACE || *params == TAB || *params == DOUBLE_QUOTE) {
+ *params++ = '\0';
+ }
+ }
+ }
+ }
+ }
+ /* Parse x-cisco-newreg */
+ } else if (cpr_strncasecmp(params, REQ_CONT_PARAM_CISCO_NEWREG,
+ sizeof(REQ_CONT_PARAM_CISCO_NEWREG) - 1) == 0) {
+ /*
+ * x-cisco-newreg in the contact is set by CCM in the 200 OK
+ * response to the 1st. line registration message as information
+ * only to the endpoint that its registration is a new
+ * registration to the CCM.
+ */
+
+ /*
+ * Move parameter pointer pass this parm (-1 is to exclude
+ * null terminating character of the parameter name).
+ */
+ params += sizeof(REQ_CONT_PARAM_CISCO_NEWREG) - 1;
+ good_params = TRUE;
+ contact_params->flags |= SIP_CONTACT_PARM_X_CISCO_NEWREG;
+
+ /* Parse contact-extension paramater */
+ } else {
+ if (params) {
+ params = parse_other_param(params, &contact_other_param);
+ if (params) {
+ good_params = TRUE;
+ /*
+ * Contact extensions are not supported. Throw away
+ * any that were just parsed.
+ */
+ if (contact_other_param != NULL) {
+ cpr_free(contact_other_param);
+ }
+ }
+ }
+ }
+ if (good_params == FALSE) {
+ parse_errno = PARSE_ERR_SYNTAX;
+ return params;
+ }
+ SKIP_LWS(params);
+ if (*params == SEMI_COLON) {
+ /* More parameters follow */
+ *params++ = 0;
+ SKIP_LWS(params);
+ } else {
+ /* Either we have encountered end of string or start of next
+ * location in this contact header.
+ */
+ return params;
+ }
+ }
+}
+
+/* Parses limit parameter for CC-Diversion or CC-Redirect
+ * header. The parsed value is in sipDiversion_t structure.
+ * Returns pointer to remaining characters in the buffer, if fails NULL
+ */
+static char *
+sippmh_parse_limit_params (char *limit_t, sipDiversion_t *sipdiversion)
+{
+ boolean params_good = FALSE;
+ char save_ch;
+ char *param_value = NULL;
+ int digit_count = 0;
+
+ if ((limit_t == NULL) || (sipdiversion == NULL)) {
+ return NULL;
+ }
+
+ SKIP_LWS(limit_t);
+ if (*limit_t == EQUAL_SIGN) {
+ limit_t++;
+ SKIP_LWS(limit_t);
+ if (*limit_t) {
+ params_good = TRUE;
+ param_value = limit_t;
+ while (isdigit((int) *limit_t)) {
+ digit_count++;
+ limit_t++;
+ }
+ if (digit_count > 2) {
+ /* More than two digits */
+ params_good = FALSE;
+ return NULL;
+ }
+ digit_count = 0;
+ save_ch = *limit_t;
+ *limit_t = 0;
+ sipdiversion->limit = strtoul(param_value, NULL, 10);
+ *limit_t = save_ch;
+ }
+ } else {
+ /* Equal to sign missing */
+ params_good = FALSE;
+ }
+
+ if (params_good) {
+ return limit_t;
+ } else {
+ return NULL;
+ }
+}
+
+
+/* Parses counter parameter for CC-Diversion or CC-Redirect
+ * header. The parsed value is in sipDiversion_t structure.
+ * Returns pointer to remaining characters in the buffer, if fails NULL
+ */
+static char *
+sippmh_parse_counter_params (char *counter_t, sipDiversion_t *sipdiversion)
+{
+ boolean params_good = FALSE;
+ char save_ch;
+ char *param_value = NULL;
+ int digit_count = 0;
+
+ if ((counter_t == NULL) || (sipdiversion == NULL)) {
+ return NULL;
+ }
+
+ SKIP_LWS(counter_t);
+ if (*counter_t == EQUAL_SIGN) {
+ counter_t++;
+ SKIP_LWS(counter_t);
+ if (*counter_t) {
+ params_good = TRUE;
+ param_value = counter_t;
+ while (isdigit((int) *counter_t)) {
+ digit_count++;
+ counter_t++;
+ }
+ if (digit_count > 2) {
+ /* More than two digits */
+ params_good = FALSE;
+ return NULL;
+ }
+ digit_count = 0;
+ save_ch = *counter_t;
+ *counter_t = 0;
+ sipdiversion->counter = strtoul(param_value, NULL, 10);
+ *counter_t = save_ch;
+
+ }
+ } else {
+ /* Equal to sign missing */
+ params_good = FALSE;
+ }
+
+ if (params_good) {
+ return counter_t;
+ } else {
+ return NULL;
+ }
+}
+
+
+static boolean
+sippmh_parse_diversion_params (char *diversion_t, sipDiversion_t *sipdiversion)
+{
+
+ while (1) {
+ /* Parsing diversion-reason parameter */
+ if (strncasecmp(diversion_t, DIVERSION_REASON, 6) == 0) {
+// We don't use reason parameter, so comment out at this time.
+// diversion_t += 6;
+// if ((diversion_t = sippmh_parse_reason_params(diversion_t, sipdiversion)) == NULL)
+// return FALSE;
+ /*
+ * Since we do not use reason parameter, search for semi-colan to mark
+ * start of next parameter. If no semi-colon, then we are done.
+ */
+ diversion_t = strchr(diversion_t, SEMI_COLON);
+ if (diversion_t == NULL) {
+ // End of parameter list
+ return TRUE;
+ }
+ /* Parse diversion-limit parameter */
+ } else if (strncasecmp(diversion_t, DIVERSION_LIMIT, 5) == 0) {
+ diversion_t += 5;
+ if ((diversion_t = sippmh_parse_limit_params(diversion_t, sipdiversion)) == FALSE)
+ return FALSE;
+
+ /* Parse diversion-counter parameter */
+ } else if (strncasecmp(diversion_t, DIVERSION_COUNTER, 7) == 0) {
+ diversion_t += 7;
+ if ((diversion_t = sippmh_parse_counter_params(diversion_t, sipdiversion)) == FALSE)
+ return FALSE;
+
+ /* Parse diversion-privacy parameter */
+ } else if (strncasecmp(diversion_t, DIVERSION_PRIVACY, 7) == 0) {
+ diversion_t += 7;
+ if ((diversion_t = parse_generic_param(diversion_t, &(sipdiversion->privacy))) == NULL)
+ return FALSE;
+
+ /* Parse diversion-screen parameter */
+ } else if (strncasecmp(diversion_t, DIVERSION_SCREEN, 6) == 0) {
+ diversion_t += 6;
+ if ((diversion_t = parse_generic_param(diversion_t, &(sipdiversion->screen))) == NULL)
+ return FALSE;
+ }
+
+ SKIP_LWS(diversion_t);
+ if (*diversion_t == SEMI_COLON) {
+ /* More parameters follow */
+ *diversion_t++ = 0;
+ SKIP_LWS(diversion_t);
+ } else {
+ break;
+ }
+ }
+
+ return TRUE;
+
+}
+
+sipDiversion_t *
+sippmh_parse_diversion (const char *diversion, char *diversionhead)
+{
+ char *param_ptr;
+ sipDiversion_t *sipdiversion;
+ sipLocation_t *sipLoc;
+ char *diversion_t, *start_ptr;
+
+ /* CC-Diversion = "CC-Diversion"
+ * *(diversion-params [comment])
+ * diversion-params = diversion-addr | diversion-reason |
+ * diversion-counter| diversion-limit
+ * diversion-addr = (name-addr | addr-spec)*(";"addr-params)
+ * diversion-reason = "reason"= "unknown" | "user-busy" | "no-answer" |
+ * "unconditional" | "deflection"| "follow-me" |
+ * "out-of-service" | " time-of-day" | "unavailable" |
+ * "do-not-disturb"
+ * diversion-counter = "counter" = 2*DIGIT
+ * diversion-limit = "limit" = 2*DIGIT
+ */
+
+ /*
+ * Diversion = "Diversion" ":" 1# (name-addr *( ";" diversion_params ))
+ * diversion-params = diversion-reason | diversion-counter |
+ * diversion-limit | diversion-privacy |
+ * diversion-screen | diversion-extension
+ * diversion-reason = "reason" "="
+ * ( "unknown" | "user-busy" | "no-answer" |
+ * "unavailable" | "unconditional" |
+ * "time-of-day" | "do-not-disturb" |
+ * "deflection" | "follow-me" |
+ * "out-of-service" | "away" |
+ * token | quoted-string )
+ * diversion-counter = "counter" "=" 1*2DIGIT
+ * diversion-limit = "limit" "=" 1*2DIGIT
+ * diversion-privacy = "privacy" "=" ( "full" | "name" |
+ * "uri" | "off" | token | quoted-string )
+ * diversion-screen = "screen" "=" ( "yes" | "no" | token |
+ * quoted-string )
+ * diversion-extension = token ["=" (token | quoted-string)]
+ */
+
+ sipdiversion = (sipDiversion_t *) cpr_calloc(1, sizeof(sipDiversion_t));
+ if (sipdiversion == NULL) {
+ return NULL;
+ }
+
+ diversion_t = cpr_strdup(diversion);
+
+ if (diversion_t == NULL) {
+ sippmh_free_diversion(sipdiversion);
+ return NULL;
+ }
+
+ start_ptr = diversion_t;
+
+ do {
+
+ param_ptr = NULL;
+ sipLoc = sippmh_parse_nameaddr_or_addrspec(diversion_t, start_ptr, FALSE, FALSE,
+ ¶m_ptr);
+ if (sipLoc == NULL) {
+ cpr_free(start_ptr);
+ sippmh_free_diversion(sipdiversion);
+ sipdiversion = NULL;
+ break;
+ }
+
+ sipdiversion->locations = sipLoc;
+
+ if (param_ptr == NULL || *param_ptr == 0) {
+ /* No params */
+ break;
+ }
+ diversion_t = param_ptr;
+ if (*diversion_t == SEMI_COLON) {
+ /* Parsing Diversion Headers */
+ *diversion_t++ = 0;
+
+ if ((strncasecmp(diversionhead, SIP_HEADER_DIVERSION,
+ sizeof(SIP_HEADER_DIVERSION)) == 0) ||
+ (strncasecmp(diversionhead, SIP_HEADER_CC_DIVERSION,
+ sizeof(SIP_HEADER_CC_DIVERSION)) == 0)) {
+
+ if (sippmh_parse_diversion_params(diversion_t, sipdiversion) == FALSE) {
+
+ CCSIP_ERR_DEBUG {
+ buginf("\nsippmh_parse_diversion: syntax error in Diversion header");
+ }
+ parse_errno = PARSE_ERR_SYNTAX;
+ sippmh_free_diversion(sipdiversion);
+ sipdiversion = NULL;
+ break;
+ }
+ }
+ /* Must reach here after parsing all parameters */
+ break; /* break out of original do loop */
+ } else {
+ CCSIP_ERR_DEBUG {
+ buginf("\nsippmh_parse_diversion: syntax error missing "
+ "semicolon in Diversion header");
+ }
+ parse_errno = PARSE_ERR_SYNTAX;
+ sippmh_free_diversion(sipdiversion);
+ sipdiversion = NULL;
+ break;
+ }
+
+ } while (1);
+ return sipdiversion;
+}
+
+void
+sippmh_free_diversion (sipDiversion_t * ccr)
+{
+ if (ccr) {
+ if (ccr->locations) {
+ sippmh_free_location(ccr->locations);
+ }
+ cpr_free(ccr);
+ }
+}
+
+
+sipContact_t *
+sippmh_parse_contact (const char *input_contact)
+{
+ int j, k;
+ char *contact = NULL, *start_ptr = NULL;
+ char *more_ptr;
+ sipContact_t *sipContact;
+ sipContactParams_t params;
+
+ /*
+ * Contact = ( "Contact" | "m" ) ":"
+ * ("*" | (1# (( name-addr | addr-spec )
+ * [ *( ";" contact-params ) ] [ comment ] )))
+ * name-addr = [ display-name ] "<" addr-spec ">"
+ * addr-spec = SIP-URL | URI
+ * display-name = *token | quoted-string
+ *
+ * contact-params = "q" "=" qvalue
+ * | "action" "=" "proxy" | "redirect"
+ * | "expires" "=" delta-seconds | <"> SIP-date <">
+ * | extension-attribute
+ *
+ */
+ parse_errno = 0;
+ contact = cpr_strdup(input_contact);
+ if (contact == NULL) {
+ return NULL;
+ }
+
+ sipContact = (sipContact_t *) cpr_calloc(1, sizeof(sipContact_t));
+ if (sipContact == NULL) {
+ cpr_free(contact);
+ return NULL;
+ }
+
+ memset(¶ms, 0, sizeof(sipContactParams_t));
+
+ start_ptr = contact;
+
+ do {
+ sipLocation_t *sipLoc;
+
+ more_ptr = NULL;
+ sipLoc = sippmh_parse_nameaddr_or_addrspec(contact, start_ptr, FALSE,
+ FALSE, &more_ptr);
+ if (sipLoc == NULL) {
+ if ((more_ptr != NULL) && (*more_ptr == COMMA)) {
+ /* Another location follows */
+ contact = more_ptr;
+ *contact++ = 0;
+ SKIP_LWS(contact);
+ if (sipContact->num_locations == SIP_MAX_LOCATIONS) {
+ CCSIP_ERR_DEBUG {
+ buginf("\nsippmh_parse_contact: Too many location headers"
+ " in Contact header");
+ }
+ /* go with what we have */
+ break;
+ }
+ continue;
+ } else {
+ if (sipContact->num_locations == 0) {
+ // Free start_ptr only if we fail the first location
+ // For the others, it will be freed when sipContact is
+ // freed
+ cpr_free(start_ptr);
+ }
+ sippmh_free_contact(sipContact);
+ sipContact = NULL;
+ break;
+ }
+ }
+ if (sipContact->num_locations) {
+ sipLoc->loc_start = NULL;
+ }
+ if (more_ptr == NULL || *more_ptr == 0) {
+ /* No params, means no qval and assume lowest priority */
+ sipContact->locations[sipContact->num_locations++] = sipLoc;
+ break;
+ }
+ contact = more_ptr;
+ /*
+ * At this point, either contact is pointing to
+ * 1) ';' - Contact params
+ * 2) ',' - Beginning of next location
+ * 3) End of string
+ * 4) Any other character is syntax error
+ */
+
+ j = sipContact->num_locations; /* By default insert at the end */
+ params.qval = "";
+
+ if (*contact == SEMI_COLON) {
+ /* Now parse the Contact params */
+ *contact++ = 0;
+ params.flags = 0;
+ contact = sippmh_parse_contact_params(contact, ¶ms);
+ /*
+ * Now, do an insertion sort on this list (qval is the key).
+ * Higher values of q come first.
+ */
+ for (j = 0; j < sipContact->num_locations; ++j) {
+ if (strcmp(params.qval, sipContact->params[j].qval) > 0) {
+ for (k = sipContact->num_locations; k > j; --k) {
+ sipContact->locations[k] = sipContact->locations[k - 1];
+ sipContact->params[k] = sipContact->params[k - 1];
+ }
+ break;
+ }
+ }
+ /* At this point j points to the entry to use */
+ }
+
+ sipContact->params[j] = params;
+ sipContact->locations[j] = sipLoc;
+ sipContact->num_locations++;
+
+ if (contact && *contact == COMMA) {
+ /* Another location follows */
+ *contact++ = 0;
+ SKIP_LWS(contact);
+ if (sipContact->num_locations == SIP_MAX_LOCATIONS) {
+ CCSIP_ERR_DEBUG {
+ buginf("\nsippmh_parse_contact: Too many location headers"
+ " in Contact header");
+ }
+ /* go with what we have */
+ break;
+ }
+ } else {
+ if (contact && *contact) {
+ parse_errno = PARSE_ERR_SYNTAX;
+ CCSIP_DEBUG_ERROR(parse_errors[parse_errno], "sippmh_parse_contact",
+ contact);
+ sippmh_free_contact(sipContact);
+ sipContact = NULL;
+ }
+ break;
+ }
+ } while (1);
+
+ if (sipContact) {
+ sipContact->new_flag = TRUE;
+ }
+ return sipContact;
+}
+
+
+void
+sippmh_free_contact (sipContact_t *sc)
+{
+ int i;
+
+ if (sc) {
+ for (i = 0; i < sc->num_locations; ++i) {
+ if (sc->locations[i]->loc_start) {
+ /* Free the entire header value that we duplicated */
+ cpr_free(sc->locations[i]->loc_start);
+ }
+ /* Free the genUrl_t struct in the sipLocation_t */
+ sippmh_genurl_free(sc->locations[i]->genUrl);
+ /* Free the sipLocation_t struct */
+ cpr_free(sc->locations[i]);
+ }
+
+ /* Free the sipContact_t struct */
+ cpr_free(sc);
+ }
+}
+
+static boolean
+parse_via_params (char *str, sipVia_t *sipVia)
+{
+ char **ptr;
+
+ /* str is currently pointing to beginning of parameters */
+
+ while (1) {
+ /* To be friendly, skip leading spaces */
+ SKIP_LWS(str);
+ if (strncasecmp(str, VIA_HIDDEN, 6) == 0) {
+ str += 6;
+ sipVia->flags |= VIA_IS_HIDDEN;
+ ptr = NULL;
+ } else if (strncasecmp(str, VIA_TTL, 3) == 0) {
+ str += 3;
+ ptr = &(sipVia->ttl);
+ } else if (strncasecmp(str, VIA_MADDR, 5) == 0) {
+ str += 5;
+ ptr = &(sipVia->maddr);
+ } else if (strncasecmp(str, VIA_RECEIVED, 8) == 0) {
+ str += 8;
+ ptr = &(sipVia->recd_host);
+ } else if (strncasecmp(str, VIA_BRANCH, 6) == 0) {
+ str += 6;
+ ptr = &(sipVia->branch_param);
+ } else {
+ ptr = NULL;
+ }
+ if (ptr) {
+ if (*ptr) {
+ /* ptr already points to something
+ * -- duplicate param found */
+ return FALSE;
+ }
+ SKIP_LWS(str); /* Skip spaces till equal sign */
+ if (*str == EQUAL_SIGN) {
+ str++;
+ SKIP_LWS(str);
+ *ptr = str;
+ }
+ }
+ str = strpbrk(str, ";,");
+ if (str == NULL) {
+ if (ptr && *ptr) {
+ trim_right(*ptr);
+ }
+ return TRUE;
+ }
+ if (*str == COMMA) {
+ *str++ = 0;
+ SKIP_LWS(str);
+ sipVia->more_via = str;
+ if (ptr && *ptr) {
+ trim_right(*ptr);
+ }
+ return TRUE;
+ }
+ *str++ = 0; /* Zero ';' and advance pointer */
+ if (ptr && *ptr) {
+ trim_right(*ptr);
+ }
+ }
+}
+
+sipVia_t *
+sippmh_parse_via (const char *input_via)
+{
+ static const char fname[] = "sippmh_parse_via";
+ char *via;
+ char *separator;
+ sipVia_t *sipVia;
+ char *endptr;
+ char *port_num_str;
+ uint16_t port_num;
+
+ /*
+ * Via = ( "Via" | "v") ":" 1#( sent-protocol sent-by
+ * *( ";" via-params ) [ comment ] )
+ * via-params = via-hidden | via-ttl | via-maddr
+ * | via-received | via-branch
+ * via-hidden = "hidden"
+ * via-ttl = "ttl" "=" ttl
+ * via-maddr = "maddr" "=" maddr
+ * via-received = "received" "=" host
+ * via-branch = "branch" "=" token
+ * sent-protocol = protocol-name "/" protocol-version "/" transport
+ * protocol-name = "SIP" | token
+ * protocol-version = token
+ * transport = "UDP" | "TCP" | "TLS" | token
+ * sent-by = ( host [ ":" port ] ) | ( concealed-host )
+ * concealed-host = token
+ * ttl = 1*3DIGIT ; 0 to 255
+ */
+
+ parse_errno = PARSE_ERR_SYNTAX;
+ if (input_via == NULL) {
+ return NULL;
+ }
+ sipVia = NULL;
+ via = NULL;
+ SKIP_LWS(input_via);
+ do {
+ if (strncasecmp(input_via, "SIP", 3)) {
+ /* Unknown protocol-name */
+ break;
+ }
+ input_via += 3;
+
+ SKIP_LWS(input_via);
+ if (*input_via != '/') {
+ break;
+ }
+ input_via++; /* Skip '/' */
+
+ SKIP_LWS(input_via);
+ /* input_via should now be pointing to version */
+
+ /* Duplicate the string and work with it */
+ via = cpr_strdup(input_via);
+ if (via == NULL) {
+ parse_errno = 0;
+ return NULL;
+ }
+ /* Allocate sipVia_t struct */
+ sipVia = (sipVia_t *) cpr_calloc(1, sizeof(sipVia_t));
+ if (sipVia == NULL) {
+ parse_errno = 0;
+ cpr_free(via);
+ return NULL;
+ }
+
+ /* version also points to the start of memory allocated */
+ sipVia->version = via;
+ if (strncmp(via, "2.0", 3)) {
+ break;
+ }
+ via += 3; /* Go past version */
+
+ SKIP_LWS(via);
+ if (*via != '/') {
+ break;
+ }
+ *via++ = 0; /* Terminate version string and go past '/' */
+
+ SKIP_LWS(via); /* Point to transport */
+ sipVia->transport = via;
+ if (strncasecmp(via, "UDP", 3) && strncasecmp(via, "TCP", 3) &&
+ strncasecmp(via, "TLS", 3)) {
+ /* Invalid transport */
+ break;
+ }
+ via += 3; /* Go past the transport string */
+ *via++ = 0; /* Terminate transport string and advance pointer */
+
+
+ /* Skip blanks */
+ SKIP_LWS(via);
+ if (*via == 0) {
+ parse_errno = PARSE_ERR_UNEXPECTED_EOS;
+ CCSIP_DEBUG_ERROR(parse_errors[parse_errno], fname);
+ break;
+ }
+
+ parse_errno = 0;
+
+ } while (0);
+
+ if (parse_errno) {
+ if (parse_errno == PARSE_ERR_SYNTAX) {
+ CCSIP_DEBUG_ERROR(parse_errors[parse_errno], fname, via ? via : input_via);
+ }
+ sippmh_free_via(sipVia);
+ return NULL;
+ }
+
+ port_num_str = SIP_WELL_KNOWN_PORT_STR;
+ sipVia->host = via;
+ /*
+ * Either we can have a ':' followed by port
+ * or start of parameters signalled by ';'
+ * or end of this Via indicated by ','
+ */
+ if (*via == '[') {
+ /* IPv6 address */
+ sipVia->host = via;
+ sipVia->is_ipv6 = TRUE;
+ separator = strpbrk(via, "]");
+
+ if (separator && *separator == ']') {
+ separator++;
+ }
+ } else {
+
+ separator = via;
+ }
+
+ if (separator) {
+ separator = strpbrk(separator, ":;,");
+ }
+ if (separator) {
+ if (*separator == COLON) {
+ /* Port number follows */
+ *separator++ = 0;
+ port_num_str = separator;
+ separator = strpbrk(separator, ";,");
+ }
+ if (separator) {
+ if (*separator == SEMI_COLON) {
+ *separator++ = 0;
+ /* Parameters follow */
+ if (parse_via_params(separator, sipVia) == FALSE) {
+ CCSIP_ERR_DEBUG
+ buginf("%s: Duplicate params in Via\n", fname);
+ sippmh_free_via(sipVia);
+ return NULL;
+ }
+ } else {
+ *separator++ = 0;
+ SKIP_LWS(separator);
+ sipVia->more_via = separator;
+ }
+ }
+ }
+
+ /* Validate the host portion */
+ if ((sipSPI_validate_ip_addr_name(sipVia->host) == FALSE)) {
+ CCSIP_ERR_DEBUG buginf("\n%s: Invalid host in Via", fname);
+ sippmh_free_via(sipVia);
+ return NULL;
+ }
+
+ /* Fix host portion */
+ trim_right(sipVia->host);
+ /* Fix IPv6 host */
+ trim_ipv6_host(sipVia->host);
+
+ /* validate port portion */
+ port_num = (uint16_t) strtol(port_num_str, &endptr, 10);
+
+ /*
+ * There may be trailing white space in the port portion. So, ignore them.
+ */
+ SKIP_LWS(endptr);
+ if (*endptr || port_num == 0) {
+ sippmh_free_via(sipVia);
+ CCSIP_ERR_DEBUG buginf("\n%s: Invalid port number in Via", fname);
+ return NULL;
+ }
+ sipVia->remote_port = port_num;
+ sipVia->recd_host = sipVia->host;
+ return sipVia;
+}
+
+void
+sippmh_free_via (sipVia_t * sipVia)
+{
+ if (sipVia) {
+ cpr_free(sipVia->version);
+ cpr_free(sipVia);
+ }
+}
+
+
+sipCseq_t *
+sippmh_parse_cseq (const char *cseq)
+{
+ char *lasts = NULL;
+ /*
+ * CSeq = "CSeq" ":" 1*DIGIT Method
+ */
+ sipCseq_t *sipCseq = (sipCseq_t *) cpr_calloc(1, sizeof(sipCseq_t));
+
+ if (!sipCseq) {
+ return (NULL);
+ }
+
+/* if ',' is present then more than 1 cseq are present */
+ if (strchr(cseq, ',')) {
+ cpr_free(sipCseq);
+ return (NULL);
+ }
+
+ if (cseq) {
+ char *mycseq = cpr_strdup(cseq);
+
+ sipCseq->method = sipMethodInvalid;
+
+ if (mycseq) {
+ char *this_token = PL_strtok_r(mycseq, " ", &lasts);
+
+ if (this_token) {
+ sipCseq->number = strtoul(this_token, NULL, 10);
+
+ /* make sure the CSeq value is not > 2^^31 */
+ if (sipCseq->number >= TWO_POWER_31) {
+ cpr_free(sipCseq);
+ cpr_free(mycseq);
+ return (NULL);
+ }
+
+ this_token = PL_strtok_r(NULL, " ", &lasts);
+ if (this_token) {
+ sipCseq->method = sippmh_get_method_code(this_token);
+ }
+
+ }
+ if (!this_token) {
+ cpr_free(sipCseq);
+ cpr_free(mycseq);
+ return (NULL);
+ }
+ cpr_free(mycseq);
+ } else {
+ cpr_free(sipCseq);
+ return NULL;
+ }
+ }
+
+ return (sipCseq);
+}
+
+sipRet_t
+sippmh_add_cseq (sipMessage_t *msg, const char *method, uint32_t seq_no)
+{
+ sipRet_t retval = STATUS_FAILURE;
+
+ if (msg && method) {
+ char cseq[32];
+
+ sprintf(&cseq[0], "%lu %s", (unsigned long) seq_no, method);
+ retval = sippmh_add_text_header(msg, SIP_HEADER_CSEQ,
+ (const char *)&cseq[0]);
+ }
+
+ return (retval);
+}
+
+/*
+ * The Valid SIP URL MUST contain host field.
+ * This is not true for TEL URLs. Only user is mandatory.
+ * This check is sufficient for "From" & "To" headers
+ * from a GW standpoint. The ReqLine MUST have a "user"
+ * in the URL as the GW supports multiple users.
+ */
+boolean
+sippmh_valid_url (genUrl_t *genUrl)
+{
+ boolean retval = FALSE;
+
+ if (!genUrl) {
+ return retval;
+ }
+ if (genUrl->schema == URL_TYPE_SIP) {
+ if (genUrl->u.sipUrl->host && genUrl->u.sipUrl->host[0])
+ retval = TRUE;
+ } else if (genUrl->schema == URL_TYPE_TEL) {
+ if (genUrl->u.telUrl->user)
+ retval = TRUE;
+ }
+
+ return (retval);
+}
+
+/*
+ * The Input string is the comma separated cached Record-Route
+ * header string. This function duplicates the input string
+ * and generates a set of pointers which are pointing to a
+ * name-addr format string. These pointers are pointing within
+ * the duplicated cached header string.
+ *
+ * Loc 0 Loc 1 Loc 2
+ * Loc_start -> name-addr1, name-addr2, name-addr3
+ *
+ * Loc_start points to the duplicated input string and needs
+ * to be freed.
+ * Loc_start is preserved so that the string
+ * can be freed, when required. Thus this pointer needs to be
+ * stored only once.
+ */
+sipRecordRoute_t *
+sippmh_parse_record_route (const char *input_record_route)
+{
+ char *record_route = NULL, *start_ptr = NULL;
+ char *more_ptr;
+ sipRecordRoute_t *sipRecordRoute;
+ char *rr_other_param = NULL;
+
+ /*
+ * Record-Route = "Record-Route" ":" (name-addr *(";" rr-param))
+ * name-addr = [ display-name ] "<" addr-spec ">"
+ * addr-spec = SIP-URL | URI
+ * display-name = *token | quoted-string
+ * rr-param = generic-param
+ * generic-param = token [ = ( token | host | quoted-string ) ]
+ */
+
+ record_route = cpr_strdup(input_record_route);
+ if (record_route == NULL) {
+ return NULL;
+ }
+
+ sipRecordRoute = (sipRecordRoute_t *)
+ cpr_calloc(1, sizeof(sipRecordRoute_t));
+
+ if (sipRecordRoute == NULL) {
+ cpr_free(record_route);
+ return NULL;
+ }
+
+ start_ptr = record_route;
+
+ do {
+ sipLocation_t *sipLoc;
+
+ more_ptr = NULL;
+ parse_errno = 0;
+ sipLoc = sippmh_parse_nameaddr_or_addrspec(record_route, start_ptr,
+ FALSE, TRUE, &more_ptr);
+ if (sipLoc == NULL) {
+ if (sipRecordRoute->locations == 0) {
+ // Free record_route only if we fail the first location
+ // For the others, it will be freed when sipRecordRoute is
+ // freed
+ cpr_free(record_route);
+ }
+ sippmh_free_record_route(sipRecordRoute);
+ sipRecordRoute = NULL;
+ break;
+ }
+
+ /* Loc_start points to the duplicated input string &
+ * is stored in the zeroth location of location[].
+ * This value needs to be freed only once
+ */
+ if (sipRecordRoute->num_locations) {
+ sipLoc->loc_start = NULL;
+ }
+
+ sipRecordRoute->locations[sipRecordRoute->num_locations++] = sipLoc;
+
+ if (more_ptr == NULL || *more_ptr == 0) {
+ /* No params, means no qval and assume lowest priority */
+ break;
+ }
+
+ record_route = more_ptr;
+
+ /*
+ * At this point, either record_route is pointing to
+ * 1) ',' - Beginning of next location
+ * 3) End of string
+ * 4) Any other character is syntax error
+ */
+
+ /*
+ * This following while loop eats up all the rr_params.
+ * Note that these 'other_params' are not the same as the ones handled
+ * by parseURLParams. That routines parses other params INSIDE the < > brackets.
+ * The following code would handle unknown params outside the brackets.
+ */
+ while (record_route && *record_route == SEMI_COLON) {
+ record_route++;
+ record_route = parse_other_param(record_route, &rr_other_param);
+ /*
+ * Record route extensions are not supported. Throw away
+ * any that were just parsed.
+ */
+ if (rr_other_param != NULL) {
+ cpr_free(rr_other_param);
+ }
+ }
+
+
+ if (record_route && *record_route == COMMA) {
+ /* Another location follows */
+ *record_route++ = 0;
+ SKIP_LWS(record_route);
+ if (sipRecordRoute->num_locations == SIP_MAX_LOCATIONS) {
+ sippmh_free_record_route(sipRecordRoute);
+ sipRecordRoute = NULL;
+ CCSIP_ERR_DEBUG {
+ buginf("\nsippmh_parse_record_route: Too many location "
+ "headers in Record-Route header");
+ }
+ break;
+ }
+ } else {
+ /* Flag error if not "end of header" &
+ * any other character other than COMMA
+ */
+ if (record_route && *record_route) {
+ parse_errno = PARSE_ERR_SYNTAX;
+ CCSIP_DEBUG_ERROR(parse_errors[parse_errno],
+ "sippmh_parse_record_route", record_route);
+ sippmh_free_record_route(sipRecordRoute);
+ sipRecordRoute = NULL;
+ }
+ break;
+ }
+ } while (1);
+
+ if (sipRecordRoute) {
+ sipRecordRoute->new_flag = TRUE;
+ }
+ return sipRecordRoute;
+}
+
+/*
+ * This function is a placeholder for future expansion.
+ * If deep copy of the record route is needed from one ccb to another
+ * this function can be used.
+ */
+sipRecordRoute_t *
+sippmh_copy_record_route (sipRecordRoute_t *rr)
+{
+ //TBD
+ return NULL;
+}
+
+void
+sippmh_free_record_route (sipRecordRoute_t *rr)
+{
+ int i;
+
+ if (rr) {
+ for (i = 0; i < rr->num_locations; ++i) {
+ if (rr->locations[i]->loc_start) {
+ /* Free the entire header value that we duplicated */
+ cpr_free(rr->locations[i]->loc_start);
+ }
+ /* Free the genUrl_t struct in the sipLocation_t */
+ sippmh_genurl_free(rr->locations[i]->genUrl);
+ /* Free the sipLocation_t in Record-Route struct */
+ cpr_free(rr->locations[i]);
+ }
+ /* Free the sipContact_t struct */
+ cpr_free(rr);
+ }
+}
+
+cc_content_disposition_t *
+sippmh_parse_content_disposition (const char *input_content_disp)
+{
+ char *content_disp = NULL;
+ char *content_disp_start = NULL;
+ cc_content_disposition_t *sipContentDisp = NULL;
+ char *separator = NULL;
+ char *more_ptr = NULL;
+
+ if (input_content_disp == NULL) {
+ return NULL;
+ }
+
+ content_disp_start = content_disp = cpr_strdup(input_content_disp);
+ if (content_disp == NULL) {
+ return NULL;
+ }
+
+ /*
+ * Content-Disposition = "Content-Disposition" ":"
+ * disposition-type*(";" disposition-param)
+ * disposition-type = "render" "session" "Icon" "alert" "precondition"
+ * disp-extension-token
+ * disposition-param = "handling" "="
+ * ("optional"|"required" other-handling)
+ * generic-param
+ * other-handling = token
+ * disp-extension-token = token
+ */
+
+ sipContentDisp = (cc_content_disposition_t *)
+ cpr_calloc(1, sizeof(cc_content_disposition_t));
+ if (sipContentDisp == NULL) {
+ cpr_free(content_disp);
+ return sipContentDisp;
+ }
+
+ /* Set the field to protocol define defaults
+ * - Session & required handling
+ */
+ sipContentDisp->disposition = cc_disposition_session;
+ sipContentDisp->required_handling = TRUE;
+
+ /* first token should be disposition-type - so look for
+ * a token delimiter either a space or semicolon
+ */
+ SKIP_LWS(content_disp);
+ separator = strpbrk(content_disp, " ;");
+ if (separator) {
+ if (*separator == ';') {
+ *separator = 0;
+ more_ptr = separator + 1;
+ } else {
+ *separator = 0;
+ more_ptr = NULL;
+ }
+ } else {
+ more_ptr = NULL;
+ }
+
+ /* Parse disposition-type */
+ if (strncasecmp(content_disp, SIP_CONTENT_DISPOSITION_SESSION, 7) == 0) {
+ sipContentDisp->disposition = cc_disposition_session;
+ } else if (strncasecmp(content_disp, SIP_CONTENT_DISPOSITION_PRECONDITION, 12) == 0) {
+ sipContentDisp->disposition = cc_disposition_precondition;
+ } else if (strncasecmp(content_disp, SIP_CONTENT_DISPOSITION_ICON, 4) == 0) {
+ sipContentDisp->disposition = cc_dispostion_icon;
+ } else if (strncasecmp(content_disp, SIP_CONTENT_DISPOSITION_ALERT, 5) == 0) {
+ sipContentDisp->disposition = cc_disposition_alert;
+ } else if (strncasecmp(content_disp, SIP_CONTENT_DISPOSITION_RENDER, 6) == 0) {
+ sipContentDisp->disposition = cc_disposition_render;
+ } else {
+ sipContentDisp->disposition = cc_disposition_unknown;
+ }
+
+ if (more_ptr) {
+ /* parse disposition-param */
+ SKIP_LWS(more_ptr);
+ if (strncasecmp(more_ptr, "handling", 8) == 0) {
+ more_ptr += 8;
+ SKIP_LWS(more_ptr);
+ if (*more_ptr == '=') {
+ more_ptr++;
+ SKIP_LWS(more_ptr);
+ if (strncasecmp(more_ptr, "optional", 8) == 0) {
+ sipContentDisp->required_handling = FALSE;
+ } else if (strncasecmp(more_ptr, "required", 8) == 0) {
+ sipContentDisp->required_handling = TRUE;
+ }
+ }
+ } else {
+ /* Keyword "handling" is not found
+ * default values are already populated
+ */
+ }
+ }
+
+ cpr_free(content_disp_start);
+ return (sipContentDisp);
+}
+
+
+/***************************************************************
+ *
+ * Parses headers in Refer-To body in a char array
+ *
+ **************************************************************/
+static uint16_t
+sippmh_parse_referto_headers (char *refto_line, char **header_arr)
+{
+ uint16_t headNum = 0;
+ char *tmpHead = NULL;
+ char *lasts = NULL;
+
+ if (refto_line == NULL) {
+ return 0;
+ }
+
+ tmpHead = PL_strtok_r(refto_line, "?&", &lasts);
+ while (tmpHead != NULL) {
+ header_arr[headNum++] = tmpHead;
+ tmpHead = PL_strtok_r(NULL, "?&", &lasts);
+ }
+ return headNum;
+}
+
+
+/*******************************************************************
+ *
+ * Parser routine for headers other than sip url. Parses Replaces
+ * header, copies Accept-Contact and Proxy-Authorization headers
+ * and skips other headers.
+ *
+ * Input parameters : Array containing headers in Refer-To body,
+ * count of number of headers in Refer-To body
+ * & pointer to Refer-To structure for parsed
+ * values to be returned to calling function
+ *
+ * Returns : Zero if success, non-zero otherwise
+ *
+ *******************************************************************/
+static int
+sippmh_parse_other_headers (char **headerArr, uint16_t tokCount,
+ sipReferTo_t *refer_to)
+{
+ uint16_t count = 0;
+ char *dup_header, *mhead;
+
+ dup_header = mhead = NULL;
+
+ for (count = 1; count < tokCount; count++) {
+ dup_header = cpr_strdup(headerArr[count]);
+ if (dup_header == NULL) {
+ return (PARSE_ERR_NO_MEMORY);
+ }
+ mhead = strchr(dup_header, '=');
+ if (mhead == NULL) {
+ cpr_free(dup_header);
+ return (PARSE_ERR_SYNTAX);
+ } else {
+ *mhead = '\0';
+ }
+ if (cpr_strcasecmp(dup_header, SIP_HEADER_REPLACES) == 0) {
+
+ char *unescRepl_str = NULL;
+
+ /*
+ * copy the Replaces header so that it can be
+ * echoed back in the triggered INVITE. Also
+ * unescape any escpaed characters.
+ */
+ headerArr[count] = strstr(headerArr[count], "=");
+ if (headerArr[count] == NULL) {
+ cpr_free(dup_header);
+ return (PARSE_ERR_SYNTAX);
+ }
+ *(headerArr[count])++ = 0;
+ SKIP_LWS(headerArr[count]);
+
+ /* if header body is NULL, return syntax error */
+ if (*headerArr[count] == '\0') {
+ cpr_free(dup_header);
+ return (PARSE_ERR_SYNTAX);
+ }
+
+ unescRepl_str = (char *) cpr_malloc(strlen(headerArr[count]) + 1);
+ if (unescRepl_str == NULL) {
+ cpr_free(dup_header);
+ return (PARSE_ERR_NO_MEMORY);
+ }
+
+ sippmh_convertEscCharToChar((const char *) headerArr[count],
+ (uint8_t) strlen(headerArr[count]), unescRepl_str);
+
+ refer_to->sip_replaces_hdr = unescRepl_str;
+
+ } else if (cpr_strcasecmp(dup_header, SIP_HEADER_ACCEPT_CONTACT) == 0 ||
+ cpr_strcasecmp(dup_header, SIP_C_HEADER_ACCEPT_CONTACT) == 0) {
+ char *unescAccCont = NULL;
+
+ /*
+ * copy unescaped version of this header so
+ * that it can be echoed back in triggered INVITE
+ */
+ headerArr[count] = strstr(headerArr[count], "=");
+ if (headerArr[count] == NULL) {
+ cpr_free(dup_header);
+ return (PARSE_ERR_SYNTAX);
+ }
+ *(headerArr[count])++ = 0;
+ SKIP_LWS(headerArr[count]);
+
+ /* if header body is NULL, return syntax error */
+ if (*headerArr[count] == '\0') {
+ cpr_free(dup_header);
+ return (PARSE_ERR_SYNTAX);
+ }
+
+ unescAccCont = (char *) cpr_malloc(strlen(headerArr[count]) + 1);
+
+ if (unescAccCont == NULL) {
+ cpr_free(dup_header);
+ return (PARSE_ERR_NO_MEMORY);
+ }
+
+ sippmh_convertEscCharToChar((const char *) headerArr[count],
+ (uint8_t) strlen(headerArr[count]),
+ unescAccCont);
+
+ refer_to->sip_acc_cont = unescAccCont;
+
+ } else if (cpr_strcasecmp(dup_header, SIP_HEADER_PROXY_AUTH) == 0) {
+
+ char *unescPrAuth = NULL;
+
+ /*
+ * copy this header to be echoed back in triggered INVITE
+ * unescape any escaped chars before storing
+ */
+
+ headerArr[count] = strstr(headerArr[count], "=");
+ if (headerArr[count] == NULL) {
+ cpr_free(dup_header);
+ return (PARSE_ERR_SYNTAX);
+ }
+ *(headerArr[count])++ = 0;
+ SKIP_LWS(headerArr[count]);
+
+ /* if header body is NULL, return syntax error */
+ if (*headerArr[count] == '\0') {
+ cpr_free(dup_header);
+ return (PARSE_ERR_SYNTAX);
+ }
+
+ unescPrAuth = (char *) cpr_malloc(strlen(headerArr[count]) + 1);
+ if (unescPrAuth == NULL) {
+ cpr_free(dup_header);
+ return (PARSE_ERR_NO_MEMORY);
+ }
+
+ sippmh_convertEscCharToChar((const char *) headerArr[count],
+ (uint8_t) strlen(headerArr[count]),
+ unescPrAuth);
+
+ refer_to->sip_proxy_auth = unescPrAuth;
+ }
+ cpr_free(dup_header);
+ }
+
+ return 0; /* SUCCESS */
+}
+
+/**************************************************************
+ * Parser routine for Refer-To header. Refer-To may contain
+ * other headers like:
+ * a) Replaces
+ * b) Accept-Contact
+ * c) Proxy-Authorization
+ * will skip headers, we do not understand; parse Replaces;
+ * and copy Accept-Contact and Proxy-Authorization headers
+ * to be echoed back in the triggered INVITE.
+ *
+ * Input parameters : Refer-To string to be parsed.
+ * Returns : Pointer to Refer-To structure with parsed values
+ * if successful, NULL otherwise.
+ *
+ **************************************************************/
+sipReferTo_t *
+sippmh_parse_refer_to (char *input_refer_to)
+{
+ char *refer_to_headers[MAX_REFER_TO_HEADER_CONTENTS];
+ char *left_bracket, *right_bracket, *msg_body, *refer_to_val;
+ sipReferTo_t *sipReferTo = NULL;
+ genUrl_t *refUrl = NULL;
+ uint16_t tokens = 0;
+ int ref_header_count = 0;
+
+ left_bracket = right_bracket = msg_body = refer_to_val = NULL;
+
+ if (input_refer_to == NULL) {
+ return NULL;
+ }
+
+ /*
+ * Refer-To = ("Refer-To" | "r") ":" URL
+ */
+
+ /* make a copy of refer-to to work with */
+ refer_to_val = cpr_strdup(input_refer_to);
+ if (refer_to_val == NULL) {
+ return NULL;
+ }
+
+ sipReferTo = (sipReferTo_t *) cpr_calloc(1, sizeof(sipReferTo_t));
+ if (sipReferTo == NULL) {
+ cpr_free(refer_to_val);
+ return NULL;
+ }
+ sipReferTo->ref_to_start = refer_to_val;
+
+ /* Initialize */
+ for (ref_header_count = 0;
+ ref_header_count < MAX_REFER_TO_HEADER_CONTENTS;
+ ref_header_count++) {
+ refer_to_headers[ref_header_count] = NULL;
+ }
+
+ /* first get rid of opening and closing braces, if there */
+ left_bracket = strpbrk(refer_to_val, ",<");
+ if (left_bracket) {
+
+ /* This is a name-addr form */
+ left_bracket++;
+ right_bracket = strchr(left_bracket, '>');
+ if (right_bracket) {
+ *right_bracket++ = 0;
+ }
+ msg_body = left_bracket;
+ } else {
+
+ /* This is addr-spec format */
+ msg_body = refer_to_val;
+ SKIP_LWS(msg_body);
+ }
+
+ /* parse headers separated by ? or & in an array of char pointers */
+ tokens = sippmh_parse_referto_headers(msg_body, refer_to_headers);
+
+ if (tokens == 0) {
+ CCSIP_ERR_DEBUG {
+ buginf("\nEmpty Refer-To header\n");
+ }
+ sippmh_free_refer_to(sipReferTo);
+ return NULL;
+ }
+
+ /* First parse url portion, this should be the first element
+ * of the headers array
+ */
+ refUrl = sippmh_parse_url(refer_to_headers[0], FALSE);
+ if (refUrl == NULL) {
+ sippmh_free_refer_to(sipReferTo);
+ return NULL;
+ }
+ sipReferTo->targetUrl = refUrl;
+
+ /* next parse rest of the headers, skip ones we don't understand */
+ parse_errno = sippmh_parse_other_headers(refer_to_headers, tokens,
+ sipReferTo);
+
+ if (parse_errno != 0) {
+ CCSIP_ERR_DEBUG {
+ buginf("\nError while parsing other Refer-To header\n");
+ }
+ sippmh_free_refer_to(sipReferTo);
+ return NULL;
+ }
+
+ return (sipReferTo);
+}
+
+
+
+
+
+/*****************************************************************
+ *
+ * Parser routine for Replaces header. Replaces header has
+ * call-id, to and from tags and signature scheme as parameters.
+ * The parser parses and stores call-id and tags in the Replaces
+ * structure and copies the signature scheme to be echoed back
+ * in the triggered INVITE for attended transfer.
+ *
+ * Input parameters : Replaces string to be parsed,
+ * boolean flag indicating whether the input
+ * string shall be duplicated or not.
+ *
+ * Returns : pointer to Replaces structure with parsed values
+ * if successful, NULL otherwise.
+ *
+ *****************************************************************/
+sipReplaces_t *
+sippmh_parse_replaces (char *input_repl, boolean dup_flag)
+{
+
+ char *repl_str, *this_tok, *tagVal, *sign, *callid;
+ sipReplaces_t *repcs = NULL;
+ char *lasts = NULL;
+
+ repl_str = this_tok = tagVal = sign = NULL;
+
+ if (input_repl == NULL) {
+ return NULL;
+ }
+
+
+ /*
+ * Replaces = "Replaces" ":" 1#replaces-values
+ * replaces-values = callid *( ";" replaces-param )
+ * callid = token [ "@" token ]
+ * replaces-param = to-tag | from-tag | rep-signature
+ * | extension-param
+ * to-tag = "to-tag=" UUID
+ * from-tag = "from-tag=" UUID
+ * rep-signature = signature-scheme *( ";" sig-scheme-params)
+ * signature-scheme = "scheme" "=" token
+ * sig-scheme-params = token "=" ( token | quoted string )
+ */
+
+ repcs = (sipReplaces_t *) cpr_calloc(1, sizeof(sipReplaces_t));
+ if (repcs == NULL) {
+ return NULL;
+ }
+
+ if (dup_flag) {
+ repl_str = cpr_strdup(input_repl);
+ if (!repl_str) {
+ cpr_free(repcs);
+ return NULL;
+ }
+ repcs->str_start = repl_str;
+ } else {
+ repl_str = input_repl;
+ }
+
+
+ /* if Replaces string has signature scheme parameter,
+ * make a copy of the input string for parsing entire signature
+ * parameter
+ */
+
+ if ((sign = strstr(repl_str, SIGNATURE_SCHEME)) != NULL) {
+
+ /*
+ * if to or from tag follows signature params, remove
+ * them from this string
+ */
+ char *sign_str, *tag_str;
+
+ sign_str = tag_str = NULL;
+
+ sign_str = cpr_strdup(sign);
+ if (sign_str == NULL) {
+ sippmh_free_replaces(repcs);
+ return NULL;
+ }
+ if ((tag_str = strstr(sign_str, ";to-tag")) ||
+ (tag_str = strstr(sign_str, ";from-tag"))) {
+ *tag_str = '\0';
+ } else {
+ /* terminate input string at signature param */
+ *sign = '\0';
+ }
+ (repcs->signature_scheme) = sign_str;
+ }
+
+
+ this_tok = PL_strtok_r(input_repl, ";", &lasts);
+ while (this_tok != NULL) {
+ if (strncasecmp(this_tok, TO_TAG, 6) == 0) {
+ if (repcs->toTag != NULL) {
+ sippmh_free_replaces(repcs);
+ return NULL; /* ERROR - more than 1 TO tag */
+ } else {
+ tagVal = strchr(this_tok, '=');
+ if (tagVal) {
+ tagVal++;
+ SKIP_LWS(tagVal);
+ repcs->toTag = tagVal;
+ } else {
+ sippmh_free_replaces(repcs);
+ return NULL; /* ERROR */
+ }
+ }
+ } else if (strncasecmp(this_tok, FROM_TAG, 8) == 0) {
+ if (repcs->fromTag != NULL) {
+ sippmh_free_replaces(repcs);
+ return NULL; /* ERROR - more than 1 FROM tag */
+ } else {
+ tagVal = strchr(this_tok, '=');
+ if (tagVal) {
+ tagVal++;
+ SKIP_LWS(tagVal);
+ repcs->fromTag = tagVal;
+ } else {
+ sippmh_free_replaces(repcs);
+ return NULL; /* ERROR */
+ }
+ }
+ } else if (strncasecmp(this_tok, SIP_HEADER_REPLACES,
+ sizeof(SIP_HEADER_REPLACES) - 1) == 0) {
+ /* only other allowable field should be callid */
+ callid = strchr(this_tok, '=');
+ if (callid) {
+ char *sp_token;
+
+ callid++;
+ SKIP_LWS(callid);
+ repcs->callid = callid;
+ /* remove trailing spaces */
+ sp_token = strchr(repcs->callid, ' ');
+ if (sp_token == NULL) {
+ sp_token = strchr(repcs->callid, '\t');
+ }
+ if (sp_token) {
+ *sp_token = 0;
+ }
+ } else {
+ sippmh_free_replaces(repcs);
+ return NULL; /* ERROR */
+ }
+ } else {
+ sippmh_free_replaces(repcs);
+ return NULL;
+ }
+ this_tok = PL_strtok_r(NULL, ";", &lasts);
+ }
+ /* check for errors */
+ if ((repcs->callid == NULL) ||
+ (repcs->toTag == NULL) ||
+ (repcs->fromTag == NULL)) {
+ sippmh_free_replaces(repcs);
+ return NULL;
+ }
+
+ return repcs; /* SUCCESS */
+}
+
+
+/*
+ * Converts a hex character (0-9, a-f, or A-F) into its integer
+ * equivalent value.
+ * ex.) '9' --> 9
+ * 'a' --> 10
+ * 'F' --> 15
+ */
+static int
+sippmh_htoi (const char inputChar)
+{
+ char inputValue[2];
+ long strtol_result;
+ char *strtol_end;
+
+ inputValue[0] = inputChar;
+ inputValue[1] = '\0';
+
+ errno = 0;
+ strtol_result = strtol(inputValue, &strtol_end, 16);
+
+ if (errno || inputValue == strtol_end) {
+ return 0;
+ } else {
+ return (int) strtol_result;
+ }
+}
+
+/*
+ * This function(similar to memchr()) works with both strings and array of characters.
+ * Returns the pointer to the matched character, if any; NULL otherwise. To include memchr.c
+ * in the phone library takes 1K of extra size and hence wrote this.
+ */
+static void *
+char_lookup (const void *src, unsigned char c, int n)
+{
+ const unsigned char *mem = (unsigned char *) src;
+
+ while (n--) {
+ if (*mem == c) {
+ return ((void *) mem);
+ }
+ mem++;
+ }
+
+ return NULL;
+}
+
+
+/* List of characters that can exist in user part of URL/URI without escaping */
+#define userUnResCharListSize 17
+static char userUnResCharList[userUnResCharListSize] =
+{
+ SEMI_COLON, EQUAL_SIGN, TILDA, STAR, UNDERSCORE, PLUS,
+ SINGLE_QUOTE, LEFT_PARENTHESIS, RIGHT_PARENTHESIS, DOLLAR_SIGN,
+ FORWARD_SLASH, DOT, DASH, EXCLAMATION, AMPERSAND, COMMA, QUESTION_MARK
+};
+
+
+/*
+ * This utility function converts selected characters in a string to escaped characters,
+ * per RFC2396. Escape format = %hexhex (hexhex - hex value of ASCII character)
+ * ex. 'abc@123' gets converted to "abc%40123" if '@' exists in escapable character list
+ *
+ * inptStr = ptr to string of chars
+ * inputStrLen = num of characters that you want to convert
+ * excludeCharTbl = lookup table/string of characters that need not be escaped
+ * excludeCharTblSize = number of characters in the table/string that need not be escaped
+ * null_terminate = TRUE if '\0' is required to be added at end
+ * FALSE if not required.
+ * outputStr = ptr to pre-allocated memory for storing the
+ * converted string
+ * outputStrSize = the size limit of the outputStr buffer
+ *
+ * returns the new size of the output string
+ * Converted string is stored in outputStr
+ * (contents = converted str)
+ */
+static size_t
+sippmh_escapeChars_util (const char *inputStr, size_t inputStrLen,
+ char *excludeCharTbl, size_t excludeCharTblSize,
+ char *outputStr, size_t outputStrSize,
+ boolean null_terminate)
+{
+ size_t char_cnt = 0;
+ char *nextOutputChar;
+ int additional_byte = null_terminate ? 1 : 0;
+ size_t copy_count = 0;
+
+ nextOutputChar = outputStr;
+
+ while (char_cnt++ < inputStrLen) {
+ /* Check for characters that doesn't need to be escaped */
+ if (((*inputStr) >= 'A' && (*inputStr) <= 'Z') ||
+ ((*inputStr) >= 'a' && (*inputStr) <= 'z') ||
+ ((*inputStr) >= '0' && (*inputStr) <= '9') ||
+ (char_lookup(excludeCharTbl, (unsigned char) *inputStr,
+ excludeCharTblSize) != NULL)) {
+ if (outputStrSize < (copy_count + 1 + additional_byte)) {
+ break;
+ }
+ *nextOutputChar++ = *inputStr++;
+ copy_count++;
+ } else { // Characters that need escaping
+ if (outputStrSize < (copy_count + 3 + additional_byte)) {
+ break;
+ }
+ /* Copy %hh to output string */
+ sprintf(nextOutputChar, "%c%x", '%', *inputStr++);
+ nextOutputChar = nextOutputChar + 3;
+ copy_count += 3;
+ }
+
+ }
+
+ if (null_terminate) {
+ copy_count++;
+ *nextOutputChar = '\0';
+ }
+ return (copy_count);
+}
+
+/*
+ * This function converts selected characters in a string to escaped characters,
+ * per RFC2396. Escape format = %hexhex (hexhex - hex value of ASCII character)
+ * ex. 'abc@123' gets converted to "abc%40123" if '@' exists in escapable character list
+ *
+ * inptStr = ptr to string of chars
+ * inputStrLen = num of characters that you want to convert
+ * outputStr = ptr to pre-allocated memory for storing the
+ * converted string
+ * outputStrSize = the size limit of the outputStr buffer
+ * null_terminate = TRUE if '\0' is required to be added at end
+ * FALSE if not required.
+ * returns the new size of the output string
+ *
+ * Converted string is stored in outputStr
+ * (contents = converted str)
+ */
+size_t
+sippmh_convertURLCharToEscChar (const char *inputStr, size_t inputStrLen,
+ char *outputStr, size_t outputStrSize,
+ boolean null_terminate)
+{
+ return (sippmh_escapeChars_util(inputStr, inputStrLen,
+ userUnResCharList, userUnResCharListSize,
+ outputStr, outputStrSize, null_terminate));
+}
+/*
+ * This function converts any '\' or '"' character in a quoted string to escaped characters,
+ * per RFC3261. Escape format = %hexhex (hexhex - hex value of ASCII character)
+ * ex. 'abc\\' gets converted to "abc%5c%5c" if '\' exists in escapable character list
+ *
+ * inptStr = ptr to string of chars
+ * inputStrLen = num of characters that you want to convert
+ * outputStr = ptr to pre-allocated memory for storing the
+ * converted string
+ * outputStrSize = the size limit of the outputStr buffer
+ * null_terminate = TRUE if '\0' is required to be added at end
+ * FALSE if not required.
+ * returns the new size of the output string
+ *
+ * Converted string is stored in outputStr
+ * (contents = converted str)
+ */
+size_t
+sippmh_converQuotedStrToEscStr(const char *inputStr, size_t inputStrLen,
+ char *outputStr, size_t outputStrSize,
+ boolean null_terminate)
+{
+ size_t char_cnt = 0;
+ char *nextOutputChar;
+ int additional_byte = null_terminate ? 1 : 0;
+ size_t copy_count = 0;
+
+ nextOutputChar = outputStr;
+
+ while (char_cnt++ < inputStrLen) {
+ /* Check for characters that need to be escaped */
+ if( ((*inputStr) == ESCAPE_CHAR) || ((*inputStr) == DOUBLE_QUOTE))
+ {
+ // Characters that need escaping
+ if (outputStrSize < (copy_count + 3 + additional_byte)) {
+ break;
+ }
+ /* Copy %hh to output string */
+ sprintf(nextOutputChar, "%c%02x", '%', *inputStr++);
+ nextOutputChar = nextOutputChar + 3;
+ copy_count += 3;
+ }
+ else {
+ if (outputStrSize < (copy_count + 1 + additional_byte)) {
+ break;
+ }
+ *nextOutputChar++ = *inputStr++;
+ copy_count++;
+ }
+
+ }
+
+ if (null_terminate) {
+ copy_count++;
+ *nextOutputChar = '\0';
+ }
+
+ return (copy_count);
+}
+
+/*
+ * This function converts all Escaped characters in a string
+ * to their non-escaped format according to RFC2396.
+ * Escape format = %hh (%)
+ * ex. 'abc%40123' gets converted to "abc@123"
+ *
+ * inptStr = ptr to string of chars
+ * inputStrLen = num of characters that you want to convert
+ * outputStr = ptr to pre-allocated memory for storing the
+ * converted string
+ *
+ * Converted string is stored in outputStr
+ * (contents = converted str)
+ * (contents = '\0' if no input string)
+ */
+void
+sippmh_convertEscCharToChar (const char *inputStr, size_t inputStrLen,
+ char *outputStr)
+{
+ size_t char_cnt = 0;
+ char *nextOutputChar;
+ int value;
+ boolean esc_char_found = FALSE;
+
+ *outputStr = '\0';
+ nextOutputChar = outputStr;
+
+ while (char_cnt < inputStrLen) {
+ if (*inputStr == PERCENT) {
+ /* Skip ESC syntax */
+ inputStr++;
+ char_cnt++;
+ esc_char_found = TRUE;
+ }
+
+ /* Copy character to output str */
+ if (esc_char_found) {
+
+ /* Convert 1st and 2nd hex chars to int */
+ value = sippmh_htoi(*inputStr) * 16;
+ inputStr++;
+ char_cnt++;
+ value += sippmh_htoi(*inputStr);
+ sprintf(nextOutputChar, "%c", toascii(value));
+
+ inputStr++;
+ char_cnt++;
+ esc_char_found = FALSE;
+
+ } else {
+ *nextOutputChar = *inputStr;
+ inputStr++;
+ char_cnt++;
+ }
+
+ nextOutputChar++;
+ }
+
+ *nextOutputChar = '\0';
+}
+
+
+void
+sippmh_free_replaces (sipReplaces_t *repl)
+{
+
+ if (repl == NULL) {
+ return;
+ }
+ if (repl->str_start) {
+ cpr_free(repl->str_start);
+ }
+ if (repl->signature_scheme) {
+ cpr_free(repl->signature_scheme);
+ }
+ cpr_free(repl);
+}
+
+
+void
+sippmh_free_refer_to (sipReferTo_t *ref_to)
+{
+
+ if (ref_to == NULL) {
+ return;
+ }
+ if (ref_to->ref_to_start) {
+ cpr_free(ref_to->ref_to_start);
+ }
+ if (ref_to->sip_replaces_hdr) {
+ cpr_free(ref_to->sip_replaces_hdr);
+ }
+ if (ref_to->sip_acc_cont) {
+ cpr_free(ref_to->sip_acc_cont);
+ }
+ if (ref_to->sip_proxy_auth) {
+ cpr_free(ref_to->sip_proxy_auth);
+ }
+ if (ref_to->targetUrl) {
+ sippmh_genurl_free(ref_to->targetUrl);
+ }
+ cpr_free(ref_to);
+
+}
+
+
+static void
+sippmh_free_remote_party_id (sipRemotePartyId_t *remote_party_id)
+{
+ if (remote_party_id) {
+ if (remote_party_id->loc) {
+ sippmh_free_location(remote_party_id->loc);
+ }
+ cpr_free(remote_party_id);
+ }
+}
+
+
+void
+sippmh_free_remote_party_id_info (sipRemotePartyIdInfo_t *rpid_info)
+{
+ uint32_t i;
+
+ if (rpid_info) {
+ if (rpid_info->num_rpid > 0) {
+ for (i = 0; i < rpid_info->num_rpid; i++) {
+ sippmh_free_remote_party_id(rpid_info->rpid[i]);
+ rpid_info->rpid[i] = NULL;
+ }
+ }
+ cpr_free(rpid_info);
+ }
+}
+
+void
+sippmh_free_diversion_info (sipDiversionInfo_t *div_info)
+{
+ if (div_info) {
+ if (div_info->orig_called_name) {
+ strlib_free(div_info->orig_called_name);
+ }
+ if (div_info->orig_called_number) {
+ strlib_free(div_info->orig_called_number);
+ }
+ if (div_info->last_redirect_name) {
+ strlib_free(div_info->last_redirect_name);
+ }
+ if (div_info->last_redirect_number) {
+ strlib_free(div_info->last_redirect_number);
+ }
+ cpr_free(div_info);
+ }
+
+}
+
+static boolean
+sippmh_parse_remote_party_id_params (char *params,
+ sipRemotePartyId_t *remote_party_id)
+{
+ boolean params_good;
+ int param_len;
+ char *param_name;
+
+ if ((params == NULL) || (remote_party_id == NULL)) {
+ return FALSE;
+ }
+
+ while (1) {
+ params_good = FALSE;
+
+ while (*params == ';') {
+ params++;
+ }
+
+ param_name = params;
+ SKIP_SIP_TOKEN(params);
+ param_len = params - param_name;
+ if (param_len == 0) {
+ return FALSE;
+ }
+
+ /* Parse screen parameter */
+ /* If there are multiple screen parameters, "no" takes precedence */
+ if ((param_len == RPID_SCREEN_LEN) &&
+ (strncasecmp(param_name, RPID_SCREEN, RPID_SCREEN_LEN) == 0) &&
+ (!remote_party_id->screen ||
+ cpr_strcasecmp(remote_party_id->screen, "no"))) {
+ params = parse_generic_param(params, &remote_party_id->screen);
+ if (params == NULL) {
+ return FALSE;
+ } else {
+ params_good = TRUE;
+ }
+
+ /* Parse party-type parameter */
+ } else if ((param_len == RPID_PARTY_TYPE_LEN) &&
+ (strncasecmp(param_name, RPID_PARTY_TYPE,
+ RPID_PARTY_TYPE_LEN) == 0)) {
+ params = parse_generic_param(params, &remote_party_id->party_type);
+ if (params == NULL) {
+ return FALSE;
+ } else {
+ params_good = TRUE;
+ }
+
+ /* Parse id-type parameter */
+ } else if ((param_len == RPID_ID_TYPE_LEN) &&
+ (strncasecmp(param_name, RPID_ID_TYPE,
+ RPID_ID_TYPE_LEN) == 0)) {
+ params = parse_generic_param(params, &remote_party_id->id_type);
+ if (params == NULL) {
+ return FALSE;
+ } else {
+ params_good = TRUE;
+ }
+
+ /* Parse privacy parameter */
+ } else if ((param_len == RPID_PRIVACY_LEN) &&
+ (strncasecmp(param_name, RPID_PRIVACY,
+ RPID_PRIVACY_LEN) == 0)) {
+ params = parse_generic_param(params, &remote_party_id->privacy);
+ if (params == NULL) {
+ return FALSE;
+ } else {
+ params_good = TRUE;
+ }
+
+ /* Parse np parameter */
+ } else if ((param_len == RPID_NP_LEN) &&
+ (strncasecmp(param_name, RPID_NP, RPID_NP_LEN) == 0)) {
+ params = parse_generic_param(params, &remote_party_id->np);
+ if (params == NULL) {
+ return FALSE;
+ } else {
+ params_good = TRUE;
+ }
+ }
+
+ SKIP_LWS(params);
+ if (*params == SEMI_COLON) {
+ /* More parameters follow */
+ *params++ = '\0';
+ SKIP_LWS(params);
+ } else {
+ break;
+ }
+ }
+
+ return params_good;
+}
+
+sipRemotePartyId_t *
+sippmh_parse_remote_party_id (const char *input_remote_party_id)
+{
+ /* static const char fname[] = "sippmh_parse_remote_party_id"; */
+ char *more_ptr;
+ sipRemotePartyId_t *remote_party_id;
+ char *remote_party_id_str;
+
+ /*
+ * Remote-Party-ID = "Remote-Party-ID" ":" [display-name]
+ * "<" addr-spec ">" *(";" rpi-token)
+ * rpi-token = rpi-screen | rpi-pty-type |
+ * rpi-id-type | rpi-privacy | rpi-np |
+ * other-rpi-token
+ * rpi-screen = "screen" "=" ("no" | "yes")
+ * rpi-pty-type = "party" "=" ("calling" | "called" | token)
+ * rpi-id-type = "id-type" "=" ("subscriber" | "user" | "alias" |
+ * "return" | "term" | token)
+ * rpi-privacy = "privacy" = 1#(
+ * ("full" | "name" | "uri" | "off" | token)
+ * ["-" ("network" | token) ] )
+ * rpi-np = "np" "=" ("ordinary" | "residential" | "business" |
+ * "priority" | "hotel" | "failure" | "hospital" |
+ * "prison" | "police" | "test" | "payphone" |
+ * "coin" | "payphone-public" | "payphone-private" |
+ * "coinless" | "restrict" | "coin-restrict" |
+ * "coinless-restrict" | "reserved" | "operator" |
+ * "trans-freephone" | "isdn-res" | "isdn-bus" |
+ * "unknown" | "emergency" | token )
+ * other-rpi-token = ["-"] token ["=" (token | quoted-string)]
+ */
+
+ remote_party_id = (sipRemotePartyId_t *)
+ cpr_calloc(1, sizeof(sipRemotePartyId_t));
+ if (remote_party_id == NULL) {
+ return NULL;
+ }
+
+ /* Duplicate the string and work with it -
+ * This duplicate string is stored in the location structure
+ * pointed to by remote_party_id->loc and freed when the that
+ * structure is freed. Note that this pointer is *not* dup'ed
+ * in the parse_nameaddr_or_addrspec structure
+ */
+ remote_party_id_str = cpr_strdup(input_remote_party_id);
+
+ if (remote_party_id_str == NULL) {
+ sippmh_free_remote_party_id(remote_party_id);
+ remote_party_id = NULL;
+ more_ptr = NULL;
+ } else {
+ remote_party_id->loc =
+ sippmh_parse_nameaddr_or_addrspec(remote_party_id_str,
+ remote_party_id_str, FALSE,
+ FALSE, &more_ptr);
+
+ if (remote_party_id->loc == NULL) {
+ cpr_free(remote_party_id_str);
+ sippmh_free_remote_party_id(remote_party_id);
+ remote_party_id = NULL;
+ more_ptr = NULL;
+ }
+ }
+
+ if (more_ptr == NULL || *more_ptr == 0) {
+ /* No params. Use defaults of:
+ * party=calling, screen=no, id-type=subscriber,
+ * privacy=off, np=0 (ordinary)
+ */
+ } else {
+ (void) sippmh_parse_remote_party_id_params(more_ptr, remote_party_id);
+ }
+
+ return remote_party_id;
+}
+
+
+char *
+sippmh_generate_authorization (sip_author_t *sip_author)
+{
+ char *buffer;
+
+ /*
+ * This routine takes a sip_author_t struct and generates an Authorization
+ * header or a Proxy-Authorization header. Since this routine generates
+ * a header for Authorization or Proxy-Authorization, the header will
+ * start with "Digest" or "Basic". The user should use sstrncat to
+ * add "Proxy Authorization: " or "Authorization: " depending which is
+ * needed.
+ */
+ if (!sip_author) {
+ return NULL;
+ }
+ buffer = (char *) cpr_malloc(MAX_SIP_HEADER_LENGTH);
+ if (!buffer) {
+ return NULL;
+ }
+
+ if (sip_author->scheme == SIP_DIGEST) {
+ snprintf(buffer, MAX_SIP_HEADER_LENGTH,
+ "%s %s=\"%s\",%s=\"%s\",%s=\"%s\",%s=\"%s\",%s=\"%s\"",
+ AUTHENTICATION_DIGEST,
+ AUTHENTICATION_USERNAME, sip_author->d_username,
+ AUTHENTICATION_REALM, sip_author->realm,
+ AUTHENTICATION_URI, sip_author->unparsed_uri,
+ AUTHENTICATION_RESPONSE, sip_author->response,
+ AUTHENTICATION_NONCE, sip_author->nonce);
+
+ /*
+ * The header must have username, realm, uri, response, and nonce.
+ * All other parameters are optional, so check if they exist and
+ * add them on to the buffer if they do.
+ */
+
+ if (sip_author->opaque) {
+ char *buffer2;
+
+ buffer2 = (char *) cpr_malloc(MAX_URI_LENGTH);
+ if (!buffer2) {
+ cpr_free(buffer);
+ return NULL;
+ }
+ snprintf(buffer2, MAX_URI_LENGTH, ",%s=\"%s\"",
+ AUTHENTICATION_OPAQUE, sip_author->opaque);
+ sstrncat(buffer, buffer2, MAX_SIP_HEADER_LENGTH - strlen(buffer));
+ cpr_free(buffer2);
+ }
+ if (sip_author->cnonce) {
+ char *buffer3;
+
+ buffer3 = (char *) cpr_malloc(MAX_URI_LENGTH);
+ if (!buffer3) {
+ cpr_free(buffer);
+ return NULL;
+ }
+ snprintf(buffer3, MAX_URI_LENGTH,
+ ",cnonce=\"%s\"", sip_author->cnonce);
+ sstrncat(buffer, buffer3, MAX_SIP_HEADER_LENGTH - strlen(buffer));
+ cpr_free(buffer3);
+ }
+ if (sip_author->qop) {
+ char *buffer4;
+
+ buffer4 = (char *) cpr_malloc(MAX_URI_LENGTH);
+ if (!buffer4) {
+ cpr_free(buffer);
+ return NULL;
+ }
+ snprintf(buffer4, MAX_URI_LENGTH, ",qop=%s", sip_author->qop);
+ sstrncat(buffer, buffer4, MAX_SIP_HEADER_LENGTH - strlen(buffer));
+ cpr_free(buffer4);
+ }
+ if (sip_author->nc_count) {
+ char *buffer5;
+
+ buffer5 = (char *) cpr_malloc(MAX_URI_LENGTH);
+ if (!buffer5) {
+ cpr_free(buffer);
+ return NULL;
+ }
+ snprintf(buffer5, MAX_URI_LENGTH, ",nc=%s", sip_author->nc_count);
+ sstrncat(buffer, buffer5, MAX_SIP_HEADER_LENGTH - strlen(buffer));
+ cpr_free(buffer5);
+ }
+ if (sip_author->algorithm) {
+ char *buffer6;
+
+ buffer6 = (char *) cpr_malloc(MAX_URI_LENGTH);
+ if (!buffer6) {
+ cpr_free(buffer);
+ return NULL;
+ }
+ snprintf(buffer6, MAX_URI_LENGTH,
+ ",%s=%s", AUTHENTICATION_ALGORITHM, sip_author->algorithm);
+ sstrncat(buffer, buffer6, MAX_SIP_HEADER_LENGTH - strlen(buffer));
+ cpr_free(buffer6);
+ }
+ } else {
+ sprintf(buffer, "%s %s", AUTHENTICATION_BASIC, sip_author->user_pass);
+ }
+ return buffer;
+}
+
+void
+sippmh_free_authen (sip_authen_t *sip_authen)
+{
+ if (sip_authen) {
+ cpr_free(sip_authen->str_start);
+ cpr_free(sip_authen);
+ }
+}
+
+static boolean
+sippmh_validate_authenticate (sip_authen_t *sip_authen)
+{
+ if (sip_authen) {
+ if ((sip_authen->realm != NULL) && (sip_authen->nonce != NULL)) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ }
+ return FALSE;
+}
+
+/* routine used to parse WWW-Authenticate and Proxy-Authenticate headers */
+
+sip_authen_t *
+sippmh_parse_authenticate (const char *input_char)
+{
+ sip_authen_t *sip_authen;
+ char *input;
+ boolean good_params;
+ boolean qop_found = FALSE;
+ char *trash;
+
+/*
+ * Basic:
+ * "WWW-Authenticate" ":" 1#challenge
+ * challenge = "Basic" realm
+ *******************************************************
+ * Digest:
+ * "Digest" digest-challenge
+ * digest-challenge = 1#( realm | [ domain ] | nonce |
+ * [ opaque ] |[ stale ] | [ algorithm ] |
+ * [ qop-options ] | [auth-param] )
+ *
+ * domain = "domain" "=" <"> URI ( 1*SP URI ) <">
+ * URI = absoluteURI | abs_path
+ * opaque = "opaque" "=" quoted-string
+ * stale = "stale" "=" ( "true" | "false" )
+ * algorithm = "algorithm" "=" ( "MD5" | "MD5-sess" |
+ * token )
+ * qop-options = "qop" "=" <"> 1#qop-value <">
+ * qop-value = "auth" | "auth-int" | token
+ */
+
+ if (!input_char) {
+ return NULL;
+ }
+
+ input = cpr_strdup(input_char);
+ if (!input) {
+ return NULL;
+ }
+
+ sip_authen = (sip_authen_t *) cpr_calloc(1, sizeof(sip_authen_t));
+ if (!sip_authen) {
+ cpr_free(input);
+ return NULL;
+ }
+
+ sip_authen->str_start = input;
+ SKIP_WHITE_SPACE(input);
+
+ /* now pointing at Basic, pgp or Digest */
+
+ if (strncasecmp(input, AUTHENTICATION_BASIC, 5) == 0) {
+ sip_authen->scheme = SIP_BASIC;
+ input += 5;
+ *input = 0;
+ input++;
+ SKIP_WHITE_SPACE(input);
+ if (strncasecmp(input, AUTHENTICATION_REALM, 5) == 0) {
+ input += 5;
+ SKIP_WHITE_SPACE(input);
+ if (*input == '=') {
+ input++;
+ } else {
+ sippmh_free_authen(sip_authen);
+ CCSIP_ERR_DEBUG {
+ buginf("\n%s", get_debug_string(DEBUG_PMH_INCORRECT_SYNTAX));
+ }
+ return NULL;
+ }
+ SKIP_WHITE_SPACE(input);
+ sip_authen->realm = input;
+ return sip_authen;
+ }
+ sip_authen->user_pass = input; /* encoded base 64 */
+ return sip_authen;
+
+ } else if (strncasecmp(input, AUTHENTICATION_DIGEST, 6) == 0) {
+ sip_authen->scheme = SIP_DIGEST;
+ input += 6;
+ *input = 0;
+ input++;
+ SKIP_WHITE_SPACE(input);
+ } else {
+ sippmh_free_authen(sip_authen);
+ CCSIP_ERR_DEBUG {
+ buginf("\n%s", get_debug_string(DEBUG_PMH_INVALID_SCHEME));
+ }
+ return NULL;
+ }
+
+ /* pointing at Digest-challenge */
+
+ /* if algorithm is not in string set it to md5 */
+
+ sip_authen->algorithm = "md5";
+
+ /* loop through string until all fields have been handled */
+
+ while (input) {
+ char **ptr = NULL;
+
+ if (strncasecmp(input, AUTHENTICATION_DOMAIN, 6) == 0) {
+ input += 6;
+ ptr = &(sip_authen->unparsed_domain);
+ } else if (strncasecmp(input, AUTHENTICATION_ALGORITHM, 9) == 0) {
+ input += 9;
+ ptr = &(sip_authen->algorithm);
+ } else if (strncasecmp(input, AUTHENTICATION_OPAQUE, 6) == 0) {
+ input += 6;
+ ptr = &(sip_authen->opaque);
+ } else if (strncasecmp(input, "stale", 5) == 0) {
+ input += 5;
+ ptr = &(sip_authen->stale);
+ } else if (strncasecmp(input, AUTHENTICATION_REALM, 5) == 0) {
+ input += 5;
+ ptr = &(sip_authen->realm);
+ } else if (strncasecmp(input, AUTHENTICATION_NONCE, 5) == 0) {
+ input += 5;
+ ptr = &(sip_authen->nonce);
+ } else if (strncasecmp(input, "qop", 3) == 0) {
+ input += 3;
+ ptr = &(sip_authen->qop);
+ qop_found = TRUE;
+ } else {
+ /*
+ * Ignore unrecognized parameters.
+ */
+ ptr = &trash;
+ input = strchr(input, EQUAL_SIGN);
+ if (input == NULL) {
+ sippmh_free_authen(sip_authen);
+ CCSIP_ERR_DEBUG {
+ buginf("\n%s", get_debug_string(DEBUG_PMH_INVALID_FIELD_VALUE));
+ }
+ return NULL;
+ }
+ }
+ SKIP_WHITE_SPACE(input);
+ if (*input != EQUAL_SIGN) {
+ sippmh_free_authen(sip_authen);
+ CCSIP_ERR_DEBUG {
+ buginf("\n%s", get_debug_string(DEBUG_PMH_INCORRECT_SYNTAX));
+ }
+ return NULL;
+ }
+ input++; /* skip the equal sign */
+ SKIP_WHITE_SPACE(input);
+ /* input is now pointing at the value of the parameter */
+ *ptr = input;
+ if (*input == DOUBLE_QUOTE) {
+ input++;
+ *ptr = input; /*sam do not want the quotes in the string */
+ input = strchr(input, DOUBLE_QUOTE);
+ if (input == NULL) {
+ sippmh_free_authen(sip_authen);
+ CCSIP_ERR_DEBUG {
+ buginf("\n%s", get_debug_string(DEBUG_PMH_INCORRECT_SYNTAX));
+ }
+ return NULL;
+ } else {
+ *input++ = '\0'; /*sam string needs to be null terminated */
+ }
+ /*
+ * Check the qop. If qop is included it has to be either
+ * auth, auth-int or both. If both are included then we will
+ * just drop the second one.
+ */
+ if (qop_found == TRUE) {
+ char *qop_input = NULL;
+
+ if (sip_authen->qop) {
+ qop_input = strchr(sip_authen->qop, COMMA);
+ }
+ if (qop_input != NULL) {
+ *qop_input = '\0';
+ }
+
+ /*
+ * Make sure that the qop is either auth or auth-int
+ */
+ if ((strncasecmp(sip_authen->qop, "auth", 4) != 0) &&
+ (strncasecmp(sip_authen->qop, "auth-int", 8) != 0)) {
+ sip_authen->qop = NULL;
+ }
+ }
+ }
+
+ input = strchr(input, COMMA);
+ if (!input) {
+ good_params = sippmh_validate_authenticate(sip_authen);
+ if (good_params) {
+ return sip_authen;
+ } else {
+ sippmh_free_authen(sip_authen);
+ CCSIP_ERR_DEBUG {
+ buginf("\n%s", get_debug_string(DEBUG_PMH_NOT_ENOUGH_PARAMETERS));
+ }
+ return NULL;
+ }
+ }
+ *input++ = 0;
+ SKIP_WHITE_SPACE(input);
+ }
+
+ sippmh_free_authen(sip_authen);
+ return NULL;
+}
+
+/*
+ * Function: sippmh_parse_displaystr
+ *
+ * Parameters: Display string to be parsed
+ *
+ * Description:Removes leading ');
+ if (temp) {
+ *temp = 0;
+ }
+ displaystr = strlib_update(displaystr, temp_ptr);
+ return (displaystr);
+}
+
+/*
+ * Function: sippmh_process_via_header
+ *
+ * Parameters: Received Sip Message
+ * IP Address the Message was received from
+ *
+ * Description: Appends received= to the first Via
+ * field if the ip address we received this message
+ * from is not the same as the ip address in the via
+ * field or if it contains a domain name
+ *
+ * Returns: None
+ *
+ */
+void
+sippmh_process_via_header (sipMessage_t *sip_message,
+ cpr_ip_addr_t *source_ip_address)
+{
+ char dotted_ip[MAX_IPADDR_STR_LEN];
+ char *hdr_start;
+ char *new_buf;
+ int new_buf_len;
+ char *offset;
+ long old_header_offset;
+ sipVia_t *via;
+ cpr_ip_addr_t tmp_ip_addr;
+
+ CPR_IP_ADDR_INIT(tmp_ip_addr);
+
+ if (sip_message && sippmh_is_request(sip_message)) {
+ via = sippmh_parse_via(sip_message->hdr_cache[VIA].val_start);
+ if (via == NULL) {
+ /* error message already displayed in parse function */
+ /* mark the message as being incomplete so a 400 will get sent */
+ sip_message->is_complete = 0;
+ return;
+ }
+
+ util_ntohl(&tmp_ip_addr, source_ip_address);
+ ipaddr2dotted(dotted_ip, &tmp_ip_addr);
+ if (strcmp(via->host, dotted_ip) && (via->recd_host == NULL)) {
+ hdr_start = sip_message->hdr_cache[VIA].hdr_start;
+
+ /*
+ * +3 accounts for the ; and the = before and after the received
+ * and the terminating NULL
+ */
+ new_buf_len = strlen(hdr_start) + sizeof(VIA_RECEIVED) + strlen(dotted_ip) + 3;
+ new_buf = (char *) cpr_malloc(new_buf_len);
+ /*
+ * If we cannot allocate memory, we will just leave
+ * the VIA alone and hope things work out for the best
+ */
+ if (new_buf != NULL) {
+ offset = strchr(hdr_start, ',');
+ old_header_offset = sip_message->hdr_cache[VIA].val_start -
+ hdr_start;
+ sip_message->hdr_cache[VIA].hdr_start = new_buf;
+ sip_message->hdr_cache[VIA].val_start = new_buf +
+ old_header_offset;
+
+ if (offset) {
+ snprintf(new_buf, new_buf_len, "%.*s;%s=%s%s", (int) (offset - hdr_start), hdr_start, VIA_RECEIVED, dotted_ip, offset);
+ } else {
+ snprintf(new_buf, new_buf_len, "%s;%s=%s", hdr_start, VIA_RECEIVED, dotted_ip);
+ }
+
+ cpr_free(hdr_start);
+ }
+ }
+ sippmh_free_via(via);
+ }
+}
+
+
+/*
+ * Function: sippmh_parse_user
+ *
+ * Parameters: user portion of URL to parse
+ *
+ * Description: This function will remove any parameters
+ * which appear in the user portion of the url.
+ * (i.e. 15726;oct3=128@10.10.10.10 will return 15726)
+ * The SIP Phone does not care about the extra parameters and
+ * they need to be removed so that the user portion will
+ * match the phone provisioning and display correctly.
+ *
+ * Returns: A Copy of the input string with the parameters removed
+ * if things go well. NULL if we encounter an error.
+ */
+char *
+sippmh_parse_user (char *url_main)
+{
+ char *user = NULL;
+ size_t size = 0;
+ char *lasts = NULL;
+
+ if (url_main == NULL) {
+ return (NULL);
+ }
+
+ /*
+ * If the first char is ';', give up. That
+ * breaks our assumption.
+ */
+ if (*url_main == SEMI_COLON) {
+ return (NULL);
+ }
+
+ /*
+ * Create a new string and copy the url_main
+ * string into it. (We can't change the original
+ * string because it may be needed for creating
+ * SIP response messages.)
+ */
+ size = strlen(url_main) + 1;
+ user = (char *) cpr_malloc(size);
+ /*
+ * If the malloc fails, return the original URL.
+ */
+ if (user == NULL) {
+ return (NULL);
+ }
+
+ sstrncpy(user, url_main, size);
+
+ /*
+ * Search for ";" and null terminate the string there.
+ * An assumption has been made that any parameters will come
+ * after the number. i.e.: "15726;param=paramval"
+ */
+ (void) PL_strtok_r(user, ";", &lasts);
+ return (user);
+}
+
+/*
+ * Function: sippmh_parse_message_summary
+ *
+ * Parameters: The incoming SIP message and a container to be
+ * filled with the parsed message body.
+ *
+ * Description: This function will parse the incoming MWI NTFY SIP message
+ * and fill the passed in structure with the
+ * contents of the parsed message.Basic Error checking is done on
+ * the passed in message.
+ *
+ * Returns: SIP_ERROR on error.SIP_OK otherwise.
+ */
+int32_t
+sippmh_parse_message_summary(sipMessage_t *pSipMessage, sipMessageSummary_t *mesgSummary)
+{
+ int i = 0;
+ int j = 0;
+ char *p = NULL;
+ char *val = NULL;
+ char temp[MAX_SIP_URL_LENGTH];
+ boolean token_found = FALSE;
+ boolean hp_found = FALSE;
+ long strtol_result;
+ char *strtol_end;
+
+ p = strstr(pSipMessage->mesg_body[0].msgBody, "Messages-Waiting");
+
+ if (!p) {
+ p = strstr(pSipMessage->mesg_body[0].msgBody, "Message-Waiting");
+ }
+
+ if (p) {
+ memset(temp, '\0', MAX_SIP_URL_LENGTH);
+
+ trim_right(p);
+
+ val = strstr(p, ":");
+ if (val) {
+ val++;
+
+ i = j = 0;
+ while (val[j] != '\0' && val[j] != '\n' && isspace(val[j])) {
+ j++;
+ }
+ while (val[j] != '\0' && val[j] != '\n' && val[j] != '\r') {
+ // return error if obviously wrong
+ if (!isalpha(val[j])) {
+ return SIP_ERROR;
+ }
+ temp[i] = val[j];
+ j++;
+ if (++i >= MAX_SIP_URL_LENGTH) {
+ return SIP_ERROR;
+ }
+ }
+ temp[i] = '\0';
+ } else {
+ return SIP_ERROR;
+ }
+ } else {
+ return SIP_ERROR;
+ }
+
+ if (cpr_strcasecmp(temp, "no") == 0) {
+ mesgSummary->mesg_waiting_on = FALSE;
+ } else if (cpr_strcasecmp(temp, "yes") == 0) {
+ mesgSummary->mesg_waiting_on = TRUE;
+ } else {
+ return SIP_ERROR;
+ }
+
+/*
+ p = strstr(pSipMessage->mesg_body[0].msgBody, "Message-Account");
+
+ if (p) {
+ trim_right(p);
+
+ val = strstr(p, ":");
+ if (val) {
+ val++;
+
+ i = j = 0;
+ while (val[j] != '\0' && val[j] != '\n' && isspace(val[j])) {
+ j++;
+ }
+
+ while (val[j] != '\0' && val[j] != '\n' && val[j] != '\r') {
+ mesgSummary->message_account[i] = val[j];
+ j++;
+ if (++i >= MAX_SIP_URL_LENGTH) {
+ return SIP_ERROR;
+ }
+ }
+ mesgSummary->message_account[i] = '\0';
+ } else {
+ return SIP_ERROR;
+ }
+ }
+*/
+
+ p = strstr(pSipMessage->mesg_body[0].msgBody, "Voice-Message");
+
+ if (p) {
+ mesgSummary->type = mwiVoiceType;
+ memset(temp, '\0', MAX_SIP_URL_LENGTH);
+ trim_right(p);
+ i = j = 0;
+ val = strstr(p, ":");
+ if (val) {
+ val++;
+
+ while (val[j] != '\0' && val[j] != '\n' && isspace(val[j])) {
+ j++;
+ }
+
+ while (val[j] != '\0' && val[j] != '\n' && val[j] != '\r' && !isspace(val[j]) && val[j] != '(') {
+ if (!isdigit(val[j])) {
+ if (val[j] == '/') {
+ temp[i] = '\0';
+
+ errno = 0;
+ strtol_result = strtol(temp, &strtol_end, 10);
+
+ if (errno || temp == strtol_end || strtol_result > INT_MAX) {
+ return SIP_ERROR;
+ }
+
+ mesgSummary->newCount = (int) strtol_result;
+ token_found = TRUE;
+ i = 0;
+ } else {
+ return SIP_ERROR;
+ }
+ } else {
+ temp[i] = val[j];
+ if (++i >= MAX_SIP_URL_LENGTH) {
+ return SIP_ERROR;
+ }
+ }
+ j++;
+ }
+ temp[i] = '\0';
+
+ if (token_found) {
+ errno = 0;
+ strtol_result = strtol(temp, &strtol_end, 10);
+
+ if (errno || temp == strtol_end || strtol_result > INT_MAX) {
+ return SIP_ERROR;
+ }
+
+ mesgSummary->oldCount = (int) strtol_result;
+ }
+
+ temp[i = 0] = '\0';
+ while (val[j] != '\0' && val[j] != '\n' && isspace(val[j])) {
+ j++;
+ }
+
+ if (val[j] == '(') {
+ j++;
+ while (val[j] != '\0' && val[j] != '\n' && isspace(val[j])) {
+ j++;
+ }
+
+ while (val[j] != '\0' && val[j] != '\n' && val[j] != '\r' && !isspace(val[j]) && val[j] != ')') {
+ if (!isdigit(val[j])) {
+ if (val[j] == '/') {
+ temp[i] = '\0';
+
+ errno = 0;
+ strtol_result = strtol(temp, &strtol_end, 10);
+
+ if (errno || temp == strtol_end || strtol_result > INT_MAX) {
+ return SIP_ERROR;
+ }
+
+ mesgSummary->hpNewCount = (int) strtol_result;
+ hp_found = TRUE;
+ i = 0;
+ } else {
+ return SIP_ERROR;
+ }
+ } else {
+ temp[i] = val[j];
+ if (++i >= MAX_SIP_URL_LENGTH) {
+ return SIP_ERROR;
+ }
+ }
+ j++;
+ }
+ temp[i] = '\0';
+ if (hp_found) {
+ errno = 0;
+ strtol_result = strtol(temp, &strtol_end, 10);
+
+ if (errno || temp == strtol_end || strtol_result > INT_MAX) {
+ return SIP_ERROR;
+ }
+
+ mesgSummary->hpOldCount = (int) strtol_result;
+ }
+ }
+ if (!hp_found) {
+ mesgSummary->hpNewCount = mesgSummary->hpOldCount = -1;
+ }
+ /*make sure the urgent message counts don't exceed the total message counts*/
+ if ((mesgSummary->hpNewCount > mesgSummary->newCount) ||
+ (mesgSummary->hpOldCount > mesgSummary->oldCount)) {
+ return SIP_ERROR;
+ }
+ if (!token_found) {
+ return SIP_ERROR;
+ }
+ } else {
+ return SIP_ERROR;
+ }
+ }
+
+ return SIP_OK;
+}
+/*
+ * This function compares two strings that may contain escaped characters
+ * in either of them and determines if they are equivalent, ignoring the
+ * case if ignore_case is TRUE.
+ * s1 = ptr to the first string of chars
+ * s2 = ptr to the second string of chars
+ * return: integer value of 0 if they are equivalent, <> 0 otherwise.
+ */
+int
+sippmh_cmpURLStrings (const char *s1, const char *s2, boolean ignore_case)
+{
+ const unsigned char *us1 = (const unsigned char *) s1;
+ const unsigned char *us2 = (const unsigned char *) s2;
+ int value1, value2;
+ int esc_char_incr_in_s1 = 0; // # of chars to skip in s1 if the given char is escaped
+ int esc_char_incr_in_s2 = 0; // # of chars to skip in s2 if the given char is escaped
+
+ if ((!s1 && s2) || (s1 && !s2)) /* no match if only one ptr is NULL */
+ return (int) (s1 - s2); /* if one of these is NULL it will be the
+ * lesser of the two values and therefore
+ * we'll get the proper sign in the int */
+
+ if (s1 == s2) { /* match if both ptrs the same (e.g. NULL) */
+ return 0;
+ }
+
+ value1 = 0;
+ value2 = 0;
+ while (*us1 != '\0') {
+ if (*us1 == PERCENT) {
+ esc_char_incr_in_s1 = 2;
+
+ /* Convert 1st and 2nd hex chars to int */
+ value1 = sippmh_htoi(*(us1 + 1)) * 16;
+ value1 += sippmh_htoi(*(us1 + 2));
+ } else {
+ value1 = *us1;
+ }
+
+ if (*us2 == PERCENT) {
+ esc_char_incr_in_s2 = 2;
+
+ /* Convert 1st and 2nd hex chars to int */
+ value2 = sippmh_htoi(*(us2 + 1)) * 16;
+ value2 += sippmh_htoi(*(us2 + 2));
+ } else {
+ value2 = *us2;
+ }
+
+ if ((ignore_case && (toupper(value1) == toupper(value2))) ||
+ (!ignore_case && (value1 == value2))) {
+ us1 += (1 + esc_char_incr_in_s1);
+ us2 += (1 + esc_char_incr_in_s2);
+ esc_char_incr_in_s1 = 0;
+ esc_char_incr_in_s2 = 0;
+ } else {
+ break;
+ }
+ }
+
+ if (ignore_case) {
+ return (toupper(value1) - toupper(value2));
+ } else {
+ return (value1 - value2);
+ }
+}
+
+int
+sippmh_add_call_info (sipMessage_t *sip_message_p, cc_call_info_t *call_info_p)
+{
+ if (sip_message_p && call_info_p) {
+ char *call_info_hdr_p = ccsip_encode_call_info_hdr(call_info_p, NULL);
+
+ if (call_info_hdr_p != NULL) {
+ (void) sippmh_add_text_header(sip_message_p, SIP_HEADER_CALL_INFO,
+ (const char *) call_info_hdr_p);
+ cpr_free(call_info_hdr_p);
+ }
+ }
+ return (0);
+}
+
+/*
+ * Function: sippmh_parse_supported_require
+ *
+ * Parameters: contents of the Supported or Require header
+ *
+ * punsupported_tokens: if the caller wants to know the
+ * unsupported option tokens, it will pass a non-null pointer.
+ * If punsupporte_tokens is NULL, then the caller does not
+ * want to know the unsupported options.
+ *
+ * It is caller's responsibility to free the contents of this
+ * pointer.
+ *
+ * Description: This function will parse for the various options tags
+ * in the supported and require headers
+ *
+ * Returns: A bit map containing the values in the header
+ *
+ * Format of the line is as follows:
+ * Supported: replaces, join, sec-agree, whatever ...
+ * Require: replaces, join, sec-agree, whatever ...
+ */
+uint32_t
+sippmh_parse_supported_require (const char *header, char **punsupported_tokens)
+{
+ const char *fname = "sippmh_parse_supported_require";
+ uint32_t tags = 0;
+ char *temp_header;
+ char *token;
+ const char *delim = ", \r\n\t";
+ int unsupported_tokens_size = 0;
+ char *bad_token = NULL;
+ int size;
+ char *lasts = NULL;
+
+ if (header == NULL) {
+ return (tags);
+ }
+
+ if (punsupported_tokens != NULL) {
+ *punsupported_tokens = NULL; //assume everything will go right
+ }
+
+ //need to keep own buffer since PL_strtok_r is destructive
+ size = strlen(header) + 1;
+ temp_header = (char *) cpr_malloc(size);
+ if (temp_header == NULL) {
+ CCSIP_DEBUG_ERROR("%s: malloc failed for strlen(header)=%d\n", fname,
+ strlen(header));
+ return tags;
+ }
+ sstrncpy(temp_header, header, size);
+
+ token = PL_strtok_r(temp_header, delim, &lasts);
+ while (token != NULL) {
+ bad_token = NULL;
+
+ if (strcmp(token, REQ_SUPP_PARAM_REPLACES) == 0) {
+ tags |= replaces_tag;
+ } else if (strcmp(token, REQ_SUPP_PARAM_100REL) == 0) {
+ tags |= rel_tag;
+ bad_token = token;
+ } else if (strcmp(token, REQ_SUPP_PARAM_EARLY_SESSION) == 0) {
+ tags |= early_session_tag;
+ bad_token = token;
+ } else if (strcmp(token, REQ_SUPP_PARAM_JOIN) == 0) {
+ tags |= join_tag;
+ } else if (strcmp(token, REQ_SUPP_PARAM_PATH) == 0) {
+ tags |= path_tag;
+ bad_token = token;
+ } else if (strcmp(token, REQ_SUPP_PARAM_PRECONDITION) == 0) {
+ tags |= precondition_tag;
+ bad_token = token;
+ } else if (strcmp(token, REQ_SUPP_PARAM_PREF) == 0) {
+ tags |= pref_tag;
+ bad_token = token;
+ } else if (strcmp(token, REQ_SUPP_PARAM_PRIVACY) == 0) {
+ tags |= privacy_tag;
+ bad_token = token;
+ } else if (strcmp(token, REQ_SUPP_PARAM_SEC_AGREE) == 0) {
+ tags |= sec_agree_tag;
+ bad_token = token;
+ } else if (strcmp(token, REQ_SUPP_PARAM_TIMER) == 0) {
+ tags |= timer_tag;
+ bad_token = token;
+ } else if (strcmp(token, REQ_SUPP_PARAM_NOREFERSUB) == 0) {
+ tags |= norefersub_tag;
+ } else if (strcmp(token, REQ_SUPP_PARAM_CISCO_CALLINFO) == 0) {
+ tags |= cisco_callinfo_tag;
+ } else if (strcmp(token, REQ_SUPP_PARAM_CISCO_SERVICE_CONTROL) == 0) {
+ tags |= cisco_service_control_tag;
+
+ } else if (strcmp(token, REQ_SUPP_PARAM_SDP_ANAT) == 0) {
+ tags |= sdp_anat_tag;
+ }
+ else if (strcmp(token, REQ_SUPP_PARAM_EXTENED_REFER) == 0) {
+ tags |= extended_refer_tag;
+ } else if (strcmp(token, REQ_SUPP_PARAM_CISCO_SERVICEURI) == 0) {
+ tags |= cisco_serviceuri_tag;
+ } else if (strcmp(token, REQ_SUPP_PARAM_CISCO_ESCAPECODES) == 0) {
+ tags |= cisco_escapecodes_tag;
+ } else if (strcmp(token, REQ_SUPP_PARAM_CISCO_SRTP_FALLBACK) == 0) {
+ tags |= cisco_srtp_fallback_tag;
+ }
+ else {
+ //This is not necessarily an error. Other end may support something we
+ //don't. Is only an error if it shows up in Require.
+ tags |= (uint32_t) unrecognized_tag;
+ bad_token = token;
+ }
+
+ if (bad_token != NULL) {
+ CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"Invalid tag in Require/Supported %s\n",
+ DEB_F_PREFIX_ARGS(SIP_TAG, fname), bad_token);
+
+ //allocate memory for unsupported options if necessary
+ if (punsupported_tokens) {
+ if (!*punsupported_tokens) {
+ unsupported_tokens_size = strlen(header) + 1;
+ *punsupported_tokens = (char *) cpr_malloc(unsupported_tokens_size);
+ if (*punsupported_tokens) {
+ memset(*punsupported_tokens, 0, unsupported_tokens_size);
+ }
+ }
+ }
+
+ //caller wants to know what came in Require and we dont support
+ if (punsupported_tokens && *punsupported_tokens) {
+ //include token into illegal_tokens
+ if (strlen(*punsupported_tokens) > 0) {
+ sstrncat(*punsupported_tokens, ",", unsupported_tokens_size - strlen(*punsupported_tokens)); //add a ","
+ }
+ sstrncat(*punsupported_tokens, bad_token, unsupported_tokens_size - strlen(*punsupported_tokens));
+ }
+ bad_token = NULL;
+ }
+
+ //get next token
+ token = PL_strtok_r(NULL, delim, &lasts);
+ }
+ cpr_free(temp_header);
+ return (tags);
+}
+
+/*
+ * Function: sippmh_parse_allow_header
+ *
+ * Parameters: contents of the Allow header
+ *
+ * Description: This function will parse for the various methods
+ * supported in the allow header
+ *
+ * Returns: A bit map containing the values in the header
+ *
+ * Format of the line is as follows:
+ * Allow: ACK, BYE, CANCEL, ....
+ */
+uint16_t
+sippmh_parse_allow_header (const char *header)
+{
+ uint16_t tags = 0;
+
+ if (header == NULL) {
+ return (tags);
+ }
+ if (strstr(header, SIP_METHOD_ACK)) {
+ tags |= ALLOW_ACK;
+ }
+ if (strstr(header, SIP_METHOD_BYE)) {
+ tags |= ALLOW_BYE;
+ }
+ if (strstr(header, SIP_METHOD_CANCEL)) {
+ tags |= ALLOW_CANCEL;
+ }
+ if (strstr(header, SIP_METHOD_INFO)) {
+ tags |= ALLOW_INFO;
+ }
+ if (strstr(header, SIP_METHOD_INVITE)) {
+ tags |= ALLOW_INVITE;
+ }
+ if (strstr(header, SIP_METHOD_MESSAGE)) {
+ tags |= ALLOW_MESSAGE;
+ }
+ if (strstr(header, SIP_METHOD_NOTIFY)) {
+ tags |= ALLOW_NOTIFY;
+ }
+ if (strstr(header, SIP_METHOD_OPTIONS)) {
+ tags |= ALLOW_OPTIONS;
+ }
+ if (strstr(header, SIP_METHOD_PRACK)) {
+ tags |= ALLOW_PRACK;
+ }
+ if (strstr(header, SIP_METHOD_PUBLISH)) {
+ tags |= ALLOW_PUBLISH;
+ }
+ if (strstr(header, SIP_METHOD_REFER)) {
+ tags |= ALLOW_REFER;
+ }
+ if (strstr(header, SIP_METHOD_REGISTER)) {
+ tags |= ALLOW_REGISTER;
+ }
+ if (strstr(header, SIP_METHOD_SUBSCRIBE)) {
+ tags |= ALLOW_SUBSCRIBE;
+ }
+ if (strstr(header, SIP_METHOD_UPDATE)) {
+ tags |= ALLOW_UPDATE;
+ }
+ return (tags);
+}
+
+/*
+ * Function: sippmh_parse_accept_header
+ *
+ * Parameters: contents of the Accept header
+ *
+ * Description: This function will parse for the various capabilities
+ * signalled in the Accept header
+ *
+ * Returns: A bit map containing the values in the header
+ *
+ * Format of the line is as follows:
+ * Accept: application/sdp, nultipart/mixed, multipart/alternative
+ */
+uint16_t
+sippmh_parse_accept_header (const char *header)
+{
+ uint16_t tags = 0;
+
+ if (header == NULL) {
+ return (tags);
+ }
+ if (strstr(header, SIP_CONTENT_TYPE_SDP)) {
+ tags |= (0x01 << SIP_CONTENT_TYPE_SDP_VALUE);
+ }
+ if (strstr(header, SIP_CONTENT_TYPE_MULTIPART_MIXED)) {
+ tags |= (0x01 << SIP_CONTENT_TYPE_MULTIPART_MIXED_VALUE);
+ }
+ if (strstr(header, SIP_CONTENT_TYPE_MULTIPART_ALTERNATIVE)) {
+ tags |= (0x01 << SIP_CONTENT_TYPE_MULTIPART_ALTERNATIVE_VALUE);
+ }
+ return tags;
+}
+
+/*
+ * Function: ccsip_process_network_message
+ *
+ * Parameters: sipmsg, pointer to pointer of the buffer
+ * bytes used, display message.
+ *
+ * Description: Currently only used for tcp packets received to do the
+ * framing. Ported from Propel.
+ * Returns: A bit map containing the values in the header
+ */
+ccsipRet_e
+ccsip_process_network_message (sipMessage_t **sipmsg_p,
+ char **buf,
+ unsigned long *nbytes_used,
+ char **display_msg)
+{
+ static const char fname[] = "ccsip_process_network_message";
+ sipMessage_t *sip_msg = NULL;
+ int local_nbytes = *nbytes_used;
+ uint32_t bytes_used;
+ char *local_buf_ptr;
+
+ sip_msg = sippmh_message_create();
+ if (sip_msg == NULL) {
+ CCSIP_ERR_DEBUG {
+ buginf("%s: Error in creating SIP Msg\n", fname);
+ }
+ *sipmsg_p = NULL;
+ return SIP_MSG_CREATE_ERR;
+ }
+
+ /* Init local variables */
+ bytes_used = local_nbytes;
+ local_buf_ptr = *buf;
+
+ if (sippmh_process_network_message(sip_msg, local_buf_ptr, &bytes_used)
+ == STATUS_FAILURE) {
+ CCSIP_ERR_DEBUG {
+ buginf("%s: process_network_message failed.\n", fname);
+ }
+ sippmh_message_free(sip_msg);
+ *sipmsg_p = NULL;
+ return SIP_MSG_PARSE_ERR;
+ }
+
+ if (sippmh_is_message_complete(sip_msg)) {
+ if (display_msg) {
+ *display_msg = (char *) cpr_malloc(bytes_used + 1);
+ if (*display_msg == NULL) {
+ CCSIP_ERR_DEBUG {
+ buginf("%s: malloc of display msg failed.\n", fname);
+ }
+ sippmh_message_free(sip_msg);
+ *sipmsg_p = NULL;
+ return SIP_MSG_PARSE_ERR;
+ }
+ sstrncpy(*display_msg, local_buf_ptr, bytes_used + 1);
+ }
+ local_nbytes -= bytes_used;
+ local_buf_ptr += bytes_used;
+
+ /* Update information */
+ *sipmsg_p = sip_msg;
+ *nbytes_used = local_nbytes;
+ *buf = local_buf_ptr;
+
+ return SIP_SUCCESS;
+ } else {
+ CCSIP_ERR_DEBUG {
+ buginf("%s: process_network_msg: not complete\n", fname);
+ }
+ sippmh_message_free(sip_msg);
+ *sipmsg_p = NULL;
+
+ return SIP_MSG_INCOMPLETE_ERR;
+ }
+}
+
+/*
+ * Function: sippmh_parse_service_control_body
+ *
+ * Parameters: contents of the service control notify body and its length
+ *
+ * Description: This function will parse for the reset/restart
+ * instructions and parameters in this body
+ *
+ * Returns: 0 if body parsed correctly
+ * Parsed values are added to passed structure
+ *
+ * Format of the body is as follows:
+ * action = [reset | restart | check-version | call-preservation | apply-config ]
+ * RegisterCallId= {}
+ * ConfigVersionStamp = {79829A69-9489-4C8E-8143-90A9C22DFAD7}
+ * DialplanVersionStamp = {79829A69-9489-4C8E-8143-90A9C22DFAD7}
+ * SoftkeyVersionStamp = {79829A69-9489-4C8E-8143-90A9C22DFAD7}
+ * CUCMResult=[no_change | config_applied | reregister_needed]
+ * FirmwareLoadId = {SIP70.8-4-0-28S}
+ * LoadServer={10.81.15.24}
+ * LogServer={ } // This is used for ppid
+ * UpgradeTime=[now | later]
+ * PPID=[enabled | disabled]
+ */
+
+sipServiceControl_t *
+sippmh_parse_service_control_body (char *msgBody, int msgLength)
+{
+ pmhRstream_t *rs = NULL;
+ char *line = NULL, *value = NULL;
+ boolean body_read = FALSE;
+ sipServiceControl_t *scp = NULL;
+
+ if (msgLength==0) {
+ return (NULL);
+ }
+
+ if ((rs = pmhutils_rstream_create(msgBody, msgLength))
+ == NULL) {
+ return (NULL);
+ }
+
+ scp = (sipServiceControl_t *)
+ cpr_calloc(1, sizeof(sipServiceControl_t));
+ if (!scp) {
+ cpr_free(rs);
+ return NULL;
+ }
+
+ while (!body_read) {
+ line = pmhutils_rstream_read_line(rs);
+ if (line) {
+ value = strchr(line, '=');
+ if (value) {
+ value++;
+ while (*value == ' ') {
+ value++;
+ }
+ }
+ if (strlen(line) == 0) {
+
+ } else if (!strncasecmp(line, "action", sizeof("action") - 1)) {
+ if (value == NULL) {
+ scp->action = SERVICE_CONTROL_ACTION_INVALID;
+ } else if (!strncasecmp(value, "reset", sizeof("reset") - 1)) {
+ scp->action = SERVICE_CONTROL_ACTION_RESET;
+ } else if (!strncasecmp(value, "restart",
+ sizeof("restart") - 1)) {
+ scp->action = SERVICE_CONTROL_ACTION_RESTART;
+ } else if (!strncasecmp(value, "check-version",
+ sizeof("check-version") - 1)) {
+ scp->action = SERVICE_CONTROL_ACTION_CHECK_VERSION;
+ } else if (!strncasecmp(value, "call-preservation",
+ sizeof("call-preservation") - 1)) {
+ scp->action = SERVICE_CONTROL_ACTION_CALL_PRESERVATION;
+ } else if (!strncasecmp(value, "apply-config",
+ sizeof("apply-config") - 1)) {
+ scp->action = SERVICE_CONTROL_ACTION_APPLY_CONFIG;
+
+ } else {
+ scp->action = SERVICE_CONTROL_ACTION_INVALID;
+ }
+ } else if (!strncasecmp(line, "RegisterCallId",
+ sizeof("RegisterCallId") - 1)) {
+ if (scp->registerCallID == NULL) {
+ if (value == NULL) {
+ scp->registerCallID = NULL;
+ } else if (value[0]) {
+ int len = strlen(value);
+
+ /* make sure curly braces are present */
+ if ((*value == '{') && (*(value + len - 1) == '}')) {
+ scp->registerCallID = (char *)
+ cpr_calloc(1, len + 1);
+ /* ignore the beginning and ending curly brace */
+ if (scp->registerCallID)
+ memcpy(scp->registerCallID, value + 1,
+ (len - 2));
+ }
+ }
+ }
+
+ } else if (!strncasecmp(line, "ConfigVersionStamp",
+ sizeof("ConfigVersionStamp") - 1)) {
+ if (scp->configVersionStamp == NULL) {
+ if (value == NULL) {
+ scp->configVersionStamp = NULL;
+ } else if (value[0]) {
+ int len = strlen(value);
+
+ /* make sure curly braces are present */
+ if ((*value == '{') && (*(value + len - 1) == '}')) {
+ scp->configVersionStamp = (char *)
+ cpr_calloc(1, len + 1);
+ /* ignore the beginning and ending curly brace */
+ if (scp->configVersionStamp)
+ memcpy(scp->configVersionStamp, value + 1,
+ (len - 2));
+ }
+ }
+ }
+
+ } else if (!strncasecmp(line, "DialplanVersionStamp",
+ sizeof("DialplanVersionStamp") - 1)) {
+ if (scp->dialplanVersionStamp == NULL) {
+ if (value == NULL) {
+ scp->dialplanVersionStamp = NULL;
+ } else if (value[0]) {
+ int len = strlen(value);
+
+ /* make sure curly braces are present */
+ if ((*value == '{') && (*(value + len - 1) == '}')) {
+ scp->dialplanVersionStamp = (char *)
+ cpr_calloc(1, len + 1);
+ /* ignore the beginning and ending curly brace */
+ if (scp->dialplanVersionStamp)
+ memcpy(scp->dialplanVersionStamp, value + 1,
+ (len - 2));
+ }
+ }
+ }
+ } else if (!strncasecmp(line, "SoftkeyVersionStamp",
+ sizeof("SoftkeyVersionStamp") - 1)) {
+ if (scp->softkeyVersionStamp == NULL) {
+ if (value == NULL) {
+ scp->softkeyVersionStamp = NULL;
+ } else if (value[0]) {
+ int len = strlen(value);
+
+ /* make sure curly braces are present */
+ if ((*value == '{') && (*(value + len - 1) == '}')) {
+ scp->softkeyVersionStamp = (char *)
+ cpr_calloc(1, len + 1);
+ /* ignore the beginning and ending curly brace */
+ if (scp->softkeyVersionStamp)
+ memcpy(scp->softkeyVersionStamp, value + 1,
+ (len - 2));
+ }
+ }
+ }
+ } else if (!strncasecmp(line, "FeatureControlVersionStamp",
+ sizeof("FeatureControlVersionStamp") - 1)) {
+ if (scp->fcpVersionStamp == NULL) {
+ if (value == NULL) {
+ scp->fcpVersionStamp = NULL;
+ } else if (value[0]) {
+ int len = strlen(value);
+
+ /* make sure curly braces are present */
+ if ((*value == '{') && (*(value + len - 1) == '}')) {
+ scp->fcpVersionStamp = (char *)
+ cpr_calloc(1, len + 1);
+ /* ignore the beginning and ending curly brace */
+ if (scp->fcpVersionStamp)
+ memcpy(scp->fcpVersionStamp, value + 1,
+ (len - 2));
+ }
+ }
+ }
+ } else if (!strncasecmp(line, "CUCMResult",
+ sizeof("CUCMResult") - 1)) {
+ if (value == NULL) {
+ scp->cucm_result = NULL;
+ } else {
+ int len =0;
+ if ((strncasecmp(value, "no_change",
+ len = strlen("no_change")) == 0) ||
+ (strncasecmp(value, "config_applied",
+ len = strlen("config_applied")) == 0) ||
+ (strncasecmp(value, "reregister_needed",
+ len = strlen("reregister_needed")) == 0)) {
+ scp->cucm_result = (char *) cpr_calloc(1,len + 1);
+ if (scp->cucm_result) {
+ sstrncpy(scp->cucm_result, value, len);
+ scp->cucm_result[len] = '\0';
+ }
+ }
+ }
+ } else if (!strncasecmp(line, "LoadId",
+ sizeof("LoadId") - 1)) {
+ if (scp->firmwareLoadId == NULL) {
+ if (value == NULL) {
+ scp->firmwareLoadId = NULL;
+ } else if (value[0]) {
+ int len = strlen(value);
+
+ /* make sure curly braces are present */
+ if ((*value == '{') && (*(value + len - 1) == '}')) {
+ scp->firmwareLoadId = (char *)
+ cpr_calloc(1, len + 1);
+ /* ignore the beginning and ending curly brace */
+ if (scp->firmwareLoadId)
+ memcpy(scp->firmwareLoadId, value + 1,
+ (len - 2));
+ }
+ }
+ }
+ } else if (!strncasecmp(line, "InactiveLoadId",
+ sizeof("InactiveLoadId") - 1)) {
+ if (scp->firmwareInactiveLoadId == NULL) {
+ if (value == NULL) {
+ scp->firmwareInactiveLoadId = NULL;
+ } else if (value[0]) {
+ int len = strlen(value);
+
+ /* make sure curly braces are present */
+ if ((*value == '{') && (*(value + len - 1) == '}')) {
+ scp->firmwareInactiveLoadId = (char *)
+ cpr_calloc(1, len + 1);
+ /* ignore the beginning and ending curly brace */
+ if (scp->firmwareInactiveLoadId)
+ memcpy(scp->firmwareInactiveLoadId, value + 1,
+ (len - 2));
+ }
+ }
+ }
+ } else if (!strncasecmp(line, "LoadServer",
+ sizeof("LoadServer") - 1)) {
+ if (scp->loadServer == NULL) {
+ if (value == NULL) {
+ scp->loadServer = NULL;
+ } else if (value[0]) {
+ int len = strlen(value);
+
+ /* make sure curly braces are present */
+ if ((*value == '{') && (*(value + len - 1) == '}')) {
+ scp->loadServer = (char *)
+ cpr_calloc(1, len + 1);
+ /* ignore the beginning and ending curly brace */
+ if (scp->loadServer)
+ memcpy(scp->loadServer, value + 1,
+ (len - 2));
+ }
+ }
+ }
+ } else if (!strncasecmp(line, "LogServer",
+ sizeof("LogServer") - 1)) {
+ if (scp->logServer == NULL) {
+ if (value == NULL) {
+ scp->logServer = NULL;
+ } else if (value[0]) {
+ int len = strlen(value);
+
+ /* make sure curly braces are present */
+ if ((*value == '{') && (*(value + len - 1) == '}')) {
+ scp->logServer = (char *)
+ cpr_calloc(1, len + 1);
+ /* ignore the beginning and ending curly brace */
+ if (scp->logServer)
+ memcpy(scp->logServer, value + 1,
+ (len - 2));
+ }
+ }
+ }
+ } else if (!strncasecmp(line, "PPID", sizeof("PPID") - 1)) {
+ if (value == NULL) {
+ scp->ppid = FALSE;
+ } else if (!strncasecmp(value, "enabled", sizeof("enabled") - 1)) {
+ scp->ppid = TRUE;
+ } else if (!strncasecmp(value, "disabled",
+ sizeof("disabled") - 1)) {
+ scp->ppid = FALSE;
+ } else {
+ scp->ppid = FALSE;
+ }
+
+ }
+ cpr_free(line);
+
+ } else {
+ body_read = TRUE;
+ }
+ }
+ // Free the created stream structure
+ pmhutils_rstream_delete(rs, FALSE);
+ cpr_free(rs);
+ return (scp);
+}
+
+void
+sippmh_free_service_control_info (sipServiceControl_t *scp)
+{
+ if (!scp) {
+ return;
+ }
+
+ if (scp->configVersionStamp)
+ cpr_free(scp->configVersionStamp);
+ if (scp->dialplanVersionStamp)
+ cpr_free(scp->dialplanVersionStamp);
+ if (scp->registerCallID)
+ cpr_free(scp->registerCallID);
+ if (scp->softkeyVersionStamp)
+ cpr_free(scp->softkeyVersionStamp);
+ if (scp->fcpVersionStamp)
+ cpr_free(scp->fcpVersionStamp);
+ if (scp->cucm_result)
+ cpr_free(scp->cucm_result);
+ if (scp->loadServer)
+ cpr_free(scp->loadServer);
+ if (scp->firmwareLoadId)
+ cpr_free(scp->firmwareLoadId);
+ if (scp->logServer)
+ cpr_free(scp->logServer);
+
+ cpr_free(scp);
+}
+
+int32_t
+sippmh_parse_max_forwards (const char *max_fwd_hdr)
+{
+ int32_t maxFwd;
+
+ if (max_fwd_hdr) {
+ if (isdigit(*max_fwd_hdr)) {
+ maxFwd = strtol(max_fwd_hdr, NULL, 10);
+ if ((maxFwd >= 0) && (maxFwd <= 255)) {
+ return maxFwd;
+ }
+ }
+ }
+ return -1;
+}
+
+/*
+ * Function: sippmh_parse_url_from_hdr
+ *
+ * Parameters: String that needs to be parsed
+ *
+ * Description: This function will strip out the tags and
+ * other characters in the header to retreive
+ * a string that could be used as the request uri.
+ * Note that the input string needs to be well formed.
+ *
+ * Returns: A string containing the request uri
+ *
+ */
+string_t
+sippmh_get_url_from_hdr (char *input_str)
+{
+ char *left_bracket, *right_bracket = NULL;
+
+ /*
+ This function is only intended for properly
+ formed headers.
+ */
+ left_bracket = strpbrk(input_str, ",<");
+ if (left_bracket) {
+ left_bracket++;
+ right_bracket = strchr(left_bracket, '>');
+ if (right_bracket) {
+ *right_bracket = '\0';
+ }
+ input_str = left_bracket;
+ }
+ return (string_t)input_str;
+}
+/*
+ * Function: sippmh_parse_join_header
+ *
+ * Parameters: pointer to string of the join header contents
+ *
+ * Returns: Parsed structure if parsed correctly, NULL otherwise
+ *
+ * Format of the header is as follows:
+ * Join: abcd;from-tag=efgh;to-tag=ijkl
+ */
+sipJoinInfo_t *
+sippmh_parse_join_header (const char *header)
+{
+ sipJoinInfo_t *join = NULL;
+ char *semi = NULL;
+ unsigned int param_len;
+ char *params, *param_name, *param_value, *save_params;
+
+ if (!header) {
+ return NULL;
+ }
+
+ join = (sipJoinInfo_t *) cpr_calloc(1, sizeof(sipJoinInfo_t));
+ if (!join) {
+ return NULL;
+ }
+
+ // Read the call-id, if present
+ semi = strchr(header, SEMI_COLON);
+ if (semi) {
+ join->call_id = (char *) cpr_calloc(1, semi-header + 1);
+ if (join->call_id == NULL) {
+ sippmh_free_join_info(join);
+ return NULL;
+ }
+ sstrncpy(join->call_id, header, semi-header);
+ } else {
+ // call-id is the only parameter
+ join->call_id = cpr_strdup(header);
+ if (join->call_id == NULL) {
+ sippmh_free_join_info(join);
+ return NULL;
+ }
+ return (join);
+ }
+
+ params = cpr_strdup(semi);
+ if (!params) {
+ sippmh_free_join_info(join);
+ return NULL;
+ }
+ save_params = params;
+ while (1) {
+ while (*params == ';') {
+ params++;
+ }
+ param_name = params;
+ SKIP_SIP_TOKEN(params);
+ param_len = params - param_name;
+ if (param_len == 0) {
+ sippmh_free_join_info(join);
+ cpr_free(save_params);
+ return NULL;
+ }
+
+ /* Parse from-tag parameter */
+ if ((param_len == sizeof(SIP_HEADER_JOIN_FROM_TAG) - 1) &&
+ (strncasecmp(param_name, SIP_HEADER_JOIN_FROM_TAG,
+ sizeof(SIP_HEADER_JOIN_FROM_TAG) - 1) == 0) &&
+ (join->from_tag == NULL)) {
+ params = parse_generic_param(params, ¶m_value);
+ if (params == NULL) {
+ sippmh_free_join_info(join);
+ cpr_free(save_params);
+ return NULL;
+ } else {
+ join->from_tag = (char *) cpr_calloc(1, params-param_value + 1);
+ if (join->from_tag) {
+ sstrncpy(join->from_tag, param_value, params-param_value + 1);
+ }
+ SKIP_LWS(params);
+ if (*params == SEMI_COLON) {
+ *params++ = '\0';
+ } else {
+ break;
+ }
+
+ }
+
+ /* Parse to-tag parameter */
+ } else if ((param_len == sizeof(SIP_HEADER_JOIN_TO_TAG) - 1) &&
+ (strncasecmp(param_name, SIP_HEADER_JOIN_TO_TAG,
+ sizeof(SIP_HEADER_JOIN_TO_TAG) - 1) == 0) &&
+ (join->to_tag == NULL)) {
+ params = parse_generic_param(params, ¶m_value);
+ if (params == NULL) {
+ sippmh_free_join_info(join);
+ cpr_free(save_params);
+ return NULL;
+ } else {
+ join->to_tag = (char *) cpr_calloc(1, params-param_value + 1);
+ if (join->to_tag) {
+ sstrncpy(join->to_tag, param_value, params-param_value + 1);
+ }
+ if (*params == SEMI_COLON) {
+ *params++ = '\0';
+ } else {
+ break;
+ }
+ }
+
+ } else {
+ // Skip over unexpected parameter
+ SKIP_SIP_TOKEN(params);
+ }
+
+ SKIP_LWS(params);
+ }
+ cpr_free(save_params);
+ return (join);
+}
+
+void
+sippmh_free_join_info (sipJoinInfo_t *join)
+{
+
+ if (!join) {
+ return;
+ }
+ if (join->call_id)
+ cpr_free(join->call_id);
+ if (join->from_tag)
+ cpr_free(join->from_tag);
+ if (join->to_tag)
+ cpr_free(join->to_tag);
+ cpr_free(join);
+}
+
+sipRet_t
+sippmh_add_join_header (sipMessage_t *message, sipJoinInfo_t *join)
+{
+ char joinhdr[MAX_SIP_HEADER_LENGTH+1];
+ int left;
+
+ // Write out the header in a buffer
+ if (!message) {
+ return STATUS_FAILURE;
+ }
+
+ snprintf(joinhdr, MAX_SIP_HEADER_LENGTH, "%s", join->call_id);
+ left = (uint16_t) MAX_SIP_HEADER_LENGTH - strlen(join->call_id);
+ if (join->from_tag && left > 0) {
+ sstrncat(joinhdr, ";from-tag=", left);
+ left -= sizeof(";from-tag=") - 1;
+ sstrncat(joinhdr, join->from_tag, left);
+ left -= strlen(join->from_tag);
+ }
+ if (join->to_tag && left > 0) {
+ sstrncat(joinhdr, ";to-tag=", left);
+ left -= sizeof(";to-tag=") - 1;
+ sstrncat(joinhdr, join->to_tag, left);
+ }
+ return (sippmh_add_text_header(message, SIP_HEADER_JOIN, joinhdr));
+}
+
+/*
+ * Function: sippmh_parse_subscription_state
+ *
+ * Parameters: contents of the Subscription-State header
+ *
+ * Description: This function will parse for the state, expiry
+ * time, and a reason code in the header
+ *
+ * Returns: -1 if error, 0 if successfully parsed.
+ *
+ * Format of the line is as follows:
+ * Subscription-State: active;expires=7200;reason=whatever;retry-after=50
+ */
+int
+sippmh_parse_subscription_state(sipSubscriptionStateInfo_t *subsStateInfo,
+ const char *subs_state)
+//TODO: how can subs_state be a const char [] when it can be modified below?
+{
+ char *ptr;
+ char temp[TEMP_PARSE_BUFFER_SIZE];
+ uint8_t i;
+
+ if (!subs_state) {
+ return (-1);
+ }
+
+ if (!strncasecmp(subs_state, SIP_SUBSCRIPTION_STATE_ACTIVE,
+ sizeof(SIP_SUBSCRIPTION_STATE_ACTIVE) - 1)) {
+ subsStateInfo->state = SUBSCRIPTION_STATE_ACTIVE;
+ } else if (!strncasecmp(subs_state, SIP_SUBSCRIPTION_STATE_PENDING,
+ sizeof(SIP_SUBSCRIPTION_STATE_PENDING) - 1)) {
+ subsStateInfo->state = SUBSCRIPTION_STATE_PENDING;
+ } else if (!strncasecmp(subs_state, SIP_SUBSCRIPTION_STATE_TERMINATED,
+ sizeof(SIP_SUBSCRIPTION_STATE_PENDING) - 1)) {
+ subsStateInfo->state = SUBSCRIPTION_STATE_TERMINATED;
+ }
+
+ ptr = strchr(subs_state, ';');
+ if (!ptr) {
+ return (0);
+ }
+ SKIP_LWS(ptr);
+
+ // Look for expires tag
+ ptr = strstr(subs_state, SIP_SUBSCRIPTION_STATE_EXPIRES);
+ if (ptr) {
+ ptr = ptr + sizeof(SIP_SUBSCRIPTION_STATE_EXPIRES); // Go over the '='
+ SKIP_LWS(ptr);
+ if (*ptr) {
+ boolean is_int = FALSE;
+
+ memset(temp, 0, sizeof(temp));
+ i = 0;
+ while (isdigit(*ptr) && (i < sizeof(temp)-1)) {
+ temp[i++] = *ptr;
+ ptr++;
+ is_int = TRUE;
+ }
+ if (is_int == TRUE) {
+ subsStateInfo->expires = strtoul(temp, NULL, 10);
+ }
+ }
+ }
+ // Look for reason tag
+ ptr = strstr(subs_state, SIP_SUBSCRIPTION_STATE_REASON);
+ if (ptr) {
+ ptr = ptr + sizeof(SIP_SUBSCRIPTION_STATE_REASON);
+ SKIP_LWS(ptr);
+ if (*ptr) {
+ if (!strncasecmp(ptr, SIP_SUBSCRIPTION_STATE_REASON_DEACTIVATED,
+ sizeof(SIP_SUBSCRIPTION_STATE_REASON_DEACTIVATED) - 1)) {
+ subsStateInfo->reason = SUBSCRIPTION_STATE_REASON_DEACTIVATED;
+ } else if (!strncasecmp(ptr, SIP_SUBSCRIPTION_STATE_REASON_PROBATION,
+ sizeof(SIP_SUBSCRIPTION_STATE_REASON_PROBATION) - 1)) {
+ subsStateInfo->reason = SUBSCRIPTION_STATE_REASON_PROBATION;
+ } else if (!strncasecmp(ptr, SIP_SUBSCRIPTION_STATE_REASON_REJECTED,
+ sizeof(SIP_SUBSCRIPTION_STATE_REASON_REJECTED) - 1)) {
+ subsStateInfo->reason = SUBSCRIPTION_STATE_REASON_REJECTED;
+ } else if (!strncasecmp(ptr, SIP_SUBSCRIPTION_STATE_REASON_TIMEOUT,
+ sizeof(SIP_SUBSCRIPTION_STATE_REASON_TIMEOUT) - 1)) {
+ subsStateInfo->reason = SUBSCRIPTION_STATE_REASON_TIMEOUT;
+ } else if (!strncasecmp(ptr, SIP_SUBSCRIPTION_STATE_REASON_GIVEUP,
+ sizeof(SIP_SUBSCRIPTION_STATE_REASON_GIVEUP) - 1)) {
+ subsStateInfo->reason = SUBSCRIPTION_STATE_REASON_GIVEUP;
+ } else if (!strncasecmp(ptr, SIP_SUBSCRIPTION_STATE_REASON_NORESOURCE,
+ sizeof(SIP_SUBSCRIPTION_STATE_REASON_NORESOURCE) - 1)) {
+ subsStateInfo->reason = SUBSCRIPTION_STATE_REASON_NORESOURCE;
+ } else {
+ subsStateInfo->reason = SUBSCRIPTION_STATE_REASON_INVALID;
+ }
+ }
+ }
+
+ // Look for retry-after tag
+ ptr = strstr(subs_state, SIP_SUBSCRIPTION_STATE_RETRY_AFTER);
+ if (ptr) {
+ ptr = ptr + sizeof(SIP_SUBSCRIPTION_STATE_RETRY_AFTER); // Go over the '='
+ SKIP_LWS(ptr);
+ if (*ptr) {
+ boolean is_int = FALSE;
+
+ memset(temp, 0, sizeof(temp));
+ i = 0;
+ while (isdigit(*ptr) && (i < sizeof(temp)-1)) {
+ temp[i++] = *ptr;
+ ptr++;
+ is_int = TRUE;
+ }
+ if (is_int == TRUE) {
+ *ptr = '\0';
+ subsStateInfo->retry_after = strtoul(temp, NULL, 10);
+ }
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * Function: sippmh_add_subscription_state
+ *
+ * Parameters: contents of the Subscription-State header
+ *
+ * Description: This function will add the subscription state header
+ *
+ * Returns: -1 if error, 0 if successfully added
+ *
+ * Format of the line is as follows:
+ * Subscription-State: active; expires=7200; reason=whatever
+ */
+int
+sippmh_add_subscription_state(sipMessage_t *msg,
+ sipSubscriptionStateInfo_t *subsStateInfo)
+{
+ char subs_state[MAX_SUB_STATE_HEADER_SIZE];
+
+ if (!msg) {
+ return -1;
+ }
+
+ if ((subsStateInfo->state == SUBSCRIPTION_STATE_ACTIVE) && (subsStateInfo->expires == 0)) {
+ snprintf(&subs_state[0], MAX_SUB_STATE_HEADER_SIZE, "%s", SIP_SUBSCRIPTION_STATE_ACTIVE);
+ } else if (subsStateInfo->state == SUBSCRIPTION_STATE_ACTIVE) {
+ snprintf(&subs_state[0], MAX_SUB_STATE_HEADER_SIZE, "%s; expires=%d",
+ SIP_SUBSCRIPTION_STATE_ACTIVE,
+ subsStateInfo->expires);
+ } else if (subsStateInfo->state == SUBSCRIPTION_STATE_PENDING) {
+ snprintf(&subs_state[0], MAX_SUB_STATE_HEADER_SIZE, "%s; expires=%d",
+ SIP_SUBSCRIPTION_STATE_PENDING,
+ subsStateInfo->expires);
+ } else if (subsStateInfo->state == SUBSCRIPTION_STATE_TERMINATED) {
+ snprintf(&subs_state[0], MAX_SUB_STATE_HEADER_SIZE, "%s; reason=timeout",
+ SIP_SUBSCRIPTION_STATE_TERMINATED);
+ }
+
+ (void) sippmh_add_text_header(msg, SIP_HEADER_SUBSCRIPTION_STATE,
+ (const char *)&subs_state[0]);
+ return 0;
+}
+
+boolean
+sippmh_parse_kpml_event_id_params (char *params, char **call_id,
+ char **from_tag, char **to_tag)
+{
+ boolean params_good;
+ int param_len;
+ char *param_name;
+
+ if (params == NULL) {
+ return FALSE;
+ }
+
+ while (1) {
+ params_good = FALSE;
+
+ while (*params == ';') {
+ params++;
+ }
+
+ param_name = params;
+ SKIP_SIP_TOKEN(params);
+ param_len = params - param_name;
+ if (param_len == 0) {
+ return FALSE;
+ }
+
+ /* Parse call-id parameter */
+ if ((param_len == KPML_ID_CALLID_LEN) &&
+ (strncasecmp(param_name, KPML_ID_CALLID, KPML_ID_CALLID_LEN) == 0)) {
+ params = parse_generic_param(params, call_id);
+ if (params == NULL) {
+ return FALSE;
+ } else {
+ params_good = TRUE;
+ }
+
+ /* Parse from-tag parameter */
+ } else if ((param_len == KPML_ID_FROM_TAG_LEN) &&
+ (strncasecmp(param_name, KPML_ID_FROM_TAG,
+ KPML_ID_FROM_TAG_LEN) == 0)) {
+ params = parse_generic_param(params, from_tag);
+ if (params == NULL) {
+ return FALSE;
+ } else {
+ params_good = TRUE;
+ }
+
+ /* Parse to-tag parameter */
+ } else if ((param_len == KPML_ID_TO_TAG_LEN) &&
+ (strncasecmp(param_name, KPML_ID_TO_TAG,
+ KPML_ID_TO_TAG_LEN) == 0)) {
+ params = parse_generic_param(params, to_tag);
+ if (params == NULL) {
+ return FALSE;
+ } else {
+ params_good = TRUE;
+ }
+
+ }
+
+ SKIP_LWS(params);
+ if (*params == SEMI_COLON) {
+ /* More parameters follow */
+ *params++ = '\0';
+ SKIP_LWS(params);
+ } else {
+ break;
+ }
+ }
+
+ return params_good;
+}
diff --git a/libs/sipcc/core/sipstack/ccsip_publish.c b/libs/sipcc/core/sipstack/ccsip_publish.c
new file mode 100644
index 0000000000..acde663e9f
--- /dev/null
+++ b/libs/sipcc/core/sipstack/ccsip_publish.c
@@ -0,0 +1,896 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "ccsip_publish.h"
+#include "phntask.h"
+#include "sip_common_transport.h"
+#include "ccsip_task.h"
+#include "ccsip_callinfo.h"
+#include "ccsip_macros.h"
+#include "util_string.h"
+#include "cpr_rand.h"
+#include "platform_api.h"
+#include "ccsip_register.h"
+#include "ccsip_reldev.h"
+#include "debug.h"
+
+static sll_handle_t s_PCB_list = NULL; // signly linked list handle of PCBs
+static int outgoingPublishes;
+
+static boolean sipSPISendPublish(ccsip_publish_cb_t *pcb_p, boolean authen);
+static void free_pending_reqs (sll_handle_t list);
+
+/**
+ * This function will generate a new handle and return it.
+ *
+ * @return a non-zero integer value
+ */
+static pub_handle_t generate_new_pub_handle (void)
+{
+ static pub_handle_t handle = 0;
+
+ handle++;
+ if (handle == NULL_PUBLISH_HANDLE) {
+ handle++;
+ }
+ return handle;
+}
+
+/**
+ * This function will check if it is the PCB we are looking for based on the key.
+ * This is only invoked by sll_find().
+ *
+ * @param[in] key - pointer to the key.
+ * @param[in] data - pointer to a node data.
+ *
+ * @return SLL_MATCH_FOUND if the node matches.
+ * Otherwise, SLL_MATCH_NOT_FOUND is returned.
+ *
+ * @pre (key != NULL) and (data != NULL)
+ */
+static sll_match_e is_matching_pcb (void *key, void *data)
+{
+ pub_handle_t pub_handle = *((pub_handle_t *)key);
+ ccsip_publish_cb_t *pcb_p = (ccsip_publish_cb_t *)data;
+
+ if (pub_handle == pcb_p->pub_handle) {
+ return SLL_MATCH_FOUND;
+ }
+ return SLL_MATCH_NOT_FOUND;
+}
+
+/**
+ * This function will create a PCB. It will also create the PCB linked list.
+ *
+ * @return NULL if there are no resources to create a PCB.
+ * Otherwise, pointer to a new PCB is returned.
+ *
+ * @pre (key != NULL) and (data != NULL)
+ */
+static ccsip_publish_cb_t *get_new_pcb (void)
+{
+ ccsip_publish_cb_t *pcb_p;
+
+ /*
+ * If PCB list is not created yet, create the list.
+ */
+ if (s_PCB_list == NULL) {
+ s_PCB_list = sll_create(is_matching_pcb);
+ if (s_PCB_list == NULL) {
+ return NULL;
+ }
+ }
+
+ pcb_p = (ccsip_publish_cb_t *)cpr_malloc(sizeof(ccsip_publish_cb_t));
+ if (pcb_p == NULL) {
+ return NULL;
+ }
+ memset(pcb_p, 0, sizeof(ccsip_publish_cb_t));
+ pcb_p->pub_handle = generate_new_pub_handle();
+ pcb_p->hb.cb_type = PUBLISH_CB;
+ pcb_p->hb.dn_line = 1; // for now set it to primary line. This will change when we do line based PUBLISH.
+ /*
+ * set up dest & src ip addr and port number.
+ */
+ ccsip_common_util_set_dest_ipaddr_port(&pcb_p->hb);
+ ccsip_common_util_set_src_ipaddr(&pcb_p->hb);
+ pcb_p->hb.local_port = sipTransportGetListenPort(pcb_p->hb.dn_line, NULL);
+ pcb_p->retry_timer.timer = cprCreateTimer("PUBLISH retry timer",
+ SIP_PUBLISH_RETRY_TIMER,
+ TIMER_EXPIRATION,
+ sip_msgq);
+ if (pcb_p->retry_timer.timer == NULL) {
+ cpr_free(pcb_p);
+ return NULL;
+ }
+ pcb_p->pending_reqs = sll_create(NULL);
+ if (pcb_p->pending_reqs == NULL) {
+ (void)cprDestroyTimer(pcb_p->retry_timer.timer);
+ cpr_free(pcb_p);
+ return NULL;
+ }
+ (void) sll_append(s_PCB_list, pcb_p);
+
+ return pcb_p;
+}
+
+/**
+ * This function will find matching PCB by the key in the PCB list.
+ *
+ * @param[in] pub_handle - publish handle.
+ *
+ * @return NULL if there is no matching PCB
+ * Otherwise, pointer to the found PCB is returned.
+ *
+ * @pre (pub_handle > 0) and (s_PCB_list != NULL)
+ */
+static ccsip_publish_cb_t *find_pcb (pub_handle_t pub_handle)
+{
+ ccsip_publish_cb_t *pcb_p;
+
+ pcb_p = (ccsip_publish_cb_t *)sll_find(s_PCB_list, &pub_handle);
+
+ return pcb_p;
+}
+
+/**
+ * This function will find matching PCB by the SIP Call-ID in the PCB list.
+ *
+ * @param[in] callID_p - SIP Call-ID
+ *
+ * @return NULL if there is no matching PCB
+ * Otherwise, pointer to the found PCB is returned.
+ *
+ * @pre (callID_p != NULL)
+ */
+static ccsip_publish_cb_t *find_pcb_by_sip_callid (const char *callID_p)
+{
+ ccsip_publish_cb_t *pcb_p;
+
+ pcb_p = (ccsip_publish_cb_t *)sll_next(s_PCB_list, NULL);
+ while (pcb_p != NULL) {
+ if (strncmp(callID_p, pcb_p->hb.sipCallID, (sizeof(pcb_p->hb.sipCallID) -1)) == 0) {
+ return pcb_p;
+ }
+ pcb_p = (ccsip_publish_cb_t *)sll_next(s_PCB_list, pcb_p);
+ }
+ return NULL;
+}
+
+/**
+ * This function will free up the PCB resources and removes it from the PCB list.
+ *
+ * @param[in] pcb_p - pointer to a PCB.
+ *
+ * @return none
+ *
+ * @pre (pcb_p != NULL)
+ */
+static void free_pcb (ccsip_publish_cb_t *pcb_p)
+{
+ if (pcb_p->hb.authen.authorization != NULL) {
+ cpr_free(pcb_p->hb.authen.authorization);
+ }
+ if (pcb_p->hb.authen.sip_authen != NULL) {
+ sippmh_free_authen(pcb_p->hb.authen.sip_authen);
+ }
+
+ cpr_free(pcb_p->entity_tag);
+ free_pending_reqs(pcb_p->pending_reqs);
+ (void)cprDestroyTimer(pcb_p->retry_timer.timer);
+ free_event_data(pcb_p->hb.event_data_p);
+ (void)sll_remove(s_PCB_list, (void *)pcb_p);
+ cpr_free(pcb_p);
+}
+
+/**
+ * This function will append the application request in a pending list.
+ *
+ * @param[in] pcb_p - pointer to a PCB.
+ * @param[in] msg_p - pointer to an application request.
+ *
+ * @return TRUE if it is successful.
+ * Otherwise, FALSE is returned.
+ *
+ * @pre (pcb_p != NULL) and (msg_p != NULL)
+ * @post ((slink_list_t *)s_pres_req_list->count++)
+ */
+static boolean append_pending_reqs (ccsip_publish_cb_t *pcb_p, pub_req_t *msg_p)
+{
+ pub_req_t *temp_msg_p;
+
+ temp_msg_p = (pub_req_t *)cpr_malloc(sizeof(pub_req_t));
+ if (temp_msg_p == NULL) {
+ return FALSE;
+ }
+ (*temp_msg_p) = (*msg_p);
+ (void) sll_append(pcb_p->pending_reqs, temp_msg_p);
+ return TRUE;
+}
+
+/**
+ * This function will free up entire list of pending requests
+ *
+ * @param[in] list - pending requests list handle
+ *
+ * @return none
+ *
+ */
+static void free_pending_reqs (sll_handle_t list)
+{
+ pub_req_t *msg_p;
+
+ if (list == NULL) {
+ return;
+ }
+
+ msg_p = (pub_req_t *)sll_next(list, NULL);
+ while (msg_p != NULL) {
+ free_event_data(msg_p->event_data_p);
+ (void)sll_remove(list, (void *)msg_p);
+ cpr_free(msg_p);
+ msg_p = (pub_req_t *)sll_next(list, NULL);
+ }
+ sll_destroy(list);
+}
+
+/**
+ * This function will send the PUBLSIH request response to the application.
+ *
+ * @param[in] resp_code - this also includes error responses that start at 1000
+ * @param[in] pub_handle - handle to a PCB
+ * @param[in] app_handle - application generated handle to this PUBLISH context.
+ * @param[in] callback_task - task in which the application resides.
+ * @param[in] resp_msg_id - messageID posted to the task.
+ *
+ * @return none
+ */
+static void send_resp_to_app (int resp_code, pub_handle_t pub_handle, pub_handle_t app_handle,
+ cc_srcs_t callback_task, int resp_msg_id)
+{
+ static const char fname[] = "send_resp_to_app";
+ pub_rsp_t rsp;
+
+ rsp.resp_code = resp_code;
+ rsp.pub_handle = pub_handle;
+ rsp.app_handle = app_handle;
+ if (publish_int_response(&rsp, callback_task, resp_msg_id) != CC_RC_SUCCESS) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Failed to post PUBLISH response to the application", fname);
+ }
+}
+
+/**
+ * This function will process SIPSPI_EV_CC_PUBLISH posted by applications.
+ * If there is an outstanding transaction, it will hold the request in the pending list.
+ *
+ * @param[in] buf - inter-process message buffer.
+ *
+ * @return SIP_OK if it successfully processes the request.
+ * SIP_ERROR if it fails to process the request.
+ * SIP_DEFER if it defers the processing.
+ *
+ * @note This will not free buf.
+ *
+ * @pre (buf != NULL)
+ */
+int publish_handle_ev_app_publish (cprBuffer_t buf)
+{
+ static const char fname[] = "publish_handle_ev_app_publish";
+ pub_req_t *msg_p = (pub_req_t *)buf;
+ ccsip_publish_cb_t *pcb_p;
+
+
+ /*
+ * If this is initial PUBLISH, allocate a PCB.
+ * Otherwise, look up for PCB based on pub_handle.
+ */
+ if (msg_p->pub_handle != NULL_PUBLISH_HANDLE) {
+ pcb_p = find_pcb(msg_p->pub_handle);
+
+ if (pcb_p == NULL) {
+ send_resp_to_app(PUBLISH_FAILED_NOCONTEXT, msg_p->pub_handle, msg_p->app_handle,
+ msg_p->callback_task, msg_p->resp_msg_id);
+ free_event_data(msg_p->event_data_p);
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX
+ "Modification PUBLISH cannot be sent as the PCB is missing\n",
+ fname);
+ return SIP_ERROR;
+ }
+
+ /*
+ * Check if there is an outstanding transaction.
+ * if so, put the request in pending request queue.
+ */
+ if (pcb_p->outstanding_trxn == TRUE) {
+ if (append_pending_reqs(pcb_p, msg_p) == TRUE) {
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"deffering as there is an outstanding transaction\n",
+ DEB_F_PREFIX_ARGS(SIP_PUB, fname));
+ return SIP_DEFER;
+ }
+ /* free up PCB and respond with error */
+ free_pcb (pcb_p);
+ send_resp_to_app(PUBLISH_FAILED_NORESOURCE, msg_p->pub_handle, msg_p->app_handle,
+ msg_p->callback_task, msg_p->resp_msg_id);
+ free_event_data(msg_p->event_data_p);
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Queueing outgoing PUBLISH request failed\n", fname);
+ return SIP_ERROR;
+ }
+ /*
+ * if event_data_p is NULL, this is terminating PUBLISH.
+ * otherwise, it is a modifying PUBLISH.
+ */
+ free_event_data(pcb_p->hb.event_data_p);
+ pcb_p->hb.event_data_p = msg_p->event_data_p;
+ if ((msg_p->event_data_p == NULL) && (msg_p->expires == 0)) { // removing PUBLISH
+ pcb_p->hb.orig_expiration = 0;
+ }
+ } else {
+ pcb_p = get_new_pcb();
+ if (pcb_p == NULL) {
+ send_resp_to_app(PUBLISH_FAILED_NORESOURCE, msg_p->pub_handle, msg_p->app_handle,
+ msg_p->callback_task, msg_p->resp_msg_id);
+ free_event_data(msg_p->event_data_p);
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"PCB allocation failed\n", fname);
+ return SIP_ERROR;
+ }
+ pcb_p->app_handle = msg_p->app_handle;
+ sstrncpy(pcb_p->ruri, msg_p->ruri, MAX_URI_LENGTH);
+ sstrncpy(pcb_p->esc, msg_p->esc, MAX_URI_LENGTH);
+ pcb_p->hb.orig_expiration = msg_p->expires;
+ pcb_p->hb.event_type = msg_p->event_type;
+ pcb_p->hb.event_data_p = msg_p->event_data_p;
+ pcb_p->callback_task = msg_p->callback_task;
+ pcb_p->resp_msg_id = msg_p->resp_msg_id;
+ }
+
+ pcb_p->hb.authen.cred_type = 0;
+
+ if (sipSPISendPublish(pcb_p, FALSE) == TRUE) {
+ pcb_p->outstanding_trxn = TRUE;
+ outgoingPublishes++;
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"PUBLISH request sent successfully\n", DEB_F_PREFIX_ARGS(SIP_PUB, fname));
+ return SIP_OK;
+ }
+
+ /* free up PCB and respond with error */
+ free_pcb (pcb_p);
+ send_resp_to_app(PUBLISH_FAILED_SEND, msg_p->pub_handle, msg_p->app_handle,
+ msg_p->callback_task, msg_p->resp_msg_id);
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Failed to send PUBLISH request\n", fname);
+ return SIP_ERROR;
+
+}
+
+
+/**
+ * This function will create the PUBLISH message and send it. it also starts the retry timer.
+ *
+ * @param[in] pcb_p - pointer to PCB
+ * @param[in] authen - boolean that indicates whether to add authorization header.
+ *
+ * @return TRUE if it successfully sent PUBLISH
+ * Otherwise, FALSE is returned
+ *
+ * @pre (pcb_p != NULL)
+ */
+static boolean sipSPISendPublish (ccsip_publish_cb_t *pcb_p, boolean authen)
+{
+ static const char fname[] = "sipSPISendPublish";
+ static uint32_t cseq = 0;
+ char dest_sip_addr_str[MAX_IPADDR_STR_LEN];
+ char *domainloc;
+ char src_addr_str[MAX_IPADDR_STR_LEN];
+ char sip_temp_str[MAX_SIP_URL_LENGTH];
+ char sip_temp_tag[MAX_SIP_URL_LENGTH];
+ uint8_t mac_address[MAC_ADDRESS_LENGTH];
+ char via[SIP_MAX_VIA_LENGTH];
+ int max_forwards_value = 70;
+ static uint16_t count = 1;
+ sipMessage_t *request = NULL;
+ int timeout = 0;
+
+ request = GET_SIP_MESSAGE();
+ if (!request) {
+ return FALSE;
+ }
+
+ /*
+ * Populate full RURI if it is not yet. Sometimes, applications may only provide user part.
+ */
+ if (pcb_p->full_ruri[0] == 0) {
+ sstrncpy(pcb_p->full_ruri, "sip:", MAX_SIP_URL_LENGTH);
+ sstrncat(pcb_p->full_ruri, pcb_p->ruri, MAX_SIP_URL_LENGTH - sizeof("sip:"));
+ /* check if it has host part */
+ domainloc = strchr(pcb_p->full_ruri, '@');
+ if (domainloc == NULL) {
+ domainloc = pcb_p->full_ruri + strlen(pcb_p->full_ruri);
+ if ((domainloc - pcb_p->full_ruri) < (MAX_SIP_URL_LENGTH - 1)) {
+ /* Do not include @ when there is no user part */
+ if (pcb_p->ruri[0] != '\0') {
+ *domainloc++ = '@';
+ }
+ ipaddr2dotted(dest_sip_addr_str, &pcb_p->hb.dest_sip_addr);
+ sstrncpy(domainloc, dest_sip_addr_str,
+ MAX_SIP_URL_LENGTH - (domainloc - (pcb_p->full_ruri)));
+ }
+ }
+ }
+
+ ipaddr2dotted(src_addr_str, &pcb_p->hb.src_addr);
+
+ // Add request line
+ if (HSTATUS_SUCCESS != sippmh_add_request_line(request,
+ sipGetMethodString(sipMethodPublish),
+ pcb_p->full_ruri, SIP_VERSION)) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding Request line\n", fname);
+ free_sip_message(request);
+ return (FALSE);
+ }
+
+ // Add local Via
+ snprintf(via, sizeof(via), "SIP/2.0/%s %s:%d;%s=%s%.8x",
+ sipTransportGetTransportType(1, TRUE, NULL),
+ src_addr_str, pcb_p->hb.local_port, VIA_BRANCH,
+ VIA_BRANCH_START, (unsigned int) cpr_rand());
+ if (HSTATUS_SUCCESS != sippmh_add_text_header(request, SIP_HEADER_VIA, via)) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding VIA header\n", fname);
+ free_sip_message(request);
+ return (FALSE);
+ }
+
+ // Add To Header
+ snprintf(sip_temp_str, MAX_SIP_URL_LENGTH, "<%s>", pcb_p->full_ruri);
+ if (HSTATUS_SUCCESS != sippmh_add_text_header(request, SIP_HEADER_TO, sip_temp_str)) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding TO header\n", fname);
+ free_sip_message(request);
+ return (FALSE);
+ }
+
+ // Add From Header.
+ sstrncat(sip_temp_str, ";tag=", MAX_SIP_URL_LENGTH - strlen(sip_temp_str));
+ sip_util_make_tag(sip_temp_tag);
+ sstrncat(sip_temp_str, sip_temp_tag, MAX_SIP_URL_LENGTH - strlen(sip_temp_str));
+ if (HSTATUS_SUCCESS != sippmh_add_text_header(request, SIP_HEADER_FROM, sip_temp_str)) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding FROM header\n", fname);
+ free_sip_message(request);
+ return (FALSE);
+ }
+
+ // Add Call-ID Header.
+ platform_get_wired_mac_address(mac_address);
+ count++;
+ snprintf(pcb_p->hb.sipCallID, MAX_SIP_CALL_ID, "%.4x%.4x-%.4x%.4x-%.8x-%.8x@%s", // was MAX_SIP_URL_LENGTH
+ mac_address[0] * 256 + mac_address[1],
+ mac_address[2] * 256 + mac_address[3],
+ mac_address[4] * 256 + mac_address[5], count,
+ (unsigned int) cpr_rand(),
+ (unsigned int) cpr_rand(),
+ src_addr_str);
+ if (HSTATUS_SUCCESS != sippmh_add_text_header(request, SIP_HEADER_CALLID, pcb_p->hb.sipCallID)) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding CALLID header\n", fname);
+ free_sip_message(request);
+ return (FALSE);
+ }
+
+ // Add Contact header. Contact header is not needed as per RFC. BUT CCM needs it.
+ snprintf(sip_temp_str, MAX_SIP_URL_LENGTH, "",
+ mac_address[0] * 256 + mac_address[1],
+ mac_address[2] * 256 + mac_address[3],
+ mac_address[4] * 256 + mac_address[5],
+ src_addr_str, pcb_p->hb.local_port);
+ if (HSTATUS_SUCCESS != sippmh_add_text_header(request, SIP_HEADER_CONTACT, sip_temp_str)) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding Contact header\n", fname);
+ free_sip_message(request);
+ return (FALSE);
+ }
+
+ // Add Cseq.
+ cseq++;
+ if (cseq == 0) {
+ cseq = 1;
+ }
+ if (HSTATUS_SUCCESS != sippmh_add_cseq(request, sipGetMethodString(sipMethodPublish), cseq)) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding CSEQ header\n", fname);
+ free_sip_message(request);
+ return (FALSE);
+ }
+
+ // Add UserAgent header
+ (void) sippmh_add_text_header(request, SIP_HEADER_USER_AGENT,
+ sipHeaderUserAgent);
+
+
+ // Add SIP-If-Match header.
+ if (pcb_p->entity_tag != NULL) {
+ if (HSTATUS_SUCCESS != sippmh_add_text_header(request, SIP_HEADER_SIPIFMATCH,
+ pcb_p->entity_tag)) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding Event header\n", fname);
+ free_sip_message(request);
+ return (FALSE);
+ }
+ }
+
+ // Add Expires Header
+ if (HSTATUS_SUCCESS != sippmh_add_int_header(request, SIP_HEADER_EXPIRES,
+ pcb_p->hb.orig_expiration)) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding Expires header\n", fname);
+ free_sip_message(request);
+ return (FALSE);
+ }
+
+ // Add max-forwards header
+ config_get_value(CFGID_SIP_MAX_FORWARDS, &max_forwards_value,
+ sizeof(max_forwards_value));
+ if (HSTATUS_SUCCESS !=
+ sippmh_add_int_header(request, SIP_HEADER_MAX_FORWARDS,
+ max_forwards_value)) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding Max-Forwards header\n", fname);
+ free_sip_message(request);
+ return (FALSE);
+ }
+
+ // add Authorization header
+ if (authen) {
+ if (HSTATUS_SUCCESS != sippmh_add_text_header(request, AUTHOR_HDR(pcb_p->hb.authen.status_code),
+ pcb_p->hb.authen.authorization)) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding Authorization header\n", fname);
+ free_sip_message(request);
+ return (FALSE);
+ }
+ }
+
+ // Add content, if any
+ if (pcb_p->hb.event_data_p) {
+ if (add_content(pcb_p->hb.event_data_p, request, fname) == FALSE) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding Content\n", fname);
+ free_sip_message(request);
+ return (FALSE);
+ }
+ } else {
+ if (HSTATUS_SUCCESS != sippmh_add_int_header(request, SIP_HEADER_CONTENT_LENGTH, 0)) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding Content-Len\n", fname);
+ free_sip_message(request);
+ return (FALSE);
+ }
+ }
+
+ ccsip_common_util_set_retry_settings(&pcb_p->hb, &timeout);
+ if (sipTransportCreateSendMessage(NULL, request, sipMethodPublish,
+ &(pcb_p->hb.dest_sip_addr),
+ (int16_t) pcb_p->hb.dest_sip_port,
+ FALSE, TRUE, timeout, pcb_p,
+ RELDEV_NO_STORED_MSG) < 0) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"failed to send PUBLISH message\n", fname);
+ return (FALSE);
+ }
+
+ return (TRUE);
+
+}
+
+/**
+ * This function will handle retry-timer expiration
+ *
+ * @param[in] handle - handle to PCB
+ *
+ * @return 0 if it is successful in handling the timer
+ * Otherwise, -1 is returned
+ *
+ * @pre (handle != 0)
+ */
+int publish_handle_retry_timer_expire (uint32_t handle)
+{
+ static const char fname[] = "publish_handle_retry_timer_expire";
+ pub_handle_t pub_handle = handle;
+ ccsip_publish_cb_t *pcb_p;
+ uint32_t max_retx = 0;
+ uint32_t time_t1 = 0;
+ uint32_t time_t2 = 0;
+ uint32_t timeout = 0;
+
+ /*
+ * find the PCB
+ */
+ pcb_p = find_pcb(pub_handle);
+ if (pcb_p == NULL) {
+ /* No PCB. So do nothing. */
+ return 0;
+ }
+ if (pcb_p->hb.retx_flag == FALSE) {
+ /* probably we got some response. so do nothing */
+ return 0;
+ }
+ config_get_value(CFGID_SIP_RETX, &max_retx, sizeof(max_retx));
+ if (max_retx > MAX_NON_INVITE_RETRY_ATTEMPTS) {
+ max_retx = MAX_NON_INVITE_RETRY_ATTEMPTS;
+ }
+ if (pcb_p->hb.retx_counter < max_retx) {
+ pcb_p->hb.retx_counter++;
+ config_get_value(CFGID_TIMER_T1, &time_t1, sizeof(time_t1));
+ timeout = time_t1 * (1 << pcb_p->hb.retx_counter);
+ config_get_value(CFGID_TIMER_T2, &time_t2, sizeof(time_t2));
+ if (timeout > time_t2) {
+ timeout = time_t2;
+ }
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Resending message #%d\n",
+ DEB_F_PREFIX_ARGS(SIP_PUB, fname), pcb_p->hb.retx_counter);
+ if (sipTransportSendMessage(NULL,
+ pcb_p->retry_timer.message_buffer,
+ pcb_p->retry_timer.message_buffer_len,
+ pcb_p->retry_timer.message_type,
+ &(pcb_p->retry_timer.ipaddr),
+ pcb_p->retry_timer.port,
+ FALSE, TRUE, timeout, pcb_p) < 0) {
+ /* free up PCB and respond with error */
+ send_resp_to_app(PUBLISH_FAILED_SEND, pcb_p->pub_handle, pcb_p->app_handle,
+ pcb_p->callback_task, pcb_p->resp_msg_id);
+ free_pcb (pcb_p);
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"failed to send message", fname);
+ return (-1);
+ }
+
+ } else {
+ /*
+ * send timeout response and free up PCB
+ */
+ send_resp_to_app(SIP_CLI_ERR_REQ_TIMEOUT, pcb_p->pub_handle, pcb_p->app_handle,
+ pcb_p->callback_task, pcb_p->resp_msg_id);
+ free_pcb (pcb_p);
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"reached MAX retries", fname);
+ }
+ return 0;
+}
+
+/**
+ * This function will check if wee need to send refresh PUBLISH.
+ * If so, it will send refresh PUBLISH
+ *
+ * @param[in] none
+ *
+ * @return none
+ */
+void publish_handle_periodic_timer_expire (void)
+{
+ static const char fname[] = "publish_handle_periodic_timer_expire";
+ int delta = 0;
+ ccsip_publish_cb_t *pcb_p;
+ pub_req_t msg;
+
+ config_get_value(CFGID_TIMER_SUBSCRIBE_DELTA, &delta,
+ sizeof(delta));
+ pcb_p = (ccsip_publish_cb_t *)sll_next(s_PCB_list, NULL);
+ while (pcb_p != NULL) {
+ if (pcb_p->outstanding_trxn == FALSE) {
+ if (pcb_p->hb.expires >= TMR_PERIODIC_PUBLISH_INTERVAL) {
+ pcb_p->hb.expires -= TMR_PERIODIC_PUBLISH_INTERVAL;
+ }
+ if (pcb_p->hb.expires <= (delta + TMR_PERIODIC_PUBLISH_INTERVAL)) {
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"sending REFRESH PUBLISH", DEB_F_PREFIX_ARGS(SIP_PUB, fname));
+ memset (&msg, 0, sizeof(msg));
+ /* refresh is triggered by NULL event data and non-zero expires value */
+ msg.pub_handle = pcb_p->pub_handle;
+ msg.expires = pcb_p->hb.orig_expiration;
+ (void)publish_handle_ev_app_publish(&msg);
+ }
+ }
+ pcb_p = (ccsip_publish_cb_t *)sll_next(s_PCB_list, pcb_p);
+ }
+}
+
+/**
+ * This function will process the response to PUBLISH request sent by us.
+ *
+ * @param[in] pSipMessage - pointer to received SIP response msg
+ *
+ * @return SIP_OK if it successfully processes the response.
+ * SIP_ERROR if it fails to process the response.
+ *
+ * @pre (pSipMessage != NULL)
+ */
+int publish_handle_ev_sip_response (sipMessage_t *pSipMessage)
+{
+ static const char fname[] = "publish_handle_ev_sip_response";
+ const char *callID_p = NULL;
+ int response_code = 0;
+ const char *expires = NULL;
+ const char *sip_etag = NULL;
+ long expiry_time;
+ pub_req_t *msg_p;
+ ccsip_publish_cb_t *pcb_p;
+ int entity_tag_size;
+
+ callID_p = sippmh_get_cached_header_val(pSipMessage, CALLID);
+ if (!callID_p) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Cannot obtain SIP Call ID.\n", fname);
+ return SIP_ERROR;
+ }
+
+ /*
+ * Find PCB by Call-ID. The Call-IDs generated by the phone ae unique.
+ */
+ pcb_p = find_pcb_by_sip_callid(callID_p);
+ if (pcb_p == NULL) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"No matching PCB found\n", fname);
+ return SIP_ERROR;
+ }
+
+ /*
+ * Cancel the retry_timer and set the retx_flag to FALSE.
+ */
+ sip_platform_msg_timer_subnot_stop(&(pcb_p->retry_timer));
+ pcb_p->hb.retx_flag = FALSE;
+
+ // Parse the return code
+ (void) sipGetResponseCode(pSipMessage, &response_code);
+
+ if (response_code >= 200) {
+ pcb_p->outstanding_trxn = FALSE;
+ }
+
+
+ if ((response_code == SIP_CLI_ERR_UNAUTH) ||
+ (response_code == SIP_CLI_ERR_PROXY_REQD)) {
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Authentication Required\n", DEB_F_PREFIX_ARGS(SIP_PUB, fname));
+ if (ccsip_common_util_generate_auth(pSipMessage, &pcb_p->hb, SIP_METHOD_PUBLISH,
+ response_code, pcb_p->full_ruri) == TRUE) {
+ if (sipSPISendPublish(pcb_p, TRUE) == TRUE) {
+ pcb_p->outstanding_trxn = TRUE;
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"sent request with Auth header\n", DEB_F_PREFIX_ARGS(SIP_PUB, fname));
+ return SIP_OK;
+ }
+ }
+ /*
+ * Since we failed to resend the PUBLISH request, free up the PCB and let the app know.
+ */
+ send_resp_to_app(PUBLISH_FAILED_SEND, pcb_p->pub_handle, pcb_p->app_handle,
+ pcb_p->callback_task, pcb_p->resp_msg_id);
+ free_pcb (pcb_p);
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"failed to respond to auth challenge\n", fname);
+ return SIP_ERROR;
+ }
+
+ /*
+ * if response code is 423, grab Min-Expires and send new PUBLISH with new expires value
+ */
+ if (response_code == SIP_CLI_ERR_INTERVAL_TOO_SMALL) {
+ expires = sippmh_get_header_val(pSipMessage,
+ (const char *)SIP_HEADER_MIN_EXPIRES,
+ NULL);
+ if (expires) {
+ expiry_time = strtoul(expires, NULL, 10);
+ //ensure new Min-Expires is > what we set before in Expires
+ if ((long) expiry_time > pcb_p->hb.expires) {
+ pcb_p->hb.expires = expiry_time;
+ pcb_p->hb.orig_expiration = expiry_time;
+ }
+ if (sipSPISendPublish(pcb_p, FALSE) == TRUE) {
+ pcb_p->outstanding_trxn = TRUE;
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"sent request with increased expires\n", DEB_F_PREFIX_ARGS(SIP_PUB, fname));
+ return SIP_OK;
+ }
+ }
+ /*
+ * Since we failed to resend the PUBLISH request, free up the PCB and let the app know.
+ */
+ send_resp_to_app(PUBLISH_FAILED_SEND, pcb_p->pub_handle, pcb_p->app_handle,
+ pcb_p->callback_task, pcb_p->resp_msg_id);
+ free_pcb (pcb_p);
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"failed to respond to 423\n", fname);
+ return SIP_ERROR;
+ }
+
+ /*
+ * if the response_code is > 299, free up the PCB and let the app know.
+ */
+ if (response_code > 299) {
+ send_resp_to_app(response_code, pcb_p->pub_handle, pcb_p->app_handle,
+ pcb_p->callback_task, pcb_p->resp_msg_id);
+ free_pcb (pcb_p);
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"received %d response\n", DEB_F_PREFIX_ARGS(SIP_PUB, fname), response_code);
+ return SIP_OK;
+ }
+
+ /*
+ * if the response is < 200, do nothing.
+ */
+ if (response_code < 200) {
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"received %d response\n", DEB_F_PREFIX_ARGS(SIP_PUB, fname), response_code);
+ return SIP_OK;
+ }
+
+ /*
+ * If it is PUBLISH remove operation, free up PCB
+ */
+ if (pcb_p->hb.orig_expiration == 0) {
+ send_resp_to_app(response_code, pcb_p->pub_handle, pcb_p->app_handle,
+ pcb_p->callback_task, pcb_p->resp_msg_id);
+ free_pcb (pcb_p);
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"removed PCB as this was a terminating PUBLISH\n", DEB_F_PREFIX_ARGS(SIP_PUB, fname));
+ return SIP_OK;
+ }
+
+ /*
+ * extract Expires and SIP-ETag headers and save them.
+ */
+ expires = sippmh_get_header_val(pSipMessage, SIP_HEADER_EXPIRES, NULL);
+ if (expires) {
+ expiry_time = strtoul(expires, NULL, 10);
+ pcb_p->hb.expires = expiry_time;
+ }
+ sip_etag = sippmh_get_header_val(pSipMessage, SIP_HEADER_SIPETAG, NULL);
+ if (sip_etag != NULL) {
+ cpr_free(pcb_p->entity_tag);
+ entity_tag_size = strlen(sip_etag) + 1;
+ pcb_p->entity_tag = cpr_malloc(entity_tag_size);
+ if (pcb_p->entity_tag != NULL) {
+ sstrncpy(pcb_p->entity_tag, sip_etag, entity_tag_size);
+ } else {
+ free_pcb (pcb_p);
+ send_resp_to_app(PUBLISH_FAILED_NORESOURCE, pcb_p->pub_handle, pcb_p->app_handle,
+ pcb_p->callback_task, pcb_p->resp_msg_id);
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"memory allocation failed\n", fname);
+ return SIP_ERROR;
+
+ }
+ }
+
+ /*
+ * If there are no pending requests, provide the response to the application.
+ */
+ msg_p = (pub_req_t *)sll_next(pcb_p->pending_reqs, NULL);
+ if (msg_p != NULL) {
+ (void)sll_remove(pcb_p->pending_reqs, msg_p);
+ (void)publish_handle_ev_app_publish(msg_p);
+ cpr_free(msg_p);
+ return SIP_OK;
+ }
+ send_resp_to_app(response_code, pcb_p->pub_handle, pcb_p->app_handle,
+ pcb_p->callback_task, pcb_p->resp_msg_id);
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"sent response %d to app\n", DEB_F_PREFIX_ARGS(SIP_PUB, fname), response_code);
+ return SIP_OK;
+}
+
+/**
+ * This function will inform the application that phone is either
+ * 1. restarting or
+ * 2. failing over/ falling back
+ *
+ * @note detection of CCM reboot will be handled by PUBLISH ETag mechanism.
+ *
+ * @param[in] none
+ *
+ * @return none
+ */
+void publish_reset (void)
+{
+ ccsip_publish_cb_t *pcb_p;
+
+ pcb_p = (ccsip_publish_cb_t *)sll_next(s_PCB_list, NULL);
+ while (pcb_p != NULL) {
+ send_resp_to_app(PUBLISH_FAILED_RESET, pcb_p->pub_handle, pcb_p->app_handle,
+ pcb_p->callback_task, pcb_p->resp_msg_id);
+ free_pcb(pcb_p);
+ pcb_p = (ccsip_publish_cb_t *)sll_next(s_PCB_list, NULL);
+ }
+}
+
+/**
+ * This function will print the stats (invoked by show command)
+ *
+ * @param[in] none
+ *
+ * @return 0 always
+ */
+cc_int32_t show_publish_stats (cc_int32_t argc, const char *argv[])
+{
+ debugif_printf("------ Current PUBLISH Statistics ------\n");
+ if (s_PCB_list != NULL) {
+ debugif_printf("Number of PCBs allocated: %d\n", sll_count(s_PCB_list));
+ } else {
+ debugif_printf("Number of PCBs allocated: 0\n");
+ }
+ debugif_printf("Total outgoing PUBLISH requests: %d\n", outgoingPublishes);
+ return 0;
+}
+
diff --git a/libs/sipcc/core/sipstack/ccsip_register.c b/libs/sipcc/core/sipstack/ccsip_register.c
new file mode 100644
index 0000000000..8f79d62e60
--- /dev/null
+++ b/libs/sipcc/core/sipstack/ccsip_register.c
@@ -0,0 +1,3079 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include
+
+#include "cpr_types.h"
+#include "cpr_stdio.h"
+#include "cpr_stdlib.h"
+#include "cpr_timers.h"
+#include "cpr_string.h"
+#include "cpr_memory.h"
+#include "cpr_ipc.h"
+#include "cpr_in.h"
+#include "util_string.h"
+#include "task.h"
+#include "phntask.h"
+#include "ccsip_core.h"
+#include "ccsip_messaging.h"
+#include "phone_debug.h"
+#include "ccsip_platform.h"
+#include "ccsip_platform_timers.h"
+#include "ccsip_macros.h"
+#include "ccsip_pmh.h"
+#include "ccsip_register.h"
+#include "ccsip_task.h"
+#include "ccsip_credentials.h"
+#include "debug.h"
+#include "logmsg.h"
+#include "ccsip_pmh.h"
+#include "ccsip_credentials.h"
+#include "dns_utils.h"
+#include "config.h"
+#include "sip_common_transport.h"
+#include "uiapi.h"
+#include "sip_common_regmgr.h"
+#include "text_strings.h"
+#include "sip_interface_regmgr.h"
+#include "phone_platform_constants.h"
+#include "ccsip_common_cb.h"
+#include "misc_util.h"
+
+extern sipPlatformUITimer_t sipPlatformUISMTimers[];
+extern void *new_standby_available;
+extern boolean regall_fail_attempt;
+extern boolean registration_reject;
+
+extern void ui_set_sip_registration_state(line_t line, boolean registered);
+extern void ui_update_registration_state_all_lines(boolean registered);
+
+boolean dump_reg_msg = TRUE;
+boolean refresh_reg_msg = FALSE;
+
+static ccsip_register_states_t ccsip_register_state = SIP_REG_IDLE;
+
+/* Need an additional ack timer for the backup proxy */
+static cprTimer_t ack_tmrs[MAX_REG_LINES + 1];
+ccm_act_stdby_table_t CCM_Active_Standby_Table;
+extern ccm_failover_table_t CCM_Failover_Table;
+static boolean start_standby_monitor = TRUE;
+extern boolean Is794x;
+
+static void show_register_data(void);
+
+#define SIP_REG_TMR_EXPIRE_TICKS 55000 /* msec; re-registration timer */
+#define REGISTER_CMD "register"
+#define SIP_REG_TMR_ACK_TICKS 32000 /* msec; supervision timer equivalent to Timer F */
+
+static const char *ccsip_register_state_names[] = {
+ "IDLE",
+ "REGISTERING",
+ "REGISTERED",
+ "UNREGISTERING",
+ "PRE_FALLBACK",
+ "IN_FAILOVER",
+ "POST_FAILOVER",
+ "STANDBY_FAILOVER",
+ "NO_CC",
+ "NO_STANDBY",
+ "NO_REGISTER"
+};
+
+static const char *ccsip_register_reg_state_names[] = {
+ "NONE",
+ "IDLE",
+ "REGISTERING",
+ "REGISTERED",
+ "UNREGISTERING",
+ "PRE_FALLBACK",
+ "IN_FAILOVER",
+ "POST_FAILOVER",
+ "STANDBY_FAILOVER",
+ "NO_CC",
+ "NO_STANDBY",
+ "NO_REGISTER"
+};
+
+
+void ccsip_handle_ev_reg_req(ccsipCCB_t *ccb, sipSMEvent_t *event);
+void ccsip_handle_ev_reg_cancel(ccsipCCB_t *ccb, sipSMEvent_t *event);
+void ccsip_handle_ev_unreg_2xx(ccsipCCB_t *ccb, sipSMEvent_t *event);
+void ccsip_handle_ev_1xx(ccsipCCB_t *ccb, sipSMEvent_t *event);
+void ccsip_handle_ev_2xx(ccsipCCB_t *ccb, sipSMEvent_t *event);
+void ccsip_handle_ev_3xx(ccsipCCB_t *ccb, sipSMEvent_t *event);
+void ccsip_handle_ev_4xx(ccsipCCB_t *ccb, sipSMEvent_t *event);
+void ccsip_handle_ev_failure_response(ccsipCCB_t *ccb, sipSMEvent_t *event);
+void ccsip_handle_ev_tmr_expire(ccsipCCB_t *ccb, sipSMEvent_t *event);
+void ccsip_handle_ev_tmr_ack(ccsipCCB_t *ccb, sipSMEvent_t *event);
+void ccsip_handle_ev_tmr_retry(ccsipCCB_t *ccb, sipSMEvent_t *event);
+void ccsip_handle_ev_unreg_tmr_ack(ccsipCCB_t *ccb, sipSMEvent_t *event);
+void ccsip_handle_ev_standby_keepalive_tmr_expire(ccsipCCB_t *ccb, sipSMEvent_t *event);
+void ccsip_handle_ev_idle_tmr_expire(ccsipCCB_t *ccb, sipSMEvent_t *event);
+
+const char *ccsip_register_state_name(ccsip_register_states_t state);
+const char *ccsip_register_reg_state_name(sipRegSMStateType_t state);
+const char *sip_util_reg_event2string(sipRegSMEventType_t event);
+char *sip_util_reg_state2string(sipRegSMStateType_t state);
+void ccsip_register_retry_timer_start(ccsipCCB_t *ccb);
+void ccsip_register_cleanup(ccsipCCB_t *ccb, boolean start);
+cc_int32_t ccsip_register_cmd(cc_int32_t argc, const char *argv[]);
+void ccsip_register_clear_all_logs(void);
+boolean ccsip_register_all_registered(void);
+
+/* convert sip line to reg line */
+#define SIP_REG_LINE2REGLINE(line) ((line) - (REG_CCB_START))
+
+/* convert reg line to sip line */
+#define SIP_REG_REGLINE2LINE(line) ((line) + (REG_CCB_START))
+
+// Date holder
+static struct {
+ boolean valid;
+ char datestring[MAX_SIP_DATE_LENGTH];
+} ccm_date;
+
+static const sipSMEventActionFn_t
+gSIPRegSMTable[SIP_REG_STATE_END - SIP_REG_STATE_BASE + 1]
+ [SIPSPI_REG_EV_END - SIPSPI_REG_EV_BASE + 1] =
+{
+ /* SIP_REG_STATE_IDLE
+ */
+ {
+ /* E_SIP_REG_REG_REQ */ ccsip_handle_ev_reg_req,
+ /* E_SIP_REG_CANCEL */ ccsip_handle_ev_default,
+ /* E_SIP_REG_1xx */ ccsip_handle_ev_default,
+ /* E_SIP_REG_2xx */ ccsip_handle_ev_default,
+ /* E_SIP_REG_3xx */ ccsip_handle_ev_default,
+ /* E_SIP_REG_4xx */ ccsip_handle_ev_default,
+ /* E_SIP_REG_FAILURE_RESPONSE */ ccsip_handle_ev_default,
+ /* E_SIP_REG_TMR_ACK */ ccsip_handle_ev_default,
+ /* E_SIP_REG_TMR_EXPIRE */ ccsip_handle_ev_idle_tmr_expire,
+ /* E_SIP_REG_TMR_WAIT */ ccsip_handle_ev_default,
+ /* E_SIP_REG_TMR_RETRY */ ccsip_handle_ev_default,
+ /* E_SIP_REG_CLEANUP */ sip_regmgr_ev_default,
+ },
+
+ /* SIP_REG_STATE_REGISTERING
+ */
+ {
+ /* E_SIP_REG_REG_REQ */ ccsip_handle_ev_reg_req,
+ /* E_SIP_REG_CANCEL */ ccsip_handle_ev_reg_cancel,
+ /* E_SIP_REG_1xx */ ccsip_handle_ev_1xx,
+ /* E_SIP_REG_2xx */ ccsip_handle_ev_2xx,
+ /* E_SIP_REG_3xx */ ccsip_handle_ev_3xx,
+ /* E_SIP_REG_4xx */ ccsip_handle_ev_4xx,
+ /* E_SIP_REG_FAILURE_RESPONSE */ ccsip_handle_ev_failure_response,
+ /* E_SIP_REG_TMR_ACK */ ccsip_handle_ev_tmr_ack,
+ /* E_SIP_REG_TMR_EXPIRE */ ccsip_handle_ev_tmr_expire,
+ /* E_SIP_REG_TMR_WAIT */ ccsip_handle_ev_default,
+ /* E_SIP_REG_TMR_RETRY */ ccsip_handle_ev_tmr_retry,
+ /* E_SIP_REG_CLEANUP */ sip_regmgr_ev_default,
+ },
+
+ /* SIP_REG_STATE_REGISTERED
+ */
+ {
+ /* E_SIP_REG_REG_REQ */ ccsip_handle_ev_default,
+ /* E_SIP_REG_CANCEL */ ccsip_handle_ev_reg_cancel,
+ /* E_SIP_REG_1xx */ ccsip_handle_ev_default,
+ /* E_SIP_REG_2xx */ ccsip_handle_ev_default,
+ /* E_SIP_REG_3xx */ ccsip_handle_ev_default,
+ /* E_SIP_REG_4xx */ ccsip_handle_ev_default,
+ /* E_SIP_REG_FAILURE_RESPONSE */ ccsip_handle_ev_default,
+ /* E_SIP_REG_TMR_ACK */ ccsip_handle_ev_default,
+ /* E_SIP_REG_TMR_EXPIRE */ ccsip_handle_ev_tmr_expire,
+ /* E_SIP_REG_TMR_WAIT */ ccsip_handle_ev_default,
+ /* E_SIP_REG_TMR_RETRY */ ccsip_handle_ev_tmr_retry,
+ /* E_SIP_REG_CLEANUP */ sip_regmgr_ev_default,
+ },
+
+ /* SIP_REG_STATE_UNREGISTERING
+ */
+ {
+ /* E_SIP_REG_REG_REQ */ ccsip_handle_ev_default,
+ /* E_SIP_REG_CANCEL */ ccsip_handle_ev_reg_cancel,
+ /* E_SIP_REG_1xx */ ccsip_handle_ev_1xx,
+ /* E_SIP_REG_2xx */ ccsip_handle_ev_unreg_2xx,
+ /* E_SIP_REG_3xx */ ccsip_handle_ev_3xx,
+ /* E_SIP_REG_4xx */ ccsip_handle_ev_4xx,
+ /* E_SIP_REG_FAILURE_RESPONSE */ ccsip_handle_ev_failure_response,
+ /* E_SIP_REG_TMR_ACK */ ccsip_handle_ev_unreg_tmr_ack,
+ /* E_SIP_REG_TMR_EXPIRE */ ccsip_handle_ev_default,
+ /* E_SIP_REG_TMR_WAIT */ ccsip_handle_ev_standby_keepalive_tmr_expire,
+ /* E_SIP_REG_TMR_RETRY */ ccsip_handle_ev_tmr_retry,
+ /* E_SIP_REG_CLEANUP */ sip_regmgr_ev_default,
+ },
+
+ /* SIP_REG_STATE_IN_FALLBACK
+ */
+ {
+ /* E_SIP_REG_REG_REQ */ sip_regmgr_ev_default,
+ /* E_SIP_REG_CANCEL */ sip_regmgr_ev_cancel,
+ /* E_SIP_REG_1xx */ ccsip_handle_ev_1xx,
+ /* E_SIP_REG_2xx */ sip_regmgr_ev_in_fallback_2xx,
+ /* E_SIP_REG_3xx */ sip_regmgr_ev_default,
+ /* E_SIP_REG_4xx */ sip_regmgr_ev_fallback_retry,
+ /* E_SIP_REG_FAILURE_RESPONSE */ sip_regmgr_ev_fallback_retry,
+ /* E_SIP_REG_TMR_ACK */ sip_regmgr_ev_tmr_ack_retry,
+ /* E_SIP_REG_TMR_EXPIRE */ sip_regmgr_ev_default,
+ /* E_SIP_REG_TMR_WAIT */ sip_regmgr_ev_default,
+ /* E_SIP_REG_TMR_RETRY */ sip_regmgr_ev_tmr_ack_retry,
+ /* E_SIP_REG_CLEANUP */ sip_regmgr_ev_default,
+ },
+ /* SIP_REG_STATE_STABILITY_CHECK
+ */
+ {
+ /* E_SIP_REG_REG_REQ */ sip_regmgr_ev_default,
+ /* E_SIP_REG_CANCEL */ sip_regmgr_ev_cancel,
+ /* E_SIP_REG_1xx */ ccsip_handle_ev_1xx,
+ /* E_SIP_REG_2xx */ sip_regmgr_ev_stability_check_2xx,
+ /* E_SIP_REG_3xx */ sip_regmgr_ev_default,
+ /* E_SIP_REG_4xx */ sip_regmgr_ev_default,
+ /* E_SIP_REG_FAILURE_RESPONSE */ sip_regmgr_ev_default,
+ /* E_SIP_REG_TMR_ACK */ sip_regmgr_ev_tmr_ack_retry,
+ /* E_SIP_REG_TMR_EXPIRE */ sip_regmgr_ev_default,
+ /* E_SIP_REG_TMR_WAIT */ sip_regmgr_ev_stability_check_tmr_wait,
+ /* E_SIP_REG_TMR_RETRY */ sip_regmgr_ev_tmr_ack_retry,
+ /* E_SIP_REG_CLEANUP */ sip_regmgr_ev_default,
+ },
+ /* SIP_REG_STATE_TOKEN_WAIT
+ */
+ {
+ /* E_SIP_REG_REG_REQ */ sip_regmgr_ev_default,
+ /* E_SIP_REG_CANCEL */ sip_regmgr_ev_default,
+ /* E_SIP_REG_1xx */ ccsip_handle_ev_1xx,
+ /* E_SIP_REG_2xx */ sip_regmgr_ev_token_wait_2xx,
+ /* E_SIP_REG_3xx */ sip_regmgr_ev_default,
+ /* E_SIP_REG_4xx */ ccsip_handle_ev_4xx,
+ /* E_SIP_REG_FAILURE_RESPONSE */ ccsip_handle_ev_failure_response,
+ /* E_SIP_REG_TMR_ACK */ sip_regmgr_ev_tmr_ack_retry,
+ /* E_SIP_REG_TMR_EXPIRE */ sip_regmgr_ev_default,
+ /* E_SIP_REG_TMR_WAIT */ sip_regmgr_ev_token_wait_tmr_wait,
+ /* E_SIP_REG_TMR_RETRY */ sip_regmgr_ev_tmr_ack_retry,
+ /* E_SIP_REG_CLEANUP */ sip_regmgr_ev_cleanup,
+ }
+};
+
+/*
+ * This function gets the supported option tags from the 200 OK response
+ * to the REG message sent.
+ */
+void
+sip_get_supported_options_2xx (ccsipCCB_t *ccb, sipMessage_t *response)
+{
+ const char *supported;
+
+ ccb->supported_tags = 0;
+ supported = sippmh_get_cached_header_val(response, SUPPORTED);
+ if (supported != NULL) {
+ /*
+ * Supported header is found, find the interrested supported
+ * function from 2xx response from the REG msg. sent. Note that
+ * the sippmh_parse_supported_require() can be used but
+ * decided to minimize the impact on performance parsing all other
+ * tags that are not interested during registration times and
+ * vice versa making changes to sippmh_parse_supported_require()
+ * to parse the tags that are not interested for other messages
+ * also impact the processing time for other messages.
+ */
+ if (strcasestr(supported, REQ_SUPP_PARAM_CISCO_SRTP_FALLBACK)) {
+ /* cisco SRTP fallback is supported by the other end */
+ ccb->supported_tags |= cisco_srtp_fallback_tag;
+ }
+ }
+}
+
+/*
+ * This function starts the Register message
+ * ack timer. If no response is received from
+ * the register message within four minutes,
+ * this timer will pop and resend the Register
+ * message.
+ */
+void
+sip_start_ack_timer (ccsipCCB_t *ccb)
+{
+ uint16_t ack_timer_index;
+
+ if (ccb->index == REG_BACKUP_CCB) {
+ ack_timer_index = MAX_REG_LINES;
+ } else {
+ ack_timer_index = ccb->dn_line - 1;
+ }
+
+ CCSIP_DEBUG_REG_STATE( DEB_L_C_F_PREFIX " ccb->index=%d ack_timer_index=%d ",
+ DEB_L_C_F_PREFIX_ARGS(SIP_STATE, ccb->dn_line, 0, "sip_start_ack_timer"),
+ ccb->index, ack_timer_index);
+
+ if (cprStartTimer(ack_tmrs[ack_timer_index], SIP_REG_TMR_ACK_TICKS,
+ (void *)(long)ccb->index) == CPR_FAILURE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ "sip_start_ack_timer", "cprStartTimer");
+ }
+}
+
+
+/*
+ * This function stops the Register message
+ * ack timer.
+ */
+void
+sip_stop_ack_timer (ccsipCCB_t *ccb)
+{
+ uint16_t ack_timer_index;
+
+ if (ccb->index == REG_BACKUP_CCB) {
+ ack_timer_index = MAX_REG_LINES;
+ } else {
+ ack_timer_index = ccb->dn_line - 1;
+ }
+
+ CCSIP_DEBUG_REG_STATE( DEB_L_C_F_PREFIX " ccb->index=%d ack_timer_index=%d ",
+ DEB_L_C_F_PREFIX_ARGS(SIP_STATE, ccb->dn_line, 0, "sip_stop_ack_timer"),
+ ccb->index, ack_timer_index);
+
+ if (cprCancelTimer(ack_tmrs[ack_timer_index]) == CPR_FAILURE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ "sip_stop_ack_timer", "cprCancelTimer");
+ }
+}
+
+
+void
+sip_reg_sm_change_state (ccsipCCB_t *ccb, sipRegSMStateType_t new_state)
+{
+ if (g_disable_mass_reg_debug_print == FALSE) {
+ CCSIP_DEBUG_REG_STATE(DEB_L_C_F_PREFIX"Registration state change: %s ---> "
+ "%s\n", DEB_L_C_F_PREFIX_ARGS(SIP_STATE, ccb->index, ccb->dn_line, "sip_reg_sm_change_state"),
+ sip_util_reg_state2string((sipRegSMStateType_t)ccb->state),
+ sip_util_reg_state2string(new_state));
+ }
+ ccb->state = (sipSMStateType_t) new_state;
+
+ if (ccb->index == REG_CCB_START) {
+ if ((new_state > SIP_REG_STATE_REGISTERED) || (!refresh_reg_msg)) {
+ dump_reg_msg = TRUE;
+ } else {
+ dump_reg_msg = FALSE;
+ }
+ }
+}
+
+
+void
+ccsip_handle_ev_reg_req (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ static const char fname[] = "ccsip_handle_ev_reg_req";
+ char line_name[MAX_LINE_NAME_SIZE];
+ int value;
+
+ config_get_value(CFGID_PROXY_REGISTER, &value, sizeof(value));
+ if (value == 0) {
+ ui_set_sip_registration_state(ccb->dn_line, FALSE);
+ CCSIP_DEBUG_REG_STATE(get_debug_string(DEBUG_REG_DISABLED),
+ ccb->index, ccb->dn_line, fname);
+
+ return;
+ }
+
+ ccsip_register_clear_all_logs();
+
+ sip_stop_ack_timer(ccb);
+ sip_start_ack_timer(ccb);
+
+ (void) sip_platform_register_expires_timer_stop(ccb->index);
+
+
+ sip_util_get_new_call_id(ccb);
+
+ ccb->authen.cred_type = 0;
+ ccb->retx_counter = 0;
+ config_get_line_string(CFGID_LINE_NAME, line_name, ccb->dn_line,
+ sizeof(line_name));
+
+ config_get_value(CFGID_TIMER_REGISTER_EXPIRES, &ccb->reg.tmr_expire,
+ sizeof(ccb->reg.tmr_expire));
+ ccb->reg.act_time = (int) time(NULL);
+
+ if (sipSPISendRegister(ccb, 0, line_name, ccb->reg.tmr_expire) != TRUE) {
+ // set expire timer and cleanup ccb in non-ccm mode.
+ // do not change the expire timer value in ccm mode
+ if (ccb->cc_type != CC_CCM) {
+ ccsip_register_cleanup(ccb, TRUE);
+ }
+ log_clear(LOG_REG_MSG);
+ log_msg(LOG_REG_MSG);
+ }
+
+ sip_reg_sm_change_state(ccb, SIP_REG_STATE_REGISTERING);
+}
+
+
+
+void
+ccsip_handle_ev_default (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ if ((event->type == (int) E_SIP_REG_CANCEL) && (ccb->state == (int) SIP_REG_STATE_IDLE)) {
+ (void) sip_platform_register_expires_timer_stop(ccb->index);
+ ccb->authen.cred_type = 0;
+ ccb->retx_counter = 0;
+ ccb->reg.tmr_expire = 0;
+ ccb->reg.act_time = 0;
+ ccsip_register_cleanup(ccb, FALSE);
+ }
+
+ /* only free SIP messages, timeouts are internal */
+ if (event->type < (int) E_SIP_REG_TMR_ACK) {
+ free_sip_message(event->u.pSipMessage);
+ }
+}
+
+
+void
+ccsip_handle_ev_tmr_expire (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ // Initiate registration if prime line or not in failover state
+ if ((!CCM_Failover_Table.failover_started) ||
+ (ccb->index == REG_CCB_START)) {
+ /*If the phone is registered with CSPS, the failover_started flag
+ * will always be false. Therefore, this code will always be
+ * executed. */
+
+ /* Cleanup and re-initialize CCB */
+ sip_sm_call_cleanup(ccb);
+
+ refresh_reg_msg = TRUE;
+ /* send a message to the SIP_REG SM to initiate registration */
+ if (ccsip_register_send_msg(SIP_REG_REQ, ccb->index) != SIP_REG_OK) {
+ ccsip_register_cleanup(ccb, TRUE);
+ }
+ } else {
+ ccsip_handle_ev_default(ccb, event);
+ }
+}
+
+void
+ccsip_handle_ev_idle_tmr_expire (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+
+ if (ccb->cc_type == CC_CCM) {
+ if (ccb->index == REG_BACKUP_CCB) {
+ ccsip_handle_ev_tmr_expire(ccb, event);
+ } else {
+ ccsip_handle_ev_default(ccb, event);
+ }
+ } else {
+ /* assuming CSPS */
+ /* Cleanup and re-initialize CCB */
+ sip_sm_call_cleanup(ccb);
+
+ /* send a message to the SIP_REG SM to initiate registration */
+ if (ccsip_register_send_msg(SIP_REG_REQ, ccb->index) != SIP_REG_OK) {
+ ccsip_register_cleanup(ccb, TRUE);
+ }
+ }
+}
+
+
+void
+ccsip_handle_ev_tmr_ack (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ log_clear(LOG_REG_AUTH_ACK_TMR);
+ log_msg(LOG_REG_AUTH_ACK_TMR);
+
+ if (ccb->cc_type == CC_CCM) {
+ /*
+ * regmgr - Send tmr ack event to the regmgr/
+ */
+ sip_regmgr_ev_tmr_ack_retry(ccb, event);
+ } else {
+ /*
+ * regmgr - Assume it is csps
+ */
+ /* Cleanup and re-initialize CCB */
+ sip_sm_call_cleanup(ccb);
+ /* send a message to the SIP_REG SM to initiate registration */
+ if (ccsip_register_send_msg(SIP_REG_REQ, ccb->index) != SIP_REG_OK) {
+ ccsip_register_cleanup(ccb, TRUE);
+ }
+ }
+}
+
+
+void
+ccsip_handle_ev_1xx (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ static const char fname[] = "ccsip_handle_ev_1xx";
+ sipMessage_t *response = NULL;
+ int status_code = 0;
+ char status[LOG_MAX_LEN];
+
+ response = event->u.pSipMessage;
+
+ if (sipGetResponseCode(response, &status_code) < 0) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_REG_SIP_RESP_CODE),
+ ccb->index, ccb->dn_line, fname);
+ return;
+ }
+
+ free_sip_message(response);
+
+ switch (status_code) {
+ case SIP_1XX_TRYING:
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_FUNCTION_ENTRY2),
+ ccb->index, ccb->dn_line, fname,
+ sip_util_reg_state2string((sipRegSMStateType_t)ccb->state),
+ "SIP", status_code);
+ return;
+
+ default:
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_FUNCTION_ENTRY2), ccb->index,
+ ccb->dn_line, fname,
+ sip_util_reg_state2string((sipRegSMStateType_t)ccb->state),
+ "SIP BAD", status_code);
+
+ snprintf(status, sizeof(status), "in %d, information", status_code);
+ log_clear(LOG_REG_UNSUPPORTED);
+ log_msg(LOG_REG_UNSUPPORTED, status);
+
+ ccsip_register_cleanup(ccb, TRUE);
+
+ return;
+ }
+}
+
+static boolean
+ccsip_get_exp_time_2xx (ccsipCCB_t *ccb, sipContact_t *contact_info,
+ const char *expires, uint32_t *exp_time_ret)
+{
+ static const char fname[] = "ccsip_get_exp_time_2xx";
+ boolean exp_found = FALSE;
+ char src_addr_str[MAX_IPADDR_STR_LEN];
+ char user[MAX_LINE_NAME_SIZE];
+ int i;
+ uint32_t gmt_time; //TODO convert to time_t
+ //uint32_t diff_time; //TODO convert to time_t
+ int32_t gmt_rc;
+ uint32_t exp_time;
+ uint32_t register_delta;
+
+ /* did the server change the expires time? */
+
+ /*
+ * Form the contact header.
+ * The proxy can return multiple contacts so we will need to see which one
+ * matches this REGISTER.
+ */
+ config_get_value(CFGID_TIMER_REGISTER_EXPIRES, &exp_time, sizeof(uint32_t));
+ if (contact_info != NULL) {
+ ipaddr2dotted(src_addr_str, &ccb->src_addr);
+ config_get_line_string(CFGID_LINE_NAME, user, ccb->dn_line,
+ sizeof(user));
+
+ /* is expires header for this line included in the contact? */
+ for (i = 0; i < contact_info->num_locations; i++) {
+ if ((sippmh_cmpURLStrings(contact_info->locations[i]->genUrl->u.sipUrl->user,
+ user, FALSE) == 0) &&
+ (strcmp(contact_info->locations[i]->genUrl->u.sipUrl->host,
+ src_addr_str) == 0)) {
+ if ((contact_info->params[i].expires > 0) &&
+ (contact_info->params[i].expires < exp_time)) {
+ exp_time = contact_info->params[i].expires;
+ exp_found = TRUE;
+ CCSIP_DEBUG_REG_STATE(get_debug_string(DEBUG_REG_PROXY_EXPIRES),
+ ccb->index, ccb->dn_line, fname);
+ break;
+ }
+ }
+ }
+ }
+
+
+ if (exp_found != TRUE) {
+ //expires param is not found in the CONTACT header
+ // look for Expires header.
+ config_get_value(CFGID_TIMER_REGISTER_EXPIRES, &exp_time,
+ sizeof(exp_time));
+ if (expires) {
+ gmt_rc = gmt_string_to_seconds((char *)expires,
+ (unsigned long *)&gmt_time);
+ if (gmt_rc != -1) {
+ // We only want to update the expires timeout if it is lower
+ // than our predefined threshold. We don't want to allow
+ // people to keep us hung up for infinite periods of time
+ if (gmt_rc == 1) {
+ // We got a numeric entry in the expires field
+ if (gmt_time < exp_time) {
+ exp_time = gmt_time;
+ exp_found = TRUE;
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ * Subtract some user defined period of time to account for network delay
+ * or the possibility that the registration server is down and this
+ * request has to be processed by a backup server after the timeout
+ * occurs. If the user has not defined this value in the config, it
+ * defaults to 5 seconds.
+ */
+ config_get_value(CFGID_TIMER_REGISTER_DELTA, ®ister_delta,
+ sizeof(register_delta));
+
+ /*
+ * Sanity check the register delta value as the proxy could have returned
+ * a much lower registration period in its' response. The minimum
+ * registration expiration is 60 seconds to prevent the phone from being
+ * flooded with msgs.
+ */
+ if ((exp_time - register_delta) < MIN_REGISTRATION_PERIOD) {
+ CCSIP_DEBUG_REG_STATE(DEB_L_C_F_PREFIX
+ "Warning - Registration period received (%d) "
+ "minus configured timer_register_delta (%d) is less than "
+ "%d seconds.\n", DEB_L_C_F_PREFIX_ARGS(SIP_REG, ccb->index, ccb->dn_line, fname), exp_time,
+ register_delta, MIN_REGISTRATION_PERIOD);
+ exp_found = FALSE;
+ } else {
+ exp_time = exp_time - register_delta;
+ exp_found = TRUE;
+ }
+ *exp_time_ret = exp_time;
+ return (exp_found);
+}
+
+/*
+ * Function: ccsip_check_ccm_restarted
+ *
+ * Parameters:
+ * new_reg_ccb - pointer to ccsipCCB_t of REG CCB.
+ * contact_info - Pointer to sipContact_t.
+ *
+ * Description:
+ * The function detects CCM just came up i.e. it sees the phone
+ * registration as a new registration. This means CCM has restarted
+ * between a REG refresh cycle.
+ *
+ * Note:
+ * CCM only sends x-cisco-newreg to the first REG that it sees
+ * from the phone as a new REG. If the phone has more than one lines,
+ * the REG of the rest of the lines will not have the x-cisco-newreg.
+ *
+ * Returns:
+ * TRUE - CCM restarted is detected.
+ * FALSE - CCM restarted is not detected.
+ */
+static boolean
+ccsip_check_ccm_restarted (sipContact_t *contact_info)
+{
+ int i;
+
+ if (contact_info == NULL) {
+ /* No contact info. */
+ return (FALSE);
+ }
+
+ for (i = 0; i < contact_info->num_locations; i++) {
+ if (contact_info->params[i].flags & SIP_CONTACT_PARM_X_CISCO_NEWREG) {
+ /*
+ * CCM or proxy just indicates that it sees the REG
+ * as a new registration to it. This means that the CCM or
+ * proxy has restarted.
+ */
+ return (TRUE);
+ }
+ }
+ return (FALSE);
+}
+
+/*
+ * Function: update_sis_protocol_version
+ *
+ * Parameters:
+ * response - 200 OK message pointer
+ *
+ * Description:
+ * The function parses theupported header in response and updates
+ * SIS protocol version received. If no version is received the default
+ * SEADRAGON version gets updated
+ *
+ * Returns:
+ * void
+ */
+
+void
+update_sis_protocol_version (sipMessage_t *response)
+{
+ const char *supported;
+ char * sipver;
+ supported = sippmh_get_cached_header_val(response, SUPPORTED);
+ if (supported != NULL) {
+ sipver = strcasestr(supported, REQ_SUPP_PARAM_CISCO_SISTAG);
+ if (sipver) {
+ cc_uint32_t major = SIS_PROTOCOL_MAJOR_VERSION_SEADRAGON, minor = 0, addtnl = 0;
+ if ( sscanf ( &sipver[strlen(REQ_SUPP_PARAM_CISCO_SISTAG)], "%d.%d.%d",
+ &major, &minor, &addtnl) == 3) {
+ platSetSISProtocolVer ( major, minor, addtnl,REQ_SUPP_PARAM_CISCO_SISTAG);
+ return;
+ }
+ }
+ }
+ /* All other cases we set the version to 1.0.0 */
+ platSetSISProtocolVer ( SIS_PROTOCOL_MAJOR_VERSION_SEADRAGON, 0, 0,REQ_SUPP_PARAM_CISCO_SISTAG);
+}
+
+void
+update_cme_sis_version (sipMessage_t *response)
+{
+ const char *supported;
+ char * sipver;
+
+ supported = sippmh_get_cached_header_val(response, SUPPORTED);
+ if (supported != NULL) {
+ sipver = strcasestr(supported, REQ_SUPP_PARAM_CISCO_CME_SISTAG);
+ if (sipver) {
+ cc_uint32_t major = 0, minor = 0, addtnl = 0;
+ if ( sscanf( &sipver[strlen(REQ_SUPP_PARAM_CISCO_CME_SISTAG)], "%d.%d.%d",
+ &major, &minor, &addtnl) ==3) {
+ platSetSISProtocolVer(major, minor, addtnl,REQ_SUPP_PARAM_CISCO_CME_SISTAG);
+ }
+ }
+ }
+}
+
+void
+ccsip_handle_ev_2xx (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ static const char fname[] = "ccsip_handle_ev_2xx";
+ sipMessage_t *response = event->u.pSipMessage;
+ const char *pViaHeaderStr = NULL;
+ sipVia_t *via = NULL;
+ uint32_t exp_time;
+ //uint32_t line_feature;
+ int dns_err_code;
+ int nat_enable = 0;
+ int nat_rx_proc_enable = 0;
+ //int last_button_index =0;
+ const char *datehdr = NULL;
+ const char *contact = NULL;
+ const char *expires = NULL;
+ sipContact_t *contact_info = NULL;
+ //line_t line_index = 0;
+ //ccsipCCB_t *line_ccb = NULL;
+
+
+ // Extract Date header and store
+ datehdr = sippmh_get_header_val(response, SIP_HEADER_DATE, NULL);
+ if (datehdr) {
+ // Copy date header in a global variable since it would be needed
+ // to set system time
+ sstrncpy(ccm_date.datestring, datehdr, sizeof(ccm_date.datestring));
+ ccm_date.valid = TRUE;
+
+ // call ntp set time handler (TNP/cnu specific; stub for legacy)
+ // do not call the handler if 2xx is from StdBy CCM
+ // We do not need to set the time when in the browser
+ //if (ccb->index != REG_BACKUP_CCB) {
+ // SipNtpUpdateClockFromCCM();
+ //}
+ }
+
+ contact = sippmh_get_cached_header_val(response, CONTACT);
+ if (contact != NULL) {
+ /* There is a contact header pass it */
+ contact_info = sippmh_parse_contact(contact);
+ }
+
+ /* Update the sip interface protocol version */
+ update_sis_protocol_version(response);
+
+ /*update the CME for the version negotiation feature */
+ update_cme_sis_version(response);
+
+ if (ccb->dn_line == PRIMARY_LINE && ccsip_check_ccm_restarted(contact_info)) {
+ /* CCM has restarted detected */
+ CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"Detected server has restarted via line %d\n",
+ DEB_F_PREFIX_ARGS(SIP_CCM_RESTART, fname), ccb->dn_line);
+ sip_regmgr_ccm_restarted(ccb);
+ }
+
+ sip_stop_ack_timer(ccb);
+ clean_method_request_trx(ccb, sipMethodRegister, TRUE);
+
+ if (ccb->send_reason_header) {
+ ccb->send_reason_header = FALSE;
+ sipUnregisterReason[0] = '\0';
+ }
+
+ /*
+ * Get expiration time. The expriation time are from contact info. or
+ * from the expire header.
+ */
+ expires = sippmh_get_header_val(response, SIP_HEADER_EXPIRES, NULL);
+ if (ccsip_get_exp_time_2xx(ccb, contact_info, expires, &exp_time)
+ == FALSE) {
+ /*
+ * The expire time received in 200OK is smaller than the minimum
+ * allowed. The phone will be unregistered and a message will be
+ * displayed under the Status Messages. The phone will retry to
+ * register after the configured expire-timer interval.
+ */
+ config_get_value(CFGID_TIMER_REGISTER_EXPIRES, &exp_time,
+ sizeof(uint32_t));
+ ccb->reg.tmr_expire = exp_time;
+ ccb->reg.act_time = (int) time(NULL);
+ sip_reg_sm_change_state(ccb, SIP_REG_STATE_UNREGISTERING);
+
+ if (ccsip_register_send_msg(SIP_REG_CANCEL, ccb->index)
+ != SIP_REG_OK) {
+ ccsip_register_cleanup(ccb, FALSE);
+ }
+ (void) sip_platform_register_expires_timer_start(ccb->reg.tmr_expire * 1000,
+ ccb->index);
+ if (contact_info != NULL) {
+ sippmh_free_contact(contact_info);
+ }
+ free_sip_message(response);
+ log_clear(LOG_REG_EXPIRE);
+ log_msg(LOG_REG_EXPIRE);
+ return;
+ }
+
+
+ ccb->reg.registered = 1;
+ sip_reg_sm_change_state(ccb, SIP_REG_STATE_REGISTERED);
+ regall_fail_attempt = FALSE;
+
+ if (ccb->index != REG_BACKUP_CCB) {
+ registration_reject = FALSE;
+ ui_set_sip_registration_state(ccb->dn_line, TRUE);
+ CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"Setting Reg state to TRUE for line=%d\n",
+ DEB_F_PREFIX_ARGS(SIP_REG_STATE, fname), ccb->dn_line);
+ /* Get supported options from the supported header from the response */
+ sip_get_supported_options_2xx(ccb, response);
+ } else {
+ log_clear(LOG_REG_BACKUP);
+ }
+
+
+ if (contact_info != NULL) {
+ sippmh_free_contact(contact_info);
+ }
+
+ ccb->reg.tmr_expire = exp_time;
+
+ ccb->reg.act_time = (int) time(NULL);
+ CCSIP_DEBUG_REG_STATE(DEB_L_C_F_PREFIX"Starting expires timer (%d "
+ "sec)\n", DEB_L_C_F_PREFIX_ARGS(SIP_TIMER, ccb->index, ccb->dn_line, fname),
+ ccb->reg.tmr_expire);
+ (void) sip_platform_register_expires_timer_start(ccb->reg.tmr_expire * 1000,
+ ccb->index);
+
+
+ if (ccb->cc_type == CC_CCM) {
+ /*
+ * regmgr - A 200 OK will reach here only if the state is
+ * REGISTERING, the unreg_200ok eve is handled
+ * separately.
+ */
+ ti_config_table_t *ccm_table_ptr;
+
+ ccm_table_ptr = (ti_config_table_t *) ccb->cc_cfg_table_entry;
+
+ if ((ccm_table_ptr == CCM_Active_Standby_Table.active_ccm_entry) &&
+ start_standby_monitor) {
+ ccsipCCB_t *standby_ccb;
+
+ start_standby_monitor = FALSE;
+ sip_platform_set_ccm_status();
+
+ /*
+ * Kickoff monitoring the standby
+ */
+
+ standby_ccb = sip_sm_get_ccb_by_index(REG_BACKUP_CCB);
+ if (CCM_Active_Standby_Table.standby_ccm_entry) {
+ config_get_value(CFGID_TIMER_REGISTER_EXPIRES,
+ &exp_time, sizeof(uint32_t));
+ standby_ccb->reg.tmr_expire = exp_time;
+ standby_ccb->reg.act_time = (int) time(NULL);
+ sip_reg_sm_change_state(standby_ccb,
+ SIP_REG_STATE_UNREGISTERING);
+ (void) ccsip_register_send_msg(SIP_REG_CANCEL, standby_ccb->index);
+ (void) sip_platform_register_expires_timer_start(standby_ccb->reg.tmr_expire * 1000,
+ standby_ccb->index);
+ }
+ } else if (ccm_table_ptr ==
+ CCM_Active_Standby_Table.standby_ccm_entry) {
+ /*
+ * REGMGR - Update stats Got a 200OK for a expires 0
+ * Keepalive msg to standby, update stats ?
+ */
+ }
+ }
+
+
+ config_get_value(CFGID_NAT_ENABLE, &nat_enable, sizeof(nat_enable));
+ config_get_value(CFGID_NAT_RECEIVED_PROCESSING, &nat_rx_proc_enable,
+ sizeof(nat_rx_proc_enable));
+ if (nat_enable == 1 && nat_rx_proc_enable == 1) {
+ pViaHeaderStr = sippmh_get_cached_header_val(response, VIA);
+ if (pViaHeaderStr != NULL) {
+ via = sippmh_parse_via(pViaHeaderStr);
+ if (via != NULL) {
+ if (via->recd_host != NULL) {
+ cpr_ip_addr_t received_ip;
+
+ memset(&received_ip, 0, sizeof(cpr_ip_addr_t));
+ dns_err_code = dnsGetHostByName(via->recd_host,
+ &received_ip, 100, 1);
+ if (dns_err_code == 0) {
+ util_ntohl(&received_ip, &received_ip);
+ } else {
+ sip_config_get_nat_ipaddr(&received_ip);
+ }
+
+ if (util_compare_ip(&received_ip, &(ccb->src_addr)) == FALSE) {
+ /*
+ * The address the proxy/registration server received
+ * is not the same as the one that we think we have
+ * so we'll update our address and re-register with
+ * the proxy/registration server
+ */
+
+ ccb->reg.rereg_pending = 1;
+
+ // Make sure our running config has the correct
+ // IP address that we got from the proxy server
+ sip_config_set_nat_ipaddr(&received_ip);
+
+ if (ccsip_register_send_msg(SIP_REG_CANCEL, ccb->index)
+ != SIP_REG_OK) {
+ ccsip_register_cleanup(ccb, FALSE);
+ }
+
+ // Update the tel ccb that this reg line belongs to
+ ccb = sip_sm_get_ccb_by_index((line_t)(ccb->index - REG_CCB_START + 1));
+ if (ccb) {
+ ccb->src_addr = received_ip;
+ }
+ }
+ }
+
+ // Cleanup memory
+ sippmh_free_via(via);
+ }
+ }
+ }
+
+ free_sip_message(response);
+}
+
+void
+ccsip_handle_ev_3xx (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ static const char fname[] = "ccsip_handle_ev_3xx";
+ sipMessage_t *response = NULL;
+ int status_code = 0;
+ char status[LOG_MAX_LEN];
+ char user[MAX_LINE_NAME_SIZE];
+ sipUrl_t *url;
+ const char *contact = NULL;
+
+ response = event->u.pSipMessage;
+ clean_method_request_trx(ccb, sipMethodRegister, TRUE);
+
+ if (sipGetResponseCode(response, &status_code) < 0) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_REG_SIP_RESP_CODE),
+ ccb->index, ccb->dn_line, fname);
+ free_sip_message(response);
+ return;
+ }
+
+ switch (status_code) {
+ case SIP_RED_MULT_CHOICES /* 300 */:
+ case SIP_RED_MOVED_PERM /* 301 */:
+ case SIP_RED_MOVED_TEMP /* 302 */:
+ case SIP_RED_USE_PROXY /* 305 */:
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_FUNCTION_ENTRY2),
+ ccb->index, ccb->dn_line, fname,
+ sip_util_reg_state2string((sipRegSMStateType_t)ccb->state),
+ "SIP", status_code);
+
+ sip_sm_200and300_update(ccb, response, status_code);
+
+ /*
+ * Record the Contact header. For 3xx messages we are recording
+ * the Contact header here, not in the sipSPICheckResponse() header,
+ * so that the ACK response to 3xx is sent to the original INVITE
+ * destination (or to the Record-Route specified destination), rather
+ * than to the new 302 Contact
+ */
+ contact = sippmh_get_cached_header_val(response, CONTACT);
+ if (contact) {
+ if (ccb->contact_info) {
+ sippmh_free_contact(ccb->contact_info);
+ }
+ ccb->contact_info = sippmh_parse_contact(contact);
+ }
+
+
+ /*
+ * Check the validity of Contact header
+ */
+ if (!ccb->contact_info) {
+ CCSIP_DEBUG_ERROR("%s: Error: Invalid Contact field. Aborting "
+ "REGISTER.\n", fname);
+ free_sip_message(response);
+ ccsip_register_cleanup(ccb, TRUE);
+ return;
+ }
+
+ if (ccb->contact_info->locations[0]->genUrl->schema == URL_TYPE_SIP) {
+ url = ccb->contact_info->locations[0]->genUrl->u.sipUrl;
+ } else {
+ CCSIP_DEBUG_ERROR("%s: Error: URL is not Sip. Aborting "
+ "REGISTER.\n", fname);
+ free_sip_message(response);
+ ccsip_register_cleanup(ccb, TRUE);
+ return;
+ }
+
+ sstrncpy(ccb->reg.proxy, url->host, MAX_IPADDR_STR_LEN);
+ ccb->reg.port = url->port;
+
+ if (ccb->contact_info) {
+ sippmh_free_contact(ccb->contact_info);
+ ccb->contact_info = NULL;
+ }
+
+ sip_util_get_new_call_id(ccb);
+
+ /*
+ * Send out a new REGISTER
+ */
+ ccb->authen.cred_type = 0;
+ config_get_line_string(CFGID_LINE_NAME, user, ccb->dn_line,
+ sizeof(user));
+
+ if (sipSPISendRegister(ccb, 0, user, ccb->reg.tmr_expire) != TRUE) {
+ ccsip_register_cleanup(ccb, TRUE);
+ free_sip_message(response);
+
+ log_clear(LOG_REG_RED_MSG);
+ log_msg(LOG_REG_RED_MSG);
+ }
+ return;
+
+ default:
+ free_sip_message(event->u.pSipMessage);
+
+ snprintf(status, sizeof(status), "in %d, redirection", status_code);
+ log_clear(LOG_REG_UNSUPPORTED);
+ log_msg(LOG_REG_UNSUPPORTED, status);
+
+ ccsip_register_cleanup(ccb, TRUE);
+ }
+}
+
+
+void
+ccsip_handle_ev_4xx (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ static const char fname[] = "ccsip_handle_ev_4xx";
+ sipMessage_t *response = NULL;
+ int status_code = 0;
+ const char *authenticate = NULL;
+ char user[MAX_LINE_NAME_SIZE];
+ credentials_t credentials;
+ char status[LOG_MAX_LEN];
+ sip_authen_t *sip_authen = NULL;
+ char *author_str = NULL;
+ char uri[MAX_IPADDR_STR_LEN + 10]; /* Proxy IP address string */
+ char tmp_str[STATUS_LINE_MAX_LEN];
+ ti_config_table_t *ccm_table_ptr = NULL;
+
+ ccm_table_ptr = (ti_config_table_t *) ccb->cc_cfg_table_entry;
+
+
+ response = event->u.pSipMessage;
+ clean_method_request_trx(ccb, sipMethodRegister, TRUE);
+
+ if (sipGetResponseCode(response, &status_code) < 0) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_REG_SIP_RESP_CODE),
+ ccb->index, ccb->dn_line, fname);
+ free_sip_message(response);
+ return;
+ }
+
+ /*
+ * Set reject flag if we get 4xx from publisher cucm.
+ * Note: if non-prime dn is congfigured with #, such as 1234##,
+ * then phone will get 404 for that DN, even though the prime DN is
+ * registered.
+ */
+ if (ccm_table_ptr &&
+ ccb->index != REG_BACKUP_CCB) {
+ DEF_DEBUG(DEB_F_PREFIX"Receive 4xx in ccm mode. set registration_reject to TRUE.\n",
+ DEB_F_PREFIX_ARGS(SIP_REG, fname));
+ registration_reject = TRUE;
+ }
+
+ switch (status_code) {
+ case SIP_CLI_ERR_UNAUTH:
+ case SIP_CLI_ERR_PROXY_REQD:
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_FUNCTION_ENTRY2),
+ ccb->index, ccb->dn_line, fname,
+ sip_util_reg_state2string((sipRegSMStateType_t)ccb->state),
+ "SIP", status_code);
+
+ if (cred_get_credentials_r(ccb, &credentials) == FALSE) {
+ CCSIP_DEBUG_REG_STATE(DEB_L_C_F_PREFIX"no more credentials, retry %d, %d\n",
+ DEB_L_C_F_PREFIX_ARGS(SIP_CRED, ccb->index, ccb->dn_line, fname),
+ ccb->authen.retries_401_407,
+ MAX_RETRIES_401);
+
+
+ if (ccb->cc_type == CC_CCM) {
+ sip_regmgr_ev_failure_response(ccb, event);
+ free_sip_message(response);
+ return;
+ }
+ ccsip_register_cleanup(ccb, TRUE);
+ free_sip_message(response);
+
+ log_clear(LOG_REG_AUTH_NO_CRED);
+ log_msg(LOG_REG_AUTH_NO_CRED);
+
+ break;
+ }
+
+ authenticate = sippmh_get_header_val(response, AUTH_HDR(status_code),
+ NULL);
+ if (authenticate) {
+ sip_authen = sippmh_parse_authenticate(authenticate);
+ }
+
+ if (sip_authen) {
+ if (sip_authen->scheme == SIP_DIGEST) {
+ if (authenticate != NULL) {
+ ccb->retx_counter = 0;
+ config_get_line_string(CFGID_LINE_NAME, user, ccb->dn_line,
+ sizeof(user));
+ ccb->authen.cnonce[0] = '\0';
+ snprintf(uri, sizeof(uri), "sip:%s", ccb->reg.proxy); /* proxy */
+ if (sipSPIGenerateAuthorizationResponse(sip_authen, uri,
+ SIP_METHOD_REGISTER,
+ credentials.id,
+ credentials.pw,
+ &author_str,
+ &(ccb->authen.nc_count),
+ ccb)) {
+
+ if (author_str) {
+ if (ccb->authen.authorization != NULL) {
+ cpr_free(ccb->authen.authorization);
+ ccb->authen.authorization = NULL;
+ }
+
+ ccb->authen.authorization =
+ (char *) cpr_malloc(strlen(author_str) *
+ sizeof(char) + 1);
+
+ if (ccb->authen.authorization != NULL) {
+ sstrncpy(ccb->authen.authorization, author_str,
+ strlen(author_str) * sizeof(char) + 1);
+ ccb->authen.status_code = status_code;
+ }
+ cpr_free(author_str);
+ }
+ } else {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ ccb->index, ccb->dn_line, fname,
+ "sipSPIGenerateAuthorizationResponse");
+ }
+
+ if (!sipSPISendRegister(ccb, TRUE, user,
+ ccb->reg.tmr_expire)){
+ ccsip_register_cleanup(ccb, TRUE);
+
+ log_clear(LOG_REG_AUTH_MSG);
+ log_msg(LOG_REG_AUTH_MSG);
+ }
+
+ } else {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ ccb->index, ccb->dn_line, fname,
+ "sippmh_parse_authenticate");
+
+ ccsip_register_cleanup(ccb, TRUE);
+ log_clear(LOG_REG_AUTH_HDR_MSG);
+ log_msg(LOG_REG_AUTH_HDR_MSG);
+ }
+ } else {
+ CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"auth scheme unsupported= %d\n",
+ DEB_F_PREFIX_ARGS(SIP_AUTH, fname), sip_authen->scheme);
+
+ ccsip_register_cleanup(ccb, TRUE);
+ log_clear(LOG_REG_AUTH_SCH_MSG);
+ log_msg(LOG_REG_AUTH_SCH_MSG);
+ }
+ sippmh_free_authen(sip_authen);
+ }
+
+ free_sip_message(response);
+ return;
+
+ case SIP_CLI_ERR_INTERVAL_TOO_SMALL:
+ {
+ int new_expires = MAX_REG_EXPIRES;
+ const char *msg_ptr = NULL;
+ char line_name[MAX_LINE_NAME_SIZE];
+
+ msg_ptr = sippmh_get_header_val(response,
+ (const char *)SIP_HEADER_MIN_EXPIRES,
+ NULL);
+ if (msg_ptr) {
+ new_expires = strtoul(msg_ptr, NULL, 10);
+ }
+
+ //ensure new Min-Expires is > what we set before in Expires
+ if (new_expires > ccb->reg.tmr_expire) {
+ ccb->reg.tmr_expire = new_expires;
+ } else {
+ ccb->reg.tmr_expire = MAX_REG_EXPIRES;
+ }
+
+ //We have to make a fresh request
+ sip_stop_ack_timer(ccb);
+ sip_start_ack_timer(ccb);
+
+ (void) sip_platform_register_expires_timer_stop(ccb->index);
+
+ sip_util_get_new_call_id(ccb);
+
+ ccb->authen.cred_type = 0;
+ ccb->retx_counter = 0;
+ config_get_line_string(CFGID_LINE_NAME, line_name, ccb->dn_line,
+ sizeof(line_name));
+
+ ccb->reg.act_time = (int) time(NULL);
+
+ if (sipSPISendRegister(ccb, 0, line_name, ccb->reg.tmr_expire) != TRUE) {
+ // set expire timer and cleanup ccb in non-ccm mode.
+ // do not change the expire timer value in ccm mode
+
+ if (ccb->cc_type != CC_CCM) {
+ ccsip_register_cleanup(ccb, TRUE);
+ }
+
+ log_clear(LOG_REG_MSG);
+ log_msg(LOG_REG_MSG);
+ }
+
+ //no change in state
+ }
+ free_sip_message(response);
+ return;
+
+
+ /*
+ * 404 (Not Found)
+ * 413 (Request Entity Too Large)
+ * 480 (Temporarily Unavailable)
+ * 486 (Busy here)
+ */
+ case SIP_CLI_ERR_NOT_FOUND:
+ case SIP_CLI_ERR_LARGE_MSG:
+ case SIP_CLI_ERR_NOT_AVAIL:
+ case SIP_CLI_ERR_BUSY_HERE:
+ if (ccb->cc_type == CC_CCM) {
+ if (ccb->state == (int) SIP_REG_STATE_TOKEN_WAIT) {
+ clean_method_request_trx(ccb, sipMethodRefer, TRUE);
+ sip_regmgr_ev_token_wait_4xx_n_5xx(ccb, event);
+ } else {
+ /*
+ * Phone sends a REGISTER message with expires=0 as a
+ * Keepalive msg. Proxy and CCM will respond with a
+ * 200 OK.
+ */
+ if (ccb->index != REG_BACKUP_CCB) {
+ if (ccsip_register_get_register_state() != SIP_REG_UNREGISTERING) {
+ if (((ti_config_table_t *)(ccb->cc_cfg_table_entry)) ||
+ ccb->dn_line == PRIMARY_LINE) {
+ if (platGetPhraseText(STR_INDEX_REGISTRATION_REJECTED,
+ (char *)tmp_str, STATUS_LINE_MAX_LEN - 1)== CPR_SUCCESS) {
+ ui_set_notification(CC_NO_LINE, CC_NO_CALL_ID, tmp_str, 15, FALSE,
+ DEF_NOTIFY_PRI);
+ }
+ }
+ log_clear(STR_INDEX_REGISTRATION_REJECTED);
+ log_msg(STR_INDEX_REGISTRATION_REJECTED);
+ }
+ }
+ if (process_retry_after(ccb, response) == FALSE) {
+ sip_regmgr_ev_failure_response(ccb, event);
+ }
+ }
+ } else {
+ if (process_retry_after(ccb, response) == FALSE) {
+ ccsip_register_cleanup(ccb, TRUE);
+ }
+ }
+ free_sip_message(response);
+ return;
+
+ default:
+ if (ccb->cc_type == CC_CCM) {
+ if (ccb->state == (int) SIP_REG_STATE_TOKEN_WAIT) {
+ clean_method_request_trx(ccb, sipMethodRefer, TRUE);
+ sip_regmgr_ev_token_wait_4xx_n_5xx(ccb, event);
+ } else {
+ sip_regmgr_ev_failure_response(ccb, event);
+ }
+ free_sip_message(response);
+ return;
+ }
+ CCSIP_DEBUG_STATE(get_debug_string(DEBUG_FUNCTION_ENTRY2),
+ ccb->index, ccb->dn_line, fname,
+ sip_util_reg_state2string((sipRegSMStateType_t)ccb->state),
+ "SIP BAD", status_code);
+
+ snprintf(status, sizeof(status), "in %d, client error", status_code);
+ ccsip_register_cleanup(ccb, TRUE);
+
+ snprintf(status, sizeof(status), "in %d, request failure", status_code);
+ log_clear(LOG_REG_UNSUPPORTED);
+ log_msg(LOG_REG_UNSUPPORTED, status);
+ free_sip_message(response);
+ break;
+ }
+
+ if (ccb->reg.rereg_pending != 0) {
+ ccb->reg.rereg_pending = 0;
+ if (ccsip_register_send_msg(SIP_REG_REQ, ccb->index) != SIP_REG_OK) {
+ ccsip_register_cleanup(ccb, TRUE);
+ }
+ }
+}
+
+
+void
+ccsip_handle_ev_failure_response (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ static const char fname[] = "ccsip_handle_ev_failure_response";
+ sipMessage_t *response = NULL;
+ int status_code = 0;
+ char status[LOG_MAX_LEN];
+ sipStatusCodeClass_t code_class = codeClassInvalid;
+ ti_config_table_t *ccm_table_ptr = NULL;
+
+ /*
+ * Set reject flag if we get 5xx/6xx from publisher cucm.
+ */
+ ccm_table_ptr = (ti_config_table_t *) ccb->cc_cfg_table_entry;
+ if (ccm_table_ptr &&
+ ccb->index != REG_BACKUP_CCB) {
+ registration_reject = TRUE;
+ DEF_DEBUG(DEB_F_PREFIX"registration has been rejected. Set registration_reject to TRUE.\n",
+ DEB_F_PREFIX_ARGS(SIP_REG, fname));
+ }
+
+ response = event->u.pSipMessage;
+ clean_method_request_trx(ccb, sipMethodRegister, TRUE);
+
+ if (sipGetResponseCode(response, &status_code) < 0) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_REG_SIP_RESP_CODE),
+ ccb->index, ccb->dn_line, fname);
+ free_sip_message(response);
+ ccsip_register_cleanup(ccb, TRUE);
+ return;
+ }
+
+ code_class = sippmh_get_code_class((uint16_t)status_code);
+
+ log_clear(LOG_REG_AUTH);
+
+ switch (code_class) {
+ case codeClass5xx:
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_REG_SIP_RESP_FAILURE),
+ ccb->index, ccb->dn_line, fname, status_code);
+
+ log_msg(LOG_REG_AUTH_SERVER_ERR, status_code);
+
+ break;
+
+ case codeClass6xx:
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_REG_SIP_RESP_FAILURE),
+ ccb->index, ccb->dn_line, fname, status_code);
+
+ log_msg(LOG_REG_AUTH_GLOBAL_ERR, status_code);
+
+ break;
+
+ default:
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_REG_SIP_RESP_FAILURE),
+ ccb->index, ccb->dn_line, fname, status_code);
+
+ snprintf(status, sizeof(status), "in %d, ??? error", status_code);
+ log_msg(LOG_REG_AUTH_UNKN_ERR, status_code);
+
+ break;
+ }
+
+ if (ccb->cc_type == CC_CCM) {
+ if (ccb->state == (int) SIP_REG_STATE_TOKEN_WAIT) {
+
+ /* Handle only 503 error condition for other errors
+ * use default state
+ */
+ if (status_code == SIP_SERV_ERR_UNAVAIL) {
+ clean_method_request_trx(ccb, sipMethodRefer, TRUE);
+ sip_regmgr_ev_token_wait_4xx_n_5xx(ccb, event);
+ free_sip_message(response);
+ } else {
+ sip_regmgr_ev_default(ccb, event);
+ }
+ return;
+ }
+
+ /* retry registration using value in the Retry-After header
+ * if response code is 503 with Retry-After
+ */
+ if ((status_code == SIP_SERV_ERR_UNAVAIL) &&
+ (process_retry_after(ccb, response) == TRUE)) {
+ free_sip_message(response);
+ return;
+ }
+ /*
+ * regmgr - Pass the event to the regmgr
+ */
+ sip_regmgr_ev_failure_response(ccb, event);
+ free_sip_message(response);
+ } else {
+ /*
+ * Assume CSPS for now
+ */
+
+ switch (status_code) {
+
+ /*
+ * 500 (Server Internal Error)
+ * 503 (Service Unavailable)
+ * 600 (Busy),
+ * 603 (Declined
+ */
+ case SIP_SERV_ERR_INTERNAL:
+ case SIP_SERV_ERR_UNAVAIL:
+
+ case SIP_FAIL_BUSY:
+ case SIP_FAIL_DECLINE:
+ if (process_retry_after(ccb, response) == FALSE) {
+ ccsip_register_cleanup(ccb, TRUE);
+ }
+ free_sip_message(response);
+ return;
+
+ default:
+ break;
+ }
+ ccsip_register_cleanup(ccb, TRUE);
+ free_sip_message(response);
+
+ if (ccb->reg.rereg_pending != 0) {
+ ccb->reg.rereg_pending = 0;
+ if (ccsip_register_send_msg(SIP_REG_REQ, ccb->index)
+ != SIP_REG_OK) {
+ ccsip_register_cleanup(ccb, TRUE);
+ }
+ }
+ }
+}
+
+/*
+ * ccsip_handle_ev_tmr_retry()
+ *
+ * This function is called when registration re-try timer
+ * pops or an ICMP unreachable is received after sending
+ * out the registration. The ICMP unreachable code sets the
+ * retx_counter to MAX to force the code to try the next
+ * proxy in the list. Event.u.usrInfo is set to the IP
+ * address that bounced or -1 if is a timeout.
+ */
+void
+ccsip_handle_ev_tmr_retry (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ static const char fname[] = "ccsip_handle_ev_tmr_retry";
+ boolean start_timer;
+ uint32_t value;
+ int dns_err_code = DNS_ERR_HOST_UNAVAIL;
+ cpr_ip_addr_t ip_addr;
+
+ CPR_IP_ADDR_INIT(ip_addr);
+
+ start_timer = (ccsip_register_get_register_state() == SIP_REG_UNREGISTERING) ?
+ (FALSE) : (TRUE);
+
+ config_get_value(CFGID_SIP_RETX, &value, sizeof(value));
+ if (value > MAX_NON_INVITE_RETRY_ATTEMPTS) {
+ value = MAX_NON_INVITE_RETRY_ATTEMPTS;
+ }
+ if (ccb->retx_counter >= value) {
+ if (ccb->cc_type == CC_CCM /* RAMC Some other state */) {
+ /*
+ * regmgr - Send event to the regmgr
+ */
+ CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"Reached here for ccb->index=%d \n",
+ DEB_F_PREFIX_ARGS(SIP_MSG_SEND, fname), ccb->index);
+ sip_regmgr_ev_tmr_ack_retry(ccb, event);
+ return;
+ } else {
+ /*
+ * Assume CSPS for now
+ */
+ ccb->retx_counter = 0;
+
+ /*
+ * Did the registration msg bounce trying to reach the outbound
+ * proxy (1st check) or did it timeout trying to reach the
+ * outbound proxy (2nd check)?
+ */
+ util_ntohl(&ip_addr, &(event->u.UsrInfo));
+ if (util_compare_ip(&ip_addr, &(ccb->outBoundProxyAddr)) ||
+ ((event->u.UsrInfo.type == CPR_IP_ADDR_INVALID) &&
+ util_check_if_ip_valid(&(ccb->outBoundProxyAddr)))) {
+ /*
+ * If there are more records, reset address to force code
+ * to use next entry. If not then bail.
+ */
+ ccb->outBoundProxyPort = 0;
+ dns_err_code = DNS_OK;
+
+ /*
+ * Trouble reaching the normal proxy. Get another proxy
+ * if records are available
+ */
+ } else if (str2ip(ccb->reg.proxy, &ccb->reg.addr) != 0) {
+ dns_err_code = sipTransportGetServerAddrPort(ccb->reg.proxy,
+ &ccb->reg.addr,
+ (uint16_t *) &ccb->reg.port,
+ &ccb->SRVhandle,
+ TRUE);
+ if (dns_err_code == 0) {
+ util_ntohl(&(ccb->reg.addr), &(ccb->reg.addr));
+ } else {
+ ccb->reg.addr = ip_addr_invalid;
+ }
+
+ /*
+ * Modify destination fields in call back timer struct
+ */
+ (void) sip_platform_msg_timer_update_destination(ccb->index,
+ &(ccb->reg.addr),
+ ccb->reg.port);
+ } else {
+ /* No other proxy to try */
+ dns_err_code = DNS_ERR_HOST_UNAVAIL;
+ }
+
+ /*
+ * Cleanup if unable to find another proxy
+ */
+ if (dns_err_code != DNS_OK) {
+ /*
+ * All retransmit attempts have been exhausted.
+ * Cleanup the call and move to the IDLE state
+ */
+ ccsip_register_cleanup(ccb, start_timer);
+
+ log_clear(LOG_REG_RETRY);
+ log_msg(LOG_REG_RETRY);
+ if ((ccb->index == REG_BACKUP_CCB) &&
+ (ccb->cc_type != CC_CCM)) {
+ log_clear(LOG_REG_BACKUP);
+ log_msg(LOG_REG_BACKUP);
+ }
+ if (ccb->reg.rereg_pending != 0) {
+ ccb->reg.rereg_pending = 0;
+ if (ccsip_register_send_msg(SIP_REG_REQ, ccb->index)
+ != SIP_REG_OK) {
+ ccsip_register_cleanup(ccb, TRUE);
+ }
+ }
+
+ return;
+ }
+ }
+ }
+
+ if (ccb->state != (int) SIP_REG_STATE_REGISTERED) {
+ /*
+ * Handling Retry timer in REGISTERED state is not needed
+ * the event has come due to race condition
+ */
+ ccb->retx_counter++;
+ CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"Resending message: #%d\n",
+ DEB_F_PREFIX_ARGS(SIP_MSG_SEND, fname), ccb->retx_counter);
+
+ if (sipSPISendLastMessage(ccb) != TRUE) {
+ if (ccb->cc_type == CC_CCM) {
+ sip_regmgr_ev_tmr_ack_retry(ccb, event);
+ } else {
+ ccsip_register_cleanup(ccb, start_timer);
+ }
+ return;
+ }
+
+ ccsip_register_retry_timer_start(ccb);
+ }
+
+}
+
+
+void
+ccsip_handle_ev_reg_cancel (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ char user[MAX_LINE_NAME_SIZE];
+ int exp_time = 0;
+
+ ccsip_register_clear_all_logs();
+
+ sip_stop_ack_timer(ccb);
+ sip_start_ack_timer(ccb);
+
+ (void) sip_platform_register_expires_timer_stop(ccb->index);
+
+ sip_util_get_new_call_id(ccb);
+
+ ccb->authen.cred_type = 0;
+ ccb->retx_counter = 0;
+ ccb->reg.tmr_expire = 0;
+ ccb->reg.act_time = 0;
+ config_get_line_string(CFGID_LINE_NAME, user, ccb->dn_line, sizeof(user));
+
+ if (sipSPISendRegister(ccb, 0, user, exp_time) != TRUE) {
+ log_clear(LOG_REG_CANCEL_MSG);
+ log_msg(LOG_REG_CANCEL_MSG);
+ } else if ((ccb->index == REG_BACKUP_CCB) && (ccb->cc_type != CC_CCM)) {
+ log_clear(LOG_REG_BACKUP);
+ log_msg(LOG_REG_BACKUP);
+ }
+
+ sip_reg_sm_change_state(ccb, SIP_REG_STATE_UNREGISTERING);
+}
+
+
+void
+ccsip_handle_ev_unreg_2xx (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ static const char fname[] = "ccsip_handle_ev_unreg_2xx";
+ sipMessage_t *response = event->u.pSipMessage;
+ int timeout;
+
+ free_sip_message(response);
+
+ ccb->reg.registered = 0;
+ ccb->reg.tmr_expire = 0;
+ ccb->reg.act_time = 0;
+ clean_method_request_trx(ccb, sipMethodRegister, TRUE);
+
+ if (ccb->cc_type == CC_CCM) {
+ if (ccb->index == REG_BACKUP_CCB) {
+ /*
+ * Stay in unregistering state and wait for the
+ * expires timer to pop to send the next keepalive.
+ */
+ sip_stop_ack_timer(ccb);
+ if (new_standby_available) {
+ sip_regmgr_replace_standby(ccb);
+ }
+
+ timeout = sip_config_get_keepalive_expires();
+
+ CCSIP_DEBUG_REG_STATE(DEB_L_C_F_PREFIX"Keep alive timer (%d sec)\n",
+ DEB_L_C_F_PREFIX_ARGS(SIP_TIMER, ccb->index, ccb->dn_line, fname), timeout);
+ (void) sip_platform_standby_keepalive_timer_start(timeout * 1000);
+ } else {
+ sip_reg_sm_change_state(ccb, SIP_REG_STATE_IDLE);
+
+ sip_stop_ack_timer(ccb);
+
+ if (ccsip_register_all_unregistered() == TRUE) {
+ ccsip_register_set_register_state(SIP_REG_IDLE);
+ /*
+ * regmgr - FALLBACK: Pick the ccb of the ccm that has
+ * come up (falling back) and post the fallback event,
+ * now that the unregistering is done.
+ * Will commit change after integration with ccm.
+ */
+ }
+ platSetSISProtocolVer(1,0,0,NULL);
+ CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"set[1] the SIS protocol ver to 1.0.0\n",
+ DEB_F_PREFIX_ARGS(SIP_REG, fname));
+ }
+ } else {
+ sip_reg_sm_change_state(ccb, SIP_REG_STATE_IDLE);
+
+ sip_stop_ack_timer(ccb);
+
+ if (ccsip_register_all_unregistered() == TRUE) {
+ ccsip_register_set_register_state(SIP_REG_IDLE);
+ }
+
+ /*
+ * Our unregistration from the proxy has succeeded now we
+ * can reregister again
+ */
+ if (ccb->reg.rereg_pending != 0) {
+ ccb->reg.rereg_pending = 0;
+ if (ccsip_register_send_msg(SIP_REG_REQ, ccb->index)
+ != SIP_REG_OK) {
+ ccsip_register_cleanup(ccb, TRUE);
+ }
+ }
+ platSetSISProtocolVer(1,0,0,NULL);
+ CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"set[2] the SIS protocol ver to 1.0.0\n",
+ DEB_F_PREFIX_ARGS(SIP_REG, fname));
+ }
+}
+
+
+void
+ccsip_handle_ev_unreg_tmr_ack (ccsipCCB_t *ccb, sipSMEvent_t *event)
+{
+ log_clear(LOG_REG_AUTH_UNREG_TMR);
+ log_msg(LOG_REG_AUTH_UNREG_TMR);
+
+ if (ccb->cc_type == CC_CCM) {
+ /*
+ * regmgr - Send tmr ack event to the regmgr
+ */
+ sip_regmgr_ev_tmr_ack_retry(ccb, event);
+ return;
+ }
+ ccsip_register_cleanup(ccb, FALSE);
+ /*
+ * We are unregistering ourselves from the proxy when our own registration
+ * timer has expired. This means that we do not need to complete our
+ * unregistration from the proxy since it is being done automatically.
+ * We can just send our new registration now
+ */
+ if (ccb->reg.rereg_pending != 0) {
+ ccb->reg.rereg_pending = 0;
+ if (ccsip_register_send_msg(SIP_REG_REQ, ccb->index) != SIP_REG_OK) {
+ ccsip_register_cleanup(ccb, TRUE);
+ }
+ }
+}
+
+void
+ccsip_handle_ev_standby_keepalive_tmr_expire (ccsipCCB_t *ccb,
+ sipSMEvent_t *event)
+{
+ /*
+ * regmgr - If there is a fallback ccb in TOKEN_WAIT
+ * state waiting to fallback notify it so it can
+ * continue with the fallback procedure.
+ */
+ if (ccb->cc_type == CC_CCM) {
+ /*
+ * REGMGR - CHECK if this event gets called.
+ * Will get in here only for REG_BACKUP_CCB in
+ * unregistering state i.e, the standby cc which
+ * is periodically monitored.
+ */
+ /*
+ * Stay in unregistering state and post a message
+ * to send another keep-alive message.
+ */
+ (void) sip_platform_standby_keepalive_timer_stop();
+ (void) ccsip_register_send_msg(SIP_REG_CANCEL, ccb->index);
+ } else {
+ ccsip_handle_ev_default(ccb, event);
+ }
+}
+
+int
+sip_reg_sm_process_event (sipSMEvent_t *pEvent)
+{
+ static const char fname[] = "sip_reg_sm_process_event";
+ ccsipCCB_t *ccb = NULL;
+
+ ccb = pEvent->ccb;
+ if (!ccb) {
+ CCSIP_DEBUG_ERROR("%s: Error: ccb is null. Unable to process event "
+ "<%d>\n", fname, pEvent->type);
+ return (-1);
+ }
+
+ /* Unbind UDP ICMP response handler */
+ if ((REG_CHECK_EVENT_SANITY((int) ccb->state, (int) pEvent->type)) &&
+ (REG_EVENT_ACTION(ccb->state, (int) pEvent->type))) {
+ if (dump_reg_msg == TRUE) {
+ DEF_DEBUG(DEB_L_C_F_PREFIX"%s <- %s\n",
+ DEB_L_C_F_PREFIX_ARGS(SIP_REG_STATE, ccb->dn_line, ccb->index, fname),
+ sip_util_reg_state2string((sipRegSMStateType_t)ccb->state),
+ sip_util_reg_event2string((sipRegSMEventType_t)pEvent->type));
+ }
+ REG_EVENT_ACTION(ccb->state, pEvent->type) (ccb, pEvent);
+ } else {
+ /* Invalid State/Event pair */
+ CCSIP_DEBUG_ERROR("%s: Error: illegal state/event pair: (%d <-- %d)\n",
+ fname, ccb->state, pEvent->type);
+ return (-1);
+ }
+
+ return (0);
+}
+
+
+const char *
+sip_util_reg_event2string (sipRegSMEventType_t event)
+{
+ switch (event) {
+ case E_SIP_REG_REG_REQ:
+ return ("E_SIP_REG_REG_REQ");
+
+ case E_SIP_REG_CANCEL:
+ return ("E_SIP_REG_CANCEL");
+
+ case E_SIP_REG_1xx:
+ return ("E_SIP_REG_1xx");
+
+ case E_SIP_REG_2xx:
+ return ("E_SIP_REG_2xx");
+
+ case E_SIP_REG_3xx:
+ return ("E_SIP_REG_3xx");
+
+ case E_SIP_REG_4xx:
+ return ("E_SIP_REG_4xx");
+
+ case E_SIP_REG_FAILURE_RESPONSE:
+ return ("E_SIP_REG_FAILURE_RESPONSE");
+
+ case E_SIP_REG_TMR_EXPIRE:
+ return ("E_SIP_REG_TMR_EXPIRE");
+
+ case E_SIP_REG_TMR_ACK:
+ return ("E_SIP_REG_TMR_ACK");
+
+ case E_SIP_REG_TMR_WAIT:
+ return ("E_SIP_REG_TMR_WAIT");
+
+ case E_SIP_REG_TMR_RETRY:
+ return ("E_SIP_REG_TMR_RETRY");
+
+ case E_SIP_REG_CLEANUP:
+ return ("E_SIP_REG_CLEANUP");
+
+ default:
+ return ("SIP_REG_STATE_UNKNOWN");
+
+ }
+}
+
+
+char *
+sip_util_reg_state2string (sipRegSMStateType_t state)
+{
+ switch (state) {
+ case SIP_REG_STATE_NONE:
+ return ("SIP_REG_STATE_NONE");
+
+ case SIP_REG_STATE_IDLE:
+ return ("SIP_REG_STATE_IDLE");
+
+ case SIP_REG_STATE_REGISTERING:
+ return ("SIP_REG_STATE_REGISTERING");
+
+ case SIP_REG_STATE_REGISTERED:
+ return ("SIP_REG_STATE_REGISTERED");
+
+ case SIP_REG_STATE_UNREGISTERING:
+ return ("SIP_REG_STATE_UNREGISTERING");
+
+ case SIP_REG_STATE_IN_FALLBACK:
+ return ("SIP_REG_STATE_IN_FALLBACK");
+
+ case SIP_REG_STATE_STABILITY_CHECK:
+ return ("SIP_REG_STATE_STABILITY_CHECK");
+
+ case SIP_REG_STATE_TOKEN_WAIT:
+ return ("SIP_REG_STATE_TOKEN_WAIT");
+
+ default:
+ return ("SIP_REG_STATE_UNKNOWN");
+
+ }
+}
+
+
+sipRegSMEventType_t
+ccsip_register_sip2sipreg_event (int sip_event)
+{
+ static const char fname[] = "ccsip_register_sip2sipreg";
+ sipRegSMEventType_t reg_event = E_SIP_REG_NONE;
+
+ switch (sip_event) {
+ case E_SIP_1xx:
+ reg_event = E_SIP_REG_1xx;
+ break;
+
+ case E_SIP_2xx:
+ reg_event = E_SIP_REG_2xx;
+ break;
+
+ case E_SIP_3xx:
+ reg_event = E_SIP_REG_3xx;
+ break;
+
+ case E_SIP_FAILURE_RESPONSE:
+ reg_event = E_SIP_REG_4xx;
+ break;
+
+ default:
+ CCSIP_DEBUG_ERROR("%s: Error: Unknown event.\n", fname);
+ reg_event = E_SIP_REG_NONE;
+ break;
+ }
+ return (reg_event);
+}
+
+
+void
+ccsip_register_timeout_retry (void *data)
+{
+ static const char fname[] = "ccsip_register_timeout_retry";
+ ccsipCCB_t *ccb;
+
+ CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"\n", DEB_F_PREFIX_ARGS(SIP_REG, fname));
+
+ ccb = (ccsipCCB_t *) data;
+ if (ccb == NULL) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "ccsip_register_timeout_retry");
+ return;
+ }
+
+ if (ccsip_register_send_msg(SIP_TMR_REG_RETRY, ccb->index) != SIP_REG_OK) {
+ ccsip_register_cleanup(ccb, TRUE);
+ }
+}
+
+
+/*
+ * timer callback function
+ *
+ * The function will search for the line that set the timer and then
+ * (1) send expire event to sm or
+ * (2) set another 60s timer. The setting of another timer is necessary
+ * because the max ticks for an OS timer is 10m. The expire timer can
+ * be larger. Therefore, set x 1m timers and count down.
+ */
+int
+ccsip_register_send_msg (uint32_t cmd, line_t ndx)
+{
+ static const char fname[] = "ccsip_register_send_msg";
+ ccsip_registration_msg_t *register_msg;
+ ccsipCCB_t *ccb = NULL;
+ CCM_ID ccm_id = UNUSED_PARAM;
+ ti_config_table_t * cc_cfg_table;
+
+ /*
+ * Get the ccm_id type from ccb corresponding to ndx.
+ * Currently, only SIP_TMR_REG_RETRY msg in SIPTaskProcessListEvent is
+ * making use of ccm_id field. No other reg msg make use of ccm_id. Also in
+ * case of SIP_REG_UPDATE, ccm_id will not be determined below but remain
+ * initialized to UNUSED_PARAM because, in case of SIP_REG_UPDATE, ndx is
+ * not ccb->index but number of available lines when lkem is attached.
+ */
+ if (cmd != SIP_REG_UPDATE) {
+ ccb = sip_sm_get_ccb_by_index(ndx);
+ if (ccb != NULL) {
+ cc_cfg_table = (ti_config_table_t *)(ccb->cc_cfg_table_entry);
+ if (cc_cfg_table != NULL) {
+ ccm_id = cc_cfg_table->ti_specific.ti_ccm.ccm_id;
+ }
+ else {
+ CCSIP_DEBUG_ERROR("%s: Error: cc_cfg_table is null.\n", fname);
+ return SIP_ERROR;
+ }
+ }
+ else {
+ CCSIP_DEBUG_ERROR("%s: Error: ccb is null.\n", fname);
+ return SIP_ERROR;
+ }
+ }
+
+ CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"cmd=%d=%s ccb->index=%d ccm_id=%s\n",
+ DEB_F_PREFIX_ARGS(SIP_MSG_SEND, fname),
+ cmd, REG_CMD_PRINT(cmd), ndx, CCM_ID_PRINT(ccm_id));
+
+ register_msg = (ccsip_registration_msg_t *)
+ SIPTaskGetBuffer(sizeof(ccsip_registration_msg_t));
+
+ if (!register_msg) {
+ CCSIP_DEBUG_ERROR("%s: Error: get buffer failed.\n", fname);
+ return SIP_ERROR;
+ }
+ register_msg->ccb_index = ndx;
+ register_msg->ccm_id = ccm_id;
+
+ if (SIPTaskSendMsg(cmd, register_msg, sizeof(ccsip_registration_msg_t), NULL)
+ == CPR_FAILURE) {
+ cpr_free(register_msg);
+ CCSIP_DEBUG_ERROR("%s: Error: send buffer failed.\n", fname);
+ return SIP_ERROR;
+ }
+
+ return SIP_REG_OK;
+}
+
+void
+ccsip_register_retry_timer_start (ccsipCCB_t *ccb)
+{
+ static const char fname[] = "ccsip_register_retry_timer_start";
+ int timeout;
+ int time_t1;
+ int time_t2;
+
+ /* Double the timeout value and do exponential time increases
+ * The doubling is used because the invite timeout is too short
+ */
+ config_get_value(CFGID_TIMER_T1, &time_t1, sizeof(time_t1));
+ timeout = time_t1 * (1 << ccb->retx_counter);
+ config_get_value(CFGID_TIMER_T2, &time_t2, sizeof(time_t2));
+ if (timeout > time_t2) {
+ timeout = time_t2;
+ }
+ CCSIP_DEBUG_REG_STATE(DEB_L_C_F_PREFIX"Starting reTx timer (%d msec)\n",
+ DEB_L_C_F_PREFIX_ARGS(SIP_TIMER, ccb->index, ccb->dn_line, fname), timeout);
+
+ ccb->retx_flag = TRUE;
+ if (sip_platform_msg_timer_start(timeout, (void *)ccb, ccb->index,
+ sipPlatformUISMTimers[ccb->index].message_buffer,
+ sipPlatformUISMTimers[ccb->index].message_buffer_len,
+ sipMethodRegister,
+ &(sipPlatformUISMTimers[ccb->index].ipaddr),
+ sipPlatformUISMTimers[ccb->index].port,
+ TRUE) != SIP_OK) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ ccb->index, ccb->dn_line, fname,
+ "sip_platform_msg_timer_start");
+ ccb->retx_flag = FALSE;
+ }
+}
+
+
+void
+ccsip_register_cleanup (ccsipCCB_t *ccb, boolean start)
+{
+ static const char fname[] = "ccsip_register_cleanup";
+ int exp_time;
+
+ config_get_value(CFGID_TIMER_REGISTER_EXPIRES, &exp_time, sizeof(exp_time));
+
+ ccb->reg.registered = 0;
+
+ if (ccb->index != REG_BACKUP_CCB) {
+ ui_set_sip_registration_state(ccb->dn_line, FALSE);
+ }
+
+ sip_stop_ack_timer(ccb);
+
+ if ((start) && (ccb->state != (int) SIP_REG_STATE_UNREGISTERING)) {
+ if (ccb->index == REG_BACKUP_CCB) {
+ ccb->reg.tmr_expire = (exp_time > 5) ? exp_time - 5 : exp_time;
+ } else {
+ ccb->reg.tmr_expire = 60;
+ }
+ ccb->reg.act_time = (int) time(NULL);
+
+ CCSIP_DEBUG_STATE(DEB_L_C_F_PREFIX"Starting expires timer (%d "
+ "sec)\n", DEB_L_C_F_PREFIX_ARGS(SIP_TIMER, ccb->index, ccb->dn_line, fname),
+ ccb->reg.tmr_expire);
+ (void) sip_platform_register_expires_timer_start(ccb->reg.tmr_expire * 1000,
+ ccb->index);
+ }
+
+ sip_reg_sm_change_state(ccb, SIP_REG_STATE_IDLE);
+
+ if (ccsip_register_all_unregistered() == TRUE) {
+ ccsip_register_set_register_state(SIP_REG_IDLE);
+ }
+
+ /*
+ * Always check how sip_sm_call_cleanup is implemented.
+ * The function has a tendency to change.
+ */
+
+ /* Cleanup and re-initialize CCB */
+ sip_sm_call_cleanup(ccb);
+}
+
+
+cc_int32_t
+ccsip_register_cmd (cc_int32_t argc, const char *argv[])
+{
+ /*
+ * On 7970 phones the command is reg line [option] [line]
+ * On 7940/60 the command is reg [option] [line]
+ * Thus the location in the argument array is different
+ * based on the phone type. OFFSET is used to get around
+ * this difference while still having common code.
+ */
+#define OFFSET 1
+ ccsipCCB_t *ccb = NULL;
+ line_t ndx = 0;
+ line_t temp_line = 0;
+ char str_val[MAX_LINE_NAME_SIZE];
+ const char *line_string;
+ char *strtol_end;
+
+ /*
+ * check if need help
+ */
+ if ((argc == 2 + OFFSET) && (argv[1 + OFFSET][0] == '?')) {
+ debugif_printf("reg [option] [line]\n");
+ debugif_printf(" options = 0: unregister\n");
+ debugif_printf(" 1: register\n");
+ debugif_printf(" line = 1 through 6\n");
+ debugif_printf(" = backup (line 1 to backup proxy)\n");
+ debugif_printf("\n");
+ return (0);
+ }else if (cpr_strcasecmp(argv[0 + OFFSET], "line") == 0) {
+
+ /*
+ make sure the user entered a complete command
+ */
+ if (argc < 3 + OFFSET) {
+ debugif_printf("Incomplete command\n");
+ debugif_printf("reg [option] [line]\n");
+ debugif_printf(" options = 0: unregister\n");
+ debugif_printf(" 1: register\n");
+ debugif_printf(" line = 1 through 6\n");
+ debugif_printf(" = backup (line 1 to backup proxy)\n");
+ debugif_printf("\n");
+ return (0);
+ }
+
+ /* make sure we have at least one line configured */
+ config_get_line_string(CFGID_LINE_NAME, str_val, 1, sizeof(str_val));
+ if ((strcmp(str_val, UNPROVISIONED) == 0) || (str_val[0] == '\0')) {
+ debugif_printf("Error:No lines configured\n");
+ return (0);
+ }
+
+ line_string = argv[2 + OFFSET];
+ if (cpr_strcasecmp(line_string, "backup") == 0) {
+ temp_line = REG_BACKUP_LINE;
+ } else {
+ errno = 0;
+ temp_line = (line_t) strtol(line_string, &strtol_end, 10);
+ if (errno || line_string == strtol_end || !sip_config_check_line(temp_line)) {
+ debugif_printf("Error:Invalid Line\n");
+ return (0);
+ }
+ }
+
+
+ ndx = SIP_REG_REGLINE2LINE(temp_line - 1);
+ ccb = sip_sm_get_ccb_by_index(ndx);
+
+ if (ccb == NULL) {
+ debugif_printf("Unable to retrieve registration information for this line.\n");
+ debugif_printf("Command aborted.\n");
+ return (0);
+ }
+
+ if ((temp_line == REG_BACKUP_LINE) && util_check_if_ip_valid(&(ccb->dest_sip_addr)) == FALSE) {
+ debugif_printf("Backup Proxy is invalid or not configured.\n");
+ return (0);
+ }
+
+ switch (argv[1 + OFFSET][0]) {
+ case '0':
+
+ if (ccb->index != REG_BACKUP_CCB) {
+ ui_set_sip_registration_state(ccb->dn_line, FALSE);
+ }
+
+ if (temp_line != REG_BACKUP_LINE) {
+ debugif_printf("Unregistering line %d\n", temp_line);
+ } else {
+ debugif_printf("Unregistering line 1 to backup proxy\n");
+ }
+ (void) sip_platform_register_expires_timer_stop(ccb->index);
+ sip_stop_ack_timer(ccb);
+
+ if (ccsip_register_send_msg(SIP_REG_CANCEL, ndx) != SIP_REG_OK) {
+ ccsip_register_cleanup(ccb, FALSE);
+ }
+ break;
+
+ case '1':
+
+ /* Cleanup and re-initialize CCB */
+ sip_sm_call_cleanup(ccb);
+
+ if (temp_line != REG_BACKUP_LINE) {
+ debugif_printf("Registering line %d\n", temp_line);
+ } else {
+ debugif_printf("Registering line 1 to backup proxy\n");
+ }
+ (void) ccsip_register_send_msg(SIP_REG_REQ, ndx);
+ break;
+
+ default:
+ debugif_printf("Invalid Option Value - please choose 1 or 0\n");
+ return (0);
+ }
+ }
+ return (0);
+}
+
+/*
+ * Function: build_reg_flags
+ *
+ * Parameters:
+ *
+ * Description: builds a 3 character string representing various flags
+ * for use by the show_reg command
+ *
+ * Returns: none
+ *
+ */
+static void
+build_reg_flags (char *buf, int buf_size, int prox_reg, ccsipCCB_t *ccb,
+ boolean provisioned)
+{
+ sstrncpy(buf, "...", buf_size);
+ if (!provisioned || !prox_reg) {
+ return;
+ }
+
+ buf[1] = '1'; // Set the Provisioned bit
+
+ if (ccb->authen.authorization != NULL) {
+ buf[0] = '1';
+ } else {
+ if (ccb->authen.status_code != 0) {
+ buf[0] = 'x';
+ }
+ }
+ if (ccb->reg.registered) {
+ buf[2] = '1';
+ } else {
+ buf[2] = 'x';
+ }
+}
+
+/*
+ * Function: show_register_data
+ *
+ * Parameters:
+ *
+ * Description: Internal print routine for show_register_cmd. Also
+ * called by reg command
+ *
+ * Returns:
+ *
+ */
+#define TMP_BUF_SIZE 8
+static void
+show_register_data (void)
+{
+ ccsipCCB_t *ccb;
+ char buf[TMP_BUF_SIZE];
+ line_t ndx = 0;
+ int proxy_register = 0;
+ boolean valid_line = FALSE;
+ int timer_count_down = 0;
+
+ config_get_value(CFGID_PROXY_REGISTER, &proxy_register,
+ sizeof(proxy_register));
+
+ debugif_printf("\nLINE REGISTRATION TABLE\nProxy Registration: ");
+ if (proxy_register == 1) {
+ debugif_printf("ENABLED");
+ } else {
+ debugif_printf("DISABLED");
+ }
+ debugif_printf(", state: %s\n",
+ ccsip_register_state_name(ccsip_register_get_register_state()));
+ debugif_printf("line APR state timer expires proxy:port\n");
+ debugif_printf("---- --- ------------- ---------- ---------- ----------------------------\n");
+ for (ndx = REG_CCB_START; ndx <= REG_BACKUP_CCB; ndx++) {
+ ccb = sip_sm_get_ccb_by_index(ndx);
+ valid_line = FALSE;
+ if (ndx == REG_BACKUP_CCB) {
+ valid_line = TRUE;
+ } else {
+ if (sip_config_check_line((line_t)(ndx - TEL_CCB_END))) {
+ valid_line = TRUE;
+ }
+ }
+ // calc the time until registration expires
+ if (ccb && valid_line) {
+ if (!proxy_register || !valid_line) {
+ timer_count_down = 0;
+ } else {
+ if (ccb->reg.act_time == 0) {
+ timer_count_down = 0;
+ } else if ((sipRegSMStateType_t)ccb->state ==
+ SIP_REG_STATE_REGISTERING) {
+ timer_count_down =
+ (SIP_REG_TMR_ACK_TICKS / 1000) -
+ (((int) time(NULL)) - ccb->reg.act_time);
+ } else {
+ timer_count_down = ccb->reg.tmr_expire -
+ (((int) time(NULL)) - ccb->reg.act_time);
+ }
+ }
+
+ /*
+ * Ensure that the timer_count_down value is valid. There
+ * are cases where the phone completes registration before an
+ * SNTP/NTP response is received which makes the act_time and
+ * time(NULL) values inconsistent.
+ */
+ if ((timer_count_down < 0) ||
+ (timer_count_down > ccb->reg.tmr_expire)) {
+
+ timer_count_down = 0;
+ }
+ }
+
+ // build the flag string
+ if (ccb) {
+ build_reg_flags((char *)&buf, TMP_BUF_SIZE, proxy_register,
+ ccb, valid_line);
+ }
+
+ if (ndx != REG_BACKUP_CCB) {
+ debugif_printf("%-4d", ndx - TEL_CCB_END);
+ } else {
+ debugif_printf("1-BU");
+ }
+ if (ccb && valid_line) {
+ debugif_printf(" %-3s %-13s %-10d %-10d %s:%d\n",
+ buf,
+ ccsip_register_reg_state_name((sipRegSMStateType_t)ccb->state),
+ ccb->reg.tmr_expire,
+ timer_count_down,
+ ((ccb->reg.proxy[0] != '\0') ? (ccb->reg.proxy) : ("undefined")),
+ ccb->reg.port);
+ } else {
+ debugif_printf(" %-3s %-13s %-10d %-10d %s:%d\n",
+ buf, "NONE", 0, 0, "undefined", 0);
+ }
+ }
+ debugif_printf("\nNote: APR is Authenticated, Provisioned, Registered\n");
+}
+
+/*
+ * Function: show_register_cmd
+ *
+ * Parameters: argc,argv
+ *
+ * Description: Shows the current registration table
+ *
+ * Returns:
+ *
+ */
+cc_int32_t
+show_register_cmd (cc_int32_t argc, const char *argv[])
+{
+
+ /*
+ * check if need help
+ */
+ if ((argc == 2) && (argv[1][0] == '?')) {
+ debugif_printf("sh reg\n");
+ return (0);
+ }
+ show_register_data();
+
+ return (0);
+}
+
+void
+ccsip_register_clear_all_logs (void)
+{
+ log_clear(LOG_REG_MSG);
+ log_clear(LOG_REG_AUTH);
+ log_clear(LOG_REG_RETRY);
+ log_clear(LOG_REG_UNSUPPORTED);
+}
+
+
+void
+ccsip_register_reset_proxy (void)
+{
+ ccsipCCB_t *ccb;
+ line_t ndx;
+ line_t line_end;
+
+ /*
+ * If this is a restart (phone is resetting) then reset the proxy
+ * string for each line. The proxy string is used to determine
+ * what address to use when registering. The proxy remains the
+ * same throughout a boot cycle and on restarts there is a new
+ * boot cycle so the proxy address is reset.
+ */
+ line_end = 1;
+
+ /*
+ * REG CCBs start after the TEL CCBs.
+ * EG., TEL CCBs are at 1 and 2 and REG CCBs are at 3 and 4.
+ * So, line_end equals the number of lines and then add the TEL_CCB_END
+ * to get the ending of the REG CCBs
+ */
+ line_end += TEL_CCB_END;
+
+ //ccsip_register_lines = line_end - REG_CCB_START + 1;
+ for (ndx = REG_CCB_START; ndx <= line_end; ndx++) {
+ if (sip_config_check_line((line_t)(ndx - TEL_CCB_END))) {
+ ccb = sip_sm_get_ccb_by_index(ndx);
+ if (ccb) {
+ ccb->reg.proxy[0] = '\0';
+ }
+ }
+ }
+
+ //reset backup proxy registration;
+ ccb = sip_sm_get_ccb_by_index(REG_BACKUP_CCB);
+ if (ccb) {
+ ccb->reg.proxy[0] = '\0';
+ }
+}
+
+int
+ccsip_register_init (void)
+{
+ static const char fname[] = "ccsip_register_init";
+ static const char sipAckTimerName[] = "sipAck";
+ int i;
+
+ ccsip_register_set_register_state(SIP_REG_IDLE);
+
+ /*
+ * Create acknowledgement timers
+ */
+ for (i = 0; i < MAX_REG_LINES + 1; i++) {
+ ack_tmrs[i] = cprCreateTimer(sipAckTimerName, SIP_ACK_TIMER,
+ TIMER_EXPIRATION, sip_msgq);
+ if (ack_tmrs[i] == NULL) {
+ CCSIP_DEBUG_ERROR("%s: timer NOT created: %d\n",
+ fname, i);
+ return SIP_ERROR;
+ }
+ }
+
+ // Initialize date holder structure
+ ccm_date.valid = FALSE;
+ ccm_date.datestring[0] = '\0';
+ start_standby_monitor = TRUE;
+
+ return SIP_OK;
+}
+
+
+ccsip_register_states_t
+ccsip_register_get_register_state (void)
+{
+ return (ccsip_register_state);
+}
+
+
+void
+ccsip_register_set_register_state (ccsip_register_states_t state)
+{
+ ccsip_register_state = state;
+}
+
+void
+ccsip_register_cancel (boolean cancel_reg, boolean backup_proxy)
+{
+ static const char fname[] = "ccsip_register_cancel";
+ ccsipCCB_t *ccb;
+ line_t ndx;
+ line_t line_end;
+
+
+ CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"\n", DEB_F_PREFIX_ARGS(SIP_REG, fname));
+
+ if (ccsip_register_get_register_state() == SIP_REG_IDLE) {
+ return;
+ }
+
+ ccsip_register_set_register_state(SIP_REG_UNREGISTERING);
+
+ line_end = 1;
+
+ ui_set_sip_registration_state((line_t) (line_end + 1), FALSE);
+
+ CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"unregistering %d lines\n", DEB_F_PREFIX_ARGS(SIP_REG, fname), line_end);
+
+ /*
+ * REG CCBs start after the TEL CCBs.
+ * EG., TEL CCBs are at 1 and 2 and REG CCBs are at 3 and 4.
+ * So, line_end equals the number of lines and then add the TEL_CCB_END
+ * to get the ending of the REG CCBs
+ */
+ line_end += TEL_CCB_END;
+
+ for (ndx = REG_CCB_START; ndx <= line_end; ndx++) {
+ if (sip_config_check_line((line_t) (ndx - TEL_CCB_END))) {
+ ccb = sip_sm_get_ccb_by_index(ndx);
+ if (!ccb) {
+ continue;
+ }
+ ui_set_sip_registration_state(ccb->dn_line, FALSE);
+
+ CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"cancelling timers, line= %d\n",
+ DEB_F_PREFIX_ARGS(SIP_TIMER, fname), ccb->index);
+ (void) sip_platform_register_expires_timer_stop(ccb->index);
+ sip_stop_ack_timer(ccb);
+
+ if (cancel_reg) {
+ if (ccb->index == REG_CCB_START) {
+ ccb->send_reason_header = TRUE;
+ }
+ if (ccb->index == REG_CCB_START) {
+ ccb->send_reason_header = TRUE;
+ }
+
+ if (ccsip_register_send_msg(SIP_REG_CANCEL, ndx)
+ != SIP_REG_OK) {
+ ccsip_register_cleanup(ccb, FALSE);
+ }
+
+ } else {
+ /* Cleanup and re-initialize CCB */
+ sip_sm_call_cleanup(ccb);
+ if (ndx == line_end) {
+ ccsip_register_set_register_state(SIP_REG_IDLE);
+ }
+ }
+ }
+ }
+
+ if (backup_proxy == FALSE) {
+ return;
+ }
+
+ /* cancel backup registration as well */
+ ccb = sip_sm_get_ccb_by_index(REG_BACKUP_CCB);
+
+ CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"cancelling timers, line= %d\n",
+ DEB_F_PREFIX_ARGS(SIP_TIMER, fname), ccb->index);
+
+ (void) sip_platform_register_expires_timer_stop(ccb->index);
+ sip_stop_ack_timer(ccb);
+
+ if (cancel_reg) {
+ if (ccsip_register_send_msg(SIP_REG_CANCEL, REG_BACKUP_CCB)
+ != SIP_REG_OK) {
+ ccsip_register_cleanup(ccb, FALSE);
+ }
+ } else {
+ /* Cleanup and re-initialize CCB */
+ sip_sm_call_cleanup(ccb);
+ }
+}
+
+
+void
+ccsip_register_all_lines (void)
+{
+ static const char fname[] = "ccsip_register_all_lines";
+ ccsipCCB_t *ccb = 0;
+ line_t ndx;
+ line_t line;
+ line_t line_end = 1;
+ int value = 0;
+ char proxyaddress[MAX_IPADDR_STR_LEN];
+
+ CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"\n", DEB_F_PREFIX_ARGS(SIP_REG, fname));
+
+ /* Do not register if
+ * - no need to register
+ * - and already registered
+ */
+
+ line_end = 1;
+ config_get_value(CFGID_PROXY_REGISTER, &value, sizeof(value));
+ if (value == 0) {
+ CCSIP_DEBUG_REG_STATE(get_debug_string(DEBUG_REG_DISABLED), NULL,
+ NULL, fname);
+
+ // mark all unregistered
+ for (line = 1; line <= line_end; line++) {
+ if (sip_config_check_line(line)) {
+ ui_set_sip_registration_state(line, FALSE);
+ }
+ }
+ ccsip_register_reset_proxy();
+ return;
+ } else if (ccsip_register_get_register_state() == SIP_REG_REGISTERED) {
+ CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"lines already registered\n", DEB_F_PREFIX_ARGS(SIP_REG, fname));
+
+ return;
+ }
+
+
+ ccsip_register_reset_proxy();
+ ccsip_register_set_register_state(SIP_REG_REGISTERING);
+
+ CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"registering %d line%c\n",
+ DEB_F_PREFIX_ARGS(SIP_REG, fname), line_end, line_end > 1 ? 's' : ' ');
+
+ /* register line 1 to the backup proxy.
+ * Start with the backup as DNS lookups hold
+ * the task meaning it could take a while to
+ * register the six regular lines.
+ */
+ ndx = REG_BACKUP_CCB;
+ ccb = sip_sm_get_ccb_by_index(ndx);
+ /* Cleanup and re-initialize CCB */
+ sip_sm_call_cleanup(ccb);
+ if (ccb->cc_type == CC_CCM) {
+ /*
+ * regmgr - Set the Backup (standby ccm) info.
+ */
+ ti_config_table_t *standby_ccm =
+ CCM_Active_Standby_Table.standby_ccm_entry;
+
+ if (standby_ccm) {
+ ti_ccm_t *ti_ccm = &standby_ccm->ti_specific.ti_ccm;
+
+ sip_regmgr_setup_new_standby_ccb(ti_ccm->ccm_id);
+ } else {
+ CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"ERROR: Standby ccm entry is NULL\n",
+ DEB_F_PREFIX_ARGS(SIP_REG, fname));
+ }
+ } else {
+ /*
+ * Assume CSPS since only those two for now.
+ */
+ if (util_check_if_ip_valid(&(ccb->dest_sip_addr))) {
+ CCSIP_DEBUG_REG_STATE(DEB_L_C_F_PREFIX"%d, 0x%x\n",
+ DEB_L_C_F_PREFIX_ARGS(SIP_REG, ccb->index, ccb->dn_line, fname),
+ ndx, ccb);
+
+ ccb->reg.addr = ccb->dest_sip_addr;
+ ccb->reg.port = (uint16_t) ccb->dest_sip_port;
+
+ if (ccb->index == REG_CCB_START) {
+ ccb->send_reason_header = TRUE;
+ } else {
+ ccb->send_reason_header = FALSE;
+ }
+
+ if (ccsip_register_send_msg(SIP_REG_REQ, ndx) != SIP_REG_OK) {
+ ccsip_register_cleanup(ccb, TRUE);
+ }
+ } else {
+ CCSIP_DEBUG_REG_STATE(DEB_L_C_F_PREFIX"%d: Backup Proxy not configured\n",
+ DEB_L_C_F_PREFIX_ARGS(SIP_REG, ccb->index, ccb->dn_line, fname), ndx);
+ }
+ }
+
+ /*
+ * REG CCBs start after the TEL CCBs.
+ * EG., TEL CCBs are at 1 and 2 and REG CCBs are at 3 and 4.
+ * So, line_end equals the number of lines and then add the TEL_CCB_END to
+ * get the ending of the REG CCBs
+ */
+ line_end += TEL_CCB_END;
+
+ DEF_DEBUG(DEB_F_PREFIX"Disabling mass reg state", DEB_F_PREFIX_ARGS(SIP_REG, fname));
+ for (ndx = REG_CCB_START; ndx <= line_end; ndx++) {
+ if (sip_config_check_line((line_t)(ndx - TEL_CCB_END))) {
+ ccb = sip_sm_get_ccb_by_index(ndx);
+ if (!ccb) {
+ continue;
+ }
+
+ CCSIP_DEBUG_REG_STATE(DEB_L_C_F_PREFIX"%d, 0x%x\n",
+ DEB_L_C_F_PREFIX_ARGS(SIP_REG, ccb->index, ccb->dn_line, fname),
+ ndx, ccb);
+
+
+ /*
+ * Clean up and re-initialize the proxy address.
+ * It is possible that the REGISTER can be redirected
+ * and this address needs to be reused for later register attempts.
+ * But, on restarts and re-enabling of registering we reset back
+ * to the original configured proxy
+ */
+ if (ndx == REG_CCB_START || ndx == (line_end)) {
+ g_disable_mass_reg_debug_print = FALSE;
+ } else {
+ g_disable_mass_reg_debug_print = TRUE;
+ }
+ sip_sm_call_cleanup(ccb);
+
+ /*
+ * Look up the name of the proxy
+ */
+ sipTransportGetPrimServerAddress(ccb->dn_line, proxyaddress);
+
+ sstrncpy(ccb->reg.proxy, proxyaddress, MAX_IPADDR_STR_LEN);
+
+ ccb->reg.addr = ccb->dest_sip_addr;
+ ccb->reg.port = (uint16_t) ccb->dest_sip_port;
+
+ if (ccb->index == REG_CCB_START) {
+ ccb->send_reason_header = TRUE;
+ } else {
+ ccb->send_reason_header = FALSE;
+ }
+
+ ui_set_sip_registration_state(ccb->dn_line, FALSE);
+ if (ccsip_register_send_msg(SIP_REG_REQ, ndx) != SIP_REG_OK) {
+ ccsip_register_cleanup(ccb, TRUE);
+ }
+
+ }
+ }
+ g_disable_mass_reg_debug_print = FALSE;
+
+ sip_platform_cc_mode_notify();
+}
+
+
+boolean
+ccsip_register_all_registered (void)
+{
+ ccsipCCB_t *ccb;
+ line_t ndx;
+ line_t line_end;
+
+ line_end = 1;
+
+ /*
+ * REG CCBs start after the TEL CCBs.
+ * EG., TEL CCBs are at 1 and 2 and REG CCBs are at 3 and 4.
+ * So, line_end equals the number of lines and then add the TEL_CCB_END
+ * to get the ending of the REG CCBs
+ */
+ line_end += TEL_CCB_END;
+
+ for (ndx = REG_CCB_START; ndx <= line_end; ndx++) {
+ if (sip_config_check_line((line_t)(ndx - TEL_CCB_END))) {
+ ccb = sip_sm_get_ccb_by_index(ndx);
+
+ if (ccb && (ccb->reg.registered == 0)) {
+ return (FALSE);
+ }
+ }
+ }
+ return (TRUE);
+}
+
+
+boolean
+ccsip_register_all_unregistered (void)
+{
+ ccsipCCB_t *ccb;
+ line_t ndx;
+ line_t line_end;
+
+ line_end = 1;
+
+ /*
+ * REG CCBs start after the TEL CCBs.
+ * EG., TEL CCBs are at 0 and 1 and REG CCBs are at 6 and 7.
+ * So, line_end equals the number of lines and then add the TEL_CCB_END
+ * to get the ending of the REG CCBs
+ */
+ line_end += TEL_CCB_END;
+
+ for (ndx = REG_CCB_START; ndx <= line_end; ndx++) {
+ if (sip_config_check_line((line_t)(ndx - TEL_CCB_END))) {
+ ccb = sip_sm_get_ccb_by_index(ndx);
+
+ if (ccb && (ccb->reg.registered == 1)) {
+ return (FALSE);
+ }
+ }
+ }
+ return (TRUE);
+}
+
+
+void
+ccsip_register_commit (void)
+{
+ static const char fname[] = "ccsip_register_commit";
+ int register_get;
+
+ CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"\n", DEB_F_PREFIX_ARGS(SIP_REG, fname));
+
+ /*
+ * Determine if lines need to register or unregister
+ *
+ * register if
+ * - proxy_register was changed from 0 to 1
+ *
+ * unregister if
+ * - proxy_register was changed from 1 to 0 and already registered
+ */
+ config_get_value(CFGID_PROXY_REGISTER, ®ister_get,
+ sizeof(register_get));
+
+ switch (register_get) {
+ case 0:
+ if (ccsip_register_get_register_state() != SIP_REG_IDLE) {
+ ccsip_register_cancel(TRUE, TRUE);
+ } else {
+ CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"lines already unregistered.\n", DEB_F_PREFIX_ARGS(SIP_REG, fname));
+ }
+
+ break;
+
+ case 1:
+ if (ccsip_register_get_register_state() != SIP_REG_REGISTERED) {
+ ccsip_register_cancel(FALSE, TRUE);
+ ccsip_register_all_lines();
+ } else {
+ CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"lines already registered.\n", DEB_F_PREFIX_ARGS(SIP_REG, fname));
+ }
+ break;
+
+ default:
+ CCSIP_DEBUG_ERROR(DEB_F_PREFIX"Error: invalid register_get= %d\n", DEB_F_PREFIX_ARGS(SIP_REG, fname),
+ register_get);
+ }
+}
+
+void
+ccsip_backup_register_commit (void)
+{
+ static const char fname[] = "ccsip_backup_register_commit";
+ line_t ndx;
+ ccsipCCB_t *ccb = 0;
+
+ CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"\n", DEB_F_PREFIX_ARGS(SIP_REG, fname));
+
+ ndx = REG_BACKUP_CCB;
+ ccb = sip_sm_get_ccb_by_index(ndx);
+
+ /* cancel an existing registration if it exists */
+ if (util_check_if_ip_valid(&(ccb->reg.addr))) {
+ CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"cancelling registration, line= %d\n",
+ DEB_F_PREFIX_ARGS(SIP_REG, fname), ccb->index);
+ if (ccsip_register_send_msg(SIP_REG_CANCEL, ndx) != SIP_REG_OK) {
+ ccsip_register_cleanup(ccb, FALSE);
+ }
+ }
+
+ /* Cleanup and re-initialize CCB */
+ sip_sm_call_cleanup(ccb);
+
+ if (util_check_if_ip_valid(&(ccb->dest_sip_addr))) {
+ CCSIP_DEBUG_REG_STATE(DEB_L_C_F_PREFIX"%d, 0x%x\n",
+ DEB_L_C_F_PREFIX_ARGS(SIP_REG, ccb->index, ccb->dn_line, fname),
+ ndx, ccb);
+ ccb->reg.addr = ccb->dest_sip_addr;
+ ccb->reg.port = (uint16_t) ccb->dest_sip_port;
+
+ if (ccsip_register_send_msg(SIP_REG_REQ, ndx) != SIP_REG_OK) {
+ ccsip_register_cleanup(ccb, TRUE);
+ }
+ } else {
+ log_clear(LOG_REG_BACKUP);
+ }
+}
+
+
+void
+cred_get_line_credentials (line_t line, credentials_t *pcredentials,
+ int id_len, int pw_len)
+{
+ config_get_line_string(CFGID_LINE_AUTHNAME, pcredentials->id, line,
+ id_len);
+
+ if ((strcmp(pcredentials->id, "") == 0) ||
+ (strcmp(pcredentials->id, UNPROVISIONED) == 0)) {
+ config_get_line_string((CFGID_LINE_AUTHNAME), pcredentials->id, 1,
+ id_len);
+ }
+
+ config_get_line_string(CFGID_LINE_PASSWORD, pcredentials->pw, line,
+ pw_len);
+ if ((strcmp(pcredentials->pw, "") == 0) ||
+ (strcmp(pcredentials->pw, UNPROVISIONED) == 0)) {
+ config_get_line_string(CFGID_LINE_PASSWORD, pcredentials->pw, 1,
+ pw_len);
+ }
+}
+
+
+boolean
+cred_get_credentials_r (ccsipCCB_t *ccb, credentials_t *pcredentials)
+{
+ if (!(ccb->authen.cred_type & CRED_LINE) ||
+ (ccb->authen.retries_401_407 < MAX_RETRIES_401)) {
+ ccb->authen.cred_type |= CRED_LINE;
+ ccb->authen.retries_401_407++;
+ cred_get_line_credentials(ccb->dn_line, pcredentials,
+ sizeof(pcredentials->id),
+ sizeof(pcredentials->pw));
+ return (TRUE);
+ }
+
+ return (FALSE);
+}
+
+
+const char *
+ccsip_register_state_name (ccsip_register_states_t state)
+{
+ if ((state < SIP_REG_IDLE) || (state >= SIP_REG_NO_REGISTER)) {
+ return ("UNDEFINED");
+ }
+
+ return (ccsip_register_state_names[state]);
+}
+
+
+const char *
+ccsip_register_reg_state_name (sipRegSMStateType_t state)
+{
+ if ((state < SIP_REG_STATE_NONE) || (state >= SIP_REG_STATE_UNREGISTERING)) {
+ return ("UNDEFINED");
+ }
+
+ return (ccsip_register_reg_state_names[state]);
+}
+
+void
+ccsip_register_shutdown ()
+{
+ int i;
+
+ for (i = 0; i < MAX_REG_LINES + 1; i++) {
+ (void) cprCancelTimer(ack_tmrs[i]);
+ (void) cprDestroyTimer(ack_tmrs[i]);
+ ack_tmrs[i] = NULL;
+ }
+}
+
+boolean
+ccsip_get_ccm_date (char *date_value)
+{
+ if (date_value) {
+ if (ccm_date.valid) {
+ sstrncpy(date_value, ccm_date.datestring,
+ sizeof(ccm_date.datestring));
+ return (TRUE);
+ } else {
+ date_value[0] = '\0';
+ }
+ }
+ return (FALSE);
+}
+
+/*
+ * Function: ccsip_is_line_registered
+ *
+ * Parameters:
+ * dn_line - line number.
+ *
+ * Description: The function determines whether the current line
+ * is registered or not.
+ *
+ * Returns:
+ * TRUE if the line is registered.
+ * FALSE if the line is not registered or the given line is invalid.
+ *
+ */
+boolean
+ccsip_is_line_registered (line_t dn_line)
+{
+ line_t ndx;
+ line_t line_end;
+ ccsipCCB_t *ccb;
+
+ /* Get the number of lines configured */
+ line_end = 1;
+ /*
+ * REG CCBs start after the TEL CCBs.
+ * So, line_end equals the number of lines and then add the TEL_CCB_END
+ * to get the ending of the REG CCBs
+ */
+ line_end += TEL_CCB_END;
+
+ for (ndx = REG_CCB_START; ndx <= line_end; ndx++) {
+ ccb = sip_sm_get_ccb_by_index(ndx);
+ if ((ccb != NULL) && (ccb->dn_line == dn_line)) {
+ /* found the requested REG ccb */
+ if (ccb->state == (int) SIP_REG_STATE_REGISTERED) {
+ return (TRUE);
+ } else {
+ /* the line is not in registered state */
+ break;
+ }
+ }
+ }
+
+ /* Found no matching REG ccb or the line is not in registered state */
+ return (FALSE);
+}
+
+/*
+ * Function: process_retry_after
+ *
+ * Parameters:
+ * ccsipCCB_t *ccb - The reg ccb.
+ * sipMessage_t *response - The received response.
+ *
+ * Description: The function processes the Retry-After header that may
+ * be present in the response.
+ *
+ * Returns:
+ * TRUE if a valid Retry-After header was present and processed correctly.
+ * FALSE if a valid Retry-After header was not present and therefore
+ * was not processed.
+ *
+ */
+boolean
+process_retry_after (ccsipCCB_t *ccb, sipMessage_t *response)
+{
+ const char *msg_ptr = NULL;
+ int32_t retry_after = 0;
+ static const char fname[] = "process_retry_after";
+
+ msg_ptr = sippmh_get_header_val(response,
+ (const char *)SIP_HEADER_RETRY_AFTER,
+ NULL);
+
+ if (msg_ptr) {
+ retry_after = strtoul(msg_ptr, NULL, 10);
+
+ } else {
+ return (FALSE);
+ }
+
+ if (retry_after > 0) {
+ sip_stop_ack_timer(ccb);
+ (void) sip_platform_register_expires_timer_start(retry_after * 1000,
+ ccb->index);
+ CCSIP_DEBUG_REG_STATE(DEB_L_C_F_PREFIX"Retrying after %d\n",
+ DEB_L_C_F_PREFIX_ARGS(SIP_REG, ccb->index, ccb->dn_line, fname), retry_after);
+ return (TRUE);
+ } else {
+ CCSIP_DEBUG_ERROR("REG %d/%d: %-35s: Error: invalid Retry-After "
+ "header in response.\n",
+ ccb->index, ccb->dn_line, fname);
+ return (FALSE);
+ }
+}
+
+
diff --git a/libs/sipcc/core/sipstack/ccsip_reldev.c b/libs/sipcc/core/sipstack/ccsip_reldev.c
new file mode 100644
index 0000000000..24d19abfb1
--- /dev/null
+++ b/libs/sipcc/core/sipstack/ccsip_reldev.c
@@ -0,0 +1,284 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "cpr_types.h"
+#include "cpr_string.h"
+#include "ccsip_reldev.h"
+#include "ccsip_macros.h"
+#include "phone_debug.h"
+#include "ccsip_pmh.h"
+#include "ccsip_messaging.h"
+#include "sip_common_transport.h"
+#include "util_string.h"
+
+/* Constants */
+#define SIP_RRLIST_LENGTH (MAX_TEL_LINES)
+
+/* Global variables */
+sipRelDevMessageRecord_t gSIPRRList[SIP_RRLIST_LENGTH];
+
+
+void
+sipRelDevMessageStore (sipRelDevMessageRecord_t * pMessageRecord)
+{
+ static int counter = 0;
+
+ /* Loop around */
+ if (counter > (SIP_RRLIST_LENGTH - 1)) {
+ counter = 0;
+ }
+
+ gSIPRRList[counter] = *pMessageRecord;
+ gSIPRRList[counter].valid_coupled_message = FALSE;
+ counter++;
+}
+
+
+boolean
+sipRelDevMessageIsDuplicate (sipRelDevMessageRecord_t *pMessageRecord,
+ int *idx)
+{
+ int i = 0;
+
+ for (i = 0; i < SIP_RRLIST_LENGTH; i++) {
+ if ((strcmp(pMessageRecord->call_id, gSIPRRList[i].call_id) == 0) &&
+ (pMessageRecord->cseq_number == gSIPRRList[i].cseq_number) &&
+ (pMessageRecord->cseq_method == gSIPRRList[i].cseq_method) &&
+ (strcasecmp_ignorewhitespace(pMessageRecord->tag, gSIPRRList[i].tag) == 0) &&
+ (strcmp(pMessageRecord->from_user, gSIPRRList[i].from_user) == 0) &&
+ (strcmp(pMessageRecord->from_host, gSIPRRList[i].from_host) == 0) &&
+ (strcmp(pMessageRecord->to_user, gSIPRRList[i].to_user) == 0)) {
+
+ if (pMessageRecord->is_request) {
+ *idx = i;
+ return (TRUE);
+ } else {
+ if (pMessageRecord->response_code == gSIPRRList[i].response_code) {
+ *idx = i;
+ return (TRUE);
+ }
+ }
+ }
+ }
+
+ *idx = -1;
+ return (FALSE);
+}
+
+
+/*
+ * Function: sipRelDevCoupledMessageStore
+ *
+ * Parameters:
+ * pCoupledMessage - pointer to sipMessage_t for the message that
+ * needed reliable delivery store.
+ * call_id - pointer to const. char for the SIP call ID.
+ * cseq_number - the uint32_t for CSeq of the message.
+ * sipMethod_t - sipMethod_t the SIP method of the message.
+ * dest_ipaddr - uint32_t IP address of the destination address.
+ * dest_port - uint16_t destination port
+ * ignore_tag - boolean to ignore tag.
+ *
+ * Description:
+ * The function finds the corresponding entry in the gSIPRRList
+ * array that matches call_id, cseq number, method and possibly tag.
+ * If a match entry is found, the SIP message is composed and stored
+ * in the corresponding entry.
+ *
+ * Returns:
+ * idx - When the entry is found and successfully stored the
+ * SIP message.
+ * RELDEV_NO_STORED_MSG - encounter errors or no message is
+ * stored.
+ */
+int
+sipRelDevCoupledMessageStore (sipMessage_t *pCoupledMessage,
+ const char *call_id,
+ uint32_t cseq_number,
+ sipMethod_t cseq_method,
+ boolean is_request,
+ int response_code,
+ cpr_ip_addr_t *dest_ipaddr,
+ uint16_t dest_port,
+ boolean ignore_tag)
+{
+ static const char *fname = "sipRelDevCoupledMessageStore";
+ int i = 0;
+ char to_tag[MAX_SIP_TAG_LENGTH];
+
+ sipGetMessageToTag(pCoupledMessage, to_tag, MAX_SIP_TAG_LENGTH);
+ CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"Storing for reTx (cseq=%d, method=%s, "
+ "to_tag=<%s>)\n", DEB_F_PREFIX_ARGS(SIP_STORE, fname), cseq_number,
+ sipGetMethodString(cseq_method), to_tag);
+
+ for (i = 0; i < SIP_RRLIST_LENGTH; i++) {
+ if ((strcmp(call_id, gSIPRRList[i].call_id) == 0) &&
+ (cseq_number == gSIPRRList[i].cseq_number) &&
+ (cseq_method == gSIPRRList[i].cseq_method) &&
+ ((ignore_tag) ? TRUE : (strcasecmp_ignorewhitespace(to_tag,
+ gSIPRRList[i].tag)
+ == 0))) {
+ hStatus_t sippmh_write_status = STATUS_FAILURE;
+ uint32_t nbytes = SIP_UDP_MESSAGE_SIZE;
+
+ /*
+ When storing the ACK message check that you are storing it
+ coupled with the correct response code and not transitional responses
+ */
+ if (is_request == FALSE ||
+ (is_request == TRUE && gSIPRRList[i].response_code == response_code)) {
+ gSIPRRList[i].coupled_message.message_buf[0] = '\0';
+ sippmh_write_status =
+ sippmh_write(pCoupledMessage,
+ gSIPRRList[i].coupled_message.message_buf,
+ &nbytes);
+ if (sippmh_write_status == STATUS_FAILURE) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"sippmh_write() failed.\n", fname);
+ return (RELDEV_NO_STORED_MSG);
+ }
+ if ((gSIPRRList[i].coupled_message.message_buf[0] == '\0') ||
+ (nbytes == 0)) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"sippmh_write() returned empty buffer string.\n",
+ fname);
+ return (RELDEV_NO_STORED_MSG);
+ }
+ gSIPRRList[i].coupled_message.message_buf_len = nbytes;
+ gSIPRRList[i].coupled_message.dest_ipaddr = *dest_ipaddr;
+ gSIPRRList[i].coupled_message.dest_port = dest_port;
+ gSIPRRList[i].valid_coupled_message = TRUE;
+ /* Return the stored idx to the caller */
+ return (i);
+ }
+ }
+ }
+ return (RELDEV_NO_STORED_MSG);
+}
+
+/*
+ * Function: sipRelDevGetStoredCoupledMessage
+ *
+ * Parameters:
+ * idx - int for the idx to retrieve stored SIP message.
+ * dest_buffer - pointer to char to retrieve the copy of the
+ * stored SIP message.
+ * dest_buf_size - uint32_t for the size of the dest_buffer.
+ *
+ * Description:
+ * The function gets the stored SIP message for the request entry.
+ *
+ * Returns:
+ * The function returns the number of the bytes of the SIP message
+ * obtained if SIP message is found otherwise it returns zero (
+ * no SIP message available).
+ */
+uint32_t
+sipRelDevGetStoredCoupledMessage (int idx,
+ char *dest_buffer,
+ uint32_t dest_buf_size)
+{
+ sipRelDevMessageRecord_t *record;
+
+ if (dest_buffer == NULL) {
+ /* No destination buffer given, can not provide any result */
+ return (0);
+ }
+ if ((idx < 0) || (idx >= SIP_RRLIST_LENGTH)) {
+ /* the stored message is out of range */
+ return (0);
+ }
+
+ record = &gSIPRRList[idx];
+
+ if (!record->valid_coupled_message) {
+ /* No message stored for the given idx */
+ return (0);
+ }
+ if ((record->coupled_message.message_buf_len > dest_buf_size) ||
+ (record->coupled_message.message_buf_len == 0)) {
+ /*
+ * The stored message size is larger than the give buffer or
+ * stored message length is zero?
+ */
+ return (0);
+ }
+ /* Get the stored message to the caller */
+ memcpy(dest_buffer, &record->coupled_message.message_buf[0],
+ record->coupled_message.message_buf_len);
+ return (record->coupled_message.message_buf_len);
+}
+
+int
+sipRelDevCoupledMessageSend (int idx)
+{
+ static const char *fname = "sipRelDevCoupledMessageSend";
+ char dest_ipaddr_str[MAX_IPADDR_STR_LEN];
+
+ if ((idx < 0) || (idx >= SIP_RRLIST_LENGTH)) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Argument Check: idx (=%d) out of bounds.\n",
+ fname, idx);
+ return SIP_ERROR;
+ }
+
+ if (gSIPRRList[idx].valid_coupled_message) {
+ ipaddr2dotted(dest_ipaddr_str,
+ &gSIPRRList[idx].coupled_message.dest_ipaddr);
+
+ CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"Sending stored coupled message (idx=%d) to "
+ "<%s>:<%d>\n", DEB_F_PREFIX_ARGS(SIP_MSG_SEND, fname), idx, dest_ipaddr_str,
+ gSIPRRList[idx].coupled_message.dest_port);
+ if (sipTransportChannelSend(NULL,
+ gSIPRRList[idx].coupled_message.message_buf,
+ gSIPRRList[idx].coupled_message.message_buf_len,
+ sipMethodInvalid,
+ &(gSIPRRList[idx].coupled_message.dest_ipaddr),
+ gSIPRRList[idx].coupled_message.dest_port,
+ 0) < 0) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"sipTransportChannelSend() failed."
+ " Stored message not sent.\n", fname);
+ return SIP_ERROR;
+ }
+ } else {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Duplicate message detected but failed to"
+ " find valid coupled message. Stored message not sent.\n",
+ fname);
+ return SIP_ERROR;
+ }
+ return SIP_OK;
+}
+
+
+/*
+ * Function for clearing all the messages belonging to the
+ * associated with the specified call_id, from_user, from_host,
+ * and to_user
+ */
+void
+sipRelDevMessagesClear (const char *call_id,
+ const char *from_user,
+ const char *from_host,
+ const char *to_user)
+{
+ int i = 0;
+
+ for (i = 0; i < SIP_RRLIST_LENGTH; i++) {
+ if ((strcmp(call_id, gSIPRRList[i].call_id) == 0) &&
+ (strcmp(from_user, gSIPRRList[i].from_user) == 0) &&
+ (strcmp(from_host, gSIPRRList[i].from_host) == 0) &&
+ (strcmp(to_user, gSIPRRList[i].to_user) == 0)) {
+ memset(&gSIPRRList[i], 0, sizeof(sipRelDevMessageRecord_t));
+ }
+ }
+ return;
+}
+
+/*
+ * Function for clearing all the messages
+ */
+void sipRelDevAllMessagesClear(){
+ int i = 0;
+ for (i = 0; i < SIP_RRLIST_LENGTH; i++) {
+ memset(&gSIPRRList[i], 0, sizeof(sipRelDevMessageRecord_t));
+ }
+ return;
+}
diff --git a/libs/sipcc/core/sipstack/ccsip_sdp.c b/libs/sipcc/core/sipstack/ccsip_sdp.c
new file mode 100644
index 0000000000..763978c3e3
--- /dev/null
+++ b/libs/sipcc/core/sipstack/ccsip_sdp.c
@@ -0,0 +1,354 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * Implements functions to parse and create SDP(Session Description Protocol)
+ * (RFC 2327) messages. Coded to be sufficient for SIP only.
+ * Note: The SDP body fields as per the RFC are :
+ * Optional items are marked with a `*'.
+ *
+ * Session description
+ * v= (protocol version)
+ * o= (owner/creator and session identifier).
+ * s= (session name)
+ * i=* (session information)
+ * u=* (URI of description)
+ * e=* (email address)
+ * p=* (phone number)
+ * c=* (connection information - not required if included in all media)
+ * b=* (bandwidth information)
+ * One or more time descriptions (see below)
+ * z=* (time zone adjustments)
+ * k=* (encryption key)
+ * a=* (zero or more session attribute lines)
+ * Zero or more media descriptions (see below)
+ *
+ *Time description
+ * t= (time the session is active)
+ * r=* (zero or more repeat times)
+ *
+ *Media description
+ * m= (media name and transport address)
+ * i=* (media title)
+ * c=* (connection information - optional if included at session-level)
+ * b=* (bandwidth information)
+ * k=* (encryption key)
+ * a=* (zero or more media attribute lines)
+ *
+ * Note that the mandatory fields are :
+ * v= , o=, s=, t=, m=
+ * Email address and phone number (e=, p=) fields would very soon be useful
+ * to SDP in large scale SIP networks.
+ *
+ * t= 0 0
+ * would indicate an unbound or a permanent session . This would be changed
+ * to specific (or probably user-configured values) once the time duration
+ * of SIP call sessions are recorded and are used for scheduling.
+ */
+
+
+#include "cpr_types.h"
+#include "cpr_memory.h"
+#include "sdp.h"
+#include "text_strings.h"
+#include "ccsip_sdp.h"
+#include "ccsip_core.h"
+#include "phone_debug.h"
+
+
+
+static void *ccsip_sdp_config = NULL; /* SDP parser/builder configuration */
+
+/*
+ * sip_sdp_init
+ *
+ * This function initializes SDP parser with SIP-specific parameters.
+ * This includes supported media, network types, address types,
+ * transports and codecs.
+ *
+ * The function must be called once.
+ *
+ * Returns TRUE - successful
+ * FALSE - failed
+ */
+boolean
+sip_sdp_init (void)
+{
+ ccsip_sdp_config = sdp_init_config();
+ if (!ccsip_sdp_config) {
+ CCSIP_ERR_MSG("sdp_init_config() failure");
+ return FALSE;
+ }
+
+ sdp_media_supported(ccsip_sdp_config, SDP_MEDIA_AUDIO, TRUE);
+ sdp_media_supported(ccsip_sdp_config, SDP_MEDIA_VIDEO, TRUE);
+ sdp_media_supported(ccsip_sdp_config, SDP_MEDIA_APPLICATION, TRUE);
+ sdp_media_supported(ccsip_sdp_config, SDP_MEDIA_DATA, TRUE);
+ sdp_media_supported(ccsip_sdp_config, SDP_MEDIA_CONTROL, TRUE);
+ sdp_media_supported(ccsip_sdp_config, SDP_MEDIA_NAS_RADIUS, TRUE);
+ sdp_media_supported(ccsip_sdp_config, SDP_MEDIA_NAS_TACACS, TRUE);
+ sdp_media_supported(ccsip_sdp_config, SDP_MEDIA_NAS_DIAMETER, TRUE);
+ sdp_media_supported(ccsip_sdp_config, SDP_MEDIA_NAS_L2TP, TRUE);
+ sdp_media_supported(ccsip_sdp_config, SDP_MEDIA_NAS_LOGIN, TRUE);
+ sdp_media_supported(ccsip_sdp_config, SDP_MEDIA_NAS_NONE, TRUE);
+ sdp_media_supported(ccsip_sdp_config, SDP_MEDIA_IMAGE, TRUE);
+ sdp_media_supported(ccsip_sdp_config, SDP_MEDIA_TEXT, TRUE);
+ sdp_nettype_supported(ccsip_sdp_config, SDP_NT_INTERNET, TRUE);
+ sdp_addrtype_supported(ccsip_sdp_config, SDP_AT_IP4, TRUE);
+ sdp_addrtype_supported(ccsip_sdp_config, SDP_AT_IP6, TRUE);
+ sdp_transport_supported(ccsip_sdp_config, SDP_TRANSPORT_RTPAVP, TRUE);
+ sdp_transport_supported(ccsip_sdp_config, SDP_TRANSPORT_UDPTL, TRUE);
+ sdp_require_session_name(ccsip_sdp_config, FALSE);
+
+ return (TRUE);
+}
+
+/*
+ * sipsdp_create()
+ *
+ * Allocate a standard SDP with SIP config and set debug options
+ * based on ccsip debug settings
+ */
+sdp_t *
+sipsdp_create (const char *peerconnection)
+{
+ sdp_t *sdp;
+
+ sdp = sdp_init_description(peerconnection, ccsip_sdp_config);
+ if (!sdp) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"SDP allocation failure\n", __FUNCTION__);
+ return (NULL);
+ }
+
+ /*
+ * Map "ccsip debug events (or info)" to SDP warnings
+ * "ccsip debug errors to SDP errors
+ */
+ CCSIP_INFO_DEBUG {
+ sdp_debug(sdp, SDP_DEBUG_WARNINGS, TRUE);
+ }
+
+ CCSIP_ERR_DEBUG {
+ sdp_debug(sdp, SDP_DEBUG_ERRORS, TRUE);
+ }
+
+
+#ifdef DEBUG_SDP_LIB
+ /*
+ * Enabling this is redundant to the existing message printing
+ * available for the entire SIP text messages, so it is not
+ * enabled here. It is useful for debugging the SDP parser,
+ * however.
+ */
+ CCSIP_MESSAGES_DEBUG {
+ sdp_debug(sdp, SDP_DEBUG_TRACE, TRUE);
+ }
+#endif
+
+ return (sdp);
+}
+
+/*
+ * sipsdp_free()
+ *
+ * Frees the SIP SDP structure, the contained common SDP structure,
+ * and each stream structure in the linked stream list.
+ *
+ * sip_sdp is set to NULL after being freed.
+ */
+void
+sipsdp_free (cc_sdp_t **sip_sdp)
+{
+ const char *fname = "sipsdp_free: ";
+ sdp_result_e sdp_ret;
+
+ if (!*sip_sdp) {
+ return;
+ }
+
+ if ((*sip_sdp)->src_sdp) {
+ sdp_ret = sdp_free_description((*sip_sdp)->src_sdp);
+ if (sdp_ret != SDP_SUCCESS) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"%d while freeing src_sdp\n",
+ fname, sdp_ret);
+ }
+ }
+ if ((*sip_sdp)->dest_sdp) {
+ sdp_ret = sdp_free_description((*sip_sdp)->dest_sdp);
+ if (sdp_ret != SDP_SUCCESS) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"%d while freeing dest_sdp\n",
+ fname, sdp_ret);
+ }
+ }
+
+ SDP_FREE(*sip_sdp);
+}
+
+/*
+ * sipsdp_info_create()
+ *
+ * Allocates and initializes a SIP SDP structure. This function does
+ * not create the src_sdp, dest_sdp, or streams list.
+ *
+ * Returns: pointer to SIP SDP structure - if successful
+ * NULL - failure to allocate storage
+ */
+cc_sdp_t *
+sipsdp_info_create (void)
+{
+ cc_sdp_t *sdp_info = (cc_sdp_t *) cpr_malloc(sizeof(cc_sdp_t));
+
+ if (sdp_info) {
+ sdp_info->src_sdp = NULL;
+ sdp_info->dest_sdp = NULL;
+ }
+
+ return (sdp_info);
+}
+
+
+/*
+ * sipsdp_src_dest_free()
+ *
+ * Frees the SRC and/or DEST SDP. It will also free the sdp_info
+ * structure if both SRC and DEST SDP are freed.
+ *
+ * Input:
+ * flags - bitmask indicating if src and/or dest sdp should be
+ * freed
+ *
+ * Returns:
+ * sdp_info is set to NULL if freed.
+ */
+void
+sipsdp_src_dest_free (uint16_t flags, cc_sdp_t **sdp_info)
+{
+ const char *fname = "sipsdp_src_dest_free: ";
+ sdp_result_e sdp_ret;
+
+ if ((sdp_info == NULL) || (*sdp_info == NULL)) {
+ return;
+ }
+
+ /* Free the SRC and/or DEST SDP */
+ if (flags & CCSIP_SRC_SDP_BIT) {
+ if ((*sdp_info)->src_sdp) {
+ sdp_ret = sdp_free_description((*sdp_info)->src_sdp);
+ if (sdp_ret != SDP_SUCCESS) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"%d while freeing src_sdp\n",
+ fname, sdp_ret);
+ }
+ (*sdp_info)->src_sdp = NULL;
+ }
+ }
+
+ if (flags & CCSIP_DEST_SDP_BIT) {
+ if ((*sdp_info)->dest_sdp) {
+ sdp_ret = sdp_free_description((*sdp_info)->dest_sdp);
+ if (sdp_ret != SDP_SUCCESS) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"%d while freeing dest_sdp\n",
+ fname, sdp_ret);
+ }
+ (*sdp_info)->dest_sdp = NULL;
+ }
+
+ }
+
+ /*
+ * If both src and dest sdp are NULL, there is no need to keep the
+ * sdp_info structure around. Free it.
+ */
+ if (((*sdp_info)->src_sdp == NULL) && ((*sdp_info)->dest_sdp == NULL)) {
+ sipsdp_free(sdp_info);
+ *sdp_info = NULL;
+ }
+}
+
+
+/*
+ * sipsdp_src_dest_create()
+ *
+ * Allocates and initializes a SRC and/or DEST SDP. If the sdp_info
+ * structure has not yet been allocated, it is allocated here.
+ *
+ * Input:
+ * flags - bitmask indicating if src and/or dest sdp should be
+ * created
+ *
+ * Returns: pointer to SIP SDP structure - if successful
+ * NULL - failure to allocate storage
+ */
+void
+sipsdp_src_dest_create (const char *peerconnection,
+ uint16_t flags, cc_sdp_t **sdp_info)
+{
+
+ if (!(*sdp_info)) {
+ *sdp_info = sipsdp_info_create();
+ if (!(*sdp_info)) {
+ return;
+ }
+ }
+
+ /* Create the SRC and/or DEST SDP */
+ if (flags & CCSIP_SRC_SDP_BIT) {
+ (*sdp_info)->src_sdp = sipsdp_create(peerconnection);
+ if (!((*sdp_info)->src_sdp)) {
+ sipsdp_src_dest_free(flags, sdp_info);
+ return;
+ }
+ }
+
+ if (flags & CCSIP_DEST_SDP_BIT) {
+ (*sdp_info)->dest_sdp = sipsdp_create(peerconnection);
+ if (!((*sdp_info)->dest_sdp)) {
+ sipsdp_src_dest_free(flags, sdp_info);
+ return;
+ }
+ }
+}
+
+/*
+ * sipsdp_write_to_buf()
+ *
+ * This function builds the specified SDP in a text buffer and returns
+ * a pointer to this buffer.
+ *
+ * Returns: pointer to buffer - no errors
+ * NULL - errors were encountered while building
+ * the SDP. The details of the build failure
+ * can be determined by enabling SDP debugs
+ * and by examining SDP library error counters.
+ */
+char *
+sipsdp_write_to_buf (cc_sdp_t *sdp_info, uint32_t *retbytes)
+{
+ flex_string fs;
+ // uint32_t sdp_len;
+ sdp_result_e rc;
+
+ flex_string_init(&fs);
+
+ if (!sdp_info || !sdp_info->src_sdp) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"NULL sdp_info or src_sdp\n", __FUNCTION__);
+ return (NULL);
+ }
+
+ if ((rc = sdp_build(sdp_info->src_sdp, &fs))
+ != SDP_SUCCESS) {
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"sdp_build rc=%s\n", DEB_F_PREFIX_ARGS(SIP_SDP, __FUNCTION__),
+ sdp_get_result_name(rc));
+
+ flex_string_free(&fs);
+ *retbytes = 0;
+ return (NULL);
+ }
+
+ *retbytes = fs.string_length;
+
+ /* We are not calling flex_string_free on this, instead returning the buffer
+ * caller's responsibility to free
+ */
+ return fs.buffer;
+}
diff --git a/libs/sipcc/core/sipstack/ccsip_spi_utils.c b/libs/sipcc/core/sipstack/ccsip_spi_utils.c
new file mode 100755
index 0000000000..97ce502d31
--- /dev/null
+++ b/libs/sipcc/core/sipstack/ccsip_spi_utils.c
@@ -0,0 +1,134 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * This file implements a bunch of stuff used only by ccsip_spi.c,
+ * and this is done mostly to reduce the file size and some extra
+ * modularity. Includes things like tables/trees to hold SIP and
+ * CCAPI callids, conversion from CCAPI to SIP cause codes and the
+ * like.
+ */
+#include "plstr.h"
+#include "cpr_types.h"
+#include "cpr_stdlib.h"
+#include "cpr_string.h"
+#include "pmhutils.h"
+#include "ccsip_spi_utils.h"
+#include "util_string.h"
+#include "ccsip_core.h"
+
+extern uint32_t IPNameCk(char *name, char *addr_error);
+
+/*
+ * Checks a token which forms a part of the
+ * domain-name and makes sure that it conforms
+ * to the grammar specified in RFC 1034 (DNS)
+ */
+int
+sipSPICheckDomainToken (char *token)
+{
+ if (token == NULL) {
+ return FALSE;
+ }
+
+ if (*token) {
+ if (isalnum((int)token[strlen(token) - 1]) == FALSE) {
+ return FALSE;
+ }
+ }
+
+ if (isalnum((int)token[0]) == FALSE) {
+ return FALSE;
+ }
+
+ while (*token) {
+ if ((isalnum((int)*token) == FALSE) && (*token != '-')) {
+ return FALSE;
+ }
+ token++;
+ }
+ return TRUE;
+}
+
+/*
+ * Checks domain-name is valid syntax-wise
+ * Returns TRUE, if valid
+ */
+boolean
+sipSPI_validate_hostname (char *str)
+{
+ char *tok;
+ char ip_addr_out[MAX_IPADDR_STR_LEN];
+ char *strtok_state;
+
+ if (str == NULL) {
+ return FALSE;
+ }
+
+ /* Check if valid IPv6 address */
+ if (cpr_inet_pton(AF_INET6, str, ip_addr_out)) {
+ return TRUE;
+ }
+
+ if (*str) {
+ if (isalnum((int)str[strlen(str) - 1]) == FALSE) {
+ return FALSE;
+ }
+ }
+
+ if (isalnum((int)str[0]) == FALSE) {
+ return FALSE;
+ }
+
+ tok = PL_strtok_r(str, ".", &strtok_state);
+ if (tok == NULL) {
+ return FALSE;
+ } else {
+ if (sipSPICheckDomainToken(tok) == FALSE) {
+ return FALSE;
+ }
+ }
+
+ while ((tok = PL_strtok_r(NULL, ".", &strtok_state)) != NULL) {
+ if (sipSPICheckDomainToken(tok) == FALSE) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/*
+ * Determines if the IP address or domain-name is
+ * valid (syntax-wise only)
+ * Returns TRUE, if valid
+ */
+boolean
+sipSPI_validate_ip_addr_name (char *str)
+{
+ uint32_t sip_address;
+ boolean retval = TRUE;
+ char *target = NULL;
+ char addr_error;
+
+ if (str == NULL) {
+ return FALSE;
+ } else {
+ target = cpr_strdup(str);
+ if (!target) {
+ return FALSE;
+ }
+ }
+ sip_address = IPNameCk(target, &addr_error);
+ if ((!sip_address) && (addr_error)) {
+ cpr_free(target);
+ return retval;
+ } else {
+ if (sipSPI_validate_hostname(target) == FALSE) {
+ retval = FALSE;
+ }
+ }
+ cpr_free(target);
+ return retval;
+}
diff --git a/libs/sipcc/core/sipstack/ccsip_subsmanager.c b/libs/sipcc/core/sipstack/ccsip_subsmanager.c
new file mode 100644
index 0000000000..5189eb24c7
--- /dev/null
+++ b/libs/sipcc/core/sipstack/ccsip_subsmanager.c
@@ -0,0 +1,5290 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "cpr_types.h"
+#include "cpr_in.h"
+#include "cpr_stdio.h"
+#include "cpr_stdlib.h"
+#include "cpr_string.h"
+#include "cpr_rand.h"
+#include "ccsip_subsmanager.h"
+#include "util_string.h"
+#include "ccapi.h"
+#include "phone_debug.h"
+#include "ccsip_messaging.h"
+#include "ccsip_platform_udp.h"
+#include "ccsip_macros.h"
+#include "ccsip_task.h"
+#include "sip_common_transport.h"
+#include "ccsip_platform_timers.h"
+#include "platform_api.h"
+#include "ccsip_register.h"
+#include "ccsip_reldev.h"
+#include "phntask.h"
+#include "subapi.h"
+#include "debug.h"
+#include "ccsip_callinfo.h"
+#include "regmgrapi.h"
+#include "text_strings.h"
+#include "configapp.h"
+#include "kpmlmap.h"
+
+/*
+ * Global Variables
+ */
+sipSCB_t subsManagerSCBS[MAX_SCBS]; // Array of SCBS
+sipSubsHistory_t gSubHistory[MAX_SCB_HISTORY];
+sipTimerCallbackFn_t callbackFunctionSubNot = sip_platform_subnot_msg_timer_callback;
+sipTimerCallbackFn_t callbackFunctionPeriodic = sip_platform_subnot_periodic_timer_callback;
+extern sipPlatformUITimer_t sipPlatformUISMSubNotTimers[]; // Array of timers
+const char kpmlRequestAcceptHeader[] = SIP_CONTENT_TYPE_KPML_REQUEST;
+const char kpmlResponseAcceptHeader[] = SIP_CONTENT_TYPE_KPML_RESPONSE;
+const char dialogAcceptHeader[] = SIP_CONTENT_TYPE_DIALOG;
+const char presenceAcceptHeader[] = "application/cpim-pidf+xml";
+const char remoteccResponseAcceptHeader[] = SIP_CONTENT_TYPE_REMOTECC_RESPONSE;
+const char remoteccRequestAcceptHeader[] = SIP_CONTENT_TYPE_REMOTECC_REQUEST;
+
+static sll_handle_t s_TCB_list = NULL; // signly linked list handle of TCBs
+
+// Externs
+extern int dns_error_code; // Global DNS error code
+
+// Status and statistics for the Subscription Manager
+int subsManagerRunning = 0;
+int internalRegistrations = 0;
+
+int incomingSubscribes = 0;
+int incomingRefers = 0;
+int incomingNotifies = 0;
+int incomingUnsolicitedNotifies = 0;
+int incomingSubscriptions = 0;
+
+int outgoingSubscribes = 0;
+int outgoingNotifies = 0;
+int outgoingUnsolicitedNotifies = 0;
+int outgoingSubscriptions = 0;
+
+int currentScbsAllocated = 0;
+int maxScbsAllocated = 0;
+
+#define MAX_SUB_EVENTS 5
+#define MAX_SUB_EVENT_NAME_LEN 16
+/*
+ * sub_id format:
+ *
+ * sub_id is a 32 bit quantity. The bit 32-16 holds a unique ID and
+ * the bits 15-0 holds a SCB index. The following definitions help
+ * support this formation.
+ *
+ * Assumption: The above format assumes that SCB index never be
+ * larger than 16 bit unsigned value.
+ */
+#define SUB_ID_UNIQUE_ID_POSITION 16 /* shift position of unique id part*/
+#define SUB_IDSCB_INDEX_MASK 0xffff /* mask for obtaining scb index */
+#define GET_SCB_INDEX_FROM_SUB_ID(sub_id) \
+ (sub_id & SUB_IDSCB_INDEX_MASK)
+
+/*
+ * Event names
+ */
+const char eventNames[MAX_SUB_EVENTS][MAX_SUB_EVENT_NAME_LEN] =
+{
+ "dialog",
+ "sip-profile",
+ "kpml",
+ "presence",
+ "refer"
+};
+
+/*
+ * Forward Function Declarations
+ */
+boolean sipSPISendSubscribe(sipSCB_t *scbp, boolean renew, boolean authen);
+boolean sipSPISendSubNotify(ccsip_common_cb_t *cbp, boolean authen);
+boolean sipSPISendSubscribeNotifyResponse(sipSCB_t *scbp,
+ uint16_t response_code,
+ uint32_t cseq);
+boolean sipSPISendSubNotifyResponse(sipSCB_t *scbp, int response_code);
+void free_scb(int scb_index, const char *fname);
+
+// External Declarations
+extern uint32_t IPNameCk(char *name, char *addr_error);
+extern void kpml_init(void);
+extern void kpml_shutdown(void);
+
+
+extern void sip_platform_handle_service_control_notify(sipServiceControl_t * scp);
+cc_int32_t show_subsmanager_stats(cc_int32_t argc, const char *argv[]);
+static void show_scbs_inuse(void);
+static void tcb_reset(void);
+
+typedef struct {
+ unsigned long cseq;
+ char *via;
+} sub_not_trxn_t;
+
+/*
+ * Function: find_matching_trxn()
+ *
+ * Parameters: key - key to find the matching node.
+ * data - node data.
+ *
+ * Descriotion: is invoked by sll_find() to find the matching node based on the key.
+ *
+ * Returns: either SLL_MATCH_FOUND or SLL_MATCH_NOT_FOUND.
+ */
+static sll_match_e
+find_matching_trxn (void *key, void *data)
+{
+ unsigned long cseq = *((unsigned long *)key);
+ sub_not_trxn_t *trxn_p = (sub_not_trxn_t *) data;
+
+ if (cseq == trxn_p->cseq) {
+ return SLL_MATCH_FOUND;
+ }
+
+ return SLL_MATCH_NOT_FOUND;
+}
+
+/*
+ * Function: store_incoming_trxn()
+ *
+ * Description: stores the via header in incoming_trxns
+ *
+ * Parameters: via, cseq and scbp
+ *
+ * Returns: TRUE if the via header is successfully stored,
+ * FALSE otherwise.
+ */
+static boolean
+store_incoming_trxn (const char *via, unsigned long cseq, sipSCB_t *scbp)
+{
+ static const char *fname = "store_incoming_trxn";
+ size_t size = 0;
+
+ sub_not_trxn_t *sub_not_trxn_p;
+
+ if (scbp->incoming_trxns == NULL) {
+ scbp->incoming_trxns = sll_create(find_matching_trxn);
+ if (scbp->incoming_trxns == NULL) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"sll_create() failed\n", fname);
+ return FALSE;
+ }
+ }
+ sub_not_trxn_p = (sub_not_trxn_t *)cpr_malloc(sizeof(sub_not_trxn_t));
+ if (sub_not_trxn_p == NULL) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"malloc failed\n", fname);
+ return FALSE;
+ }
+ sub_not_trxn_p->cseq = cseq;
+ size = strlen(via) + 1;
+ sub_not_trxn_p->via = (char *) cpr_malloc(size);
+ if (sub_not_trxn_p->via) {
+ sstrncpy(sub_not_trxn_p->via, via, size);
+ }
+ (void) sll_append(scbp->incoming_trxns, sub_not_trxn_p);
+
+ return TRUE;
+}
+
+void
+free_event_data (ccsip_event_data_t *event_data)
+{
+ ccsip_event_data_t *tmp;
+
+ if (event_data == NULL) {
+ return;
+ }
+
+ while (event_data != NULL) {
+ tmp = event_data->next;
+ if (event_data->type == EVENT_DATA_RAW) {
+ if (event_data->u.raw_data.data)
+ cpr_free(event_data->u.raw_data.data);
+ }
+ cpr_free(event_data);
+ event_data = tmp;
+ }
+}
+
+void
+append_event_data (ccsip_event_data_t * event_data,
+ ccsip_event_data_t *new_data)
+{
+ while (event_data->next != NULL) {
+ event_data = event_data->next;
+ }
+ event_data->next = new_data;
+ new_data->next = NULL;
+}
+
+void
+free_pending_requests (sipspi_msg_list_t *pendingRequests)
+{
+ sipspi_msg_list_t *tmp;
+
+ while (pendingRequests) {
+ switch (pendingRequests->cmd) {
+ case SIPSPI_EV_CC_NOTIFY:
+ {
+ sipspi_notify_t *notify = &(pendingRequests->msg->msg.notify);
+
+ free_event_data(notify->eventData);
+ cpr_free(pendingRequests->msg);
+ }
+ break;
+ case SIPSPI_EV_CC_SUBSCRIBE_REGISTER:
+ cpr_free(&pendingRequests->msg->msg.subs_reg);
+ break;
+ case SIPSPI_EV_CC_SUBSCRIBE:
+ {
+ sipspi_subscribe_t *subs = &(pendingRequests->msg->msg.subscribe);
+
+ free_event_data(subs->eventData);
+ cpr_free(pendingRequests->msg);
+ }
+ break;
+ case SIPSPI_EV_CC_SUBSCRIBE_RESPONSE:
+ cpr_free(pendingRequests->msg);
+ break;
+ case SIPSPI_EV_CC_NOTIFY_RESPONSE:
+ cpr_free(pendingRequests->msg);
+ break;
+ case SIPSPI_EV_CC_SUBSCRIPTION_TERMINATED:
+ cpr_free(pendingRequests->msg);
+ break;
+ default:
+ break;
+ }
+ tmp = pendingRequests;
+ pendingRequests = pendingRequests->next;
+ cpr_free(tmp);
+ }
+}
+
+boolean
+append_pending_requests (sipSCB_t *scbp,
+ sipspi_msg_t *newRequest,
+ uint32_t cmd)
+{
+ static const char *fname = "append_pending_requests";
+ sipspi_msg_list_t *pendingRequest = NULL;
+ sipspi_msg_list_t *tmp = NULL;
+
+ if (!scbp)
+ return (FALSE);
+
+ pendingRequest = (sipspi_msg_list_t *)
+ cpr_malloc(sizeof(sipspi_msg_list_t));
+ if (!pendingRequest) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"malloc failed\n", fname);
+ return (FALSE);
+ }
+ pendingRequest->cmd = cmd;
+ pendingRequest->msg = newRequest;
+ pendingRequest->next = NULL;
+
+ if (scbp->pendingRequests == NULL) {
+ scbp->pendingRequests = pendingRequest;
+ return (TRUE);
+ }
+
+ tmp = scbp->pendingRequests;
+ while (tmp->next != NULL) {
+ tmp = tmp->next;
+ }
+ tmp->next = pendingRequest;
+ return (TRUE);
+}
+
+void
+handle_pending_requests (sipSCB_t *scbp)
+{
+ sipspi_msg_list_t *pendingRequest = NULL;
+
+ if (scbp->pendingRequests) {
+ pendingRequest = scbp->pendingRequests;
+ scbp->pendingRequests = pendingRequest->next;
+ switch (pendingRequest->cmd) {
+ case SIPSPI_EV_CC_NOTIFY:
+ {
+ sipspi_msg_t *notify = pendingRequest->msg;
+
+ cpr_free(pendingRequest);
+ (void) subsmanager_handle_ev_app_notify(notify);
+ cpr_free(notify);
+ }
+ break;
+ case SIPSPI_EV_CC_SUBSCRIBE_REGISTER:
+ cpr_free(pendingRequest->msg);
+ cpr_free(pendingRequest);
+ break;
+ case SIPSPI_EV_CC_SUBSCRIBE:
+ {
+ sipspi_msg_t *subs = pendingRequest->msg;
+
+ cpr_free(pendingRequest);
+ (void) subsmanager_handle_ev_app_subscribe(subs);
+ cpr_free(subs);
+ }
+ break;
+ case SIPSPI_EV_CC_SUBSCRIBE_RESPONSE:
+ {
+ sipspi_msg_t *subs_resp = pendingRequest->msg;
+
+ cpr_free(pendingRequest);
+ (void) subsmanager_handle_ev_app_subscribe_response(subs_resp);
+ cpr_free(subs_resp);
+ }
+ break;
+ case SIPSPI_EV_CC_NOTIFY_RESPONSE:
+ {
+ sipspi_msg_t *not_resp = pendingRequest->msg;
+
+ cpr_free(pendingRequest);
+ (void) subsmanager_handle_ev_app_notify_response(not_resp);
+ cpr_free(not_resp);
+ }
+ break;
+ case SIPSPI_EV_CC_SUBSCRIPTION_TERMINATED:
+ {
+ sipspi_msg_t *term = pendingRequest->msg;
+
+ cpr_free(pendingRequest);
+ (void) subsmanager_handle_ev_app_subscription_terminated(term);
+ cpr_free(term);
+ }
+ break;
+ default:
+ if (pendingRequest->msg) {
+ cpr_free(pendingRequest->msg);
+ }
+ cpr_free(pendingRequest);
+ break;
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////// Test Only !!
+
+static void
+ccsip_api_subscribe_result (ccsip_sub_not_data_t * msg_data)
+{
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Received Subscribe Response: request_id=%d, sub_id=%x\n",
+ DEB_F_PREFIX_ARGS(SIP_SUB_RESP, "ccsip_api_subscribe_result"),
+ msg_data->request_id, msg_data->sub_id);
+ if (msg_data->u.subs_result_data.status_code == REQUEST_TIMEOUT) {
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Request timed out\n", DEB_F_PREFIX_ARGS(SIP_SUB_RESP, "ccsip_api_subscribe_result"));
+ }
+}
+
+static void
+print_event_data (ccsip_event_data_t * eventDatap)
+{
+ static const char *fname = "print_event_data";
+
+ while (eventDatap) {
+ switch (eventDatap->type) {
+ case EVENT_DATA_INVALID:
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Invalid Data Received\n", DEB_F_PREFIX_ARGS(SIP_EVT, fname));
+ break;
+ case EVENT_DATA_KPML_REQUEST:
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"KPML Request Event Data Received\n", DEB_F_PREFIX_ARGS(SIP_EVT, fname));
+ break;
+ case EVENT_DATA_KPML_RESPONSE:
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"KPML Response Event Data Received\n", DEB_F_PREFIX_ARGS(SIP_EVT, fname));
+ break;
+ case EVENT_DATA_PRESENCE:
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Presence Event Data Received\n", DEB_F_PREFIX_ARGS(SIP_EVT, fname));
+ break;
+ case EVENT_DATA_DIALOG:
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Dialog Event Data Received\n", DEB_F_PREFIX_ARGS(SIP_EVT, fname));
+ break;
+ case EVENT_DATA_RAW:
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Raw Event Data Received\n", DEB_F_PREFIX_ARGS(SIP_EVT, fname));
+ break;
+ default:
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Event Data Type Not Understood\n", DEB_F_PREFIX_ARGS(SIP_EVT, fname));
+ break;
+ }
+ eventDatap = eventDatap->next;
+ }
+}
+
+static void
+ccsip_api_notify_result (ccsip_sub_not_data_t *msg_data)
+{
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Received Notify Response\n", DEB_F_PREFIX_ARGS(SIP_SUB_RESP, "ccsip_api_notify_result"));
+}
+
+static void
+ccsip_api_notify_ind (ccsip_sub_not_data_t *msg)
+{
+ static const char *fname = "ccsip_api_notify_ind";
+ sipspi_msg_t not_resp;
+
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Received Notify, request_id=%d, sub_id=%x\n",DEB_F_PREFIX_ARGS(SIP_SUB_RESP, fname),
+ msg->request_id, msg->sub_id);
+
+ // Check out what's there in the notify indication
+ if (msg->u.notify_ind_data.eventData) {
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Event Data Received\n", DEB_F_PREFIX_ARGS(SIP_EVT, fname));
+ print_event_data(msg->u.notify_ind_data.eventData);
+ free_event_data(msg->u.notify_ind_data.eventData);
+ } else {
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"No event data received\n", DEB_F_PREFIX_ARGS(SIP_EVT, fname));
+ }
+
+ // Respond with a 200OK
+ memset(¬_resp, 0, sizeof(sipspi_msg_t));
+ not_resp.msg.notify_resp.sub_id = msg->sub_id;
+ not_resp.msg.notify_resp.response_code = SIP_SUCCESS_SETUP;
+ not_resp.msg.notify_resp.duration = 3600;
+
+ (void) subsmanager_handle_ev_app_notify_response(¬_resp);
+}
+
+static void
+ccsip_api_subscribe_terminate (ccsip_sub_not_data_t *msg_data)
+{
+ sipspi_msg_t terminate;
+
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Received Terminate notice\n", DEB_F_PREFIX_ARGS(SIP_SUB, "ccsip_api_subscribe_terminate"));
+ if (msg_data->u.subs_term_data.status_code == NETWORK_SUBSCRIPTION_EXPIRED) {
+ terminate.msg.subs_term.sub_id = msg_data->sub_id;
+ terminate.msg.subs_term.immediate = TRUE;
+ (void) subsmanager_handle_ev_app_subscription_terminated(&terminate);
+ }
+}
+
+static void
+ccsip_api_subscribe_ind (ccsip_sub_not_data_t *msg)
+{
+ static const char *fname = "ccsip_api_subscribe_ind";
+ sipspi_msg_t subs_resp, notify, terminate;
+ ccsip_event_data_t *eventData;
+ char *junkdata;
+
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Received Subscription Request\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname));
+
+ // Check out what's there in the subs indication
+ if (msg->u.subs_ind_data.eventData) {
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Event Data Received\n", DEB_F_PREFIX_ARGS(SIP_EVT, fname));
+ print_event_data(msg->u.subs_ind_data.eventData);
+ free_event_data(msg->u.subs_ind_data.eventData);
+ } else {
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"No event data received\n", DEB_F_PREFIX_ARGS(SIP_EVT, fname));
+ }
+
+ // Accept the subscription with a 200 OK response
+ subs_resp.msg.subscribe_resp.duration = msg->u.subs_ind_data.expires;
+ subs_resp.msg.subscribe_resp.response_code = SIP_SUCCESS_SETUP;
+ subs_resp.msg.subscribe_resp.sub_id = msg->sub_id;
+ (void) subsmanager_handle_ev_app_subscribe_response(&subs_resp);
+
+ // Now send a NOTIFY
+ notify.msg.notify.notifyResultCallback = ccsip_api_notify_result;
+ notify.msg.notify.sub_id = msg->sub_id;
+ notify.msg.notify.eventData = NULL;
+
+ // Now fill in some data in the kpml structure
+ eventData = (ccsip_event_data_t *) cpr_malloc(sizeof(ccsip_event_data_t));
+ if (eventData == NULL) {
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Malloc of ccsip event data structure failed.\n", DEB_F_PREFIX_ARGS(SIP_EVT, fname));
+ return;
+ }
+
+ memset(eventData, 0, sizeof(ccsip_event_data_t));
+ sstrncpy(eventData->u.kpml_request.pattern.regex.regexData, "012", 32);
+ sstrncpy(eventData->u.kpml_request.version, "1.0", 16);
+ eventData->type = EVENT_DATA_KPML_REQUEST;
+ notify.msg.notify.eventData = eventData;
+
+ // Now fill in some other junk data
+ eventData = (ccsip_event_data_t *) cpr_malloc(sizeof(ccsip_event_data_t));
+ if (eventData == NULL) {
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Malloc of ccsip event structure failed.\n", DEB_F_PREFIX_ARGS(SIP_EVT, fname));
+ cpr_free(notify.msg.notify.eventData);
+ return;
+ }
+
+ junkdata = (char *) cpr_malloc(20);
+ if (junkdata == NULL) {
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Malloc of junk data structure failed.\n", DEB_F_PREFIX_ARGS(SIP_EVT, fname));
+ cpr_free(eventData);
+ cpr_free(notify.msg.notify.eventData);
+ return;
+ }
+
+ memset(eventData, 0, sizeof(ccsip_event_data_t));
+ memset(junkdata, 0, 20);
+ sstrncpy(junkdata, "Hello", 20);
+
+ eventData->u.raw_data.data = junkdata;
+ eventData->u.raw_data.length = strlen(junkdata);
+ eventData->type = EVENT_DATA_RAW;
+ notify.msg.notify.eventData->next = eventData;
+ (void) subsmanager_handle_ev_app_notify(¬ify);
+
+ // If expires is 0, terminate the subscription
+ if (msg->u.subs_ind_data.expires == 0) {
+ terminate.msg.subs_term.sub_id = msg->sub_id;
+ terminate.msg.subs_term.immediate = TRUE;
+ (void) subsmanager_handle_ev_app_subscription_terminated(&terminate);
+ }
+}
+
+static void
+test_send_subscribe ()
+{
+ sipspi_msg_t subscribe;
+ ccsip_event_data_t *eventData;
+
+ memset(&subscribe.msg.subscribe, 0, sizeof(sipspi_subscribe_t));
+
+ subscribe.msg.subscribe.eventPackage = CC_SUBSCRIPTIONS_KPML;
+ subscribe.msg.subscribe.duration = 15;
+ sstrncpy(subscribe.msg.subscribe.subscribe_uri, "19921", CC_MAX_DIALSTRING_LEN);
+ sstrncpy(subscribe.msg.subscribe.subscriber_uri, "12345", CC_MAX_DIALSTRING_LEN);
+ subscribe.msg.subscribe.request_id = 1003;
+ subscribe.msg.subscribe.dn_line = 2;
+ subscribe.msg.subscribe.sub_id = CCSIP_SUBS_INVALID_SUB_ID;
+ subscribe.msg.subscribe.subsResultCallback = ccsip_api_subscribe_result;
+ subscribe.msg.subscribe.subsTermCallback = ccsip_api_subscribe_terminate;
+ subscribe.msg.subscribe.notifyIndCallback = ccsip_api_notify_ind;
+ subscribe.msg.subscribe.auto_resubscribe = TRUE;
+
+ // Now fill in some data in the kpml structure
+ /*
+ * eventData = (ccsip_event_data_t *) cpr_malloc(sizeof(ccsip_event_data_t));
+ * if (eventData == NULL) {
+ * CCSIP_DEBUG_TASK("Malloc of ccsip event data failed.\n");
+ * return;
+ * }
+ *
+ * memset(eventData, 0, sizeof(ccsip_event_data_t));
+ * sstrncpy(eventData->u.kpml_request.pattern.regex.regexData, "012", sizeof(eventData->u.kpml_request.pattern.regex.regexData));
+ * sstrncpy(eventData->u.kpml_request.version, "1.0", sizeof(eventData->u.kpml_request.version));
+ * eventData->type = EVENT_DATA_KPML_REQUEST;
+ * subscribe.msg.subscribe.eventData = eventData;
+ */
+ // Now fill in some other junk data
+ eventData = (ccsip_event_data_t *) cpr_malloc(sizeof(ccsip_event_data_t));
+ if (eventData == NULL) {
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Malloc of ccsip event data failed.\n", DEB_F_PREFIX_ARGS(SIP_EVT, "test_send_subscribe"));
+ return;
+ }
+
+ memset(eventData, 0, sizeof(ccsip_event_data_t));
+ eventData->type = EVENT_DATA_RAW;
+ eventData->u.raw_data.data = (char *) cpr_malloc(150);
+ if (eventData->u.raw_data.data) {
+ eventData->u.raw_data.length = 150;
+ memset(eventData->u.raw_data.data, 'V', 150);
+ } else {
+ eventData->u.raw_data.length = 0;
+ }
+ eventData->next = NULL;
+ subscribe.msg.subscribe.eventData = eventData;
+
+ (void) subsmanager_handle_ev_app_subscribe(&subscribe);
+}
+
+static void
+test_send_register ()
+{
+ sipspi_msg_t register_msg;
+
+ memset(®ister_msg, 0, sizeof(sipspi_msg_t));
+ register_msg.msg.subs_reg.eventPackage = CC_SUBSCRIPTIONS_PRESENCE;
+ register_msg.msg.subs_reg.subsIndCallback = ccsip_api_subscribe_ind;
+ register_msg.msg.subs_reg.subsTermCallback = ccsip_api_subscribe_terminate;
+ (void) subsmanager_handle_ev_app_subscribe_register(®ister_msg);
+}
+
+int
+subsmanager_test_start_routine ()
+{
+ static int subscribe_sent = 0;
+ static int register_sent = 0;
+
+ if (subscribe_sent == 0) {
+ test_send_subscribe();
+ subscribe_sent = 1;
+ }
+
+ if (register_sent == 0) {
+ test_send_register();
+ register_sent = 1;
+ }
+ return 0;
+
+}
+
+/************************************************************
+ * Send local error to the calling application
+ * This function reuses the callback interface to pass the
+ * (bad) result of requests from the application
+ ************************************************************/
+void
+sip_send_error_message (ccsip_sub_not_data_t *msg_data,
+ cc_srcs_t dest_task,
+ int msgid,
+ ccsipGenericCallbackFn_t callbackFn,
+ const char *fname)
+{
+ if (!msg_data) {
+ return;
+ }
+ if (callbackFn) {
+ (*callbackFn) (msg_data);
+ } else if (dest_task != CC_SRC_MIN) {
+ (void) sip_send_message(msg_data, dest_task, msgid);
+ }
+}
+
+
+/********************************************************
+ * Shutdown the Subscription Manager
+ ********************************************************/
+int
+sip_subsManager_shut ()
+{
+ const char *fname = "sip_subsManager_shut";
+ int i;
+ sipSCB_t *scbp = NULL;
+ ccsip_sub_not_data_t error_data;
+
+ if (subsManagerRunning == 0) {
+ return (0);
+ }
+ error_data.reason_code = SM_REASON_CODE_SHUTDOWN;
+ // Send indication of subscription ended to internal apps
+ // then clean and free up subscriptions and SCB
+ for (i = 0; i < MAX_SCBS; i++) {
+ scbp = &(subsManagerSCBS[i]);
+ if (scbp->smState == SUBS_STATE_IDLE) {
+ continue;
+ }
+
+ error_data.sub_id = scbp->sub_id;
+ error_data.request_id = scbp->request_id;
+ error_data.sub_duration = 0;
+ error_data.event = scbp->hb.event_type;
+ error_data.msg_id = scbp->subsTermCallbackMsgID;
+ error_data.line_id = scbp->hb.dn_line;
+ error_data.gsm_id = scbp->gsm_id;
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Sending shutdown notification for scb=%d"
+ " sub_id=%x\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname), i, scbp->sub_id);
+
+ sip_send_error_message(&error_data, scbp->subsNotCallbackTask,
+ scbp->subsTermCallbackMsgID,
+ scbp->subsTermCallback, fname);
+
+ free_scb(i, fname);
+ }
+
+ // Shut down the periodic timer
+ (void) sip_platform_subnot_periodic_timer_stop();
+
+ // Mark subsManager as stopped running
+ subsManagerRunning = 0;
+
+ tcb_reset();
+
+ return (0);
+}
+
+/********************************************************
+ * Common code notifying application for a failover/fallback
+ * or CCM new registration (reset) event. Send a notification to
+ * applications that have an active subscription
+ ********************************************************/
+static int
+sip_subsManager_reg_failure_common (ccsip_reason_code_e reason)
+{
+ const char *fname = "sip_subsManager_reg_failure_common";
+ int i;
+ sipSCB_t *scbp = NULL;
+ ccsip_sub_not_data_t error_data;
+
+ if (subsManagerRunning == 0) {
+ return (0);
+ }
+ error_data.reason_code = reason;
+ // Send indication of subscription ended to internal apps
+ // then clean and free up subscriptions and SCB
+ for (i = 0; i < MAX_SCBS; i++) {
+ scbp = &(subsManagerSCBS[i]);
+ if (scbp->smState == SUBS_STATE_IDLE ||
+ scbp->smState == SUBS_STATE_REGISTERED) {
+ // Update addr and port after rollover/ccm reset
+ scbp->hb.local_port = sipTransportGetListenPort(1, NULL);
+ sipTransportGetServerIPAddr(&(scbp->hb.dest_sip_addr),1);
+ scbp->hb.dest_sip_port = sipTransportGetPrimServerPort(1);
+ continue;
+ }
+
+ error_data.sub_id = scbp->sub_id;
+ error_data.line_id = scbp->hb.dn_line;
+ error_data.request_id = scbp->request_id;
+ error_data.sub_duration = 0;
+ error_data.event = scbp->hb.event_type;
+ error_data.msg_id = scbp->subsTermCallbackMsgID;
+
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Sending reg failure notification for "
+ "scb=%d sub_id=%x reason=%d\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname), i,
+ scbp->sub_id, reason);
+
+ sip_send_error_message(&error_data, scbp->subsNotCallbackTask,
+ scbp->subsTermCallbackMsgID,
+ scbp->subsTermCallback, fname);
+
+ if (scbp->internal) {
+ outgoingSubscriptions--;
+ } else {
+ incomingSubscriptions--;
+ }
+ free_scb(i, fname);
+ }
+
+ sipRelDevAllMessagesClear();
+ return (0);
+}
+
+/********************************************************
+ * Handle a failover/fallback event
+ * to handle this event, send a notification to all
+ * applications that have an active subscription
+ ********************************************************/
+int
+sip_subsManager_rollover ()
+{
+ tcb_reset();
+ return (sip_subsManager_reg_failure_common(SM_REASON_CODE_ROLLOVER));
+}
+
+/********************************************************
+ * Handle a (CCM or Proxy) server down and up event^M
+ * to handle this event, send a notification to all^M
+ * applications that have an active subscription^M
+ ********************************************************/
+int
+sip_subsManager_reset_reg (void)
+{
+ return (sip_subsManager_reg_failure_common(SM_REASON_CODE_RESET_REG));
+}
+
+
+/***********************************************************
+ * Send a protocol error message to application. The application
+ * decides whether to terminate and restart the subscription
+ * or otherwise
+ ***********************************************************/
+void
+sip_subsManager_send_protocol_error (sipSCB_t *scbp, int scb_index,
+ boolean terminate)
+{
+ const char *fname = "sip_subsManager_send_protocol_error";
+ ccsip_sub_not_data_t error_data;
+
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Protocol Error for scb=%d sub_id=%x\n", fname,
+ scb_index, scbp->sub_id);
+
+ error_data.reason_code = SM_REASON_CODE_ERROR;
+ error_data.sub_id = scbp->sub_id;
+ error_data.request_id = scbp->request_id;
+ error_data.sub_duration = 0;
+ error_data.event = scbp->hb.event_type;
+ error_data.msg_id = scbp->subsTermCallbackMsgID;
+ error_data.line_id = scbp->hb.dn_line;
+
+ sip_send_error_message(&error_data, scbp->subsNotCallbackTask,
+ scbp->subsTermCallbackMsgID, scbp->subsTermCallback,
+ fname);
+
+ if (terminate) {
+ free_scb(scb_index, fname);
+ }
+
+}
+
+/********************************************************
+ * Start and initialize the Subscription Manager
+ ********************************************************/
+void
+initialize_scb (sipSCB_t *scbp)
+{
+ int nat_enable = 0;
+
+ if (!scbp) {
+ return;
+ }
+ memset(scbp, 0, sizeof(sipSCB_t));
+
+ scbp->sub_id = CCSIP_SUBS_INVALID_SUB_ID;
+ scbp->pendingClean = FALSE;
+ scbp->pendingCount = 0;
+ scbp->internal = FALSE;
+ scbp->subsIndCallback = NULL;
+ scbp->subsResultCallback = NULL;
+ scbp->notifyIndCallback = NULL;
+ scbp->notifyResultCallback = NULL;
+ scbp->subsTermCallback = NULL;
+ scbp->notIndCallbackMsgID = 0;
+ scbp->notResCallbackMsgID = 0;
+ scbp->subsIndCallbackMsgID = 0;
+ scbp->subsResCallbackMsgID = 0;
+ scbp->subsTermCallbackMsgID = 0;
+ scbp->subsIndCallbackTask = CC_SRC_MIN;
+ scbp->subsNotCallbackTask = CC_SRC_MIN;
+
+ config_get_value(CFGID_NAT_ENABLE, &nat_enable, sizeof(nat_enable));
+ if (nat_enable == 0) {
+ sip_config_get_net_device_ipaddr(&(scbp->hb.src_addr));
+ } else {
+ sip_config_get_nat_ipaddr(&(scbp->hb.src_addr));
+ }
+ scbp->hb.cb_type = SUBNOT_CB;
+ scbp->hb.dn_line = 1;
+ scbp->hb.local_port = sipTransportGetListenPort(scbp->hb.dn_line, NULL);
+ sipTransportGetServerIPAddr(&(scbp->hb.dest_sip_addr),1);
+ scbp->hb.dest_sip_port = sipTransportGetPrimServerPort(1);
+
+ scbp->hb.sipCallID[0] = '\0';
+ scbp->smState = SUBS_STATE_IDLE;
+ scbp->SubURI[0] = '\0';
+ scbp->SubscriberURI[0] = '\0';
+ scbp->sip_from = strlib_empty();
+ scbp->sip_to = strlib_empty();
+ scbp->sip_to_tag = strlib_empty();
+ scbp->sip_from_tag = strlib_empty();
+ scbp->sip_contact = strlib_empty();
+ scbp->cached_record_route = strlib_empty();
+ scbp->callingNumber = strlib_empty();
+ scbp->subscription_state = SUBSCRIPTION_STATE_INVALID;
+ scbp->norefersub = FALSE;
+ scbp->request_id = -1;
+ scbp->hb.authen.cred_type = 0;
+ scbp->hb.authen.authorization = NULL;
+ scbp->hb.authen.status_code = 0;
+ scbp->hb.authen.nc_count = 0;
+ scbp->hb.authen.new_flag = FALSE;
+ scbp->hb.event_data_p = NULL;
+ scbp->pendingRequests = NULL;
+}
+
+int
+sip_subsManager_init ()
+{
+ // Initialize SCBS array
+ const char *fname = "sip_subsManager_init";
+ line_t i = 0;
+ sipSCB_t *scbp;
+
+ if (subsManagerRunning == 1) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Subscription Manager already running!!\n", fname);
+ return SIP_OK;
+ }
+
+ for (i = 0; i < MAX_SCBS; i++) {
+ scbp = &(subsManagerSCBS[i]);
+ initialize_scb(scbp);
+ scbp->line = i;
+ }
+
+ for (i = 0; i < MAX_SCB_HISTORY; i++) {
+ gSubHistory[i].last_call_id[0] = '\0';
+ gSubHistory[i].last_from_tag[0] = '\0';
+ gSubHistory[i].eventPackage = CC_SUBSCRIPTIONS_NONE;
+ }
+
+ // reset status and stats
+ internalRegistrations = 0;
+
+ incomingSubscribes = 0;
+ incomingRefers = 0;
+ incomingNotifies = 0;
+ incomingUnsolicitedNotifies = 0;
+ incomingSubscriptions = 0;
+
+ outgoingSubscribes = 0;
+ outgoingNotifies = 0;
+ outgoingUnsolicitedNotifies = 0;
+ outgoingSubscriptions = 0;
+
+ currentScbsAllocated = 0;
+ maxScbsAllocated = 0;
+
+ // Start periodic timer
+ (void) sip_platform_subnot_periodic_timer_start(TMR_PERIODIC_SUBNOT_INTERVAL * 1000);
+
+ subsManagerRunning = 1;
+
+ // Print out the size of the SCB
+ // CCSIP_DEBUG_ERROR("SCB Size=%d\n", sizeof(sipSCB_t));
+ // CCSIP_DEBUG_ERROR("CCB Size=%d\n", sizeof(ccsipCCB_t));
+ // Kick-off the test routine
+ // subsmanager_test_start_routine();
+
+ /* Initialize modules which uses SUB/MANAGER */
+ kpml_init();
+ configapp_init();
+
+ return SIP_OK;
+}
+
+
+/********************************************************
+ * Functions to allocate, locate, free, and update SCBs
+ ********************************************************/
+
+/*
+ * Function: find_scb_by_callid
+ *
+ * Parameters:
+ * callID - pointer to const. char for the target call ID.
+ * scb_index - pointer to int where the SCB index of the result
+ * SCB to be stored.
+ *
+ * Description:
+ * The find_scb_by_callid function searches for an SCB that
+ * contains the matching callID. It is possible to have multiple
+ * SCB that matches the given callID. The function only returns
+ * the first SCB that has the matching callID.
+ *
+ * Returns:
+ * Pointer to SCB and its index if the SCB is found. Otherwise
+ * it returns NULL and the index is undefined.
+ */
+sipSCB_t *
+find_scb_by_callid (const char *callID, int *scb_index)
+{
+ int i;
+ int num_scb = currentScbsAllocated;
+ sipSCB_t *scbp;
+
+ if (num_scb == 0) {
+ /* No active subscription */
+ return (NULL);
+ }
+ scbp = &subsManagerSCBS[0];
+ for (i = 0; (i < MAX_SCBS) && num_scb; i++, scbp++) {
+ if (scbp->smState != SUBS_STATE_IDLE) {
+ if ((scbp->smState != SUBS_STATE_REGISTERED) &&
+ (strcmp(callID, scbp->hb.sipCallID) == 0)) {
+ *scb_index = i;
+ return (scbp);
+ }
+ num_scb--;
+ }
+ }
+
+ return (NULL);
+}
+
+/*
+ * Function: find_req_scb
+ *
+ * Parameters:
+ * callID - pointer to const. char for the target call ID.
+ * method - SIP method to match.
+ * cseq - CSEQ value to match.
+ * scb_index - pointer to int where the SCB index of the result
+ * SCB to be stored.
+ *
+ * Description:
+ * The find_req_scb function searches for an SCB that contains
+ * the matching callID, last request method and last cseq sent. If
+ * the match SCB is found, the function returns the pointer to the
+ * sipSCB_t along with the corresponding index.
+ *
+ * Returns:
+ * Pointer to SCB and its index if the SCB is found. Otherwise
+ * returns NULL and the index will be set to MAX_SCBS.
+ */
+static sipSCB_t *
+find_req_scb (const char *callID, sipMethod_t method,
+ uint32_t cseq, int *scb_index)
+{
+ int idx, num_scb;
+ sipSCB_t *scbp;
+
+ scbp = &subsManagerSCBS[0];
+ num_scb = currentScbsAllocated;
+ /*
+ * Search SCB tables for all allocated SCBs.
+ */
+ for (idx = 0; (idx < MAX_SCBS) && num_scb; idx++, scbp++) {
+ if (scbp->smState != SUBS_STATE_IDLE) {
+ if ((scbp->smState != SUBS_STATE_REGISTERED) &&
+ (scbp->last_sent_request_cseq_method == method) &&
+ (scbp->last_sent_request_cseq == cseq) &&
+ (strcmp(callID, scbp->hb.sipCallID) == 0)) {
+ /* Found the matching scb */
+ *scb_index = idx;
+ return (scbp);
+ }
+ num_scb--;
+ }
+ }
+ *scb_index = MAX_SCBS;
+ return (NULL);
+}
+
+/*
+ * Function: find_scb_by_sub_id
+ *
+ * Parameters:
+ * sub_id - the sub_id_t parameter from which scb index
+ * to be obtained.
+ * scb_index - pointer to int for index of the SCB entry to
+ * be returned if the pointer is provided (not
+ * NULL).
+ *
+ * Description:
+ * The function finds the SCB for the given sub_id.
+ *
+ * Returns:
+ * 1) pointer to sipSCB_t or NULL if finding fails.
+ * 2) the index into the SCB array is also returned if the
+ * scb_index parameter is provided.
+ */
+static sipSCB_t *
+find_scb_by_sub_id (sub_id_t sub_id, int *scb_index)
+{
+ int idx, ret_idx = MAX_SCBS;
+ sipSCB_t *scbp = NULL;
+
+ /*
+ * Use index part of the sub_id to find the SCB
+ */
+ idx = GET_SCB_INDEX_FROM_SUB_ID(sub_id);
+ if (idx < MAX_SCBS) {
+ /*
+ * SCB index is within a valid range, get the SCB by index.
+ * Match the SCB's sub_id and the one provided.
+ */
+ if (subsManagerSCBS[idx].sub_id == sub_id) {
+ /* The correct SCB is found */
+ scbp = &(subsManagerSCBS[idx]);
+ ret_idx = idx;
+ }
+ }
+
+ if (scb_index != NULL) {
+ *scb_index = ret_idx;
+ }
+ return (scbp);
+}
+
+sipSCB_t *
+find_scb_by_registration (cc_subscriptions_t event, int *scb_index)
+{
+ int i;
+
+ for (i = 0; i < MAX_SCBS; i++) {
+ if ((subsManagerSCBS[i].hb.event_type == event) &&
+ (subsManagerSCBS[i].smState == SUBS_STATE_REGISTERED)) {
+ *scb_index = i;
+ return &(subsManagerSCBS[i]);
+ }
+ }
+
+ return (NULL);
+}
+
+sipSCB_t *
+find_scb_by_subscription (cc_subscriptions_t event, int *scb_index,
+ const char *callID)
+{
+ int i;
+
+ for (i = 0; i < MAX_SCBS; i++) {
+ if (cpr_strcasecmp(subsManagerSCBS[i].hb.sipCallID, callID) == 0) {
+ *scb_index = i;
+ return &(subsManagerSCBS[i]);
+ }
+ }
+ return (NULL);
+}
+
+/*
+ * Function: new_sub_id
+ *
+ * Parameters:
+ * scb_index - the SCB index.
+ *
+ * Description:
+ * The function allocates a new unique sub_id and return
+ * it to the caller.
+ *
+ * NOTE: the scb_index can not exceed 16 bit unsigned value.
+ *
+ * Returns:
+ * sub_id.
+ */
+static sub_id_t
+new_sub_id (int scb_index)
+{
+ static sub_id_t unique_id = 0;
+ sub_id_t sub_id;
+
+ /*
+ * Form the sub_id is encoded as the following:
+ * bit 31 - bit 16 contains unique ID
+ * bit 15 - bit 0 contains scb index.
+ */
+ sub_id = (unique_id << SUB_ID_UNIQUE_ID_POSITION) |
+ (sub_id_t)(scb_index & SUB_IDSCB_INDEX_MASK);
+ unique_id++; /* next unique sub id */
+ if (sub_id == CCSIP_SUBS_INVALID_SUB_ID) {
+ /* sub_id becomes the invalid value marker, re-calcualte new id */
+ sub_id = (unique_id << SUB_ID_UNIQUE_ID_POSITION) |
+ (sub_id_t)(scb_index & SUB_IDSCB_INDEX_MASK);
+ unique_id++;
+ }
+ return (sub_id);
+}
+
+sipSCB_t *
+allocate_scb (int *scb_index)
+{
+ int i;
+
+ for (i = 0; i < MAX_SCBS; i++) {
+ if (subsManagerSCBS[i].smState == SUBS_STATE_IDLE) {
+ *scb_index = i;
+ currentScbsAllocated++;
+ if (currentScbsAllocated > maxScbsAllocated) {
+ maxScbsAllocated = currentScbsAllocated;
+ }
+ /*
+ * assigned sub_id to the allocated SCB.
+ */
+ subsManagerSCBS[i].sub_id = new_sub_id(i);
+ CCSIP_DEBUG_TASK("allocate_scb scb_index: %d, currentScbsAllocated: %d, "
+ "maxScbsAllocated: %d, sub_id: %x\n", scb_index,
+ currentScbsAllocated, maxScbsAllocated, subsManagerSCBS[i].sub_id);
+
+ /*
+ * local port may have changed because of failover/fallback.
+ * So update it with current info so that the Via & Contact headers
+ * in SUB/NOT are generated correctly.
+ */
+ subsManagerSCBS[i].hb.local_port =
+ sipTransportGetListenPort(subsManagerSCBS[i].hb.dn_line, NULL);
+ return &(subsManagerSCBS[i]);
+ }
+ }
+ return (NULL);
+}
+
+boolean
+is_previous_sub (const char *pCallID,
+ char *pFromTag,
+ cc_subscriptions_t event)
+{
+ int i;
+
+ if (!pCallID || !pFromTag) {
+ return FALSE;
+ }
+
+ for (i = 0; i < MAX_SCB_HISTORY; i++) {
+ if (strncmp(gSubHistory[i].last_call_id, pCallID, MAX_SIP_CALL_ID) == 0) {
+ if (strncmp(gSubHistory[i].last_from_tag, pFromTag, MAX_SIP_TAG_LENGTH) == 0) {
+ if (gSubHistory[i].eventPackage == event) {
+ return TRUE;
+ }
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+void
+clean_scb (sipSCB_t *scbp)
+{
+ sub_not_trxn_t *trxn_p;
+
+ if (scbp) {
+ strlib_free(scbp->sip_from);
+ strlib_free(scbp->sip_to);
+ strlib_free(scbp->sip_to_tag);
+ strlib_free(scbp->sip_from_tag);
+ strlib_free(scbp->callingNumber);
+ strlib_free(scbp->sip_contact);
+ strlib_free(scbp->cached_record_route);
+ if (scbp->contact_info)
+ sippmh_free_contact(scbp->contact_info);
+ if (scbp->record_route_info)
+ sippmh_free_record_route(scbp->record_route_info);
+ if (scbp->hb.event_data_p)
+ free_event_data(scbp->hb.event_data_p);
+ if (scbp->pendingRequests) {
+ free_pending_requests(scbp->pendingRequests);
+ }
+
+ scbp->hb.authen.cnonce[0] = '\0';
+ if (scbp->hb.authen.authorization != NULL) {
+ cpr_free(scbp->hb.authen.authorization);
+ scbp->hb.authen.authorization = NULL;
+ }
+ if (scbp->hb.authen.sip_authen != NULL) {
+ sippmh_free_authen(scbp->hb.authen.sip_authen);
+ scbp->hb.authen.sip_authen = NULL;
+ }
+
+ /* free all transactions */
+ if (scbp->incoming_trxns) {
+ while ((trxn_p = (sub_not_trxn_t *)
+ sll_next(scbp->incoming_trxns, NULL)) != NULL) {
+ (void) sll_remove(scbp->incoming_trxns, (void *)trxn_p);
+ cpr_free(trxn_p->via);
+ cpr_free(trxn_p);
+ }
+ sll_destroy(scbp->incoming_trxns);
+ scbp->incoming_trxns = NULL;
+ }
+
+ }
+}
+void
+store_scb_history (sipSCB_t *scbp)
+{
+ // Copy SCB parameters in the next available history array
+ static int next_history = 0;
+
+ next_history++;
+ if (next_history == MAX_SCB_HISTORY) {
+ next_history = 0;
+ }
+ sstrncpy(gSubHistory[next_history].last_call_id, scbp->hb.sipCallID, MAX_SIP_CALL_ID);
+ sstrncpy(gSubHistory[next_history].last_from_tag, scbp->sip_from_tag, MAX_SIP_TAG_LENGTH);
+ gSubHistory[next_history].eventPackage = scbp->hb.event_type;
+}
+
+/**
+ *
+ * frees the SCB. It will cleanup the scb (ie, free the memory allocated for any sub fields).
+ * It will also mark the SCB as free (smState = SUBS_STATE_IDLE).
+ * Please note this function may be invoked can be invoked even when smState == SUBS_STATE_IDLE.
+ * An example case is when parse_body() fails.
+ *
+ * @param[in] scb_index - indext of the SCB into SCB array.
+ * @param[in] fname - name of the function calling this function.
+ *
+ * @return none
+ *
+ * @pre (scb_index >= 0) and (scb_index < MAX_SCBS)
+ * @post (subsManagerSCBS[scb_index].smState equals FALSE)
+ */
+void
+free_scb (int scb_index, const char *fname)
+{
+ sipSCB_t *scbp = NULL;
+
+ if (scb_index >= MAX_SCBS || scb_index < 0) {
+ CCSIP_DEBUG_ERROR("%s Trying to free an invalid scb_index. Return.\n", fname);
+ return;
+ }
+ scbp = &(subsManagerSCBS[scb_index]);
+
+
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Freeing SCB: scb=%d sub_id=%x\n",
+ DEB_F_PREFIX_ARGS(SIP_SUB, "free_scb"), scb_index, scbp->sub_id);
+
+ if (scbp->smState != SUBS_STATE_IDLE) {
+ currentScbsAllocated--;
+ /*
+ * This condition should never happen. If occurs, it is a strong indication
+ * something has gone wrong in our code logic and should be investigated.
+ */
+ if (currentScbsAllocated < 0) {
+ CCSIP_DEBUG_ERROR("%s: Error somewhere in scb accounting which results"
+ "in negative currentScbsAllocated. Set it to 0.\n", fname);
+ currentScbsAllocated = 0;
+ }
+ }
+ // If this was an incoming subscription, store values in history first
+ if ((scbp->internal == FALSE) && (scbp->smState != SUBS_STATE_REGISTERED)) {
+ store_scb_history(scbp);
+ }
+
+ clean_scb(scbp);
+
+ // Stop associated message retry timer
+ if (sipPlatformUISMSubNotTimers[scb_index].outstanding) {
+ sip_platform_msg_timer_subnot_stop(&sipPlatformUISMSubNotTimers[scb_index]);
+ }
+
+ // Re-initialize
+ initialize_scb(scbp);
+ scbp->line = (line_t) scb_index;
+}
+
+/**
+ * This function will free up the TCB resources and removes it from the TCB list.
+ *
+ * @param[in] tcbp - pointer to a TCB.
+ *
+ * @return none
+ *
+ * @pre (tcbp != NULL)
+ */
+static void free_tcb (sipTCB_t *tcbp)
+{
+ if (tcbp->hb.authen.authorization != NULL) {
+ cpr_free(tcbp->hb.authen.authorization);
+ }
+ if (tcbp->hb.authen.sip_authen != NULL) {
+ sippmh_free_authen(tcbp->hb.authen.sip_authen);
+ }
+
+ (void)cprDestroyTimer(tcbp->timer);
+ free_event_data(tcbp->hb.event_data_p);
+ (void)sll_remove(s_TCB_list, (void *)tcbp);
+ cpr_free(tcbp);
+}
+
+/**
+ * This function will find matching TCB by the SIP Call-ID in the TCB list.
+ *
+ * @param[in] callID_p - SIP Call-ID
+ *
+ * @return NULL if there is no matching TCB
+ * Otherwise, pointer to the found TCB is returned.
+ *
+ * @pre (callID_p != NULL)
+ */
+sipTCB_t *find_tcb_by_sip_callid (const char *callID_p)
+{
+ sipTCB_t *tcb_p;
+
+ tcb_p = (sipTCB_t *)sll_next(s_TCB_list, NULL);
+ while (tcb_p != NULL) {
+ if (strncmp(callID_p, tcb_p->hb.sipCallID, (sizeof(tcb_p->hb.sipCallID) -1)) == 0) {
+ return tcb_p;
+ }
+ tcb_p = (sipTCB_t *)sll_next(s_TCB_list, tcb_p);
+ }
+ return NULL;
+}
+
+/**
+ * This function will free up TCBs when
+ * 1. restarting or
+ * 2. failing over/ falling back
+ *
+ * @param[in] none
+ *
+ * @return none
+ */
+static void tcb_reset (void)
+{
+ sipTCB_t *tcb_p;
+
+ tcb_p = (sipTCB_t *)sll_next(s_TCB_list, NULL);
+ while (tcb_p != NULL) {
+ free_tcb(tcb_p);
+ tcb_p = (sipTCB_t *)sll_next(s_TCB_list, NULL);
+ }
+}
+
+/*
+ * Function is called to remove ccb pointer from scb
+ * When the dialog is cleared then ccb associated with
+ * that dialog is cleared as well. Remove that from
+ * scb parameters as well
+ */
+void
+submanager_update_ccb_addr (ccsipCCB_t *ccb)
+{
+ sipSCB_t *scbp = NULL;
+ int scb_index = 0;
+ int num_scb;
+
+ if ((ccb == NULL) || (currentScbsAllocated == 0)) {
+ /* The CCB is NULL or no active SCBs */
+ return;
+ }
+
+ /* Once the dialog is cleared i.e ccb is removed, the subnot
+ * should continue to use from its last sequence number. So
+ * re-assign last sequence value to scbp.
+ *
+ * There are possibility of multiple subscriptions associate
+ * with a call dialog. Search all of the SCB for the given CCB.
+ */
+ scbp = &subsManagerSCBS[0];
+ num_scb = currentScbsAllocated;
+ for (scb_index = 0; (scb_index < MAX_SCBS) && num_scb; scb_index++, scbp++) {
+ if (scbp->smState != SUBS_STATE_IDLE) {
+ if ((scbp->smState != SUBS_STATE_REGISTERED) &&
+ (scbp->ccbp == ccb)) {
+ scbp->last_sent_request_cseq = ccb->last_used_cseq;
+ scbp->ccbp = NULL;
+ }
+ num_scb--;
+ }
+ }
+
+}
+
+
+/*
+ * Takes care of all the parsing requirements
+ */
+static int
+parse_body (cc_subscriptions_t event_type, char *msgBody, int msgLength,
+ ccsip_event_data_t **eventDatapp,
+ const char *fname)
+{
+ const char *fname1 = "parse_body";
+ ccsip_event_data_type_e type = EVENT_DATA_INVALID;
+
+ if (!msgBody) {
+ return SIP_ERROR;
+ }
+
+ switch (event_type) {
+ case CC_SUBSCRIPTIONS_KPML:
+ type = EVENT_DATA_KPML_REQUEST;
+ break;
+ case CC_SUBSCRIPTIONS_CONFIGAPP:
+ type = EVENT_DATA_CONFIGAPP_REQUEST;
+ break;
+ default:
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"%s: unknown event type %d\n", fname1, fname, type);
+ return SIP_ERROR;
+ }
+
+ return SIP_OK;
+}
+
+boolean
+add_content (ccsip_event_data_t *eventData, sipMessage_t *request, const char *fname)
+{
+ return FALSE;
+
+/* This function requires XML handling */
+#if 0
+ const char *fname1 = "add_content";
+ uint32_t len;
+ char *eventBody = NULL;
+
+ while (eventData) {
+ /* Encode eventData into eventBody here */
+ len = strlen(eventBody);
+
+ switch (eventData->type) {
+ case EVENT_DATA_RAW:
+ // Assume body is of type CMXML for now
+ (void) sippmh_add_message_body(request, eventBody, len,
+ SIP_CONTENT_TYPE_CMXML,
+ SIP_CONTENT_DISPOSITION_SESSION_VALUE, TRUE, NULL);
+ break;
+ case EVENT_DATA_KPML_REQUEST:
+ (void) sippmh_add_message_body(request, eventBody, len,
+ SIP_CONTENT_TYPE_KPML_REQUEST,
+ SIP_CONTENT_DISPOSITION_SESSION_VALUE, TRUE, NULL);
+ break;
+ case EVENT_DATA_KPML_RESPONSE:
+ (void) sippmh_add_message_body(request, eventBody, len,
+ SIP_CONTENT_TYPE_KPML_RESPONSE,
+ SIP_CONTENT_DISPOSITION_SESSION_VALUE, TRUE, NULL);
+ break;
+ default:
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"%s: Data type not supported\n", fname1, fname);
+ cpr_free(eventBody);
+ break;
+ }
+
+ eventData = eventData->next;
+ }
+ return (TRUE);
+#endif
+}
+
+// Functions to handle requests from internal applications
+
+/************************************************************
+ * Applications Register to Receive an incoming subscribe(s)
+ ************************************************************/
+int
+subsmanager_handle_ev_app_subscribe_register (cprBuffer_t buf)
+{
+ const char *fname = "subsmanager_handle_ev_app_register";
+ sipspi_subscribe_reg_t *reg_datap;
+ sipSCB_t *scbp = NULL;
+ int scb_index;
+ sipspi_msg_t *pSIPSPIMsg = NULL;
+
+
+ pSIPSPIMsg = (sipspi_msg_t *) buf;
+
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Processing a new subscription registration\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname));
+
+ if (!subsManagerRunning) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Subscription Manager Not Initialized!\n", fname);
+ return SIP_ERROR;
+ }
+
+ reg_datap = &(pSIPSPIMsg->msg.subs_reg);
+ if (reg_datap->subsIndCallback == NULL &&
+ reg_datap->subsIndCallbackMsgID == 0) {
+ return SIP_ERROR;
+ }
+
+ scbp = find_scb_by_registration(reg_datap->eventPackage, &scb_index);
+ if (scbp) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Duplicate registration!\n", fname);
+ return SIP_ERROR;
+ } else {
+ scbp = allocate_scb(&scb_index);
+ if (!scbp) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Subscription control block allocation failed\n", fname);
+ return SIP_ERROR;
+ }
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Allocated SCB for App Registration,"
+ " event=%d, scb=%d, sub_id=%x\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname),
+ reg_datap->eventPackage,
+ GET_SCB_INDEX_FROM_SUB_ID(scbp->sub_id),
+ scbp->sub_id);
+ }
+
+ scbp->hb.dn_line = 1;
+ scbp->hb.event_type = reg_datap->eventPackage;
+ if (reg_datap->eventPackage - CC_SUBSCRIPTIONS_DIALOG > -1 &&
+ reg_datap->eventPackage - CC_SUBSCRIPTIONS_DIALOG < 5) {
+ sstrncpy(scbp->event_name, eventNames[reg_datap->eventPackage - CC_SUBSCRIPTIONS_DIALOG], MAX_EVENT_NAME_LEN);
+ }
+
+ // Get callback information (either event or function)
+ scbp->subsIndCallback = reg_datap->subsIndCallback;
+ scbp->subsIndCallbackTask = reg_datap->subsIndCallbackTask;
+ scbp->subsNotCallbackTask = reg_datap->subsIndCallbackTask;
+ scbp->subsIndCallbackMsgID = reg_datap->subsIndCallbackMsgID;
+ scbp->subsTermCallback = reg_datap->subsTermCallback;
+ scbp->subsTermCallbackMsgID = reg_datap->subsTermCallbackMsgID;
+ scbp->subsTermCallback = reg_datap->subsTermCallback;
+ scbp->subsTermCallbackMsgID = reg_datap->subsTermCallbackMsgID;
+
+ scbp->smState = SUBS_STATE_REGISTERED;
+ internalRegistrations++;
+ return (0);
+}
+
+/********************************************************
+ * Application Generated Subscribe Request
+ ********************************************************/
+int
+subsmanager_handle_ev_app_subscribe (cprBuffer_t buf)
+{
+ const char *fname = "subsmanager_handle_ev_app_subscribe";
+ sipspi_subscribe_t *sub_datap;
+ sipSCB_t *scbp = NULL;
+ int scb_index;
+ ccsip_sub_not_data_t subs_result_data;
+ boolean reSubscribe = FALSE;
+ ccsipCCB_t *ccbp = NULL;
+ sipspi_msg_t *pSIPSPIMsg = NULL;
+ int subscription_expires;
+
+ pSIPSPIMsg = (sipspi_msg_t *) buf;
+
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Processing a new App subscription request\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname));
+
+ if (!subsManagerRunning) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Subscription Manager Not Initialized!\n", fname);
+ return SIP_ERROR;
+ }
+
+ // Get Data
+ sub_datap = &(pSIPSPIMsg->msg.subscribe);
+
+ /* Steps:
+ * * Extract subscription details from the event information
+ * * Check data to ensure we support the event package asked for
+ * * Allocate an SCB to hold subscription details
+ * * Create body of the SUBSCRIBE message, if needed
+ * * Prep the message by adding fields to the SCB
+ * * Call sipSPISendSubscribe to send the message out
+ */
+
+ // Get ready for any failure
+ subs_result_data.u.subs_result_data.expires = 0;
+ subs_result_data.u.subs_result_data.status_code = SUBSCRIBE_REQUEST_FAILED;
+ subs_result_data.sub_id = CCSIP_SUBS_INVALID_SUB_ID;
+ subs_result_data.request_id = sub_datap->request_id;
+ subs_result_data.msg_id = sub_datap->subsResCallbackMsgID;
+
+ /*
+ * Finding SCB by sub_id or request id and eventPakage if the
+ * sub_id is not known.
+ */
+ if (sub_datap->sub_id == CCSIP_SUBS_INVALID_SUB_ID) {
+ /*
+ * find scb based on request_id and event package.
+ * This scenario is possible if application decides to terminate a
+ * subscription before subsmanager provides app with sub_id.
+ */
+ for (scb_index = 0; scb_index < MAX_SCBS; scb_index++) {
+ if ((subsManagerSCBS[scb_index].request_id == sub_datap->request_id) &&
+ (subsManagerSCBS[scb_index].hb.event_type == sub_datap->eventPackage) &&
+ (!subsManagerSCBS[scb_index].pendingClean)) {
+ scbp = &(subsManagerSCBS[scb_index]);
+ break;
+ }
+ }
+ } else {
+ /* Find SCB from sub_id */
+ scbp = find_scb_by_sub_id(sub_datap->sub_id, &scb_index);
+ }
+ if (scbp == NULL) {
+ // Process new subscription
+ if ((sub_datap->eventPackage != CC_SUBSCRIPTIONS_DIALOG) &&
+ (sub_datap->eventPackage != CC_SUBSCRIPTIONS_KPML) &&
+ (sub_datap->eventPackage != CC_SUBSCRIPTIONS_PRESENCE)) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Event %d not supported!\n",
+ fname, sub_datap->eventPackage);
+ subs_result_data.u.subs_result_data.status_code = SUBSCRIBE_FAILED_BADEVENT;
+ sip_send_error_message(&subs_result_data, sub_datap->subsNotCallbackTask,
+ sub_datap->subsResCallbackMsgID, sub_datap->subsResultCallback,
+ fname);
+ return SIP_ERROR;
+ }
+
+ // Reject this if there is no way to get back to the subscriber
+ if (!((sub_datap->subsResultCallback) ||
+ ((sub_datap->subsNotCallbackTask != CC_SRC_MIN) &&
+ sub_datap->subsResCallbackMsgID))) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"No callback info provided by the App\n", fname);
+ subs_result_data.u.subs_result_data.status_code =
+ SUBSCRIBE_FAILED_BADINFO;
+ sip_send_error_message(&subs_result_data,
+ sub_datap->subsNotCallbackTask,
+ sub_datap->subsResCallbackMsgID,
+ sub_datap->subsResultCallback,
+ fname);
+ return SIP_ERROR;
+ }
+
+ // If this is a presence request - check if sufficient SCBs will still
+ // be available for other "more important" functions
+ if (sub_datap->eventPackage == CC_SUBSCRIPTIONS_PRESENCE) {
+ if (currentScbsAllocated >= LIMIT_SCBS_USAGE) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"reached Presence SCBs threshold\n", fname);
+ subs_result_data.u.subs_result_data.status_code =
+ SUBSCRIBE_FAILED_NORESOURCE;
+ sip_send_error_message(&subs_result_data,
+ sub_datap->subsNotCallbackTask,
+ sub_datap->subsResCallbackMsgID,
+ sub_datap->subsResultCallback, fname);
+ return SIP_ERROR;
+ }
+ }
+
+ // Allocate SCB and copy needed parameters
+ scbp = allocate_scb(&scb_index);
+ if (!scbp) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"ran out of SCBs\n", fname);
+ subs_result_data.u.subs_result_data.status_code =
+ SUBSCRIBE_FAILED_NORESOURCE;
+ sip_send_error_message(&subs_result_data,
+ sub_datap->subsNotCallbackTask,
+ sub_datap->subsResCallbackMsgID,
+ sub_datap->subsResultCallback,
+ fname);
+ show_scbs_inuse();
+ return SIP_ERROR;
+ }
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Allocated SCB for Sending Subscribe,"
+ " event=%d scb=%d sub_id=%x\n",
+ DEB_F_PREFIX_ARGS(SIP_SUB, fname), sub_datap->eventPackage,
+ scb_index, scbp->sub_id);
+ if (sub_datap->dn_line == 0 || sub_datap->dn_line > MAX_REG_LINES) {
+ // By not giving a DN line, the app is asking us to use
+ // device addressing and not line addressing
+ scbp->hb.dn_line = 1;
+ scbp->useDeviceAddressing = TRUE;
+ } else {
+ scbp->hb.dn_line = sub_datap->dn_line;
+ }
+
+ scbp->gsm_id = sub_datap->call_id;
+ if (scbp->gsm_id != 0) {
+ ccbp = sip_sm_get_ccb_by_gsm_id(scbp->gsm_id);
+ } else {
+ ccbp = NULL;
+ }
+ scbp->ccbp = ccbp;
+
+ scbp->hb.event_type = sub_datap->eventPackage;
+ scbp->hb.accept_type = sub_datap->acceptPackage;
+ if (sub_datap->eventPackage - CC_SUBSCRIPTIONS_DIALOG > -1 &&
+ sub_datap->eventPackage - CC_SUBSCRIPTIONS_DIALOG < 5) {
+ sstrncpy(scbp->event_name, eventNames[sub_datap->eventPackage - CC_SUBSCRIPTIONS_DIALOG], MAX_EVENT_NAME_LEN);
+ }
+ sstrncpy(scbp->SubURIOriginal, sub_datap->subscribe_uri,
+ sizeof(scbp->SubURIOriginal));
+ sstrncpy(scbp->SubscriberURI, sub_datap->subscriber_uri,
+ sizeof(scbp->SubscriberURI));
+ scbp->subsResultCallback = sub_datap->subsResultCallback;
+ scbp->notifyIndCallback = sub_datap->notifyIndCallback;
+ scbp->subsTermCallback = sub_datap->subsTermCallback;
+ scbp->subsNotCallbackTask = sub_datap->subsNotCallbackTask;
+ scbp->subsResCallbackMsgID = sub_datap->subsResCallbackMsgID;
+ scbp->notIndCallbackMsgID = sub_datap->subsNotIndCallbackMsgID;
+ scbp->subsTermCallbackMsgID = sub_datap->subsTermCallbackMsgID;
+
+ scbp->hb.dest_sip_addr = sub_datap->dest_sip_addr;
+ scbp->hb.dest_sip_port = sub_datap->dest_sip_port;
+
+ scbp->auto_resubscribe = sub_datap->auto_resubscribe;
+ scbp->norefersub = sub_datap->norefersub;
+ scbp->request_id = sub_datap->request_id;
+
+ // Set default value of subscribe duration, if not specified
+ if (sub_datap->duration < 0) {
+ config_get_value(CFGID_TIMER_SUBSCRIBE_EXPIRES, &subscription_expires,
+ sizeof(subscription_expires));
+ sub_datap->duration = subscription_expires;
+ }
+ scbp->internal = TRUE;
+ } else {
+ /* SCB exists, it is a re-subscribe */
+ reSubscribe = TRUE;
+ }
+
+ scbp->hb.expires = sub_datap->duration;
+ scbp->hb.orig_expiration = sub_datap->duration;
+
+ if (scbp->hb.event_data_p) {
+ free_event_data(scbp->hb.event_data_p);
+ scbp->hb.event_data_p = NULL;
+ }
+
+ // Copy any body received - it will be framed later
+ if (sub_datap->eventData) {
+ scbp->hb.event_data_p = sub_datap->eventData;
+ sub_datap->eventData = NULL;
+ }
+
+ //re-initialize cred_type
+ scbp->hb.authen.cred_type = 0;
+
+ if (sipSPISendSubscribe(scbp, reSubscribe, FALSE /* auth */)) {
+ if (scbp->smState == SUBS_STATE_RCVD_NOTIFY) {
+ scbp->smState = SUBS_STATE_SENT_SUBSCRIBE_RCVD_NOTIFY;
+ } else {
+ scbp->smState = SUBS_STATE_SENT_SUBSCRIBE;
+ }
+ outgoingSubscribes++;
+ if (!reSubscribe) {
+ outgoingSubscriptions++;
+ }
+ return (0);
+ }
+ // If unable to send subscribe, return error immediately
+ // and return scb to the pool if not resubscribing
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"failed to send SUBSCRIBE message\n", fname);
+ sip_send_error_message(&subs_result_data, scbp->subsNotCallbackTask,
+ scbp->subsResCallbackMsgID,
+ scbp->subsResultCallback, fname);
+
+ if (!reSubscribe) {
+ free_scb(scb_index, fname);
+ }
+ return SIP_ERROR;
+}
+
+/***********************************************************
+ * Handle Application Response to a Remote Subscribe Request
+ ***********************************************************/
+int
+subsmanager_handle_ev_app_subscribe_response (cprBuffer_t buf)
+{
+ const char *fname = "subsmanager_handle_ev_app_subscribe_response";
+ sipspi_subscribe_resp_t *subres_datap;
+ sipSCB_t *scbp;
+ sipspi_msg_t *pSIPSPIMsg = NULL;
+
+
+ pSIPSPIMsg = (sipspi_msg_t *) buf;
+
+ subres_datap = &(pSIPSPIMsg->msg.subscribe_resp);
+
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Processing an app subscribe response for"
+ " sub_id=%x\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname), subres_datap->sub_id);
+ /*
+ * Find SCB from the sub_id.
+ */
+ scbp = find_scb_by_sub_id(subres_datap->sub_id, NULL);
+ if (scbp == NULL) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"no SCB for sub_id=%x found\n",
+ fname, subres_datap->sub_id);
+ return SIP_ERROR;
+ }
+
+ scbp->hb.expires = subres_datap->duration;
+ if (sipSPISendSubscribeNotifyResponse
+ (scbp, subres_datap->response_code, scbp->last_recv_request_cseq)) {
+ if (scbp->smState == SUBS_STATE_RCVD_SUBSCRIBE_SENT_NOTIFY) {
+ scbp->smState = SUBS_STATE_SENT_NOTIFY;
+ } else {
+ scbp->smState = SUBS_STATE_ACTIVE;
+ }
+ } else {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"failed to send SUBSCRIBE Response\n", fname);
+ return SIP_ERROR;
+ }
+ return (0);
+}
+
+/********************************************************
+ * Handle Application Generated NOTIFY
+ ********************************************************/
+int
+subsmanager_handle_ev_app_notify (cprBuffer_t buf)
+{
+ const char *fname = "subsmanager_handle_ev_app_notify";
+ sipspi_notify_t *not_datap;
+ sipSCB_t *scbp;
+ ccsip_sub_not_data_t notify_result_data;
+ sipspi_msg_t *pSIPSPIMsg = NULL;
+ sipspi_msg_t *temp_SIPSPIMsg = NULL;
+
+ pSIPSPIMsg = (sipspi_msg_t *) buf;
+
+ not_datap = &(pSIPSPIMsg->msg.notify);
+
+ // Fill in the return data structure in case we encounter any problems
+ notify_result_data.u.notify_result_data.status_code = NOTIFY_REQUEST_FAILED;
+ notify_result_data.msg_id = not_datap->subsNotResCallbackMsgID;
+ notify_result_data.sub_id = not_datap->sub_id;
+
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Processing an app notify request for"
+ " sub_id=%x\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname),
+ not_datap->sub_id);
+ /*
+ * Find SCB from the sub_id.
+ */
+ scbp = find_scb_by_sub_id(not_datap->sub_id, NULL);
+ if (scbp == NULL) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"no SCB for sub_id=%x found\n", fname,
+ not_datap->sub_id);
+ free_event_data(not_datap->eventData);
+ sip_send_error_message(¬ify_result_data,
+ not_datap->subsNotCallbackTask,
+ not_datap->subsNotResCallbackMsgID,
+ not_datap->notifyResultCallback,
+ fname);
+ return SIP_ERROR;
+ }
+
+ notify_result_data.line_id = scbp->hb.dn_line;
+
+ // Check state to see if we need to queue this request
+ if ((scbp->smState == SUBS_STATE_SENT_NOTIFY) ||
+ (scbp->smState == SUBS_STATE_RCVD_SUBSCRIBE_SENT_NOTIFY)) {
+ // This means we have sent a NOTIFY but have not received a response
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Queueing request for later transmission\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname));
+ temp_SIPSPIMsg = (sipspi_msg_t *) cpr_malloc(sizeof(sipspi_msg_t));
+ if (temp_SIPSPIMsg) {
+ /* Copy the content so that we do not touch the pSIPSPImsg */
+ (*temp_SIPSPIMsg) = (*pSIPSPIMsg);
+
+ /* Append the request */
+ if (append_pending_requests(scbp, temp_SIPSPIMsg,
+ SIPSPI_EV_CC_NOTIFY)) {
+ return SIP_DEFER;
+ }
+ cpr_free(temp_SIPSPIMsg);
+ }
+ /* We either do not have buffer or failed to append msg. */
+ free_event_data(not_datap->eventData);
+ sip_send_error_message(¬ify_result_data,
+ not_datap->subsNotCallbackTask,
+ not_datap->subsNotResCallbackMsgID,
+ not_datap->notifyResultCallback,
+ fname);
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Unable to queue request\n", fname);
+ return SIP_ERROR;
+ }
+
+ // Check state to see if we are in a position to send this NOTIFY
+ if (scbp->smState == SUBS_STATE_IDLE) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Bad SCB State: %d\n", fname, scbp->smState);
+ free_event_data(not_datap->eventData);
+ sip_send_error_message(¬ify_result_data,
+ not_datap->subsNotCallbackTask,
+ not_datap->subsNotResCallbackMsgID,
+ not_datap->notifyResultCallback, fname);
+ return SIP_ERROR;
+ }
+
+ // Copy the callback function, if not already copied
+ if (not_datap->notifyResultCallback == NULL &&
+ not_datap->subsNotResCallbackMsgID == 0) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"No callback event or function\n", fname);
+ // Can't really send back any error ...
+ free_event_data(not_datap->eventData);
+ return SIP_ERROR;
+ } else {
+ scbp->notifyResultCallback = not_datap->notifyResultCallback;
+ scbp->notResCallbackMsgID = not_datap->subsNotResCallbackMsgID;
+ }
+
+ if (scbp->hb.event_data_p) {
+ free_event_data(scbp->hb.event_data_p);
+ scbp->hb.event_data_p = NULL;
+ }
+
+ // Copy any body received - it will be framed later
+ if (not_datap->eventData) {
+ scbp->hb.event_data_p = not_datap->eventData;
+ not_datap->eventData = NULL;
+ }
+
+ // Find out if app wants to terminate this subscription
+ if (not_datap->subState == SUBSCRIPTION_TERMINATE) {
+ scbp->hb.expires = 0;
+ }
+
+ //re-initialize cred_type
+ scbp->hb.authen.cred_type = 0;
+
+ if (sipSPISendSubNotify((ccsip_common_cb_t *)scbp, FALSE) != TRUE) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"failed to send Notify Message\n", fname);
+ sip_send_error_message(¬ify_result_data, scbp->subsNotCallbackTask,
+ scbp->notResCallbackMsgID,
+ scbp->notifyResultCallback, fname);
+ return SIP_ERROR;
+ }
+
+ if (scbp->smState == SUBS_STATE_RCVD_SUBSCRIBE) {
+ scbp->smState = SUBS_STATE_RCVD_SUBSCRIBE_SENT_NOTIFY;
+ } else {
+ scbp->smState = SUBS_STATE_SENT_NOTIFY;
+ }
+ outgoingNotifies++;
+
+ return (0);
+}
+
+/**
+ * This function will handle Application Generated unsolicited NOTIFY
+ *
+ * @param[in] buf - pointer to sipspi_msg_t
+ * @param[in] line - line id.
+ *
+ * @return none
+ */
+void subsmanager_handle_ev_app_unsolicited_notify (cprBuffer_t buf, line_t line)
+{
+ const char *fname = "subsmanager_handle_ev_app_unsolicited_notify";
+ sipspi_msg_t *pSIPSPIMsg = NULL;
+ sipspi_notify_t *not_datap;
+ sipTCB_t *tcbp;
+ int nat_enable = 0;
+ static uint32_t trxn_id = 1;
+
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Processing an outgoing unsolicited notify request\n",
+ DEB_F_PREFIX_ARGS(SIP_SUB, fname));
+
+ pSIPSPIMsg = (sipspi_msg_t *) buf;
+ not_datap = &(pSIPSPIMsg->msg.notify);
+
+ /*
+ * If TCB list is not created yet, create the list.
+ */
+ if (s_TCB_list == NULL) {
+ s_TCB_list = sll_create(NULL);
+ if (s_TCB_list == NULL) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"malloc of TCBList failed\n", fname);
+ free_event_data(not_datap->eventData);
+ return;
+ }
+ }
+
+ /*
+ * create a TCB (transaction control block)
+ */
+ tcbp = cpr_malloc(sizeof(sipTCB_t));
+ if (tcbp == NULL) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"malloc of TCB failed\n", fname);
+ free_event_data(not_datap->eventData);
+ return;
+ }
+ memset(tcbp, 0, sizeof(sipTCB_t));
+ tcbp->trxn_id = trxn_id;
+ trxn_id++;
+ if (trxn_id == 0) {
+ trxn_id = 1;
+ }
+ tcbp->timer = cprCreateTimer("Unsolicited transaction timer",
+ SIP_UNSOLICITED_TRANSACTION_TIMER,
+ TIMER_EXPIRATION,
+ sip_msgq);
+ if (tcbp->timer == NULL) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"failed to create a timer\n", fname);
+ free_event_data(not_datap->eventData);
+ cpr_free(tcbp);
+ return;
+ }
+ tcbp->hb.cb_type = UNSOLICIT_NOTIFY_CB;
+ config_get_value(CFGID_NAT_ENABLE, &nat_enable, sizeof(nat_enable));
+ if (nat_enable == 0) {
+ sip_config_get_net_device_ipaddr(&(tcbp->hb.src_addr));
+ } else {
+ sip_config_get_nat_ipaddr(&(tcbp->hb.src_addr));
+ }
+ tcbp->hb.dn_line = line;
+ tcbp->hb.local_port = sipTransportGetListenPort(tcbp->hb.dn_line, NULL);
+
+ tcbp->hb.event_type = not_datap->eventPackage;
+
+ // Copy any body received - it will be framed later
+ if (not_datap->eventData) {
+ tcbp->hb.event_data_p = not_datap->eventData;
+ not_datap->eventData = NULL;
+ }
+ (void) sll_append(s_TCB_list, tcbp);
+
+ if (sipSPISendSubNotify((ccsip_common_cb_t *)tcbp, FALSE) != TRUE) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"failed to send Notify Message\n", fname);
+ free_tcb(tcbp);
+ return;
+ }
+
+ outgoingUnsolicitedNotifies++;
+
+ return;
+}
+
+/**
+ * This function will handle network generated response to unsolicited NOTIFY
+ *
+ * @param[in] pSipMessage - pointer to sipMessage_t
+ * @param[in] tcbp - pointer to associated trnsaction control block.
+ *
+ * @returns SIP_OK/SIP_ERROR
+ */
+int subsmanager_handle_ev_sip_unsolicited_notify_response (sipMessage_t *pSipMessage, sipTCB_t *tcbp)
+{
+ int response_code = 0;
+ const char *fname = "subsmanager_handle_ev_sip_unsolicited_notify_response";
+
+ // Parse the return code
+ (void) sipGetResponseCode(pSipMessage, &response_code);
+
+ /*
+ * if the response is < 200, do nothing.
+ */
+ if (response_code < 200) {
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"received %d response\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname), response_code);
+ return SIP_OK;
+ }
+
+ if ((response_code == SIP_CLI_ERR_UNAUTH) ||
+ (response_code == SIP_CLI_ERR_PROXY_REQD)) {
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Authentication Required\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname));
+ if (ccsip_common_util_generate_auth(pSipMessage, &tcbp->hb, SIP_METHOD_NOTIFY,
+ response_code, tcbp->full_ruri) == TRUE) {
+ if (sipSPISendSubNotify((ccsip_common_cb_t *)tcbp, TRUE) == TRUE) {
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"sent request with Auth header\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname));
+ return SIP_OK;
+ }
+ }
+ free_tcb (tcbp);
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"failed to respond to auth challenge\n", fname);
+ return SIP_ERROR;
+ }
+
+ free_tcb(tcbp);
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"received %d response\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname), response_code);
+ return SIP_OK;
+}
+
+/**
+ * This function will handle outgoing unsolicited NOTIFY transaction timeout.
+ *
+ * @param[in] data - pointer to an id that identifies the TCB.
+ *
+ * @returns none.
+ */
+void subsmanager_unsolicited_notify_timeout (void *data)
+{
+ const char *fname = "subsmanager_unsolicited_notify_timeout";
+ uint32_t trxn_id = (long)data;
+ sipTCB_t *temp_tcbp = NULL;
+
+ /*
+ * make sure that the TCB still exists.
+ */
+ temp_tcbp = (sipTCB_t *)sll_next(s_TCB_list, NULL);
+ while (temp_tcbp != NULL) {
+ if (temp_tcbp->trxn_id == trxn_id) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"unsolicited notify transaction timedout\n", fname);
+ free_tcb(temp_tcbp);
+ return;
+ }
+ temp_tcbp = (sipTCB_t *)sll_next(s_TCB_list, temp_tcbp);
+ }
+}
+
+/**********************************************************
+ * Handle Application Response to a received Notify request
+ **********************************************************/
+int
+subsmanager_handle_ev_app_notify_response (cprBuffer_t buf)
+{
+ sipspi_notify_resp_t *notify_resp;
+ sipSCB_t *scbp = NULL;
+ sipspi_msg_t *pSIPSPIMsg = NULL;
+ uint32_t cseq;
+ const char *fname = "subsmanager_handle_ev_app_notify_response";
+
+ pSIPSPIMsg = (sipspi_msg_t *) buf;
+
+ notify_resp = &(pSIPSPIMsg->msg.notify_resp);
+
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Processing an app notify response for"
+ " sub_id=%x\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname),
+ notify_resp->sub_id);
+
+ // Retrieve response parameters
+ /*
+ * Find SCB from the sub_id.
+ */
+ scbp = find_scb_by_sub_id(notify_resp->sub_id, NULL);
+ if (scbp == NULL) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"no SCB for sub_id=%x found\n",
+ fname, notify_resp->sub_id);
+ return SIP_ERROR;
+ }
+
+ if (notify_resp->cseq == 0) {
+ cseq = scbp->last_recv_request_cseq;
+ } else {
+ cseq = notify_resp->cseq;
+ }
+ // Call function to make and send the response
+ if (sipSPISendSubscribeNotifyResponse(scbp,
+ (uint16_t)(notify_resp->response_code), cseq)) {
+ /*
+ * if the outstanding NOTIFY transaction is only one,
+ * then update the scbp->smState.
+ */
+ if (scbp->outstandingIncomingNotifyTrxns == 1) {
+ if (scbp->smState == SUBS_STATE_SENT_SUBSCRIBE_RCVD_NOTIFY) {
+ scbp->smState = SUBS_STATE_SENT_SUBSCRIBE;
+ } else {
+ scbp->smState = SUBS_STATE_ACTIVE;
+ }
+ }
+ scbp->outstandingIncomingNotifyTrxns -= 1;
+ return (0);
+ }
+ return SIP_ERROR;
+}
+
+/********************************************************
+ * Handle Application Request to Terminate Subscription
+ ********************************************************/
+int
+subsmanager_handle_ev_app_subscription_terminated (cprBuffer_t buf)
+{
+ /*
+ * This function is used by the application to clean up a subscription
+ * whether internally or externally initiated. The application should have
+ * taken care of all the protocol related messaging before calling this
+ * function.
+ */
+ const char *fname = "subsmanager_handle_ev_app_subscription_terminated";
+ sipspi_subscribe_term_t *subs_term;
+ int scb_index;
+ sipSCB_t *scbp;
+ sipspi_msg_t *pSIPSPIMsg = NULL;
+
+
+ pSIPSPIMsg = (sipspi_msg_t *) buf;
+
+ subs_term = &(pSIPSPIMsg->msg.subs_term);
+
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Processing terminate request for sub_id=%x\n",
+ DEB_F_PREFIX_ARGS(SIP_SUB, fname), subs_term->sub_id);
+ /*
+ * Find SCB from the sub_id and allow matching with request ID and
+ * eventPackage if sub id is not known.
+ */
+ if (subs_term->sub_id == CCSIP_SUBS_INVALID_SUB_ID) {
+ /*
+ * find scb based on request_id and event package.
+ * This scenario is possible if application decides to terminate a
+ * subscription before subsmanager provides app with sub_id.
+ */
+ for (scb_index = 0; scb_index < MAX_SCBS; scb_index++) {
+ if ((subsManagerSCBS[scb_index].request_id == subs_term->request_id) &&
+ (subsManagerSCBS[scb_index].hb.event_type == subs_term->eventPackage) &&
+ (!subsManagerSCBS[scb_index].pendingClean)) {
+ break;
+ }
+ }
+ if (scb_index >= MAX_SCBS) {
+ scbp = NULL;
+ } else {
+ scbp = &(subsManagerSCBS[scb_index]);
+ }
+ } else {
+ /* Find SCB by sub_id */
+ scbp = find_scb_by_sub_id(subs_term->sub_id, &scb_index);
+ }
+ if (scbp == NULL) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"no SCB for sub_id=%x or request id %d"
+ " and eventPackage %d found\n", fname,
+ subs_term->sub_id, subs_term->request_id,
+ subs_term->eventPackage);
+ return SIP_ERROR;
+ }
+ if (scbp->smState == SUBS_STATE_IDLE || scbp->pendingClean) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"SCB: scb=%d sub_id=%x has already been"
+ " cleaned up\n", fname,
+ scb_index, subs_term->sub_id);
+ return 0;
+ }
+
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Cleaning out subscription for SCB: scb=%d sub_id=%x\n",
+ DEB_F_PREFIX_ARGS(SIP_SUB, fname), scb_index, scbp->sub_id);
+
+ if (scbp->internal) {
+ outgoingSubscriptions--;
+ } else {
+ incomingSubscriptions--;
+ }
+
+ // There could still be messages left to receive and flush, so if not
+ // immediate, we mark this SCB as pending deletion and we will clean it up
+ // later
+ if (subs_term->immediate) {
+ free_scb(scb_index, fname);
+ } else {
+ scbp->pendingClean = TRUE;
+ if (scbp->pendingRequests)
+ scbp->pendingCount = 2 * TMR_PERIODIC_SUBNOT_INTERVAL;
+ else
+ scbp->pendingCount = 1 * TMR_PERIODIC_SUBNOT_INTERVAL;
+ }
+
+ return (0);
+}
+
+
+/********************************************************
+ * Handle network response to a Sub/Not request
+ ********************************************************/
+int
+subsmanager_handle_ev_sip_response (sipMessage_t *pSipMessage)
+{
+ const char *fname = "subsmanager_handle_ev_sip_response";
+ sipSCB_t *scbp;
+ int scb_index;
+ ccsip_sub_not_data_t sub_not_result_data;
+
+ // currently not used SysHdr *pSm = NULL;
+ int response_code = 0;
+ const char *pCallID = NULL;
+ const char *rsp_method = NULL;
+ sipMethod_t method = sipMethodInvalid;
+ sipStatusCodeClass_t code_class = codeClassInvalid;
+ const char *expires = NULL;
+ long expiry_time;
+ const char *to = NULL, *from = NULL;
+ const char *record_route = NULL;
+ sipLocation_t *to_loc = NULL;
+ sipCseq_t *resp_cseq_structure = NULL;
+ uint32_t cseq;
+
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Processing a response\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname));
+
+ if (sipGetResponseMethod(pSipMessage, &method) < 0) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname, "sipGetResponseMethod");
+ return SIP_ERROR;
+ }
+ if (method == sipMethodSubscribe) {
+ rsp_method = SIP_METHOD_SUBSCRIBE;
+ } else if (method == sipMethodRefer) {
+ rsp_method = SIP_METHOD_REFER;
+ } else {
+ rsp_method = SIP_METHOD_NOTIFY;
+ }
+
+ pCallID = sippmh_get_cached_header_val(pSipMessage, CALLID);
+ if (!pCallID) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Cannot obtain SIP Call ID.\n", fname);
+ return SIP_ERROR;
+ }
+
+ if (!getCSeqInfo(pSipMessage, &resp_cseq_structure)) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Cannot obtain SIP CSEQ.\n", fname);
+ return SIP_ERROR;
+ }
+ cseq = resp_cseq_structure->number;
+ cpr_free(resp_cseq_structure);
+
+ // Locate request scbp from that match the response
+ scbp = find_req_scb(pCallID, method, cseq, &scb_index);
+ if (!scbp) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"No matching request found\n", fname);
+ return SIP_ERROR;
+ }
+ // Cancel any outstanding retry timer
+ if (scbp->hb.retx_flag == TRUE) {
+ sip_platform_msg_timer_subnot_stop(&sipPlatformUISMSubNotTimers[scb_index]);
+ scbp->hb.retx_flag = FALSE;
+ }
+ // Parse the return code
+ (void) sipGetResponseCode(pSipMessage, &response_code);
+ code_class = sippmh_get_code_class((uint16_t) response_code);
+
+ /*
+ * If it is a response (18x/2xx) to a dialog initiating SUBSCRIBE,
+ * parse the Record-Route header and set up Route set for this dialog.
+ * If the sip_to_tag is not yet populated and if there is no associated
+ * CCB, then this can be considered as a response to dialog
+ * initating SUBSCRIBE.
+ */
+ if ((strcmp(rsp_method, SIP_METHOD_SUBSCRIBE) == 0) &&
+ (scbp->ccbp == NULL) && (scbp->sip_to_tag[0] == '\0')) {
+ if (((response_code >= 180) && (response_code <= 189)) ||
+ ((response_code >= 200) && (response_code <= 299))) {
+ record_route = sippmh_get_cached_header_val(pSipMessage,
+ RECORD_ROUTE);
+ if (record_route) {
+ if (scbp->record_route_info) {
+ sippmh_free_record_route(scbp->record_route_info);
+ }
+ scbp->record_route_info = sippmh_parse_record_route(record_route);
+ if (scbp->record_route_info == NULL) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"sippmh_parse_record_route() failed",
+ fname);
+ return SIP_ERROR;
+ }
+ }
+ }
+ }
+
+ if ((response_code == SIP_CLI_ERR_UNAUTH) ||
+ (response_code == SIP_CLI_ERR_PROXY_REQD)) {
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Authentication Required\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname));
+ if (ccsip_common_util_generate_auth(pSipMessage, (ccsip_common_cb_t *)scbp, rsp_method,
+ response_code, scbp->SubURI) == TRUE) {
+ // Send Sub/Not message again - this time with authorization
+ if ((method == sipMethodSubscribe) || (method == sipMethodRefer)) {
+ (void) sipSPISendSubscribe(scbp, TRUE, TRUE);
+ } else {
+ (void) sipSPISendSubNotify((ccsip_common_cb_t *)scbp, TRUE);
+ }
+ } else {
+ // Return error to caller
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"failed to generate Auth header", fname);
+ return SIP_ERROR;
+ }
+ return (0);
+ }
+
+ // If this subscription has been cleaned by the application, then
+ // return SCB to IDLE state and discard this response
+ if (scbp->pendingClean) {
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Recd msg for terminated sub\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname));
+ if (scbp->pendingRequests) {
+ scbp->pendingCount += TMR_PERIODIC_SUBNOT_INTERVAL;
+ scbp->smState = SUBS_STATE_ACTIVE;
+ handle_pending_requests(scbp);
+ } else {
+ free_scb(scb_index, fname);
+ }
+ return (0);
+ }
+
+ /*
+ * if response code is 423, grab Min-Expires and let app know so
+ * that it can be used for subsequent subscriptions.
+ */
+ if ((response_code == SIP_CLI_ERR_INTERVAL_TOO_SMALL) &&
+ (strcmp(rsp_method, SIP_METHOD_SUBSCRIBE) == 0)) {
+ expires = sippmh_get_header_val(pSipMessage,
+ (const char *)SIP_HEADER_MIN_EXPIRES,
+ NULL);
+ if (expires) {
+ expiry_time = strtoul(expires, NULL, 10);
+ //ensure new Min-Expires is > what we set before in Expires
+ if ((long) expiry_time > scbp->hb.expires) {
+ scbp->hb.expires = expiry_time;
+ }
+ }
+ } else {
+ // Get the expires header value and add to scb
+ expires = sippmh_get_header_val(pSipMessage, SIP_HEADER_EXPIRES, NULL);
+ if (expires) {
+ expiry_time = strtoul(expires, NULL, 10);
+ scbp->hb.expires = expiry_time;
+ }
+ }
+
+ // update to and from headers to capture the tag
+ if (strcmp(rsp_method, SIP_METHOD_SUBSCRIBE) == 0) {
+ to = sippmh_get_cached_header_val(pSipMessage, TO);
+ from = sippmh_get_cached_header_val(pSipMessage, FROM);
+ scbp->sip_to = strlib_update(scbp->sip_to, to);
+ // grab the to-tag if present, and if this is a response to a SUBSCRIBE
+ to_loc = sippmh_parse_from_or_to((char *) to, TRUE);
+ if (to_loc != NULL) {
+ if (to_loc->tag != NULL) {
+ scbp->sip_to_tag = strlib_update(scbp->sip_to_tag,
+ sip_sm_purify_tag(to_loc->tag));
+ }
+ sippmh_free_location(to_loc);
+ }
+ scbp->sip_from = strlib_update(scbp->sip_from, from);
+ }
+
+ // Delete body, if any, since it is no longer needed
+ if (code_class > codeClass1xx) {
+ if (scbp->hb.event_data_p) {
+ free_event_data(scbp->hb.event_data_p);
+ scbp->hb.event_data_p = NULL;
+ }
+ }
+
+ if ((scbp->smState == SUBS_STATE_SENT_SUBSCRIBE_RCVD_NOTIFY) ||
+ (scbp->smState == SUBS_STATE_SENT_SUBSCRIBE)) {
+ sub_not_result_data.u.subs_result_data.expires = scbp->hb.expires;
+ sub_not_result_data.u.subs_result_data.status_code = response_code;
+ sub_not_result_data.request_id = scbp->request_id;
+ sub_not_result_data.sub_id = scbp->sub_id;
+ sub_not_result_data.msg_id = scbp->subsResCallbackMsgID;
+ sub_not_result_data.gsm_id = scbp->gsm_id;
+ sub_not_result_data.line_id = scbp->hb.dn_line;
+
+ if (code_class > codeClass1xx) {
+ if (scbp->smState == SUBS_STATE_SENT_SUBSCRIBE_RCVD_NOTIFY) {
+ scbp->smState = SUBS_STATE_RCVD_NOTIFY;
+ } else {
+ scbp->smState = SUBS_STATE_ACTIVE;
+ }
+ }
+
+ if (scbp->subsResultCallback) {
+ (scbp->subsResultCallback) (&sub_not_result_data);
+ } else if (scbp->subsNotCallbackTask != CC_SRC_MIN) {
+ (void) sip_send_message(&sub_not_result_data,
+ scbp->subsNotCallbackTask,
+ scbp->subsResCallbackMsgID);
+ }
+ } else if ((scbp->smState == SUBS_STATE_SENT_NOTIFY) ||
+ (scbp->smState == SUBS_STATE_RCVD_SUBSCRIBE_SENT_NOTIFY)) {
+ sub_not_result_data.u.notify_result_data.status_code = response_code;
+ sub_not_result_data.request_id = scbp->request_id;
+ sub_not_result_data.sub_id = scbp->sub_id;
+ sub_not_result_data.msg_id = scbp->notResCallbackMsgID;
+ sub_not_result_data.gsm_id = scbp->gsm_id;
+ sub_not_result_data.line_id = scbp->hb.dn_line;
+
+ if (code_class > codeClass1xx) {
+ if (scbp->smState == SUBS_STATE_RCVD_SUBSCRIBE_SENT_NOTIFY) {
+ scbp->smState = SUBS_STATE_RCVD_SUBSCRIBE;
+ } else {
+ scbp->smState = SUBS_STATE_ACTIVE;
+ }
+ }
+
+ if (scbp->notifyResultCallback) {
+ (scbp->notifyResultCallback) (&sub_not_result_data);
+ } else if (scbp->subsNotCallbackTask != CC_SRC_MIN) {
+ (void) sip_send_message(&sub_not_result_data,
+ scbp->subsNotCallbackTask,
+ scbp->notResCallbackMsgID);
+ }
+ // If there are pending requests - handle them now
+ if (scbp->pendingRequests) {
+ handle_pending_requests(scbp);
+ }
+ } else {
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Incorrect SCB State\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname));
+ return SIP_ERROR;
+ }
+
+ return (0);
+}
+
+/********************************************************
+ * Handle Network Received Subscribe Request
+ ********************************************************/
+int
+subsmanager_handle_ev_sip_subscribe (sipMessage_t *pSipMessage,
+ sipMethod_t sipMethod,
+ boolean in_dialog)
+{
+ const char *fname = "subsmanager_handle_ev_sip_subscribe";
+ const char *event = NULL;
+ cc_subscriptions_t eventPackage = CC_SUBSCRIPTIONS_NONE;
+ sipSCB_t *scbpReg = NULL, *scbp = NULL;
+ const char *callID = NULL, *via = NULL;
+ const char *contact = NULL;
+ const char *record_route = NULL;
+ const char *expires = NULL;
+ const char *require = NULL, *supported = NULL;
+ sipCseq_t *request_cseq_structure = NULL;
+ unsigned long request_cseq_number = 0, expiry_time = 0;
+
+ // currently not used unsigned long diff_time = 0;
+ sipMethod_t request_cseq_method = sipMethodInvalid;
+ unsigned int content_length = 0;
+ line_t dn_line = 0;
+ boolean request_uri_error = FALSE;
+ sipReqLine_t *requestURI = NULL;
+
+ // currently not used sipLocation_t *uri_loc = NULL;
+ genUrl_t *genUrl = NULL;
+ const char *sip_from = NULL;
+ const char *sip_to = NULL;
+ sipLocation_t *to_loc = NULL;
+ sipLocation_t *from_loc = NULL;
+ sipUrl_t *sipUriUrl = NULL, *sipFromUrl = NULL;
+ char *pUser = NULL;
+ char *sip_to_tag_temp, *sip_to_temp;
+ char *kpml_call_id = NULL, *from_tag, *to_tag;
+ ccsip_event_data_t *subDatap = NULL;
+ int scb_index;
+ boolean reSubscribe = FALSE;
+ ccsip_sub_not_data_t subs_ind_data;
+ ccsipCCB_t *ccb = NULL;
+ char *referToString = NULL;
+ uint32_t tags = 0;
+ int result;
+ int requestStatus = SIP_MESSAGING_ERROR;
+ uint8_t i;
+ char line_contact[MAX_LINE_CONTACT_SIZE];
+ char line_name[MAX_LINE_NAME_SIZE];
+ int noOfReferTo = 0;
+ sipServiceControl_t *scp=NULL;
+
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Processing a new SIP subscription request\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname));
+
+ if (!subsManagerRunning) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Subscription Manager Not Initialized!\n", fname);
+ return SIP_ERROR;
+ }
+
+ /* Steps:
+ * * Check request for support by a registered app
+ * * If not, reject the request as unsupported
+ * * Decode the body, if any, and if understood
+ * * Allocate and fill in SCB
+ * * Call the callback function by registered application
+ */
+ if (!in_dialog) {
+ requestStatus = sipSPICheckRequest(NULL, pSipMessage);
+ if (requestStatus != SIP_MESSAGING_OK) {
+ if (requestStatus == SIP_MESSAGING_DUPLICATE) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Recieved duplicate request\n", fname);
+ } else {
+ if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ SIP_WARN_MISC, NULL, NULL) != TRUE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
+ fname, SIP_CLI_ERR_BAD_REQ);
+ }
+ }
+ return SIP_ERROR;
+ }
+ }
+
+ memset(&subs_ind_data, 0, sizeof(ccsip_sub_not_data_t));
+
+ // Get relevant parameters from the SIP message
+ // These are: Event, Subscription-State, Accept, Content-Length besides
+ // To, From, Via, Call-ID, CSeq, and Contact
+
+ event = sippmh_get_header_val(pSipMessage, SIP_HEADER_EVENT,
+ SIP_C_HEADER_EVENT);
+
+ if (event) {
+ if (cpr_strcasecmp(event, "dialog") == 0) {
+ eventPackage = CC_SUBSCRIPTIONS_DIALOG;
+ } else if (cpr_strncasecmp(event, "kpml", 4) == 0) {
+ eventPackage = CC_SUBSCRIPTIONS_KPML;
+ } else if (cpr_strcasecmp(event, "presence") == 0) {
+ eventPackage = CC_SUBSCRIPTIONS_PRESENCE;
+ } else {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Unsupported event=%s\n", fname, event);
+ if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_EVENT,
+ SIP_CLI_ERR_BAD_EVENT_PHRASE,
+ 0, NULL, NULL) != TRUE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
+ fname, SIP_CLI_ERR_BAD_EVENT);
+ }
+ return SIP_ERROR;
+ }
+ } else if (sipMethod == sipMethodRefer) {
+
+ } else if (sipMethod == sipMethodBye) {
+
+ return SIP_ERROR;
+
+ } else {
+ // Reached here in error
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"No event header\n", fname);
+ if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_EVENT,
+ SIP_CLI_ERR_BAD_EVENT_PHRASE,
+ SIP_WARN_MISC,
+ NULL,
+ NULL) != TRUE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
+ fname, SIP_CLI_ERR_BAD_EVENT);
+ }
+ return SIP_ERROR;
+ }
+
+
+ // Parse Call-ID
+ callID = sippmh_get_cached_header_val(pSipMessage, CALLID);
+ if (!callID) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Unable to obtain request's "
+ "Call-ID header.\n", fname);
+ if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ SIP_WARN_MISC,
+ SIP_CLI_ERR_BAD_REQ_CALLID_ABSENT,
+ NULL) != TRUE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
+ fname, SIP_CLI_ERR_BAD_REQ);
+ }
+ return SIP_ERROR;
+ }
+ // Check content
+ content_length = sippmh_get_content_length(pSipMessage);
+
+ if (pSipMessage->raw_body) {
+ if (content_length != strlen(pSipMessage->raw_body)) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"\n Mismatched Content length and \
+ Actual message body length:content length=%d \
+ \n and message as %s \
+ \n and strlenof messagebody = %d\n", fname,
+ content_length, pSipMessage->raw_body,
+ strlen(pSipMessage->raw_body));
+ if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ SIP_WARN_MISC,
+ SIP_CLI_ERR_BAD_REQ_CONTENT_LENGTH_ERROR,
+ NULL) != TRUE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
+ fname, SIP_CLI_ERR_BAD_REQ);
+ }
+ return SIP_ERROR;
+ }
+ } else if (content_length != 0) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"\n Mismatched Content length and \
+ Actual message body length:content length=%d \
+ \n and message is EMPTY \
+ \n and strlenof messagebody = 0\n", fname,
+ content_length);
+ if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ SIP_WARN_MISC,
+ SIP_CLI_ERR_BAD_REQ_CONTENT_LENGTH_ERROR,
+ NULL) != TRUE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
+ fname, SIP_CLI_ERR_BAD_REQ);
+ }
+ return SIP_ERROR;
+ }
+ // Parse CSEQ
+ if (getCSeqInfo(pSipMessage, &request_cseq_structure) == FALSE) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Unable to obtain or parse request's CSeq "
+ "header.\n", fname);
+ if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ SIP_WARN_MISC,
+ SIP_CLI_ERR_BAD_REQ_CSEQ_FIELD,
+ NULL) != TRUE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
+ fname, SIP_CLI_ERR_BAD_REQ);
+ }
+ return SIP_ERROR;
+ }
+
+ request_cseq_number = request_cseq_structure->number;
+ request_cseq_method = request_cseq_structure->method;
+ cpr_free(request_cseq_structure);
+
+ // Parse From
+ sip_from = sippmh_get_cached_header_val(pSipMessage, FROM);
+ from_loc = sippmh_parse_from_or_to((char *) sip_from, TRUE);
+ if (!from_loc) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname,
+ get_debug_string(DEBUG_FUNCTIONNAME_SIPPMH_PARSE_FROM));
+ if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ SIP_WARN_MISC,
+ SIP_CLI_ERR_BAD_REQ_FROM_OR_TO_FIELD,
+ NULL) != TRUE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
+ fname, SIP_CLI_ERR_BAD_REQ);
+ }
+ return SIP_ERROR;
+ }
+ // Parse To
+ sip_to = sippmh_get_cached_header_val(pSipMessage, TO);
+ to_loc = sippmh_parse_from_or_to((char *) sip_to, TRUE);
+ if (!to_loc) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
+ fname,
+ get_debug_string(DEBUG_FUNCTIONNAME_SIPPMH_PARSE_TO));
+ if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ SIP_WARN_MISC,
+ SIP_CLI_ERR_BAD_REQ_FROM_OR_TO_FIELD,
+ NULL) != TRUE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
+ fname, SIP_CLI_ERR_BAD_REQ);
+ }
+ sippmh_free_location(from_loc);
+ return SIP_ERROR;
+ }
+ // Parse Req-URI
+ requestURI = sippmh_get_request_line(pSipMessage);
+ if (requestURI) {
+ if (requestURI->url) {
+ genUrl = sippmh_parse_url(requestURI->url, TRUE);
+ if (genUrl) {
+ if (genUrl->schema != URL_TYPE_SIP) {
+ request_uri_error = TRUE;
+ }
+ } else {
+ request_uri_error = TRUE;
+ }
+ } else {
+ request_uri_error = TRUE;
+ }
+
+ } else {
+ request_uri_error = TRUE;
+ }
+ if (request_uri_error) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Invalid Request URI" "failed.\n", fname);
+ if (to_loc)
+ sippmh_free_location(to_loc);
+ if (from_loc)
+ sippmh_free_location(from_loc);
+ if (genUrl)
+ sippmh_genurl_free(genUrl);
+ if (requestURI)
+ SIPPMH_FREE_REQUEST_LINE(requestURI);
+ if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ SIP_WARN_MISC,
+ SIP_CLI_ERR_BAD_REQ_URL_ERROR,
+ NULL) != TRUE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
+ fname, SIP_CLI_ERR_BAD_REQ);
+ }
+ return SIP_ERROR;
+ }
+ // Parse Expires header
+ expires = sippmh_get_header_val(pSipMessage, SIP_HEADER_EXPIRES, NULL);
+ if (expires) {
+ expiry_time = strtoul(expires, NULL, 10);
+ } else {
+ // No expires header, use default
+ expiry_time = 3600;
+ }
+
+ scbp = find_scb_by_subscription(eventPackage, &scb_index, callID);
+ if (scbp && eventPackage == scbp->hb.event_type) {
+ // SCB is already there - must be a re-subscribe
+ reSubscribe = TRUE;
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Received a reSubscribe Message\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname));
+ if (scbp->pendingClean) {
+ // Oops, the application has already terminated this subscription
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Subscribe received for subscription "
+ "already terminated by application.\n", fname);
+ if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ SIP_WARN_MISC,
+ SIP_CLI_ERR_BAD_REQ_SUBSCRIPTION_DELETED,
+ NULL) != TRUE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
+ fname, SIP_CLI_ERR_BAD_REQ);
+ }
+ sippmh_free_location(to_loc);
+ sippmh_free_location(from_loc);
+ sippmh_genurl_free(genUrl);
+ SIPPMH_FREE_REQUEST_LINE(requestURI);
+ return SIP_ERROR;
+ }
+ // Check continuity of CSeq numbers
+ if (request_cseq_number <= scbp->last_recv_request_cseq) {
+ // Return 500 Internal Server Error
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Out of order CSeq number received\n",
+ fname);
+ if (sipSPISendErrorResponse(pSipMessage, SIP_SERV_ERR_INTERNAL,
+ SIP_SERV_ERR_INTERNAL_PHRASE,
+ SIP_WARN_MISC,
+ SIP_CLI_ERR_BAD_REQ_CSEQ_FIELD,
+ NULL) != TRUE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
+ fname, SIP_SERV_ERR_INTERNAL);
+ }
+ sippmh_free_location(to_loc);
+ sippmh_free_location(from_loc);
+ sippmh_genurl_free(genUrl);
+ SIPPMH_FREE_REQUEST_LINE(requestURI);
+ return SIP_ERROR;
+ }
+
+ sippmh_free_location(to_loc);
+ sippmh_free_location(from_loc);
+ sippmh_genurl_free(genUrl);
+ SIPPMH_FREE_REQUEST_LINE(requestURI);
+ } else {
+ // Check if this is a SUBSCRIBE request for an already terminated
+ // subscription. If this subscription is associated with an
+ // existing dialog, let it go
+ ccb = sip_sm_get_ccb_by_callid(callID);
+ if ((ccb == NULL) &&
+ is_previous_sub(callID, from_loc->tag, eventPackage)) {
+ // Return 481 Internal Server Error
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"SUBSCRIBE received for terminated "
+ "subscription\n", fname);
+ if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_CALLEG,
+ SIP_CLI_ERR_CALLEG_PHRASE,
+ SIP_WARN_MISC,
+ SIP_CLI_ERR_BAD_REQ_SUBSCRIPTION_DELETED,
+ NULL) != TRUE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
+ fname, SIP_CLI_ERR_CALLEG);
+ }
+ sippmh_free_location(to_loc);
+ sippmh_free_location(from_loc);
+ sippmh_genurl_free(genUrl);
+ SIPPMH_FREE_REQUEST_LINE(requestURI);
+ return SIP_ERROR;
+ }
+ // This is a valid new subscription - get all the params
+ scbpReg = find_scb_by_registration(eventPackage, &scb_index);
+ if (!scbpReg) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"No application registered "
+ "to accept this event.\n", fname);
+ if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_EVENT,
+ SIP_CLI_ERR_BAD_EVENT_PHRASE,
+ 0, NULL, NULL) != TRUE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
+ fname, SIP_CLI_ERR_BAD_EVENT);
+ }
+ sippmh_free_location(to_loc);
+ sippmh_free_location(from_loc);
+ sippmh_genurl_free(genUrl);
+ SIPPMH_FREE_REQUEST_LINE(requestURI);
+ return SIP_ERROR;
+ }
+
+ scbp = allocate_scb(&scb_index);
+ if (!scbp) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"No SCB Available "
+ "to accept this event.\n", fname);
+ if (sipSPISendErrorResponse(pSipMessage, SIP_SERV_ERR_INTERNAL,
+ SIP_SERV_ERR_INTERNAL_PHRASE,
+ 0, NULL, NULL) != TRUE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
+ fname, SIP_CLI_ERR_BAD_REQ);
+ }
+ sippmh_free_location(to_loc);
+ sippmh_free_location(from_loc);
+ sippmh_genurl_free(genUrl);
+ SIPPMH_FREE_REQUEST_LINE(requestURI);
+ show_scbs_inuse();
+ return SIP_ERROR;
+ }
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Allocated SCB for Received Subscribe, event=%d,"
+ " scb=%d sub_id=%x\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname), scbpReg->hb.event_type,
+ scb_index, scbp->sub_id);
+ scbp->hb.event_type = scbpReg->hb.event_type;
+ scbp->subsIndCallback = scbpReg->subsIndCallback;
+ scbp->subsIndCallbackTask = scbpReg->subsIndCallbackTask;
+ scbp->subsNotCallbackTask = scbpReg->subsNotCallbackTask;
+ scbp->subsIndCallbackMsgID = scbpReg->subsIndCallbackMsgID;
+ scbp->subsTermCallback = scbpReg->subsTermCallback;
+ scbp->subsTermCallbackMsgID = scbpReg->subsTermCallbackMsgID;
+ sstrncpy(scbp->event_name, scbpReg->event_name, MAX_EVENT_NAME_LEN);
+
+ scbp->internal = FALSE;
+
+ /* If the event package is KPML then check if the ID values
+ * are associated with it
+ */
+ if (eventPackage == CC_SUBSCRIPTIONS_KPML) {
+ /*
+ * At this point from_tag and to_tag is never used. Since
+ * kpml_call_id, from_tag and to_tag just point to the
+ * appropriate location and does not allocate memory by itself.
+ */
+ (void) sippmh_parse_kpml_event_id_params((char *)event,
+ &kpml_call_id,
+ &from_tag,
+ &to_tag);
+ }
+
+ if (kpml_call_id) {
+ ccb = sip_sm_get_ccb_by_callid(kpml_call_id);
+ } else {
+ ccb = sip_sm_get_ccb_by_callid(callID);
+ scbp->ccbp = ccb;
+ }
+ if (ccb) {
+ scbp->gsm_id = ccb->gsm_id;
+ scbp->hb.dn_line = ccb->dn_line;
+ } else {
+ scbp->gsm_id = 0;
+ scbp->hb.dn_line = 0;
+ }
+ // Parse Supported and Required headers to see if there is the
+ // norefersub option tag specified
+ require = sippmh_get_cached_header_val(pSipMessage, REQUIRE);
+ if (require) {
+ tags = sippmh_parse_supported_require(require, NULL);
+ if (tags & norefersub_tag) {
+ scbp->norefersub = TRUE;
+ }
+ }
+ if ((eventPackage == CC_SUBSCRIPTIONS_CONFIGAPP) &&
+ (scbp->norefersub == FALSE)) {
+ //noReferSub tag is required for OOD Refer for config change
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"noReferSub missing from Require header.\n",
+ fname);
+ if (sipSPISendErrorResponse(pSipMessage,
+ SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ SIP_WARN_MISC,
+ SIP_CLI_ERR_BAD_REQ_REQUIRE_HDR,
+ NULL) != TRUE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
+ fname, SIP_CLI_ERR_BAD_REQ);
+ }
+ free_scb(scb_index, fname);
+ sippmh_free_location(to_loc);
+ sippmh_free_location(from_loc);
+ sippmh_genurl_free(genUrl);
+ SIPPMH_FREE_REQUEST_LINE(requestURI);
+ return SIP_ERROR;
+ }
+ supported = sippmh_get_cached_header_val(pSipMessage, SUPPORTED);
+ if (supported) {
+ tags = sippmh_parse_supported_require(supported, NULL);
+ if (tags & norefersub_tag) {
+ scbp->norefersub = TRUE;
+ }
+ }
+ // Check to see if the expires value is within the acceptable range,
+ // if any has been given to us
+ if (scbp->min_expires != 0) {
+ if (expiry_time < scbp->min_expires && expiry_time < 3600) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Too small expiry time: %d; "
+ "Min acceptable: %d.\n", fname,
+ expiry_time, scbp->min_expires);
+
+ if (sipSPISendErrorResponse(pSipMessage,
+ SIP_CLI_ERR_INTERVAL_TOO_SMALL,
+ SIP_CLI_ERR_INTERVAL_TOO_SMALL_PHRASE,
+ 0, NULL, NULL) != TRUE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
+ fname, SIP_CLI_ERR_INTERVAL_TOO_SMALL);
+ }
+ free_scb(scb_index, fname);
+ sippmh_free_location(to_loc);
+ sippmh_free_location(from_loc);
+ sippmh_genurl_free(genUrl);
+ SIPPMH_FREE_REQUEST_LINE(requestURI);
+ return SIP_ERROR;
+ }
+ }
+ if (scbp->max_expires != 0) {
+ if (expiry_time > scbp->max_expires) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Too large expiry time: %d; "
+ "Max acceptable: %d.\n", fname,
+ expiry_time, scbp->max_expires);
+ // There doesn't seem to be any particular error code for
+ // maximum expiry time so just return the generic error
+ if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ SIP_WARN_MISC,
+ SIP_CLI_ERR_INTERVAL_TOO_LARGE_PHRASE,
+ NULL) != TRUE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
+ fname, SIP_CLI_ERR_BAD_REQ);
+ }
+ CCSIP_DEBUG_TASK(DEB_F_PREFIX"Freeing SCB: scb=%d sub_id=%x\n",
+ DEB_F_PREFIX_ARGS(SIP_SUB, fname), scb_index, scbp->sub_id);
+ free_scb(scb_index, fname);
+ sippmh_free_location(to_loc);
+ sippmh_free_location(from_loc);
+ sippmh_genurl_free(genUrl);
+ SIPPMH_FREE_REQUEST_LINE(requestURI);
+ return SIP_ERROR;
+ }
+ }
+ sipUriUrl = genUrl->u.sipUrl;
+ if (sipUriUrl) {
+ pUser = sippmh_parse_user(sipUriUrl->user);
+ if (pUser) {
+ sstrncpy(scbp->SubURI, pUser, sizeof(scbp->SubURI));
+ cpr_free(pUser);
+ } else {
+ /* An error occurred, copy the whole thing.. */
+ sstrncpy(scbp->SubURI, sipUriUrl->user, sizeof(scbp->SubURI));
+ }
+ }
+ sippmh_genurl_free(genUrl);
+ SIPPMH_FREE_REQUEST_LINE(requestURI);
+
+ scbp->sip_from = strlib_update(scbp->sip_from, sip_from);
+ if (from_loc->tag) {
+ scbp->sip_from_tag = strlib_update(scbp->sip_from_tag,
+ sip_sm_purify_tag(from_loc->tag));
+ }
+
+ if (from_loc->genUrl->schema == URL_TYPE_SIP) {
+ sipFromUrl = from_loc->genUrl->u.sipUrl;
+ }
+ if (sipFromUrl) {
+ if (sipFromUrl->user) {
+ char *pUserTemp, *target = NULL, addr_error;
+ uint32_t sip_address = 0;
+
+ pUserTemp = sippmh_parse_user(sipFromUrl->user);
+ if (pUserTemp) {
+ scbp->callingNumber = strlib_update(scbp->callingNumber,
+ pUserTemp);
+ cpr_free(pUserTemp);
+ } else {
+ scbp->callingNumber = strlib_update(scbp->callingNumber,
+ sipFromUrl->user);
+ }
+
+ target = cpr_strdup(sipFromUrl->host);
+ if (!target) {
+ sip_address = 0;
+ } else {
+//CPR TODO: need reference for
+//Should replace with a boolean util_check_ip_addr(char *addr) call
+ sip_address = IPNameCk(target, &addr_error);
+ cpr_free(target);
+ }
+
+ if ((from_loc->genUrl->schema == URL_TYPE_SIP) &&
+ (!sip_address)) {
+ if (scbp->callingNumber) {
+ scbp->callingNumber = strlib_append(scbp->callingNumber, "@");
+ scbp->callingNumber = strlib_append(scbp->callingNumber, sipFromUrl->host);
+ }
+ }
+ } else {
+ scbp->callingNumber = strlib_update(scbp->callingNumber,
+ "Unknown Number");
+ }
+ }
+
+ scbp->sip_to = strlib_update(scbp->sip_to, sip_to);
+ if (to_loc->tag == NULL) {
+ // Create To tag
+ sip_to_tag_temp = strlib_open(scbp->sip_to_tag, MAX_SIP_TAG_LENGTH);
+ if (sip_to_tag_temp) {
+ sip_util_make_tag(sip_to_tag_temp);
+ }
+ scbp->sip_to_tag = strlib_close(sip_to_tag_temp);
+ sip_to_temp = strlib_open(scbp->sip_to, MAX_SIP_URL_LENGTH);
+ if (sip_to_temp) {
+ sstrncat(sip_to_temp, ";tag=",
+ MAX_SIP_URL_LENGTH - strlen(sip_to_temp));
+ if (scbp->sip_to_tag) {
+ sstrncat(sip_to_temp, scbp->sip_to_tag,
+ MAX_SIP_URL_LENGTH - strlen(sip_to_temp));
+ }
+ }
+ scbp->sip_to = strlib_close(sip_to_temp);
+ }
+
+ sippmh_free_location(to_loc);
+ sippmh_free_location(from_loc);
+
+ sstrncpy(scbp->hb.sipCallID, callID, MAX_SIP_CALL_ID);
+
+ // Parse Contact info
+ contact = sippmh_get_cached_header_val(pSipMessage, CONTACT);
+ if (contact) {
+ if (scbp->contact_info) {
+ sippmh_free_contact(scbp->contact_info);
+ }
+ scbp->contact_info = sippmh_parse_contact(contact);
+
+ if ((scbp->contact_info == NULL) || // contact in msg, parse error
+ (sipSPICheckContact(contact) < 0)) { // If contact is invalid
+ if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ SIP_WARN_MISC,
+ SIP_CLI_ERR_BAD_REQ_CONTACT_FIELD,
+ NULL) != TRUE) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
+ fname, SIP_CLI_ERR_BAD_REQ);
+ }
+ free_scb(scb_index, fname);
+ return SIP_ERROR;
+ }
+ }
+
+ if ((sipMethod == sipMethodSubscribe) && (scbp->ccbp == NULL)) {
+ record_route = sippmh_get_cached_header_val(pSipMessage,
+ RECORD_ROUTE);
+ if (record_route) {
+ if (scbp->record_route_info) {
+ sippmh_free_record_route(scbp->record_route_info);
+ }
+ scbp->record_route_info = sippmh_parse_record_route(record_route);
+ if (scbp->record_route_info == NULL) {
+ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"sippmh_parse_record_route() failed",
+ fname);
+ free_scb(scb_index, fname);
+ return SIP_ERROR;
+ }
+ /*
+ * Store the Record-Route header value to be used
+ * in 18x or 2xx response
+ */
+ scbp->cached_record_route = strlib_update(scbp->cached_record_route,
+ record_route);
+ }
+ }
+
+ } // End of populating a new SCB
+
+ scbp->hb.expires = expiry_time;
+ scbp->hb.orig_expiration = expiry_time;
+ scbp->last_recv_request_cseq = request_cseq_number;
+ scbp->last_recv_request_cseq_method = request_cseq_method;
+
+ // Parse Refer-To
+ if (sipMethod == sipMethodRefer) {
+ sipReferTo_t *referto = NULL;
+
+ noOfReferTo = sippmh_get_num_particular_headers(pSipMessage,
+ SIP_HEADER_REFER_TO,
+ SIP_C_HEADER_REFER_TO,
+ &referToString,
+ MAX_REFER_TO_HEADERS);
+
+ if ((noOfReferTo == 0) || (noOfReferTo > 1)) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ scb_index, scbp->hb.dn_line, fname,
+ "Incorrect number of Refer-To headers\n");
+ (void) sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ SIP_WARN_MISC,
+ SIP_CLI_ERR_BAD_REQ_PHRASE_REFER_TO,
+ NULL);
+ return SIP_ERROR;
+ }
+ // Note that the refer-to header is not parsed for CCM mode since it was
+ // malformed in older versions of CCM
+ if (sip_regmgr_get_cc_mode(1) != REG_MODE_CCM) {
+ referto = sippmh_parse_refer_to(referToString);
+ if (referto == NULL) {
+ CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
+ scb_index, scbp->hb.dn_line, fname,
+ "Refer-To header could not be parsed\n");
+ (void) sipSPISendErrorResponse(pSipMessage,
+ SIP_CLI_ERR_BAD_REQ,
+ SIP_CLI_ERR_BAD_REQ_PHRASE,
+ SIP_WARN_MISC,
+ SIP_CLI_ERR_BAD_REQ_PHRASE_REFER_TO,
+ NULL);
+ return SIP_ERROR;
+ } else {
+ sippmh_free_refer_to(referto);
+ }
+ }
+ }
+
+ // Parse and store Via Header
+ via = sippmh_get_cached_header_val(pSipMessage, VIA);
+ if (via) {
+ /* store the via header */
+ if (store_incoming_trxn(via, request_cseq_number, scbp) == FALSE) {
+ (void) sipSPISendErrorResponse(pSipMessage,
+ SIP_SERV_ERR_INTERNAL,
+ SIP_SERV_ERR_INTERNAL_PHRASE,
+ 0,
+ NULL,
+ NULL);
+ return SIP_ERROR;
+ }
+ }
+
+ // See if can determine dn_line from any of the parameters
+ // 1st try the REQ-URI
+ // CCM should send us
+ // SUBSCRIBE sip: